diff options
548 files changed, 6079 insertions, 4847 deletions
@@ -3709,6 +3709,13 @@ N: Dirk Verworner D: Co-author of German book ``Linux-Kernel-Programmierung'' D: Co-founder of Berlin Linux User Group +N: Andrew Victor +E: linux@maxim.org.za +W: http://maxim.org.za/at91_26.html +D: First maintainer of Atmel ARM-based SoC, aka AT91 +D: Introduced support for at91rm9200, the first chip of AT91 family +S: South Africa + N: Riku Voipio E: riku.voipio@iki.fi D: Author of PCA9532 LED and Fintek f75375s hwmon driver diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index 653d5d7..31d1d65 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt @@ -505,7 +505,10 @@ at module load time (for a module) with: The addresses are normal I2C addresses. The adapter is the string name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name. -It is *NOT* i2c-<n> itself. +It is *NOT* i2c-<n> itself. Also, the comparison is done ignoring +spaces, so if the name is "This is an I2C chip" you can say +adapter_name=ThisisanI2cchip. This is because it's hard to pass in +spaces in kernel parameters. The debug flags are bit flags for each BMC found, they are: IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8 diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index 750401f..15dfce7 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -253,7 +253,7 @@ input driver: GPIO support ~~~~~~~~~~~~ ACPI 5 introduced two new resources to describe GPIO connections: GpioIo -and GpioInt. These resources are used be used to pass GPIO numbers used by +and GpioInt. These resources can be used to pass GPIO numbers used by the device to the driver. ACPI 5.1 extended this with _DSD (Device Specific Data) which made it possible to name the GPIOs among other things. diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt index ae36fcf..f35dad1 100644 --- a/Documentation/acpi/gpio-properties.txt +++ b/Documentation/acpi/gpio-properties.txt @@ -1,9 +1,9 @@ _DSD Device Properties Related to GPIO -------------------------------------- -With the release of ACPI 5.1 and the _DSD configuration objecte names -can finally be given to GPIOs (and other things as well) returned by -_CRS. Previously, we were only able to use an integer index to find +With the release of ACPI 5.1, the _DSD configuration object finally +allows names to be given to GPIOs (and other things as well) returned +by _CRS. Previously, we were only able to use an integer index to find the corresponding GPIO, which is pretty error prone (it depends on the _CRS output ordering, for example). diff --git a/Documentation/devicetree/bindings/arm/omap/l3-noc.txt b/Documentation/devicetree/bindings/arm/omap/l3-noc.txt index 974624e..161448d 100644 --- a/Documentation/devicetree/bindings/arm/omap/l3-noc.txt +++ b/Documentation/devicetree/bindings/arm/omap/l3-noc.txt @@ -6,6 +6,7 @@ provided by Arteris. Required properties: - compatible : Should be "ti,omap3-l3-smx" for OMAP3 family Should be "ti,omap4-l3-noc" for OMAP4 family + Should be "ti,omap5-l3-noc" for OMAP5 family Should be "ti,dra7-l3-noc" for DRA7 family Should be "ti,am4372-l3-noc" for AM43 family - reg: Contains L3 register address range for each noc domain. diff --git a/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt b/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt index a4873e5..e30e184 100644 --- a/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-mxs-dma.txt @@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 { 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt index f20b111..2bee681 100644 --- a/Documentation/devicetree/bindings/mtd/m25p80.txt +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt @@ -8,8 +8,8 @@ Required properties: is not Linux-only, but in case of Linux, see the "m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of supported chips. - Must also include "nor-jedec" for any SPI NOR flash that can be - identified by the JEDEC READ ID opcode (0x9F). + Must also include "jedec,spi-nor" for any SPI NOR flash that can + be identified by the JEDEC READ ID opcode (0x9F). - reg : Chip-Select number - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at @@ -25,7 +25,7 @@ Example: flash: m25p80@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "spansion,m25p80", "nor-jedec"; + compatible = "spansion,m25p80", "jedec,spi-nor"; reg = <0>; spi-max-frequency = <40000000>; m25p,fast-read; diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt new file mode 100644 index 0000000..be78968 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt @@ -0,0 +1,30 @@ +Abracon ABX80X I2C ultra low power RTC/Alarm chip + +The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801, +ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805 +is the superset of ab180x. + +Required properties: + + - "compatible": should one of: + "abracon,abx80x" + "abracon,ab0801" + "abracon,ab0803" + "abracon,ab0804" + "abracon,ab0805" + "abracon,ab1801" + "abracon,ab1803" + "abracon,ab1804" + "abracon,ab1805" + Using "abracon,abx80x" will enable chip autodetection. + - "reg": I2C bus address of the device + +Optional properties: + +The abx804 and abx805 have a trickle charger that is able to charge the +connected battery or supercap. Both the following properties have to be defined +and valid to enable charging: + + - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V) + - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output + resistor, the other values are in ohm. diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt index 092fc10..4692241 100644 --- a/Documentation/kasan.txt +++ b/Documentation/kasan.txt @@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds bugs. KASan uses compile-time instrumentation for checking every memory access, -therefore you will need a certain version of GCC > 4.9.2 +therefore you will need a gcc version of 4.9.2 or later. KASan could detect out +of bounds accesses to stack or global variables, but only if gcc 5.0 or later was +used to built the kernel. Currently KASan is supported only for x86_64 architecture and requires that the kernel be built with the SLUB allocator. @@ -23,8 +25,8 @@ To enable KASAN configure kernel with: and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline is compiler instrumentation types. The former produces smaller binary the -latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or -latter. +latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version +of 5.0 or later. Currently KASAN works only with the SLUB memory allocator. For better bug detection and nicer report, enable CONFIG_STACKTRACE and put diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt index 1e52d67..dbe6623 100644 --- a/Documentation/serial/tty.txt +++ b/Documentation/serial/tty.txt @@ -198,6 +198,9 @@ TTY_IO_ERROR If set, causes all subsequent userspace read/write TTY_OTHER_CLOSED Device is a pty and the other side has closed. +TTY_OTHER_DONE Device is a pty and the other side has closed and + all pending input processing has been completed. + TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into smaller chunks. diff --git a/MAINTAINERS b/MAINTAINERS index 781e099..f8e0afb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -892,11 +892,10 @@ S: Maintained F: arch/arm/mach-alpine/ ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES -M: Andrew Victor <linux@maxim.org.za> M: Nicolas Ferre <nicolas.ferre@atmel.com> +M: Alexandre Belloni <alexandre.belloni@free-electrons.com> M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -W: http://maxim.org.za/at91_26.html W: http://www.linux4sam.org S: Supported F: arch/arm/mach-at91/ @@ -975,7 +974,7 @@ S: Maintained ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE M: Hans Ulli Kroll <ulli.kroll@googlemail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -T: git git://git.berlios.de/gemini-board +T: git git://github.com/ulli-kroll/linux.git S: Maintained F: arch/arm/mach-gemini/ @@ -990,6 +989,12 @@ F: drivers/clocksource/timer-prima2.c F: drivers/clocksource/timer-atlas7.c N: [^a-z]sirf +ARM/CONEXANT DIGICOLOR MACHINE SUPPORT +M: Baruch Siach <baruch@tkos.co.il> +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +N: digicolor + ARM/EBSA110 MACHINE SUPPORT M: Russell King <linux@arm.linux.org.uk> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1188,7 +1193,7 @@ ARM/MAGICIAN MACHINE SUPPORT M: Philipp Zabel <philipp.zabel@gmail.com> S: Maintained -ARM/Marvell Armada 370 and Armada XP SOC support +ARM/Marvell Kirkwood and Armada 370, 375, 38x, XP SOC support M: Jason Cooper <jason@lakedaemon.net> M: Andrew Lunn <andrew@lunn.ch> M: Gregory Clement <gregory.clement@free-electrons.com> @@ -1197,12 +1202,17 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-mvebu/ F: drivers/rtc/rtc-armada38x.c +F: arch/arm/boot/dts/armada* +F: arch/arm/boot/dts/kirkwood* + ARM/Marvell Berlin SoC support M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-berlin/ +F: arch/arm/boot/dts/berlin* + ARM/Marvell Dove/MV78xx0/Orion SOC support M: Jason Cooper <jason@lakedaemon.net> @@ -1215,6 +1225,9 @@ F: arch/arm/mach-dove/ F: arch/arm/mach-mv78xx0/ F: arch/arm/mach-orion5x/ F: arch/arm/plat-orion/ +F: arch/arm/boot/dts/dove* +F: arch/arm/boot/dts/orion5x* + ARM/Orion SoC/Technologic Systems TS-78xx platform support M: Alexander Clouter <alex@digriz.org.uk> @@ -1366,6 +1379,7 @@ N: rockchip ARM/SAMSUNG EXYNOS ARM ARCHITECTURES M: Kukjin Kim <kgene@kernel.org> +M: Krzysztof Kozlowski <k.kozlowski@samsung.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained @@ -1439,9 +1453,10 @@ ARM/SOCFPGA ARCHITECTURE M: Dinh Nguyen <dinguyen@opensource.altera.com> S: Maintained F: arch/arm/mach-socfpga/ +F: arch/arm/boot/dts/socfpga* +F: arch/arm/configs/socfpga_defconfig W: http://www.rocketboards.org -T: git://git.rocketboards.org/linux-socfpga.git -T: git://git.rocketboards.org/linux-socfpga-next.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT M: Dinh Nguyen <dinguyen@opensource.altera.com> @@ -1929,7 +1944,7 @@ S: Maintained F: drivers/net/wireless/b43legacy/ BACKLIGHT CLASS/SUBSYSTEM -M: Jingoo Han <jg1.han@samsung.com> +M: Jingoo Han <jingoohan1@gmail.com> M: Lee Jones <lee.jones@linaro.org> S: Maintained F: drivers/video/backlight/ @@ -2116,8 +2131,9 @@ S: Supported F: drivers/net/ethernet/broadcom/bnx2x/ BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE -M: Christian Daudt <bcm@fixthebug.org> M: Florian Fainelli <f.fainelli@gmail.com> +M: Ray Jui <rjui@broadcom.com> +M: Scott Branden <sbranden@broadcom.com> L: bcm-kernel-feedback-list@broadcom.com T: git git://github.com/broadcom/mach-bcm S: Maintained @@ -2168,7 +2184,6 @@ S: Maintained F: drivers/usb/gadget/udc/bcm63xx_udc.* BROADCOM BCM7XXX ARM ARCHITECTURE -M: Marc Carino <marc.ceeeee@gmail.com> M: Brian Norris <computersforpeace@gmail.com> M: Gregory Fong <gregory.0xf0@gmail.com> M: Florian Fainelli <f.fainelli@gmail.com> @@ -3912,7 +3927,7 @@ F: drivers/extcon/ F: Documentation/extcon/ EXYNOS DP DRIVER -M: Jingoo Han <jg1.han@samsung.com> +M: Jingoo Han <jingoohan1@gmail.com> L: dri-devel@lists.freedesktop.org S: Maintained F: drivers/gpu/drm/exynos/exynos_dp* @@ -4371,11 +4386,10 @@ F: fs/gfs2/ F: include/uapi/linux/gfs2_ondisk.h GIGASET ISDN DRIVERS -M: Hansjoerg Lipp <hjlipp@web.de> -M: Tilman Schmidt <tilman@imap.cc> +M: Paul Bolle <pebolle@tiscali.nl> L: gigaset307x-common@lists.sourceforge.net W: http://gigaset307x.sourceforge.net/ -S: Maintained +S: Odd Fixes F: Documentation/isdn/README.gigaset F: drivers/isdn/gigaset/ F: include/uapi/linux/gigaset_dev.h @@ -5042,17 +5056,19 @@ S: Orphan F: drivers/video/fbdev/imsttfb.c INFINIBAND SUBSYSTEM -M: Roland Dreier <roland@kernel.org> +M: Doug Ledford <dledford@redhat.com> M: Sean Hefty <sean.hefty@intel.com> M: Hal Rosenstock <hal.rosenstock@gmail.com> L: linux-rdma@vger.kernel.org W: http://www.openfabrics.org/ Q: http://patchwork.kernel.org/project/linux-rdma/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git S: Supported F: Documentation/infiniband/ F: drivers/infiniband/ F: include/uapi/linux/if_infiniband.h +F: include/uapi/rdma/ +F: include/rdma/ INOTIFY M: John McCutchan <john@johnmccutchan.com> @@ -5805,6 +5821,7 @@ F: drivers/scsi/53c700* LED SUBSYSTEM M: Bryan Wu <cooloney@gmail.com> M: Richard Purdie <rpurdie@rpsys.net> +M: Jacek Anaszewski <j.anaszewski@samsung.com> L: linux-leds@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git S: Maintained @@ -6950,6 +6967,17 @@ T: git git://git.rocketboards.org/linux-socfpga-next.git S: Maintained F: arch/nios2/ +NOKIA N900 POWER SUPPLY DRIVERS +M: Pali Rohár <pali.rohar@gmail.com> +S: Maintained +F: include/linux/power/bq2415x_charger.h +F: include/linux/power/bq27x00_battery.h +F: include/linux/power/isp1704_charger.h +F: drivers/power/bq2415x_charger.c +F: drivers/power/bq27x00_battery.c +F: drivers/power/isp1704_charger.c +F: drivers/power/rx51_battery.c + NTB DRIVER M: Jon Mason <jdmason@kudzu.us> M: Dave Jiang <dave.jiang@intel.com> @@ -7538,7 +7566,7 @@ S: Maintained F: drivers/pci/host/*rcar* PCI DRIVER FOR SAMSUNG EXYNOS -M: Jingoo Han <jg1.han@samsung.com> +M: Jingoo Han <jingoohan1@gmail.com> L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) @@ -7546,7 +7574,7 @@ S: Maintained F: drivers/pci/host/pci-exynos.c PCI DRIVER FOR SYNOPSIS DESIGNWARE -M: Jingoo Han <jg1.han@samsung.com> +M: Jingoo Han <jingoohan1@gmail.com> L: linux-pci@vger.kernel.org S: Maintained F: drivers/pci/host/*designware* @@ -8502,7 +8530,7 @@ S: Supported F: sound/soc/samsung/ SAMSUNG FRAMEBUFFER DRIVER -M: Jingoo Han <jg1.han@samsung.com> +M: Jingoo Han <jingoohan1@gmail.com> L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/video/fbdev/s3c-fb.c @@ -8807,10 +8835,11 @@ W: http://www.emulex.com S: Supported F: drivers/scsi/be2iscsi/ -SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER -M: Sathya Perla <sathya.perla@emulex.com> -M: Subbu Seetharaman <subbu.seetharaman@emulex.com> -M: Ajit Khaparde <ajit.khaparde@emulex.com> +Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER +M: Sathya Perla <sathya.perla@avagotech.com> +M: Ajit Khaparde <ajit.khaparde@avagotech.com> +M: Padmanabh Ratnakar <padmanabh.ratnakar@avagotech.com> +M: Sriharsha Basavapatna <sriharsha.basavapatna@avagotech.com> L: netdev@vger.kernel.org W: http://www.emulex.com S: Supported @@ -11037,6 +11066,7 @@ F: drivers/media/pci/zoran/ ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER M: Minchan Kim <minchan@kernel.org> M: Nitin Gupta <ngupta@vflare.org> +R: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> L: linux-kernel@vger.kernel.org S: Maintained F: drivers/block/zram/ @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 1 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc4 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* diff --git a/arch/arc/Kconfig.debug b/arch/arc/Kconfig.debug index a7fc0da..ff6a4b5 100644 --- a/arch/arc/Kconfig.debug +++ b/arch/arc/Kconfig.debug @@ -2,19 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config EARLY_PRINTK - bool "Early printk" if EMBEDDED - default y - help - Write kernel log output directly into the VGA buffer or to a serial - port. - - This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks ugly and doesn't cooperate - with klogd/syslogd or the X server. You should normally N here, - unless you want to debug such a crash. - config 16KSTACKS bool "Use 16Kb for kernel stacks instead of 8Kb" help diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 067551b..9917a45 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -99,7 +99,7 @@ static inline void atomic_##op(int i, atomic_t *v) \ atomic_ops_unlock(flags); \ } -#define ATOMIC_OP_RETURN(op, c_op) \ +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ unsigned long flags; \ diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 8c3a3e0..12b2100 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c @@ -266,7 +266,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr, * Machine specific helpers for Entire D-Cache or Per Line ops */ -static unsigned int __before_dc_op(const int op) +static inline unsigned int __before_dc_op(const int op) { unsigned int reg = reg; @@ -284,7 +284,7 @@ static unsigned int __before_dc_op(const int op) return reg; } -static void __after_dc_op(const int op, unsigned int reg) +static inline void __after_dc_op(const int op, unsigned int reg) { if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ while (read_aux_reg(ARC_REG_DC_CTRL) & DC_CTRL_FLUSH_STATUS); diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 8ae29c9..c17097d 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -49,7 +49,7 @@ pinctrl-0 = <&matrix_keypad_pins>; debounce-delay-ms = <5>; - col-scan-delay-us = <1500>; + col-scan-delay-us = <5>; row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH /* Bank5, pin5 */ &gpio5 6 GPIO_ACTIVE_HIGH>; /* Bank5, pin6 */ @@ -473,7 +473,7 @@ interrupt-parent = <&gpio0>; interrupts = <31 0>; - wake-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; touchscreen-size-x = <480>; touchscreen-size-y = <272>; diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts index 15f198e..7128fad 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15.dts +++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts @@ -18,6 +18,7 @@ aliases { rtc0 = &mcp_rtc; rtc1 = &tps659038_rtc; + rtc2 = &rtc; }; memory { @@ -83,7 +84,7 @@ gpio_fan: gpio_fan { /* Based on 5v 500mA AFB02505HHB */ compatible = "gpio-fan"; - gpios = <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>; + gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>; gpio-fan,speed-map = <0 0>, <13000 1>; #cooling-cells = <2>; @@ -130,8 +131,8 @@ uart3_pins_default: uart3_pins_default { pinctrl-single,pins = < - 0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */ - 0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */ + 0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */ + 0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */ >; }; @@ -455,7 +456,7 @@ mcp_rtc: rtc@6f { compatible = "microchip,mcp7941x"; reg = <0x6f>; - interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */ + interrupts = <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>; /* IRQ_SYS_1N */ pinctrl-names = "default"; pinctrl-0 = <&mcp79410_pins_default>; @@ -478,7 +479,7 @@ &uart3 { status = "okay"; interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, - <&dra7_pmx_core 0x248>; + <&dra7_pmx_core 0x3f8>; pinctrl-names = "default"; pinctrl-0 = <&uart3_pins_default>; diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi index c675257..f076ff8 100644 --- a/arch/arm/boot/dts/armada-375.dtsi +++ b/arch/arm/boot/dts/armada-375.dtsi @@ -69,7 +69,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; /* 25 MHz reference crystal */ refclk: oscillator { diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index ed2dd8b..218a2ac 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -585,7 +585,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; /* 25 MHz reference crystal */ diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi index 0e85fc1..ecd1318 100644 --- a/arch/arm/boot/dts/armada-39x.dtsi +++ b/arch/arm/boot/dts/armada-39x.dtsi @@ -502,7 +502,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; }; }; diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts index e3b08fb..990e8a2 100644 --- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts @@ -105,6 +105,10 @@ }; internal-regs { + rtc@10300 { + /* No crystal connected to the internal RTC */ + status = "disabled"; + }; serial@12000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/dove-cubox.dts b/arch/arm/boot/dts/dove-cubox.dts index aae7efc..e6fa251 100644 --- a/arch/arm/boot/dts/dove-cubox.dts +++ b/arch/arm/boot/dts/dove-cubox.dts @@ -87,6 +87,7 @@ /* connect xtal input to 25MHz reference */ clocks = <&ref25>; + clock-names = "xtal"; /* connect xtal input as source of pll0 and pll1 */ silabs,pll-source = <0 0>, <1 0>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 5332b57..f03a091 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -911,7 +911,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>, - <0x4ae06014 0x4>, <0x4a003b20 0x8>, + <0x4ae06014 0x4>, <0x4a003b20 0xc>, <0x4ae0c158 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -944,7 +944,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>, - <0x4ae06010 0x4>, <0x4a0025cc 0x8>, + <0x4ae06010 0x4>, <0x4a0025cc 0xc>, <0x4a002470 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -977,7 +977,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>, - <0x4ae06010 0x4>, <0x4a0025e0 0x8>, + <0x4ae06010 0x4>, <0x4a0025e0 0xc>, <0x4a00246c 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -1010,7 +1010,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>, - <0x4ae06010 0x4>, <0x4a003b08 0x8>, + <0x4ae06010 0x4>, <0x4a003b08 0xc>, <0x4ae0c154 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -1203,7 +1203,7 @@ status = "disabled"; }; - rtc@48838000 { + rtc: rtc@48838000 { compatible = "ti,am3352-rtc"; reg = <0x48838000 0x100>; interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 8de12af7..d6b49e5 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -9,6 +9,7 @@ #include <dt-bindings/sound/samsung-i2s.h> #include <dt-bindings/input/input.h> +#include <dt-bindings/clock/maxim,max77686.h> #include "exynos4412.dtsi" / { @@ -105,6 +106,8 @@ rtc@10070000 { status = "okay"; + clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>; + clock-names = "rtc", "rtc_src"; }; g2d@10800000 { diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 2657e84..1eca97e 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -567,6 +567,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; samsung,dw-mshc-ciu-div = <3>; samsung,dw-mshc-sdr-timing = <2 3>; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 0788d08..146e711 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -711,6 +711,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; clock-frequency = <400000000>; samsung,dw-mshc-ciu-div = <1>; diff --git a/arch/arm/boot/dts/exynos5420-trip-points.dtsi b/arch/arm/boot/dts/exynos5420-trip-points.dtsi index 5d31fc1..2180a01 100644 --- a/arch/arm/boot/dts/exynos5420-trip-points.dtsi +++ b/arch/arm/boot/dts/exynos5420-trip-points.dtsi @@ -28,7 +28,7 @@ trips { type = "active"; }; cpu-crit-0 { - temperature = <1200000>; /* millicelsius */ + temperature = <120000>; /* millicelsius */ hysteresis = <0>; /* millicelsius */ type = "critical"; }; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index f67b23f..4531753 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -536,6 +536,7 @@ clock-names = "dp"; phys = <&dp_phy>; phy-names = "dp"; + power-domains = <&disp_pd>; }; mipi_phy: video-phy@10040714 { diff --git a/arch/arm/boot/dts/exynos5440-trip-points.dtsi b/arch/arm/boot/dts/exynos5440-trip-points.dtsi index 48adfa8..356e963 100644 --- a/arch/arm/boot/dts/exynos5440-trip-points.dtsi +++ b/arch/arm/boot/dts/exynos5440-trip-points.dtsi @@ -18,7 +18,7 @@ trips { type = "active"; }; cpu-crit-0 { - temperature = <1050000>; /* millicelsius */ + temperature = <105000>; /* millicelsius */ hysteresis = <0>; /* millicelsius */ type = "critical"; }; diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index 412f41d..02eb8b1 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -674,6 +674,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; clock-frequency = <400000000>; samsung,dw-mshc-ciu-div = <1>; diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts index 7e6eef2..8204539 100644 --- a/arch/arm/boot/dts/imx23-olinuxino.dts +++ b/arch/arm/boot/dts/imx23-olinuxino.dts @@ -12,6 +12,7 @@ */ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include "imx23.dtsi" / { @@ -93,6 +94,7 @@ ahb@80080000 { usb0: usb@80080000 { + dr_mode = "host"; vbus-supply = <®_usb0_vbus>; status = "okay"; }; @@ -122,7 +124,7 @@ user { label = "green"; - gpios = <&gpio2 1 1>; + gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; }; }; }; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index e4d3aec..677f81d 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -428,6 +428,7 @@ pwm4: pwm@53fc8000 { compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; + #pwm-cells = <2>; reg = <0x53fc8000 0x4000>; clocks = <&clks 108>, <&clks 52>; clock-names = "ipg", "per"; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 25e25f8..4e073e8 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -913,7 +913,7 @@ 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi index 19cc269..1ce6133 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi @@ -31,6 +31,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio4 15 0>; + enable-active-high; }; reg_usb_h1_vbus: regulator@1 { @@ -40,6 +41,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio1 0 0>; + enable-active-high; }; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index 46b2fed..3b24b126 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -185,7 +185,6 @@ &i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; - pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; status = "okay"; max7310_a: gpio@30 { diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index a293158..5c16145 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -498,6 +498,8 @@ DRVDD-supply = <&vmmc2>; IOVDD-supply = <&vio>; DVDD-supply = <&vio>; + + ai3x-micbias-vg = <1>; }; tlv320aic3x_aux: tlv320aic3x@19 { @@ -509,6 +511,8 @@ DRVDD-supply = <&vmmc2>; IOVDD-supply = <&vio>; DVDD-supply = <&vio>; + + ai3x-micbias-vg = <2>; }; tsl2563: tsl2563@29 { diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index d18a90f..69a40cf 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -456,6 +456,7 @@ }; mmu_isp: mmu@480bd400 { + #iommu-cells = <0>; compatible = "ti,omap2-iommu"; reg = <0x480bd400 0x80>; interrupts = <24>; @@ -464,6 +465,7 @@ }; mmu_iva: mmu@5d000000 { + #iommu-cells = <0>; compatible = "ti,omap2-iommu"; reg = <0x5d000000 0x80>; interrupts = <28>; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index efe5f73..7d24ae0 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -128,7 +128,7 @@ * hierarchy. */ ocp { - compatible = "ti,omap4-l3-noc", "simple-bus"; + compatible = "ti,omap5-l3-noc", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 74c3212..824ddab 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -545,7 +545,7 @@ compatible = "adi,adv7511w"; reg = <0x39>; interrupt-parent = <&gpio3>; - interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; adi,input-depth = <8>; adi,input-colorspace = "rgb"; diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index bfd3f1c..2201cd5 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -1017,23 +1017,6 @@ status = "disabled"; }; - vmmci: regulator-gpio { - compatible = "regulator-gpio"; - - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2900000>; - regulator-name = "mmci-reg"; - regulator-type = "voltage"; - - startup-delay-us = <100>; - enable-active-high; - - states = <1800000 0x1 - 2900000 0x0>; - - status = "disabled"; - }; - mcde@a0350000 { compatible = "stericsson,mcde"; reg = <0xa0350000 0x1000>, /* MCDE */ diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index bf8f0ed..744c1e3 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -111,6 +111,21 @@ pinctrl-1 = <&i2c3_sleep_mode>; }; + vmmci: regulator-gpio { + compatible = "regulator-gpio"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-name = "mmci-reg"; + regulator-type = "voltage"; + + startup-delay-us = <100>; + enable-active-high; + + states = <1800000 0x1 + 2900000 0x0>; + }; + // External Micro SD slot sdi0_per1@80126000 { arm,primecell-periphid = <0x10480180>; diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index 206826a..1bc84eb 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -146,8 +146,21 @@ }; vmmci: regulator-gpio { + compatible = "regulator-gpio"; + gpios = <&gpio7 4 0x4>; enable-gpio = <&gpio6 25 0x4>; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-name = "mmci-reg"; + regulator-type = "voltage"; + + startup-delay-us = <100>; + enable-active-high; + + states = <1800000 0x1 + 2900000 0x0>; }; // External Micro SD slot diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index cf01c81..13cc7ca 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -826,7 +826,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 59>, <&tegra_car 22>; + resets = <&tegra_car 22>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; @@ -838,6 +838,7 @@ nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -862,7 +863,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 22>, <&tegra_car 22>; + resets = <&tegra_car 58>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; @@ -874,7 +875,6 @@ nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; - nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -899,7 +899,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 58>, <&tegra_car 22>; + resets = <&tegra_car 59>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 7a2aeac..107395c 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -191,6 +191,7 @@ compatible = "arm,cortex-a15-pmu"; interrupts = <0 68 4>, <0 69 4>; + interrupt-affinity = <&cpu0>, <&cpu1>; }; oscclk6a: oscclk6a { diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts index 23662b5..d949fac 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts @@ -33,28 +33,28 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + A9_0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; next-level-cache = <&L2>; }; - cpu@1 { + A9_1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; next-level-cache = <&L2>; }; - cpu@2 { + A9_2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <2>; next-level-cache = <&L2>; }; - cpu@3 { + A9_3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <3>; @@ -170,6 +170,7 @@ compatible = "arm,pl310-cache"; reg = <0x1e00a000 0x1000>; interrupts = <0 43 4>; + cache-unified; cache-level = <2>; arm,data-latency = <1 1 1>; arm,tag-latency = <1 1 1>; @@ -181,6 +182,8 @@ <0 61 4>, <0 62 4>, <0 63 4>; + interrupt-affinity = <&A9_0>, <&A9_1>, <&A9_2>, <&A9_3>; + }; dcc { diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index ab86655..0ca4a3e 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -39,11 +39,14 @@ CONFIG_ARCH_HIP04=y CONFIG_ARCH_KEYSTONE=y CONFIG_ARCH_MESON=y CONFIG_ARCH_MXC=y +CONFIG_SOC_IMX50=y CONFIG_SOC_IMX51=y CONFIG_SOC_IMX53=y CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6SL=y +CONFIG_SOC_IMX6SX=y CONFIG_SOC_VF610=y +CONFIG_SOC_LS1021A=y CONFIG_ARCH_OMAP3=y CONFIG_ARCH_OMAP4=y CONFIG_SOC_OMAP5=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 9ff7b54..3743ca2 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -393,7 +393,7 @@ CONFIG_TI_EDMA=y CONFIG_DMA_OMAP=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXTCON=m -CONFIG_EXTCON_GPIO=m +CONFIG_EXTCON_USB_GPIO=m CONFIG_EXTCON_PALMAS=m CONFIG_TI_EMIF=m CONFIG_PWM=y diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h index 8e3fcb9..2ef282f 100644 --- a/arch/arm/include/asm/dma-iommu.h +++ b/arch/arm/include/asm/dma-iommu.h @@ -25,7 +25,7 @@ struct dma_iommu_mapping { }; struct dma_iommu_mapping * -arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size); +arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size); void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 2f7e6ff..0b579b2 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -110,5 +110,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) bool xen_arch_need_swiotlb(struct device *dev, unsigned long pfn, unsigned long mfn); +unsigned long xen_get_swiotlb_free_pages(unsigned int order); #endif /* _ASM_ARM_XEN_PAGE_H */ diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 91c7ba1..213919b 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -303,12 +303,17 @@ static int probe_current_pmu(struct arm_pmu *pmu) static int of_pmu_irq_cfg(struct platform_device *pdev) { - int i; + int i, irq; int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); if (!irqs) return -ENOMEM; + /* Don't bother with PPIs; they're already affine */ + irq = platform_get_irq(pdev, 0); + if (irq >= 0 && irq_is_percpu(irq)) + return 0; + for (i = 0; i < pdev->num_resources; ++i) { struct device_node *dn; int cpu; @@ -317,7 +322,7 @@ static int of_pmu_irq_cfg(struct platform_device *pdev) i); if (!dn) { pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", - of_node_full_name(dn), i); + of_node_full_name(pdev->dev.of_node), i); break; } diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index acd5b56..5f5cd56 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -159,6 +159,8 @@ extern void exynos_enter_aftr(void); extern struct cpuidle_exynos_data cpuidle_coupled_exynos_data; +extern void exynos_set_delayed_reset_assertion(bool enable); + extern void s5p_init_cpu(void __iomem *cpuid_addr); extern unsigned int samsung_rev(void); extern void __iomem *cpu_boot_reg_base(void); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index bcde0dd..5917a30 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -167,6 +167,33 @@ static void __init exynos_init_io(void) } /* + * Set or clear the USE_DELAYED_RESET_ASSERTION option. Used by smp code + * and suspend. + * + * This is necessary only on Exynos4 SoCs. When system is running + * USE_DELAYED_RESET_ASSERTION should be set so the ARM CLK clock down + * feature could properly detect global idle state when secondary CPU is + * powered down. + * + * However this should not be set when such system is going into suspend. + */ +void exynos_set_delayed_reset_assertion(bool enable) +{ + if (of_machine_is_compatible("samsung,exynos4")) { + unsigned int tmp, core_id; + + for (core_id = 0; core_id < num_possible_cpus(); core_id++) { + tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id)); + if (enable) + tmp |= S5P_USE_DELAYED_RESET_ASSERTION; + else + tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION); + pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id)); + } + } +} + +/* * Apparently, these SoCs are not able to wake-up from suspend using * the PMU. Too bad. Should they suddenly become capable of such a * feat, the matches below should be moved to suspend.c. diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index ebd135b..a825bca 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -34,30 +34,6 @@ extern void exynos4_secondary_startup(void); -/* - * Set or clear the USE_DELAYED_RESET_ASSERTION option, set on Exynos4 SoCs - * during hot-(un)plugging CPUx. - * - * The feature can be cleared safely during first boot of secondary CPU. - * - * Exynos4 SoCs require setting USE_DELAYED_RESET_ASSERTION during powering - * down a CPU so the CPU idle clock down feature could properly detect global - * idle state when CPUx is off. - */ -static void exynos_set_delayed_reset_assertion(u32 core_id, bool enable) -{ - if (soc_is_exynos4()) { - unsigned int tmp; - - tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id)); - if (enable) - tmp |= S5P_USE_DELAYED_RESET_ASSERTION; - else - tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION); - pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id)); - } -} - #ifdef CONFIG_HOTPLUG_CPU static inline void cpu_leave_lowpower(u32 core_id) { @@ -73,8 +49,6 @@ static inline void cpu_leave_lowpower(u32 core_id) : "=&r" (v) : "Ir" (CR_C), "Ir" (0x40) : "cc"); - - exynos_set_delayed_reset_assertion(core_id, false); } static inline void platform_do_lowpower(unsigned int cpu, int *spurious) @@ -87,14 +61,6 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) /* Turn the CPU off on next WFI instruction. */ exynos_cpu_power_down(core_id); - /* - * Exynos4 SoCs require setting - * USE_DELAYED_RESET_ASSERTION so the CPU idle - * clock down feature could properly detect - * global idle state when CPUx is off. - */ - exynos_set_delayed_reset_assertion(core_id, true); - wfi(); if (pen_release == core_id) { @@ -371,9 +337,6 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) udelay(10); } - /* No harm if this is called during first boot of secondary CPU */ - exynos_set_delayed_reset_assertion(core_id, false); - /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish @@ -420,6 +383,8 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) exynos_sysram_init(); + exynos_set_delayed_reset_assertion(true); + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) scu_enable(scu_base_addr()); diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index cbe56b3..a968653 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -188,7 +188,7 @@ no_clk: args.np = np; args.args_count = 0; child_domain = of_genpd_get_from_provider(&args); - if (!child_domain) + if (IS_ERR(child_domain)) continue; if (of_parse_phandle_with_args(np, "power-domains", @@ -196,7 +196,7 @@ no_clk: continue; parent_domain = of_genpd_get_from_provider(&args); - if (!parent_domain) + if (IS_ERR(parent_domain)) continue; if (pm_genpd_add_subdomain(parent_domain, child_domain)) diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 3e6aea7..c0b6dcc 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -342,6 +342,8 @@ static void exynos_pm_enter_sleep_mode(void) static void exynos_pm_prepare(void) { + exynos_set_delayed_reset_assertion(false); + /* Set wake-up mask registers */ exynos_pm_set_wakeup_mask(); @@ -482,6 +484,7 @@ early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); + exynos_set_delayed_reset_assertion(true); } static void exynos3250_pm_resume(void) @@ -723,8 +726,10 @@ void __init exynos_pm_init(void) return; } - if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) + if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) { pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); + return; + } pm_data = (const struct exynos_pm_data *) match->data; diff --git a/arch/arm/mach-gemini/common.h b/arch/arm/mach-gemini/common.h index 38a4526..dd88369 100644 --- a/arch/arm/mach-gemini/common.h +++ b/arch/arm/mach-gemini/common.h @@ -12,6 +12,8 @@ #ifndef __GEMINI_COMMON_H__ #define __GEMINI_COMMON_H__ +#include <linux/reboot.h> + struct mtd_partition; extern void gemini_map_io(void); @@ -26,6 +28,6 @@ extern int platform_register_pflash(unsigned int size, struct mtd_partition *parts, unsigned int nr_parts); -extern void gemini_restart(char mode, const char *cmd); +extern void gemini_restart(enum reboot_mode mode, const char *cmd); #endif /* __GEMINI_COMMON_H__ */ diff --git a/arch/arm/mach-gemini/reset.c b/arch/arm/mach-gemini/reset.c index b266597..21a6d6d 100644 --- a/arch/arm/mach-gemini/reset.c +++ b/arch/arm/mach-gemini/reset.c @@ -14,7 +14,9 @@ #include <mach/hardware.h> #include <mach/global_reg.h> -void gemini_restart(char mode, const char *cmd) +#include "common.h" + +void gemini_restart(enum reboot_mode mode, const char *cmd) { __raw_writel(RESET_GLOBAL | RESET_CPU1, IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_RESET); diff --git a/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c b/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c index fb8d4a2..a5edd7d 100644 --- a/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c +++ b/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang@pengutronix.de> + * Copyright (C) 2010 Pengutronix, Wolfram Sang <kernel@pengutronix.de> * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 355b089..752969f 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -171,6 +171,12 @@ */ #define LINKS_PER_OCP_IF 2 +/* + * Address offset (in bytes) between the reset control and the reset + * status registers: 4 bytes on OMAP4 + */ +#define OMAP4_RST_CTRL_ST_OFFSET 4 + /** * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations * @enable_module: function to enable a module (via MODULEMODE) @@ -3016,10 +3022,12 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh, if (ohri->st_shift) pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", oh->name, ohri->name); - return omap_prm_deassert_hardreset(ohri->rst_shift, 0, + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->rst_shift, oh->clkdm->pwrdm.ptr->prcm_partition, oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs, 0); + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstctrl_offs + + OMAP4_RST_CTRL_ST_OFFSET); } /** @@ -3048,27 +3056,6 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, } /** - * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args - * @oh: struct omap_hwmod * to assert hardreset - * @ohri: hardreset line data - * - * Call am33xx_prminst_assert_hardreset() with parameters extracted - * from the hwmod @oh and the hardreset line data @ohri. Only - * intended for use as an soc_ops function pointer. Passes along the - * return value from am33xx_prminst_assert_hardreset(). XXX This - * function is scheduled for removal when the PRM code is moved into - * drivers/. - */ -static int _am33xx_assert_hardreset(struct omap_hwmod *oh, - struct omap_hwmod_rst_info *ohri) - -{ - return omap_prm_assert_hardreset(ohri->rst_shift, 0, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); -} - -/** * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args * @oh: struct omap_hwmod * to deassert hardreset * @ohri: hardreset line data @@ -3083,32 +3070,13 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, oh->clkdm->pwrdm.ptr->prcm_offs, oh->prcm.omap4.rstctrl_offs, oh->prcm.omap4.rstst_offs); } -/** - * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args - * @oh: struct omap_hwmod * to test hardreset - * @ohri: hardreset line data - * - * Call am33xx_prminst_is_hardreset_asserted() with parameters - * extracted from the hwmod @oh and the hardreset line data @ohri. - * Only intended for use as an soc_ops function pointer. Passes along - * the return value from am33xx_prminst_is_hardreset_asserted(). XXX - * This function is scheduled for removal when the PRM code is moved - * into drivers/. - */ -static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, - struct omap_hwmod_rst_info *ohri) -{ - return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); -} - /* Public functions */ u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) @@ -3908,21 +3876,13 @@ void __init omap_hwmod_init(void) soc_ops.init_clkdm = _init_clkdm; soc_ops.update_context_lost = _omap4_update_context_lost; soc_ops.get_context_lost = _omap4_get_context_lost; - } else if (soc_is_am43xx()) { + } else if (cpu_is_ti816x() || soc_is_am33xx() || soc_is_am43xx()) { soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; soc_ops.wait_target_ready = _omap4_wait_target_ready; soc_ops.assert_hardreset = _omap4_assert_hardreset; - soc_ops.deassert_hardreset = _omap4_deassert_hardreset; - soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; - soc_ops.init_clkdm = _init_clkdm; - } else if (cpu_is_ti816x() || soc_is_am33xx()) { - soc_ops.enable_module = _omap4_enable_module; - soc_ops.disable_module = _omap4_disable_module; - soc_ops.wait_target_ready = _omap4_wait_target_ready; - soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; - soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; + soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else { WARN(1, "omap_hwmod: unknown SoC type\n"); diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c index e222314..17e8004 100644 --- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c @@ -544,6 +544,44 @@ static struct omap_hwmod am43xx_hdq1w_hwmod = { }, }; +static struct omap_hwmod_class_sysconfig am43xx_vpfe_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x104, + .sysc_flags = SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_SMART | MSTANDBY_NO), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class am43xx_vpfe_hwmod_class = { + .name = "vpfe", + .sysc = &am43xx_vpfe_sysc, +}; + +static struct omap_hwmod am43xx_vpfe0_hwmod = { + .name = "vpfe0", + .class = &am43xx_vpfe_hwmod_class, + .clkdm_name = "l3s_clkdm", + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = AM43XX_CM_PER_VPFE0_CLKCTRL_OFFSET, + }, + }, +}; + +static struct omap_hwmod am43xx_vpfe1_hwmod = { + .name = "vpfe1", + .class = &am43xx_vpfe_hwmod_class, + .clkdm_name = "l3s_clkdm", + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = AM43XX_CM_PER_VPFE1_CLKCTRL_OFFSET, + }, + }, +}; + /* Interfaces */ static struct omap_hwmod_ocp_if am43xx_l3_main__l4_hs = { .master = &am33xx_l3_main_hwmod, @@ -825,6 +863,34 @@ static struct omap_hwmod_ocp_if am43xx_l4_ls__hdq1w = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_ocp_if am43xx_l3__vpfe0 = { + .master = &am43xx_vpfe0_hwmod, + .slave = &am33xx_l3_main_hwmod, + .clk = "l3_gclk", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if am43xx_l3__vpfe1 = { + .master = &am43xx_vpfe1_hwmod, + .slave = &am33xx_l3_main_hwmod, + .clk = "l3_gclk", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if am43xx_l4_ls__vpfe0 = { + .master = &am33xx_l4_ls_hwmod, + .slave = &am43xx_vpfe0_hwmod, + .clk = "l4ls_gclk", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if am43xx_l4_ls__vpfe1 = { + .master = &am33xx_l4_ls_hwmod, + .slave = &am43xx_vpfe1_hwmod, + .clk = "l4ls_gclk", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { &am33xx_l4_wkup__synctimer, &am43xx_l4_ls__timer8, @@ -925,6 +991,10 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { &am43xx_l4_ls__dss_dispc, &am43xx_l4_ls__dss_rfbi, &am43xx_l4_ls__hdq1w, + &am43xx_l3__vpfe0, + &am43xx_l3__vpfe1, + &am43xx_l4_ls__vpfe0, + &am43xx_l4_ls__vpfe1, NULL, }; diff --git a/arch/arm/mach-omap2/prcm43xx.h b/arch/arm/mach-omap2/prcm43xx.h index 48df3b5..d026199 100644 --- a/arch/arm/mach-omap2/prcm43xx.h +++ b/arch/arm/mach-omap2/prcm43xx.h @@ -144,5 +144,6 @@ #define AM43XX_CM_PER_USBPHYOCP2SCP1_CLKCTRL_OFFSET 0x05C0 #define AM43XX_CM_PER_DSS_CLKCTRL_OFFSET 0x0a20 #define AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET 0x04a0 - +#define AM43XX_CM_PER_VPFE0_CLKCTRL_OFFSET 0x0068 +#define AM43XX_CM_PER_VPFE1_CLKCTRL_OFFSET 0x0070 #endif diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index cbefbd7..661d753 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h @@ -112,6 +112,7 @@ #define OMAP3430_VC_CMD_ONLP_SHIFT 16 #define OMAP3430_VC_CMD_RET_SHIFT 8 #define OMAP3430_VC_CMD_OFF_SHIFT 0 +#define OMAP3430_SREN_MASK (1 << 4) #define OMAP3430_HSEN_MASK (1 << 3) #define OMAP3430_MCODE_MASK (0x7 << 0) #define OMAP3430_VALID_MASK (1 << 24) diff --git a/arch/arm/mach-omap2/prm-regbits-44xx.h b/arch/arm/mach-omap2/prm-regbits-44xx.h index b1c7a33..e794828 100644 --- a/arch/arm/mach-omap2/prm-regbits-44xx.h +++ b/arch/arm/mach-omap2/prm-regbits-44xx.h @@ -35,6 +35,7 @@ #define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1 #define OMAP4430_GLOBAL_WUEN_MASK (1 << 16) #define OMAP4430_HSMCODE_MASK (0x7 << 0) +#define OMAP4430_SRMODEEN_MASK (1 << 4) #define OMAP4430_HSMODEEN_MASK (1 << 3) #define OMAP4430_HSSCLL_SHIFT 24 #define OMAP4430_ICEPICK_RST_SHIFT 9 diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c index c4859c4..d0b15db 100644 --- a/arch/arm/mach-omap2/prminst44xx.c +++ b/arch/arm/mach-omap2/prminst44xx.c @@ -87,12 +87,6 @@ u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst, return v; } -/* - * Address offset (in bytes) between the reset control and the reset - * status registers: 4 bytes on OMAP4 - */ -#define OMAP4_RST_CTRL_ST_OFFSET 4 - /** * omap4_prminst_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module @@ -141,11 +135,11 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and * wait * @shift: register bit shift corresponding to the reset line to deassert - * @st_shift: status bit offset, not used for OMAP4+ + * @st_shift: status bit offset corresponding to the reset line * @part: PRM partition * @inst: PRM instance offset * @rstctrl_offs: reset register offset - * @st_offs: reset status register offset, not used for OMAP4+ + * @rstst_offs: reset status register offset * * Some IPs like dsp, ipu or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -157,11 +151,11 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, * of reset, or -EBUSY if the submodule did not exit reset promptly. */ int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst, - u16 rstctrl_offs, u16 st_offs) + u16 rstctrl_offs, u16 rstst_offs) { int c; u32 mask = 1 << shift; - u16 rstst_offs = rstctrl_offs + OMAP4_RST_CTRL_ST_OFFSET; + u32 st_mask = 1 << st_shift; /* Check the current status to avoid de-asserting the line twice */ if (omap4_prminst_is_hardreset_asserted(shift, part, inst, @@ -169,13 +163,13 @@ int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst, return -EEXIST; /* Clear the reset status by writing 1 to the status bit */ - omap4_prminst_rmw_inst_reg_bits(0xffffffff, mask, part, inst, + omap4_prminst_rmw_inst_reg_bits(0xffffffff, st_mask, part, inst, rstst_offs); /* de-assert the reset control line */ omap4_prminst_rmw_inst_reg_bits(mask, 0, part, inst, rstctrl_offs); /* wait the status to be set */ - omap_test_timeout(omap4_prminst_is_hardreset_asserted(shift, part, inst, - rstst_offs), + omap_test_timeout(omap4_prminst_is_hardreset_asserted(st_shift, part, + inst, rstst_offs), MAX_MODULE_HARDRESET_WAIT, c); return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index cef67af..cac46d8 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -298,14 +298,11 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, if (IS_ERR(src)) return PTR_ERR(src); - if (clk_get_parent(timer->fclk) != src) { - r = clk_set_parent(timer->fclk, src); - if (r < 0) { - pr_warn("%s: %s cannot set source\n", __func__, - oh->name); - clk_put(src); - return r; - } + r = clk_set_parent(timer->fclk, src); + if (r < 0) { + pr_warn("%s: %s cannot set source\n", __func__, oh->name); + clk_put(src); + return r; } clk_put(src); diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index be9ef83..076fd20 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -316,7 +316,8 @@ static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm) * idle. And we can also scale voltages to zero for off-idle. * Note that no actual voltage scaling during off-idle will * happen unless the board specific twl4030 PMIC scripts are - * loaded. + * loaded. See also omap_vc_i2c_init for comments regarding + * erratum i531. */ val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { @@ -704,9 +705,16 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) return; } + /* + * Note that for omap3 OMAP3430_SREN_MASK clears SREN to work around + * erratum i531 "Extra Power Consumed When Repeated Start Operation + * Mode Is Enabled on I2C Interface Dedicated for Smart Reflex (I2C4)". + * Otherwise I2C4 eventually leads into about 23mW extra power being + * consumed even during off idle using VMODE. + */ i2c_high_speed = voltdm->pmic->i2c_high_speed; if (i2c_high_speed) - voltdm->rmw(vc->common->i2c_cfg_hsen_mask, + voltdm->rmw(vc->common->i2c_cfg_clear_mask, vc->common->i2c_cfg_hsen_mask, vc->common->i2c_cfg_reg); diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index cdbdd78..89b83b7 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -34,6 +34,7 @@ struct voltagedomain; * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register * @i2c_cfg_reg: I2C configuration register offset + * @i2c_cfg_clear_mask: high-speed mode bit clear mask in I2C config register * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register * @i2c_mcode_mask: MCODE field mask for I2C config register * @@ -52,6 +53,7 @@ struct omap_vc_common { u8 cmd_ret_shift; u8 cmd_off_shift; u8 i2c_cfg_reg; + u8 i2c_cfg_clear_mask; u8 i2c_cfg_hsen_mask; u8 i2c_mcode_mask; }; diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c index 75bc4aa..71d74c9 100644 --- a/arch/arm/mach-omap2/vc3xxx_data.c +++ b/arch/arm/mach-omap2/vc3xxx_data.c @@ -40,6 +40,7 @@ static struct omap_vc_common omap3_vc_common = { .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT, .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, + .i2c_cfg_clear_mask = OMAP3430_SREN_MASK | OMAP3430_HSEN_MASK, .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, .i2c_mcode_mask = OMAP3430_MCODE_MASK, diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c index 085e5d6..2abd5fa 100644 --- a/arch/arm/mach-omap2/vc44xx_data.c +++ b/arch/arm/mach-omap2/vc44xx_data.c @@ -42,6 +42,7 @@ static const struct omap_vc_common omap4_vc_common = { .cmd_ret_shift = OMAP4430_RET_SHIFT, .cmd_off_shift = OMAP4430_OFF_SHIFT, .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, + .i2c_cfg_clear_mask = OMAP4430_SRMODEEN_MASK | OMAP4430_HSMODEEN_MASK, .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, .i2c_mcode_mask = OMAP4430_HSMCODE_MASK, }; diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 8896e71..f096836 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111 config PXA310_ULPI bool +config PXA_SYSTEMS_CPLDS + tristate "Motherboard cplds" + default ARCH_LUBBOCK || MACH_MAINSTONE + help + This driver supports the Lubbock and Mainstone multifunction chip + found on the pxa25x development platform system (Lubbock) and pxa27x + development platform system (Mainstone). This IO board supports the + interrupts handling, ethernet controller, flash chips, etc ... + endif diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index eb0bf76..4087d33 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o obj-$(CONFIG_MACH_ZIPIT2) += z2.o +obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o obj-$(CONFIG_TOSA_BT) += tosa-bt.o diff --git a/arch/arm/mach-pxa/include/mach/lubbock.h b/arch/arm/mach-pxa/include/mach/lubbock.h index 958cd6af..1eecf79 100644 --- a/arch/arm/mach-pxa/include/mach/lubbock.h +++ b/arch/arm/mach-pxa/include/mach/lubbock.h @@ -37,7 +37,9 @@ #define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100) /* Board specific IRQs */ -#define LUBBOCK_IRQ(x) (IRQ_BOARD_START + (x)) +#define LUBBOCK_NR_IRQS IRQ_BOARD_START + +#define LUBBOCK_IRQ(x) (LUBBOCK_NR_IRQS + (x)) #define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) #define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) #define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */ @@ -47,8 +49,7 @@ #define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ #define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) -#define LUBBOCK_SA1111_IRQ_BASE (IRQ_BOARD_START + 16) -#define LUBBOCK_NR_IRQS (IRQ_BOARD_START + 16 + 55) +#define LUBBOCK_SA1111_IRQ_BASE (LUBBOCK_NR_IRQS + 32) #ifndef __ASSEMBLY__ extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set); diff --git a/arch/arm/mach-pxa/include/mach/mainstone.h b/arch/arm/mach-pxa/include/mach/mainstone.h index 1bfc4e8..e82a7d3 100644 --- a/arch/arm/mach-pxa/include/mach/mainstone.h +++ b/arch/arm/mach-pxa/include/mach/mainstone.h @@ -120,7 +120,9 @@ #define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */ /* board specific IRQs */ -#define MAINSTONE_IRQ(x) (IRQ_BOARD_START + (x)) +#define MAINSTONE_NR_IRQS IRQ_BOARD_START + +#define MAINSTONE_IRQ(x) (MAINSTONE_NR_IRQS + (x)) #define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0) #define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1) #define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2) @@ -136,6 +138,4 @@ #define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14) #define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15) -#define MAINSTONE_NR_IRQS (IRQ_BOARD_START + 16) - #endif diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index d8a1be6..4ac9ab8 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -123,84 +124,6 @@ void lubbock_set_misc_wr(unsigned int mask, unsigned int set) } EXPORT_SYMBOL(lubbock_set_misc_wr); -static unsigned long lubbock_irq_enabled; - -static void lubbock_mask_irq(struct irq_data *d) -{ - int lubbock_irq = (d->irq - LUBBOCK_IRQ(0)); - LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); -} - -static void lubbock_unmask_irq(struct irq_data *d) -{ - int lubbock_irq = (d->irq - LUBBOCK_IRQ(0)); - /* the irq can be acknowledged only if deasserted, so it's done here */ - LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); - LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); -} - -static struct irq_chip lubbock_irq_chip = { - .name = "FPGA", - .irq_ack = lubbock_mask_irq, - .irq_mask = lubbock_mask_irq, - .irq_unmask = lubbock_unmask_irq, -}; - -static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; - do { - /* clear our parent irq */ - desc->irq_data.chip->irq_ack(&desc->irq_data); - if (likely(pending)) { - irq = LUBBOCK_IRQ(0) + __ffs(pending); - generic_handle_irq(irq); - } - pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; - } while (pending); -} - -static void __init lubbock_init_irq(void) -{ - int irq; - - pxa25x_init_irq(); - - /* setup extra lubbock irqs */ - for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { - irq_set_chip_and_handler(irq, &lubbock_irq_chip, - handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - - irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lubbock_irq_handler); - irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING); -} - -#ifdef CONFIG_PM - -static void lubbock_irq_resume(void) -{ - LUB_IRQ_MASK_EN = lubbock_irq_enabled; -} - -static struct syscore_ops lubbock_irq_syscore_ops = { - .resume = lubbock_irq_resume, -}; - -static int __init lubbock_irq_device_init(void) -{ - if (machine_is_lubbock()) { - register_syscore_ops(&lubbock_irq_syscore_ops); - return 0; - } - return -ENODEV; -} - -device_initcall(lubbock_irq_device_init); - -#endif - static int lubbock_udc_is_connected(void) { return (LUB_MISC_RD & (1 << 9)) == 0; @@ -383,11 +306,38 @@ static struct platform_device lubbock_flash_device[2] = { }, }; +static struct resource lubbock_cplds_resources[] = { + [0] = { + .start = LUBBOCK_FPGA_PHYS + 0xc0, + .end = LUBBOCK_FPGA_PHYS + 0xe0 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PXA_GPIO_TO_IRQ(0), + .end = PXA_GPIO_TO_IRQ(0), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + }, + [2] = { + .start = LUBBOCK_IRQ(0), + .end = LUBBOCK_IRQ(6), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device lubbock_cplds_device = { + .name = "pxa_cplds_irqs", + .id = -1, + .resource = &lubbock_cplds_resources[0], + .num_resources = 3, +}; + + static struct platform_device *devices[] __initdata = { &sa1111_device, &smc91x_device, &lubbock_flash_device[0], &lubbock_flash_device[1], + &lubbock_cplds_device, }; static struct pxafb_mode_info sharp_lm8v31_mode = { @@ -648,7 +598,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") /* Maintainer: MontaVista Software Inc. */ .map_io = lubbock_map_io, .nr_irqs = LUBBOCK_NR_IRQS, - .init_irq = lubbock_init_irq, + .init_irq = pxa25x_init_irq, .handle_irq = pxa25x_handle_irq, .init_time = pxa_timer_init, .init_machine = lubbock_init, diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 78b84c0..2c0658c 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -13,6 +13,7 @@ * published by the Free Software Foundation. */ #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/syscore_ops.h> @@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = { GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, }; -static unsigned long mainstone_irq_enabled; - -static void mainstone_mask_irq(struct irq_data *d) -{ - int mainstone_irq = (d->irq - MAINSTONE_IRQ(0)); - MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); -} - -static void mainstone_unmask_irq(struct irq_data *d) -{ - int mainstone_irq = (d->irq - MAINSTONE_IRQ(0)); - /* the irq can be acknowledged only if deasserted, so it's done here */ - MST_INTSETCLR &= ~(1 << mainstone_irq); - MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); -} - -static struct irq_chip mainstone_irq_chip = { - .name = "FPGA", - .irq_ack = mainstone_mask_irq, - .irq_mask = mainstone_mask_irq, - .irq_unmask = mainstone_unmask_irq, -}; - -static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; - do { - /* clear useless edge notification */ - desc->irq_data.chip->irq_ack(&desc->irq_data); - if (likely(pending)) { - irq = MAINSTONE_IRQ(0) + __ffs(pending); - generic_handle_irq(irq); - } - pending = MST_INTSETCLR & mainstone_irq_enabled; - } while (pending); -} - -static void __init mainstone_init_irq(void) -{ - int irq; - - pxa27x_init_irq(); - - /* setup extra Mainstone irqs */ - for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { - irq_set_chip_and_handler(irq, &mainstone_irq_chip, - handle_level_irq); - if (irq == MAINSTONE_IRQ(10) || irq == MAINSTONE_IRQ(14)) - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN); - else - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - set_irq_flags(MAINSTONE_IRQ(8), 0); - set_irq_flags(MAINSTONE_IRQ(12), 0); - - MST_INTMSKENA = 0; - MST_INTSETCLR = 0; - - irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), mainstone_irq_handler); - irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING); -} - -#ifdef CONFIG_PM - -static void mainstone_irq_resume(void) -{ - MST_INTMSKENA = mainstone_irq_enabled; -} - -static struct syscore_ops mainstone_irq_syscore_ops = { - .resume = mainstone_irq_resume, -}; - -static int __init mainstone_irq_device_init(void) -{ - if (machine_is_mainstone()) - register_syscore_ops(&mainstone_irq_syscore_ops); - - return 0; -} - -device_initcall(mainstone_irq_device_init); - -#endif - - static struct resource smc91x_resources[] = { [0] = { .start = (MST_ETH_PHYS + 0x300), @@ -487,11 +402,37 @@ static struct platform_device mst_gpio_keys_device = { }, }; +static struct resource mst_cplds_resources[] = { + [0] = { + .start = MST_FPGA_PHYS + 0xc0, + .end = MST_FPGA_PHYS + 0xe0 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PXA_GPIO_TO_IRQ(0), + .end = PXA_GPIO_TO_IRQ(0), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + }, + [2] = { + .start = MAINSTONE_IRQ(0), + .end = MAINSTONE_IRQ(15), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mst_cplds_device = { + .name = "pxa_cplds_irqs", + .id = -1, + .resource = &mst_cplds_resources[0], + .num_resources = 3, +}; + static struct platform_device *platform_devices[] __initdata = { &smc91x_device, &mst_flash_device[0], &mst_flash_device[1], &mst_gpio_keys_device, + &mst_cplds_device, }; static struct pxaohci_platform_data mainstone_ohci_platform_data = { @@ -718,7 +659,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") .atag_offset = 0x100, /* BLOB boot parameter setting */ .map_io = mainstone_map_io, .nr_irqs = MAINSTONE_NR_IRQS, - .init_irq = mainstone_init_irq, + .init_irq = pxa27x_init_irq, .handle_irq = pxa27x_handle_irq, .init_time = pxa_timer_init, .init_machine = mainstone_init, diff --git a/arch/arm/mach-pxa/pxa_cplds_irqs.c b/arch/arm/mach-pxa/pxa_cplds_irqs.c new file mode 100644 index 0000000..f1aeb54 --- /dev/null +++ b/arch/arm/mach-pxa/pxa_cplds_irqs.c @@ -0,0 +1,200 @@ +/* + * Intel Reference Systems cplds + * + * Copyright (C) 2014 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Cplds motherboard driver, supporting lubbock and mainstone SoC board. + */ + +#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/of_platform.h> + +#define FPGA_IRQ_MASK_EN 0x0 +#define FPGA_IRQ_SET_CLR 0x10 + +#define CPLDS_NB_IRQ 32 + +struct cplds { + void __iomem *base; + int irq; + unsigned int irq_mask; + struct gpio_desc *gpio0; + struct irq_domain *irqdomain; +}; + +static irqreturn_t cplds_irq_handler(int in_irq, void *d) +{ + struct cplds *fpga = d; + unsigned long pending; + unsigned int bit; + + pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask; + for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) + generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit)); + + return IRQ_HANDLED; +} + +static void cplds_irq_mask_ack(struct irq_data *d) +{ + struct cplds *fpga = irq_data_get_irq_chip_data(d); + unsigned int cplds_irq = irqd_to_hwirq(d); + unsigned int set, bit = BIT(cplds_irq); + + fpga->irq_mask &= ~bit; + writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); + set = readl(fpga->base + FPGA_IRQ_SET_CLR); + writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR); +} + +static void cplds_irq_unmask(struct irq_data *d) +{ + struct cplds *fpga = irq_data_get_irq_chip_data(d); + unsigned int cplds_irq = irqd_to_hwirq(d); + unsigned int bit = BIT(cplds_irq); + + fpga->irq_mask |= bit; + writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); +} + +static struct irq_chip cplds_irq_chip = { + .name = "pxa_cplds", + .irq_mask_ack = cplds_irq_mask_ack, + .irq_unmask = cplds_irq_unmask, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, +}; + +static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct cplds *fpga = d->host_data; + + irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq); + irq_set_chip_data(irq, fpga); + + return 0; +} + +static const struct irq_domain_ops cplds_irq_domain_ops = { + .xlate = irq_domain_xlate_twocell, + .map = cplds_irq_domain_map, +}; + +static int cplds_resume(struct platform_device *pdev) +{ + struct cplds *fpga = platform_get_drvdata(pdev); + + writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); + + return 0; +} + +static int cplds_probe(struct platform_device *pdev) +{ + struct resource *res; + struct cplds *fpga; + int ret; + unsigned int base_irq = 0; + unsigned long irqflags = 0; + + fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL); + if (!fpga) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) { + fpga->irq = (unsigned int)res->start; + irqflags = res->flags; + } + if (!fpga->irq) + return -ENODEV; + + base_irq = platform_get_irq(pdev, 1); + if (base_irq < 0) + base_irq = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fpga->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fpga->base)) + return PTR_ERR(fpga->base); + + platform_set_drvdata(pdev, fpga); + + writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); + writel(0, fpga->base + FPGA_IRQ_SET_CLR); + + ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler, + irqflags, dev_name(&pdev->dev), fpga); + if (ret == -ENOSYS) + return -EPROBE_DEFER; + + if (ret) { + dev_err(&pdev->dev, "couldn't request main irq%d: %d\n", + fpga->irq, ret); + return ret; + } + + irq_set_irq_wake(fpga->irq, 1); + fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node, + CPLDS_NB_IRQ, + &cplds_irq_domain_ops, fpga); + if (!fpga->irqdomain) + return -ENODEV; + + if (base_irq) { + ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0, + CPLDS_NB_IRQ); + if (ret) { + dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n", + base_irq, base_irq + CPLDS_NB_IRQ); + return ret; + } + } + + return 0; +} + +static int cplds_remove(struct platform_device *pdev) +{ + struct cplds *fpga = platform_get_drvdata(pdev); + + irq_set_chip_and_handler(fpga->irq, NULL, NULL); + + return 0; +} + +static const struct of_device_id cplds_id_table[] = { + { .compatible = "intel,lubbock-cplds-irqs", }, + { .compatible = "intel,mainstone-cplds-irqs", }, + { } +}; +MODULE_DEVICE_TABLE(of, cplds_id_table); + +static struct platform_driver cplds_driver = { + .driver = { + .name = "pxa_cplds_irqs", + .of_match_table = of_match_ptr(cplds_id_table), + }, + .probe = cplds_probe, + .remove = cplds_remove, + .resume = cplds_resume, +}; + +module_platform_driver(cplds_driver); + +MODULE_DESCRIPTION("PXA Cplds interrupts driver"); +MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c index b07d886..b0dcbe2 100644 --- a/arch/arm/mach-rockchip/pm.c +++ b/arch/arm/mach-rockchip/pm.c @@ -83,6 +83,13 @@ static void rk3288_slp_mode_set(int level) SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN | SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE); + /* + * The dapswjdp can not auto reset before resume, that cause it may + * access some illegal address during resume. Let's disable it before + * suspend, and the MASKROM will enable it back. + */ + regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0, SGRF_DAPDEVICEEN_WRITE); + /* booting address of resuming system is from this register value */ regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR, rk3288_bootram_phy); diff --git a/arch/arm/mach-rockchip/pm.h b/arch/arm/mach-rockchip/pm.h index 03ff31d..3e8d39c 100644 --- a/arch/arm/mach-rockchip/pm.h +++ b/arch/arm/mach-rockchip/pm.h @@ -55,6 +55,10 @@ static inline void rockchip_suspend_init(void) #define SGRF_FAST_BOOT_EN BIT(8) #define SGRF_FAST_BOOT_EN_WRITE BIT(24) +#define RK3288_SGRF_CPU_CON0 (0x40) +#define SGRF_DAPDEVICEEN BIT(0) +#define SGRF_DAPDEVICEEN_WRITE BIT(16) + #define RK3288_CRU_MODE_CON 0x50 #define RK3288_CRU_SEL0_CON 0x60 #define RK3288_CRU_SEL1_CON 0x64 diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c index d360ec0..b6cf3b4 100644 --- a/arch/arm/mach-rockchip/rockchip.c +++ b/arch/arm/mach-rockchip/rockchip.c @@ -30,11 +30,30 @@ #include "pm.h" #define RK3288_GRF_SOC_CON0 0x244 +#define RK3288_TIMER6_7_PHYS 0xff810000 static void __init rockchip_timer_init(void) { if (of_machine_is_compatible("rockchip,rk3288")) { struct regmap *grf; + void __iomem *reg_base; + + /* + * Most/all uboot versions for rk3288 don't enable timer7 + * which is needed for the architected timer to work. + * So make sure it is running during early boot. + */ + reg_base = ioremap(RK3288_TIMER6_7_PHYS, SZ_16K); + if (reg_base) { + writel(0, reg_base + 0x30); + writel(0xffffffff, reg_base + 0x20); + writel(0xffffffff, reg_base + 0x24); + writel(1, reg_base + 0x30); + dsb(); + iounmap(reg_base); + } else { + pr_err("rockchip: could not map timer7 registers\n"); + } /* * Disable auto jtag/sdmmc switching that causes issues diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 09c5fe3..7e7583d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1878,7 +1878,7 @@ struct dma_map_ops iommu_coherent_ops = { * arm_iommu_attach_device function. */ struct dma_iommu_mapping * -arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) +arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size) { unsigned int bits = size >> PAGE_SHIFT; unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); @@ -1886,6 +1886,10 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) int extensions = 1; int err = -ENOMEM; + /* currently only 32-bit DMA address space is supported */ + if (size > DMA_BIT_MASK(32) + 1) + return ERR_PTR(-ERANGE); + if (!bitmap_size) return ERR_PTR(-EINVAL); @@ -2057,13 +2061,6 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, if (!iommu) return false; - /* - * currently arm_iommu_create_mapping() takes a max of size_t - * for size param. So check this limit for now. - */ - if (size > SIZE_MAX) - return false; - mapping = arm_iommu_create_mapping(dev->bus, dma_base, size); if (IS_ERR(mapping)) { pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n", diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index aa0519e..774ef13 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -22,8 +22,6 @@ * * These are the low level assembler for performing cache and TLB * functions on the arm1020. - * - * CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt */ #include <linux/linkage.h> #include <linux/init.h> diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index bff4c7f..ae3c27b 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -22,8 +22,6 @@ * * These are the low level assembler for performing cache and TLB * functions on the arm1020e. - * - * CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt */ #include <linux/linkage.h> #include <linux/init.h> diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index ede8c54..32a47cc 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -441,9 +441,6 @@ ENTRY(cpu_arm925_set_pte_ext) .type __arm925_setup, #function __arm925_setup: mov r0, #0 -#if defined(CONFIG_CPU_ICACHE_STREAMING_DISABLE) - orr r0,r0,#1 << 7 -#endif /* Transparent on, D-cache clean & flush mode. See NOTE2 above */ orr r0,r0,#1 << 1 @ transparent mode on diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index e494d6d..92e08bf 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S @@ -602,7 +602,6 @@ __\name\()_proc_info: PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ initfn __feroceon_setup, __\name\()_proc_info - .long __feroceon_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index e1268f9..e0e2358 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -54,6 +54,7 @@ #define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) #define FLAG_NEED_X_RESET (1 << 0) +#define FLAG_IMM_OVERFLOW (1 << 1) struct jit_ctx { const struct bpf_prog *skf; @@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx) /* PC in ARM mode == address of the instruction + 8 */ imm = offset - (8 + ctx->idx * 4); + if (imm & ~0xfff) { + /* + * literal pool is too far, signal it into flags. we + * can only detect it on the second pass unfortunately. + */ + ctx->flags |= FLAG_IMM_OVERFLOW; + return 0; + } + return imm; } @@ -449,10 +459,21 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx) return; } #endif - if (rm != ARM_R0) - emit(ARM_MOV_R(ARM_R0, rm), ctx); + + /* + * For BPF_ALU | BPF_DIV | BPF_K instructions, rm is ARM_R4 + * (r_A) and rn is ARM_R0 (r_scratch) so load rn first into + * ARM_R1 to avoid accidentally overwriting ARM_R0 with rm + * before using it as a source for ARM_R1. + * + * For BPF_ALU | BPF_DIV | BPF_X rm is ARM_R4 (r_A) and rn is + * ARM_R5 (r_X) so there is no particular register overlap + * issues. + */ if (rn != ARM_R1) emit(ARM_MOV_R(ARM_R1, rn), ctx); + if (rm != ARM_R0) + emit(ARM_MOV_R(ARM_R0, rm), ctx); ctx->seen |= SEEN_CALL; emit_mov_i(ARM_R3, (u32)jit_udiv, ctx); @@ -855,6 +876,14 @@ b_epilogue: default: return -1; } + + if (ctx->flags & FLAG_IMM_OVERFLOW) + /* + * this instruction generated an overflow when + * trying to access the literal pool, so + * delegate this filter to the kernel interpreter. + */ + return -1; } /* compute offsets only during the first pass */ @@ -917,7 +946,14 @@ void bpf_jit_compile(struct bpf_prog *fp) ctx.idx = 0; build_prologue(&ctx); - build_body(&ctx); + if (build_body(&ctx) < 0) { +#if __LINUX_ARM_ARCH__ < 7 + if (ctx.imm_count) + kfree(ctx.imms); +#endif + bpf_jit_binary_free(header); + goto out; + } build_epilogue(&ctx); flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index 793551d..4983250 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -4,6 +4,7 @@ #include <linux/gfp.h> #include <linux/highmem.h> #include <linux/export.h> +#include <linux/memblock.h> #include <linux/of_address.h> #include <linux/slab.h> #include <linux/types.h> @@ -21,6 +22,20 @@ #include <asm/xen/hypercall.h> #include <asm/xen/interface.h> +unsigned long xen_get_swiotlb_free_pages(unsigned int order) +{ + struct memblock_region *reg; + gfp_t flags = __GFP_NOWARN; + + for_each_memblock(memory, reg) { + if (reg->base < (phys_addr_t)0xffffffff) { + flags |= __GFP_DMA; + break; + } + } + return __get_free_pages(flags, order); +} + enum dma_cache_op { DMA_UNMAP, DMA_MAP, diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi index c138b95..351c95b 100644 --- a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi +++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi @@ -21,6 +21,20 @@ clock-output-names = "juno_mb:clk25mhz"; }; + v2m_refclk1mhz: refclk1mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "juno_mb:refclk1mhz"; + }; + + v2m_refclk32khz: refclk32khz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "juno_mb:refclk32khz"; + }; + motherboard { compatible = "arm,vexpress,v2p-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ @@ -66,6 +80,15 @@ #size-cells = <1>; ranges = <0 3 0 0x200000>; + v2m_sysctl: sysctl@020000 { + compatible = "arm,sp810", "arm,primecell"; + reg = <0x020000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&mb_clk24mhz>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; + }; + mmci@050000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; @@ -106,16 +129,16 @@ compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x10000>; interrupts = <9>; - clocks = <&mb_clk24mhz>, <&soc_smc50mhz>; - clock-names = "timclken1", "apb_pclk"; + clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&mb_clk24mhz>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x10000>; interrupts = <9>; - clocks = <&mb_clk24mhz>, <&soc_smc50mhz>; - clock-names = "timclken1", "apb_pclk"; + clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&mb_clk24mhz>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; rtc@170000 { diff --git a/arch/arm64/crypto/crc32-arm64.c b/arch/arm64/crypto/crc32-arm64.c index 9499199..6a37c3c 100644 --- a/arch/arm64/crypto/crc32-arm64.c +++ b/arch/arm64/crypto/crc32-arm64.c @@ -147,13 +147,21 @@ static int chksum_final(struct shash_desc *desc, u8 *out) { struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + put_unaligned_le32(ctx->crc, out); + return 0; +} + +static int chksumc_final(struct shash_desc *desc, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + put_unaligned_le32(~ctx->crc, out); return 0; } static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) { - put_unaligned_le32(~crc32_arm64_le_hw(crc, data, len), out); + put_unaligned_le32(crc32_arm64_le_hw(crc, data, len), out); return 0; } @@ -199,6 +207,14 @@ static int crc32_cra_init(struct crypto_tfm *tfm) { struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + mctx->key = 0; + return 0; +} + +static int crc32c_cra_init(struct crypto_tfm *tfm) +{ + struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + mctx->key = ~0; return 0; } @@ -229,7 +245,7 @@ static struct shash_alg crc32c_alg = { .setkey = chksum_setkey, .init = chksum_init, .update = chksumc_update, - .final = chksum_final, + .final = chksumc_final, .finup = chksumc_finup, .digest = chksumc_digest, .descsize = sizeof(struct chksum_desc_ctx), @@ -241,7 +257,7 @@ static struct shash_alg crc32c_alg = { .cra_alignmask = 0, .cra_ctxsize = sizeof(struct chksum_ctx), .cra_module = THIS_MODULE, - .cra_init = crc32_cra_init, + .cra_init = crc32c_cra_init, } }; diff --git a/arch/arm64/crypto/sha1-ce-glue.c b/arch/arm64/crypto/sha1-ce-glue.c index 114e7cc..aefda98 100644 --- a/arch/arm64/crypto/sha1-ce-glue.c +++ b/arch/arm64/crypto/sha1-ce-glue.c @@ -74,6 +74,9 @@ static int sha1_ce_finup(struct shash_desc *desc, const u8 *data, static int sha1_ce_final(struct shash_desc *desc, u8 *out) { + struct sha1_ce_state *sctx = shash_desc_ctx(desc); + + sctx->finalize = 0; kernel_neon_begin_partial(16); sha1_base_do_finalize(desc, (sha1_block_fn *)sha1_ce_transform); kernel_neon_end(); diff --git a/arch/arm64/crypto/sha2-ce-glue.c b/arch/arm64/crypto/sha2-ce-glue.c index 1340e44c..7cd5875 100644 --- a/arch/arm64/crypto/sha2-ce-glue.c +++ b/arch/arm64/crypto/sha2-ce-glue.c @@ -75,6 +75,9 @@ static int sha256_ce_finup(struct shash_desc *desc, const u8 *data, static int sha256_ce_final(struct shash_desc *desc, u8 *out) { + struct sha256_ce_state *sctx = shash_desc_ctx(desc); + + sctx->finalize = 0; kernel_neon_begin_partial(28); sha256_base_do_finalize(desc, (sha256_block_fn *)sha2_ce_transform); kernel_neon_end(); diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 21033bb..28f8365 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -24,7 +24,6 @@ #include <asm/cacheflush.h> #include <asm/alternative.h> #include <asm/cpufeature.h> -#include <asm/insn.h> #include <linux/stop_machine.h> extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; @@ -34,48 +33,6 @@ struct alt_region { struct alt_instr *end; }; -/* - * Decode the imm field of a b/bl instruction, and return the byte - * offset as a signed value (so it can be used when computing a new - * branch target). - */ -static s32 get_branch_offset(u32 insn) -{ - s32 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn); - - /* sign-extend the immediate before turning it into a byte offset */ - return (imm << 6) >> 4; -} - -static u32 get_alt_insn(u8 *insnptr, u8 *altinsnptr) -{ - u32 insn; - - aarch64_insn_read(altinsnptr, &insn); - - /* Stop the world on instructions we don't support... */ - BUG_ON(aarch64_insn_is_cbz(insn)); - BUG_ON(aarch64_insn_is_cbnz(insn)); - BUG_ON(aarch64_insn_is_bcond(insn)); - /* ... and there is probably more. */ - - if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) { - enum aarch64_insn_branch_type type; - unsigned long target; - - if (aarch64_insn_is_b(insn)) - type = AARCH64_INSN_BRANCH_NOLINK; - else - type = AARCH64_INSN_BRANCH_LINK; - - target = (unsigned long)altinsnptr + get_branch_offset(insn); - insn = aarch64_insn_gen_branch_imm((unsigned long)insnptr, - target, type); - } - - return insn; -} - static int __apply_alternatives(void *alt_region) { struct alt_instr *alt; @@ -83,9 +40,6 @@ static int __apply_alternatives(void *alt_region) u8 *origptr, *replptr; for (alt = region->begin; alt < region->end; alt++) { - u32 insn; - int i; - if (!cpus_have_cap(alt->cpufeature)) continue; @@ -95,12 +49,7 @@ static int __apply_alternatives(void *alt_region) origptr = (u8 *)&alt->orig_offset + alt->orig_offset; replptr = (u8 *)&alt->alt_offset + alt->alt_offset; - - for (i = 0; i < alt->alt_len; i += sizeof(insn)) { - insn = get_alt_insn(origptr + i, replptr + i); - aarch64_insn_write(origptr + i, insn); - } - + memcpy(origptr, replptr, alt->alt_len); flush_icache_range((uintptr_t)origptr, (uintptr_t)(origptr + alt->alt_len)); } diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 23f25ac..cce18c8 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -1315,15 +1315,15 @@ static int armpmu_device_probe(struct platform_device *pdev) if (!cpu_pmu) return -ENODEV; - irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); - if (!irqs) - return -ENOMEM; - /* Don't bother with PPIs; they're already affine */ irq = platform_get_irq(pdev, 0); if (irq >= 0 && irq_is_percpu(irq)) return 0; + irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); + if (!irqs) + return -ENOMEM; + for (i = 0; i < pdev->num_resources; ++i) { struct device_node *dn; int cpu; diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index 74c2567..f3d6221 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -328,10 +328,12 @@ static int ptdump_init(void) for (j = 0; j < pg_level[i].num; j++) pg_level[i].mask |= pg_level[i].bits[j].mask; +#ifdef CONFIG_SPARSEMEM_VMEMMAP address_markers[VMEMMAP_START_NR].start_address = (unsigned long)virt_to_page(PAGE_OFFSET); address_markers[VMEMMAP_END_NR].start_address = (unsigned long)virt_to_page(high_memory); +#endif pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops); diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index edba042..dc6a484 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -487,7 +487,7 @@ emit_cond_jmp: return -EINVAL; } - imm64 = (u64)insn1.imm << 32 | imm; + imm64 = (u64)insn1.imm << 32 | (u32)imm; emit_a64_mov_i64(dst, imm64, ctx); return 1; diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index ce7aea3..c18ddc7 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -45,7 +45,7 @@ static volatile unsigned long flushcache_cpumask = 0; /* * For flush_tlb_others() */ -static volatile cpumask_t flush_cpumask; +static cpumask_t flush_cpumask; static struct mm_struct *flush_mm; static struct vm_area_struct *flush_vma; static volatile unsigned long flush_va; @@ -415,7 +415,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, */ send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0); - while (!cpumask_empty((cpumask_t*)&flush_cpumask)) { + while (!cpumask_empty(&flush_cpumask)) { /* nothing. lockup detection does not belong here */ mb(); } @@ -468,7 +468,7 @@ void smp_invalidate_interrupt(void) __flush_tlb_page(va); } } - cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask); + cpumask_clear_cpu(cpu_id, &flush_cpumask); } /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 5200f64..ae2dd59 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -277,7 +277,7 @@ LDFLAGS += -m $(ld-emul) ifdef CONFIG_MIPS CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ - sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/") + sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g') ifdef CONFIG_64BIT CHECKFLAGS += -m64 endif diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index a594d8e..f19e890 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -304,7 +304,7 @@ do { \ \ current->thread.abi = &mips_abi; \ \ - current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31; \ + current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31; \ } while (0) #endif /* CONFIG_32BIT */ @@ -366,7 +366,7 @@ do { \ else \ current->thread.abi = &mips_abi; \ \ - current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31; \ + current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31; \ \ p = personality(current->personality); \ if (p != PER_LINUX32 && p != PER_LINUX) \ diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index bb02fac..2b25d1b 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -45,7 +45,7 @@ extern int __cpu_logical_map[NR_CPUS]; #define SMP_DUMP 0x8 #define SMP_ASK_C0COUNT 0x10 -extern volatile cpumask_t cpu_callin_map; +extern cpumask_t cpu_callin_map; /* Mask of CPUs which are currently definitely operating coherently */ extern cpumask_t cpu_coherent_mask; diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index be4899f..4a4d9e0 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -76,14 +76,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, /* Lets see if this is an O32 ELF */ if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) { - /* FR = 1 for N32 */ - if (ehdr32->e_flags & EF_MIPS_ABI2) - state->overall_fp_mode = FP_FR1; - else - /* Set a good default FPU mode for O32 */ - state->overall_fp_mode = cpu_has_mips_r6 ? - FP_FRE : FP_FR0; - if (ehdr32->e_flags & EF_MIPS_FP64) { /* * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it @@ -104,9 +96,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, (char *)&abiflags, sizeof(abiflags)); } else { - /* FR=1 is really the only option for 64-bit */ - state->overall_fp_mode = FP_FR1; - if (phdr64->p_type != PT_MIPS_ABIFLAGS) return 0; if (phdr64->p_filesz < sizeof(abiflags)) @@ -137,6 +126,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, struct elf32_hdr *ehdr = _ehdr; struct mode_req prog_req, interp_req; int fp_abi, interp_fp_abi, abi0, abi1, max_abi; + bool is_mips64; if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) return 0; @@ -152,10 +142,22 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, abi0 = abi1 = fp_abi; } - /* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */ - max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) && - (!(ehdr->e_flags & EF_MIPS_ABI2))) ? - MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT; + is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) || + (ehdr->e_flags & EF_MIPS_ABI2); + + if (is_mips64) { + /* MIPS64 code always uses FR=1, thus the default is easy */ + state->overall_fp_mode = FP_FR1; + + /* Disallow access to the various FPXX & FP64 ABIs */ + max_abi = MIPS_ABI_FP_SOFT; + } else { + /* Default to a mode capable of running code expecting FR=0 */ + state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0; + + /* Allow all ABIs we know about */ + max_abi = MIPS_ABI_FP_64A; + } if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) || (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index d544e77..e933a30 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -176,7 +176,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) __get_user(value, data + 64); fcr31 = child->thread.fpu.fcr31; - mask = current_cpu_data.fpu_msk31; + mask = boot_cpu_data.fpu_msk31; child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); /* FIR may not be written. */ diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 7e011f9..4251d39 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -92,7 +92,7 @@ static void __init cps_smp_setup(void) #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ if (cpu_has_fpu) - cpu_set(0, mt_fpu_cpumask); + cpumask_set_cpu(0, &mt_fpu_cpumask); #endif /* CONFIG_MIPS_MT_FPAFF */ } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 193ace7..faa46eb 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -43,7 +43,7 @@ #include <asm/time.h> #include <asm/setup.h> -volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ +cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ EXPORT_SYMBOL(__cpu_number_map); @@ -218,8 +218,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) /* * Trust is futile. We should really have timeouts ... */ - while (!cpumask_test_cpu(cpu, &cpu_callin_map)) + while (!cpumask_test_cpu(cpu, &cpu_callin_map)) { udelay(100); + schedule(); + } synchronise_count_master(cpu); return 0; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ba32e48..d2d1c19 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -269,7 +269,6 @@ static void __show_regs(const struct pt_regs *regs) */ printk("epc : %0*lx %pS\n", field, regs->cp0_epc, (void *) regs->cp0_epc); - printk(" %s\n", print_tainted()); printk("ra : %0*lx %pS\n", field, regs->regs[31], (void *) regs->regs[31]); diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index 6230f37..4b50c57 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -2389,7 +2389,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, { unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr]; enum emulation_result er = EMULATE_DONE; - unsigned long curr_pc; if (run->mmio.len > sizeof(*gpr)) { kvm_err("Bad MMIO length: %d", run->mmio.len); @@ -2397,11 +2396,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, goto done; } - /* - * Update PC and hold onto current PC in case there is - * an error and we want to rollback the PC - */ - curr_pc = vcpu->arch.pc; er = update_pc(vcpu, vcpu->arch.pending_load_cause); if (er == EMULATE_FAIL) return er; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index d31c537..22b9b2c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -889,7 +889,7 @@ static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; case FPCREG_RID: - value = current_cpu_data.fpu_id; + value = boot_cpu_data.fpu_id; break; default: @@ -921,7 +921,7 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); /* Preserve read-only bits. */ - mask = current_cpu_data.fpu_msk31; + mask = boot_cpu_data.fpu_msk31; fcr31 = (value & ~mask) | (fcr31 & mask); break; diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index a27a088..08318ec 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -495,7 +495,7 @@ static void r4k_tlb_configure(void) if (cpu_has_rixi) { /* - * Enable the no read, no exec bits, and enable large virtual + * Enable the no read, no exec bits, and enable large physical * address. */ #ifdef CONFIG_64BIT diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c index 0134db2..5a2a821 100644 --- a/arch/mips/sgi-ip32/ip32-platform.c +++ b/arch/mips/sgi-ip32/ip32-platform.c @@ -130,9 +130,9 @@ struct platform_device ip32_rtc_device = { .resource = ip32_rtc_resources, }; -+static int __init sgio2_rtc_devinit(void) +static __init int sgio2_rtc_devinit(void) { return platform_device_register(&ip32_rtc_device); } -device_initcall(sgio2_cmos_devinit); +device_initcall(sgio2_rtc_devinit); diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 3391d06..78c9fd3 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h @@ -348,6 +348,10 @@ struct pt_regs; /* forward declaration... */ #define ELF_HWCAP 0 +#define STACK_RND_MASK (is_32bit_task() ? \ + 0x7ff >> (PAGE_SHIFT - 12) : \ + 0x3ffff >> (PAGE_SHIFT - 12)) + struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *); #define arch_randomize_brk arch_randomize_brk diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 8a488c2..809905a 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -181,9 +181,12 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) return 1; } +/* + * Copy architecture-specific thread state + */ int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long arg, struct task_struct *p) + unsigned long kthread_arg, struct task_struct *p) { struct pt_regs *cregs = &(p->thread.regs); void *stack = task_stack_page(p); @@ -195,11 +198,10 @@ copy_thread(unsigned long clone_flags, unsigned long usp, extern void * const child_return; if (unlikely(p->flags & PF_KTHREAD)) { + /* kernel thread */ memset(cregs, 0, sizeof(struct pt_regs)); if (!usp) /* idle thread */ return 0; - - /* kernel thread */ /* Must exit via ret_from_kernel_thread in order * to call schedule_tail() */ @@ -215,7 +217,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, #else cregs->gr[26] = usp; #endif - cregs->gr[25] = arg; + cregs->gr[25] = kthread_arg; } else { /* user thread */ /* usp must be word aligned. This also prevents users from diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index e1ffea2..5aba01a 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -77,6 +77,9 @@ static unsigned long mmap_upper_limit(void) if (stack_base > STACK_SIZE_MAX) stack_base = STACK_SIZE_MAX; + /* Add space for stack randomization. */ + stack_base += (STACK_RND_MASK << PAGE_SHIFT); + return PAGE_ALIGN(STACK_TOP - stack_base); } diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index ef17683..48304b8 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -1109,6 +1109,8 @@ struct boot_params *make_boot_params(struct efi_config *c) if (!cmdline_ptr) goto fail; hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; + /* Fill in upper bits of command line address, NOP on 32 bit */ + boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32; hdr->ramdisk_image = 0; hdr->ramdisk_size = 0; diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index e42f758..055ea99 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h @@ -50,7 +50,7 @@ extern const struct hypervisor_x86 *x86_hyper; /* Recognized hypervisors */ extern const struct hypervisor_x86 x86_hyper_vmware; extern const struct hypervisor_x86 x86_hyper_ms_hyperv; -extern const struct hypervisor_x86 x86_hyper_xen_hvm; +extern const struct hypervisor_x86 x86_hyper_xen; extern const struct hypervisor_x86 x86_hyper_kvm; extern void init_hypervisor(struct cpuinfo_x86 *c); diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h index cf87de3..64b6117 100644 --- a/arch/x86/include/asm/spinlock.h +++ b/arch/x86/include/asm/spinlock.h @@ -169,7 +169,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock) struct __raw_tickets tmp = READ_ONCE(lock->tickets); tmp.head &= ~TICKET_SLOWPATH_FLAG; - return (tmp.tail - tmp.head) > TICKET_LOCK_INC; + return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC; } #define arch_spin_is_contended arch_spin_is_contended diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 358dcd3..c44a5d5 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -269,4 +269,9 @@ static inline bool xen_arch_need_swiotlb(struct device *dev, return false; } +static inline unsigned long xen_get_swiotlb_free_pages(unsigned int order) +{ + return __get_free_pages(__GFP_NOWARN, order); +} + #endif /* _ASM_X86_XEN_PAGE_H */ diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index 36ce402..d820d8e 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c @@ -27,8 +27,8 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = { -#ifdef CONFIG_XEN_PVHVM - &x86_hyper_xen_hvm, +#ifdef CONFIG_XEN + &x86_hyper_xen, #endif &x86_hyper_vmware, &x86_hyper_ms_hyperv, diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 219d3fb..3998131 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1134,7 +1134,7 @@ static __initconst const u64 slm_hw_cache_extra_regs [ C(LL ) ] = { [ C(OP_READ) ] = { [ C(RESULT_ACCESS) ] = SLM_DMND_READ|SLM_LLC_ACCESS, - [ C(RESULT_MISS) ] = SLM_DMND_READ|SLM_LLC_MISS, + [ C(RESULT_MISS) ] = 0, }, [ C(OP_WRITE) ] = { [ C(RESULT_ACCESS) ] = SLM_DMND_WRITE|SLM_LLC_ACCESS, @@ -1184,8 +1184,7 @@ static __initconst const u64 slm_hw_cache_event_ids [ C(OP_READ) ] = { /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01b7, + [ C(RESULT_MISS) ] = 0, }, [ C(OP_WRITE) ] = { /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ @@ -1217,7 +1216,7 @@ static __initconst const u64 slm_hw_cache_event_ids [ C(ITLB) ] = { [ C(OP_READ) ] = { [ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */ - [ C(RESULT_MISS) ] = 0x0282, /* ITLB.MISSES */ + [ C(RESULT_MISS) ] = 0x40205, /* PAGE_WALKS.I_SIDE_WALKS */ }, [ C(OP_WRITE) ] = { [ C(RESULT_ACCESS) ] = -1, @@ -2533,34 +2532,6 @@ ssize_t intel_event_sysfs_show(char *page, u64 config) return x86_event_sysfs_show(page, config, event); } -static __initconst const struct x86_pmu core_pmu = { - .name = "core", - .handle_irq = x86_pmu_handle_irq, - .disable_all = x86_pmu_disable_all, - .enable_all = core_pmu_enable_all, - .enable = core_pmu_enable_event, - .disable = x86_pmu_disable_event, - .hw_config = x86_pmu_hw_config, - .schedule_events = x86_schedule_events, - .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, - .perfctr = MSR_ARCH_PERFMON_PERFCTR0, - .event_map = intel_pmu_event_map, - .max_events = ARRAY_SIZE(intel_perfmon_event_map), - .apic = 1, - /* - * Intel PMCs cannot be accessed sanely above 32 bit width, - * so we install an artificial 1<<31 period regardless of - * the generic event period: - */ - .max_period = (1ULL << 31) - 1, - .get_event_constraints = intel_get_event_constraints, - .put_event_constraints = intel_put_event_constraints, - .event_constraints = intel_core_event_constraints, - .guest_get_msrs = core_guest_get_msrs, - .format_attrs = intel_arch_formats_attr, - .events_sysfs_show = intel_event_sysfs_show, -}; - struct intel_shared_regs *allocate_shared_regs(int cpu) { struct intel_shared_regs *regs; @@ -2743,6 +2714,44 @@ static struct attribute *intel_arch3_formats_attr[] = { NULL, }; +static __initconst const struct x86_pmu core_pmu = { + .name = "core", + .handle_irq = x86_pmu_handle_irq, + .disable_all = x86_pmu_disable_all, + .enable_all = core_pmu_enable_all, + .enable = core_pmu_enable_event, + .disable = x86_pmu_disable_event, + .hw_config = x86_pmu_hw_config, + .schedule_events = x86_schedule_events, + .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, + .perfctr = MSR_ARCH_PERFMON_PERFCTR0, + .event_map = intel_pmu_event_map, + .max_events = ARRAY_SIZE(intel_perfmon_event_map), + .apic = 1, + /* + * Intel PMCs cannot be accessed sanely above 32-bit width, + * so we install an artificial 1<<31 period regardless of + * the generic event period: + */ + .max_period = (1ULL<<31) - 1, + .get_event_constraints = intel_get_event_constraints, + .put_event_constraints = intel_put_event_constraints, + .event_constraints = intel_core_event_constraints, + .guest_get_msrs = core_guest_get_msrs, + .format_attrs = intel_arch_formats_attr, + .events_sysfs_show = intel_event_sysfs_show, + + /* + * Virtual (or funny metal) CPU can define x86_pmu.extra_regs + * together with PMU version 1 and thus be using core_pmu with + * shared_regs. We need following callbacks here to allocate + * it properly. + */ + .cpu_prepare = intel_pmu_cpu_prepare, + .cpu_starting = intel_pmu_cpu_starting, + .cpu_dying = intel_pmu_cpu_dying, +}; + static __initconst const struct x86_pmu intel_pmu = { .name = "Intel", .handle_irq = intel_pmu_handle_irq, diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c index 999289b9..358c54a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c @@ -722,6 +722,7 @@ static int __init rapl_pmu_init(void) break; case 60: /* Haswell */ case 69: /* Haswell-Celeron */ + case 61: /* Broadwell */ rapl_cntr_mask = RAPL_IDX_HSW; rapl_pmu_events_group.attrs = rapl_events_hsw_attr; break; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c index 3001015..4562e9e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c @@ -1,6 +1,13 @@ /* Nehalem/SandBridge/Haswell uncore support */ #include "perf_event_intel_uncore.h" +/* Uncore IMC PCI IDs */ +#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 +#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 +#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150 +#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00 +#define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04 + /* SNB event control */ #define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff #define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 @@ -472,6 +479,10 @@ static const struct pci_device_id hsw_uncore_pci_ids[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC), .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), }, + { /* IMC */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_U_IMC), + .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), + }, { /* end: all zeroes */ }, }; @@ -502,6 +513,7 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = { IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver), /* 3rd Gen Core processor */ IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */ IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core Processor */ + IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core ULT Mobile Processor */ { /* end marker */ } }; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 8213da6..6e338e3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -57,7 +57,7 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { .io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 }, #endif }; -EXPORT_PER_CPU_SYMBOL_GPL(cpu_tss); +EXPORT_PER_CPU_SYMBOL(cpu_tss); #ifdef CONFIG_X86_64 static DEFINE_PER_CPU(unsigned char, is_idle); @@ -156,11 +156,13 @@ void flush_thread(void) /* FPU state will be reallocated lazily at the first use. */ drop_fpu(tsk); free_thread_xstate(tsk); - } else if (!used_math()) { - /* kthread execs. TODO: cleanup this horror. */ - if (WARN_ON(init_fpu(tsk))) - force_sig(SIGKILL, tsk); - user_fpu_begin(); + } else { + if (!tsk_used_math(tsk)) { + /* kthread execs. TODO: cleanup this horror. */ + if (WARN_ON(init_fpu(tsk))) + force_sig(SIGKILL, tsk); + user_fpu_begin(); + } restore_init_xstate(); } } diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 5ead4d6c..70e7444 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -351,18 +351,20 @@ int arch_ioremap_pmd_supported(void) */ void *xlate_dev_mem_ptr(phys_addr_t phys) { - void *addr; - unsigned long start = phys & PAGE_MASK; + unsigned long start = phys & PAGE_MASK; + unsigned long offset = phys & ~PAGE_MASK; + unsigned long vaddr; /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */ if (page_is_ram(start >> PAGE_SHIFT)) return __va(phys); - addr = (void __force *)ioremap_cache(start, PAGE_SIZE); - if (addr) - addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK)); + vaddr = (unsigned long)ioremap_cache(start, PAGE_SIZE); + /* Only add the offset on success and return NULL if the ioremap() failed: */ + if (vaddr) + vaddr += offset; - return addr; + return (void *)vaddr; } void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 9875143..99f7610 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -559,6 +559,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, if (is_ereg(dst_reg)) EMIT1(0x41); EMIT3(0xC1, add_1reg(0xC8, dst_reg), 8); + + /* emit 'movzwl eax, ax' */ + if (is_ereg(dst_reg)) + EMIT3(0x45, 0x0F, 0xB7); + else + EMIT2(0x0F, 0xB7); + EMIT1(add_2reg(0xC0, dst_reg, dst_reg)); break; case 32: /* emit 'bswap eax' to swap lower 4 bytes */ @@ -577,6 +584,27 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, break; case BPF_ALU | BPF_END | BPF_FROM_LE: + switch (imm32) { + case 16: + /* emit 'movzwl eax, ax' to zero extend 16-bit + * into 64 bit + */ + if (is_ereg(dst_reg)) + EMIT3(0x45, 0x0F, 0xB7); + else + EMIT2(0x0F, 0xB7); + EMIT1(add_2reg(0xC0, dst_reg, dst_reg)); + break; + case 32: + /* emit 'mov eax, eax' to clear upper 32-bits */ + if (is_ereg(dst_reg)) + EMIT1(0x45); + EMIT2(0x89, add_2reg(0xC0, dst_reg, dst_reg)); + break; + case 64: + /* nop */ + break; + } break; /* ST: *(u8*)(dst_reg + off) = imm */ diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index e469598..d939633 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -325,6 +325,26 @@ static void release_pci_root_info(struct pci_host_bridge *bridge) kfree(info); } +/* + * An IO port or MMIO resource assigned to a PCI host bridge may be + * consumed by the host bridge itself or available to its child + * bus/devices. The ACPI specification defines a bit (Producer/Consumer) + * to tell whether the resource is consumed by the host bridge itself, + * but firmware hasn't used that bit consistently, so we can't rely on it. + * + * On x86 and IA64 platforms, all IO port and MMIO resources are assumed + * to be available to child bus/devices except one special case: + * IO port [0xCF8-0xCFF] is consumed by the host bridge itself + * to access PCI configuration space. + * + * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF]. + */ +static bool resource_is_pcicfg_ioport(struct resource *res) +{ + return (res->flags & IORESOURCE_IO) && + res->start == 0xCF8 && res->end == 0xCFF; +} + static void probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, int busnum, int domain, @@ -346,8 +366,8 @@ static void probe_pci_root_info(struct pci_root_info *info, "no IO and memory resources present in _CRS\n"); else resource_list_for_each_entry_safe(entry, tmp, list) { - if ((entry->res->flags & IORESOURCE_WINDOW) == 0 || - (entry->res->flags & IORESOURCE_DISABLED)) + if ((entry->res->flags & IORESOURCE_DISABLED) || + resource_is_pcicfg_ioport(entry->res)) resource_list_destroy_entry(entry); else entry->res->name = info->name; diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 275a3a8..e970320 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -51,7 +51,7 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ $(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE $(call if_changed,vdso) -HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi +HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi -I$(srctree)/arch/x86/include/uapi hostprogs-y += vdso2c quiet_cmd_vdso2c = VDSO2C $@ diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 94578ef..46957ea 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1760,6 +1760,9 @@ static struct notifier_block xen_hvm_cpu_notifier = { static void __init xen_hvm_guest_init(void) { + if (xen_pv_domain()) + return; + init_hvm_pv_info(); xen_hvm_init_shared_info(); @@ -1775,6 +1778,7 @@ static void __init xen_hvm_guest_init(void) xen_hvm_init_time_ops(); xen_hvm_init_mmu_ops(); } +#endif static bool xen_nopv = false; static __init int xen_parse_nopv(char *arg) @@ -1784,14 +1788,11 @@ static __init int xen_parse_nopv(char *arg) } early_param("xen_nopv", xen_parse_nopv); -static uint32_t __init xen_hvm_platform(void) +static uint32_t __init xen_platform(void) { if (xen_nopv) return 0; - if (xen_pv_domain()) - return 0; - return xen_cpuid_base(); } @@ -1809,11 +1810,19 @@ bool xen_hvm_need_lapic(void) } EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); -const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = { - .name = "Xen HVM", - .detect = xen_hvm_platform, +static void xen_set_cpu_features(struct cpuinfo_x86 *c) +{ + if (xen_pv_domain()) + clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); +} + +const struct hypervisor_x86 x86_hyper_xen = { + .name = "Xen", + .detect = xen_platform, +#ifdef CONFIG_XEN_PVHVM .init_platform = xen_hvm_guest_init, +#endif .x2apic_available = xen_x2apic_para_available, + .set_cpu_features = xen_set_cpu_features, }; -EXPORT_SYMBOL(x86_hyper_xen_hvm); -#endif +EXPORT_SYMBOL(x86_hyper_xen); diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index d949769..53b4c08 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -88,7 +88,17 @@ static void xen_vcpu_notify_restore(void *data) tick_resume_local(); } +static void xen_vcpu_notify_suspend(void *data) +{ + tick_suspend_local(); +} + void xen_arch_resume(void) { on_each_cpu(xen_vcpu_notify_restore, NULL, 1); } + +void xen_arch_suspend(void) +{ + on_each_cpu(xen_vcpu_notify_suspend, NULL, 1); +} diff --git a/block/blk-core.c b/block/blk-core.c index fd154b9..7871603 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -552,6 +552,8 @@ void blk_cleanup_queue(struct request_queue *q) q->queue_lock = &q->__queue_lock; spin_unlock_irq(lock); + bdi_destroy(&q->backing_dev_info); + /* @q is and will stay empty, shutdown and put */ blk_put_queue(q); } diff --git a/block/blk-mq.c b/block/blk-mq.c index ade8a2d..e68b71b 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -677,8 +677,11 @@ static void blk_mq_rq_timer(unsigned long priv) data.next = blk_rq_timeout(round_jiffies_up(data.next)); mod_timer(&q->timeout, data.next); } else { - queue_for_each_hw_ctx(q, hctx, i) - blk_mq_tag_idle(hctx); + queue_for_each_hw_ctx(q, hctx, i) { + /* the hctx may be unmapped, so check it here */ + if (blk_mq_hw_queue_mapped(hctx)) + blk_mq_tag_idle(hctx); + } } } @@ -855,6 +858,16 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) spin_lock(&hctx->lock); list_splice(&rq_list, &hctx->dispatch); spin_unlock(&hctx->lock); + /* + * the queue is expected stopped with BLK_MQ_RQ_QUEUE_BUSY, but + * it's possible the queue is stopped and restarted again + * before this. Queue restart will dispatch requests. And since + * requests in rq_list aren't added into hctx->dispatch yet, + * the requests in rq_list might get lost. + * + * blk_mq_run_hw_queue() already checks the STOPPED bit + **/ + blk_mq_run_hw_queue(hctx, true); } } @@ -1571,22 +1584,6 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu) return NOTIFY_OK; } -static int blk_mq_hctx_cpu_online(struct blk_mq_hw_ctx *hctx, int cpu) -{ - struct request_queue *q = hctx->queue; - struct blk_mq_tag_set *set = q->tag_set; - - if (set->tags[hctx->queue_num]) - return NOTIFY_OK; - - set->tags[hctx->queue_num] = blk_mq_init_rq_map(set, hctx->queue_num); - if (!set->tags[hctx->queue_num]) - return NOTIFY_STOP; - - hctx->tags = set->tags[hctx->queue_num]; - return NOTIFY_OK; -} - static int blk_mq_hctx_notify(void *data, unsigned long action, unsigned int cpu) { @@ -1594,8 +1591,11 @@ static int blk_mq_hctx_notify(void *data, unsigned long action, if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) return blk_mq_hctx_cpu_offline(hctx, cpu); - else if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) - return blk_mq_hctx_cpu_online(hctx, cpu); + + /* + * In case of CPU online, tags may be reallocated + * in blk_mq_map_swqueue() after mapping is updated. + */ return NOTIFY_OK; } @@ -1775,6 +1775,7 @@ static void blk_mq_map_swqueue(struct request_queue *q) unsigned int i; struct blk_mq_hw_ctx *hctx; struct blk_mq_ctx *ctx; + struct blk_mq_tag_set *set = q->tag_set; queue_for_each_hw_ctx(q, hctx, i) { cpumask_clear(hctx->cpumask); @@ -1803,16 +1804,20 @@ static void blk_mq_map_swqueue(struct request_queue *q) * disable it and free the request entries. */ if (!hctx->nr_ctx) { - struct blk_mq_tag_set *set = q->tag_set; - if (set->tags[i]) { blk_mq_free_rq_map(set, set->tags[i], i); set->tags[i] = NULL; - hctx->tags = NULL; } + hctx->tags = NULL; continue; } + /* unmapped hw queue can be remapped after CPU topo changed */ + if (!set->tags[i]) + set->tags[i] = blk_mq_init_rq_map(set, i); + hctx->tags = set->tags[i]; + WARN_ON(!hctx->tags); + /* * Set the map size to the number of mapped software queues. * This is more accurate and more efficient than looping @@ -2090,9 +2095,16 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb, */ list_for_each_entry(q, &all_q_list, all_q_node) blk_mq_freeze_queue_start(q); - list_for_each_entry(q, &all_q_list, all_q_node) + list_for_each_entry(q, &all_q_list, all_q_node) { blk_mq_freeze_queue_wait(q); + /* + * timeout handler can't touch hw queue during the + * reinitialization + */ + del_timer_sync(&q->timeout); + } + list_for_each_entry(q, &all_q_list, all_q_node) blk_mq_queue_reinit(q); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index faaf36a..2b8fd30 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -522,8 +522,6 @@ static void blk_release_queue(struct kobject *kobj) blk_trace_shutdown(q); - bdi_destroy(&q->backing_dev_info); - ida_simple_remove(&blk_queue_ida, q->id); call_rcu(&q->rcu_head, blk_free_queue_rcu); } diff --git a/block/bounce.c b/block/bounce.c index ab21ba2..ed9dd80 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -221,8 +221,8 @@ bounce: if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force) continue; - inc_zone_page_state(to->bv_page, NR_BOUNCE); to->bv_page = mempool_alloc(pool, q->bounce_gfp); + inc_zone_page_state(to->bv_page, NR_BOUNCE); if (rw == WRITE) { char *vto, *vfrom; diff --git a/block/elevator.c b/block/elevator.c index 59794d0..8985038 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -157,7 +157,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q, eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, q->node); if (unlikely(!eq)) - goto err; + return NULL; eq->type = e; kobject_init(&eq->kobj, &elv_ktype); @@ -165,10 +165,6 @@ struct elevator_queue *elevator_alloc(struct request_queue *q, hash_init(eq->hash); return eq; -err: - kfree(eq); - elevator_put(e); - return NULL; } EXPORT_SYMBOL(elevator_alloc); diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index b193f84..ff6d8ad 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -304,6 +304,8 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { {"PNPb006"}, /* cs423x-pnpbios */ {"CSC0100"}, + {"CSC0103"}, + {"CSC0110"}, {"CSC0000"}, {"GIM0100"}, /* Guillemot Turtlebeach something appears to be cs4232 compatible */ /* es18xx-pnpbios */ diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index a72685c..5e8df91 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -102,19 +102,12 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_TZ_", ACPI_TYPE_DEVICE, NULL}, - /* - * March, 2015: - * The _REV object is in the process of being deprecated, because - * other ACPI implementations permanently return 2. Thus, it - * has little or no value. Return 2 for compatibility with - * other ACPI implementations. - */ - {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR(char, 2)}, + {"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, - {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR(char, 1)}, + {"_GL_", ACPI_TYPE_MUTEX, (char *)1}, #if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) - {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR(char, 1)}, + {"_OSI", ACPI_TYPE_METHOD, (char *)1}, #endif /* Table terminator */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 39748bb..7ccba39 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -182,7 +182,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas, request_mem_region(addr, length, desc); } -static int __init acpi_reserve_resources(void) +static void __init acpi_reserve_resources(void) { acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, "ACPI PM1a_EVT_BLK"); @@ -211,10 +211,7 @@ static int __init acpi_reserve_resources(void) if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) acpi_request_region(&acpi_gbl_FADT.xgpe1_block, acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); - - return 0; } -device_initcall(acpi_reserve_resources); void acpi_os_printf(const char *fmt, ...) { @@ -1845,6 +1842,7 @@ acpi_status __init acpi_os_initialize(void) acpi_status __init acpi_os_initialize1(void) { + acpi_reserve_resources(); kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 5589a6e..8244f01 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_get_resources); * @ares: Input ACPI resource object. * @types: Valid resource types of IORESOURCE_XXX * - * This is a hepler function to support acpi_dev_get_resources(), which filters + * This is a helper function to support acpi_dev_get_resources(), which filters * ACPI resource objects according to resource types. */ int acpi_dev_filter_resource_type(struct acpi_resource *ares, diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 26e5b50..bf034f8 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/dmi.h> #include "sbshc.h" #define PREFIX "ACPI: " @@ -87,6 +88,8 @@ enum acpi_smb_offset { ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ }; +static bool macbook; + static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) { return ec_read(hc->offset + address, data); @@ -132,6 +135,8 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, } mutex_lock(&hc->lock); + if (macbook) + udelay(5); if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) goto end; if (temp) { @@ -257,12 +262,29 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data); +static int macbook_dmi_match(const struct dmi_system_id *d) +{ + pr_debug("Detected MacBook, enabling workaround\n"); + macbook = true; + return 0; +} + +static struct dmi_system_id acpi_smbus_dmi_table[] = { + { macbook_dmi_match, "Apple MacBook", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") }, + }, + { }, +}; + static int acpi_smbus_hc_add(struct acpi_device *device) { int status; unsigned long long val; struct acpi_smb_hc *hc; + dmi_check_system(acpi_smbus_dmi_table); + if (!device) return -EINVAL; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 5f60155..9dca4b9 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -270,6 +270,7 @@ config ATA_PIIX config SATA_DWC tristate "DesignWare Cores SATA support" depends on 460EX + select DW_DMAC help This option enables support for the on-chip SATA controller of the AppliedMicro processor 460EX. @@ -729,15 +730,6 @@ config PATA_SC1200 If unsure, say N. -config PATA_SCC - tristate "Toshiba's Cell Reference Set IDE support" - depends on PCI && PPC_CELLEB - help - This option enables support for the built-in IDE controller on - Toshiba Cell Reference Board. - - If unsure, say N. - config PATA_SCH tristate "Intel SCH PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index b67e995..40f7865 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -75,7 +75,6 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o obj-$(CONFIG_PATA_RDC) += pata_rdc.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o -obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_SCH) += pata_sch.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o obj-$(CONFIG_PATA_SIL680) += pata_sil680.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c7a92a7..65ee944 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -66,6 +66,7 @@ enum board_ids { board_ahci_yes_fbs, /* board IDs for specific chipsets in alphabetical order */ + board_ahci_avn, board_ahci_mcp65, board_ahci_mcp77, board_ahci_mcp89, @@ -84,6 +85,8 @@ enum board_ids { static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); +static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void ahci_mcp89_apple_enable(struct pci_dev *pdev); static bool is_mcp89_apple(struct pci_dev *pdev); static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, @@ -107,6 +110,11 @@ static struct ata_port_operations ahci_p5wdh_ops = { .hardreset = ahci_p5wdh_hardreset, }; +static struct ata_port_operations ahci_avn_ops = { + .inherits = &ahci_ops, + .hardreset = ahci_avn_hardreset, +}; + static const struct ata_port_info ahci_port_info[] = { /* by features */ [board_ahci] = { @@ -151,6 +159,12 @@ static const struct ata_port_info ahci_port_info[] = { .port_ops = &ahci_ops, }, /* by chipsets */ + [board_ahci_avn] = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_avn_ops, + }, [board_ahci_mcp65] = { AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), @@ -290,14 +304,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */ - { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */ - { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ @@ -670,6 +684,79 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, return rc; } +/* + * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports. + * + * It has been observed with some SSDs that the timing of events in the + * link synchronization phase can leave the port in a state that can not + * be recovered by a SATA-hard-reset alone. The failing signature is + * SStatus.DET stuck at 1 ("Device presence detected but Phy + * communication not established"). It was found that unloading and + * reloading the driver when this problem occurs allows the drive + * connection to be recovered (DET advanced to 0x3). The critical + * component of reloading the driver is that the port state machines are + * reset by bouncing "port enable" in the AHCI PCS configuration + * register. So, reproduce that effect by bouncing a port whenever we + * see DET==1 after a reset. + */ +static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + unsigned long tmo = deadline - jiffies; + struct ata_taskfile tf; + bool online; + int rc, i; + + DPRINTK("ENTER\n"); + + ahci_stop_engine(ap); + + for (i = 0; i < 2; i++) { + u16 val; + u32 sstatus; + int port = ap->port_no; + struct ata_host *host = ap->host; + struct pci_dev *pdev = to_pci_dev(host->dev); + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = ATA_BUSY; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + + rc = sata_link_hardreset(link, timing, deadline, &online, + ahci_check_ready); + + if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 || + (sstatus & 0xf) != 1) + break; + + ata_link_printk(link, KERN_INFO, "avn bounce port%d\n", + port); + + pci_read_config_word(pdev, 0x92, &val); + val &= ~(1 << port); + pci_write_config_word(pdev, 0x92, val); + ata_msleep(ap, 1000); + val |= 1 << port; + pci_write_config_word(pdev, 0x92, val); + deadline += tmo; + } + + hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + return rc; +} + + #ifdef CONFIG_PM static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index ea0ff00..8ff428f 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -37,7 +37,6 @@ struct st_ahci_drv_data { struct reset_control *pwr; struct reset_control *sw_rst; struct reset_control *pwr_rst; - struct ahci_host_priv *hpriv; }; static void st_ahci_configure_oob(void __iomem *mmio) @@ -55,9 +54,10 @@ static void st_ahci_configure_oob(void __iomem *mmio) writel(new_val, mmio + ST_AHCI_OOBR); } -static int st_ahci_deassert_resets(struct device *dev) +static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv, + struct device *dev) { - struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); + struct st_ahci_drv_data *drv_data = hpriv->plat_data; int err; if (drv_data->pwr) { @@ -90,8 +90,8 @@ static int st_ahci_deassert_resets(struct device *dev) static void st_ahci_host_stop(struct ata_host *host) { struct ahci_host_priv *hpriv = host->private_data; + struct st_ahci_drv_data *drv_data = hpriv->plat_data; struct device *dev = host->dev; - struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); int err; if (drv_data->pwr) { @@ -103,29 +103,30 @@ static void st_ahci_host_stop(struct ata_host *host) ahci_platform_disable_resources(hpriv); } -static int st_ahci_probe_resets(struct platform_device *pdev) +static int st_ahci_probe_resets(struct ahci_host_priv *hpriv, + struct device *dev) { - struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev); + struct st_ahci_drv_data *drv_data = hpriv->plat_data; - drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn"); + drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn"); if (IS_ERR(drv_data->pwr)) { - dev_info(&pdev->dev, "power reset control not defined\n"); + dev_info(dev, "power reset control not defined\n"); drv_data->pwr = NULL; } - drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst"); + drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst"); if (IS_ERR(drv_data->sw_rst)) { - dev_info(&pdev->dev, "soft reset control not defined\n"); + dev_info(dev, "soft reset control not defined\n"); drv_data->sw_rst = NULL; } - drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst"); + drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst"); if (IS_ERR(drv_data->pwr_rst)) { - dev_dbg(&pdev->dev, "power soft reset control not defined\n"); + dev_dbg(dev, "power soft reset control not defined\n"); drv_data->pwr_rst = NULL; } - return st_ahci_deassert_resets(&pdev->dev); + return st_ahci_deassert_resets(hpriv, dev); } static struct ata_port_operations st_ahci_port_ops = { @@ -154,15 +155,12 @@ static int st_ahci_probe(struct platform_device *pdev) if (!drv_data) return -ENOMEM; - platform_set_drvdata(pdev, drv_data); - hpriv = ahci_platform_get_resources(pdev); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); + hpriv->plat_data = drv_data; - drv_data->hpriv = hpriv; - - err = st_ahci_probe_resets(pdev); + err = st_ahci_probe_resets(hpriv, &pdev->dev); if (err) return err; @@ -170,7 +168,7 @@ static int st_ahci_probe(struct platform_device *pdev) if (err) return err; - st_ahci_configure_oob(drv_data->hpriv->mmio); + st_ahci_configure_oob(hpriv->mmio); err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, &ahci_platform_sht); @@ -185,8 +183,9 @@ static int st_ahci_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int st_ahci_suspend(struct device *dev) { - struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); - struct ahci_host_priv *hpriv = drv_data->hpriv; + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + struct st_ahci_drv_data *drv_data = hpriv->plat_data; int err; err = ahci_platform_suspend_host(dev); @@ -208,21 +207,21 @@ static int st_ahci_suspend(struct device *dev) static int st_ahci_resume(struct device *dev) { - struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); - struct ahci_host_priv *hpriv = drv_data->hpriv; + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; int err; err = ahci_platform_enable_resources(hpriv); if (err) return err; - err = st_ahci_deassert_resets(dev); + err = st_ahci_deassert_resets(hpriv, dev); if (err) { ahci_platform_disable_resources(hpriv); return err; } - st_ahci_configure_oob(drv_data->hpriv->mmio); + st_ahci_configure_oob(hpriv->mmio); return ahci_platform_resume_host(dev); } diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 61a9c07..287c4ba 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1707,8 +1707,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, if (unlikely(resetting)) status &= ~PORT_IRQ_BAD_PMP; - /* if LPM is enabled, PHYRDY doesn't mean anything */ - if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) { + if (sata_lpm_ignore_phy_events(&ap->link)) { status &= ~PORT_IRQ_PHYRDY; ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f6cb1f1..577849c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4235,7 +4235,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, - { "Samsung SSD 850 PRO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + { "Samsung SSD 8*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, /* @@ -6752,6 +6752,38 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, return tmp; } +/** + * sata_lpm_ignore_phy_events - test if PHY event should be ignored + * @link: Link receiving the event + * + * Test whether the received PHY event has to be ignored or not. + * + * LOCKING: + * None: + * + * RETURNS: + * True if the event has to be ignored. + */ +bool sata_lpm_ignore_phy_events(struct ata_link *link) +{ + unsigned long lpm_timeout = link->last_lpm_change + + msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); + + /* if LPM is enabled, PHYRDY doesn't mean anything */ + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return true; + + /* ignore the first PHY event after the LPM policy changed + * as it is might be spurious + */ + if ((link->flags & ATA_LFLAG_CHANGED) && + time_before(jiffies, lpm_timeout)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); + /* * Dummy port_ops */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 07f41be..cf0022e 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3597,6 +3597,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } + link->last_lpm_change = jiffies; + link->flags |= ATA_LFLAG_CHANGED; + return 0; fail: diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c deleted file mode 100644 index 5cd60d6..0000000 --- a/drivers/ata/pata_scc.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* - * Support for IDE interfaces on Celleb platform - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/ata/ata_piix.c: - * Copyright 2003-2005 Red Hat Inc - * Copyright 2003-2005 Jeff Garzik - * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2003 Red Hat Inc - * - * and drivers/ata/ahci.c: - * Copyright 2004-2005 Red Hat, Inc. - * - * and drivers/ata/libata-core.c: - * Copyright 2003-2004 Red Hat, Inc. All rights reserved. - * Copyright 2003-2004 Jeff Garzik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <scsi/scsi_host.h> -#include <linux/libata.h> - -#define DRV_NAME "pata_scc" -#define DRV_VERSION "0.3" - -#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 - -/* PCI BARs */ -#define SCC_CTRL_BAR 0 -#define SCC_BMID_BAR 1 - -/* offset of CTRL registers */ -#define SCC_CTL_PIOSHT 0x000 -#define SCC_CTL_PIOCT 0x004 -#define SCC_CTL_MDMACT 0x008 -#define SCC_CTL_MCRCST 0x00C -#define SCC_CTL_SDMACT 0x010 -#define SCC_CTL_SCRCST 0x014 -#define SCC_CTL_UDENVT 0x018 -#define SCC_CTL_TDVHSEL 0x020 -#define SCC_CTL_MODEREG 0x024 -#define SCC_CTL_ECMODE 0xF00 -#define SCC_CTL_MAEA0 0xF50 -#define SCC_CTL_MAEC0 0xF54 -#define SCC_CTL_CCKCTRL 0xFF0 - -/* offset of BMID registers */ -#define SCC_DMA_CMD 0x000 -#define SCC_DMA_STATUS 0x004 -#define SCC_DMA_TABLE_OFS 0x008 -#define SCC_DMA_INTMASK 0x010 -#define SCC_DMA_INTST 0x014 -#define SCC_DMA_PTERADD 0x018 -#define SCC_REG_CMD_ADDR 0x020 -#define SCC_REG_DATA 0x000 -#define SCC_REG_ERR 0x004 -#define SCC_REG_FEATURE 0x004 -#define SCC_REG_NSECT 0x008 -#define SCC_REG_LBAL 0x00C -#define SCC_REG_LBAM 0x010 -#define SCC_REG_LBAH 0x014 -#define SCC_REG_DEVICE 0x018 -#define SCC_REG_STATUS 0x01C -#define SCC_REG_CMD 0x01C -#define SCC_REG_ALTSTATUS 0x020 - -/* register value */ -#define TDVHSEL_MASTER 0x00000001 -#define TDVHSEL_SLAVE 0x00000004 - -#define MODE_JCUSFEN 0x00000080 - -#define ECMODE_VALUE 0x01 - -#define CCKCTRL_ATARESET 0x00040000 -#define CCKCTRL_BUFCNT 0x00020000 -#define CCKCTRL_CRST 0x00010000 -#define CCKCTRL_OCLKEN 0x00000100 -#define CCKCTRL_ATACLKOEN 0x00000002 -#define CCKCTRL_LCLKEN 0x00000001 - -#define QCHCD_IOS_SS 0x00000001 - -#define QCHSD_STPDIAG 0x00020000 - -#define INTMASK_MSK 0xD1000012 -#define INTSTS_SERROR 0x80000000 -#define INTSTS_PRERR 0x40000000 -#define INTSTS_RERR 0x10000000 -#define INTSTS_ICERR 0x01000000 -#define INTSTS_BMSINT 0x00000010 -#define INTSTS_BMHE 0x00000008 -#define INTSTS_IOIRQS 0x00000004 -#define INTSTS_INTRQ 0x00000002 -#define INTSTS_ACTEINT 0x00000001 - - -/* PIO transfer mode table */ -/* JCHST */ -static const unsigned long JCHSTtbl[2][7] = { - {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ - {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ -}; - -/* JCHHT */ -static const unsigned long JCHHTtbl[2][7] = { - {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ - {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ -}; - -/* JCHCT */ -static const unsigned long JCHCTtbl[2][7] = { - {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ - {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ -}; - -/* DMA transfer mode table */ -/* JCHDCTM/JCHDCTS */ -static const unsigned long JCHDCTxtbl[2][7] = { - {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ - {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ -}; - -/* JCSTWTM/JCSTWTS */ -static const unsigned long JCSTWTxtbl[2][7] = { - {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ - {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ -}; - -/* JCTSS */ -static const unsigned long JCTSStbl[2][7] = { - {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ - {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ -}; - -/* JCENVT */ -static const unsigned long JCENVTtbl[2][7] = { - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ - {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ -}; - -/* JCACTSELS/JCACTSELM */ -static const unsigned long JCACTSELtbl[2][7] = { - {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ -}; - -static const struct pci_device_id scc_pci_tbl[] = { - { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0}, - { } /* terminate list */ -}; - -/** - * scc_set_piomode - Initialize host controller PATA PIO timings - * @ap: Port whose timings we are configuring - * @adev: um - * - * Set PIO mode for device. - * - * LOCKING: - * None (inherited from caller). - */ - -static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev) -{ - unsigned int pio = adev->pio_mode - XFER_PIO_0; - void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; - void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; - void __iomem *piosht_port = ctrl_base + SCC_CTL_PIOSHT; - void __iomem *pioct_port = ctrl_base + SCC_CTL_PIOCT; - unsigned long reg; - int offset; - - reg = in_be32(cckctrl_port); - if (reg & CCKCTRL_ATACLKOEN) - offset = 1; /* 133MHz */ - else - offset = 0; /* 100MHz */ - - reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio]; - out_be32(piosht_port, reg); - reg = JCHCTtbl[offset][pio]; - out_be32(pioct_port, reg); -} - -/** - * scc_set_dmamode - Initialize host controller PATA DMA timings - * @ap: Port whose timings we are configuring - * @adev: um - * - * Set UDMA mode for device. - * - * LOCKING: - * None (inherited from caller). - */ - -static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev) -{ - unsigned int udma = adev->dma_mode; - unsigned int is_slave = (adev->devno != 0); - u8 speed = udma; - void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; - void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; - void __iomem *mdmact_port = ctrl_base + SCC_CTL_MDMACT; - void __iomem *mcrcst_port = ctrl_base + SCC_CTL_MCRCST; - void __iomem *sdmact_port = ctrl_base + SCC_CTL_SDMACT; - void __iomem *scrcst_port = ctrl_base + SCC_CTL_SCRCST; - void __iomem *udenvt_port = ctrl_base + SCC_CTL_UDENVT; - void __iomem *tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL; - int offset, idx; - - if (in_be32(cckctrl_port) & CCKCTRL_ATACLKOEN) - offset = 1; /* 133MHz */ - else - offset = 0; /* 100MHz */ - - if (speed >= XFER_UDMA_0) - idx = speed - XFER_UDMA_0; - else - return; - - if (is_slave) { - out_be32(sdmact_port, JCHDCTxtbl[offset][idx]); - out_be32(scrcst_port, JCSTWTxtbl[offset][idx]); - out_be32(tdvhsel_port, - (in_be32(tdvhsel_port) & ~TDVHSEL_SLAVE) | (JCACTSELtbl[offset][idx] << 2)); - } else { - out_be32(mdmact_port, JCHDCTxtbl[offset][idx]); - out_be32(mcrcst_port, JCSTWTxtbl[offset][idx]); - out_be32(tdvhsel_port, - (in_be32(tdvhsel_port) & ~TDVHSEL_MASTER) | JCACTSELtbl[offset][idx]); - } - out_be32(udenvt_port, - JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]); -} - -unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask) -{ - /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */ - if (adev->class == ATA_DEV_ATAPI && - (mask & (0xE0 << ATA_SHIFT_UDMA))) { - printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME); - mask &= ~(0xE0 << ATA_SHIFT_UDMA); - } - return mask; -} - -/** - * scc_tf_load - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set - * - * Note: Original code is ata_sff_tf_load(). - */ - -static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; - - if (tf->ctl != ap->last_ctl) { - out_be32(ioaddr->ctl_addr, tf->ctl); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } - - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - out_be32(ioaddr->feature_addr, tf->hob_feature); - out_be32(ioaddr->nsect_addr, tf->hob_nsect); - out_be32(ioaddr->lbal_addr, tf->hob_lbal); - out_be32(ioaddr->lbam_addr, tf->hob_lbam); - out_be32(ioaddr->lbah_addr, tf->hob_lbah); - VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", - tf->hob_feature, - tf->hob_nsect, - tf->hob_lbal, - tf->hob_lbam, - tf->hob_lbah); - } - - if (is_addr) { - out_be32(ioaddr->feature_addr, tf->feature); - out_be32(ioaddr->nsect_addr, tf->nsect); - out_be32(ioaddr->lbal_addr, tf->lbal); - out_be32(ioaddr->lbam_addr, tf->lbam); - out_be32(ioaddr->lbah_addr, tf->lbah); - VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", - tf->feature, - tf->nsect, - tf->lbal, - tf->lbam, - tf->lbah); - } - - if (tf->flags & ATA_TFLAG_DEVICE) { - out_be32(ioaddr->device_addr, tf->device); - VPRINTK("device 0x%X\n", tf->device); - } - - ata_wait_idle(ap); -} - -/** - * scc_check_status - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Note: Original code is ata_check_status(). - */ - -static u8 scc_check_status (struct ata_port *ap) -{ - return in_be32(ap->ioaddr.status_addr); -} - -/** - * scc_tf_read - input device's ATA taskfile shadow registers - * @ap: Port from which input is read - * @tf: ATA taskfile register set for storing input - * - * Note: Original code is ata_sff_tf_read(). - */ - -static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->command = scc_check_status(ap); - tf->feature = in_be32(ioaddr->error_addr); - tf->nsect = in_be32(ioaddr->nsect_addr); - tf->lbal = in_be32(ioaddr->lbal_addr); - tf->lbam = in_be32(ioaddr->lbam_addr); - tf->lbah = in_be32(ioaddr->lbah_addr); - tf->device = in_be32(ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - out_be32(ioaddr->ctl_addr, tf->ctl | ATA_HOB); - tf->hob_feature = in_be32(ioaddr->error_addr); - tf->hob_nsect = in_be32(ioaddr->nsect_addr); - tf->hob_lbal = in_be32(ioaddr->lbal_addr); - tf->hob_lbam = in_be32(ioaddr->lbam_addr); - tf->hob_lbah = in_be32(ioaddr->lbah_addr); - out_be32(ioaddr->ctl_addr, tf->ctl); - ap->last_ctl = tf->ctl; - } -} - -/** - * scc_exec_command - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Note: Original code is ata_sff_exec_command(). - */ - -static void scc_exec_command (struct ata_port *ap, - const struct ata_taskfile *tf) -{ - DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); - - out_be32(ap->ioaddr.command_addr, tf->command); - ata_sff_pause(ap); -} - -/** - * scc_check_altstatus - Read device alternate status reg - * @ap: port where the device is - */ - -static u8 scc_check_altstatus (struct ata_port *ap) -{ - return in_be32(ap->ioaddr.altstatus_addr); -} - -/** - * scc_dev_select - Select device 0/1 on ATA bus - * @ap: ATA channel to manipulate - * @device: ATA device (numbered from zero) to select - * - * Note: Original code is ata_sff_dev_select(). - */ - -static void scc_dev_select (struct ata_port *ap, unsigned int device) -{ - u8 tmp; - - if (device == 0) - tmp = ATA_DEVICE_OBS; - else - tmp = ATA_DEVICE_OBS | ATA_DEV1; - - out_be32(ap->ioaddr.device_addr, tmp); - ata_sff_pause(ap); -} - -/** - * scc_set_devctl - Write device control reg - * @ap: port where the device is - * @ctl: value to write - */ - -static void scc_set_devctl(struct ata_port *ap, u8 ctl) -{ - out_be32(ap->ioaddr.ctl_addr, ctl); -} - -/** - * scc_bmdma_setup - Set up PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Note: Original code is ata_bmdma_setup(). - */ - -static void scc_bmdma_setup (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 dmactl; - void __iomem *mmio = ap->ioaddr.bmdma_addr; - - /* load PRD table addr */ - out_be32(mmio + SCC_DMA_TABLE_OFS, ap->bmdma_prd_dma); - - /* specify data direction, triple-check start bit is clear */ - dmactl = in_be32(mmio + SCC_DMA_CMD); - dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); - if (!rw) - dmactl |= ATA_DMA_WR; - out_be32(mmio + SCC_DMA_CMD, dmactl); - - /* issue r/w command */ - ap->ops->sff_exec_command(ap, &qc->tf); -} - -/** - * scc_bmdma_start - Start a PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Note: Original code is ata_bmdma_start(). - */ - -static void scc_bmdma_start (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - u8 dmactl; - void __iomem *mmio = ap->ioaddr.bmdma_addr; - - /* start host DMA transaction */ - dmactl = in_be32(mmio + SCC_DMA_CMD); - out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START); -} - -/** - * scc_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * Note: Original code is ata_devchk(). - */ - -static unsigned int scc_devchk (struct ata_port *ap, - unsigned int device) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 nsect, lbal; - - ap->ops->sff_dev_select(ap, device); - - out_be32(ioaddr->nsect_addr, 0x55); - out_be32(ioaddr->lbal_addr, 0xaa); - - out_be32(ioaddr->nsect_addr, 0xaa); - out_be32(ioaddr->lbal_addr, 0x55); - - out_be32(ioaddr->nsect_addr, 0x55); - out_be32(ioaddr->lbal_addr, 0xaa); - - nsect = in_be32(ioaddr->nsect_addr); - lbal = in_be32(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - - return 0; /* nothing found */ -} - -/** - * scc_wait_after_reset - wait for devices to become ready after reset - * - * Note: Original code is ata_sff_wait_after_reset - */ - -static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, - unsigned long deadline) -{ - struct ata_port *ap = link->ap; - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int dev0 = devmask & (1 << 0); - unsigned int dev1 = devmask & (1 << 1); - int rc, ret = 0; - - /* Spec mandates ">= 2ms" before checking status. We wait - * 150ms, because that was the magic delay used for ATAPI - * devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready. - */ - ata_msleep(ap, 150); - - /* always check readiness of the master device */ - rc = ata_sff_wait_ready(link, deadline); - /* -ENODEV means the odd clown forgot the D7 pulldown resistor - * and TF status is 0xff, bail out on it too. - */ - if (rc) - return rc; - - /* if device 1 was found in ata_devchk, wait for register - * access briefly, then wait for BSY to clear. - */ - if (dev1) { - int i; - - ap->ops->sff_dev_select(ap, 1); - - /* Wait for register access. Some ATAPI devices fail - * to set nsect/lbal after reset, so don't waste too - * much time on it. We're gonna wait for !BSY anyway. - */ - for (i = 0; i < 2; i++) { - u8 nsect, lbal; - - nsect = in_be32(ioaddr->nsect_addr); - lbal = in_be32(ioaddr->lbal_addr); - if ((nsect == 1) && (lbal == 1)) - break; - ata_msleep(ap, 50); /* give drive a breather */ - } - - rc = ata_sff_wait_ready(link, deadline); - if (rc) { - if (rc != -ENODEV) - return rc; - ret = rc; - } - } - - /* is all this really necessary? */ - ap->ops->sff_dev_select(ap, 0); - if (dev1) - ap->ops->sff_dev_select(ap, 1); - if (dev0) - ap->ops->sff_dev_select(ap, 0); - - return ret; -} - -/** - * scc_bus_softreset - PATA device software reset - * - * Note: Original code is ata_bus_softreset(). - */ - -static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, - unsigned long deadline) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); - - /* software reset. causes dev0 to be selected */ - out_be32(ioaddr->ctl_addr, ap->ctl); - udelay(20); - out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST); - udelay(20); - out_be32(ioaddr->ctl_addr, ap->ctl); - - return scc_wait_after_reset(&ap->link, devmask, deadline); -} - -/** - * scc_softreset - reset host port via ATA SRST - * @ap: port to reset - * @classes: resulting classes of attached devices - * @deadline: deadline jiffies for the operation - * - * Note: Original code is ata_sff_softreset(). - */ - -static int scc_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) -{ - struct ata_port *ap = link->ap; - unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - unsigned int devmask = 0; - int rc; - u8 err; - - DPRINTK("ENTER\n"); - - /* determine if device 0/1 are present */ - if (scc_devchk(ap, 0)) - devmask |= (1 << 0); - if (slave_possible && scc_devchk(ap, 1)) - devmask |= (1 << 1); - - /* select device 0 again */ - ap->ops->sff_dev_select(ap, 0); - - /* issue bus reset */ - DPRINTK("about to softreset, devmask=%x\n", devmask); - rc = scc_bus_softreset(ap, devmask, deadline); - if (rc) { - ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc); - return -EIO; - } - - /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_sff_dev_classify(&ap->link.device[0], - devmask & (1 << 0), &err); - if (slave_possible && err != 0x81) - classes[1] = ata_sff_dev_classify(&ap->link.device[1], - devmask & (1 << 1), &err); - - DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); - return 0; -} - -/** - * scc_bmdma_stop - Stop PCI IDE BMDMA transfer - * @qc: Command we are ending DMA for - */ - -static void scc_bmdma_stop (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; - void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR]; - u32 reg; - - while (1) { - reg = in_be32(bmid_base + SCC_DMA_INTST); - - if (reg & INTSTS_SERROR) { - printk(KERN_WARNING "%s: SERROR\n", DRV_NAME); - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT); - out_be32(bmid_base + SCC_DMA_CMD, - in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); - continue; - } - - if (reg & INTSTS_PRERR) { - u32 maea0, maec0; - maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0); - maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0); - printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0); - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT); - out_be32(bmid_base + SCC_DMA_CMD, - in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); - continue; - } - - if (reg & INTSTS_RERR) { - printk(KERN_WARNING "%s: Response Error\n", DRV_NAME); - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT); - out_be32(bmid_base + SCC_DMA_CMD, - in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); - continue; - } - - if (reg & INTSTS_ICERR) { - out_be32(bmid_base + SCC_DMA_CMD, - in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); - printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME); - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT); - continue; - } - - if (reg & INTSTS_BMSINT) { - unsigned int classes; - unsigned long deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT); - printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME); - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT); - /* TBD: SW reset */ - scc_softreset(&ap->link, &classes, deadline); - continue; - } - - if (reg & INTSTS_BMHE) { - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE); - continue; - } - - if (reg & INTSTS_ACTEINT) { - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT); - continue; - } - - if (reg & INTSTS_IOIRQS) { - out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS); - continue; - } - break; - } - - /* clear start/stop bit */ - out_be32(bmid_base + SCC_DMA_CMD, - in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_sff_dma_pause(ap); /* dummy read */ -} - -/** - * scc_bmdma_status - Read PCI IDE BMDMA status - * @ap: Port associated with this ATA transaction. - */ - -static u8 scc_bmdma_status (struct ata_port *ap) -{ - void __iomem *mmio = ap->ioaddr.bmdma_addr; - u8 host_stat = in_be32(mmio + SCC_DMA_STATUS); - u32 int_status = in_be32(mmio + SCC_DMA_INTST); - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); - static int retry = 0; - - /* return if IOS_SS is cleared */ - if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START)) - return host_stat; - - /* errata A252,A308 workaround: Step4 */ - if ((scc_check_altstatus(ap) & ATA_ERR) - && (int_status & INTSTS_INTRQ)) - return (host_stat | ATA_DMA_INTR); - - /* errata A308 workaround Step5 */ - if (int_status & INTSTS_IOIRQS) { - host_stat |= ATA_DMA_INTR; - - /* We don't check ATAPI DMA because it is limited to UDMA4 */ - if ((qc->tf.protocol == ATA_PROT_DMA && - qc->dev->xfer_mode > XFER_UDMA_4)) { - if (!(int_status & INTSTS_ACTEINT)) { - printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n", - ap->print_id); - host_stat |= ATA_DMA_ERR; - if (retry++) - ap->udma_mask &= ~(1 << qc->dev->xfer_mode); - } else - retry = 0; - } - } - - return host_stat; -} - -/** - * scc_data_xfer - Transfer data by PIO - * @dev: device for this I/O - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Note: Original code is ata_sff_data_xfer(). - */ - -static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) -{ - struct ata_port *ap = dev->link->ap; - unsigned int words = buflen >> 1; - unsigned int i; - __le16 *buf16 = (__le16 *) buf; - void __iomem *mmio = ap->ioaddr.data_addr; - - /* Transfer multiple of 2 bytes */ - if (rw == READ) - for (i = 0; i < words; i++) - buf16[i] = cpu_to_le16(in_be32(mmio)); - else - for (i = 0; i < words; i++) - out_be32(mmio, le16_to_cpu(buf16[i])); - - /* Transfer trailing 1 byte, if any. */ - if (unlikely(buflen & 0x01)) { - __le16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (rw == READ) { - align_buf[0] = cpu_to_le16(in_be32(mmio)); - memcpy(trailing_buf, align_buf, 1); - } else { - memcpy(align_buf, trailing_buf, 1); - out_be32(mmio, le16_to_cpu(align_buf[0])); - } - words++; - } - - return words << 1; -} - -/** - * scc_postreset - standard postreset callback - * @ap: the target ata_port - * @classes: classes of attached devices - * - * Note: Original code is ata_sff_postreset(). - */ - -static void scc_postreset(struct ata_link *link, unsigned int *classes) -{ - struct ata_port *ap = link->ap; - - DPRINTK("ENTER\n"); - - /* is double-select really necessary? */ - if (classes[0] != ATA_DEV_NONE) - ap->ops->sff_dev_select(ap, 1); - if (classes[1] != ATA_DEV_NONE) - ap->ops->sff_dev_select(ap, 0); - - /* bail out if no device is present */ - if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { - DPRINTK("EXIT, no device\n"); - return; - } - - /* set up device control */ - out_be32(ap->ioaddr.ctl_addr, ap->ctl); - - DPRINTK("EXIT\n"); -} - -/** - * scc_irq_clear - Clear PCI IDE BMDMA interrupt. - * @ap: Port associated with this ATA transaction. - * - * Note: Original code is ata_bmdma_irq_clear(). - */ - -static void scc_irq_clear (struct ata_port *ap) -{ - void __iomem *mmio = ap->ioaddr.bmdma_addr; - - if (!mmio) - return; - - out_be32(mmio + SCC_DMA_STATUS, in_be32(mmio + SCC_DMA_STATUS)); -} - -/** - * scc_port_start - Set port up for dma. - * @ap: Port to initialize - * - * Allocate space for PRD table using ata_bmdma_port_start(). - * Set PRD table address for PTERADD. (PRD Transfer End Read) - */ - -static int scc_port_start (struct ata_port *ap) -{ - void __iomem *mmio = ap->ioaddr.bmdma_addr; - int rc; - - rc = ata_bmdma_port_start(ap); - if (rc) - return rc; - - out_be32(mmio + SCC_DMA_PTERADD, ap->bmdma_prd_dma); - return 0; -} - -/** - * scc_port_stop - Undo scc_port_start() - * @ap: Port to shut down - * - * Reset PTERADD. - */ - -static void scc_port_stop (struct ata_port *ap) -{ - void __iomem *mmio = ap->ioaddr.bmdma_addr; - - out_be32(mmio + SCC_DMA_PTERADD, 0); -} - -static struct scsi_host_template scc_sht = { - ATA_BMDMA_SHT(DRV_NAME), -}; - -static struct ata_port_operations scc_pata_ops = { - .inherits = &ata_bmdma_port_ops, - - .set_piomode = scc_set_piomode, - .set_dmamode = scc_set_dmamode, - .mode_filter = scc_mode_filter, - - .sff_tf_load = scc_tf_load, - .sff_tf_read = scc_tf_read, - .sff_exec_command = scc_exec_command, - .sff_check_status = scc_check_status, - .sff_check_altstatus = scc_check_altstatus, - .sff_dev_select = scc_dev_select, - .sff_set_devctl = scc_set_devctl, - - .bmdma_setup = scc_bmdma_setup, - .bmdma_start = scc_bmdma_start, - .bmdma_stop = scc_bmdma_stop, - .bmdma_status = scc_bmdma_status, - .sff_data_xfer = scc_data_xfer, - - .cable_detect = ata_cable_80wire, - .softreset = scc_softreset, - .postreset = scc_postreset, - - .sff_irq_clear = scc_irq_clear, - - .port_start = scc_port_start, - .port_stop = scc_port_stop, -}; - -static struct ata_port_info scc_port_info[] = { - { - .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = ATA_PIO4, - /* No MWDMA */ - .udma_mask = ATA_UDMA6, - .port_ops = &scc_pata_ops, - }, -}; - -/** - * scc_reset_controller - initialize SCC PATA controller. - */ - -static int scc_reset_controller(struct ata_host *host) -{ - void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR]; - void __iomem *bmid_base = host->iomap[SCC_BMID_BAR]; - void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; - void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG; - void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE; - void __iomem *intmask_port = bmid_base + SCC_DMA_INTMASK; - void __iomem *dmastatus_port = bmid_base + SCC_DMA_STATUS; - u32 reg = 0; - - out_be32(cckctrl_port, reg); - reg |= CCKCTRL_ATACLKOEN; - out_be32(cckctrl_port, reg); - reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; - out_be32(cckctrl_port, reg); - reg |= CCKCTRL_CRST; - out_be32(cckctrl_port, reg); - - for (;;) { - reg = in_be32(cckctrl_port); - if (reg & CCKCTRL_CRST) - break; - udelay(5000); - } - - reg |= CCKCTRL_ATARESET; - out_be32(cckctrl_port, reg); - out_be32(ecmode_port, ECMODE_VALUE); - out_be32(mode_port, MODE_JCUSFEN); - out_be32(intmask_port, INTMASK_MSK); - - if (in_be32(dmastatus_port) & QCHSD_STPDIAG) { - printk(KERN_WARNING "%s: failed to detect 80c cable. (PDIAG# is high)\n", DRV_NAME); - return -EIO; - } - - return 0; -} - -/** - * scc_setup_ports - initialize ioaddr with SCC PATA port offsets. - * @ioaddr: IO address structure to be initialized - * @base: base address of BMID region - */ - -static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base) -{ - ioaddr->cmd_addr = base + SCC_REG_CMD_ADDR; - ioaddr->altstatus_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS; - ioaddr->ctl_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS; - ioaddr->bmdma_addr = base; - ioaddr->data_addr = ioaddr->cmd_addr + SCC_REG_DATA; - ioaddr->error_addr = ioaddr->cmd_addr + SCC_REG_ERR; - ioaddr->feature_addr = ioaddr->cmd_addr + SCC_REG_FEATURE; - ioaddr->nsect_addr = ioaddr->cmd_addr + SCC_REG_NSECT; - ioaddr->lbal_addr = ioaddr->cmd_addr + SCC_REG_LBAL; - ioaddr->lbam_addr = ioaddr->cmd_addr + SCC_REG_LBAM; - ioaddr->lbah_addr = ioaddr->cmd_addr + SCC_REG_LBAH; - ioaddr->device_addr = ioaddr->cmd_addr + SCC_REG_DEVICE; - ioaddr->status_addr = ioaddr->cmd_addr + SCC_REG_STATUS; - ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD; -} - -static int scc_host_init(struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - int rc; - - rc = scc_reset_controller(host); - if (rc) - return rc; - - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - - scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]); - - pci_set_master(pdev); - - return 0; -} - -/** - * scc_init_one - Register SCC PATA device with kernel services - * @pdev: PCI device to register - * @ent: Entry in scc_pci_tbl matching with @pdev - * - * LOCKING: - * Inherited from PCI layer (may sleep). - * - * RETURNS: - * Zero on success, or -ERRNO value. - */ - -static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -{ - unsigned int board_idx = (unsigned int) ent->driver_data; - const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL }; - struct ata_host *host; - int rc; - - ata_print_version_once(&pdev->dev, DRV_VERSION); - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); - if (!host) - return -ENOMEM; - - rc = pcim_enable_device(pdev); - if (rc) - return rc; - - rc = pcim_iomap_regions(pdev, (1 << SCC_CTRL_BAR) | (1 << SCC_BMID_BAR), DRV_NAME); - if (rc == -EBUSY) - pcim_pin_device(pdev); - if (rc) - return rc; - host->iomap = pcim_iomap_table(pdev); - - ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl"); - ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid"); - - rc = scc_host_init(host); - if (rc) - return rc; - - return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, - IRQF_SHARED, &scc_sht); -} - -static struct pci_driver scc_pci_driver = { - .name = DRV_NAME, - .id_table = scc_pci_tbl, - .probe = scc_init_one, - .remove = ata_pci_remove_one, -#ifdef CONFIG_PM_SLEEP - .suspend = ata_pci_device_suspend, - .resume = ata_pci_device_resume, -#endif -}; - -module_pci_driver(scc_pci_driver); - -MODULE_AUTHOR("Toshiba corp"); -MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, scc_pci_tbl); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ae3fcb4..d7173cb 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1620,8 +1620,8 @@ out: static void loop_remove(struct loop_device *lo) { - del_gendisk(lo->lo_disk); blk_cleanup_queue(lo->lo_queue); + del_gendisk(lo->lo_disk); blk_mq_free_tag_set(&lo->tag_set); put_disk(lo->lo_disk); kfree(lo); diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index 6b736b0..88f13c5 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -944,7 +944,8 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, static int nvme_trans_bdev_limits_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 *inq_response, int alloc_len) { - __be32 max_sectors = cpu_to_be32(queue_max_hw_sectors(ns->queue)); + __be32 max_sectors = cpu_to_be32( + nvme_block_nr(ns, queue_max_hw_sectors(ns->queue))); __be32 max_discard = cpu_to_be32(ns->queue->limits.max_discard_sectors); __be32 discard_desc_count = cpu_to_be32(0x100); diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index bd2b3bb..713fc9f 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -265,17 +265,6 @@ static void put_persistent_gnt(struct xen_blkif *blkif, atomic_dec(&blkif->persistent_gnt_in_use); } -static void free_persistent_gnts_unmap_callback(int result, - struct gntab_unmap_queue_data *data) -{ - struct completion *c = data->data; - - /* BUG_ON used to reproduce existing behaviour, - but is this the best way to deal with this? */ - BUG_ON(result); - complete(c); -} - static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, unsigned int num) { @@ -285,12 +274,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, struct rb_node *n; int segs_to_unmap = 0; struct gntab_unmap_queue_data unmap_data; - struct completion unmap_completion; - init_completion(&unmap_completion); - - unmap_data.data = &unmap_completion; - unmap_data.done = &free_persistent_gnts_unmap_callback; unmap_data.pages = pages; unmap_data.unmap_ops = unmap; unmap_data.kunmap_ops = NULL; @@ -310,8 +294,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, !rb_next(&persistent_gnt->node)) { unmap_data.count = segs_to_unmap; - gnttab_unmap_refs_async(&unmap_data); - wait_for_completion(&unmap_completion); + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); segs_to_unmap = 0; @@ -329,8 +312,13 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work) struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct persistent_gnt *persistent_gnt; - int ret, segs_to_unmap = 0; + int segs_to_unmap = 0; struct xen_blkif *blkif = container_of(work, typeof(*blkif), persistent_purge_work); + struct gntab_unmap_queue_data unmap_data; + + unmap_data.pages = pages; + unmap_data.unmap_ops = unmap; + unmap_data.kunmap_ops = NULL; while(!list_empty(&blkif->persistent_purge_list)) { persistent_gnt = list_first_entry(&blkif->persistent_purge_list, @@ -346,17 +334,16 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work) pages[segs_to_unmap] = persistent_gnt->page; if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) { - ret = gnttab_unmap_refs(unmap, NULL, pages, - segs_to_unmap); - BUG_ON(ret); + unmap_data.count = segs_to_unmap; + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); segs_to_unmap = 0; } kfree(persistent_gnt); } if (segs_to_unmap > 0) { - ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap); - BUG_ON(ret); + unmap_data.count = segs_to_unmap; + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); } } diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c94386a..8dcbced 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -74,6 +74,27 @@ static inline struct zram *dev_to_zram(struct device *dev) return (struct zram *)dev_to_disk(dev)->private_data; } +static ssize_t compact_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + unsigned long nr_migrated; + struct zram *zram = dev_to_zram(dev); + struct zram_meta *meta; + + down_read(&zram->init_lock); + if (!init_done(zram)) { + up_read(&zram->init_lock); + return -EINVAL; + } + + meta = zram->meta; + nr_migrated = zs_compact(meta->mem_pool); + atomic64_add(nr_migrated, &zram->stats.num_migrated); + up_read(&zram->init_lock); + + return len; +} + static ssize_t disksize_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1038,6 +1059,7 @@ static const struct block_device_operations zram_devops = { .owner = THIS_MODULE }; +static DEVICE_ATTR_WO(compact); static DEVICE_ATTR_RW(disksize); static DEVICE_ATTR_RO(initstate); static DEVICE_ATTR_WO(reset); @@ -1114,6 +1136,7 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_num_writes.attr, &dev_attr_failed_reads.attr, &dev_attr_failed_writes.attr, + &dev_attr_compact.attr, &dev_attr_invalid_io.attr, &dev_attr_notify_free.attr, &dev_attr_zero_pages.attr, diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 4f7e8d4..6de97b3 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -227,7 +227,6 @@ static void bt3c_receive(struct bt3c_info *info) iobase = info->p_dev->resource[0]->start; avail = bt3c_read(iobase, 0x7006); - //printk("bt3c_cs: receiving %d bytes\n", avail); bt3c_address(iobase, 0x7480); while (size < avail) { @@ -250,7 +249,6 @@ static void bt3c_receive(struct bt3c_info *info) bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L); inb(iobase + DATA_H); - //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type); switch (bt_cb(info->rx_skb)->pkt_type) { @@ -364,7 +362,6 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) if (stat & 0x0001) bt3c_receive(info); if (stat & 0x0002) { - //BT_ERR("Ack (stat=0x%04x)", stat); clear_bit(XMIT_SENDING, &(info->tx_state)); bt3c_write_wakeup(info); } diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index d0741f3..4bba866 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -95,6 +95,78 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); +int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +{ + const struct hci_command_hdr *cmd; + const struct firmware *fw; + const u8 *fw_ptr; + size_t fw_size; + struct sk_buff *skb; + u16 opcode; + int err; + + err = request_firmware(&fw, firmware, &hdev->dev); + if (err < 0) { + BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware); + return err; + } + + /* Start Download */ + skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Download Minidrv command failed (%d)", + hdev->name, err); + goto done; + } + kfree_skb(skb); + + /* 50 msec delay after Download Minidrv completes */ + msleep(50); + + fw_ptr = fw->data; + fw_size = fw->size; + + while (fw_size >= sizeof(*cmd)) { + const u8 *cmd_param; + + cmd = (struct hci_command_hdr *)fw_ptr; + fw_ptr += sizeof(*cmd); + fw_size -= sizeof(*cmd); + + if (fw_size < cmd->plen) { + BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name, + firmware); + err = -EINVAL; + goto done; + } + + cmd_param = fw_ptr; + fw_ptr += cmd->plen; + fw_size -= cmd->plen; + + opcode = le16_to_cpu(cmd->opcode); + + skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Patch command %04x failed (%d)", + hdev->name, opcode, err); + goto done; + } + kfree_skb(skb); + } + + /* 250 msec delay after Launch Ram completes */ + msleep(250); + +done: + release_firmware(fw); + return err; +} +EXPORT_SYMBOL(btbcm_patchram); + static int btbcm_reset(struct hci_dev *hdev) { struct sk_buff *skb; @@ -198,12 +270,8 @@ static const struct { int btbcm_setup_patchram(struct hci_dev *hdev) { - const struct hci_command_hdr *cmd; - const struct firmware *fw; - const u8 *fw_ptr; - size_t fw_size; char fw_name[64]; - u16 opcode, subver, rev, pid, vid; + u16 subver, rev, pid, vid; const char *hw_name = NULL; struct sk_buff *skb; struct hci_rp_read_local_version *ver; @@ -273,74 +341,19 @@ int btbcm_setup_patchram(struct hci_dev *hdev) hw_name ? : "BCM", (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - err = request_firmware(&fw, fw_name, &hdev->dev); - if (err < 0) { - BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); + err = btbcm_patchram(hdev, fw_name); + if (err == -ENOENT) return 0; - } - - /* Start Download */ - skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: Download Minidrv command failed (%d)", - hdev->name, err); - goto reset; - } - kfree_skb(skb); - - /* 50 msec delay after Download Minidrv completes */ - msleep(50); - - fw_ptr = fw->data; - fw_size = fw->size; - - while (fw_size >= sizeof(*cmd)) { - const u8 *cmd_param; - - cmd = (struct hci_command_hdr *)fw_ptr; - fw_ptr += sizeof(*cmd); - fw_size -= sizeof(*cmd); - - if (fw_size < cmd->plen) { - BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, - fw_name); - err = -EINVAL; - goto reset; - } - cmd_param = fw_ptr; - fw_ptr += cmd->plen; - fw_size -= cmd->plen; - - opcode = le16_to_cpu(cmd->opcode); - - skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: patch command %04x failed (%d)", - hdev->name, opcode, err); - goto reset; - } - kfree_skb(skb); - } - - /* 250 msec delay after Launch Ram completes */ - msleep(250); - -reset: /* Reset */ err = btbcm_reset(hdev); if (err) - goto done; + return err; /* Read Local Version Info */ skb = btbcm_read_local_version(hdev); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - goto done; - } + if (IS_ERR(skb)) + return PTR_ERR(skb); ver = (struct hci_rp_read_local_version *)skb->data; rev = le16_to_cpu(ver->hci_rev); @@ -355,10 +368,7 @@ reset: set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); -done: - release_firmware(fw); - - return err; + return 0; } EXPORT_SYMBOL_GPL(btbcm_setup_patchram); diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index 34268ae..eb6ab5f 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h @@ -25,6 +25,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev); int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +int btbcm_patchram(struct hci_dev *hdev, const char *firmware); int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_apple(struct hci_dev *hdev); @@ -41,6 +42,11 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) return -EOPNOTSUPP; } +static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +{ + return -EOPNOTSUPP; +} + static inline int btbcm_setup_patchram(struct hci_dev *hdev) { return 0; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index de7b236..d21f3b4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/firmware.h> +#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -57,6 +58,7 @@ static struct usb_driver btusb_driver; #define BTUSB_AMP 0x4000 #define BTUSB_QCA_ROME 0x8000 #define BTUSB_BCM_APPLE 0x10000 +#define BTUSB_REALTEK 0x20000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -288,6 +290,28 @@ static const struct usb_device_id blacklist_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), .driver_info = BTUSB_IGNORE }, + /* Realtek Bluetooth devices */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), + .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8723AE Bluetooth devices */ + { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8723BE Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8821AE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3458), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK }, + { } /* Terminating entry */ }; @@ -892,7 +916,7 @@ static int btusb_open(struct hci_dev *hdev) */ if (data->setup_on_usb) { err = data->setup_on_usb(hdev); - if (err <0) + if (err < 0) return err; } @@ -1345,6 +1369,378 @@ static int btusb_setup_csr(struct hci_dev *hdev) return ret; } +#define RTL_FRAG_LEN 252 + +struct rtl_download_cmd { + __u8 index; + __u8 data[RTL_FRAG_LEN]; +} __packed; + +struct rtl_download_response { + __u8 status; + __u8 index; +} __packed; + +struct rtl_rom_version_evt { + __u8 status; + __u8 version; +} __packed; + +struct rtl_epatch_header { + __u8 signature[8]; + __le32 fw_version; + __le16 num_patches; +} __packed; + +#define RTL_EPATCH_SIGNATURE "Realtech" +#define RTL_ROM_LMP_3499 0x3499 +#define RTL_ROM_LMP_8723A 0x1200 +#define RTL_ROM_LMP_8723B 0x8723 +#define RTL_ROM_LMP_8821A 0x8821 +#define RTL_ROM_LMP_8761A 0x8761 + +static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) +{ + struct rtl_rom_version_evt *rom_version; + struct sk_buff *skb; + int ret; + + /* Read RTL ROM version command */ + skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Read ROM version failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rom_version)) { + BT_ERR("%s: RTL version event length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rom_version = (struct rtl_rom_version_evt *)skb->data; + BT_INFO("%s: rom_version status=%x version=%x", + hdev->name, rom_version->status, rom_version->version); + + ret = rom_version->status; + if (ret == 0) + *version = rom_version->version; + + kfree_skb(skb); + return ret; +} + +static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, + const struct firmware *fw, + unsigned char **_buf) +{ + const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + struct rtl_epatch_header *epatch_info; + unsigned char *buf; + int i, ret, len; + size_t min_size; + u8 opcode, length, data, rom_version = 0; + int project_id = -1; + const unsigned char *fwptr, *chip_id_base; + const unsigned char *patch_length_base, *patch_offset_base; + u32 patch_offset = 0; + u16 patch_length, num_patches; + const u16 project_id_to_lmp_subver[] = { + RTL_ROM_LMP_8723A, + RTL_ROM_LMP_8723B, + RTL_ROM_LMP_8821A, + RTL_ROM_LMP_8761A + }; + + ret = rtl_read_rom_version(hdev, &rom_version); + if (ret) + return -bt_to_errno(ret); + + min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; + if (fw->size < min_size) + return -EINVAL; + + fwptr = fw->data + fw->size - sizeof(extension_sig); + if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { + BT_ERR("%s: extension section signature mismatch", hdev->name); + return -EINVAL; + } + + /* Loop from the end of the firmware parsing instructions, until + * we find an instruction that identifies the "project ID" for the + * hardware supported by this firwmare file. + * Once we have that, we double-check that that project_id is suitable + * for the hardware we are working with. + */ + while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { + opcode = *--fwptr; + length = *--fwptr; + data = *--fwptr; + + BT_DBG("check op=%x len=%x data=%x", opcode, length, data); + + if (opcode == 0xff) /* EOF */ + break; + + if (length == 0) { + BT_ERR("%s: found instruction with length 0", + hdev->name); + return -EINVAL; + } + + if (opcode == 0 && length == 1) { + project_id = data; + break; + } + + fwptr -= length; + } + + if (project_id < 0) { + BT_ERR("%s: failed to find version instruction", hdev->name); + return -EINVAL; + } + + if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { + BT_ERR("%s: unknown project id %d", hdev->name, project_id); + return -EINVAL; + } + + if (lmp_subver != project_id_to_lmp_subver[project_id]) { + BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, + project_id_to_lmp_subver[project_id], lmp_subver); + return -EINVAL; + } + + epatch_info = (struct rtl_epatch_header *)fw->data; + if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { + BT_ERR("%s: bad EPATCH signature", hdev->name); + return -EINVAL; + } + + num_patches = le16_to_cpu(epatch_info->num_patches); + BT_DBG("fw_version=%x, num_patches=%d", + le32_to_cpu(epatch_info->fw_version), num_patches); + + /* After the rtl_epatch_header there is a funky patch metadata section. + * Assuming 2 patches, the layout is: + * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 + * + * Find the right patch for this chip. + */ + min_size += 8 * num_patches; + if (fw->size < min_size) + return -EINVAL; + + chip_id_base = fw->data + sizeof(struct rtl_epatch_header); + patch_length_base = chip_id_base + (sizeof(u16) * num_patches); + patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); + for (i = 0; i < num_patches; i++) { + u16 chip_id = get_unaligned_le16(chip_id_base + + (i * sizeof(u16))); + if (chip_id == rom_version + 1) { + patch_length = get_unaligned_le16(patch_length_base + + (i * sizeof(u16))); + patch_offset = get_unaligned_le32(patch_offset_base + + (i * sizeof(u32))); + break; + } + } + + if (!patch_offset) { + BT_ERR("%s: didn't find patch for chip id %d", + hdev->name, rom_version); + return -EINVAL; + } + + BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); + min_size = patch_offset + patch_length; + if (fw->size < min_size) + return -EINVAL; + + /* Copy the firmware into a new buffer and write the version at + * the end. + */ + len = patch_length; + buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); + + *_buf = buf; + return len; +} + +static int rtl_download_firmware(struct hci_dev *hdev, + const unsigned char *data, int fw_len) +{ + struct rtl_download_cmd *dl_cmd; + int frag_num = fw_len / RTL_FRAG_LEN + 1; + int frag_len = RTL_FRAG_LEN; + int ret = 0; + int i; + + dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); + if (!dl_cmd) + return -ENOMEM; + + for (i = 0; i < frag_num; i++) { + struct rtl_download_response *dl_resp; + struct sk_buff *skb; + + BT_DBG("download fw (%d/%d)", i, frag_num); + + dl_cmd->index = i; + if (i == (frag_num - 1)) { + dl_cmd->index |= 0x80; /* data end */ + frag_len = fw_len % RTL_FRAG_LEN; + } + memcpy(dl_cmd->data, data, frag_len); + + /* Send download command */ + skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: download fw command failed (%ld)", + hdev->name, PTR_ERR(skb)); + ret = -PTR_ERR(skb); + goto out; + } + + if (skb->len != sizeof(*dl_resp)) { + BT_ERR("%s: download fw event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto out; + } + + dl_resp = (struct rtl_download_response *)skb->data; + if (dl_resp->status != 0) { + kfree_skb(skb); + ret = bt_to_errno(dl_resp->status); + goto out; + } + + kfree_skb(skb); + data += RTL_FRAG_LEN; + } + +out: + kfree(dl_cmd); + return ret; +} + +static int btusb_setup_rtl8723a(struct hci_dev *hdev) +{ + struct btusb_data *data = dev_get_drvdata(&hdev->dev); + struct usb_device *udev = interface_to_usbdev(data->intf); + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); + ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); + return ret; + } + + if (fw->size < 8) { + ret = -EINVAL; + goto out; + } + + /* Check that the firmware doesn't have the epatch signature + * (which is only for RTL8723B and newer). + */ + if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { + BT_ERR("%s: unexpected EPATCH signature!", hdev->name); + ret = -EINVAL; + goto out; + } + + ret = rtl_download_firmware(hdev, fw->data, fw->size); + +out: + release_firmware(fw); + return ret; +} + +static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, + const char *fw_name) +{ + struct btusb_data *data = dev_get_drvdata(&hdev->dev); + struct usb_device *udev = interface_to_usbdev(data->intf); + unsigned char *fw_data = NULL; + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); + ret = request_firmware(&fw, fw_name, &udev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load %s", hdev->name, fw_name); + return ret; + } + + ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); + if (ret < 0) + goto out; + + ret = rtl_download_firmware(hdev, fw_data, ret); + kfree(fw_data); + if (ret < 0) + goto out; + +out: + release_firmware(fw); + return ret; +} + +static int btusb_setup_realtek(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_local_version *resp; + u16 lmp_subver; + + skb = btusb_read_local_version(hdev); + if (IS_ERR(skb)) + return -PTR_ERR(skb); + + resp = (struct hci_rp_read_local_version *)skb->data; + BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, + resp->lmp_ver, resp->lmp_subver); + + lmp_subver = le16_to_cpu(resp->lmp_subver); + kfree_skb(skb); + + /* Match a set of subver values that correspond to stock firmware, + * which is not compatible with standard btusb. + * If matched, upload an alternative firmware that does conform to + * standard btusb. Once that firmware is uploaded, the subver changes + * to a different value. + */ + switch (lmp_subver) { + case RTL_ROM_LMP_8723A: + case RTL_ROM_LMP_3499: + return btusb_setup_rtl8723a(hdev); + case RTL_ROM_LMP_8723B: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8723b_fw.bin"); + case RTL_ROM_LMP_8821A: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8821a_fw.bin"); + case RTL_ROM_LMP_8761A: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8761a_fw.bin"); + default: + BT_INFO("rtl: assuming no firmware upload needed."); + return 0; + } +} + static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -2577,7 +2973,7 @@ static int btusb_setup_qca(struct hci_dev *hdev) int i, err; err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver, - sizeof(ver)); + sizeof(ver)); if (err < 0) return err; @@ -2776,6 +3172,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_ath3012; } + if (id->driver_info & BTUSB_REALTEK) + hdev->setup = btusb_setup_realtek; + if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ data->isoc = NULL; diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 1b3f864..ec8fa0e 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -95,7 +95,6 @@ static void ath_hci_uart_work(struct work_struct *work) hci_uart_tx_wakeup(hu); } -/* Initialize protocol */ static int ath_open(struct hci_uart *hu) { struct ath_struct *ath; @@ -116,8 +115,7 @@ static int ath_open(struct hci_uart *hu) return 0; } -/* Flush protocol data */ -static int ath_flush(struct hci_uart *hu) +static int ath_close(struct hci_uart *hu) { struct ath_struct *ath = hu->priv; @@ -125,11 +123,17 @@ static int ath_flush(struct hci_uart *hu) skb_queue_purge(&ath->txq); + kfree_skb(ath->rx_skb); + + cancel_work_sync(&ath->ctxtsw); + + hu->priv = NULL; + kfree(ath); + return 0; } -/* Close protocol */ -static int ath_close(struct hci_uart *hu) +static int ath_flush(struct hci_uart *hu) { struct ath_struct *ath = hu->priv; @@ -137,19 +141,65 @@ static int ath_close(struct hci_uart *hu) skb_queue_purge(&ath->txq); - kfree_skb(ath->rx_skb); + return 0; +} - cancel_work_sync(&ath->ctxtsw); +static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 buf[10]; + int err; + + buf[0] = 0x01; + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = sizeof(bdaddr_t); + memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Change address command failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); - hu->priv = NULL; - kfree(ath); + return 0; +} + +static int ath_setup(struct hci_uart *hu) +{ + BT_DBG("hu %p", hu); + + hu->hdev->set_bdaddr = ath_set_bdaddr; return 0; } +static const struct h4_recv_pkt ath_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, +}; + +static int ath_recv(struct hci_uart *hu, const void *data, int count) +{ + struct ath_struct *ath = hu->priv; + + ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, + ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); + if (IS_ERR(ath->rx_skb)) { + int err = PTR_ERR(ath->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + return err; + } + + return count; +} + #define HCI_OP_ATH_SLEEP 0xFC04 -/* Enqueue frame for transmittion */ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) { struct ath_struct *ath = hu->priv; @@ -159,8 +209,7 @@ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } - /* - * Update power management enable flag with parameters of + /* Update power management enable flag with parameters of * HCI sleep enable vendor specific HCI command. */ if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { @@ -190,37 +239,16 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) return skb_dequeue(&ath->txq); } -static const struct h4_recv_pkt ath_recv_pkts[] = { - { H4_RECV_ACL, .recv = hci_recv_frame }, - { H4_RECV_SCO, .recv = hci_recv_frame }, - { H4_RECV_EVENT, .recv = hci_recv_frame }, -}; - -/* Recv data */ -static int ath_recv(struct hci_uart *hu, const void *data, int count) -{ - struct ath_struct *ath = hu->priv; - - ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, - ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); - if (IS_ERR(ath->rx_skb)) { - int err = PTR_ERR(ath->rx_skb); - BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); - return err; - } - - return count; -} - static const struct hci_uart_proto athp = { .id = HCI_UART_ATH3K, .name = "ATH3K", .open = ath_open, .close = ath_close, + .flush = ath_flush, + .setup = ath_setup, .recv = ath_recv, .enqueue = ath_enqueue, .dequeue = ath_dequeue, - .flush = ath_flush, }; int __init ath_init(void) diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index b854125..5340604 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -660,7 +660,7 @@ validate_group(struct perf_event *event) * Initialise the fake PMU. We only need to populate the * used_mask for the purposes of validation. */ - .used_mask = CPU_BITS_NONE, + .used_mask = { 0 }, }; if (!validate_event(event->pmu, &fake_pmu, leader)) diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 11f7982..ebee57d 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -1,7 +1,7 @@ /* * OMAP L3 Interconnect error handling driver * - * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar <santosh.shilimkar@ti.com> * Sricharan <r.sricharan@ti.com> * @@ -233,7 +233,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) } static const struct of_device_id l3_noc_match[] = { - {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data}, + {.compatible = "ti,omap4-l3-noc", .data = &omap4_l3_data}, + {.compatible = "ti,omap5-l3-noc", .data = &omap5_l3_data}, {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data}, {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data}, {}, diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 9525458..73431f8 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -1,7 +1,7 @@ /* * OMAP L3 Interconnect error handling driver header * - * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar <santosh.shilimkar@ti.com> * sricharan <r.sricharan@ti.com> * @@ -175,16 +175,14 @@ static struct l3_flagmux_data omap_l3_flagmux_clk2 = { }; -static struct l3_target_data omap_l3_target_data_clk3[] = { - {0x0100, "EMUSS",}, - {0x0300, "DEBUG SOURCE",}, - {0x0, "HOST CLK3",}, +static struct l3_target_data omap4_l3_target_data_clk3[] = { + {0x0100, "DEBUGSS",}, }; -static struct l3_flagmux_data omap_l3_flagmux_clk3 = { +static struct l3_flagmux_data omap4_l3_flagmux_clk3 = { .offset = 0x0200, - .l3_targ = omap_l3_target_data_clk3, - .num_targ_data = ARRAY_SIZE(omap_l3_target_data_clk3), + .l3_targ = omap4_l3_target_data_clk3, + .num_targ_data = ARRAY_SIZE(omap4_l3_target_data_clk3), }; static struct l3_masters_data omap_l3_masters[] = { @@ -215,21 +213,49 @@ static struct l3_masters_data omap_l3_masters[] = { { 0x32, "USBHOSTFS"} }; -static struct l3_flagmux_data *omap_l3_flagmux[] = { +static struct l3_flagmux_data *omap4_l3_flagmux[] = { &omap_l3_flagmux_clk1, &omap_l3_flagmux_clk2, - &omap_l3_flagmux_clk3, + &omap4_l3_flagmux_clk3, }; -static const struct omap_l3 omap_l3_data = { - .l3_flagmux = omap_l3_flagmux, - .num_modules = ARRAY_SIZE(omap_l3_flagmux), +static const struct omap_l3 omap4_l3_data = { + .l3_flagmux = omap4_l3_flagmux, + .num_modules = ARRAY_SIZE(omap4_l3_flagmux), .l3_masters = omap_l3_masters, .num_masters = ARRAY_SIZE(omap_l3_masters), /* The 6 MSBs of register field used to distinguish initiator */ .mst_addr_mask = 0xFC, }; +/* OMAP5 data */ +static struct l3_target_data omap5_l3_target_data_clk3[] = { + {0x0100, "L3INSTR",}, + {0x0300, "DEBUGSS",}, + {0x0, "HOSTCLK3",}, +}; + +static struct l3_flagmux_data omap5_l3_flagmux_clk3 = { + .offset = 0x0200, + .l3_targ = omap5_l3_target_data_clk3, + .num_targ_data = ARRAY_SIZE(omap5_l3_target_data_clk3), +}; + +static struct l3_flagmux_data *omap5_l3_flagmux[] = { + &omap_l3_flagmux_clk1, + &omap_l3_flagmux_clk2, + &omap5_l3_flagmux_clk3, +}; + +static const struct omap_l3 omap5_l3_data = { + .l3_flagmux = omap5_l3_flagmux, + .num_modules = ARRAY_SIZE(omap5_l3_flagmux), + .l3_masters = omap_l3_masters, + .num_masters = ARRAY_SIZE(omap_l3_masters), + /* The 6 MSBs of register field used to distinguish initiator */ + .mst_addr_mask = 0x7E0, +}; + /* DRA7 data */ static struct l3_target_data dra_l3_target_data_clk1[] = { {0x2a00, "AES1",}, @@ -274,7 +300,7 @@ static struct l3_flagmux_data dra_l3_flagmux_clk1 = { static struct l3_target_data dra_l3_target_data_clk2[] = { {0x0, "HOST CLK1",}, - {0x0, "HOST CLK2",}, + {0x800000, "HOST CLK2",}, {0xdead, L3_TARGET_NOT_SUPPORTED,}, {0x3400, "SHA2_2",}, {0x0900, "BB2D",}, diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index d1494ec..4b31f13 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -57,7 +57,7 @@ static void bcm63xx_rng_cleanup(struct hwrng *rng) val &= ~RNG_EN; __raw_writel(val, priv->regs + RNG_CTRL); - clk_didsable_unprepare(prov->clk); + clk_disable_unprepare(priv->clk); } static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) @@ -97,14 +97,14 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) priv->rng.name = pdev->name; priv->rng.init = bcm63xx_rng_init; priv->rng.cleanup = bcm63xx_rng_cleanup; - prov->rng.data_present = bcm63xx_rng_data_present; + priv->rng.data_present = bcm63xx_rng_data_present; priv->rng.data_read = bcm63xx_rng_data_read; priv->clk = devm_clk_get(&pdev->dev, "ipsec"); if (IS_ERR(priv->clk)) { - error = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "no clock for device: %d\n", error); - return error; + ret = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "no clock for device: %d\n", ret); + return ret; } if (!devm_request_mem_region(&pdev->dev, r->start, @@ -120,11 +120,11 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) return -ENOMEM; } - error = devm_hwrng_register(&pdev->dev, &priv->rng); - if (error) { + ret = devm_hwrng_register(&pdev->dev, &priv->rng); + if (ret) { dev_err(&pdev->dev, "failed to register rng device: %d\n", - error); - return error; + ret); + return ret; } dev_info(&pdev->dev, "registered RNG driver\n"); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9bb5928..bf75f63 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2000,7 +2000,7 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v) seq_printf(m, " %x", intf->channels[i].address); seq_putc(m, '\n'); - return seq_has_overflowed(m); + return 0; } static int smi_ipmb_proc_open(struct inode *inode, struct file *file) @@ -2023,7 +2023,7 @@ static int smi_version_proc_show(struct seq_file *m, void *v) ipmi_version_major(&intf->bmc->id), ipmi_version_minor(&intf->bmc->id)); - return seq_has_overflowed(m); + return 0; } static int smi_version_proc_open(struct inode *inode, struct file *file) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5e90a18..8a45e92 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -942,8 +942,7 @@ static void sender(void *send_info, * If we are running to completion, start it and run * transactions until everything is clear. */ - smi_info->curr_msg = msg; - smi_info->waiting_msg = NULL; + smi_info->waiting_msg = msg; /* * Run to completion means we are single-threaded, no @@ -2244,7 +2243,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, acpi_handle handle; acpi_status status; unsigned long long tmp; - int rv; + int rv = -EINVAL; acpi_dev = pnp_acpi_device(dev); if (!acpi_dev) @@ -2262,8 +2261,10 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, /* _IFT tells us the interface type: KCS, BT, etc */ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); goto err_free; + } switch (tmp) { case 1: @@ -2276,6 +2277,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, info->si_type = SI_BT; break; case 4: /* SSIF, just ignore */ + rv = -ENODEV; goto err_free; default: dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); @@ -2336,7 +2338,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, err_free: kfree(info); - return -EINVAL; + return rv; } static void ipmi_pnp_remove(struct pnp_dev *dev) @@ -3080,7 +3082,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v) seq_printf(m, "%s\n", si_to_str[smi->si_type]); - return seq_has_overflowed(m); + return 0; } static int smi_type_proc_open(struct inode *inode, struct file *file) @@ -3153,7 +3155,7 @@ static int smi_params_proc_show(struct seq_file *m, void *v) smi->irq, smi->slave_addr); - return seq_has_overflowed(m); + return 0; } static int smi_params_proc_open(struct inode *inode, struct file *file) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index f40e3bd..207689c 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -31,7 +31,6 @@ * interface into the I2C driver, I believe. */ -#include <linux/version.h> #if defined(MODVERSIONS) #include <linux/modversions.h> #endif @@ -166,6 +165,9 @@ enum ssif_stat_indexes { /* Number of watchdog pretimeouts. */ SSIF_STAT_watchdog_pretimeouts, + /* Number of alers received. */ + SSIF_STAT_alerts, + /* Always add statistics before this value, it must be last. */ SSIF_NUM_STATS }; @@ -214,7 +216,16 @@ struct ssif_info { #define WDT_PRE_TIMEOUT_INT 0x08 unsigned char msg_flags; + u8 global_enables; bool has_event_buffer; + bool supports_alert; + + /* + * Used to tell what we should do with alerts. If we are + * waiting on a response, read the data immediately. + */ + bool got_alert; + bool waiting_alert; /* * If set to true, this will request events the next time the @@ -478,13 +489,13 @@ static int ipmi_ssif_thread(void *data) if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) { result = i2c_smbus_write_block_data( - ssif_info->client, SSIF_IPMI_REQUEST, + ssif_info->client, ssif_info->i2c_command, ssif_info->i2c_data[0], ssif_info->i2c_data + 1); ssif_info->done_handler(ssif_info, result, NULL, 0); } else { result = i2c_smbus_read_block_data( - ssif_info->client, SSIF_IPMI_RESPONSE, + ssif_info->client, ssif_info->i2c_command, ssif_info->i2c_data); if (result < 0) ssif_info->done_handler(ssif_info, result, @@ -518,15 +529,12 @@ static int ssif_i2c_send(struct ssif_info *ssif_info, static void msg_done_handler(struct ssif_info *ssif_info, int result, unsigned char *data, unsigned int len); -static void retry_timeout(unsigned long data) +static void start_get(struct ssif_info *ssif_info) { - struct ssif_info *ssif_info = (void *) data; int rv; - if (ssif_info->stopping) - return; - ssif_info->rtc_us_timer = 0; + ssif_info->multi_pos = 0; rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, SSIF_IPMI_RESPONSE, @@ -540,6 +548,46 @@ static void retry_timeout(unsigned long data) } } +static void retry_timeout(unsigned long data) +{ + struct ssif_info *ssif_info = (void *) data; + unsigned long oflags, *flags; + bool waiting; + + if (ssif_info->stopping) + return; + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + waiting = ssif_info->waiting_alert; + ssif_info->waiting_alert = false; + ipmi_ssif_unlock_cond(ssif_info, flags); + + if (waiting) + start_get(ssif_info); +} + + +static void ssif_alert(struct i2c_client *client, unsigned int data) +{ + struct ssif_info *ssif_info = i2c_get_clientdata(client); + unsigned long oflags, *flags; + bool do_get = false; + + ssif_inc_stat(ssif_info, alerts); + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + if (ssif_info->waiting_alert) { + ssif_info->waiting_alert = false; + del_timer(&ssif_info->retry_timer); + do_get = true; + } else if (ssif_info->curr_msg) { + ssif_info->got_alert = true; + } + ipmi_ssif_unlock_cond(ssif_info, flags); + if (do_get) + start_get(ssif_info); +} + static int start_resend(struct ssif_info *ssif_info); static void msg_done_handler(struct ssif_info *ssif_info, int result, @@ -559,9 +607,12 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if (ssif_info->retries_left > 0) { ssif_inc_stat(ssif_info, receive_retries); + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + ssif_info->waiting_alert = true; + ssif_info->rtc_us_timer = SSIF_MSG_USEC; mod_timer(&ssif_info->retry_timer, jiffies + SSIF_MSG_JIFFIES); - ssif_info->rtc_us_timer = SSIF_MSG_USEC; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } @@ -581,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ssif_inc_stat(ssif_info, received_message_parts); /* Remove the multi-part read marker. */ - for (i = 0; i < (len-2); i++) - ssif_info->data[i] = data[i+2]; len -= 2; + for (i = 0; i < len; i++) + ssif_info->data[i] = data[i+2]; ssif_info->multi_len = len; ssif_info->multi_pos = 1; @@ -610,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, goto continue_op; } - blocknum = data[ssif_info->multi_len]; + blocknum = data[0]; - if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) { + if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) { /* Received message too big, abort the operation. */ result = -E2BIG; if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) @@ -622,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, } /* Remove the blocknum from the data. */ - for (i = 0; i < (len-1); i++) - ssif_info->data[i+ssif_info->multi_len] = data[i+1]; len--; + for (i = 0; i < len; i++) + ssif_info->data[i + ssif_info->multi_len] = data[i + 1]; ssif_info->multi_len += len; if (blocknum == 0xff) { /* End of read */ len = ssif_info->multi_len; data = ssif_info->data; - } else if ((blocknum+1) != ssif_info->multi_pos) { + } else if (blocknum + 1 != ssif_info->multi_pos) { /* * Out of sequence block, just abort. Block * numbers start at zero for the second block, @@ -650,7 +701,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if (rv < 0) { if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) pr_info(PFX - "Error from i2c_non_blocking_op(2)\n"); + "Error from ssif_i2c_send\n"); result = -EIO; } else @@ -830,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, } if (ssif_info->multi_data) { - /* In the middle of a multi-data write. */ + /* + * In the middle of a multi-data write. See the comment + * in the SSIF_MULTI_n_PART case in the probe function + * for details on the intricacies of this. + */ int left; ssif_inc_stat(ssif_info, sent_messages_parts); @@ -864,15 +919,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, msg_done_handler(ssif_info, -EIO, NULL, 0); } } else { + unsigned long oflags, *flags; + bool got_alert; + ssif_inc_stat(ssif_info, sent_messages); ssif_inc_stat(ssif_info, sent_messages_parts); - /* Wait a jiffie then request the next message */ - ssif_info->retries_left = SSIF_RECV_RETRIES; - ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; - mod_timer(&ssif_info->retry_timer, - jiffies + SSIF_MSG_PART_JIFFIES); - return; + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + got_alert = ssif_info->got_alert; + if (got_alert) { + ssif_info->got_alert = false; + ssif_info->waiting_alert = false; + } + + if (got_alert) { + ipmi_ssif_unlock_cond(ssif_info, flags); + /* The alert already happened, try now. */ + retry_timeout((unsigned long) ssif_info); + } else { + /* Wait a jiffie then request the next message */ + ssif_info->waiting_alert = true; + ssif_info->retries_left = SSIF_RECV_RETRIES; + ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_PART_JIFFIES); + ipmi_ssif_unlock_cond(ssif_info, flags); + } } } @@ -881,6 +953,8 @@ static int start_resend(struct ssif_info *ssif_info) int rv; int command; + ssif_info->got_alert = false; + if (ssif_info->data_len > 32) { command = SSIF_IPMI_MULTI_PART_REQUEST_START; ssif_info->multi_data = ssif_info->data; @@ -915,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info, return -E2BIG; ssif_info->retries_left = SSIF_SEND_RETRIES; - memcpy(ssif_info->data+1, data, len); + memcpy(ssif_info->data + 1, data, len); ssif_info->data_len = len; return start_resend(ssif_info); } @@ -1200,7 +1274,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v) { seq_puts(m, "ssif\n"); - return seq_has_overflowed(m); + return 0; } static int smi_type_proc_open(struct inode *inode, struct file *file) @@ -1243,6 +1317,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v) ssif_get_stat(ssif_info, events)); seq_printf(m, "watchdog_pretimeouts: %u\n", ssif_get_stat(ssif_info, watchdog_pretimeouts)); + seq_printf(m, "alerts: %u\n", + ssif_get_stat(ssif_info, alerts)); return 0; } @@ -1258,6 +1334,23 @@ static const struct file_operations smi_stats_proc_ops = { .release = single_release, }; +static int strcmp_nospace(char *s1, char *s2) +{ + while (*s1 && *s2) { + while (isspace(*s1)) + s1++; + while (isspace(*s2)) + s2++; + if (*s1 > *s2) + return 1; + if (*s1 < *s2) + return -1; + s1++; + s2++; + } + return 0; +} + static struct ssif_addr_info *ssif_info_find(unsigned short addr, char *adapter_name, bool match_null_name) @@ -1272,8 +1365,10 @@ restart: /* One is NULL and one is not */ continue; } - if (strcmp(info->adapter_name, adapter_name)) - /* Names to not match */ + if (adapter_name && + strcmp_nospace(info->adapter_name, + adapter_name)) + /* Names do not match */ continue; } found = info; @@ -1306,6 +1401,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) return false; } +/* + * Global enables we care about. + */ +#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \ + IPMI_BMC_EVT_MSG_INTR) + static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) { unsigned char msg[3]; @@ -1391,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) break; case SSIF_MULTI_2_PART: - if (ssif_info->max_xmit_msg_size > 64) - ssif_info->max_xmit_msg_size = 64; + if (ssif_info->max_xmit_msg_size > 63) + ssif_info->max_xmit_msg_size = 63; if (ssif_info->max_recv_msg_size > 62) ssif_info->max_recv_msg_size = 62; break; case SSIF_MULTI_n_PART: + /* + * The specification is rather confusing at + * this point, but I think I understand what + * is meant. At least I have a workable + * solution. With multi-part messages, you + * cannot send a message that is a multiple of + * 32-bytes in length, because the start and + * middle messages are 32-bytes and the end + * message must be at least one byte. You + * can't fudge on an extra byte, that would + * screw up things like fru data writes. So + * we limit the length to 63 bytes. That way + * a 32-byte message gets sent as a single + * part. A larger message will be a 32-byte + * start and the next message is always going + * to be 1-31 bytes in length. Not ideal, but + * it should work. + */ + if (ssif_info->max_xmit_msg_size > 63) + ssif_info->max_xmit_msg_size = 63; break; default: @@ -1407,7 +1528,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } else { no_support: /* Assume no multi-part or PEC support */ - pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", + pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", rv, len, resp[2]); ssif_info->max_xmit_msg_size = 32; @@ -1436,6 +1557,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) goto found; } + ssif_info->global_enables = resp[3]; + if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) { ssif_info->has_event_buffer = true; /* buffer is already enabled, nothing to do. */ @@ -1444,18 +1567,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF; + msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF; rv = do_cmd(client, 3, msg, &len, resp); if (rv || (len < 2)) { - pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", + pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", rv, len, resp[2]); rv = 0; /* Not fatal */ goto found; } - if (resp[2] == 0) + if (resp[2] == 0) { /* A successful return means the event buffer is supported. */ ssif_info->has_event_buffer = true; + ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF; + } + + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; + rv = do_cmd(client, 3, msg, &len, resp); + if (rv || (len < 2)) { + pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", + rv, len, resp[2]); + rv = 0; /* Not fatal */ + goto found; + } + + if (resp[2] == 0) { + /* A successful return means the alert is supported. */ + ssif_info->supports_alert = true; + ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR; + } found: ssif_info->intf_num = atomic_inc_return(&next_intf); @@ -1813,6 +1955,7 @@ static struct i2c_driver ssif_i2c_driver = { }, .probe = ssif_probe, .remove = ssif_remove, + .alert = ssif_alert, .id_table = ssif_id, .detect = ssif_detect }; @@ -1832,7 +1975,7 @@ static int init_ipmi_ssif(void) rv = new_ssif_client(addr[i], adapter_name[i], dbg[i], slave_addrs[i], SI_HARDCODED); - if (!rv) + if (rv) pr_err(PFX "Couldn't add hardcoded device at addr 0x%x\n", addr[i]); diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index de67fce..e45d1f1 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -119,6 +119,18 @@ static int usb_extcon_probe(struct platform_device *pdev) return PTR_ERR(info->id_gpiod); } + info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); + if (IS_ERR(info->edev)) { + dev_err(dev, "failed to allocate extcon device\n"); + return -ENOMEM; + } + + ret = devm_extcon_dev_register(dev, info->edev); + if (ret < 0) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } + ret = gpiod_set_debounce(info->id_gpiod, USB_GPIO_DEBOUNCE_MS * 1000); if (ret < 0) @@ -142,18 +154,6 @@ static int usb_extcon_probe(struct platform_device *pdev) return ret; } - info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); - if (IS_ERR(info->edev)) { - dev_err(dev, "failed to allocate extcon device\n"); - return -ENOMEM; - } - - ret = devm_extcon_dev_register(dev, info->edev); - if (ret < 0) { - dev_err(dev, "failed to register extcon device\n"); - return ret; - } - platform_set_drvdata(pdev, info); device_init_wakeup(dev, 1); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 6e45a43..97b1616 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -499,19 +499,19 @@ static int __init dmi_present(const u8 *buf) buf += 16; if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) { + if (smbios_ver) + dmi_ver = smbios_ver; + else + dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F); dmi_num = get_unaligned_le16(buf + 12); dmi_len = get_unaligned_le16(buf + 6); dmi_base = get_unaligned_le32(buf + 8); if (dmi_walk_early(dmi_decode) == 0) { if (smbios_ver) { - dmi_ver = smbios_ver; - pr_info("SMBIOS %d.%d%s present.\n", - dmi_ver >> 8, dmi_ver & 0xFF, - (dmi_ver < 0x0300) ? "" : ".x"); + pr_info("SMBIOS %d.%d present.\n", + dmi_ver >> 8, dmi_ver & 0xFF); } else { - dmi_ver = (buf[14] & 0xF0) << 4 | - (buf[14] & 0x0F); pr_info("Legacy DMI %d.%d present.\n", dmi_ver >> 8, dmi_ver & 0xFF); } diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 87b8e3b..5c55227 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -120,7 +120,8 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr) entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { kset_unregister(map_kset); - return entry; + map_kset = NULL; + return ERR_PTR(-ENOMEM); } memcpy(&entry->md, efi_runtime_map + nr * efi_memdesc_size, @@ -132,6 +133,7 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr) if (ret) { kobject_put(&entry->kobj); kset_unregister(map_kset); + map_kset = NULL; return ERR_PTR(ret); } @@ -195,8 +197,6 @@ out_add_entry: entry = *(map_entries + j); kobject_put(&entry->kobj); } - if (map_kset) - kset_unregister(map_kset); out: return ret; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index cd1d5bf..b232397 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1054,38 +1054,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) dev_err(bank->dev, "Could not get gpio dbck\n"); } -static void -omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, - unsigned int num) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base, - handle_simple_irq); - if (!gc) { - dev_err(bank->dev, "Memory alloc failed for gc\n"); - return; - } - - ct = gc->chip_types; - - /* NOTE: No ack required, reading IRQ status clears it. */ - ct->chip.irq_mask = irq_gc_mask_set_bit; - ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_set_type = omap_gpio_irq_type; - - if (bank->regs->wkup_en) - ct->chip.irq_set_wake = omap_gpio_wake_enable; - - ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; - irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); -} - static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) { - int j; static int gpio; int irq_base = 0; int ret; @@ -1132,6 +1102,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) } #endif + /* MPUIO is a bit different, reading IRQ status clears it */ + if (bank->is_mpuio) { + irqc->irq_ack = dummy_irq_chip.irq_ack; + irqc->irq_mask = irq_gc_mask_set_bit; + irqc->irq_unmask = irq_gc_mask_clr_bit; + if (!bank->regs->wkup_en) + irqc->irq_set_wake = NULL; + } + ret = gpiochip_irqchip_add(&bank->chip, irqc, irq_base, omap_gpio_irq_handler, IRQ_TYPE_NONE); @@ -1145,15 +1124,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, omap_gpio_irq_handler); - for (j = 0; j < bank->width; j++) { - int irq = irq_find_mapping(bank->chip.irqdomain, j); - if (bank->is_mpuio) { - omap_mpuio_alloc_gc(bank, irq, bank->width); - irq_set_chip_and_handler(irq, NULL, NULL); - set_irq_flags(irq, 0); - } - } - return 0; } diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d2303d5..725d161 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -550,7 +550,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, length = min(agpio->pin_table_length, (u16)(pin_index + bits)); for (i = pin_index; i < length; ++i) { - unsigned pin = agpio->pin_table[i]; + int pin = agpio->pin_table[i]; struct acpi_gpio_connection *conn; struct gpio_desc *desc; bool found; diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 7722ed5..af3bc7a 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -551,6 +551,7 @@ static struct class gpio_class = { */ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { + struct gpio_chip *chip; unsigned long flags; int status; const char *ioname = NULL; @@ -568,8 +569,16 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) return -EINVAL; } + chip = desc->chip; + mutex_lock(&sysfs_lock); + /* check if chip is being removed */ + if (!chip || !chip->exported) { + status = -ENODEV; + goto fail_unlock; + } + spin_lock_irqsave(&gpio_lock, flags); if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { @@ -783,12 +792,15 @@ void gpiochip_unexport(struct gpio_chip *chip) { int status; struct device *dev; + struct gpio_desc *desc; + unsigned int i; mutex_lock(&sysfs_lock); dev = class_find_device(&gpio_class, NULL, chip, match_export); if (dev) { put_device(dev); device_unregister(dev); + /* prevent further gpiod exports */ chip->exported = false; status = 0; } else @@ -797,6 +809,13 @@ void gpiochip_unexport(struct gpio_chip *chip) if (status) chip_dbg(chip, "%s: status %d\n", __func__, status); + + /* unregister gpiod class devices owned by sysfs */ + for (i = 0; i < chip->ngpio; i++) { + desc = &chip->desc[i]; + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) + gpiod_free(desc); + } } static int __init gpiolib_sysfs_init(void) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 69af73f..596ee5c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -430,9 +430,10 @@ static int unregister_process_nocpsch(struct device_queue_manager *dqm, BUG_ON(!dqm || !qpd); - BUG_ON(!list_empty(&qpd->queues_list)); + pr_debug("In func %s\n", __func__); - pr_debug("kfd: In func %s\n", __func__); + pr_debug("qpd->queues_list is %s\n", + list_empty(&qpd->queues_list) ? "empty" : "not empty"); retval = 0; mutex_lock(&dqm->lock); @@ -882,6 +883,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, return -ENOMEM; } + init_sdma_vm(dqm, q, qpd); + retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval != 0) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 661c660..e469c4b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -728,9 +728,9 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute", dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz( dev->gpu->kgd)); + sysfs_show_64bit_prop(buffer, "local_mem_size", - dev->gpu->kfd2kgd->get_vmem_size( - dev->gpu->kgd)); + (unsigned long long int) 0); sysfs_show_32bit_prop(buffer, "fw_version", dev->gpu->kfd2kgd->get_fw_version( diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index c8a3447..af9662e 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -131,12 +131,11 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) /* Reinitialize corresponding vblank timestamp if high-precision query * available. Skip this step if query unsupported or failed. Will - * reinitialize delayed at next vblank interrupt in that case. + * reinitialize delayed at next vblank interrupt in that case and + * assign 0 for now, to mark the vblanktimestamp as invalid. */ - if (rc) { - tslot = atomic_read(&vblank->count) + diff; - vblanktimestamp(dev, crtc, tslot) = t_vblank; - } + tslot = atomic_read(&vblank->count) + diff; + vblanktimestamp(dev, crtc, tslot) = rc ? t_vblank : (struct timeval) {0, 0}; smp_mb__before_atomic(); atomic_add(diff, &vblank->count); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c302ffb..a19d2c7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -699,6 +699,16 @@ static int i915_drm_resume(struct drm_device *dev) intel_init_pch_refclk(dev); drm_mode_config_reset(dev); + /* + * Interrupts have to be enabled before any batches are run. If not the + * GPU will hang. i915_gem_init_hw() will initiate batches to + * update/restore the context. + * + * Modeset enabling in intel_modeset_init_hw() also needs working + * interrupts. + */ + intel_runtime_pm_enable_interrupts(dev_priv); + mutex_lock(&dev->struct_mutex); if (i915_gem_init_hw(dev)) { DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n"); @@ -706,9 +716,6 @@ static int i915_drm_resume(struct drm_device *dev) } mutex_unlock(&dev->struct_mutex); - /* We need working interrupts for modeset enabling ... */ - intel_runtime_pm_enable_interrupts(dev_priv); - intel_modeset_init_hw(dev); spin_lock_irq(&dev_priv->irq_lock); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d547d9c8..d0f3cbc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13635,9 +13635,6 @@ static const struct intel_dmi_quirk intel_dmi_quirks[] = { }; static struct intel_quirk intel_quirks[] = { - /* HP Mini needs pipe A force quirk (LP: #322104) */ - { 0x27ae, 0x103c, 0x361a, quirk_pipea_force }, - /* Toshiba Protege R-205, S-209 needs pipe A force quirk */ { 0x2592, 0x1179, 0x0001, quirk_pipea_force }, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d023710..f27346e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1348,7 +1348,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->has_dp_encoder = true; pipe_config->has_drrs = false; - pipe_config->has_audio = intel_dp->has_audio; + pipe_config->has_audio = intel_dp->has_audio && port != PORT_A; if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { intel_fixed_panel_mode(intel_connector->panel.fixed_mode, @@ -2211,8 +2211,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder, int dotclock; tmp = I915_READ(intel_dp->output_reg); - if (tmp & DP_AUDIO_OUTPUT_ENABLE) - pipe_config->has_audio = true; + + pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A; if ((port == PORT_A) || !HAS_PCH_CPT(dev)) { if (tmp & DP_SYNC_HS_HIGH) @@ -3812,7 +3812,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) if (val == 0) break; - intel_dp->sink_rates[i] = val * 200; + /* Value read is in kHz while drm clock is saved in deca-kHz */ + intel_dp->sink_rates[i] = (val * 200) / 10; } intel_dp->num_sink_rates = i; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 5abda1d..fbcc7df 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -813,12 +813,28 @@ static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) static const struct dmi_system_id intel_dual_link_lvds[] = { { .callback = intel_dual_link_lvds_callback, - .ident = "Apple MacBook Pro (Core i5/i7 Series)", + .ident = "Apple MacBook Pro 15\" (2010)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"), + }, + }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2011)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), }, }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2012)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"), + }, + }, { } /* terminating entry */ }; @@ -848,6 +864,11 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) if (i915.lvds_channel_mode > 0) return i915.lvds_channel_mode == 2; + /* single channel LVDS is limited to 112 MHz */ + if (lvds_encoder->attached_connector->base.panel.fixed_mode->clock + > 112999) + return true; + if (dmi_check_system(intel_dual_link_lvds)) return true; @@ -1111,6 +1132,8 @@ void intel_lvds_init(struct drm_device *dev) out: mutex_unlock(&dev->mode_config.mutex); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); + lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); DRM_DEBUG_KMS("detected %s-link lvds configuration\n", lvds_encoder->is_dual_link ? "dual" : "single"); @@ -1125,7 +1148,6 @@ out: } drm_connector_register(connector); - intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_panel_setup_backlight(connector, INVALID_PIPE); return; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 28faea9..a0c35bb 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5822,7 +5822,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) L2_CACHE_BIGK_FRAGMENT_SIZE(4)); /* setup context0 */ WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(rdev->dummy_page.addr >> 12)); @@ -5837,7 +5837,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) /* restore context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f848acf..05e6d6e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2485,7 +2485,7 @@ static int evergreen_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index e8a496f..aba2f42 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1282,7 +1282,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) L2_CACHE_BIGK_FRAGMENT_SIZE(6)); /* setup context0 */ WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(rdev->dummy_page.addr >> 12)); @@ -1301,7 +1301,8 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) */ for (i = 1; i < 8; i++) { WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), + rdev->vm_manager.max_pfn - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), rdev->vm_manager.saved_table_addr[i]); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 8f6d862..25b4ac9 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1112,7 +1112,7 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d2abe48..46eb0fa 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1673,7 +1673,6 @@ struct radeon_uvd { struct radeon_bo *vcpu_bo; void *cpu_addr; uint64_t gpu_addr; - void *saved_bo; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; unsigned img_size[RADEON_MAX_UVD_HANDLES]; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index fafd8ce..8dbf508 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1202,7 +1202,7 @@ static struct radeon_asic rs780_asic = { static struct radeon_asic_ring rv770_uvd_ring = { .ib_execute = &uvd_v1_0_ib_execute, .emit_fence = &uvd_v2_2_fence_emit, - .emit_semaphore = &uvd_v1_0_semaphore_emit, + .emit_semaphore = &uvd_v2_2_semaphore_emit, .cs_parse = &radeon_uvd_cs_parse, .ring_test = &uvd_v1_0_ring_test, .ib_test = &uvd_v1_0_ib_test, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index cf0a90b..a3ca8cd 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -949,6 +949,10 @@ void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int uvd_v2_2_resume(struct radeon_device *rdev); void uvd_v2_2_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait); /* uvd v3.1 */ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index 8b82abb..dcb7796 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -464,6 +464,10 @@ void radeon_audio_detect(struct drm_connector *connector, return; rdev = connector->encoder->dev->dev_private; + + if (!radeon_audio_chipset_supported(rdev)) + return; + radeon_encoder = to_radeon_encoder(connector->encoder); dig = radeon_encoder->enc_priv; diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 1017338..2b98ed3 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -666,6 +666,9 @@ radeon_dp_mst_probe(struct radeon_connector *radeon_connector) int ret; u8 msg[1]; + if (!radeon_mst) + return 0; + if (dig_connector->dpcd[DP_DPCD_REV] < 0x12) return 0; diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c index 535bf40..eef006c 100644 --- a/drivers/gpu/drm/radeon/radeon_mn.c +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -142,6 +142,9 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, list_for_each_entry(bo, &node->bos, mn_list) { + if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound) + continue; + r = radeon_bo_reserve(bo, true); if (r) { DRM_ERROR("(%ld) failed to reserve user bo\n", r); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index b292aca..edafd3c 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -591,8 +591,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) { struct radeon_device *rdev = radeon_get_rdev(ttm->bdev); struct radeon_ttm_tt *gtt = (void *)ttm; - struct scatterlist *sg; - int i; + struct sg_page_iter sg_iter; int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY); enum dma_data_direction direction = write ? @@ -605,9 +604,8 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) /* free the sg table and pages again */ dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); - for_each_sg(ttm->sg->sgl, sg, ttm->sg->nents, i) { - struct page *page = sg_page(sg); - + for_each_sg_page(ttm->sg->sgl, &sg_iter, ttm->sg->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY)) set_page_dirty(page); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index c10b2ae..6edcb54 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -204,28 +204,32 @@ void radeon_uvd_fini(struct radeon_device *rdev) int radeon_uvd_suspend(struct radeon_device *rdev) { - unsigned size; - void *ptr; - int i; + int i, r; if (rdev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) - if (atomic_read(&rdev->uvd.handles[i])) - break; + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + uint32_t handle = atomic_read(&rdev->uvd.handles[i]); + if (handle != 0) { + struct radeon_fence *fence; - if (i == RADEON_MAX_UVD_HANDLES) - return 0; + radeon_uvd_note_usage(rdev); - size = radeon_bo_size(rdev->uvd.vcpu_bo); - size -= rdev->uvd_fw->size; + r = radeon_uvd_get_destroy_msg(rdev, + R600_RING_TYPE_UVD_INDEX, handle, &fence); + if (r) { + DRM_ERROR("Error destroying UVD (%d)!\n", r); + continue; + } - ptr = rdev->uvd.cpu_addr; - ptr += rdev->uvd_fw->size; + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); - rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); - memcpy(rdev->uvd.saved_bo, ptr, size); + rdev->uvd.filp[i] = NULL; + atomic_set(&rdev->uvd.handles[i], 0); + } + } return 0; } @@ -246,12 +250,7 @@ int radeon_uvd_resume(struct radeon_device *rdev) ptr = rdev->uvd.cpu_addr; ptr += rdev->uvd_fw->size; - if (rdev->uvd.saved_bo != NULL) { - memcpy(ptr, rdev->uvd.saved_bo, size); - kfree(rdev->uvd.saved_bo); - rdev->uvd.saved_bo = NULL; - } else - memset(ptr, 0, size); + memset(ptr, 0, size); return 0; } @@ -396,6 +395,29 @@ static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) return 0; } +static int radeon_uvd_validate_codec(struct radeon_cs_parser *p, + unsigned stream_type) +{ + switch (stream_type) { + case 0: /* H264 */ + case 1: /* VC1 */ + /* always supported */ + return 0; + + case 3: /* MPEG2 */ + case 4: /* MPEG4 */ + /* only since UVD 3 */ + if (p->rdev->family >= CHIP_PALM) + return 0; + + /* fall through */ + default: + DRM_ERROR("UVD codec not supported by hardware %d!\n", + stream_type); + return -EINVAL; + } +} + static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, unsigned offset, unsigned buf_sizes[]) { @@ -436,50 +458,70 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - if (msg_type == 1) { - /* it's a decode msg, calc buffer sizes */ - r = radeon_uvd_cs_msg_decode(msg, buf_sizes); - /* calc image size (width * height) */ - img_size = msg[6] * msg[7]; + switch (msg_type) { + case 0: + /* it's a create msg, calc image size (width * height) */ + img_size = msg[7] * msg[8]; + + r = radeon_uvd_validate_codec(p, msg[4]); radeon_bo_kunmap(bo); if (r) return r; - } else if (msg_type == 2) { + /* try to alloc a new handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + DRM_ERROR("Handle 0x%x already in use!\n", handle); + return -EINVAL; + } + + if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { + p->rdev->uvd.filp[i] = p->filp; + p->rdev->uvd.img_size[i] = img_size; + return 0; + } + } + + DRM_ERROR("No more free UVD handles!\n"); + return -EINVAL; + + case 1: + /* it's a decode msg, validate codec and calc buffer sizes */ + r = radeon_uvd_validate_codec(p, msg[4]); + if (!r) + r = radeon_uvd_cs_msg_decode(msg, buf_sizes); + radeon_bo_kunmap(bo); + if (r) + return r; + + /* validate the handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + if (p->rdev->uvd.filp[i] != p->filp) { + DRM_ERROR("UVD handle collision detected!\n"); + return -EINVAL; + } + return 0; + } + } + + DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); + return -ENOENT; + + case 2: /* it's a destroy msg, free the handle */ for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); radeon_bo_kunmap(bo); return 0; - } else { - /* it's a create msg, calc image size (width * height) */ - img_size = msg[7] * msg[8]; - radeon_bo_kunmap(bo); - if (msg_type != 0) { - DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); - return -EINVAL; - } - - /* it's a create msg, no special handling needed */ - } - - /* create or decode, validate the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (atomic_read(&p->rdev->uvd.handles[i]) == handle) - return 0; - } + default: - /* handle not found try to alloc a new one */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { - p->rdev->uvd.filp[i] = p->filp; - p->rdev->uvd.img_size[i] = img_size; - return 0; - } + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); + return -EINVAL; } - DRM_ERROR("No more free UVD handles!\n"); + BUG(); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index 24f849f..0de5711 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -493,18 +493,27 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, * * @p: parser context * @handle: handle to validate + * @allocated: allocated a new handle? * * Validates the handle and return the found session index or -EINVAL * we we don't have another free session index. */ -int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) +static int radeon_vce_validate_handle(struct radeon_cs_parser *p, + uint32_t handle, bool *allocated) { unsigned i; + *allocated = false; + /* validate the handle */ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { - if (atomic_read(&p->rdev->vce.handles[i]) == handle) + if (atomic_read(&p->rdev->vce.handles[i]) == handle) { + if (p->rdev->vce.filp[i] != p->filp) { + DRM_ERROR("VCE handle collision detected!\n"); + return -EINVAL; + } return i; + } } /* handle not found try to alloc a new one */ @@ -512,6 +521,7 @@ int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { p->rdev->vce.filp[i] = p->filp; p->rdev->vce.img_size[i] = 0; + *allocated = true; return i; } } @@ -529,10 +539,10 @@ int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) int radeon_vce_cs_parse(struct radeon_cs_parser *p) { int session_idx = -1; - bool destroyed = false; + bool destroyed = false, created = false, allocated = false; uint32_t tmp, handle = 0; uint32_t *size = &tmp; - int i, r; + int i, r = 0; while (p->idx < p->chunk_ib->length_dw) { uint32_t len = radeon_get_ib_value(p, p->idx); @@ -540,18 +550,21 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) if ((len < 8) || (len & 3)) { DRM_ERROR("invalid VCE command length (%d)!\n", len); - return -EINVAL; + r = -EINVAL; + goto out; } if (destroyed) { DRM_ERROR("No other command allowed after destroy!\n"); - return -EINVAL; + r = -EINVAL; + goto out; } switch (cmd) { case 0x00000001: // session handle = radeon_get_ib_value(p, p->idx + 2); - session_idx = radeon_vce_validate_handle(p, handle); + session_idx = radeon_vce_validate_handle(p, handle, + &allocated); if (session_idx < 0) return session_idx; size = &p->rdev->vce.img_size[session_idx]; @@ -561,6 +574,13 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) break; case 0x01000001: // create + created = true; + if (!allocated) { + DRM_ERROR("Handle already in use!\n"); + r = -EINVAL; + goto out; + } + *size = radeon_get_ib_value(p, p->idx + 8) * radeon_get_ib_value(p, p->idx + 10) * 8 * 3 / 2; @@ -578,12 +598,12 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, *size); if (r) - return r; + goto out; r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, *size / 3); if (r) - return r; + goto out; break; case 0x02000001: // destroy @@ -594,7 +614,7 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, *size * 2); if (r) - return r; + goto out; break; case 0x05000004: // video bitstream buffer @@ -602,36 +622,47 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, tmp); if (r) - return r; + goto out; break; case 0x05000005: // feedback buffer r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 4096); if (r) - return r; + goto out; break; default: DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); - return -EINVAL; + r = -EINVAL; + goto out; } if (session_idx == -1) { DRM_ERROR("no session command at start of IB\n"); - return -EINVAL; + r = -EINVAL; + goto out; } p->idx += len / 4; } - if (destroyed) { - /* IB contains a destroy msg, free the handle */ + if (allocated && !created) { + DRM_ERROR("New session without create command!\n"); + r = -ENOENT; + } + +out: + if ((!r && destroyed) || (r && allocated)) { + /* + * IB contains a destroy msg or we have allocated an + * handle and got an error, anyway free the handle + */ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); } - return 0; + return r; } /** diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 01ee96a..c54d631 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -921,7 +921,7 @@ static int rv770_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 3cf1e29..9ef2064 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -989,6 +989,9 @@ ((n) & 0x3FFF) << 16) /* UVD */ +#define UVD_SEMA_ADDR_LOW 0xef00 +#define UVD_SEMA_ADDR_HIGH 0xef04 +#define UVD_SEMA_CMD 0xef08 #define UVD_GPCOM_VCPU_CMD 0xef0c #define UVD_GPCOM_VCPU_DATA0 0xef10 #define UVD_GPCOM_VCPU_DATA1 0xef14 diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index b1d74bc..5326f75 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -4303,7 +4303,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) L2_CACHE_BIGK_FRAGMENT_SIZE(4)); /* setup context0 */ WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end >> 12) - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(rdev->dummy_page.addr >> 12)); @@ -4318,7 +4318,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) /* empty context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); /* Assign the pt base to something valid for now; the pts used for * the VMs are determined by the application and setup and assigned * on the fly in the vm part of radeon_gart.c diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index e72b3cb..c6b1cbc 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -466,18 +466,8 @@ bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, struct radeon_semaphore *semaphore, bool emit_wait) { - uint64_t addr = semaphore->gpu_addr; - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); - radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); - radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); - radeon_ring_write(ring, emit_wait ? 1 : 0); - - return true; + /* disable semaphores for UVD V1 hardware */ + return false; } /** diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index 8919351..7ed778c 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -60,6 +60,35 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev, } /** + * uvd_v2_2_semaphore_emit - emit semaphore command + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * @semaphore: semaphore to emit commands for + * @emit_wait: true if we should emit a wait command + * + * Emit a semaphore command (either wait or signal) to the UVD ring. + */ +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait) +{ + uint64_t addr = semaphore->gpu_addr; + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); + radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); + radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); + radeon_ring_write(ring, emit_wait ? 1 : 0); + + return true; +} + +/** * uvd_v2_2_resume - memory controller programming * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 1833abd..bfad15a 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -173,7 +173,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) drm->irq_enabled = true; /* syncpoints are used for full 32-bit hardware VBLANK counters */ - drm->vblank_disable_immediate = true; drm->max_vblank_count = 0xffffffff; err = drm_vblank_init(drm, drm->mode_config.num_crtc); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index a04c49f..39ea67f 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -643,15 +643,6 @@ config BLK_DEV_TC86C001 help This driver adds support for Toshiba TC86C001 GOKU-S chip. -config BLK_DEV_CELLEB - tristate "Toshiba's Cell Reference Set IDE support" - depends on PPC_CELLEB - select BLK_DEV_IDEDMA_PCI - help - This driver provides support for the on-board IDE controller on - Toshiba Cell Reference Board. - If unsure, say Y. - endif # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index a04ee82..2a8c417 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o -obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c deleted file mode 100644 index 2a2d188..0000000 --- a/drivers/ide/scc_pata.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * Support for IDE interfaces on Celleb platform - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/ide/pci/siimage.c: - * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2003 Red Hat - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/ide.h> -#include <linux/init.h> - -#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 - -#define SCC_PATA_NAME "scc IDE" - -#define TDVHSEL_MASTER 0x00000001 -#define TDVHSEL_SLAVE 0x00000004 - -#define MODE_JCUSFEN 0x00000080 - -#define CCKCTRL_ATARESET 0x00040000 -#define CCKCTRL_BUFCNT 0x00020000 -#define CCKCTRL_CRST 0x00010000 -#define CCKCTRL_OCLKEN 0x00000100 -#define CCKCTRL_ATACLKOEN 0x00000002 -#define CCKCTRL_LCLKEN 0x00000001 - -#define QCHCD_IOS_SS 0x00000001 - -#define QCHSD_STPDIAG 0x00020000 - -#define INTMASK_MSK 0xD1000012 -#define INTSTS_SERROR 0x80000000 -#define INTSTS_PRERR 0x40000000 -#define INTSTS_RERR 0x10000000 -#define INTSTS_ICERR 0x01000000 -#define INTSTS_BMSINT 0x00000010 -#define INTSTS_BMHE 0x00000008 -#define INTSTS_IOIRQS 0x00000004 -#define INTSTS_INTRQ 0x00000002 -#define INTSTS_ACTEINT 0x00000001 - -#define ECMODE_VALUE 0x01 - -static struct scc_ports { - unsigned long ctl, dma; - struct ide_host *host; /* for removing port from system */ -} scc_ports[MAX_HWIFS]; - -/* PIO transfer mode table */ -/* JCHST */ -static unsigned long JCHSTtbl[2][7] = { - {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ - {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ -}; - -/* JCHHT */ -static unsigned long JCHHTtbl[2][7] = { - {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ - {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ -}; - -/* JCHCT */ -static unsigned long JCHCTtbl[2][7] = { - {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ - {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ -}; - - -/* DMA transfer mode table */ -/* JCHDCTM/JCHDCTS */ -static unsigned long JCHDCTxtbl[2][7] = { - {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ - {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ -}; - -/* JCSTWTM/JCSTWTS */ -static unsigned long JCSTWTxtbl[2][7] = { - {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ - {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ -}; - -/* JCTSS */ -static unsigned long JCTSStbl[2][7] = { - {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ - {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ -}; - -/* JCENVT */ -static unsigned long JCENVTtbl[2][7] = { - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ - {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ -}; - -/* JCACTSELS/JCACTSELM */ -static unsigned long JCACTSELtbl[2][7] = { - {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ -}; - - -static u8 scc_ide_inb(unsigned long port) -{ - u32 data = in_be32((void*)port); - return (u8)data; -} - -static void scc_exec_command(ide_hwif_t *hwif, u8 cmd) -{ - out_be32((void *)hwif->io_ports.command_addr, cmd); - eieio(); - in_be32((void *)(hwif->dma_base + 0x01c)); - eieio(); -} - -static u8 scc_read_status(ide_hwif_t *hwif) -{ - return (u8)in_be32((void *)hwif->io_ports.status_addr); -} - -static u8 scc_read_altstatus(ide_hwif_t *hwif) -{ - return (u8)in_be32((void *)hwif->io_ports.ctl_addr); -} - -static u8 scc_dma_sff_read_status(ide_hwif_t *hwif) -{ - return (u8)in_be32((void *)(hwif->dma_base + 4)); -} - -static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl) -{ - out_be32((void *)hwif->io_ports.ctl_addr, ctl); - eieio(); - in_be32((void *)(hwif->dma_base + 0x01c)); - eieio(); -} - -static void scc_ide_insw(unsigned long port, void *addr, u32 count) -{ - u16 *ptr = (u16 *)addr; - while (count--) { - *ptr++ = le16_to_cpu(in_be32((void*)port)); - } -} - -static void scc_ide_insl(unsigned long port, void *addr, u32 count) -{ - u16 *ptr = (u16 *)addr; - while (count--) { - *ptr++ = le16_to_cpu(in_be32((void*)port)); - *ptr++ = le16_to_cpu(in_be32((void*)port)); - } -} - -static void scc_ide_outb(u8 addr, unsigned long port) -{ - out_be32((void*)port, addr); -} - -static void -scc_ide_outsw(unsigned long port, void *addr, u32 count) -{ - u16 *ptr = (u16 *)addr; - while (count--) { - out_be32((void*)port, cpu_to_le16(*ptr++)); - } -} - -static void -scc_ide_outsl(unsigned long port, void *addr, u32 count) -{ - u16 *ptr = (u16 *)addr; - while (count--) { - out_be32((void*)port, cpu_to_le16(*ptr++)); - out_be32((void*)port, cpu_to_le16(*ptr++)); - } -} - -/** - * scc_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Load the timing settings for this device mode into the - * controller. - */ - -static void scc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct scc_ports *ports = ide_get_hwifdata(hwif); - unsigned long ctl_base = ports->ctl; - unsigned long cckctrl_port = ctl_base + 0xff0; - unsigned long piosht_port = ctl_base + 0x000; - unsigned long pioct_port = ctl_base + 0x004; - unsigned long reg; - int offset; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - reg = in_be32((void __iomem *)cckctrl_port); - if (reg & CCKCTRL_ATACLKOEN) { - offset = 1; /* 133MHz */ - } else { - offset = 0; /* 100MHz */ - } - reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio]; - out_be32((void __iomem *)piosht_port, reg); - reg = JCHCTtbl[offset][pio]; - out_be32((void __iomem *)pioct_port, reg); -} - -/** - * scc_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Load the timing settings for this device mode into the - * controller. - */ - -static void scc_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct scc_ports *ports = ide_get_hwifdata(hwif); - unsigned long ctl_base = ports->ctl; - unsigned long cckctrl_port = ctl_base + 0xff0; - unsigned long mdmact_port = ctl_base + 0x008; - unsigned long mcrcst_port = ctl_base + 0x00c; - unsigned long sdmact_port = ctl_base + 0x010; - unsigned long scrcst_port = ctl_base + 0x014; - unsigned long udenvt_port = ctl_base + 0x018; - unsigned long tdvhsel_port = ctl_base + 0x020; - int is_slave = drive->dn & 1; - int offset, idx; - unsigned long reg; - unsigned long jcactsel; - const u8 speed = drive->dma_mode; - - reg = in_be32((void __iomem *)cckctrl_port); - if (reg & CCKCTRL_ATACLKOEN) { - offset = 1; /* 133MHz */ - } else { - offset = 0; /* 100MHz */ - } - - idx = speed - XFER_UDMA_0; - - jcactsel = JCACTSELtbl[offset][idx]; - if (is_slave) { - out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]); - out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]); - jcactsel = jcactsel << 2; - out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel); - } else { - out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]); - out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]); - out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel); - } - reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; - out_be32((void __iomem *)udenvt_port, reg); -} - -static void scc_dma_host_set(ide_drive_t *drive, int on) -{ - ide_hwif_t *hwif = drive->hwif; - u8 unit = drive->dn & 1; - u8 dma_stat = scc_dma_sff_read_status(hwif); - - if (on) - dma_stat |= (1 << (5 + unit)); - else - dma_stat &= ~(1 << (5 + unit)); - - scc_ide_outb(dma_stat, hwif->dma_base + 4); -} - -/** - * scc_dma_setup - begin a DMA phase - * @drive: target device - * @cmd: command - * - * Build an IDE DMA PRD (IDE speak for scatter gather table) - * and then set up the DMA transfer registers. - * - * Returns 0 on success. If a PIO fallback is required then 1 - * is returned. - */ - -static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - u32 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; - u8 dma_stat; - - /* fall back to pio! */ - if (ide_build_dmatable(drive, cmd) == 0) - return 1; - - /* PRD table */ - out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); - - /* specify r/w */ - out_be32((void __iomem *)hwif->dma_base, rw); - - /* read DMA status for INTR & ERROR flags */ - dma_stat = scc_dma_sff_read_status(hwif); - - /* clear INTR & ERROR flags */ - out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6); - - return 0; -} - -static void scc_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_cmd = scc_ide_inb(hwif->dma_base); - - /* start DMA */ - scc_ide_outb(dma_cmd | 1, hwif->dma_base); -} - -static int __scc_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat, dma_cmd; - - /* get DMA command mode */ - dma_cmd = scc_ide_inb(hwif->dma_base); - /* stop DMA */ - scc_ide_outb(dma_cmd & ~1, hwif->dma_base); - /* get DMA status */ - dma_stat = scc_dma_sff_read_status(hwif); - /* clear the INTR & ERROR bits */ - scc_ide_outb(dma_stat | 6, hwif->dma_base + 4); - /* verify good DMA status */ - return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; -} - -/** - * scc_dma_end - Stop DMA - * @drive: IDE drive - * - * Check and clear INT Status register. - * Then call __scc_dma_end(). - */ - -static int scc_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *dma_base = (void __iomem *)hwif->dma_base; - unsigned long intsts_port = hwif->dma_base + 0x014; - u32 reg; - int dma_stat, data_loss = 0; - static int retry = 0; - - /* errata A308 workaround: Step5 (check data loss) */ - /* We don't check non ide_disk because it is limited to UDMA4 */ - if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr) - & ATA_ERR) && - drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) { - reg = in_be32((void __iomem *)intsts_port); - if (!(reg & INTSTS_ACTEINT)) { - printk(KERN_WARNING "%s: operation failed (transfer data loss)\n", - drive->name); - data_loss = 1; - if (retry++) { - struct request *rq = hwif->rq; - ide_drive_t *drive; - int i; - - /* ERROR_RESET and drive->crc_count are needed - * to reduce DMA transfer mode in retry process. - */ - if (rq) - rq->errors |= ERROR_RESET; - - ide_port_for_each_dev(i, drive, hwif) - drive->crc_count++; - } - } - } - - while (1) { - reg = in_be32((void __iomem *)intsts_port); - - if (reg & INTSTS_SERROR) { - printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME); - out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT); - - out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); - continue; - } - - if (reg & INTSTS_PRERR) { - u32 maea0, maec0; - unsigned long ctl_base = hwif->config_data; - - maea0 = in_be32((void __iomem *)(ctl_base + 0xF50)); - maec0 = in_be32((void __iomem *)(ctl_base + 0xF54)); - - printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0); - - out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT); - - out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); - continue; - } - - if (reg & INTSTS_RERR) { - printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME); - out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT); - - out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); - continue; - } - - if (reg & INTSTS_ICERR) { - out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); - - printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME); - out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT); - continue; - } - - if (reg & INTSTS_BMSINT) { - printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME); - out_be32((void __iomem *)intsts_port, INTSTS_BMSINT); - - ide_do_reset(drive); - continue; - } - - if (reg & INTSTS_BMHE) { - out_be32((void __iomem *)intsts_port, INTSTS_BMHE); - continue; - } - - if (reg & INTSTS_ACTEINT) { - out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT); - continue; - } - - if (reg & INTSTS_IOIRQS) { - out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS); - continue; - } - break; - } - - dma_stat = __scc_dma_end(drive); - if (data_loss) - dma_stat |= 2; /* emulate DMA error (to retry command) */ - return dma_stat; -} - -/* returns 1 if dma irq issued, 0 otherwise */ -static int scc_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014); - - /* SCC errata A252,A308 workaround: Step4 */ - if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr) - & ATA_ERR) && - (int_stat & INTSTS_INTRQ)) - return 1; - - /* SCC errata A308 workaround: Step5 (polling IOIRQS) */ - if (int_stat & INTSTS_IOIRQS) - return 1; - - return 0; -} - -static u8 scc_udma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 mask = hwif->ultra_mask; - - /* errata A308 workaround: limit non ide_disk drive to UDMA4 */ - if ((drive->media != ide_disk) && (mask & 0xE0)) { - printk(KERN_INFO "%s: limit %s to UDMA4\n", - SCC_PATA_NAME, drive->name); - mask = ATA_UDMA4; - } - - return mask; -} - -/** - * setup_mmio_scc - map CTRL/BMID region - * @dev: PCI device we are configuring - * @name: device name - * - */ - -static int setup_mmio_scc (struct pci_dev *dev, const char *name) -{ - void __iomem *ctl_addr; - void __iomem *dma_addr; - int i, ret; - - for (i = 0; i < MAX_HWIFS; i++) { - if (scc_ports[i].ctl == 0) - break; - } - if (i >= MAX_HWIFS) - return -ENOMEM; - - ret = pci_request_selected_regions(dev, (1 << 2) - 1, name); - if (ret < 0) { - printk(KERN_ERR "%s: can't reserve resources\n", name); - return ret; - } - - ctl_addr = pci_ioremap_bar(dev, 0); - if (!ctl_addr) - goto fail_0; - - dma_addr = pci_ioremap_bar(dev, 1); - if (!dma_addr) - goto fail_1; - - pci_set_master(dev); - scc_ports[i].ctl = (unsigned long)ctl_addr; - scc_ports[i].dma = (unsigned long)dma_addr; - pci_set_drvdata(dev, (void *) &scc_ports[i]); - - return 1; - - fail_1: - iounmap(ctl_addr); - fail_0: - return -ENOMEM; -} - -static int scc_ide_setup_pci_device(struct pci_dev *dev, - const struct ide_port_info *d) -{ - struct scc_ports *ports = pci_get_drvdata(dev); - struct ide_host *host; - struct ide_hw hw, *hws[] = { &hw }; - int i, rc; - - memset(&hw, 0, sizeof(hw)); - for (i = 0; i <= 8; i++) - hw.io_ports_array[i] = ports->dma + 0x20 + i * 4; - hw.irq = dev->irq; - hw.dev = &dev->dev; - - rc = ide_host_add(d, hws, 1, &host); - if (rc) - return rc; - - ports->host = host; - - return 0; -} - -/** - * init_setup_scc - set up an SCC PATA Controller - * @dev: PCI device - * @d: IDE port info - * - * Perform the initial set up for this device. - */ - -static int init_setup_scc(struct pci_dev *dev, const struct ide_port_info *d) -{ - unsigned long ctl_base; - unsigned long dma_base; - unsigned long cckctrl_port; - unsigned long intmask_port; - unsigned long mode_port; - unsigned long ecmode_port; - u32 reg = 0; - struct scc_ports *ports; - int rc; - - rc = pci_enable_device(dev); - if (rc) - goto end; - - rc = setup_mmio_scc(dev, d->name); - if (rc < 0) - goto end; - - ports = pci_get_drvdata(dev); - ctl_base = ports->ctl; - dma_base = ports->dma; - cckctrl_port = ctl_base + 0xff0; - intmask_port = dma_base + 0x010; - mode_port = ctl_base + 0x024; - ecmode_port = ctl_base + 0xf00; - - /* controller initialization */ - reg = 0; - out_be32((void*)cckctrl_port, reg); - reg |= CCKCTRL_ATACLKOEN; - out_be32((void*)cckctrl_port, reg); - reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; - out_be32((void*)cckctrl_port, reg); - reg |= CCKCTRL_CRST; - out_be32((void*)cckctrl_port, reg); - - for (;;) { - reg = in_be32((void*)cckctrl_port); - if (reg & CCKCTRL_CRST) - break; - udelay(5000); - } - - reg |= CCKCTRL_ATARESET; - out_be32((void*)cckctrl_port, reg); - - out_be32((void*)ecmode_port, ECMODE_VALUE); - out_be32((void*)mode_port, MODE_JCUSFEN); - out_be32((void*)intmask_port, INTMASK_MSK); - - rc = scc_ide_setup_pci_device(dev, d); - - end: - return rc; -} - -static void scc_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - struct ide_io_ports *io_ports = &drive->hwif->io_ports; - - if (valid & IDE_VALID_FEATURE) - scc_ide_outb(tf->feature, io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - scc_ide_outb(tf->nsect, io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - scc_ide_outb(tf->lbal, io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - scc_ide_outb(tf->lbam, io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - scc_ide_outb(tf->lbah, io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - scc_ide_outb(tf->device, io_ports->device_addr); -} - -static void scc_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - struct ide_io_ports *io_ports = &drive->hwif->io_ports; - - if (valid & IDE_VALID_ERROR) - tf->error = scc_ide_inb(io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - tf->nsect = scc_ide_inb(io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - tf->lbal = scc_ide_inb(io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - tf->lbam = scc_ide_inb(io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - tf->lbah = scc_ide_inb(io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - tf->device = scc_ide_inb(io_ports->device_addr); -} - -static void scc_input_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long data_addr = drive->hwif->io_ports.data_addr; - - len++; - - if (drive->io_32bit) { - scc_ide_insl(data_addr, buf, len / 4); - - if ((len & 3) >= 2) - scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1); - } else - scc_ide_insw(data_addr, buf, len / 2); -} - -static void scc_output_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long data_addr = drive->hwif->io_ports.data_addr; - - len++; - - if (drive->io_32bit) { - scc_ide_outsl(data_addr, buf, len / 4); - - if ((len & 3) >= 2) - scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1); - } else - scc_ide_outsw(data_addr, buf, len / 2); -} - -/** - * init_mmio_iops_scc - set up the iops for MMIO - * @hwif: interface to set up - * - */ - -static void init_mmio_iops_scc(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct scc_ports *ports = pci_get_drvdata(dev); - unsigned long dma_base = ports->dma; - - ide_set_hwifdata(hwif, ports); - - hwif->dma_base = dma_base; - hwif->config_data = ports->ctl; -} - -/** - * init_iops_scc - set up iops - * @hwif: interface to set up - * - * Do the basic setup for the SCC hardware interface - * and then do the MMIO setup. - */ - -static void init_iops_scc(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - - hwif->hwif_data = NULL; - if (pci_get_drvdata(dev) == NULL) - return; - init_mmio_iops_scc(hwif); -} - -static int scc_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - return ide_allocate_dma_engine(hwif); -} - -static u8 scc_cable_detect(ide_hwif_t *hwif) -{ - return ATA_CBL_PATA80; -} - -/** - * init_hwif_scc - set up hwif - * @hwif: interface to set up - * - * We do the basic set up of the interface structure. The SCC - * requires several custom handlers so we override the default - * ide DMA handlers appropriately. - */ - -static void init_hwif_scc(ide_hwif_t *hwif) -{ - /* PTERADD */ - out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); - - if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) - hwif->ultra_mask = ATA_UDMA6; /* 133MHz */ - else - hwif->ultra_mask = ATA_UDMA5; /* 100MHz */ -} - -static const struct ide_tp_ops scc_tp_ops = { - .exec_command = scc_exec_command, - .read_status = scc_read_status, - .read_altstatus = scc_read_altstatus, - .write_devctl = scc_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = scc_tf_load, - .tf_read = scc_tf_read, - - .input_data = scc_input_data, - .output_data = scc_output_data, -}; - -static const struct ide_port_ops scc_port_ops = { - .set_pio_mode = scc_set_pio_mode, - .set_dma_mode = scc_set_dma_mode, - .udma_filter = scc_udma_filter, - .cable_detect = scc_cable_detect, -}; - -static const struct ide_dma_ops scc_dma_ops = { - .dma_host_set = scc_dma_host_set, - .dma_setup = scc_dma_setup, - .dma_start = scc_dma_start, - .dma_end = scc_dma_end, - .dma_test_irq = scc_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = scc_dma_sff_read_status, -}; - -static const struct ide_port_info scc_chipset = { - .name = "sccIDE", - .init_iops = init_iops_scc, - .init_dma = scc_init_dma, - .init_hwif = init_hwif_scc, - .tp_ops = &scc_tp_ops, - .port_ops = &scc_port_ops, - .dma_ops = &scc_dma_ops, - .host_flags = IDE_HFLAG_SINGLE, - .irq_flags = IRQF_SHARED, - .pio_mask = ATA_PIO4, - .chipset = ide_pci, -}; - -/** - * scc_init_one - pci layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds an SCC PATA controller. - * We then use the IDE PCI generic helper to do most of the work. - */ - -static int scc_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return init_setup_scc(dev, &scc_chipset); -} - -/** - * scc_remove - pci layer remove entry - * @dev: PCI device - * - * Called by the PCI code when it removes an SCC PATA controller. - */ - -static void scc_remove(struct pci_dev *dev) -{ - struct scc_ports *ports = pci_get_drvdata(dev); - struct ide_host *host = ports->host; - - ide_host_remove(host); - - iounmap((void*)ports->dma); - iounmap((void*)ports->ctl); - pci_release_selected_regions(dev, (1 << 2) - 1); - memset(ports, 0, sizeof(*ports)); -} - -static const struct pci_device_id scc_pci_tbl[] = { - { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, scc_pci_tbl); - -static struct pci_driver scc_pci_driver = { - .name = "SCC IDE", - .id_table = scc_pci_tbl, - .probe = scc_init_one, - .remove = scc_remove, -}; - -static int __init scc_ide_init(void) -{ - return ide_pci_register_driver(&scc_pci_driver); -} - -static void __exit scc_ide_exit(void) -{ - pci_unregister_driver(&scc_pci_driver); -} - -module_init(scc_ide_init); -module_exit(scc_ide_exit); - -MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 7f55a6d..c6d5a3a 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -389,7 +389,12 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, { int ret, i; int len_words = len / sizeof(u16); - __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS]; + __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; + + if (len_words > ARRAY_SIZE(be_buf)) { + dev_err(&client->dev, "Invalid buffer size %d\n", len); + return -EINVAL; + } ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, (u8 *) be_buf, len); @@ -424,7 +429,12 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id, { int ret, i; int len_words = len / sizeof(u16); - __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS]; + __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; + + if (len_words > ARRAY_SIZE(be_buf)) { + dev_err(&client->dev, "Invalid buffer size %d\n", len); + return -EINVAL; + } ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, (u8 *) be_buf, len); @@ -459,7 +469,12 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id, { int i; int len_words = len / sizeof(u16); - __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS]; + __be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2]; + + if (len_words > ARRAY_SIZE(be_buf)) { + dev_err(&client->dev, "Invalid buffer size %d\n", len); + return -EINVAL; + } for (i = 0; i < len_words; i++) be_buf[i] = cpu_to_be16(buf[i]); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 2df1af7..365a109 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -54,6 +54,7 @@ #define MMA9553_MASK_CONF_STEPCOALESCE GENMASK(7, 0) #define MMA9553_REG_CONF_ACTTHD 0x0E +#define MMA9553_MAX_ACTTHD GENMASK(15, 0) /* Pedometer status registers (R-only) */ #define MMA9553_REG_STATUS 0x00 @@ -316,22 +317,19 @@ static int mma9553_set_config(struct mma9553_data *data, u16 reg, static int mma9553_read_activity_stepcnt(struct mma9553_data *data, u8 *activity, u16 *stepcnt) { - u32 status_stepcnt; - u16 status; + u16 buf[2]; int ret; ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER, - MMA9553_REG_STATUS, sizeof(u32), - (u16 *) &status_stepcnt); + MMA9553_REG_STATUS, sizeof(u32), buf); if (ret < 0) { dev_err(&data->client->dev, "error reading status and stepcnt\n"); return ret; } - status = status_stepcnt & MMA9553_MASK_CONF_WORD; - *activity = mma9553_get_bits(status, MMA9553_MASK_STATUS_ACTIVITY); - *stepcnt = status_stepcnt >> 16; + *activity = mma9553_get_bits(buf[0], MMA9553_MASK_STATUS_ACTIVITY); + *stepcnt = buf[1]; return 0; } @@ -872,6 +870,9 @@ static int mma9553_write_event_value(struct iio_dev *indio_dev, case IIO_EV_INFO_PERIOD: switch (chan->type) { case IIO_ACTIVITY: + if (val < 0 || val > MMA9553_ACTIVITY_THD_TO_SEC( + MMA9553_MAX_ACTTHD)) + return -EINVAL; mutex_lock(&data->mutex); ret = mma9553_set_config(data, MMA9553_REG_CONF_ACTTHD, &data->conf.actthd, @@ -971,7 +972,8 @@ static const struct iio_chan_spec_ext_info mma9553_ext_info[] = { .modified = 1, \ .channel2 = _chan2, \ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ .event_spec = mma9553_activity_events, \ .num_event_specs = ARRAY_SIZE(mma9553_activity_events), \ .ext_info = mma9553_ext_info, \ diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 58d1d13..211b132 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -546,6 +546,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; + mutex_init(&adata->tb.buf_lock); st_sensors_power_enable(indio_dev); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 08bcfb0..56008a8 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -53,39 +53,42 @@ static const struct iio_chan_spec const axp288_adc_channels[] = { .channel = 0, .address = AXP288_TS_ADC_H, .datasheet_name = "TS_PIN", + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, { .indexed = 1, .type = IIO_TEMP, .channel = 1, .address = AXP288_PMIC_ADC_H, .datasheet_name = "PMIC_TEMP", + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, { .indexed = 1, .type = IIO_TEMP, .channel = 2, .address = AXP288_GP_ADC_H, .datasheet_name = "GPADC", + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, { .indexed = 1, .type = IIO_CURRENT, .channel = 3, .address = AXP20X_BATT_CHRG_I_H, .datasheet_name = "BATT_CHG_I", - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, { .indexed = 1, .type = IIO_CURRENT, .channel = 4, .address = AXP20X_BATT_DISCHRG_I_H, .datasheet_name = "BATT_DISCHRG_I", - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, { .indexed = 1, .type = IIO_VOLTAGE, .channel = 5, .address = AXP20X_BATT_V_H, .datasheet_name = "BATT_V", - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }, }; @@ -151,9 +154,6 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev, chan->address)) dev_err(&indio_dev->dev, "TS pin restore\n"); break; - case IIO_CHAN_INFO_PROCESSED: - ret = axp288_adc_read_channel(val, chan->address, info->regmap); - break; default: ret = -EINVAL; } diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 51e2a83..115f6e9 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -35,8 +35,9 @@ #define CC10001_ADC_EOC_SET BIT(0) #define CC10001_ADC_CHSEL_SAMPLED 0x0c -#define CC10001_ADC_POWER_UP 0x10 -#define CC10001_ADC_POWER_UP_SET BIT(0) +#define CC10001_ADC_POWER_DOWN 0x10 +#define CC10001_ADC_POWER_DOWN_SET BIT(0) + #define CC10001_ADC_DEBUG 0x14 #define CC10001_ADC_DATA_COUNT 0x20 @@ -62,7 +63,6 @@ struct cc10001_adc_device { u16 *buf; struct mutex lock; - unsigned long channel_map; unsigned int start_delay_ns; unsigned int eoc_delay_ns; }; @@ -79,6 +79,18 @@ static inline u32 cc10001_adc_read_reg(struct cc10001_adc_device *adc_dev, return readl(adc_dev->reg_base + reg); } +static void cc10001_adc_power_up(struct cc10001_adc_device *adc_dev) +{ + cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_DOWN, 0); + ndelay(adc_dev->start_delay_ns); +} + +static void cc10001_adc_power_down(struct cc10001_adc_device *adc_dev) +{ + cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_DOWN, + CC10001_ADC_POWER_DOWN_SET); +} + static void cc10001_adc_start(struct cc10001_adc_device *adc_dev, unsigned int channel) { @@ -88,6 +100,7 @@ static void cc10001_adc_start(struct cc10001_adc_device *adc_dev, val = (channel & CC10001_ADC_CH_MASK) | CC10001_ADC_MODE_SINGLE_CONV; cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val); + udelay(1); val = cc10001_adc_read_reg(adc_dev, CC10001_ADC_CONFIG); val = val | CC10001_ADC_START_CONV; cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val); @@ -129,6 +142,7 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p) struct iio_dev *indio_dev; unsigned int delay_ns; unsigned int channel; + unsigned int scan_idx; bool sample_invalid; u16 *data; int i; @@ -139,20 +153,17 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p) mutex_lock(&adc_dev->lock); - cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, - CC10001_ADC_POWER_UP_SET); - - /* Wait for 8 (6+2) clock cycles before activating START */ - ndelay(adc_dev->start_delay_ns); + cc10001_adc_power_up(adc_dev); /* Calculate delay step for eoc and sampled data */ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; i = 0; sample_invalid = false; - for_each_set_bit(channel, indio_dev->active_scan_mask, + for_each_set_bit(scan_idx, indio_dev->active_scan_mask, indio_dev->masklength) { + channel = indio_dev->channels[scan_idx].channel; cc10001_adc_start(adc_dev, channel); data[i] = cc10001_adc_poll_done(indio_dev, channel, delay_ns); @@ -166,7 +177,7 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p) } done: - cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0); + cc10001_adc_power_down(adc_dev); mutex_unlock(&adc_dev->lock); @@ -185,11 +196,7 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev, unsigned int delay_ns; u16 val; - cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, - CC10001_ADC_POWER_UP_SET); - - /* Wait for 8 (6+2) clock cycles before activating START */ - ndelay(adc_dev->start_delay_ns); + cc10001_adc_power_up(adc_dev); /* Calculate delay step for eoc and sampled data */ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; @@ -198,7 +205,7 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev, val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns); - cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0); + cc10001_adc_power_down(adc_dev); return val; } @@ -224,7 +231,7 @@ static int cc10001_adc_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: ret = regulator_get_voltage(adc_dev->reg); - if (ret) + if (ret < 0) return ret; *val = ret / 1000; @@ -255,22 +262,22 @@ static const struct iio_info cc10001_adc_info = { .update_scan_mode = &cc10001_update_scan_mode, }; -static int cc10001_adc_channel_init(struct iio_dev *indio_dev) +static int cc10001_adc_channel_init(struct iio_dev *indio_dev, + unsigned long channel_map) { - struct cc10001_adc_device *adc_dev = iio_priv(indio_dev); struct iio_chan_spec *chan_array, *timestamp; unsigned int bit, idx = 0; - indio_dev->num_channels = bitmap_weight(&adc_dev->channel_map, - CC10001_ADC_NUM_CHANNELS); + indio_dev->num_channels = bitmap_weight(&channel_map, + CC10001_ADC_NUM_CHANNELS) + 1; - chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels + 1, + chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels, sizeof(struct iio_chan_spec), GFP_KERNEL); if (!chan_array) return -ENOMEM; - for_each_set_bit(bit, &adc_dev->channel_map, CC10001_ADC_NUM_CHANNELS) { + for_each_set_bit(bit, &channel_map, CC10001_ADC_NUM_CHANNELS) { struct iio_chan_spec *chan = &chan_array[idx]; chan->type = IIO_VOLTAGE; @@ -305,6 +312,7 @@ static int cc10001_adc_probe(struct platform_device *pdev) unsigned long adc_clk_rate; struct resource *res; struct iio_dev *indio_dev; + unsigned long channel_map; int ret; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev)); @@ -313,9 +321,9 @@ static int cc10001_adc_probe(struct platform_device *pdev) adc_dev = iio_priv(indio_dev); - adc_dev->channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0); + channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0); if (!of_property_read_u32(node, "adc-reserved-channels", &ret)) - adc_dev->channel_map &= ~ret; + channel_map &= ~ret; adc_dev->reg = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(adc_dev->reg)) @@ -361,7 +369,7 @@ static int cc10001_adc_probe(struct platform_device *pdev) adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES; /* Setup the ADC channels available on the device */ - ret = cc10001_adc_channel_init(indio_dev); + ret = cc10001_adc_channel_init(indio_dev, channel_map); if (ret < 0) goto err_disable_clk; diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index efbfd12..8d9c9b9 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -60,12 +60,12 @@ struct mcp320x { struct spi_message msg; struct spi_transfer transfer[2]; - u8 tx_buf; - u8 rx_buf[2]; - struct regulator *reg; struct mutex lock; const struct mcp320x_chip_info *chip_info; + + u8 tx_buf ____cacheline_aligned; + u8 rx_buf[2]; }; static int mcp320x_channel_to_tx_data(int device_index, diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index 3211729..0c4618b 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -18,6 +18,7 @@ #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -471,11 +472,11 @@ static s32 vadc_calibrate(struct vadc_priv *vadc, const struct vadc_channel_prop *prop, u16 adc_code) { const struct vadc_prescale_ratio *prescale; - s32 voltage; + s64 voltage; voltage = adc_code - vadc->graph[prop->calibration].gnd; voltage *= vadc->graph[prop->calibration].dx; - voltage = voltage / vadc->graph[prop->calibration].dy; + voltage = div64_s64(voltage, vadc->graph[prop->calibration].dy); if (prop->calibration == VADC_CALIB_ABSOLUTE) voltage += vadc->graph[prop->calibration].dx; @@ -487,7 +488,7 @@ static s32 vadc_calibrate(struct vadc_priv *vadc, voltage = voltage * prescale->den; - return voltage / prescale->num; + return div64_s64(voltage, prescale->num); } static int vadc_decimation_from_dt(u32 value) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index a221f73..ce93bd8 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -856,6 +856,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev, switch (chan->address) { case XADC_REG_VCCINT: case XADC_REG_VCCAUX: + case XADC_REG_VREFP: case XADC_REG_VCCBRAM: case XADC_REG_VCCPINT: case XADC_REG_VCCPAUX: @@ -996,7 +997,7 @@ static const struct iio_event_spec xadc_voltage_events[] = { .num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \ .scan_index = (_scan_index), \ .scan_type = { \ - .sign = 'u', \ + .sign = ((_addr) == XADC_REG_VREFN) ? 's' : 'u', \ .realbits = 12, \ .storagebits = 16, \ .shift = 4, \ @@ -1008,7 +1009,7 @@ static const struct iio_event_spec xadc_voltage_events[] = { static const struct iio_chan_spec xadc_channels[] = { XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP), XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), - XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true), + XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true), XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true), XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true), diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index c7487e8..54adc50 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -145,9 +145,9 @@ static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg, #define XADC_REG_MAX_VCCPINT 0x28 #define XADC_REG_MAX_VCCPAUX 0x29 #define XADC_REG_MAX_VCCO_DDR 0x2a -#define XADC_REG_MIN_VCCPINT 0x2b -#define XADC_REG_MIN_VCCPAUX 0x2c -#define XADC_REG_MIN_VCCO_DDR 0x2d +#define XADC_REG_MIN_VCCPINT 0x2c +#define XADC_REG_MIN_VCCPAUX 0x2d +#define XADC_REG_MIN_VCCO_DDR 0x2e #define XADC_REG_CONF0 0x40 #define XADC_REG_CONF1 0x41 diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index edd13d2..8dd0477 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -304,8 +304,6 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, struct st_sensors_platform_data *of_pdata; int err = 0; - mutex_init(&sdata->tb.buf_lock); - /* If OF/DT pdata exists, it will take precedence of anything else */ of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata); if (of_pdata) diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 21395f2..ffe9664 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -400,6 +400,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; + mutex_init(&gdata->tb.buf_lock); st_sensors_power_enable(indio_dev); diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index 847ca56..55c267b 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -38,7 +38,8 @@ static int iio_request_update_kfifo(struct iio_buffer *r) kfifo_free(&buf->kf); ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, buf->buffer.length); - buf->update_needed = false; + if (ret >= 0) + buf->update_needed = false; } else { kfifo_reset_out(&buf->kf); } diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 91ecc46..ef60bae 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -43,8 +43,6 @@ struct prox_state { static const struct iio_chan_spec prox_channels[] = { { .type = IIO_PROXIMITY, - .modified = 1, - .channel2 = IIO_NO_MOD, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | @@ -253,7 +251,6 @@ static int hid_prox_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct prox_state *prox_state; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; - struct iio_chan_spec *channels; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state)); @@ -272,20 +269,21 @@ static int hid_prox_probe(struct platform_device *pdev) return ret; } - channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL); - if (!channels) { + indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels), + GFP_KERNEL); + if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; } - ret = prox_parse_report(pdev, hsdev, channels, + ret = prox_parse_report(pdev, hsdev, + (struct iio_chan_spec *)indio_dev->channels, HID_USAGE_SENSOR_PROX, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); goto error_free_dev_mem; } - indio_dev->channels = channels; indio_dev->num_channels = ARRAY_SIZE(prox_channels); indio_dev->dev.parent = &pdev->dev; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8ade473..2e56f81 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -369,6 +369,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; + mutex_init(&mdata->tb.buf_lock); st_sensors_power_enable(indio_dev); diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index 7c623e2..a2602d8 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -172,6 +172,7 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data, var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) * ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) * ((s32)(s16)le16_to_cpu(buf[T3]))) >> 14; + data->t_fine = var1 + var2; return (data->t_fine * 5 + 128) >> 8; } diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 7bb8d4c..3cf0bd6 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -47,8 +47,6 @@ struct press_state { static const struct iio_chan_spec press_channels[] = { { .type = IIO_PRESSURE, - .modified = 1, - .channel2 = IIO_NO_MOD, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 97baf40d..e881fa6 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -417,6 +417,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; + mutex_init(&press_data->tb.buf_lock); st_sensors_power_enable(indio_dev); diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index f80da50..38339d2 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -472,13 +472,8 @@ int rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *dmac, } sgid_addr, dgid_addr; - ret = rdma_gid2ip(&sgid_addr._sockaddr, sgid); - if (ret) - return ret; - - ret = rdma_gid2ip(&dgid_addr._sockaddr, dgid); - if (ret) - return ret; + rdma_gid2ip(&sgid_addr._sockaddr, sgid); + rdma_gid2ip(&dgid_addr._sockaddr, dgid); memset(&dev_addr, 0, sizeof(dev_addr)); @@ -512,10 +507,8 @@ int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id) struct sockaddr_in6 _sockaddr_in6; } gid_addr; - ret = rdma_gid2ip(&gid_addr._sockaddr, sgid); + rdma_gid2ip(&gid_addr._sockaddr, sgid); - if (ret) - return ret; memset(&dev_addr, 0, sizeof(dev_addr)); ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id); if (ret) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index e28a494..0c14191 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -437,39 +437,38 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) return cm_id_priv; } -static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) +static void cm_mask_copy(u32 *dst, const u32 *src, const u32 *mask) { int i; - for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) - ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & - ((unsigned long *) mask)[i]; + for (i = 0; i < IB_CM_COMPARE_SIZE; i++) + dst[i] = src[i] & mask[i]; } static int cm_compare_data(struct ib_cm_compare_data *src_data, struct ib_cm_compare_data *dst_data) { - u8 src[IB_CM_COMPARE_SIZE]; - u8 dst[IB_CM_COMPARE_SIZE]; + u32 src[IB_CM_COMPARE_SIZE]; + u32 dst[IB_CM_COMPARE_SIZE]; if (!src_data || !dst_data) return 0; cm_mask_copy(src, src_data->data, dst_data->mask); cm_mask_copy(dst, dst_data->data, src_data->mask); - return memcmp(src, dst, IB_CM_COMPARE_SIZE); + return memcmp(src, dst, sizeof(src)); } -static int cm_compare_private_data(u8 *private_data, +static int cm_compare_private_data(u32 *private_data, struct ib_cm_compare_data *dst_data) { - u8 src[IB_CM_COMPARE_SIZE]; + u32 src[IB_CM_COMPARE_SIZE]; if (!dst_data) return 0; cm_mask_copy(src, private_data, dst_data->mask); - return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); + return memcmp(src, dst_data->data, sizeof(src)); } /* @@ -538,7 +537,7 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) static struct cm_id_private * cm_find_listen(struct ib_device *device, __be64 service_id, - u8 *private_data) + u32 *private_data) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; @@ -953,7 +952,7 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, cm_mask_copy(cm_id_priv->compare_data->data, compare_data->data, compare_data->mask); memcpy(cm_id_priv->compare_data->mask, compare_data->mask, - IB_CM_COMPARE_SIZE); + sizeof(compare_data->mask)); } cm_id->state = IB_CM_LISTEN; diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h index be068f4..8b76f0e 100644 --- a/drivers/infiniband/core/cm_msgs.h +++ b/drivers/infiniband/core/cm_msgs.h @@ -103,7 +103,7 @@ struct cm_req_msg { /* local ACK timeout:5, rsvd:3 */ u8 alt_offset139; - u8 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE]; + u32 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE / sizeof(u32)]; } __attribute__ ((packed)); @@ -801,7 +801,7 @@ struct cm_sidr_req_msg { __be16 rsvd; __be64 service_id; - u8 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE]; + u32 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE / sizeof(u32)]; } __attribute__ ((packed)); struct cm_sidr_rep_msg { diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index d570030..06441a4 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -859,19 +859,27 @@ static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id memcpy(&ib->sib_addr, &path->dgid, 16); } +static __be16 ss_get_port(const struct sockaddr_storage *ss) +{ + if (ss->ss_family == AF_INET) + return ((struct sockaddr_in *)ss)->sin_port; + else if (ss->ss_family == AF_INET6) + return ((struct sockaddr_in6 *)ss)->sin6_port; + BUG(); +} + static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, struct cma_hdr *hdr) { - struct sockaddr_in *listen4, *ip4; + struct sockaddr_in *ip4; - listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr; ip4 = (struct sockaddr_in *) &id->route.addr.src_addr; - ip4->sin_family = listen4->sin_family; + ip4->sin_family = AF_INET; ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr; - ip4->sin_port = listen4->sin_port; + ip4->sin_port = ss_get_port(&listen_id->route.addr.src_addr); ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr; - ip4->sin_family = listen4->sin_family; + ip4->sin_family = AF_INET; ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr; ip4->sin_port = hdr->port; } @@ -879,16 +887,15 @@ static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_i static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, struct cma_hdr *hdr) { - struct sockaddr_in6 *listen6, *ip6; + struct sockaddr_in6 *ip6; - listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr; ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr; - ip6->sin6_family = listen6->sin6_family; + ip6->sin6_family = AF_INET6; ip6->sin6_addr = hdr->dst_addr.ip6; - ip6->sin6_port = listen6->sin6_port; + ip6->sin6_port = ss_get_port(&listen_id->route.addr.src_addr); ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr; - ip6->sin6_family = listen6->sin6_family; + ip6->sin6_family = AF_INET6; ip6->sin6_addr = hdr->src_addr.ip6; ip6->sin6_port = hdr->port; } diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c index b85ddbc..e6ffa2e 100644 --- a/drivers/infiniband/core/iwpm_msg.c +++ b/drivers/infiniband/core/iwpm_msg.c @@ -33,7 +33,7 @@ #include "iwpm_util.h" -static const char iwpm_ulib_name[] = "iWarpPortMapperUser"; +static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser"; static int iwpm_ulib_version = 3; static int iwpm_user_pid = IWPM_PID_UNDEFINED; static atomic_t echo_nlmsg_seq; @@ -468,7 +468,8 @@ add_mapping_response_exit: } EXPORT_SYMBOL(iwpm_add_mapping_cb); -/* netlink attribute policy for the response to add and query mapping request */ +/* netlink attribute policy for the response to add and query mapping request + * and response with remote address info */ static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = { [IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 }, [IWPM_NLA_QUERY_LOCAL_ADDR] = { .len = sizeof(struct sockaddr_storage) }, @@ -559,6 +560,76 @@ query_mapping_response_exit: } EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb); +/* + * iwpm_remote_info_cb - Process a port mapper message, containing + * the remote connecting peer address info + */ +int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX]; + struct sockaddr_storage *local_sockaddr, *remote_sockaddr; + struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr; + struct iwpm_remote_info *rem_info; + const char *msg_type; + u8 nl_client; + int ret = -EINVAL; + + msg_type = "Remote Mapping info"; + if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX, + resp_query_policy, nltb, msg_type)) + return ret; + + nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); + if (!iwpm_valid_client(nl_client)) { + pr_info("%s: Invalid port mapper client = %d\n", + __func__, nl_client); + return ret; + } + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + + local_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]); + remote_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]); + mapped_loc_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]); + mapped_rem_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]); + + if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family || + mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) { + pr_info("%s: Sockaddr family doesn't match the requested one\n", + __func__); + return ret; + } + rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC); + if (!rem_info) { + pr_err("%s: Unable to allocate a remote info\n", __func__); + ret = -ENOMEM; + return ret; + } + memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr, + sizeof(struct sockaddr_storage)); + memcpy(&rem_info->remote_sockaddr, remote_sockaddr, + sizeof(struct sockaddr_storage)); + memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr, + sizeof(struct sockaddr_storage)); + rem_info->nl_client = nl_client; + + iwpm_add_remote_info(rem_info); + + iwpm_print_sockaddr(local_sockaddr, + "remote_info: Local sockaddr:"); + iwpm_print_sockaddr(mapped_loc_sockaddr, + "remote_info: Mapped local sockaddr:"); + iwpm_print_sockaddr(remote_sockaddr, + "remote_info: Remote sockaddr:"); + iwpm_print_sockaddr(mapped_rem_sockaddr, + "remote_info: Mapped remote sockaddr:"); + return ret; +} +EXPORT_SYMBOL(iwpm_remote_info_cb); + /* netlink attribute policy for the received request for mapping info */ static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index 69e9f84..a626795 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -33,8 +33,10 @@ #include "iwpm_util.h" -#define IWPM_HASH_BUCKET_SIZE 512 -#define IWPM_HASH_BUCKET_MASK (IWPM_HASH_BUCKET_SIZE - 1) +#define IWPM_MAPINFO_HASH_SIZE 512 +#define IWPM_MAPINFO_HASH_MASK (IWPM_MAPINFO_HASH_SIZE - 1) +#define IWPM_REMINFO_HASH_SIZE 64 +#define IWPM_REMINFO_HASH_MASK (IWPM_REMINFO_HASH_SIZE - 1) static LIST_HEAD(iwpm_nlmsg_req_list); static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock); @@ -42,31 +44,49 @@ static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock); static struct hlist_head *iwpm_hash_bucket; static DEFINE_SPINLOCK(iwpm_mapinfo_lock); +static struct hlist_head *iwpm_reminfo_bucket; +static DEFINE_SPINLOCK(iwpm_reminfo_lock); + static DEFINE_MUTEX(iwpm_admin_lock); static struct iwpm_admin_data iwpm_admin; int iwpm_init(u8 nl_client) { + int ret = 0; if (iwpm_valid_client(nl_client)) return -EINVAL; mutex_lock(&iwpm_admin_lock); if (atomic_read(&iwpm_admin.refcount) == 0) { - iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE * + iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE * sizeof(struct hlist_head), GFP_KERNEL); if (!iwpm_hash_bucket) { - mutex_unlock(&iwpm_admin_lock); + ret = -ENOMEM; pr_err("%s Unable to create mapinfo hash table\n", __func__); - return -ENOMEM; + goto init_exit; + } + iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE * + sizeof(struct hlist_head), GFP_KERNEL); + if (!iwpm_reminfo_bucket) { + kfree(iwpm_hash_bucket); + ret = -ENOMEM; + pr_err("%s Unable to create reminfo hash table\n", __func__); + goto init_exit; } } atomic_inc(&iwpm_admin.refcount); +init_exit: mutex_unlock(&iwpm_admin_lock); - iwpm_set_valid(nl_client, 1); - return 0; + if (!ret) { + iwpm_set_valid(nl_client, 1); + pr_debug("%s: Mapinfo and reminfo tables are created\n", + __func__); + } + return ret; } EXPORT_SYMBOL(iwpm_init); static void free_hash_bucket(void); +static void free_reminfo_bucket(void); int iwpm_exit(u8 nl_client) { @@ -81,7 +101,8 @@ int iwpm_exit(u8 nl_client) } if (atomic_dec_and_test(&iwpm_admin.refcount)) { free_hash_bucket(); - pr_debug("%s: Mapinfo hash table is destroyed\n", __func__); + free_reminfo_bucket(); + pr_debug("%s: Resources are destroyed\n", __func__); } mutex_unlock(&iwpm_admin_lock); iwpm_set_valid(nl_client, 0); @@ -89,7 +110,7 @@ int iwpm_exit(u8 nl_client) } EXPORT_SYMBOL(iwpm_exit); -static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *, +static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *, struct sockaddr_storage *); int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, @@ -99,9 +120,10 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, struct hlist_head *hash_bucket_head; struct iwpm_mapping_info *map_info; unsigned long flags; + int ret = -EINVAL; if (!iwpm_valid_client(nl_client)) - return -EINVAL; + return ret; map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL); if (!map_info) { pr_err("%s: Unable to allocate a mapping info\n", __func__); @@ -115,13 +137,16 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - hash_bucket_head = get_hash_bucket_head( + hash_bucket_head = get_mapinfo_hash_bucket( &map_info->local_sockaddr, &map_info->mapped_sockaddr); - hlist_add_head(&map_info->hlist_node, hash_bucket_head); + if (hash_bucket_head) { + hlist_add_head(&map_info->hlist_node, hash_bucket_head); + ret = 0; + } } spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(iwpm_create_mapinfo); @@ -136,9 +161,12 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - hash_bucket_head = get_hash_bucket_head( + hash_bucket_head = get_mapinfo_hash_bucket( local_sockaddr, mapped_local_addr); + if (!hash_bucket_head) + goto remove_mapinfo_exit; + hlist_for_each_entry_safe(map_info, tmp_hlist_node, hash_bucket_head, hlist_node) { @@ -152,6 +180,7 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, } } } +remove_mapinfo_exit: spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); return ret; } @@ -166,7 +195,7 @@ static void free_hash_bucket(void) /* remove all the mapinfo data from the list */ spin_lock_irqsave(&iwpm_mapinfo_lock, flags); - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { hlist_for_each_entry_safe(map_info, tmp_hlist_node, &iwpm_hash_bucket[i], hlist_node) { @@ -180,6 +209,96 @@ static void free_hash_bucket(void) spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); } +static void free_reminfo_bucket(void) +{ + struct hlist_node *tmp_hlist_node; + struct iwpm_remote_info *rem_info; + unsigned long flags; + int i; + + /* remove all the remote info from the list */ + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) { + hlist_for_each_entry_safe(rem_info, tmp_hlist_node, + &iwpm_reminfo_bucket[i], hlist_node) { + + hlist_del_init(&rem_info->hlist_node); + kfree(rem_info); + } + } + /* free the hash list */ + kfree(iwpm_reminfo_bucket); + iwpm_reminfo_bucket = NULL; + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); +} + +static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *, + struct sockaddr_storage *); + +void iwpm_add_remote_info(struct iwpm_remote_info *rem_info) +{ + struct hlist_head *hash_bucket_head; + unsigned long flags; + + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + if (iwpm_reminfo_bucket) { + hash_bucket_head = get_reminfo_hash_bucket( + &rem_info->mapped_loc_sockaddr, + &rem_info->mapped_rem_sockaddr); + if (hash_bucket_head) + hlist_add_head(&rem_info->hlist_node, hash_bucket_head); + } + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); +} + +int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr, + struct sockaddr_storage *mapped_rem_addr, + struct sockaddr_storage *remote_addr, + u8 nl_client) +{ + struct hlist_node *tmp_hlist_node; + struct hlist_head *hash_bucket_head; + struct iwpm_remote_info *rem_info = NULL; + unsigned long flags; + int ret = -EINVAL; + + if (!iwpm_valid_client(nl_client)) { + pr_info("%s: Invalid client = %d\n", __func__, nl_client); + return ret; + } + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + if (iwpm_reminfo_bucket) { + hash_bucket_head = get_reminfo_hash_bucket( + mapped_loc_addr, + mapped_rem_addr); + if (!hash_bucket_head) + goto get_remote_info_exit; + hlist_for_each_entry_safe(rem_info, tmp_hlist_node, + hash_bucket_head, hlist_node) { + + if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr, + mapped_loc_addr) && + !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr, + mapped_rem_addr)) { + + memcpy(remote_addr, &rem_info->remote_sockaddr, + sizeof(struct sockaddr_storage)); + iwpm_print_sockaddr(remote_addr, + "get_remote_info: Remote sockaddr:"); + + hlist_del_init(&rem_info->hlist_node); + kfree(rem_info); + ret = 0; + break; + } + } + } +get_remote_info_exit: + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); + return ret; +} +EXPORT_SYMBOL(iwpm_get_remote_info); + struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, u8 nl_client, gfp_t gfp) { @@ -409,31 +528,54 @@ static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr) return hash; } -static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage - *local_sockaddr, - struct sockaddr_storage - *mapped_sockaddr) +static int get_hash_bucket(struct sockaddr_storage *a_sockaddr, + struct sockaddr_storage *b_sockaddr, u32 *hash) { - u32 local_hash, mapped_hash, hash; + u32 a_hash, b_hash; - if (local_sockaddr->ss_family == AF_INET) { - local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr); - mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr); + if (a_sockaddr->ss_family == AF_INET) { + a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr); + b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr); - } else if (local_sockaddr->ss_family == AF_INET6) { - local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr); - mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr); + } else if (a_sockaddr->ss_family == AF_INET6) { + a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr); + b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr); } else { pr_err("%s: Invalid sockaddr family\n", __func__); - return NULL; + return -EINVAL; } - if (local_hash == mapped_hash) /* if port mapper isn't available */ - hash = local_hash; + if (a_hash == b_hash) /* if port mapper isn't available */ + *hash = a_hash; else - hash = jhash_2words(local_hash, mapped_hash, 0); + *hash = jhash_2words(a_hash, b_hash, 0); + return 0; +} + +static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage + *local_sockaddr, struct sockaddr_storage + *mapped_sockaddr) +{ + u32 hash; + int ret; - return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK]; + ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash); + if (ret) + return NULL; + return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK]; +} + +static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage + *mapped_loc_sockaddr, struct sockaddr_storage + *mapped_rem_sockaddr) +{ + u32 hash; + int ret; + + ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash); + if (ret) + return NULL; + return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK]; } static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid) @@ -512,7 +654,7 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid) } skb_num++; spin_lock_irqsave(&iwpm_mapinfo_lock, flags); - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { hlist_for_each_entry(map_info, &iwpm_hash_bucket[i], hlist_node) { if (map_info->nl_client != nl_client) @@ -595,7 +737,7 @@ int iwpm_mapinfo_available(void) spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { if (!hlist_empty(&iwpm_hash_bucket[i])) { full_bucket = 1; break; diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h index 9777c86..ee2d9ff 100644 --- a/drivers/infiniband/core/iwpm_util.h +++ b/drivers/infiniband/core/iwpm_util.h @@ -76,6 +76,14 @@ struct iwpm_mapping_info { u8 nl_client; }; +struct iwpm_remote_info { + struct hlist_node hlist_node; + struct sockaddr_storage remote_sockaddr; + struct sockaddr_storage mapped_loc_sockaddr; + struct sockaddr_storage mapped_rem_sockaddr; + u8 nl_client; +}; + struct iwpm_admin_data { atomic_t refcount; atomic_t nlmsg_seq; @@ -128,6 +136,13 @@ int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request); int iwpm_get_nlmsg_seq(void); /** + * iwpm_add_reminfo - Add remote address info of the connecting peer + * to the remote info hash table + * @reminfo: The remote info to be added + */ +void iwpm_add_remote_info(struct iwpm_remote_info *reminfo); + +/** * iwpm_valid_client - Check if the port mapper client is valid * @nl_client: The index of the netlink client * diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 8b8cc6f..40becdb 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -446,7 +446,6 @@ static int ib_umem_odp_map_dma_single_page( int remove_existing_mapping = 0; int ret = 0; - mutex_lock(&umem->odp_data->umem_mutex); /* * Note: we avoid writing if seq is different from the initial seq, to * handle case of a racing notifier. This check also allows us to bail @@ -479,8 +478,6 @@ static int ib_umem_odp_map_dma_single_page( } out: - mutex_unlock(&umem->odp_data->umem_mutex); - /* On Demand Paging - avoid pinning the page */ if (umem->context->invalidate_range || !stored_page) put_page(page); @@ -586,6 +583,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt); user_virt += npages << PAGE_SHIFT; + mutex_lock(&umem->odp_data->umem_mutex); for (j = 0; j < npages; ++j) { ret = ib_umem_odp_map_dma_single_page( umem, k, base_virt_addr, local_page_list[j], @@ -594,6 +592,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, break; k++; } + mutex_unlock(&umem->odp_data->umem_mutex); if (ret < 0) { /* Release left over pages when handling errors. */ @@ -633,12 +632,11 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, * faults from completion. We might be racing with other * invalidations, so we must make sure we free each page only * once. */ + mutex_lock(&umem->odp_data->umem_mutex); for (addr = virt; addr < bound; addr += (u64)umem->page_size) { idx = (addr - ib_umem_start(umem)) / PAGE_SIZE; - mutex_lock(&umem->odp_data->umem_mutex); if (umem->odp_data->page_list[idx]) { struct page *page = umem->odp_data->page_list[idx]; - struct page *head_page = compound_head(page); dma_addr_t dma = umem->odp_data->dma_list[idx]; dma_addr_t dma_addr = dma & ODP_DMA_ADDR_MASK; @@ -646,7 +644,8 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, ib_dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma & ODP_WRITE_ALLOWED_BIT) + if (dma & ODP_WRITE_ALLOWED_BIT) { + struct page *head_page = compound_head(page); /* * set_page_dirty prefers being called with * the page lock. However, MMU notifiers are @@ -657,13 +656,14 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, * be removed. */ set_page_dirty(head_page); + } /* on demand pinning support */ if (!umem->context->invalidate_range) put_page(page); umem->odp_data->page_list[idx] = NULL; umem->odp_data->dma_list[idx] = 0; } - mutex_unlock(&umem->odp_data->umem_mutex); } + mutex_unlock(&umem->odp_data->umem_mutex); } EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 57176dd..3ad8dc7 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -583,6 +583,22 @@ static void c4iw_record_pm_msg(struct c4iw_ep *ep, sizeof(ep->com.mapped_remote_addr)); } +static int get_remote_addr(struct c4iw_ep *parent_ep, struct c4iw_ep *child_ep) +{ + int ret; + + print_addr(&parent_ep->com, __func__, "get_remote_addr parent_ep "); + print_addr(&child_ep->com, __func__, "get_remote_addr child_ep "); + + ret = iwpm_get_remote_info(&parent_ep->com.mapped_local_addr, + &child_ep->com.mapped_remote_addr, + &child_ep->com.remote_addr, RDMA_NL_C4IW); + if (ret) + PDBG("Unable to find remote peer addr info - err %d\n", ret); + + return ret; +} + static void best_mtu(const unsigned short *mtus, unsigned short mtu, unsigned int *idx, int use_ts, int ipv6) { @@ -675,7 +691,7 @@ static int send_connect(struct c4iw_ep *ep) if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { opt2 |= T5_OPT_2_VALID_F; opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE); - opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ + opt2 |= T5_ISS_F; } t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure); @@ -2042,9 +2058,12 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) status, status2errno(status)); if (is_neg_adv(status)) { - dev_warn(&dev->rdev.lldi.pdev->dev, - "Connection problems for atid %u status %u (%s)\n", - atid, status, neg_adv_str(status)); + PDBG("%s Connection problems for atid %u status %u (%s)\n", + __func__, atid, status, neg_adv_str(status)); + ep->stats.connect_neg_adv++; + mutex_lock(&dev->rdev.stats.lock); + dev->rdev.stats.neg_adv++; + mutex_unlock(&dev->rdev.stats.lock); return 0; } @@ -2214,7 +2233,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb, u32 isn = (prandom_u32() & ~7UL) - 1; opt2 |= T5_OPT_2_VALID_F; opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE); - opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ + opt2 |= T5_ISS_F; rpl5 = (void *)rpl; memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16)); if (peer2peer) @@ -2352,27 +2371,57 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) state_set(&child_ep->com, CONNECTING); child_ep->com.dev = dev; child_ep->com.cm_id = NULL; + + /* + * The mapped_local and mapped_remote addresses get setup with + * the actual 4-tuple. The local address will be based on the + * actual local address of the connection, but on the port number + * of the parent listening endpoint. The remote address is + * setup based on a query to the IWPM since we don't know what it + * originally was before mapping. If no mapping was done, then + * mapped_remote == remote, and mapped_local == local. + */ if (iptype == 4) { struct sockaddr_in *sin = (struct sockaddr_in *) - &child_ep->com.local_addr; + &child_ep->com.mapped_local_addr; + sin->sin_family = PF_INET; sin->sin_port = local_port; sin->sin_addr.s_addr = *(__be32 *)local_ip; - sin = (struct sockaddr_in *)&child_ep->com.remote_addr; + + sin = (struct sockaddr_in *)&child_ep->com.local_addr; + sin->sin_family = PF_INET; + sin->sin_port = ((struct sockaddr_in *) + &parent_ep->com.local_addr)->sin_port; + sin->sin_addr.s_addr = *(__be32 *)local_ip; + + sin = (struct sockaddr_in *)&child_ep->com.mapped_remote_addr; sin->sin_family = PF_INET; sin->sin_port = peer_port; sin->sin_addr.s_addr = *(__be32 *)peer_ip; } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) - &child_ep->com.local_addr; + &child_ep->com.mapped_local_addr; + sin6->sin6_family = PF_INET6; sin6->sin6_port = local_port; memcpy(sin6->sin6_addr.s6_addr, local_ip, 16); - sin6 = (struct sockaddr_in6 *)&child_ep->com.remote_addr; + + sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr; + sin6->sin6_family = PF_INET6; + sin6->sin6_port = ((struct sockaddr_in6 *) + &parent_ep->com.local_addr)->sin6_port; + memcpy(sin6->sin6_addr.s6_addr, local_ip, 16); + + sin6 = (struct sockaddr_in6 *)&child_ep->com.mapped_remote_addr; sin6->sin6_family = PF_INET6; sin6->sin6_port = peer_port; memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16); } + memcpy(&child_ep->com.remote_addr, &child_ep->com.mapped_remote_addr, + sizeof(child_ep->com.remote_addr)); + get_remote_addr(parent_ep, child_ep); + c4iw_get_ep(&parent_ep->com); child_ep->parent_ep = parent_ep; child_ep->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid)); @@ -2520,9 +2569,13 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) ep = lookup_tid(t, tid); if (is_neg_adv(req->status)) { - dev_warn(&dev->rdev.lldi.pdev->dev, - "Negative advice on abort - tid %u status %d (%s)\n", - ep->hwtid, req->status, neg_adv_str(req->status)); + PDBG("%s Negative advice on abort- tid %u status %d (%s)\n", + __func__, ep->hwtid, req->status, + neg_adv_str(req->status)); + ep->stats.abort_neg_adv++; + mutex_lock(&dev->rdev.stats.lock); + dev->rdev.stats.neg_adv++; + mutex_unlock(&dev->rdev.stats.lock); return 0; } PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid, @@ -3571,7 +3624,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb, * TP will ignore any value > 0 for MSS index. */ req->tcb.opt0 = cpu_to_be64(MSS_IDX_V(0xF)); - req->cookie = (unsigned long)skb; + req->cookie = (uintptr_t)skb; set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id); ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb); @@ -3931,9 +3984,11 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) return 0; } if (is_neg_adv(req->status)) { - dev_warn(&dev->rdev.lldi.pdev->dev, - "Negative advice on abort - tid %u status %d (%s)\n", - ep->hwtid, req->status, neg_adv_str(req->status)); + PDBG("%s Negative advice on abort- tid %u status %d (%s)\n", + __func__, ep->hwtid, req->status, + neg_adv_str(req->status)); + ep->stats.abort_neg_adv++; + dev->rdev.stats.neg_adv++; kfree_skb(skb); return 0; } diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index ab7692a..68ddb37 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -55,7 +55,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, FW_RI_RES_WR_NRES_V(1) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); - res_wr->cookie = (unsigned long) &wr_wait; + res_wr->cookie = (uintptr_t)&wr_wait; res = res_wr->res; res->u.cq.restype = FW_RI_RES_TYPE_CQ; res->u.cq.op = FW_RI_RES_OP_RESET; @@ -125,7 +125,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, FW_RI_RES_WR_NRES_V(1) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); - res_wr->cookie = (unsigned long) &wr_wait; + res_wr->cookie = (uintptr_t)&wr_wait; res = res_wr->res; res->u.cq.restype = FW_RI_RES_TYPE_CQ; res->u.cq.op = FW_RI_RES_OP_WRITE; @@ -156,12 +156,19 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, goto err4; cq->gen = 1; - cq->gts = rdev->lldi.gts_reg; cq->rdev = rdev; if (user) { - cq->ugts = (u64)pci_resource_start(rdev->lldi.pdev, 2) + - (cq->cqid << rdev->cqshift); - cq->ugts &= PAGE_MASK; + u32 off = (cq->cqid << rdev->cqshift) & PAGE_MASK; + + cq->ugts = (u64)rdev->bar2_pa + off; + } else if (is_t4(rdev->lldi.adapter_type)) { + cq->gts = rdev->lldi.gts_reg; + cq->qid_mask = -1U; + } else { + u32 off = ((cq->cqid << rdev->cqshift) & PAGE_MASK) + 12; + + cq->gts = rdev->bar2_kva + off; + cq->qid_mask = rdev->qpmask; } return 0; err4: @@ -970,8 +977,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, } PDBG("%s cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n", __func__, chp->cq.cqid, chp, chp->cq.size, - chp->cq.memsize, - (unsigned long long) chp->cq.dma_addr); + chp->cq.memsize, (unsigned long long) chp->cq.dma_addr); return &chp->ibcq; err5: kfree(mm2); diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 8fb295e..7e895d7 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -93,6 +93,7 @@ static struct ibnl_client_cbs c4iw_nl_cb_table[] = { [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb}, [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb}, [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb}, + [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb}, [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb}, [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb} }; @@ -151,7 +152,7 @@ static int wr_log_show(struct seq_file *seq, void *v) int prev_ts_set = 0; int idx, end; -#define ts2ns(ts) div64_ul((ts) * dev->rdev.lldi.cclk_ps, 1000) +#define ts2ns(ts) div64_u64((ts) * dev->rdev.lldi.cclk_ps, 1000) idx = atomic_read(&dev->rdev.wr_log_idx) & (dev->rdev.wr_log_size - 1); @@ -489,6 +490,7 @@ static int stats_show(struct seq_file *seq, void *v) dev->rdev.stats.act_ofld_conn_fails); seq_printf(seq, "PAS_OFLD_CONN_FAILS: %10llu\n", dev->rdev.stats.pas_ofld_conn_fails); + seq_printf(seq, "NEG_ADV_RCVD: %10llu\n", dev->rdev.stats.neg_adv); seq_printf(seq, "AVAILABLE IRD: %10u\n", dev->avail_ird); return 0; } @@ -560,10 +562,13 @@ static int dump_ep(int id, void *p, void *data) cc = snprintf(epd->buf + epd->pos, space, "ep %p cm_id %p qp %p state %d flags 0x%lx " "history 0x%lx hwtid %d atid %d " + "conn_na %u abort_na %u " "%pI4:%d/%d <-> %pI4:%d/%d\n", ep, ep->com.cm_id, ep->com.qp, (int)ep->com.state, ep->com.flags, ep->com.history, ep->hwtid, ep->atid, + ep->stats.connect_neg_adv, + ep->stats.abort_neg_adv, &lsin->sin_addr, ntohs(lsin->sin_port), ntohs(mapped_lsin->sin_port), &rsin->sin_addr, ntohs(rsin->sin_port), @@ -581,10 +586,13 @@ static int dump_ep(int id, void *p, void *data) cc = snprintf(epd->buf + epd->pos, space, "ep %p cm_id %p qp %p state %d flags 0x%lx " "history 0x%lx hwtid %d atid %d " + "conn_na %u abort_na %u " "%pI6:%d/%d <-> %pI6:%d/%d\n", ep, ep->com.cm_id, ep->com.qp, (int)ep->com.state, ep->com.flags, ep->com.history, ep->hwtid, ep->atid, + ep->stats.connect_neg_adv, + ep->stats.abort_neg_adv, &lsin6->sin6_addr, ntohs(lsin6->sin6_port), ntohs(mapped_lsin6->sin6_port), &rsin6->sin6_addr, ntohs(rsin6->sin6_port), @@ -765,6 +773,29 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) c4iw_init_dev_ucontext(rdev, &rdev->uctx); /* + * This implementation assumes udb_density == ucq_density! Eventually + * we might need to support this but for now fail the open. Also the + * cqid and qpid range must match for now. + */ + if (rdev->lldi.udb_density != rdev->lldi.ucq_density) { + pr_err(MOD "%s: unsupported udb/ucq densities %u/%u\n", + pci_name(rdev->lldi.pdev), rdev->lldi.udb_density, + rdev->lldi.ucq_density); + err = -EINVAL; + goto err1; + } + if (rdev->lldi.vr->qp.start != rdev->lldi.vr->cq.start || + rdev->lldi.vr->qp.size != rdev->lldi.vr->cq.size) { + pr_err(MOD "%s: unsupported qp and cq id ranges " + "qp start %u size %u cq start %u size %u\n", + pci_name(rdev->lldi.pdev), rdev->lldi.vr->qp.start, + rdev->lldi.vr->qp.size, rdev->lldi.vr->cq.size, + rdev->lldi.vr->cq.size); + err = -EINVAL; + goto err1; + } + + /* * qpshift is the number of bits to shift the qpid left in order * to get the correct address of the doorbell for that qp. */ @@ -784,10 +815,10 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) rdev->lldi.vr->qp.size, rdev->lldi.vr->cq.start, rdev->lldi.vr->cq.size); - PDBG("udb len 0x%x udb base %llx db_reg %p gts_reg %p qpshift %lu " + PDBG("udb len 0x%x udb base %p db_reg %p gts_reg %p qpshift %lu " "qpmask 0x%x cqshift %lu cqmask 0x%x\n", (unsigned)pci_resource_len(rdev->lldi.pdev, 2), - (u64)pci_resource_start(rdev->lldi.pdev, 2), + (void *)pci_resource_start(rdev->lldi.pdev, 2), rdev->lldi.db_reg, rdev->lldi.gts_reg, rdev->qpshift, rdev->qpmask, @@ -1355,7 +1386,7 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list) t4_sq_host_wq_pidx(&qp->wq), t4_sq_wq_size(&qp->wq)); if (ret) { - pr_err(KERN_ERR MOD "%s: Fatal error - " + pr_err(MOD "%s: Fatal error - " "DB overflow recovery failed - " "error syncing SQ qid %u\n", pci_name(ctx->lldi.pdev), qp->wq.sq.qid); @@ -1371,7 +1402,7 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list) t4_rq_wq_size(&qp->wq)); if (ret) { - pr_err(KERN_ERR MOD "%s: Fatal error - " + pr_err(MOD "%s: Fatal error - " "DB overflow recovery failed - " "error syncing RQ qid %u\n", pci_name(ctx->lldi.pdev), qp->wq.rq.qid); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index d87e165..97bb555 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -137,6 +137,7 @@ struct c4iw_stats { u64 tcam_full; u64 act_ofld_conn_fails; u64 pas_ofld_conn_fails; + u64 neg_adv; }; struct c4iw_hw_queue { @@ -814,6 +815,11 @@ struct c4iw_listen_ep { int backlog; }; +struct c4iw_ep_stats { + unsigned connect_neg_adv; + unsigned abort_neg_adv; +}; + struct c4iw_ep { struct c4iw_ep_common com; struct c4iw_ep *parent_ep; @@ -846,6 +852,7 @@ struct c4iw_ep { unsigned int retry_count; int snd_win; int rcv_win; + struct c4iw_ep_stats stats; }; static inline void print_addr(struct c4iw_ep_common *epc, const char *func, diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 3ef0cf9..cff815b 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -144,7 +144,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len, if (i == (num_wqe-1)) { req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) | FW_WR_COMPL_F); - req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait; + req->wr.wr_lo = (__force __be64)&wr_wait; } else req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR)); req->wr.wr_mid = cpu_to_be32( @@ -676,12 +676,12 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc) mhp->attr.zbva = 0; mhp->attr.va_fbo = 0; mhp->attr.page_size = 0; - mhp->attr.len = ~0UL; + mhp->attr.len = ~0ULL; mhp->attr.pbl_size = 0; ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid, FW_RI_STAG_NSMR, mhp->attr.perms, - mhp->attr.mw_bind_enable, 0, 0, ~0UL, 0, 0, 0); + mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0); if (ret) goto err1; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 15cae5a..389ced3 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -275,7 +275,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, FW_RI_RES_WR_NRES_V(2) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); - res_wr->cookie = (unsigned long) &wr_wait; + res_wr->cookie = (uintptr_t)&wr_wait; res = res_wr->res; res->u.sqrq.restype = FW_RI_RES_TYPE_SQ; res->u.sqrq.op = FW_RI_RES_OP_WRITE; @@ -1209,7 +1209,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, wqe->flowid_len16 = cpu_to_be32( FW_WR_FLOWID_V(ep->hwtid) | FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); - wqe->cookie = (unsigned long) &ep->com.wr_wait; + wqe->cookie = (uintptr_t)&ep->com.wr_wait; wqe->u.fini.type = FW_RI_TYPE_FINI; ret = c4iw_ofld_send(&rhp->rdev, skb); @@ -1279,7 +1279,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) FW_WR_FLOWID_V(qhp->ep->hwtid) | FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); - wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait; + wqe->cookie = (uintptr_t)&qhp->ep->com.wr_wait; wqe->u.init.type = FW_RI_TYPE_INIT; wqe->u.init.mpareqbit_p2ptype = @@ -1766,11 +1766,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize); insert_mmap(ucontext, mm2); mm3->key = uresp.sq_db_gts_key; - mm3->addr = (__force unsigned long) qhp->wq.sq.udb; + mm3->addr = (__force unsigned long)qhp->wq.sq.udb; mm3->len = PAGE_SIZE; insert_mmap(ucontext, mm3); mm4->key = uresp.rq_db_gts_key; - mm4->addr = (__force unsigned long) qhp->wq.rq.udb; + mm4->addr = (__force unsigned long)qhp->wq.rq.udb; mm4->len = PAGE_SIZE; insert_mmap(ucontext, mm4); if (mm5) { diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 871cdca..7f2a6c2 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -539,6 +539,7 @@ struct t4_cq { size_t memsize; __be64 bits_type_ts; u32 cqid; + u32 qid_mask; int vector; u16 size; /* including status page */ u16 cidx; @@ -563,12 +564,12 @@ static inline int t4_arm_cq(struct t4_cq *cq, int se) set_bit(CQ_ARMED, &cq->flags); while (cq->cidx_inc > CIDXINC_M) { val = SEINTARM_V(0) | CIDXINC_V(CIDXINC_M) | TIMERREG_V(7) | - INGRESSQID_V(cq->cqid); + INGRESSQID_V(cq->cqid & cq->qid_mask); writel(val, cq->gts); cq->cidx_inc -= CIDXINC_M; } val = SEINTARM_V(se) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(6) | - INGRESSQID_V(cq->cqid); + INGRESSQID_V(cq->cqid & cq->qid_mask); writel(val, cq->gts); cq->cidx_inc = 0; return 0; @@ -601,7 +602,7 @@ static inline void t4_hwcq_consume(struct t4_cq *cq) u32 val; val = SEINTARM_V(0) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(7) | - INGRESSQID_V(cq->cqid); + INGRESSQID_V(cq->cqid & cq->qid_mask); writel(val, cq->gts); cq->cidx_inc = 0; } diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h index 5e53327..343e8daf 100644 --- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h +++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h @@ -848,6 +848,8 @@ enum { /* TCP congestion control algorithms */ #define CONG_CNTRL_V(x) ((x) << CONG_CNTRL_S) #define CONG_CNTRL_G(x) (((x) >> CONG_CNTRL_S) & CONG_CNTRL_M) -#define CONG_CNTRL_VALID (1 << 18) +#define T5_ISS_S 18 +#define T5_ISS_V(x) ((x) << T5_ISS_S) +#define T5_ISS_F T5_ISS_V(1U) #endif /* _T4FW_RI_API_H_ */ diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c index 120aedf..cec1815 100644 --- a/drivers/infiniband/hw/ehca/ehca_mcast.c +++ b/drivers/infiniband/hw/ehca/ehca_mcast.c @@ -77,7 +77,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return -EINVAL; } - memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid)); + memcpy(&my_gid, gid->raw, sizeof(union ib_gid)); subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix); interface_id = be64_to_cpu(my_gid.global.interface_id); @@ -114,7 +114,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return -EINVAL; } - memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid)); + memcpy(&my_gid, gid->raw, sizeof(union ib_gid)); subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix); interface_id = be64_to_cpu(my_gid.global.interface_id); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 57070c5..cc64400 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1569,8 +1569,7 @@ static void reset_gids_task(struct work_struct *work) MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); if (err) - pr_warn(KERN_WARNING - "set port %d command failed\n", gw->port); + pr_warn("set port %d command failed\n", gw->port); } mlx4_free_cmd_mailbox(dev, mailbox); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 4d7024b..d35f62d 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1392,7 +1392,7 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, if (ah->ah_flags & IB_AH_GRH) { if (ah->grh.sgid_index >= gen->port[port - 1].gid_table_len) { - pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n", + pr_err("sgid_index (%u) too large. max is %d\n", ah->grh.sgid_index, gen->port[port - 1].gid_table_len); return -EINVAL; } diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 3b2a6dc..9f9d5c5 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -116,6 +116,7 @@ static struct ibnl_client_cbs nes_nl_cb_table[] = { [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb}, [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb}, [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb}, + [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb}, [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb}, [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb}, [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb} diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 6f09a72..72b4341 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -596,27 +596,52 @@ static void nes_form_reg_msg(struct nes_vnic *nesvnic, memcpy(pm_msg->if_name, nesvnic->netdev->name, IWPM_IFNAME_SIZE); } +static void record_sockaddr_info(struct sockaddr_storage *addr_info, + nes_addr_t *ip_addr, u16 *port_num) +{ + struct sockaddr_in *in_addr = (struct sockaddr_in *)addr_info; + + if (in_addr->sin_family == AF_INET) { + *ip_addr = ntohl(in_addr->sin_addr.s_addr); + *port_num = ntohs(in_addr->sin_port); + } +} + /* * nes_record_pm_msg - Save the received mapping info */ static void nes_record_pm_msg(struct nes_cm_info *cm_info, struct iwpm_sa_data *pm_msg) { - struct sockaddr_in *mapped_loc_addr = - (struct sockaddr_in *)&pm_msg->mapped_loc_addr; - struct sockaddr_in *mapped_rem_addr = - (struct sockaddr_in *)&pm_msg->mapped_rem_addr; - - if (mapped_loc_addr->sin_family == AF_INET) { - cm_info->mapped_loc_addr = - ntohl(mapped_loc_addr->sin_addr.s_addr); - cm_info->mapped_loc_port = ntohs(mapped_loc_addr->sin_port); - } - if (mapped_rem_addr->sin_family == AF_INET) { - cm_info->mapped_rem_addr = - ntohl(mapped_rem_addr->sin_addr.s_addr); - cm_info->mapped_rem_port = ntohs(mapped_rem_addr->sin_port); - } + record_sockaddr_info(&pm_msg->mapped_loc_addr, + &cm_info->mapped_loc_addr, &cm_info->mapped_loc_port); + + record_sockaddr_info(&pm_msg->mapped_rem_addr, + &cm_info->mapped_rem_addr, &cm_info->mapped_rem_port); +} + +/* + * nes_get_reminfo - Get the address info of the remote connecting peer + */ +static int nes_get_remote_addr(struct nes_cm_node *cm_node) +{ + struct sockaddr_storage mapped_loc_addr, mapped_rem_addr; + struct sockaddr_storage remote_addr; + int ret; + + nes_create_sockaddr(htonl(cm_node->mapped_loc_addr), + htons(cm_node->mapped_loc_port), &mapped_loc_addr); + nes_create_sockaddr(htonl(cm_node->mapped_rem_addr), + htons(cm_node->mapped_rem_port), &mapped_rem_addr); + + ret = iwpm_get_remote_info(&mapped_loc_addr, &mapped_rem_addr, + &remote_addr, RDMA_NL_NES); + if (ret) + nes_debug(NES_DBG_CM, "Unable to find remote peer address info\n"); + else + record_sockaddr_info(&remote_addr, &cm_node->rem_addr, + &cm_node->rem_port); + return ret; } /** @@ -1566,9 +1591,14 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, return NULL; /* set our node specific transport info */ - cm_node->loc_addr = cm_info->loc_addr; + if (listener) { + cm_node->loc_addr = listener->loc_addr; + cm_node->loc_port = listener->loc_port; + } else { + cm_node->loc_addr = cm_info->loc_addr; + cm_node->loc_port = cm_info->loc_port; + } cm_node->rem_addr = cm_info->rem_addr; - cm_node->loc_port = cm_info->loc_port; cm_node->rem_port = cm_info->rem_port; cm_node->mapped_loc_addr = cm_info->mapped_loc_addr; @@ -2151,6 +2181,7 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->state = NES_CM_STATE_ESTABLISHED; if (datasize) { cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; + nes_get_remote_addr(cm_node); handle_rcv_mpa(cm_node, skb); } else { /* rcvd ACK only */ dev_kfree_skb_any(skb); diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index ffd48bf..7df16f7 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -903,7 +903,7 @@ struct qib_devdata { /* PCI Device ID (here for NodeInfo) */ u16 deviceid; /* for write combining settings */ - unsigned long wc_cookie; + int wc_cookie; unsigned long wc_base; unsigned long wc_len; @@ -1136,7 +1136,6 @@ extern struct qib_devdata *qib_lookup(int unit); extern u32 qib_cpulist_count; extern unsigned long *qib_cpulist; -extern unsigned qib_wc_pat; extern unsigned qib_cc_table_size; int qib_init(struct qib_devdata *, int); int init_chip_wc_pat(struct qib_devdata *dd, u32); diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 9ea6c44..7258818 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -835,7 +835,8 @@ static int mmap_piobufs(struct vm_area_struct *vma, vma->vm_flags &= ~VM_MAYREAD; vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; - if (qib_wc_pat) + /* We used PAT if wc_cookie == 0 */ + if (!dd->wc_cookie) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 0d2ba59..4b927809 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -3315,11 +3315,9 @@ static int init_6120_variables(struct qib_devdata *dd) qib_6120_config_ctxts(dd); qib_set_ctxtcnt(dd); - if (qib_wc_pat) { - ret = init_chip_wc_pat(dd, 0); - if (ret) - goto bail; - } + ret = init_chip_wc_pat(dd, 0); + if (ret) + goto bail; set_6120_baseaddrs(dd); /* set chip access pointers now */ ret = 0; diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 22affda..00b2af2 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -4126,11 +4126,9 @@ static int qib_init_7220_variables(struct qib_devdata *dd) qib_7220_config_ctxts(dd); qib_set_ctxtcnt(dd); /* needed for PAT setup */ - if (qib_wc_pat) { - ret = init_chip_wc_pat(dd, 0); - if (ret) - goto bail; - } + ret = init_chip_wc_pat(dd, 0); + if (ret) + goto bail; set_7220_baseaddrs(dd); /* set chip access pointers now */ ret = 0; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index ef97b71..f32b462 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -6429,6 +6429,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd) unsigned features, pidx, sbufcnt; int ret, mtu; u32 sbufs, updthresh; + resource_size_t vl15off; /* pport structs are contiguous, allocated after devdata */ ppd = (struct qib_pportdata *)(dd + 1); @@ -6677,29 +6678,27 @@ static int qib_init_7322_variables(struct qib_devdata *dd) qib_7322_config_ctxts(dd); qib_set_ctxtcnt(dd); - if (qib_wc_pat) { - resource_size_t vl15off; - /* - * We do not set WC on the VL15 buffers to avoid - * a rare problem with unaligned writes from - * interrupt-flushed store buffers, so we need - * to map those separately here. We can't solve - * this for the rarely used mtrr case. - */ - ret = init_chip_wc_pat(dd, 0); - if (ret) - goto bail; + /* + * We do not set WC on the VL15 buffers to avoid + * a rare problem with unaligned writes from + * interrupt-flushed store buffers, so we need + * to map those separately here. We can't solve + * this for the rarely used mtrr case. + */ + ret = init_chip_wc_pat(dd, 0); + if (ret) + goto bail; - /* vl15 buffers start just after the 4k buffers */ - vl15off = dd->physaddr + (dd->piobufbase >> 32) + - dd->piobcnt4k * dd->align4k; - dd->piovl15base = ioremap_nocache(vl15off, - NUM_VL15_BUFS * dd->align4k); - if (!dd->piovl15base) { - ret = -ENOMEM; - goto bail; - } + /* vl15 buffers start just after the 4k buffers */ + vl15off = dd->physaddr + (dd->piobufbase >> 32) + + dd->piobcnt4k * dd->align4k; + dd->piovl15base = ioremap_nocache(vl15off, + NUM_VL15_BUFS * dd->align4k); + if (!dd->piovl15base) { + ret = -ENOMEM; + goto bail; } + qib_7322_set_baseaddrs(dd); /* set chip access pointers now */ ret = 0; diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 2ee3695..7e00470 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -91,15 +91,6 @@ MODULE_PARM_DESC(krcvqs, "number of kernel receive queues per IB port"); unsigned qib_cc_table_size; module_param_named(cc_table_size, qib_cc_table_size, uint, S_IRUGO); MODULE_PARM_DESC(cc_table_size, "Congestion control table entries 0 (CCA disabled - default), min = 128, max = 1984"); -/* - * qib_wc_pat parameter: - * 0 is WC via MTRR - * 1 is WC via PAT - * If PAT initialization fails, code reverts back to MTRR - */ -unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */ -module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO); -MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism"); static void verify_interrupt(unsigned long); @@ -1377,8 +1368,7 @@ static void cleanup_device_data(struct qib_devdata *dd) spin_unlock(&dd->pport[pidx].cc_shadow_lock); } - if (!qib_wc_pat) - qib_disable_wc(dd); + qib_disable_wc(dd); if (dd->pioavailregs_dma) { dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE, @@ -1547,14 +1537,12 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto bail; } - if (!qib_wc_pat) { - ret = qib_enable_wc(dd); - if (ret) { - qib_dev_err(dd, - "Write combining not enabled (err %d): performance may be poor\n", - -ret); - ret = 0; - } + ret = qib_enable_wc(dd); + if (ret) { + qib_dev_err(dd, + "Write combining not enabled (err %d): performance may be poor\n", + -ret); + ret = 0; } qib_verify_pioperf(dd); diff --git a/drivers/infiniband/hw/qib/qib_wc_x86_64.c b/drivers/infiniband/hw/qib/qib_wc_x86_64.c index 81b225f..edd0ddb 100644 --- a/drivers/infiniband/hw/qib/qib_wc_x86_64.c +++ b/drivers/infiniband/hw/qib/qib_wc_x86_64.c @@ -116,21 +116,10 @@ int qib_enable_wc(struct qib_devdata *dd) } if (!ret) { - int cookie; - - cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0); - if (cookie < 0) { - { - qib_devinfo(dd->pcidev, - "mtrr_add() WC for PIO bufs failed (%d)\n", - cookie); - ret = -EINVAL; - } - } else { - dd->wc_cookie = cookie; - dd->wc_base = (unsigned long) pioaddr; - dd->wc_len = (unsigned long) piolen; - } + dd->wc_cookie = arch_phys_wc_add(pioaddr, piolen); + if (dd->wc_cookie < 0) + /* use error from routine */ + ret = dd->wc_cookie; } return ret; @@ -142,18 +131,7 @@ int qib_enable_wc(struct qib_devdata *dd) */ void qib_disable_wc(struct qib_devdata *dd) { - if (dd->wc_cookie) { - int r; - - r = mtrr_del(dd->wc_cookie, dd->wc_base, - dd->wc_len); - if (r < 0) - qib_devinfo(dd->pcidev, - "mtrr_del(%lx, %lx, %lx) failed: %d\n", - dd->wc_cookie, dd->wc_base, - dd->wc_len, r); - dd->wc_cookie = 0; /* even on failure */ - } + arch_phys_wc_del(dd->wc_cookie); } /** diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 56959ad..cf32a778 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -386,8 +386,8 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i rx->rx_ring[i].mapping, GFP_KERNEL)) { ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); - ret = -ENOMEM; - goto err_count; + ret = -ENOMEM; + goto err_count; } ret = ipoib_cm_post_receive_nonsrq(dev, rx, &t->wr, t->sge, i); if (ret) { diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index a1cbba9..3465faf 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -266,6 +266,7 @@ static void put_pasid_state(struct pasid_state *pasid_state) static void put_pasid_state_wait(struct pasid_state *pasid_state) { + atomic_dec(&pasid_state->count); wait_event(pasid_state->wq, !atomic_read(&pasid_state->count)); free_pasid_state(pasid_state); } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 9f7e1d3..66a803b 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -224,14 +224,7 @@ #define RESUME_TERMINATE (1 << 0) #define TTBCR2_SEP_SHIFT 15 -#define TTBCR2_SEP_MASK 0x7 - -#define TTBCR2_ADDR_32 0 -#define TTBCR2_ADDR_36 1 -#define TTBCR2_ADDR_40 2 -#define TTBCR2_ADDR_42 3 -#define TTBCR2_ADDR_44 4 -#define TTBCR2_ADDR_48 5 +#define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) #define TTBRn_HI_ASID_SHIFT 16 @@ -793,26 +786,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); if (smmu->version > ARM_SMMU_V1) { reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; - switch (smmu->va_size) { - case 32: - reg |= (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT); - break; - case 36: - reg |= (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT); - break; - case 40: - reg |= (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT); - break; - case 42: - reg |= (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT); - break; - case 44: - reg |= (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT); - break; - case 48: - reg |= (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT); - break; - } + reg |= TTBCR2_SEP_UPSTREAM; writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2); } } else { diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 4015560..cab2145 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1004,20 +1004,18 @@ static int rk_iommu_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF static const struct of_device_id rk_iommu_dt_ids[] = { { .compatible = "rockchip,iommu" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids); -#endif static struct platform_driver rk_iommu_driver = { .probe = rk_iommu_probe, .remove = rk_iommu_remove, .driver = { .name = "rk_iommu", - .of_match_table = of_match_ptr(rk_iommu_dt_ids), + .of_match_table = rk_iommu_dt_ids, }, }; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 7b315e3..01999d7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -82,19 +82,6 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock); #define NR_GIC_CPU_IF 8 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; -/* - * Supported arch specific GIC irq extension. - * Default make them NULL. - */ -struct irq_chip gic_arch_extn = { - .irq_eoi = NULL, - .irq_mask = NULL, - .irq_unmask = NULL, - .irq_retrigger = NULL, - .irq_set_type = NULL, - .irq_set_wake = NULL, -}; - #ifndef MAX_GIC_NR #define MAX_GIC_NR 1 #endif @@ -167,34 +154,16 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) static void gic_mask_irq(struct irq_data *d) { - unsigned long flags; - - raw_spin_lock_irqsave(&irq_controller_lock, flags); gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR); - if (gic_arch_extn.irq_mask) - gic_arch_extn.irq_mask(d); - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); } static void gic_unmask_irq(struct irq_data *d) { - unsigned long flags; - - raw_spin_lock_irqsave(&irq_controller_lock, flags); - if (gic_arch_extn.irq_unmask) - gic_arch_extn.irq_unmask(d); gic_poke_irq(d, GIC_DIST_ENABLE_SET); - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); } static void gic_eoi_irq(struct irq_data *d) { - if (gic_arch_extn.irq_eoi) { - raw_spin_lock(&irq_controller_lock); - gic_arch_extn.irq_eoi(d); - raw_spin_unlock(&irq_controller_lock); - } - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); } @@ -251,8 +220,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type) { void __iomem *base = gic_dist_base(d); unsigned int gicirq = gic_irq(d); - unsigned long flags; - int ret; /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) @@ -263,25 +230,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) type != IRQ_TYPE_EDGE_RISING) return -EINVAL; - raw_spin_lock_irqsave(&irq_controller_lock, flags); - - if (gic_arch_extn.irq_set_type) - gic_arch_extn.irq_set_type(d, type); - - ret = gic_configure_irq(gicirq, type, base, NULL); - - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); - - return ret; -} - -static int gic_retrigger(struct irq_data *d) -{ - if (gic_arch_extn.irq_retrigger) - return gic_arch_extn.irq_retrigger(d); - - /* the genirq layer expects 0 if we can't retrigger in hardware */ - return 0; + return gic_configure_irq(gicirq, type, base, NULL); } #ifdef CONFIG_SMP @@ -312,21 +261,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, } #endif -#ifdef CONFIG_PM -static int gic_set_wake(struct irq_data *d, unsigned int on) -{ - int ret = -ENXIO; - - if (gic_arch_extn.irq_set_wake) - ret = gic_arch_extn.irq_set_wake(d, on); - - return ret; -} - -#else -#define gic_set_wake NULL -#endif - static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqstat, irqnr; @@ -385,11 +319,9 @@ static struct irq_chip gic_chip = { .irq_unmask = gic_unmask_irq, .irq_eoi = gic_eoi_irq, .irq_set_type = gic_set_type, - .irq_retrigger = gic_retrigger, #ifdef CONFIG_SMP .irq_set_affinity = gic_set_affinity, #endif - .irq_set_wake = gic_set_wake, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, }; @@ -1055,7 +987,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, set_handle_irq(gic_handle_irq); } - gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic); gic_cpu_init(gic); gic_pm_init(gic); diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c index 51c485d..f67bbd8 100644 --- a/drivers/irqchip/irq-tegra.c +++ b/drivers/irqchip/irq-tegra.c @@ -264,7 +264,7 @@ static int tegra_ictlr_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &tegra_ictlr_chip, - &info->base[ictlr]); + info->base[ictlr]); } parent_args = *args; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 9eeea19..5503e43 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -925,10 +925,11 @@ static int crypt_convert(struct crypt_config *cc, switch (r) { /* async */ - case -EINPROGRESS: case -EBUSY: wait_for_completion(&ctx->restart); reinit_completion(&ctx->restart); + /* fall through*/ + case -EINPROGRESS: ctx->req = NULL; ctx->cc_sector++; continue; @@ -1345,8 +1346,10 @@ static void kcryptd_async_done(struct crypto_async_request *async_req, struct dm_crypt_io *io = container_of(ctx, struct dm_crypt_io, ctx); struct crypt_config *cc = io->cc; - if (error == -EINPROGRESS) + if (error == -EINPROGRESS) { + complete(&ctx->restart); return; + } if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post) error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq); @@ -1357,15 +1360,12 @@ static void kcryptd_async_done(struct crypto_async_request *async_req, crypt_free_req(cc, req_of_dmreq(cc, dmreq), io->base_bio); if (!atomic_dec_and_test(&ctx->cc_pending)) - goto done; + return; if (bio_data_dir(io->base_bio) == READ) kcryptd_crypt_read_done(io); else kcryptd_crypt_write_io_submit(io, 1); -done: - if (!completion_done(&ctx->restart)) - complete(&ctx->restart); } static void kcryptd_crypt(struct work_struct *work) diff --git a/drivers/md/md.c b/drivers/md/md.c index d4f31e1..593a024 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4818,12 +4818,12 @@ static void md_free(struct kobject *ko) if (mddev->sysfs_state) sysfs_put(mddev->sysfs_state); + if (mddev->queue) + blk_cleanup_queue(mddev->queue); if (mddev->gendisk) { del_gendisk(mddev->gendisk); put_disk(mddev->gendisk); } - if (mddev->queue) - blk_cleanup_queue(mddev->queue); kfree(mddev); } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 2cb59a6..6a68ef5 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -188,8 +188,9 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) } dev[j] = rdev1; - disk_stack_limits(mddev->gendisk, rdev1->bdev, - rdev1->data_offset << 9); + if (mddev->queue) + disk_stack_limits(mddev->gendisk, rdev1->bdev, + rdev1->data_offset << 9); if (rdev1->bdev->bd_disk->queue->merge_bvec_fn) conf->has_merge_bvec = 1; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 77dfd72..1ba97fd 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1078,9 +1078,6 @@ again: pr_debug("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); clear_bit(R5_LOCKED, &sh->dev[i].flags); - if (sh->batch_head) - set_bit(STRIPE_BATCH_ERR, - &sh->batch_head->state); set_bit(STRIPE_HANDLE, &sh->state); } @@ -1971,17 +1968,30 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) put_cpu(); } +static struct stripe_head *alloc_stripe(struct kmem_cache *sc, gfp_t gfp) +{ + struct stripe_head *sh; + + sh = kmem_cache_zalloc(sc, gfp); + if (sh) { + spin_lock_init(&sh->stripe_lock); + spin_lock_init(&sh->batch_lock); + INIT_LIST_HEAD(&sh->batch_list); + INIT_LIST_HEAD(&sh->lru); + atomic_set(&sh->count, 1); + } + return sh; +} static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) { struct stripe_head *sh; - sh = kmem_cache_zalloc(conf->slab_cache, gfp); + + sh = alloc_stripe(conf->slab_cache, gfp); if (!sh) return 0; sh->raid_conf = conf; - spin_lock_init(&sh->stripe_lock); - if (grow_buffers(sh, gfp)) { shrink_buffers(sh); kmem_cache_free(conf->slab_cache, sh); @@ -1990,13 +2000,8 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) sh->hash_lock_index = conf->max_nr_stripes % NR_STRIPE_HASH_LOCKS; /* we just created an active stripe so... */ - atomic_set(&sh->count, 1); atomic_inc(&conf->active_stripes); - INIT_LIST_HEAD(&sh->lru); - spin_lock_init(&sh->batch_lock); - INIT_LIST_HEAD(&sh->batch_list); - sh->batch_head = NULL; release_stripe(sh); conf->max_nr_stripes++; return 1; @@ -2060,6 +2065,35 @@ static struct flex_array *scribble_alloc(int num, int cnt, gfp_t flags) return ret; } +static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) +{ + unsigned long cpu; + int err = 0; + + mddev_suspend(conf->mddev); + get_online_cpus(); + for_each_present_cpu(cpu) { + struct raid5_percpu *percpu; + struct flex_array *scribble; + + percpu = per_cpu_ptr(conf->percpu, cpu); + scribble = scribble_alloc(new_disks, + new_sectors / STRIPE_SECTORS, + GFP_NOIO); + + if (scribble) { + flex_array_free(percpu->scribble); + percpu->scribble = scribble; + } else { + err = -ENOMEM; + break; + } + } + put_online_cpus(); + mddev_resume(conf->mddev); + return err; +} + static int resize_stripes(struct r5conf *conf, int newsize) { /* Make all the stripes able to hold 'newsize' devices. @@ -2088,7 +2122,6 @@ static int resize_stripes(struct r5conf *conf, int newsize) struct stripe_head *osh, *nsh; LIST_HEAD(newstripes); struct disk_info *ndisks; - unsigned long cpu; int err; struct kmem_cache *sc; int i; @@ -2109,13 +2142,11 @@ static int resize_stripes(struct r5conf *conf, int newsize) return -ENOMEM; for (i = conf->max_nr_stripes; i; i--) { - nsh = kmem_cache_zalloc(sc, GFP_KERNEL); + nsh = alloc_stripe(sc, GFP_KERNEL); if (!nsh) break; nsh->raid_conf = conf; - spin_lock_init(&nsh->stripe_lock); - list_add(&nsh->lru, &newstripes); } if (i) { @@ -2142,13 +2173,11 @@ static int resize_stripes(struct r5conf *conf, int newsize) lock_device_hash_lock(conf, hash)); osh = get_free_stripe(conf, hash); unlock_device_hash_lock(conf, hash); - atomic_set(&nsh->count, 1); + for(i=0; i<conf->pool_size; i++) { nsh->dev[i].page = osh->dev[i].page; nsh->dev[i].orig_page = osh->dev[i].page; } - for( ; i<newsize; i++) - nsh->dev[i].page = NULL; nsh->hash_lock_index = hash; kmem_cache_free(conf->slab_cache, osh); cnt++; @@ -2174,25 +2203,6 @@ static int resize_stripes(struct r5conf *conf, int newsize) } else err = -ENOMEM; - get_online_cpus(); - for_each_present_cpu(cpu) { - struct raid5_percpu *percpu; - struct flex_array *scribble; - - percpu = per_cpu_ptr(conf->percpu, cpu); - scribble = scribble_alloc(newsize, conf->chunk_sectors / - STRIPE_SECTORS, GFP_NOIO); - - if (scribble) { - flex_array_free(percpu->scribble); - percpu->scribble = scribble; - } else { - err = -ENOMEM; - break; - } - } - put_online_cpus(); - /* Step 4, return new stripes to service */ while(!list_empty(&newstripes)) { nsh = list_entry(newstripes.next, struct stripe_head, lru); @@ -2212,7 +2222,8 @@ static int resize_stripes(struct r5conf *conf, int newsize) conf->slab_cache = sc; conf->active_name = 1-conf->active_name; - conf->pool_size = newsize; + if (!err) + conf->pool_size = newsize; return err; } @@ -2434,7 +2445,7 @@ static void raid5_end_write_request(struct bio *bi, int error) } rdev_dec_pending(rdev, conf->mddev); - if (sh->batch_head && !uptodate) + if (sh->batch_head && !uptodate && !replacement) set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state); if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) @@ -3278,7 +3289,9 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, /* reconstruct-write isn't being forced */ return 0; for (i = 0; i < s->failed; i++) { - if (!test_bit(R5_UPTODATE, &fdev[i]->flags) && + if (s->failed_num[i] != sh->pd_idx && + s->failed_num[i] != sh->qd_idx && + !test_bit(R5_UPTODATE, &fdev[i]->flags) && !test_bit(R5_OVERWRITE, &fdev[i]->flags)) return 1; } @@ -3298,6 +3311,7 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, */ BUG_ON(test_bit(R5_Wantcompute, &dev->flags)); BUG_ON(test_bit(R5_Wantread, &dev->flags)); + BUG_ON(sh->batch_head); if ((s->uptodate == disks - 1) && (s->failed && (disk_idx == s->failed_num[0] || disk_idx == s->failed_num[1]))) { @@ -3366,7 +3380,6 @@ static void handle_stripe_fill(struct stripe_head *sh, { int i; - BUG_ON(sh->batch_head); /* look for blocks to read/compute, skip this if a compute * is already in flight, or if the stripe contents are in the * midst of changing due to a write @@ -4198,15 +4211,9 @@ static void check_break_stripe_batch_list(struct stripe_head *sh) return; head_sh = sh; - do { - sh = list_first_entry(&sh->batch_list, - struct stripe_head, batch_list); - BUG_ON(sh == head_sh); - } while (!test_bit(STRIPE_DEGRADED, &sh->state)); - while (sh != head_sh) { - next = list_first_entry(&sh->batch_list, - struct stripe_head, batch_list); + list_for_each_entry_safe(sh, next, &head_sh->batch_list, batch_list) { + list_del_init(&sh->batch_list); set_mask_bits(&sh->state, ~STRIPE_EXPAND_SYNC_FLAG, @@ -4226,8 +4233,6 @@ static void check_break_stripe_batch_list(struct stripe_head *sh) set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); - - sh = next; } } @@ -6221,8 +6226,11 @@ static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu percpu->spare_page = alloc_page(GFP_KERNEL); if (!percpu->scribble) percpu->scribble = scribble_alloc(max(conf->raid_disks, - conf->previous_raid_disks), conf->chunk_sectors / - STRIPE_SECTORS, GFP_KERNEL); + conf->previous_raid_disks), + max(conf->chunk_sectors, + conf->prev_chunk_sectors) + / STRIPE_SECTORS, + GFP_KERNEL); if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { free_scratch_buffer(conf, percpu); @@ -7198,6 +7206,15 @@ static int check_reshape(struct mddev *mddev) if (!check_stripe_cache(mddev)) return -ENOSPC; + if (mddev->new_chunk_sectors > mddev->chunk_sectors || + mddev->delta_disks > 0) + if (resize_chunks(conf, + conf->previous_raid_disks + + max(0, mddev->delta_disks), + max(mddev->new_chunk_sectors, + mddev->chunk_sectors) + ) < 0) + return -ENOMEM; return resize_stripes(conf, (conf->previous_raid_disks + mddev->delta_disks)); } diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 9c64b5d..110fd70 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -116,8 +116,8 @@ static struct mcam_format_struct { .planar = false, }, { - .desc = "UYVY 4:2:2", - .pixelformat = V4L2_PIX_FMT_UYVY, + .desc = "YVYU 4:2:2", + .pixelformat = V4L2_PIX_FMT_YVYU, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, @@ -748,7 +748,7 @@ static void mcam_ctlr_image(struct mcam_camera *cam) switch (fmt->pixelformat) { case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: widthy = fmt->width * 2; widthuv = 0; break; @@ -784,15 +784,15 @@ static void mcam_ctlr_image(struct mcam_camera *cam) case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV | C0_YUV_420PL | C0_YUVE_YVYU, C0_DF_MASK); + C0_DF_YUV | C0_YUV_420PL | C0_YUVE_VYUY, C0_DF_MASK); break; case V4L2_PIX_FMT_YUYV: mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_UYVY, C0_DF_MASK); + C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_NOSWAP, C0_DF_MASK); break; - case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: mcam_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK); + C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_SWAP24, C0_DF_MASK); break; case V4L2_PIX_FMT_JPEG: mcam_reg_write_mask(cam, REG_CTRL0, diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index aa0c6ea..7ffdf4d 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -330,10 +330,10 @@ int mccic_resume(struct mcam_camera *cam); #define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ #define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ #define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ -#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ -#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ -#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ -#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ +#define C0_YUVE_NOSWAP 0x00000000 /* no bytes swapping */ +#define C0_YUVE_SWAP13 0x00010000 /* swap byte 1 and 3 */ +#define C0_YUVE_SWAP24 0x00020000 /* swap byte 2 and 4 */ +#define C0_YUVE_SWAP1324 0x00030000 /* swap bytes 1&3 and 2&4 */ /* Bayer bits 18,19 if needed */ #define C0_EOF_VSYNC 0x00400000 /* Generate EOF by VSYNC */ #define C0_VEDGE_CTRL 0x00800000 /* Detect falling edge of VSYNC */ diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 9351f64..6460f8e 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -135,6 +135,8 @@ #define VIN_MAX_WIDTH 2048 #define VIN_MAX_HEIGHT 2048 +#define TIMEOUT_MS 100 + enum chip_id { RCAR_GEN2, RCAR_H1, @@ -820,7 +822,10 @@ static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv) if (priv->state == STOPPING) { priv->request_to_stop = true; spin_unlock_irq(&priv->lock); - wait_for_completion(&priv->capture_stop); + if (!wait_for_completion_timeout( + &priv->capture_stop, + msecs_to_jiffies(TIMEOUT_MS))) + priv->state = STOPPED; spin_lock_irq(&priv->lock); } } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 2c25271..60f7141 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1029,6 +1029,18 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) md->reset_done &= ~type; } +int mmc_access_rpmb(struct mmc_queue *mq) +{ + struct mmc_blk_data *md = mq->data; + /* + * If this is a RPMB partition access, return ture + */ + if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) + return true; + + return false; +} + static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 236d194..8efa368 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -38,7 +38,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_KILL; } - if (mq && mmc_card_removed(mq->card)) + if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) return BLKPREP_KILL; req->cmd_flags |= REQ_DONTPREP; diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 5752d50..99e6521 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -73,4 +73,6 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *); extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *); extern void mmc_packed_clean(struct mmc_queue *); +extern int mmc_access_rpmb(struct mmc_queue *); + #endif diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c296bc0..92e7671 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2651,6 +2651,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 38b2926..5f5adaf 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -589,9 +589,11 @@ static int dw_mci_idmac_init(struct dw_mci *host) host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); /* Forward link the descriptor list */ - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) { p->des3 = cpu_to_le32(host->sg_dma + (sizeof(struct idmac_desc) * (i + 1))); + p->des1 = 0; + } /* Set the last descriptor as the end-of-ring descriptor */ p->des3 = cpu_to_le32(host->sg_dma); @@ -1300,7 +1302,8 @@ static int dw_mci_get_cd(struct mmc_host *mmc) int gpio_cd = mmc_gpio_get_cd(mmc); /* Use platform get_cd function, else try onboard card detect */ - if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) + if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) || + (mmc->caps & MMC_CAP_NONREMOVABLE)) present = 1; else if (!IS_ERR_VALUE(gpio_cd)) present = gpio_cd; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 2b6ef6b..7eff087 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1408,7 +1408,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; host->addr = reg; - host->timeout = msecs_to_jiffies(1000); + host->timeout = msecs_to_jiffies(10000); host->ccs_enable = !pd || !pd->ccs_unsupported; host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7c8b169..3af137f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -223,7 +223,7 @@ static int m25p_probe(struct spi_device *spi) */ if (data && data->type) flash_name = data->type; - else if (!strcmp(spi->modalias, "nor-jedec")) + else if (!strcmp(spi->modalias, "spi-nor")) flash_name = NULL; /* auto-detect */ else flash_name = spi->modalias; @@ -255,7 +255,7 @@ static int m25p_remove(struct spi_device *spi) * since most of these flash are compatible to some extent, and their * differences can often be differentiated by the JEDEC read-ID command, we * encourage new users to add support to the spi-nor library, and simply bind - * against a generic string here (e.g., "nor-jedec"). + * against a generic string here (e.g., "jedec,spi-nor"). * * Many flash names are kept here in this list (as well as in spi-nor.c) to * keep them available as module aliases for existing platforms. @@ -305,7 +305,7 @@ static const struct spi_device_id m25p_ids[] = { * Generic support for SPI NOR that can be identified by the JEDEC READ * ID opcode (0x9F). Use this, if possible. */ - {"nor-jedec"}, + {"spi-nor"}, { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c index a3196b7..58df07a 100644 --- a/drivers/mtd/tests/readtest.c +++ b/drivers/mtd/tests/readtest.c @@ -191,9 +191,11 @@ static int __init mtd_readtest_init(void) err = ret; } - err = mtdtest_relax(); - if (err) + ret = mtdtest_relax(); + if (ret) { + err = ret; goto out; + } } if (err) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index db2c05b..c9eb78f 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -310,6 +310,8 @@ static void ubiblock_do_work(struct work_struct *work) blk_rq_map_sg(req->q, req, pdu->usgl.sg); ret = ubiblock_read(pdu); + rq_flush_dcache_pages(req); + blk_mq_end_request(req, ret); } diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 6bddfe0..fc55e8e 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -509,10 +509,11 @@ static int xcan_rx(struct net_device *ndev) cf->can_id |= CAN_RTR_FLAG; } - if (!(id_xcan & XCAN_IDR_SRR_MASK)) { - data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); - data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + /* DW1/DW2 must always be read to remove message from RXFIFO */ + data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); + data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + if (!(cf->can_id & CAN_RTR_FLAG)) { /* Change Xilinx CAN data format to socketCAN data format */ if (cf->can_dlc > 0) *(__be32 *)(cf->data) = cpu_to_be32(data[0]); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index af639ab..cf309aa9 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1469,6 +1469,9 @@ static void __exit mv88e6xxx_cleanup(void) #if IS_ENABLED(CONFIG_NET_DSA_MV88E6171) unregister_switch_driver(&mv88e6171_switch_driver); #endif +#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352) + unregister_switch_driver(&mv88e6352_switch_driver); +#endif #if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65) unregister_switch_driver(&mv88e6123_61_65_switch_driver); #endif diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 089c269..4269160 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -180,6 +180,7 @@ config SUNLANCE config AMD_XGBE tristate "AMD 10GbE Ethernet driver" depends on (OF_NET || ACPI) && HAS_IOMEM && HAS_DMA + depends on ARM64 || COMPILE_TEST select PHYLIB select AMD_XGBE_PHY select BITREVERSE diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig index f4054d24..19e38af 100644 --- a/drivers/net/ethernet/apm/xgene/Kconfig +++ b/drivers/net/ethernet/apm/xgene/Kconfig @@ -1,6 +1,7 @@ config NET_XGENE tristate "APM X-Gene SoC Ethernet Driver" depends on HAS_DMA + depends on ARCH_XGENE || COMPILE_TEST select PHYLIB help This is the Ethernet driver for the on-chip ethernet interface on the diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index a8bb8f6..ec56a9b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -4786,6 +4786,11 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); + if (pci_num_vf(bp->pdev)) { + DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n"); + return -EPERM; + } + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { BNX2X_ERR("Can't perform change MTU during parity recovery\n"); return -EAGAIN; @@ -4938,11 +4943,6 @@ int bnx2x_resume(struct pci_dev *pdev) } bp = netdev_priv(dev); - if (pci_num_vf(bp->pdev)) { - DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n"); - return -EPERM; - } - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { BNX2X_ERR("Handling parity error recovery. Try again later\n"); return -EAGAIN; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 556dcc1..fd52ce9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13371,8 +13371,13 @@ static int bnx2x_init_one(struct pci_dev *pdev, /* Management FW 'remembers' living interfaces. Allow it some time * to forget previously living interfaces, allowing a proper re-load. */ - if (is_kdump_kernel()) - msleep(5000); + if (is_kdump_kernel()) { + ktime_t now = ktime_get_boottime(); + ktime_t fw_ready_time = ktime_set(5, 0); + + if (ktime_before(now, fw_ready_time)) + msleep(ktime_ms_delta(fw_ready_time, now)); + } /* An estimated maximum supported CoS number according to the chip * version. diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4104d49..61aa570 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -981,7 +981,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) struct macb_queue *queue = dev_id; struct macb *bp = queue->bp; struct net_device *dev = bp->dev; - u32 status; + u32 status, ctrl; status = queue_readl(queue, ISR); @@ -1037,6 +1037,15 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * add that if/when we get our hands on a full-blown MII PHY. */ + if (status & MACB_BIT(RXUBR)) { + ctrl = macb_readl(bp, NCR); + macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + macb_writel(bp, ISR, MACB_BIT(RXUBR)); + } + if (status & MACB_BIT(ISR_ROVR)) { /* We missed at least one packet */ if (macb_is_gem(bp)) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 5d9ceb1..0abc942 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -40,6 +40,7 @@ #include <linux/ptp_classify.h> #include <linux/mii.h> #include <linux/mdio.h> +#include <linux/pm_qos.h> #include "hw.h" struct e1000_info; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 1b0661e..c754b20 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -610,7 +610,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector, unsigned int total_bytes = 0, total_packets = 0; u16 cleaned_count = fm10k_desc_unused(rx_ring); - do { + while (likely(total_packets < budget)) { union fm10k_rx_desc *rx_desc; /* return some buffers to hardware, one at a time is too slow */ @@ -659,7 +659,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector, /* update budget accounting */ total_packets++; - } while (likely(total_packets < budget)); + } /* place incomplete frames back on ring for completion */ rx_ring->skb = skb; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 8457d03..a0a9b1fc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1036,7 +1036,7 @@ static void igb_reset_q_vector(struct igb_adapter *adapter, int v_idx) adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; if (q_vector->rx.ring) - adapter->tx_ring[q_vector->rx.ring->queue_index] = NULL; + adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL; netif_napi_del(&q_vector->napi); @@ -1207,6 +1207,8 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter, q_vector = adapter->q_vector[v_idx]; if (!q_vector) q_vector = kzalloc(size, GFP_KERNEL); + else + memset(q_vector, 0, size); if (!q_vector) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a16d267..e71cdde 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3612,7 +3612,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) u8 *dst_mac = skb_header_pointer(skb, 0, 0, NULL); if (!dst_mac || is_link_local_ether_addr(dst_mac)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index 54f0e5a..0a56f01 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -139,7 +139,7 @@ static unsigned long en_stats_adder(__be64 *start, __be64 *next, int num) int i; int offset = next - start; - for (i = 0; i <= num; i++) { + for (i = 0; i < num; i++) { ret += be64_to_cpu(*curr); curr += offset; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index c7f28bf..92fce1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2845,7 +2845,7 @@ int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, { int err; int eqn = vhcr->in_modifier; - int res_id = (slave << 8) | eqn; + int res_id = (slave << 10) | eqn; struct mlx4_eq_context *eqc = inbox->buf; int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; int mtt_size = eq_get_mtt_size(eqc); @@ -3051,7 +3051,7 @@ int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); + int res_id = eqn | (slave << 10); struct res_eq *eq; int err; @@ -3108,7 +3108,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) return 0; mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); - res_id = (slave << 8) | event_eq->eqn; + res_id = (slave << 10) | event_eq->eqn; err = get_res(dev, slave, res_id, RES_EQ, &req); if (err) goto unlock; @@ -3131,7 +3131,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) memcpy(mailbox->buf, (u8 *) eqe, 28); - in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); + in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16); err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, @@ -3157,7 +3157,7 @@ int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); + int res_id = eqn | (slave << 10); struct res_eq *eq; int err; @@ -4714,13 +4714,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) break; case RES_EQ_HW: - err = mlx4_cmd(dev, slave, eqn & 0xff, + err = mlx4_cmd(dev, slave, eqn & 0x3ff, 1, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", - slave, eqn); + slave, eqn & 0x3ff); atomic_dec(&eq->mtt->ref_count); state = RES_EQ_RESERVED; break; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 8da7c3f..7b43a3b 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -1764,7 +1764,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) int done = 0; struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - if (!spin_trylock(&adapter->tx_clean_lock)) + if (!spin_trylock_bh(&adapter->tx_clean_lock)) return 1; sw_consumer = tx_ring->sw_consumer; @@ -1819,7 +1819,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) */ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); done = (sw_consumer == hw_consumer); - spin_unlock(&adapter->tx_clean_lock); + spin_unlock_bh(&adapter->tx_clean_lock); return done; } diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index f66641d..6af028d 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -912,6 +912,8 @@ qca_spi_probe(struct spi_device *spi_device) qca->spi_dev = spi_device; qca->legacy_mode = legacy_mode; + spi_set_drvdata(spi_device, qcaspi_devs); + mac = of_get_mac_address(spi_device->dev.of_node); if (mac) @@ -944,8 +946,6 @@ qca_spi_probe(struct spi_device *spi_device) return -EFAULT; } - spi_set_drvdata(spi_device, qcaspi_devs); - qcaspi_init_device_debugfs(qca); return 0; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index c70ab40..3df51fa 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -6884,7 +6884,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp, rtl8169_start_xmit(nskb, tp->dev); } while (segs); - dev_kfree_skb(skb); + dev_consume_skb_any(skb); } else if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb_checksum_help(skb) < 0) goto drop; @@ -6896,7 +6896,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp, drop: stats = &tp->dev->stats; stats->tx_dropped++; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 14b363a..630f0b7 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2238,9 +2238,10 @@ static int smc_drv_probe(struct platform_device *pdev) const struct of_device_id *match = NULL; struct smc_local *lp; struct net_device *ndev; - struct resource *res, *ires; + struct resource *res; unsigned int __iomem *addr; unsigned long irq_flags = SMC_IRQ_FLAGS; + unsigned long irq_resflags; int ret; ndev = alloc_etherdev(sizeof(struct smc_local)); @@ -2332,16 +2333,19 @@ static int smc_drv_probe(struct platform_device *pdev) goto out_free_netdev; } - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { + ndev->irq = platform_get_irq(pdev, 0); + if (ndev->irq <= 0) { ret = -ENODEV; goto out_release_io; } - - ndev->irq = ires->start; - - if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK) - irq_flags = ires->flags & IRQF_TRIGGER_MASK; + /* + * If this platform does not specify any special irqflags, or if + * the resource supplies a trigger, override the irqflags with + * the trigger flags from the resource. + */ + irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq)); + if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK) + irq_flags = irq_resflags & IRQF_TRIGGER_MASK; ret = smc_request_attrib(pdev, ndev); if (ret) diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 41047c9..959aeea 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2418,9 +2418,9 @@ static int smsc911x_drv_probe(struct platform_device *pdev) struct net_device *dev; struct smsc911x_data *pdata; struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev); - struct resource *res, *irq_res; + struct resource *res; unsigned int intcfg = 0; - int res_size, irq_flags; + int res_size, irq, irq_flags; int retval; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -2434,8 +2434,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev) } res_size = resource_size(res); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; @@ -2455,8 +2455,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); pdata = netdev_priv(dev); - dev->irq = irq_res->start; - irq_flags = irq_res->flags & IRQF_TRIGGER_MASK; + dev->irq = irq; + irq_flags = irq_get_trigger_type(irq); pdata->ioaddr = ioremap_nocache(res->start, res_size); pdata->dev = dev; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 705bbdf..68aec5c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -23,6 +23,7 @@ *******************************************************************************/ #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_net.h> diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 690a4c3..af2694d 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -707,8 +707,8 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) cur_p->app0 |= STS_CTRL_APP0_SOP; cur_p->len = skb_headlen(skb); - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, - DMA_TO_DEVICE); + cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); cur_p->app4 = (unsigned long)skb; for (ii = 0; ii < num_frag; ii++) { diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 2d9ef53..ea091bc 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -826,7 +826,6 @@ int netvsc_send(struct hv_device *device, u16 q_idx = packet->q_idx; u32 pktlen = packet->total_data_buflen, msd_len = 0; unsigned int section_index = NETVSC_INVALID_INDEX; - struct sk_buff *skb = NULL; unsigned long flag; struct multi_send_data *msdp; struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL; @@ -924,12 +923,8 @@ int netvsc_send(struct hv_device *device, if (cur_send) ret = netvsc_send_pkt(cur_send, net_device); - if (ret != 0) { - if (section_index != NETVSC_INVALID_INDEX) - netvsc_free_send_slot(net_device, section_index); - } else if (skb) { - dev_kfree_skb_any(skb); - } + if (ret != 0 && section_index != NETVSC_INVALID_INDEX) + netvsc_free_send_slot(net_device, section_index); return ret; } diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3802665..67d00fb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -85,6 +85,7 @@ struct at86rf230_local { struct ieee802154_hw *hw; struct at86rf2xx_chip_data *data; struct regmap *regmap; + int slp_tr; struct completion state_complete; struct at86rf230_state_change state; @@ -95,163 +96,164 @@ struct at86rf230_local { unsigned long cal_timeout; s8 max_frame_retries; bool is_tx; + bool is_tx_from_off; u8 tx_retry; struct sk_buff *tx_skb; struct at86rf230_state_change tx; }; -#define RG_TRX_STATUS (0x01) -#define SR_TRX_STATUS 0x01, 0x1f, 0 -#define SR_RESERVED_01_3 0x01, 0x20, 5 -#define SR_CCA_STATUS 0x01, 0x40, 6 -#define SR_CCA_DONE 0x01, 0x80, 7 -#define RG_TRX_STATE (0x02) -#define SR_TRX_CMD 0x02, 0x1f, 0 -#define SR_TRAC_STATUS 0x02, 0xe0, 5 -#define RG_TRX_CTRL_0 (0x03) -#define SR_CLKM_CTRL 0x03, 0x07, 0 -#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 -#define SR_PAD_IO_CLKM 0x03, 0x30, 4 -#define SR_PAD_IO 0x03, 0xc0, 6 -#define RG_TRX_CTRL_1 (0x04) -#define SR_IRQ_POLARITY 0x04, 0x01, 0 -#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 -#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 -#define SR_RX_BL_CTRL 0x04, 0x10, 4 -#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 -#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 -#define SR_PA_EXT_EN 0x04, 0x80, 7 -#define RG_PHY_TX_PWR (0x05) -#define SR_TX_PWR 0x05, 0x0f, 0 -#define SR_PA_LT 0x05, 0x30, 4 -#define SR_PA_BUF_LT 0x05, 0xc0, 6 -#define RG_PHY_RSSI (0x06) -#define SR_RSSI 0x06, 0x1f, 0 -#define SR_RND_VALUE 0x06, 0x60, 5 -#define SR_RX_CRC_VALID 0x06, 0x80, 7 -#define RG_PHY_ED_LEVEL (0x07) -#define SR_ED_LEVEL 0x07, 0xff, 0 -#define RG_PHY_CC_CCA (0x08) -#define SR_CHANNEL 0x08, 0x1f, 0 -#define SR_CCA_MODE 0x08, 0x60, 5 -#define SR_CCA_REQUEST 0x08, 0x80, 7 -#define RG_CCA_THRES (0x09) -#define SR_CCA_ED_THRES 0x09, 0x0f, 0 -#define SR_RESERVED_09_1 0x09, 0xf0, 4 -#define RG_RX_CTRL (0x0a) -#define SR_PDT_THRES 0x0a, 0x0f, 0 -#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 -#define RG_SFD_VALUE (0x0b) -#define SR_SFD_VALUE 0x0b, 0xff, 0 -#define RG_TRX_CTRL_2 (0x0c) -#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 -#define SR_SUB_MODE 0x0c, 0x04, 2 -#define SR_BPSK_QPSK 0x0c, 0x08, 3 -#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 -#define SR_RESERVED_0c_5 0x0c, 0x60, 5 -#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 -#define RG_ANT_DIV (0x0d) -#define SR_ANT_CTRL 0x0d, 0x03, 0 -#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 -#define SR_ANT_DIV_EN 0x0d, 0x08, 3 -#define SR_RESERVED_0d_2 0x0d, 0x70, 4 -#define SR_ANT_SEL 0x0d, 0x80, 7 -#define RG_IRQ_MASK (0x0e) -#define SR_IRQ_MASK 0x0e, 0xff, 0 -#define RG_IRQ_STATUS (0x0f) -#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 -#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 -#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 -#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 -#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 -#define SR_IRQ_5_AMI 0x0f, 0x20, 5 -#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 -#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 -#define RG_VREG_CTRL (0x10) -#define SR_RESERVED_10_6 0x10, 0x03, 0 -#define SR_DVDD_OK 0x10, 0x04, 2 -#define SR_DVREG_EXT 0x10, 0x08, 3 -#define SR_RESERVED_10_3 0x10, 0x30, 4 -#define SR_AVDD_OK 0x10, 0x40, 6 -#define SR_AVREG_EXT 0x10, 0x80, 7 -#define RG_BATMON (0x11) -#define SR_BATMON_VTH 0x11, 0x0f, 0 -#define SR_BATMON_HR 0x11, 0x10, 4 -#define SR_BATMON_OK 0x11, 0x20, 5 -#define SR_RESERVED_11_1 0x11, 0xc0, 6 -#define RG_XOSC_CTRL (0x12) -#define SR_XTAL_TRIM 0x12, 0x0f, 0 -#define SR_XTAL_MODE 0x12, 0xf0, 4 -#define RG_RX_SYN (0x15) -#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 -#define SR_RESERVED_15_2 0x15, 0x70, 4 -#define SR_RX_PDT_DIS 0x15, 0x80, 7 -#define RG_XAH_CTRL_1 (0x17) -#define SR_RESERVED_17_8 0x17, 0x01, 0 -#define SR_AACK_PROM_MODE 0x17, 0x02, 1 -#define SR_AACK_ACK_TIME 0x17, 0x04, 2 -#define SR_RESERVED_17_5 0x17, 0x08, 3 -#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 -#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 -#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 -#define SR_RESERVED_17_1 0x17, 0x80, 7 -#define RG_FTN_CTRL (0x18) -#define SR_RESERVED_18_2 0x18, 0x7f, 0 -#define SR_FTN_START 0x18, 0x80, 7 -#define RG_PLL_CF (0x1a) -#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 -#define SR_PLL_CF_START 0x1a, 0x80, 7 -#define RG_PLL_DCU (0x1b) -#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 -#define SR_RESERVED_1b_2 0x1b, 0x40, 6 -#define SR_PLL_DCU_START 0x1b, 0x80, 7 -#define RG_PART_NUM (0x1c) -#define SR_PART_NUM 0x1c, 0xff, 0 -#define RG_VERSION_NUM (0x1d) -#define SR_VERSION_NUM 0x1d, 0xff, 0 -#define RG_MAN_ID_0 (0x1e) -#define SR_MAN_ID_0 0x1e, 0xff, 0 -#define RG_MAN_ID_1 (0x1f) -#define SR_MAN_ID_1 0x1f, 0xff, 0 -#define RG_SHORT_ADDR_0 (0x20) -#define SR_SHORT_ADDR_0 0x20, 0xff, 0 -#define RG_SHORT_ADDR_1 (0x21) -#define SR_SHORT_ADDR_1 0x21, 0xff, 0 -#define RG_PAN_ID_0 (0x22) -#define SR_PAN_ID_0 0x22, 0xff, 0 -#define RG_PAN_ID_1 (0x23) -#define SR_PAN_ID_1 0x23, 0xff, 0 -#define RG_IEEE_ADDR_0 (0x24) -#define SR_IEEE_ADDR_0 0x24, 0xff, 0 -#define RG_IEEE_ADDR_1 (0x25) -#define SR_IEEE_ADDR_1 0x25, 0xff, 0 -#define RG_IEEE_ADDR_2 (0x26) -#define SR_IEEE_ADDR_2 0x26, 0xff, 0 -#define RG_IEEE_ADDR_3 (0x27) -#define SR_IEEE_ADDR_3 0x27, 0xff, 0 -#define RG_IEEE_ADDR_4 (0x28) -#define SR_IEEE_ADDR_4 0x28, 0xff, 0 -#define RG_IEEE_ADDR_5 (0x29) -#define SR_IEEE_ADDR_5 0x29, 0xff, 0 -#define RG_IEEE_ADDR_6 (0x2a) -#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 -#define RG_IEEE_ADDR_7 (0x2b) -#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 -#define RG_XAH_CTRL_0 (0x2c) -#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 -#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 -#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 -#define RG_CSMA_SEED_0 (0x2d) -#define SR_CSMA_SEED_0 0x2d, 0xff, 0 -#define RG_CSMA_SEED_1 (0x2e) -#define SR_CSMA_SEED_1 0x2e, 0x07, 0 -#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 -#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 -#define SR_AACK_SET_PD 0x2e, 0x20, 5 -#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 -#define RG_CSMA_BE (0x2f) -#define SR_MIN_BE 0x2f, 0x0f, 0 -#define SR_MAX_BE 0x2f, 0xf0, 4 +#define RG_TRX_STATUS (0x01) +#define SR_TRX_STATUS 0x01, 0x1f, 0 +#define SR_RESERVED_01_3 0x01, 0x20, 5 +#define SR_CCA_STATUS 0x01, 0x40, 6 +#define SR_CCA_DONE 0x01, 0x80, 7 +#define RG_TRX_STATE (0x02) +#define SR_TRX_CMD 0x02, 0x1f, 0 +#define SR_TRAC_STATUS 0x02, 0xe0, 5 +#define RG_TRX_CTRL_0 (0x03) +#define SR_CLKM_CTRL 0x03, 0x07, 0 +#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 +#define SR_PAD_IO_CLKM 0x03, 0x30, 4 +#define SR_PAD_IO 0x03, 0xc0, 6 +#define RG_TRX_CTRL_1 (0x04) +#define SR_IRQ_POLARITY 0x04, 0x01, 0 +#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 +#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 +#define SR_RX_BL_CTRL 0x04, 0x10, 4 +#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 +#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 +#define SR_PA_EXT_EN 0x04, 0x80, 7 +#define RG_PHY_TX_PWR (0x05) +#define SR_TX_PWR 0x05, 0x0f, 0 +#define SR_PA_LT 0x05, 0x30, 4 +#define SR_PA_BUF_LT 0x05, 0xc0, 6 +#define RG_PHY_RSSI (0x06) +#define SR_RSSI 0x06, 0x1f, 0 +#define SR_RND_VALUE 0x06, 0x60, 5 +#define SR_RX_CRC_VALID 0x06, 0x80, 7 +#define RG_PHY_ED_LEVEL (0x07) +#define SR_ED_LEVEL 0x07, 0xff, 0 +#define RG_PHY_CC_CCA (0x08) +#define SR_CHANNEL 0x08, 0x1f, 0 +#define SR_CCA_MODE 0x08, 0x60, 5 +#define SR_CCA_REQUEST 0x08, 0x80, 7 +#define RG_CCA_THRES (0x09) +#define SR_CCA_ED_THRES 0x09, 0x0f, 0 +#define SR_RESERVED_09_1 0x09, 0xf0, 4 +#define RG_RX_CTRL (0x0a) +#define SR_PDT_THRES 0x0a, 0x0f, 0 +#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 +#define RG_SFD_VALUE (0x0b) +#define SR_SFD_VALUE 0x0b, 0xff, 0 +#define RG_TRX_CTRL_2 (0x0c) +#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 +#define SR_SUB_MODE 0x0c, 0x04, 2 +#define SR_BPSK_QPSK 0x0c, 0x08, 3 +#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 +#define SR_RESERVED_0c_5 0x0c, 0x60, 5 +#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 +#define RG_ANT_DIV (0x0d) +#define SR_ANT_CTRL 0x0d, 0x03, 0 +#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 +#define SR_ANT_DIV_EN 0x0d, 0x08, 3 +#define SR_RESERVED_0d_2 0x0d, 0x70, 4 +#define SR_ANT_SEL 0x0d, 0x80, 7 +#define RG_IRQ_MASK (0x0e) +#define SR_IRQ_MASK 0x0e, 0xff, 0 +#define RG_IRQ_STATUS (0x0f) +#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 +#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 +#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 +#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 +#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 +#define SR_IRQ_5_AMI 0x0f, 0x20, 5 +#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 +#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 +#define RG_VREG_CTRL (0x10) +#define SR_RESERVED_10_6 0x10, 0x03, 0 +#define SR_DVDD_OK 0x10, 0x04, 2 +#define SR_DVREG_EXT 0x10, 0x08, 3 +#define SR_RESERVED_10_3 0x10, 0x30, 4 +#define SR_AVDD_OK 0x10, 0x40, 6 +#define SR_AVREG_EXT 0x10, 0x80, 7 +#define RG_BATMON (0x11) +#define SR_BATMON_VTH 0x11, 0x0f, 0 +#define SR_BATMON_HR 0x11, 0x10, 4 +#define SR_BATMON_OK 0x11, 0x20, 5 +#define SR_RESERVED_11_1 0x11, 0xc0, 6 +#define RG_XOSC_CTRL (0x12) +#define SR_XTAL_TRIM 0x12, 0x0f, 0 +#define SR_XTAL_MODE 0x12, 0xf0, 4 +#define RG_RX_SYN (0x15) +#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 +#define SR_RESERVED_15_2 0x15, 0x70, 4 +#define SR_RX_PDT_DIS 0x15, 0x80, 7 +#define RG_XAH_CTRL_1 (0x17) +#define SR_RESERVED_17_8 0x17, 0x01, 0 +#define SR_AACK_PROM_MODE 0x17, 0x02, 1 +#define SR_AACK_ACK_TIME 0x17, 0x04, 2 +#define SR_RESERVED_17_5 0x17, 0x08, 3 +#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 +#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 +#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 +#define SR_RESERVED_17_1 0x17, 0x80, 7 +#define RG_FTN_CTRL (0x18) +#define SR_RESERVED_18_2 0x18, 0x7f, 0 +#define SR_FTN_START 0x18, 0x80, 7 +#define RG_PLL_CF (0x1a) +#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 +#define SR_PLL_CF_START 0x1a, 0x80, 7 +#define RG_PLL_DCU (0x1b) +#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 +#define SR_RESERVED_1b_2 0x1b, 0x40, 6 +#define SR_PLL_DCU_START 0x1b, 0x80, 7 +#define RG_PART_NUM (0x1c) +#define SR_PART_NUM 0x1c, 0xff, 0 +#define RG_VERSION_NUM (0x1d) +#define SR_VERSION_NUM 0x1d, 0xff, 0 +#define RG_MAN_ID_0 (0x1e) +#define SR_MAN_ID_0 0x1e, 0xff, 0 +#define RG_MAN_ID_1 (0x1f) +#define SR_MAN_ID_1 0x1f, 0xff, 0 +#define RG_SHORT_ADDR_0 (0x20) +#define SR_SHORT_ADDR_0 0x20, 0xff, 0 +#define RG_SHORT_ADDR_1 (0x21) +#define SR_SHORT_ADDR_1 0x21, 0xff, 0 +#define RG_PAN_ID_0 (0x22) +#define SR_PAN_ID_0 0x22, 0xff, 0 +#define RG_PAN_ID_1 (0x23) +#define SR_PAN_ID_1 0x23, 0xff, 0 +#define RG_IEEE_ADDR_0 (0x24) +#define SR_IEEE_ADDR_0 0x24, 0xff, 0 +#define RG_IEEE_ADDR_1 (0x25) +#define SR_IEEE_ADDR_1 0x25, 0xff, 0 +#define RG_IEEE_ADDR_2 (0x26) +#define SR_IEEE_ADDR_2 0x26, 0xff, 0 +#define RG_IEEE_ADDR_3 (0x27) +#define SR_IEEE_ADDR_3 0x27, 0xff, 0 +#define RG_IEEE_ADDR_4 (0x28) +#define SR_IEEE_ADDR_4 0x28, 0xff, 0 +#define RG_IEEE_ADDR_5 (0x29) +#define SR_IEEE_ADDR_5 0x29, 0xff, 0 +#define RG_IEEE_ADDR_6 (0x2a) +#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 +#define RG_IEEE_ADDR_7 (0x2b) +#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 +#define RG_XAH_CTRL_0 (0x2c) +#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 +#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 +#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 +#define RG_CSMA_SEED_0 (0x2d) +#define SR_CSMA_SEED_0 0x2d, 0xff, 0 +#define RG_CSMA_SEED_1 (0x2e) +#define SR_CSMA_SEED_1 0x2e, 0x07, 0 +#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 +#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 +#define SR_AACK_SET_PD 0x2e, 0x20, 5 +#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 +#define RG_CSMA_BE (0x2f) +#define SR_MIN_BE 0x2f, 0x0f, 0 +#define SR_MAX_BE 0x2f, 0xf0, 4 #define CMD_REG 0x80 #define CMD_REG_MASK 0x3f @@ -292,6 +294,8 @@ struct at86rf230_local { #define STATE_BUSY_RX_AACK_NOCLK 0x1E #define STATE_TRANSITION_IN_PROGRESS 0x1F +#define TRX_STATE_MASK (0x1F) + #define AT86RF2XX_NUMREGS 0x3F static void @@ -336,6 +340,14 @@ at86rf230_write_subreg(struct at86rf230_local *lp, return regmap_update_bits(lp->regmap, addr, mask, data << shift); } +static inline void +at86rf230_slp_tr_rising_edge(struct at86rf230_local *lp) +{ + gpio_set_value(lp->slp_tr, 1); + udelay(1); + gpio_set_value(lp->slp_tr, 0); +} + static bool at86rf230_reg_writeable(struct device *dev, unsigned int reg) { @@ -509,7 +521,7 @@ at86rf230_async_state_assert(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; const u8 *buf = ctx->buf; - const u8 trx_state = buf[1] & 0x1f; + const u8 trx_state = buf[1] & TRX_STATE_MASK; /* Assert state change */ if (trx_state != ctx->to_state) { @@ -609,11 +621,17 @@ at86rf230_async_state_delay(void *context) switch (ctx->to_state) { case STATE_RX_AACK_ON: tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC); + /* state change from TRX_OFF to RX_AACK_ON to do a + * calibration, we need to reset the timeout for the + * next one. + */ + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; goto change; + case STATE_TX_ARET_ON: case STATE_TX_ON: tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); - /* state change from TRX_OFF to TX_ON to do a - * calibration, we need to reset the timeout for the + /* state change from TRX_OFF to TX_ON or ARET_ON to do + * a calibration, we need to reset the timeout for the * next one. */ lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; @@ -667,7 +685,7 @@ at86rf230_async_state_change_start(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; - const u8 trx_state = buf[1] & 0x1f; + const u8 trx_state = buf[1] & TRX_STATE_MASK; int rc; /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ @@ -773,16 +791,6 @@ at86rf230_tx_on(void *context) } static void -at86rf230_tx_trac_error(void *context) -{ - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_tx_on, true); -} - -static void at86rf230_tx_trac_check(void *context) { struct at86rf230_state_change *ctx = context; @@ -791,12 +799,12 @@ at86rf230_tx_trac_check(void *context) const u8 trac = (buf[1] & 0xe0) >> 5; /* If trac status is different than zero we need to do a state change - * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver - * state to TX_ON. + * to STATE_FORCE_TRX_OFF then STATE_RX_AACK_ON to recover the + * transceiver. */ if (trac) at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, - at86rf230_tx_trac_error, true); + at86rf230_tx_on, true); else at86rf230_tx_on(context); } @@ -941,13 +949,18 @@ at86rf230_write_frame_complete(void *context) u8 *buf = ctx->buf; int rc; - buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; - buf[1] = STATE_BUSY_TX; ctx->trx.len = 2; - ctx->msg.complete = NULL; - rc = spi_async(lp->spi, &ctx->msg); - if (rc) - at86rf230_async_error(lp, ctx, rc); + + if (gpio_is_valid(lp->slp_tr)) { + at86rf230_slp_tr_rising_edge(lp); + } else { + buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; + buf[1] = STATE_BUSY_TX; + ctx->msg.complete = NULL; + rc = spi_async(lp->spi, &ctx->msg); + if (rc) + at86rf230_async_error(lp, ctx, rc); + } } static void @@ -993,12 +1006,21 @@ at86rf230_xmit_start(void *context) * are in STATE_TX_ON. The pfad differs here, so we change * the complete handler. */ - if (lp->tx_aret) - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_xmit_tx_on, false); - else + if (lp->tx_aret) { + if (lp->is_tx_from_off) { + lp->is_tx_from_off = false; + at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, + at86rf230_xmit_tx_on, + false); + } else { + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_xmit_tx_on, + false); + } + } else { at86rf230_async_state_change(lp, ctx, STATE_TX_ON, at86rf230_write_frame, false); + } } static int @@ -1017,11 +1039,13 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) * to TX_ON, the lp->cal_timeout should be reinit by state_delay * function then to start in the next 5 minutes. */ - if (time_is_before_jiffies(lp->cal_timeout)) + if (time_is_before_jiffies(lp->cal_timeout)) { + lp->is_tx_from_off = true; at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, at86rf230_xmit_start, false); - else + } else { at86rf230_xmit_start(ctx); + } return 0; } @@ -1037,9 +1061,6 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) static int at86rf230_start(struct ieee802154_hw *hw) { - struct at86rf230_local *lp = hw->priv; - - lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); } @@ -1673,6 +1694,7 @@ static int at86rf230_probe(struct spi_device *spi) lp = hw->priv; lp->hw = hw; lp->spi = spi; + lp->slp_tr = slp_tr; hw->parent = &spi->dev; hw->vif_data_size = sizeof(*lp); ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b227a13..9f59f17 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -599,10 +599,18 @@ static int macvlan_open(struct net_device *dev) goto del_unicast; } + if (dev->flags & IFF_PROMISC) { + err = dev_set_promiscuity(lowerdev, 1); + if (err < 0) + goto clear_multi; + } + hash_add: macvlan_hash_add(vlan); return 0; +clear_multi: + dev_set_allmulti(lowerdev, -1); del_unicast: dev_uc_del(lowerdev, dev->dev_addr); out: @@ -638,6 +646,9 @@ static int macvlan_stop(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(lowerdev, -1); + dev_uc_del(lowerdev, dev->dev_addr); hash_del: @@ -696,6 +707,10 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) if (dev->flags & IFF_UP) { if (change & IFF_ALLMULTI) dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); + if (change & IFF_PROMISC) + dev_set_promiscuity(lowerdev, + dev->flags & IFF_PROMISC ? 1 : -1); + } } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8fadaa1..70641d2 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -27,6 +27,7 @@ config AMD_PHY config AMD_XGBE_PHY tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" depends on (OF || ACPI) && HAS_IOMEM + depends on ARM64 || COMPILE_TEST ---help--- Currently supports the AMD 10GbE PHY diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index c9cb486c..53d1815 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -168,7 +168,10 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, if (!new_bus->irq[i]) new_bus->irq[i] = PHY_POLL; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); + if (bus_id != -1) + snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); + else + strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); if (devm_gpio_request(dev, bitbang->mdc, "mdc")) goto out_free_bus; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 1190fd8..ebdc357 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -548,7 +548,8 @@ static int kszphy_probe(struct phy_device *phydev) } clk = devm_clk_get(&phydev->dev, "rmii-ref"); - if (!IS_ERR(clk)) { + /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */ + if (!IS_ERR_OR_NULL(clk)) { unsigned long rate = clk_get_rate(clk); bool rmii_ref_clk_sel_25_mhz; diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index aa1dd92..b62a5e3 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -465,6 +465,10 @@ static void pppoe_unbind_sock_work(struct work_struct *work) struct sock *sk = sk_pppox(po); lock_sock(sk); + if (po->pppoe_dev) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } pppox_unbind_sock(sk); release_sock(sk); sock_put(sk); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ac4d03b..aafa1a1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4116,6 +4116,7 @@ static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, {} }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 733f4fe..3c86b10 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1285,7 +1285,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) { struct usbnet *dev = netdev_priv(net); - int length; + unsigned int length; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; @@ -1413,7 +1413,7 @@ not_drop: } } else netif_dbg(dev, tx_queued, dev->net, - "> tx, len %d, type 0x%x\n", length, skb->protocol); + "> tx, len %u, type 0x%x\n", length, skb->protocol); #ifdef CONFIG_PM deferred: #endif diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0acd079..3ad79bb 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1103,28 +1103,14 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ath_frame_info *fi; struct ieee80211_tx_info *info; - struct ieee80211_vif *vif; struct ath_hw *ah = sc->sc_ah; if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; skb = bf->bf_mpdu; - info = IEEE80211_SKB_CB(skb); - vif = info->control.vif; - - if (!vif) { - max_power = sc->cur_chan->cur_txpower; - goto out; - } - - if (vif->bss_conf.txpower_type != NL80211_TX_POWER_LIMITED) { - max_power = min_t(u8, sc->cur_chan->cur_txpower, - 2 * vif->bss_conf.txpower); - goto out; - } - fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); if (!AR_SREV_9300_20_OR_LATER(ah)) { int txpower = fi->tx_power; @@ -1161,25 +1147,26 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, txpower -= 2; txpower = max(txpower, 0); - max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min_t(u8, max_power, txpower); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) max_power = min_t(u8, ah->tx_power_stbc[rateidx], - 2 * vif->bss_conf.txpower); + fi->tx_power); else max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min(max_power, fi->tx_power); + fi->tx_power); } else { max_power = ah->paprd_training_power; } -out: - /* XXX: clamp minimum TX power at 1 for AR9160 since if max_power - * is set to 0, frames are transmitted at max TX power - */ - return (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) ? 1 : max_power; + + return max_power; } static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -2129,6 +2116,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct ath_node *an = NULL; enum ath9k_key_type keytype; bool short_preamble = false; + u8 txpower; /* * We check if Short Preamble is needed for the CTS rate by @@ -2145,6 +2133,16 @@ static void setup_frame_info(struct ieee80211_hw *hw, if (sta) an = (struct ath_node *) sta->drv_priv; + if (tx_info->control.vif) { + struct ieee80211_vif *vif = tx_info->control.vif; + + txpower = 2 * vif->bss_conf.txpower; + } else { + struct ath_softc *sc = hw->priv; + + txpower = sc->cur_chan->cur_txpower; + } + memset(fi, 0, sizeof(*fi)); fi->txq = -1; if (hw_key) @@ -2155,7 +2153,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; - fi->tx_power = MAX_RATE_POWER; + fi->tx_power = txpower; if (!rate) return; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index bfdf3fa..62db2e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag { * longer than the passive one, which is essential for fragmented scan. * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR + * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate * the actual dwell time. @@ -260,6 +261,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), + IWL_UCODE_TLV_API_TX_POWER_DEV = BIT(11), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), IWL_UCODE_TLV_API_SCD_CFG = BIT(15), IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 6dfed12..56254a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg { * * All the handlers MUST be implemented * - * @start_hw: starts the HW- from that point on, the HW can send interrupts - * May sleep + * @start_hw: starts the HW. If low_power is true, the NIC needs to be taken + * out of a low power state. From that point on, the HW can send + * interrupts. May sleep. * @op_mode_leave: Turn off the HW RF kill indication if on * May sleep * @start_fw: allocates and inits all the resources for the transport @@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg { * the SCD base address in SRAM, then provide it here, or 0 otherwise. * May sleep * @stop_device: stops the whole device (embedded CPU put to reset) and stops - * the HW. From that point on, the HW will be in low power but will still - * issue interrupt if the HW RF kill is triggered. This callback must do - * the right thing and not crash even if start_hw() was called but not - * start_fw(). May sleep + * the HW. If low_power is true, the NIC will be put in low power state. + * From that point on, the HW will be stopped but will still issue an + * interrupt if the HW RF kill switch is triggered. + * This callback must do the right thing and not crash even if %start_hw() + * was called but not &start_fw(). May sleep. * @d3_suspend: put the device into the correct mode for WoWLAN during * suspend. This is optional, if not implemented WoWLAN will not be * supported. This callback may sleep. @@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg { */ struct iwl_trans_ops { - int (*start_hw)(struct iwl_trans *iwl_trans); + int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power); void (*op_mode_leave)(struct iwl_trans *iwl_trans); int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill); int (*update_sf)(struct iwl_trans *trans, struct iwl_sf_region *st_fwrd_space); void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); - void (*stop_device)(struct iwl_trans *trans); + void (*stop_device)(struct iwl_trans *trans, bool low_power); void (*d3_suspend)(struct iwl_trans *trans, bool test); int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, @@ -652,11 +654,16 @@ static inline void iwl_trans_configure(struct iwl_trans *trans, trans->ops->configure(trans, trans_cfg); } -static inline int iwl_trans_start_hw(struct iwl_trans *trans) +static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power) { might_sleep(); - return trans->ops->start_hw(trans); + return trans->ops->start_hw(trans, low_power); +} + +static inline int iwl_trans_start_hw(struct iwl_trans *trans) +{ + return trans->ops->start_hw(trans, true); } static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans) @@ -703,15 +710,21 @@ static inline int iwl_trans_update_sf(struct iwl_trans *trans, return 0; } -static inline void iwl_trans_stop_device(struct iwl_trans *trans) +static inline void _iwl_trans_stop_device(struct iwl_trans *trans, + bool low_power) { might_sleep(); - trans->ops->stop_device(trans); + trans->ops->stop_device(trans, low_power); trans->state = IWL_TRANS_NO_FW; } +static inline void iwl_trans_stop_device(struct iwl_trans *trans) +{ + _iwl_trans_stop_device(trans, true); +} + static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) { might_sleep(); diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a6c48c7..1b1b2bf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1726,7 +1726,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, results->matched_profiles = le32_to_cpu(query->matched_profiles); memcpy(results->matches, query->matches, sizeof(results->matches)); -#ifdef CPTCFG_IWLWIFI_DEBUGFS +#ifdef CONFIG_IWLWIFI_DEBUGFS mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done); #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 4fc0938b..b1baa33 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -298,6 +298,40 @@ struct iwl_uapsd_misbehaving_ap_notif { } __packed; /** + * struct iwl_reduce_tx_power_cmd - TX power reduction command + * REDUCE_TX_POWER_CMD = 0x9f + * @flags: (reserved for future implementation) + * @mac_context_id: id of the mac ctx for which we are reducing TX power. + * @pwr_restriction: TX power restriction in dBms. + */ +struct iwl_reduce_tx_power_cmd { + u8 flags; + u8 mac_context_id; + __le16 pwr_restriction; +} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ + +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * REDUCE_TX_POWER_CMD = 0x9f + * @set_mode: 0 - MAC tx power, 1 - device tx power + * @mac_context_id: id of the mac ctx for which we are reducing TX power. + * @pwr_restriction: TX power restriction in 1/8 dBms. + * @dev_24: device TX power restriction in 1/8 dBms + * @dev_52_low: device TX power restriction upper band - low + * @dev_52_high: device TX power restriction upper band - high + */ +struct iwl_dev_tx_power_cmd { + __le32 set_mode; + __le32 mac_context_id; + __le16 pwr_restriction; + __le16 dev_24; + __le16 dev_52_low; + __le16 dev_52_high; +} __packed; /* TX_REDUCED_POWER_API_S_VER_2 */ + +#define IWL_DEV_MAX_TX_POWER 0x7FFF + +/** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 4f81dcf..d6cced4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -122,46 +122,6 @@ enum iwl_scan_complete_status { SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, }; -/** - * struct iwl_scan_results_notif - scan results for one channel - * ( SCAN_RESULTS_NOTIFICATION = 0x83 ) - * @channel: which channel the results are from - * @band: 0 for 5.2 GHz, 1 for 2.4 GHz - * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request - * @num_probe_not_sent: # of request that weren't sent due to not enough time - * @duration: duration spent in channel, in usecs - * @statistics: statistics gathered for this channel - */ -struct iwl_scan_results_notif { - u8 channel; - u8 band; - u8 probe_status; - u8 num_probe_not_sent; - __le32 duration; - __le32 statistics[SCAN_RESULTS_STATISTICS]; -} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */ - -/** - * struct iwl_scan_complete_notif - notifies end of scanning (all channels) - * ( SCAN_COMPLETE_NOTIFICATION = 0x84 ) - * @scanned_channels: number of channels scanned (and number of valid results) - * @status: one of SCAN_COMP_STATUS_* - * @bt_status: BT on/off status - * @last_channel: last channel that was scanned - * @tsf_low: TSF timer (lower half) in usecs - * @tsf_high: TSF timer (higher half) in usecs - * @results: array of scan results, only "scanned_channels" of them are valid - */ -struct iwl_scan_complete_notif { - u8 scanned_channels; - u8 status; - u8 bt_status; - u8 last_channel; - __le32 tsf_low; - __le32 tsf_high; - struct iwl_scan_results_notif results[]; -} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ - /* scan offload */ #define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 @@ -554,7 +514,7 @@ struct iwl_scan_req_unified_lmac { } __packed; /** - * struct iwl_lmac_scan_results_notif - scan results for one channel - + * struct iwl_scan_results_notif - scan results for one channel - * SCAN_RESULT_NTF_API_S_VER_3 * @channel: which channel the results are from * @band: 0 for 5.2 GHz, 1 for 2.4 GHz @@ -562,7 +522,7 @@ struct iwl_scan_req_unified_lmac { * @num_probe_not_sent: # of request that weren't sent due to not enough time * @duration: duration spent in channel, in usecs */ -struct iwl_lmac_scan_results_notif { +struct iwl_scan_results_notif { u8 channel; u8 band; u8 probe_status; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index aab68cb..01b1da6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -281,19 +281,6 @@ struct iwl_tx_ant_cfg_cmd { __le32 valid; } __packed; -/** - * struct iwl_reduce_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @flags: (reserved for future implementation) - * @mac_context_id: id of the mac ctx for which we are reducing TX power. - * @pwr_restriction: TX power restriction in dBms. - */ -struct iwl_reduce_tx_power_cmd { - u8 flags; - u8 mac_context_id; - __le16 pwr_restriction; -} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ - /* * Calibration control struct. * Sent as part of the phy configuration command. diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index bc5eac4..df86963 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -322,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) + if (WARN_ON_ONCE(mvm->calibrating)) return 0; iwl_init_notification_wait(&mvm->notif_wait, @@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) */ ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, MVM_UCODE_CALIB_TIMEOUT); - if (!ret) - mvm->init_ucode_complete = true; if (ret && iwl_mvm_is_radio_killed(mvm)) { IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); @@ -494,15 +492,6 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, mvm->fw_dump_desc = desc; - /* stop recording */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); - } else { - iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); - /* wait before we collect the data till the DBGC stop */ - udelay(100); - } - queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); return 0; @@ -658,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm) * module loading, load init ucode now * (for example, if we were in RFKILL) */ - if (!mvm->init_ucode_complete) { - ret = iwl_run_init_mvm_ucode(mvm, false); - if (ret && !iwlmvm_mod_params.init_dbg) { - IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); - /* this can't happen */ - if (WARN_ON(ret > 0)) - ret = -ERFKILL; - goto error; - } - if (!iwlmvm_mod_params.init_dbg) { - /* - * should stop and start HW since that INIT - * image just loaded - */ - iwl_trans_stop_device(mvm->trans); - ret = iwl_trans_start_hw(mvm->trans); - if (ret) - return ret; - } + ret = iwl_run_init_mvm_ucode(mvm, false); + if (ret && !iwlmvm_mod_params.init_dbg) { + IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); + /* this can't happen */ + if (WARN_ON(ret > 0)) + ret = -ERFKILL; + goto error; + } + if (!iwlmvm_mod_params.init_dbg) { + /* + * Stop and start the transport without entering low power + * mode. This will save the state of other components on the + * device that are triggered by the INIT firwmare (MFUART). + */ + _iwl_trans_stop_device(mvm->trans, false); + _iwl_trans_start_hw(mvm->trans, false); + if (ret) + return ret; } if (iwlmvm_mod_params.init_dbg) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8455517..40265b9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1322,7 +1322,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); iwl_mvm_d0i3_enable_tx(mvm, NULL); - ret = iwl_mvm_update_quotas(mvm, false, NULL); + ret = iwl_mvm_update_quotas(mvm, true, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); @@ -1471,8 +1471,8 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) return NULL; } -static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - s8 tx_power) +static int iwl_mvm_set_tx_power_old(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, s8 tx_power) { /* FW is in charge of regulatory enforcement */ struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { @@ -1485,6 +1485,26 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &reduce_txpwr_cmd); } +static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + s16 tx_power) +{ + struct iwl_dev_tx_power_cmd cmd = { + .set_mode = 0, + .mac_context_id = + cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), + .pwr_restriction = cpu_to_le16(8 * tx_power), + }; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV)) + return iwl_mvm_set_tx_power_old(mvm, vif, tx_power); + + if (tx_power == IWL_DEFAULT_MAX_TX_POWER) + cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, + sizeof(cmd), &cmd); +} + static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d5522a1..cf70f68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -603,7 +603,6 @@ struct iwl_mvm { enum iwl_ucode_type cur_ucode; bool ucode_loaded; - bool init_ucode_complete; bool calibrating; u32 error_event_table; u32 log_event_table; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a08b03d..1c66297 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -865,6 +865,16 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) return; mutex_lock(&mvm->mutex); + + /* stop recording */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + } else { + iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); + /* wait before we collect the data till the DBGC stop */ + udelay(100); + } + iwl_mvm_fw_error_dump(mvm); /* start recording again if the firmware is not crashed */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 78ec7db..d6314dd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -478,6 +478,11 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, if (vif->type != NL80211_IFTYPE_STATION) return; + if (sig == 0) { + IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); + return; + } + mvmvif->bf_data.ave_beacon_signal = sig; /* BT Coex */ diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 74e1c86..1075a21 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -319,7 +319,7 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_scan_complete_notif *notif = (void *)pkt->data; + struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; IWL_DEBUG_SCAN(mvm, "Scan offload iteration complete: status=0x%x scanned channels=%d\n", diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 2de8fbf..47bbf57 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -5,8 +5,8 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,8 +31,8 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,7 +104,7 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct page *page; + struct page *page = NULL; dma_addr_t phys; u32 size; u8 power; @@ -131,6 +131,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) DMA_FROM_DEVICE); if (dma_mapping_error(trans->dev, phys)) { __free_pages(page, order); + page = NULL; continue; } IWL_INFO(trans, @@ -1020,7 +1021,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill, was_hw_rfkill; @@ -1115,7 +1116,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) { if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - iwl_trans_pcie_stop_device(trans); + iwl_trans_pcie_stop_device(trans, true); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -1200,7 +1201,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { bool hw_rfkill; int err; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f0188c8..2721cf8 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -126,7 +126,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, do { status = usb_control_msg(udev, pipe, request, reqtype, value, - index, pdata, len, 0); /*max. timeout*/ + index, pdata, len, 1000); if (status < 0) { /* firmware download is checksumed, don't retry */ if ((value >= FW_8192C_START_ADDRESS && diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 8be2096..deeaed5 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -348,7 +348,7 @@ int superio_fixup_irq(struct pci_dev *pcidev) BUG(); return -1; } - printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n", + printk(KERN_DEBUG "superio_fixup_irq(%s) ven 0x%x dev 0x%x from %ps\n", pci_name(pcidev), pcidev->vendor, pcidev->device, __builtin_return_address(0)); diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 89dca77..18ee208 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1110,7 +1110,7 @@ void devm_pinctrl_put(struct pinctrl *p) EXPORT_SYMBOL_GPL(devm_pinctrl_put); int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, - bool dup, bool locked) + bool dup) { int i, ret; struct pinctrl_maps *maps_node; @@ -1178,11 +1178,9 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, maps_node->maps = maps; } - if (!locked) - mutex_lock(&pinctrl_maps_mutex); + mutex_lock(&pinctrl_maps_mutex); list_add_tail(&maps_node->node, &pinctrl_maps); - if (!locked) - mutex_unlock(&pinctrl_maps_mutex); + mutex_unlock(&pinctrl_maps_mutex); return 0; } @@ -1197,7 +1195,7 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, int pinctrl_register_mappings(struct pinctrl_map const *maps, unsigned num_maps) { - return pinctrl_register_map(maps, num_maps, true, false); + return pinctrl_register_map(maps, num_maps, true); } void pinctrl_unregister_map(struct pinctrl_map const *map) diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 75476b3..b24ea84 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -183,7 +183,7 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, } int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, - bool dup, bool locked); + bool dup); void pinctrl_unregister_map(struct pinctrl_map const *map); extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index eda13de..0bbf7d7 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -92,7 +92,7 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, dt_map->num_maps = num_maps; list_add_tail(&dt_map->node, &p->dt_maps); - return pinctrl_register_map(map, num_maps, false, true); + return pinctrl_register_map(map, num_maps, false); } struct pinctrl_dev *of_pinctrl_get(struct device_node *np) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 493294c..474812e 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -881,6 +881,8 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, if (!mtk_eint_get_mask(pctl, eint_num)) { mtk_eint_mask(d); unmask = 1; + } else { + unmask = 0; } clr_bit = 0xff << eint_offset; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c index 42f930f..03aa58c 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c @@ -364,7 +364,7 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = { MPP_FUNCTION(0x5, "audio", "mclk"), MPP_FUNCTION(0x6, "uart0", "cts")), MPP_MODE(63, - MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x0, "gpio", NULL), MPP_FUNCTION(0x1, "spi0", "sck"), MPP_FUNCTION(0x2, "tclk", NULL)), MPP_MODE(64, diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index b2d2221..ae4115e 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -260,6 +260,7 @@ static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function, val = 1; } + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; @@ -417,7 +418,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, return ret; val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT; - val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; + val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val); if (ret < 0) @@ -466,12 +467,13 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, seq_puts(s, " ---"); } else { - if (!pad->input_enabled) { + if (pad->input_enabled) { ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); - if (!ret) { - ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; - pad->out_value = ret; - } + if (ret < 0) + return; + + ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; + pad->out_value = ret; } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 8f36c5f..211b942 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -370,6 +370,7 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, } } + val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; @@ -576,10 +577,11 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, if (pad->input_enabled) { ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); - if (!ret) { - ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; - pad->out_value = ret; - } + if (ret < 0) + return; + + ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; + pad->out_value = ret; } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index b3d419a..b496db8 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -830,6 +830,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) */ static const struct dmi_system_id no_hw_rfkill_list[] = { { + .ident = "Lenovo G40-30", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"), + }, + }, + { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7769575..9bb9ad6 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2115,7 +2115,7 @@ static int hotkey_mask_get(void) return 0; } -void static hotkey_mask_warn_incomplete_mask(void) +static void hotkey_mask_warn_incomplete_mask(void) { /* log only what the user can fix... */ const u32 wantedmask = hotkey_driver_mask & diff --git a/drivers/power/axp288_fuel_gauge.c b/drivers/power/axp288_fuel_gauge.c index ca1cc5a..bd1dbfe 100644 --- a/drivers/power/axp288_fuel_gauge.c +++ b/drivers/power/axp288_fuel_gauge.c @@ -1149,6 +1149,7 @@ static struct platform_driver axp288_fuel_gauge_driver = { module_platform_driver(axp288_fuel_gauge_driver); +MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>"); MODULE_AUTHOR("Todd Brandt <todd.e.brandt@linux.intel.com>"); MODULE_DESCRIPTION("Xpower AXP288 Fuel Gauge Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index a57433d..b6b9837 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -1109,6 +1109,14 @@ static void __exit bq27x00_battery_exit(void) } module_exit(bq27x00_battery_exit); +#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM +MODULE_ALIAS("platform:bq27000-battery"); +#endif + +#ifdef CONFIG_BATTERY_BQ27X00_I2C +MODULE_ALIAS("i2c:bq27000-battery"); +#endif + MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); MODULE_DESCRIPTION("BQ27x00 battery monitor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index 2da9ed8..8a971b3 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c @@ -347,7 +347,7 @@ static int collie_bat_probe(struct ucb1x00_dev *dev) goto err_psy_reg_main; } - psy_main_cfg.drv_data = &collie_bat_bu; + psy_bu_cfg.drv_data = &collie_bat_bu; collie_bat_bu.psy = power_supply_register(&dev->ucb->dev, &collie_bat_bu_desc, &psy_bu_cfg); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index aad9c33..17d93a7 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -41,6 +41,7 @@ config POWER_RESET_AXXIA config POWER_RESET_BRCMSTB bool "Broadcom STB reset driver" depends on ARM || MIPS || COMPILE_TEST + depends on MFD_SYSCON default ARCH_BRCMSTB help This driver provides restart support for Broadcom STB boards. diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 01c7055..ca461eb 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -212,9 +212,9 @@ static int at91_reset_platform_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 ); at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (IS_ERR(at91_ramc_base[idx])) { + if (!at91_ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); - return PTR_ERR(at91_ramc_base[idx]); + return -ENOMEM; } } diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 7ef193b..1e08195 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -120,18 +120,7 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer) static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data) { - if (hrtimer_start(&data->timer_wde, data->wde_interval, - HRTIMER_MODE_REL)) { - /* - * The device will not toggle the watchdog reset, - * thus shut down is only safe if the PowerPath controller - * has a long enough time-off before triggering a hardware - * power-off. - * - * Only sending a warning as the system will power-off anyway - */ - dev_err(data->dev, "unable to start the timer\n"); - } + hrtimer_start(&data->timer_wde, data->wde_interval, HRTIMER_MODE_REL); } static enum hrtimer_restart @@ -165,9 +154,8 @@ static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id) } if (gpiod_get_value(data->gpio_trigger)) { - if (hrtimer_start(&data->timer_trigger, data->trigger_delay, - HRTIMER_MODE_REL)) - dev_err(data->dev, "unable to start the wait timer\n"); + hrtimer_start(&data->timer_trigger, data->trigger_delay, + HRTIMER_MODE_REL); } else { hrtimer_cancel(&data->timer_trigger); /* omitting return value check, timer should have been valid */ diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6149ae0..0fe4ad8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -164,6 +164,16 @@ config RTC_DRV_ABB5ZES3 This driver can also be built as a module. If so, the module will be called rtc-ab-b5ze-s3. +config RTC_DRV_ABX80X + tristate "Abracon ABx80x" + help + If you say yes here you get support for Abracon AB080X and AB180X + families of ultra-low-power battery- and capacitor-backed real-time + clock chips. + + This driver can also be built as a module. If so, the module + will be called rtc-abx80x. + config RTC_DRV_AS3722 tristate "ams AS3722 RTC driver" depends on MFD_AS3722 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c31731c..2b82e2b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o +obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c new file mode 100644 index 0000000..4337c3b --- /dev/null +++ b/drivers/rtc/rtc-abx80x.c @@ -0,0 +1,307 @@ +/* + * A driver for the I2C members of the Abracon AB x8xx RTC family, + * and compatible: AB 1805 and AB 0805 + * + * Copyright 2014-2015 Macq S.A. + * + * Author: Philippe De Muyter <phdm@macqel.be> + * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/bcd.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/rtc.h> + +#define ABX8XX_REG_HTH 0x00 +#define ABX8XX_REG_SC 0x01 +#define ABX8XX_REG_MN 0x02 +#define ABX8XX_REG_HR 0x03 +#define ABX8XX_REG_DA 0x04 +#define ABX8XX_REG_MO 0x05 +#define ABX8XX_REG_YR 0x06 +#define ABX8XX_REG_WD 0x07 + +#define ABX8XX_REG_CTRL1 0x10 +#define ABX8XX_CTRL_WRITE BIT(1) +#define ABX8XX_CTRL_12_24 BIT(6) + +#define ABX8XX_REG_CFG_KEY 0x1f +#define ABX8XX_CFG_KEY_MISC 0x9d + +#define ABX8XX_REG_ID0 0x28 + +#define ABX8XX_REG_TRICKLE 0x20 +#define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0 +#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8 +#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4 + +static u8 trickle_resistors[] = {0, 3, 6, 11}; + +enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, + AB1801, AB1803, AB1804, AB1805, ABX80X}; + +struct abx80x_cap { + u16 pn; + bool has_tc; +}; + +static struct abx80x_cap abx80x_caps[] = { + [AB0801] = {.pn = 0x0801}, + [AB0803] = {.pn = 0x0803}, + [AB0804] = {.pn = 0x0804, .has_tc = true}, + [AB0805] = {.pn = 0x0805, .has_tc = true}, + [AB1801] = {.pn = 0x1801}, + [AB1803] = {.pn = 0x1803}, + [AB1804] = {.pn = 0x1804, .has_tc = true}, + [AB1805] = {.pn = 0x1805, .has_tc = true}, + [ABX80X] = {.pn = 0} +}; + +static struct i2c_driver abx80x_driver; + +static int abx80x_enable_trickle_charger(struct i2c_client *client, + u8 trickle_cfg) +{ + int err; + + /* + * Write the configuration key register to enable access to the Trickle + * register + */ + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, + ABX8XX_CFG_KEY_MISC); + if (err < 0) { + dev_err(&client->dev, "Unable to write configuration key\n"); + return -EIO; + } + + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_TRICKLE, + ABX8XX_TRICKLE_CHARGE_ENABLE | + trickle_cfg); + if (err < 0) { + dev_err(&client->dev, "Unable to write trickle register\n"); + return -EIO; + } + + return 0; +} + +static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char buf[8]; + int err; + + err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH, + sizeof(buf), buf); + if (err < 0) { + dev_err(&client->dev, "Unable to read date\n"); + return -EIO; + } + + tm->tm_sec = bcd2bin(buf[ABX8XX_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(buf[ABX8XX_REG_MN] & 0x7F); + tm->tm_hour = bcd2bin(buf[ABX8XX_REG_HR] & 0x3F); + tm->tm_wday = buf[ABX8XX_REG_WD] & 0x7; + tm->tm_mday = bcd2bin(buf[ABX8XX_REG_DA] & 0x3F); + tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F) - 1; + tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 100; + + err = rtc_valid_tm(tm); + if (err < 0) + dev_err(&client->dev, "retrieved date/time is not valid.\n"); + + return err; +} + +static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char buf[8]; + int err; + + if (tm->tm_year < 100) + return -EINVAL; + + buf[ABX8XX_REG_HTH] = 0; + buf[ABX8XX_REG_SC] = bin2bcd(tm->tm_sec); + buf[ABX8XX_REG_MN] = bin2bcd(tm->tm_min); + buf[ABX8XX_REG_HR] = bin2bcd(tm->tm_hour); + buf[ABX8XX_REG_DA] = bin2bcd(tm->tm_mday); + buf[ABX8XX_REG_MO] = bin2bcd(tm->tm_mon + 1); + buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 100); + buf[ABX8XX_REG_WD] = tm->tm_wday; + + err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_HTH, + sizeof(buf), buf); + if (err < 0) { + dev_err(&client->dev, "Unable to write to date registers\n"); + return -EIO; + } + + return 0; +} + +static const struct rtc_class_ops abx80x_rtc_ops = { + .read_time = abx80x_rtc_read_time, + .set_time = abx80x_rtc_set_time, +}; + +static int abx80x_dt_trickle_cfg(struct device_node *np) +{ + const char *diode; + int trickle_cfg = 0; + int i, ret; + u32 tmp; + + ret = of_property_read_string(np, "abracon,tc-diode", &diode); + if (ret) + return ret; + + if (!strcmp(diode, "standard")) + trickle_cfg |= ABX8XX_TRICKLE_STANDARD_DIODE; + else if (!strcmp(diode, "schottky")) + trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE; + else + return -EINVAL; + + ret = of_property_read_u32(np, "abracon,tc-resistor", &tmp); + if (ret) + return ret; + + for (i = 0; i < sizeof(trickle_resistors); i++) + if (trickle_resistors[i] == tmp) + break; + + if (i == sizeof(trickle_resistors)) + return -EINVAL; + + return (trickle_cfg | i); +} + +static int abx80x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *np = client->dev.of_node; + struct rtc_device *rtc; + int i, data, err, trickle_cfg = -EINVAL; + char buf[7]; + unsigned int part = id->driver_data; + unsigned int partnumber; + unsigned int majrev, minrev; + unsigned int lot; + unsigned int wafer; + unsigned int uid; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ID0, + sizeof(buf), buf); + if (err < 0) { + dev_err(&client->dev, "Unable to read partnumber\n"); + return -EIO; + } + + partnumber = (buf[0] << 8) | buf[1]; + majrev = buf[2] >> 3; + minrev = buf[2] & 0x7; + lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3]; + uid = ((buf[4] & 0x7f) << 8) | buf[5]; + wafer = (buf[6] & 0x7c) >> 2; + dev_info(&client->dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n", + partnumber, majrev, minrev, lot, wafer, uid); + + data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL1); + if (data < 0) { + dev_err(&client->dev, "Unable to read control register\n"); + return -EIO; + } + + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1, + ((data & ~ABX8XX_CTRL_12_24) | + ABX8XX_CTRL_WRITE)); + if (err < 0) { + dev_err(&client->dev, "Unable to write control register\n"); + return -EIO; + } + + /* part autodetection */ + if (part == ABX80X) { + for (i = 0; abx80x_caps[i].pn; i++) + if (partnumber == abx80x_caps[i].pn) + break; + if (abx80x_caps[i].pn == 0) { + dev_err(&client->dev, "Unknown part: %04x\n", + partnumber); + return -EINVAL; + } + part = i; + } + + if (partnumber != abx80x_caps[part].pn) { + dev_err(&client->dev, "partnumber mismatch %04x != %04x\n", + partnumber, abx80x_caps[part].pn); + return -EINVAL; + } + + if (np && abx80x_caps[part].has_tc) + trickle_cfg = abx80x_dt_trickle_cfg(np); + + if (trickle_cfg > 0) { + dev_info(&client->dev, "Enabling trickle charger: %02x\n", + trickle_cfg); + abx80x_enable_trickle_charger(client, trickle_cfg); + } + + rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name, + &abx80x_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + i2c_set_clientdata(client, rtc); + + return 0; +} + +static int abx80x_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id abx80x_id[] = { + { "abx80x", ABX80X }, + { "ab0801", AB0801 }, + { "ab0803", AB0803 }, + { "ab0804", AB0804 }, + { "ab0805", AB0805 }, + { "ab1801", AB1801 }, + { "ab1803", AB1803 }, + { "ab1804", AB1804 }, + { "ab1805", AB1805 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, abx80x_id); + +static struct i2c_driver abx80x_driver = { + .driver = { + .name = "rtc-abx80x", + }, + .probe = abx80x_probe, + .remove = abx80x_remove, + .id_table = abx80x_id, +}; + +module_i2c_driver(abx80x_driver); + +MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>"); +MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); +MODULE_DESCRIPTION("Abracon ABX80X RTC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 43e04af..4b62d1a 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -40,6 +40,13 @@ struct armada38x_rtc { void __iomem *regs; void __iomem *regs_soc; spinlock_t lock; + /* + * While setting the time, the RTC TIME register should not be + * accessed. Setting the RTC time involves sleeping during + * 100ms, so a mutex instead of a spinlock is used to protect + * it + */ + struct mutex mutex_time; int irq; }; @@ -57,10 +64,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset) static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); - unsigned long time, time_check, flags; - - spin_lock_irqsave(&rtc->lock, flags); + unsigned long time, time_check; + mutex_lock(&rtc->mutex_time); time = readl(rtc->regs + RTC_TIME); /* * WA for failing time set attempts. As stated in HW ERRATA if @@ -71,7 +77,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) if ((time_check - time) > 1) time_check = readl(rtc->regs + RTC_TIME); - spin_unlock_irqrestore(&rtc->lock, flags); + mutex_unlock(&rtc->mutex_time); rtc_time_to_tm(time_check, tm); @@ -94,19 +100,12 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) * then wait for 100ms before writing to the time register to be * sure that the data will be taken into account. */ - spin_lock_irqsave(&rtc->lock, flags); - + mutex_lock(&rtc->mutex_time); rtc_delayed_write(0, rtc, RTC_STATUS); - - spin_unlock_irqrestore(&rtc->lock, flags); - msleep(100); - - spin_lock_irqsave(&rtc->lock, flags); - rtc_delayed_write(time, rtc, RTC_TIME); + mutex_unlock(&rtc->mutex_time); - spin_unlock_irqrestore(&rtc->lock, flags); out: return ret; } @@ -230,6 +229,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&rtc->lock); + mutex_init(&rtc->mutex_time); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); rtc->regs = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 198f96b..72b0590 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -78,6 +78,7 @@ config SPI_ATMEL config SPI_BCM2835 tristate "BCM2835 SPI controller" depends on ARCH_BCM2835 || COMPILE_TEST + depends on GPIOLIB help This selects a driver for the Broadcom BCM2835 SPI master. @@ -302,7 +303,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on SOC_VF610 || COMPILE_TEST + depends on SOC_VF610 || SOC_LS1021A || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index f63864a..37875cf 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, unsigned long xfer_time_us) { struct bcm2835_spi *bs = spi_master_get_devdata(master); - unsigned long timeout = jiffies + - max(4 * xfer_time_us * HZ / 1000000, 2uL); + /* set timeout to 1 second of maximum polling */ + unsigned long timeout = jiffies + HZ; /* enable HW block without interrupts */ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); - /* set timeout to 4x the expected time, or 2 jiffies */ /* loop until finished the transfer */ while (bs->rx_len) { /* read from fifo as much as possible */ diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 5ef6638..840a498 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi) { struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; - int retval; unsigned long flags; bitbang = spi_master_get_devdata(spi->master); @@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi) if (!cs->txrx_word) return -EINVAL; - retval = bitbang->setup_transfer(spi, NULL); - if (retval < 0) - return retval; + if (bitbang->setup_transfer) { + int retval = bitbang->setup_transfer(spi, NULL); + if (retval < 0) + return retval; + } dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); @@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master, /* init (-1) or override (1) transfer params */ if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; + if (bitbang->setup_transfer) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) + break; + } if (do_setup == -1) do_setup = 0; } diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 9c46a30..896add8 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -24,6 +24,7 @@ #include <linux/of_address.h> #include <linux/spi/spi.h> #include <linux/types.h> +#include <linux/platform_device.h> #include "spi-fsl-cpm.h" #include "spi-fsl-lib.h" @@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) if (mspi->flags & SPI_CPM2) { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); out_be16(spi_base, pram_ofs); - } else { - struct spi_pram __iomem *pram = spi_base; - u16 rpbase = in_be16(&pram->rpbase); - - /* Microcode relocation patch applied? */ - if (rpbase) { - pram_ofs = rpbase; - } else { - pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); - out_be16(spi_base, pram_ofs); - } } iounmap(spi_base); @@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) struct device_node *np = dev->of_node; const u32 *iprop; int size; - unsigned long pram_ofs; unsigned long bds_ofs; if (!(mspi->flags & SPI_CPM_MODE)) @@ -319,8 +308,26 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) } } - pram_ofs = fsl_spi_cpm_get_pram(mspi); - if (IS_ERR_VALUE(pram_ofs)) { + if (mspi->flags & SPI_CPM1) { + struct resource *res; + void *pram; + + res = platform_get_resource(to_platform_device(dev), + IORESOURCE_MEM, 1); + pram = devm_ioremap_resource(dev, res); + if (IS_ERR(pram)) + mspi->pram = NULL; + else + mspi->pram = pram; + } else { + unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi); + + if (IS_ERR_VALUE(pram_ofs)) + mspi->pram = NULL; + else + mspi->pram = cpm_muram_addr(pram_ofs); + } + if (mspi->pram == NULL) { dev_err(dev, "can't allocate spi parameter ram\n"); goto err_pram; } @@ -346,8 +353,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) goto err_dummy_rx; } - mspi->pram = cpm_muram_addr(pram_ofs); - mspi->tx_bd = cpm_muram_addr(bds_ofs); mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); @@ -375,7 +380,8 @@ err_dummy_rx: err_dummy_tx: cpm_muram_free(bds_ofs); err_bds: - cpm_muram_free(pram_ofs); + if (!(mspi->flags & SPI_CPM1)) + cpm_muram_free(cpm_muram_offset(mspi->pram)); err_pram: fsl_spi_free_dummy_rx(); return -ENOMEM; diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d0a73a0..80d245a 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -359,14 +359,16 @@ static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { struct fsl_espi_transfer *espi_trans = trans; - unsigned int n_tx = espi_trans->n_tx; - unsigned int n_rx = espi_trans->n_rx; + unsigned int total_len = espi_trans->len; struct spi_transfer *t; u8 *local_buf; u8 *rx_buf = rx_buff; unsigned int trans_len; unsigned int addr; - int i, pos, loop; + unsigned int tx_only; + unsigned int rx_pos = 0; + unsigned int pos; + int i, loop; local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); if (!local_buf) { @@ -374,36 +376,48 @@ static void fsl_espi_rw_trans(struct spi_message *m, return; } - for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) { - trans_len = n_rx - pos; - if (trans_len > SPCOM_TRANLEN_MAX - n_tx) - trans_len = SPCOM_TRANLEN_MAX - n_tx; + for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) { + trans_len = total_len - pos; i = 0; + tx_only = 0; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) { memcpy(local_buf + i, t->tx_buf, t->len); i += t->len; + if (!t->rx_buf) + tx_only += t->len; } } + /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */ + if (loop > 0) + trans_len += tx_only; + + if (trans_len > SPCOM_TRANLEN_MAX) + trans_len = SPCOM_TRANLEN_MAX; + + /* Update device offset */ if (pos > 0) { addr = fsl_espi_cmd2addr(local_buf); - addr += pos; + addr += rx_pos; fsl_espi_addr2cmd(addr, local_buf); } - espi_trans->n_tx = n_tx; - espi_trans->n_rx = trans_len; - espi_trans->len = trans_len + n_tx; + espi_trans->len = trans_len; espi_trans->tx_buf = local_buf; espi_trans->rx_buf = local_buf; fsl_espi_do_trans(m, espi_trans); - memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); + /* If there is at least one RX byte then copy it to rx_buf */ + if (tx_only < SPCOM_TRANLEN_MAX) + memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only, + trans_len - tx_only); + + rx_pos += trans_len - tx_only; if (loop > 0) - espi_trans->actual_length += espi_trans->len - n_tx; + espi_trans->actual_length += espi_trans->len - tx_only; else espi_trans->actual_length += espi_trans->len; } @@ -418,6 +432,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, u8 *rx_buf = NULL; unsigned int n_tx = 0; unsigned int n_rx = 0; + unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; list_for_each_entry(t, &m->transfers, transfer_list) { @@ -427,11 +442,13 @@ static int fsl_espi_do_one_msg(struct spi_master *master, n_rx += t->len; rx_buf = t->rx_buf; } + if ((t->tx_buf) || (t->rx_buf)) + xfer_len += t->len; } espi_trans.n_tx = n_tx; espi_trans.n_rx = n_rx; - espi_trans.len = n_tx + n_rx; + espi_trans.len = xfer_len; espi_trans.actual_length = 0; espi_trans.status = 0; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 4df89420..d1a5b9f 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1210,6 +1210,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; struct spi_transfer *t; + int status; spi = m->spi; mcspi = spi_master_get_devdata(master); @@ -1229,7 +1230,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, tx_buf ? "tx" : "", rx_buf ? "rx" : "", t->bits_per_word); - return -EINVAL; + status = -EINVAL; + goto out; } if (m->is_dma_mapped || len < DMA_MIN_BYTES) @@ -1241,7 +1243,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, if (dma_mapping_error(mcspi->dev, t->tx_dma)) { dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 'T', len); - return -EINVAL; + status = -EINVAL; + goto out; } } if (mcspi_dma->dma_rx && rx_buf != NULL) { @@ -1253,14 +1256,19 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, if (tx_buf != NULL) dma_unmap_single(mcspi->dev, t->tx_dma, len, DMA_TO_DEVICE); - return -EINVAL; + status = -EINVAL; + goto out; } } } omap2_mcspi_work(mcspi, m); + /* spi_finalize_current_message() changes the status inside the + * spi_message, save the status here. */ + status = m->status; +out: spi_finalize_current_message(master); - return 0; + return status; } static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d5d7d22..50910d8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -583,6 +583,15 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) rx_dev = master->dma_rx->device->dev; list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* + * Restore the original value of tx_buf or rx_buf if they are + * NULL. + */ + if (xfer->tx_buf == master->dummy_tx) + xfer->tx_buf = NULL; + if (xfer->rx_buf == master->dummy_rx) + xfer->rx_buf = NULL; + if (!master->can_dma(master, msg->spi, xfer)) continue; diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c index 8199b0a..1cf24e4 100644 --- a/drivers/staging/gdm724x/gdm_mux.c +++ b/drivers/staging/gdm724x/gdm_mux.c @@ -158,7 +158,7 @@ static int up_to_host(struct mux_rx *r) unsigned int start_flag; unsigned int payload_size; unsigned short packet_type; - int dummy_cnt; + int total_len; u32 packet_size_sum = r->offset; int index; int ret = TO_HOST_INVALID_PACKET; @@ -176,10 +176,10 @@ static int up_to_host(struct mux_rx *r) break; } - dummy_cnt = ALIGN(MUX_HEADER_SIZE + payload_size, 4); + total_len = ALIGN(MUX_HEADER_SIZE + payload_size, 4); if (len - packet_size_sum < - MUX_HEADER_SIZE + payload_size + dummy_cnt) { + total_len) { pr_err("invalid payload : %d %d %04x\n", payload_size, len, packet_type); break; @@ -202,7 +202,7 @@ static int up_to_host(struct mux_rx *r) break; } - packet_size_sum += MUX_HEADER_SIZE + payload_size + dummy_cnt; + packet_size_sum += total_len; if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) { ret = r->callback(NULL, 0, @@ -361,7 +361,6 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, struct mux_pkt_header *mux_header; struct mux_tx *t = NULL; static u32 seq_num = 1; - int dummy_cnt; int total_len; int ret; unsigned long flags; @@ -374,9 +373,7 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, spin_lock_irqsave(&mux_dev->write_lock, flags); - dummy_cnt = ALIGN(MUX_HEADER_SIZE + len, 4); - - total_len = len + MUX_HEADER_SIZE + dummy_cnt; + total_len = ALIGN(MUX_HEADER_SIZE + len, 4); t = alloc_mux_tx(total_len); if (!t) { @@ -392,7 +389,8 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, mux_header->packet_type = __cpu_to_le16(packet_type[tty_index]); memcpy(t->buf+MUX_HEADER_SIZE, data, len); - memset(t->buf+MUX_HEADER_SIZE+len, 0, dummy_cnt); + memset(t->buf+MUX_HEADER_SIZE+len, 0, total_len - MUX_HEADER_SIZE - + len); t->len = total_len; t->callback = cb; diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index b78643f..072dac0 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -2,6 +2,7 @@ config VIDEO_OMAP4 bool "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 depends on HAS_DMA + select MFD_SYSCON select VIDEOBUF2_DMA_CONTIG ---help--- Driver for an OMAP 4 ISS controller. diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index e0ad5e5..7ced940 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -17,6 +17,7 @@ #include <linux/dma-mapping.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -1386,6 +1387,16 @@ static int iss_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iss); + /* + * TODO: When implementing DT support switch to syscon regmap lookup by + * phandle. + */ + iss->syscon = syscon_regmap_lookup_by_compatible("syscon"); + if (IS_ERR(iss->syscon)) { + ret = PTR_ERR(iss->syscon); + goto error; + } + /* Clocks */ ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP); if (ret < 0) diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h index 734cfee..35df8b4 100644 --- a/drivers/staging/media/omap4iss/iss.h +++ b/drivers/staging/media/omap4iss/iss.h @@ -29,6 +29,8 @@ #include "iss_ipipe.h" #include "iss_resizer.h" +struct regmap; + #define to_iss_device(ptr_module) \ container_of(ptr_module, struct iss_device, ptr_module) #define to_device(ptr_module) \ @@ -79,6 +81,7 @@ struct iss_reg { /* * struct iss_device - ISS device structure. + * @syscon: Regmap for the syscon register space * @crashed: Bitmask of crashed entities (indexed by entity ID) */ struct iss_device { @@ -93,6 +96,7 @@ struct iss_device { struct resource *res[OMAP4_ISS_MEM_LAST]; void __iomem *regs[OMAP4_ISS_MEM_LAST]; + struct regmap *syscon; u64 raw_dmamask; diff --git a/drivers/staging/media/omap4iss/iss_csiphy.c b/drivers/staging/media/omap4iss/iss_csiphy.c index 7c3d55d..748607f 100644 --- a/drivers/staging/media/omap4iss/iss_csiphy.c +++ b/drivers/staging/media/omap4iss/iss_csiphy.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/regmap.h> #include "../../../../arch/arm/mach-omap2/control.h" @@ -140,9 +141,11 @@ int omap4iss_csiphy_config(struct iss_device *iss, * - bit [18] : CSIPHY1 CTRLCLK enable * - bit [17:16] : CSIPHY1 config: 00 d-phy, 01/10 ccp2 */ - cam_rx_ctrl = omap4_ctrl_pad_readl( - OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX); - + /* + * TODO: When implementing DT support specify the CONTROL_CAMERA_RX + * register offset in the syscon property instead of hardcoding it. + */ + regmap_read(iss->syscon, 0x68, &cam_rx_ctrl); if (subdevs->interface == ISS_INTERFACE_CSI2A_PHY1) { cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI21_LANEENABLE_MASK | @@ -166,8 +169,7 @@ int omap4iss_csiphy_config(struct iss_device *iss, cam_rx_ctrl |= OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK; } - omap4_ctrl_pad_writel(cam_rx_ctrl, - OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX); + regmap_write(iss->syscon, 0x68, cam_rx_ctrl); /* Reset used lane count */ csi2->phy->used_data_lanes = 0; diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 42fba3f..cb0b63877 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -1900,23 +1900,20 @@ static int r871x_mp_ioctl_hdl(struct net_device *dev, struct mp_ioctl_handler *phandler; struct mp_ioctl_param *poidparam; unsigned long BytesRead, BytesWritten, BytesNeeded; - u8 *pparmbuf = NULL, bset; + u8 *pparmbuf, bset; u16 len; uint status; int ret = 0; - if ((!p->length) || (!p->pointer)) { - ret = -EINVAL; - goto _r871x_mp_ioctl_hdl_exit; - } + if ((!p->length) || (!p->pointer)) + return -EINVAL; + bset = (u8)(p->flags & 0xFFFF); len = p->length; - pparmbuf = NULL; pparmbuf = memdup_user(p->pointer, len); - if (IS_ERR(pparmbuf)) { - ret = PTR_ERR(pparmbuf); - goto _r871x_mp_ioctl_hdl_exit; - } + if (IS_ERR(pparmbuf)) + return PTR_ERR(pparmbuf); + poidparam = (struct mp_ioctl_param *)pparmbuf; if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { ret = -EINVAL; diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 3c7ea95..dbbb2f8 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -1250,7 +1250,7 @@ err_enable: return -ENODEV; } -static void __exit lynxfb_pci_remove(struct pci_dev *pdev) +static void lynxfb_pci_remove(struct pci_dev *pdev) { struct fb_info *info; struct lynx_share *share; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 1cdcf49..e00c060 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -362,12 +362,16 @@ bool CARDbSetPhyParameter(struct vnt_private *pDevice, u8 bb_type) * Return Value: none */ bool CARDbUpdateTSF(struct vnt_private *pDevice, unsigned char byRxRate, - u64 qwBSSTimestamp, u64 qwLocalTSF) + u64 qwBSSTimestamp) { + u64 local_tsf; u64 qwTSFOffset = 0; - if (qwBSSTimestamp != qwLocalTSF) { - qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF); + CARDbGetCurrentTSF(pDevice, &local_tsf); + + if (qwBSSTimestamp != local_tsf) { + qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, + local_tsf); /* adjust TSF, HW's TSF add TSF Offset reg */ VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST, (u32)qwTSFOffset); VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, (u32)(qwTSFOffset >> 32)); diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h index 2dfc419..16cca49 100644 --- a/drivers/staging/vt6655/card.h +++ b/drivers/staging/vt6655/card.h @@ -83,7 +83,7 @@ bool CARDbRadioPowerOff(struct vnt_private *); bool CARDbRadioPowerOn(struct vnt_private *); bool CARDbSetPhyParameter(struct vnt_private *, u8); bool CARDbUpdateTSF(struct vnt_private *, unsigned char byRxRate, - u64 qwBSSTimestamp, u64 qwLocalTSF); + u64 qwBSSTimestamp); bool CARDbSetBeaconPeriod(struct vnt_private *, unsigned short wBeaconInterval); #endif /* __CARD_H__ */ diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 4bb4f8e..0343ae3 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -912,7 +912,11 @@ static int vnt_int_report_rate(struct vnt_private *priv, if (!(tsr1 & TSR1_TERR)) { info->status.rates[0].idx = idx; - info->flags |= IEEE80211_TX_STAT_ACK; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags |= IEEE80211_TX_STAT_ACK; } return 0; @@ -937,9 +941,6 @@ static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx) /* Only the status of first TD in the chain is correct */ if (pTD->m_td1TD1.byTCR & TCR_STP) { if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) { - - vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1); - if (!(byTsr1 & TSR1_TERR)) { if (byTsr0 != 0) { pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n", @@ -958,6 +959,9 @@ static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx) (int)uIdx, byTsr1, byTsr0); } } + + vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1); + device_free_tx_buf(pDevice, pTD); pDevice->iTDUsed[uIdx]--; } @@ -989,10 +993,8 @@ static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc) skb->len, DMA_TO_DEVICE); } - if (pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) + if (skb) ieee80211_tx_status_irqsafe(pDevice->hw, skb); - else - dev_kfree_skb_irq(skb); pTDInfo->skb_dma = 0; pTDInfo->skb = NULL; @@ -1204,14 +1206,6 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) if (dma_idx == TYPE_AC0DMA) head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB; - priv->iTDUsed[dma_idx]++; - - /* Take ownership */ - wmb(); - head_td->m_td0TD0.f1Owner = OWNED_BY_NIC; - - /* get Next */ - wmb(); priv->apCurrTD[dma_idx] = head_td->next; spin_unlock_irqrestore(&priv->lock, flags); @@ -1232,11 +1226,18 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma); + /* Poll Transmit the adapter */ + wmb(); + head_td->m_td0TD0.f1Owner = OWNED_BY_NIC; + wmb(); /* second memory barrier */ + if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) MACvTransmitAC0(priv->PortOffset); else MACvTransmit0(priv->PortOffset); + priv->iTDUsed[dma_idx]++; + spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -1416,9 +1417,16 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, priv->current_aid = conf->aid; - if (changed & BSS_CHANGED_BSSID) + if (changed & BSS_CHANGED_BSSID) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + MACvWriteBSSIDAddress(priv->PortOffset, (u8 *)conf->bssid); + spin_unlock_irqrestore(&priv->lock, flags); + } + if (changed & BSS_CHANGED_BASIC_RATES) { priv->basic_rates = conf->basic_rates; @@ -1477,7 +1485,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) { if (conf->assoc) { CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, - conf->sync_device_ts, conf->sync_tsf); + conf->sync_tsf); CARDbSetBeaconPeriod(priv, conf->beacon_int); diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index f6c2cf8..5c58996 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -805,10 +805,18 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) vnt_schedule_command(priv, WLAN_CMD_SETPOWER); } - if (current_rate > RATE_11M) - pkt_type = priv->packet_type; - else + if (current_rate > RATE_11M) { + if (info->band == IEEE80211_BAND_5GHZ) { + pkt_type = PK_TYPE_11A; + } else { + if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + pkt_type = PK_TYPE_11GB; + else + pkt_type = PK_TYPE_11GA; + } + } else { pkt_type = PK_TYPE_11B; + } spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 12623bc..725718e 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -206,51 +206,57 @@ static void find_target_mwait(void) } +struct pkg_cstate_info { + bool skip; + int msr_index; + int cstate_id; +}; + +#define PKG_CSTATE_INIT(id) { \ + .msr_index = MSR_PKG_C##id##_RESIDENCY, \ + .cstate_id = id \ + } + +static struct pkg_cstate_info pkg_cstates[] = { + PKG_CSTATE_INIT(2), + PKG_CSTATE_INIT(3), + PKG_CSTATE_INIT(6), + PKG_CSTATE_INIT(7), + PKG_CSTATE_INIT(8), + PKG_CSTATE_INIT(9), + PKG_CSTATE_INIT(10), + {NULL}, +}; + static bool has_pkg_state_counter(void) { - u64 tmp; - return !rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &tmp) || - !rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &tmp) || - !rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &tmp) || - !rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &tmp); + u64 val; + struct pkg_cstate_info *info = pkg_cstates; + + /* check if any one of the counter msrs exists */ + while (info->msr_index) { + if (!rdmsrl_safe(info->msr_index, &val)) + return true; + info++; + } + + return false; } static u64 pkg_state_counter(void) { u64 val; u64 count = 0; - - static bool skip_c2; - static bool skip_c3; - static bool skip_c6; - static bool skip_c7; - - if (!skip_c2) { - if (!rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &val)) - count += val; - else - skip_c2 = true; - } - - if (!skip_c3) { - if (!rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &val)) - count += val; - else - skip_c3 = true; - } - - if (!skip_c6) { - if (!rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &val)) - count += val; - else - skip_c6 = true; - } - - if (!skip_c7) { - if (!rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &val)) - count += val; - else - skip_c7 = true; + struct pkg_cstate_info *info = pkg_cstates; + + while (info->msr_index) { + if (!info->skip) { + if (!rdmsrl_safe(info->msr_index, &val)) + count += val; + else + info->skip = true; + } + info++; } return count; @@ -667,7 +673,7 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = { }; /* runs on Nehalem and later */ -static const struct x86_cpu_id intel_powerclamp_ids[] = { +static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { { X86_VENDOR_INTEL, 6, 0x1a}, { X86_VENDOR_INTEL, 6, 0x1c}, { X86_VENDOR_INTEL, 6, 0x1e}, @@ -689,12 +695,13 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = { { X86_VENDOR_INTEL, 6, 0x46}, { X86_VENDOR_INTEL, 6, 0x4c}, { X86_VENDOR_INTEL, 6, 0x4d}, + { X86_VENDOR_INTEL, 6, 0x4f}, { X86_VENDOR_INTEL, 6, 0x56}, {} }; MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); -static int powerclamp_probe(void) +static int __init powerclamp_probe(void) { if (!x86_match_cpu(intel_powerclamp_ids)) { pr_err("Intel powerclamp does not run on family %d model %d\n", @@ -760,7 +767,7 @@ file_error: debugfs_remove_recursive(debug_dir); } -static int powerclamp_init(void) +static int __init powerclamp_init(void) { int retval; int bitmap_size; @@ -809,7 +816,7 @@ exit_free: } module_init(powerclamp_init); -static void powerclamp_exit(void) +static void __exit powerclamp_exit(void) { unregister_hotcpu_notifier(&powerclamp_cpu_notifier); end_power_clamp(); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 3aa46ac..cd8f5f93 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -529,7 +529,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(thermal->pclk)) { - error = PTR_ERR(thermal->clk); + error = PTR_ERR(thermal->pclk); dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n", error); return error; diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 0531c75..8e39181 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -103,7 +103,7 @@ static inline int of_thermal_get_ntrips(struct thermal_zone_device *tz) static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip) { - return 0; + return false; } static inline const struct thermal_trip * of_thermal_get_trip_points(struct thermal_zone_device *tz) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index f1e5742..5bab1c6 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -299,11 +299,27 @@ static int xen_initial_domain_console_init(void) return 0; } +static void xen_console_update_evtchn(struct xencons_info *info) +{ + if (xen_hvm_domain()) { + uint64_t v; + int err; + + err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + if (!err && v) + info->evtchn = v; + } else + info->evtchn = xen_start_info->console.domU.evtchn; +} + void xen_console_resume(void) { struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); - if (info != NULL && info->irq) + if (info != NULL && info->irq) { + if (!xen_initial_domain()) + xen_console_update_evtchn(info); rebind_evtchn_irq(info->evtchn, info->irq); + } } static void xencons_disconnect_backend(struct xencons_info *info) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 91abc00..2c34c32 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3170,7 +3170,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) return gsmtty_modem_update(dlci, encode); } -static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) +static void gsmtty_cleanup(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; struct gsm_mux *gsm = dlci->gsm; @@ -3178,7 +3178,6 @@ static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) dlci_put(dlci); dlci_put(gsm->dlci[0]); mux_put(gsm); - driver->ttys[tty->index] = NULL; } /* Virtual ttys for the demux */ @@ -3199,7 +3198,7 @@ static const struct tty_operations gsmtty_ops = { .tiocmget = gsmtty_tiocmget, .tiocmset = gsmtty_tiocmset, .break_ctl = gsmtty_break_ctl, - .remove = gsmtty_remove, + .cleanup = gsmtty_cleanup, }; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 644ddb8..bbc4ce6 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -600,7 +600,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->read_wait, &wait); for (;;) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (test_bit(TTY_OTHER_DONE, &tty->flags)) { ret = -EIO; break; } @@ -828,7 +828,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, /* set bits for operations that won't block */ if (n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + if (test_bit(TTY_OTHER_DONE, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(filp)) mask |= POLLHUP; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cf6e0f2..cc57a3a 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1949,6 +1949,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll) return ldata->commit_head - ldata->read_tail >= amt; } +static inline int check_other_done(struct tty_struct *tty) +{ + int done = test_bit(TTY_OTHER_DONE, &tty->flags); + if (done) { + /* paired with cmpxchg() in check_other_closed(); ensures + * read buffer head index is not stale + */ + smp_mb__after_atomic(); + } + return done; +} + /** * copy_from_read_buf - copy read data directly * @tty: terminal device @@ -2167,7 +2179,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c; + int c, done; int minimum, time; ssize_t retval = 0; long timeout; @@ -2235,8 +2247,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ((minimum - (b - buf)) >= 1)) ldata->minimum_to_wake = (minimum - (b - buf)); + done = check_other_done(tty); + if (!input_available_p(tty, 0)) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (done) { retval = -EIO; break; } @@ -2443,12 +2457,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + if (check_other_done(tty)) + mask |= POLLHUP; if (input_available_p(tty, 1)) mask |= POLLIN | POLLRDNORM; if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index e72ee62..4d5e840 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -53,9 +53,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp) /* Review - krefs on tty_link ?? */ if (!tty->link) return; - tty_flush_to_ldisc(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); - wake_up_interruptible(&tty->link->read_wait); + tty_flip_buffer_push(tty->link->port); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); @@ -243,7 +242,9 @@ static int pty_open(struct tty_struct *tty, struct file *filp) goto out; clear_bit(TTY_IO_ERROR, &tty->flags); + /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); + clear_bit(TTY_OTHER_DONE, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); return 0; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 5a4e9d5..6f5a072 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1639,6 +1639,9 @@ static int pl011_startup(struct uart_port *port) writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + /* Assume that TX IRQ doesn't work until we see one: */ + uap->tx_irq_seen = 0; + spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ @@ -1702,7 +1705,7 @@ static void pl011_shutdown(struct uart_port *port) spin_lock_irq(&uap->port.lock); uap->im = 0; writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR); + writew(0xffff, uap->port.membase + UART011_ICR); spin_unlock_irq(&uap->port.lock); pl011_dma_shutdown(uap); diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 5fdc9f3..6dc471e 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -187,13 +187,8 @@ static int __init param_setup_earlycon(char *buf) return 0; err = setup_earlycon(buf); - if (err == -ENOENT) { - pr_warn("no match for %s\n", buf); - err = 0; - } else if (err == -EALREADY) { - pr_warn("already registered\n"); - err = 0; - } + if (err == -ENOENT || err == -EALREADY) + return 0; return err; } early_param("earlycon", param_setup_earlycon); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 211479a..7f49172 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1735,6 +1735,8 @@ static int serial_omap_probe(struct platform_device *pdev) err_add_port: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_qos_remove_request(&up->pm_qos_request); + device_init_wakeup(up->dev, false); err_rs485: err_port_line: return ret; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 7566164..2f78b77 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -37,6 +37,28 @@ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) +/* + * If all tty flip buffers have been processed by flush_to_ldisc() or + * dropped by tty_buffer_flush(), check if the linked pty has been closed. + * If so, wake the reader/poll to process + */ +static inline void check_other_closed(struct tty_struct *tty) +{ + unsigned long flags, old; + + /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */ + for (flags = ACCESS_ONCE(tty->flags); + test_bit(TTY_OTHER_CLOSED, &flags); + ) { + old = flags; + __set_bit(TTY_OTHER_DONE, &flags); + flags = cmpxchg(&tty->flags, old, flags); + if (old == flags) { + wake_up_interruptible(&tty->read_wait); + break; + } + } +} /** * tty_buffer_lock_exclusive - gain exclusive access to buffer @@ -229,6 +251,8 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); + check_other_closed(tty); + atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } @@ -471,8 +495,10 @@ static void flush_to_ldisc(struct work_struct *work) smp_rmb(); count = head->commit - head->read; if (!count) { - if (next == NULL) + if (next == NULL) { + check_other_closed(tty); break; + } buf->head = next; tty_buffer_free(port, head); continue; @@ -489,19 +515,6 @@ static void flush_to_ldisc(struct work_struct *work) } /** - * tty_flush_to_ldisc - * @tty: tty to push - * - * Push the terminal flip buffers to the line discipline. - * - * Must not be called from IRQ context. - */ -void tty_flush_to_ldisc(struct tty_struct *tty) -{ - flush_work(&tty->port->buf.work); -} - -/** * tty_flip_buffer_push - terminal * @port: tty port to push * diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index dfb05ed..5b7061a 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -88,9 +88,13 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, char buf[32]; int ret; - if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + count = min_t(size_t, sizeof(buf) - 1, count); + if (copy_from_user(buf, ubuf, count)) return -EFAULT; + /* sscanf requires a zero terminated string */ + buf[count] = '\0'; + if (sscanf(buf, "%u", &mode) != 1) return -EINVAL; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 41e510a..d85abfe 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -106,6 +106,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04f3, 0x010c), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, + { USB_DEVICE(0x04f3, 0x0125), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + { USB_DEVICE(0x04f3, 0x016f), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index edba534..6b486a3 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -65,8 +65,8 @@ #define USBOTGSS_IRQENABLE_SET_MISC 0x003c #define USBOTGSS_IRQENABLE_CLR_MISC 0x0040 #define USBOTGSS_IRQMISC_OFFSET 0x03fc -#define USBOTGSS_UTMI_OTG_CTRL 0x0080 -#define USBOTGSS_UTMI_OTG_STATUS 0x0084 +#define USBOTGSS_UTMI_OTG_STATUS 0x0080 +#define USBOTGSS_UTMI_OTG_CTRL 0x0084 #define USBOTGSS_UTMI_OTG_OFFSET 0x0480 #define USBOTGSS_TXFIFO_DEPTH 0x0508 #define USBOTGSS_RXFIFO_DEPTH 0x050c @@ -98,20 +98,20 @@ #define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3) #define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0) -/* UTMI_OTG_CTRL REGISTER */ -#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5) -#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4) -#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3) -#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0) - /* UTMI_OTG_STATUS REGISTER */ -#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31) -#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9) -#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8) -#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4) -#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3) -#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2) -#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1) +#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS (1 << 5) +#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS (1 << 4) +#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS (1 << 3) +#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP (1 << 0) + +/* UTMI_OTG_CTRL REGISTER */ +#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE (1 << 31) +#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT (1 << 9) +#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8) +#define USBOTGSS_UTMI_OTG_CTRL_IDDIG (1 << 4) +#define USBOTGSS_UTMI_OTG_CTRL_SESSEND (1 << 3) +#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID (1 << 2) +#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID (1 << 1) struct dwc3_omap { struct device *dev; @@ -119,7 +119,7 @@ struct dwc3_omap { int irq; void __iomem *base; - u32 utmi_otg_status; + u32 utmi_otg_ctrl; u32 utmi_otg_offset; u32 irqmisc_offset; u32 irq_eoi_offset; @@ -153,15 +153,15 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value) writel(value, base + offset); } -static u32 dwc3_omap_read_utmi_status(struct dwc3_omap *omap) +static u32 dwc3_omap_read_utmi_ctrl(struct dwc3_omap *omap) { - return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS + + return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL + omap->utmi_otg_offset); } -static void dwc3_omap_write_utmi_status(struct dwc3_omap *omap, u32 value) +static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value) { - dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS + + dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL + omap->utmi_otg_offset, value); } @@ -235,25 +235,25 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, } } - val = dwc3_omap_read_utmi_status(omap); - val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG - | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID - | USBOTGSS_UTMI_OTG_STATUS_SESSEND); - val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID - | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT; - dwc3_omap_write_utmi_status(omap, val); + val = dwc3_omap_read_utmi_ctrl(omap); + val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG + | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID + | USBOTGSS_UTMI_OTG_CTRL_SESSEND); + val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID + | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT; + dwc3_omap_write_utmi_ctrl(omap, val); break; case OMAP_DWC3_VBUS_VALID: dev_dbg(omap->dev, "VBUS Connect\n"); - val = dwc3_omap_read_utmi_status(omap); - val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND; - val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG - | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID - | USBOTGSS_UTMI_OTG_STATUS_SESSVALID - | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT; - dwc3_omap_write_utmi_status(omap, val); + val = dwc3_omap_read_utmi_ctrl(omap); + val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND; + val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG + | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID + | USBOTGSS_UTMI_OTG_CTRL_SESSVALID + | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT; + dwc3_omap_write_utmi_ctrl(omap, val); break; case OMAP_DWC3_ID_FLOAT: @@ -263,13 +263,13 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, case OMAP_DWC3_VBUS_OFF: dev_dbg(omap->dev, "VBUS Disconnect\n"); - val = dwc3_omap_read_utmi_status(omap); - val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID - | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID - | USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT); - val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND - | USBOTGSS_UTMI_OTG_STATUS_IDDIG; - dwc3_omap_write_utmi_status(omap, val); + val = dwc3_omap_read_utmi_ctrl(omap); + val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID + | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID + | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT); + val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND + | USBOTGSS_UTMI_OTG_CTRL_IDDIG; + dwc3_omap_write_utmi_ctrl(omap, val); break; default: @@ -422,22 +422,22 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap) struct device_node *node = omap->dev->of_node; int utmi_mode = 0; - reg = dwc3_omap_read_utmi_status(omap); + reg = dwc3_omap_read_utmi_ctrl(omap); of_property_read_u32(node, "utmi-mode", &utmi_mode); switch (utmi_mode) { case DWC3_OMAP_UTMI_MODE_SW: - reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + reg |= USBOTGSS_UTMI_OTG_CTRL_SW_MODE; break; case DWC3_OMAP_UTMI_MODE_HW: - reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE; break; default: dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); } - dwc3_omap_write_utmi_status(omap, reg); + dwc3_omap_write_utmi_ctrl(omap, reg); } static int dwc3_omap_extcon_register(struct dwc3_omap *omap) @@ -614,7 +614,7 @@ static int dwc3_omap_suspend(struct device *dev) { struct dwc3_omap *omap = dev_get_drvdata(dev); - omap->utmi_otg_status = dwc3_omap_read_utmi_status(omap); + omap->utmi_otg_ctrl = dwc3_omap_read_utmi_ctrl(omap); dwc3_omap_disable_irqs(omap); return 0; @@ -624,7 +624,7 @@ static int dwc3_omap_resume(struct device *dev) { struct dwc3_omap *omap = dev_get_drvdata(dev); - dwc3_omap_write_utmi_status(omap, omap->utmi_otg_status); + dwc3_omap_write_utmi_ctrl(omap, omap->utmi_otg_ctrl); dwc3_omap_enable_irqs(omap); pm_runtime_disable(dev); diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index c42765b..0495c94 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1295,6 +1295,7 @@ static void purge_configs_funcs(struct gadget_info *gi) } } c->next_interface_id = 0; + memset(c->interface, 0, sizeof(c->interface)); c->superspeed = 0; c->highspeed = 0; c->fullspeed = 0; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 13dfc99..f7f35a3 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -437,12 +437,20 @@ static int hidg_setup(struct usb_function *f, | USB_REQ_GET_DESCRIPTOR): switch (value >> 8) { case HID_DT_HID: + { + struct hid_descriptor hidg_desc_copy = hidg_desc; + VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n"); + hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT; + hidg_desc_copy.desc[0].wDescriptorLength = + cpu_to_le16(hidg->report_desc_length); + length = min_t(unsigned short, length, - hidg_desc.bLength); - memcpy(req->buf, &hidg_desc, length); + hidg_desc_copy.bLength); + memcpy(req->buf, &hidg_desc_copy, length); goto respond; break; + } case HID_DT_REPORT: VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n"); length = min_t(unsigned short, length, @@ -632,6 +640,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); + /* + * We can use hidg_desc struct here but we should not relay + * that its content won't change after returning from this function. + */ hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT; hidg_desc.desc[0].wDescriptorLength = cpu_to_le16(hidg->report_desc_length); diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 89179ab..7ee0579 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -113,6 +113,7 @@ struct gs_port { int write_allocated; struct gs_buf port_write_buf; wait_queue_head_t drain_wait; /* wait while writes drain */ + bool write_busy; /* REVISIT this state ... */ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ @@ -363,7 +364,7 @@ __acquires(&port->port_lock) int status = 0; bool do_tty_wake = false; - while (!list_empty(pool)) { + while (!port->write_busy && !list_empty(pool)) { struct usb_request *req; int len; @@ -393,9 +394,11 @@ __acquires(&port->port_lock) * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ + port->write_busy = true; spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); + port->write_busy = false; if (status) { pr_debug("%s: %s %s err %d\n", diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c30b7b5..1194b09 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -121,7 +121,7 @@ static struct usb_function *f_msg; /* * We _always_ have both ACM and mass storage functions. */ -static int __init acm_ms_do_config(struct usb_configuration *c) +static int acm_ms_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int status; @@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = { /*-------------------------------------------------------------------------*/ -static int __init acm_ms_bind(struct usb_composite_dev *cdev) +static int acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct fsg_opts *opts; @@ -249,7 +249,7 @@ fail_get_msg: return status; } -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +static int acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_msg); usb_put_function_instance(fi_msg); @@ -258,13 +258,13 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver acm_ms_driver = { +static struct usb_composite_driver acm_ms_driver = { .name = "g_acm_ms", .dev = &device_desc, .max_speed = USB_SPEED_SUPER, .strings = dev_strings, .bind = acm_ms_bind, - .unbind = __exit_p(acm_ms_unbind), + .unbind = acm_ms_unbind, }; module_usb_composite_driver(acm_ms_driver); diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f46a395..f289caf 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-------------------------------------------------------------------------*/ -static int __init audio_do_config(struct usb_configuration *c) +static int audio_do_config(struct usb_configuration *c) { int status; @@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = { /*-------------------------------------------------------------------------*/ -static int __init audio_bind(struct usb_composite_dev *cdev) +static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; @@ -276,7 +276,7 @@ fail: return status; } -static int __exit audio_unbind(struct usb_composite_dev *cdev) +static int audio_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_GADGET_UAC1 if (!IS_ERR_OR_NULL(f_uac1)) @@ -292,13 +292,13 @@ static int __exit audio_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver audio_driver = { +static struct usb_composite_driver audio_driver = { .name = "g_audio", .dev = &device_desc, .strings = audio_strings, .max_speed = USB_SPEED_HIGH, .bind = audio_bind, - .unbind = __exit_p(audio_unbind), + .unbind = audio_unbind, }; module_usb_composite_driver(audio_driver); diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 2e85d94..afd3e37 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __init cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { int status; @@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = { /*-------------------------------------------------------------------------*/ -static int __init cdc_bind(struct usb_composite_dev *cdev) +static int cdc_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct f_ecm_opts *ecm_opts; @@ -211,7 +211,7 @@ fail: return status; } -static int __exit cdc_unbind(struct usb_composite_dev *cdev) +static int cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); @@ -222,13 +222,13 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver cdc_driver = { +static struct usb_composite_driver cdc_driver = { .name = "g_cdc", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = cdc_bind, - .unbind = __exit_p(cdc_unbind), + .unbind = cdc_unbind, }; module_usb_composite_driver(cdc_driver); diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 633683a..204b10b 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -284,7 +284,7 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget, +static int dbgp_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { int err, stp; @@ -406,7 +406,7 @@ fail: return err; } -static __refdata struct usb_gadget_driver dbgp_driver = { +static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", .max_speed = USB_SPEED_HIGH, .bind = dbgp_bind, diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index c5fdc61..a3323dc 100644 --- a/drivers/usb/gadget/legacy/ether.c +++ b/drivers/usb/gadget/legacy/ether.c @@ -222,7 +222,7 @@ static struct usb_function *f_rndis; * the first one present. That's to make Microsoft's drivers happy, * and to follow DOCSIS 1.0 (cable modem standard). */ -static int __init rndis_do_config(struct usb_configuration *c) +static int rndis_do_config(struct usb_configuration *c) { int status; @@ -264,7 +264,7 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); /* * We _always_ have an ECM, CDC Subset, or EEM configuration. */ -static int __init eth_do_config(struct usb_configuration *c) +static int eth_do_config(struct usb_configuration *c) { int status = 0; @@ -318,7 +318,7 @@ static struct usb_configuration eth_config_driver = { /*-------------------------------------------------------------------------*/ -static int __init eth_bind(struct usb_composite_dev *cdev) +static int eth_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct f_eem_opts *eem_opts = NULL; @@ -447,7 +447,7 @@ fail: return status; } -static int __exit eth_unbind(struct usb_composite_dev *cdev) +static int eth_unbind(struct usb_composite_dev *cdev) { if (has_rndis()) { usb_put_function(f_rndis); @@ -466,13 +466,13 @@ static int __exit eth_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver eth_driver = { +static struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, .bind = eth_bind, - .unbind = __exit_p(eth_unbind), + .unbind = eth_unbind, }; module_usb_composite_driver(eth_driver); diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index b01b88e..7b9ef7e 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -163,7 +163,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev); static int gfs_do_config(struct usb_configuration *c); -static __refdata struct usb_composite_driver gfs_driver = { +static struct usb_composite_driver gfs_driver = { .name = DRIVER_NAME, .dev = &gfs_dev_desc, .strings = gfs_dev_strings, diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index e02a095..da19c48 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -118,7 +118,7 @@ static struct usb_gadget_strings *dev_strings[] = { static struct usb_function_instance *fi_midi; static struct usb_function *f_midi; -static int __exit midi_unbind(struct usb_composite_dev *dev) +static int midi_unbind(struct usb_composite_dev *dev) { usb_put_function(f_midi); usb_put_function_instance(fi_midi); @@ -133,7 +133,7 @@ static struct usb_configuration midi_config = { .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, }; -static int __init midi_bind_config(struct usb_configuration *c) +static int midi_bind_config(struct usb_configuration *c) { int status; @@ -150,7 +150,7 @@ static int __init midi_bind_config(struct usb_configuration *c) return 0; } -static int __init midi_bind(struct usb_composite_dev *cdev) +static int midi_bind(struct usb_composite_dev *cdev) { struct f_midi_opts *midi_opts; int status; @@ -185,13 +185,13 @@ put: return status; } -static __refdata struct usb_composite_driver midi_driver = { +static struct usb_composite_driver midi_driver = { .name = (char *) longname, .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = midi_bind, - .unbind = __exit_p(midi_unbind), + .unbind = midi_unbind, }; module_usb_composite_driver(midi_driver); diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 614b06d..2baa572 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -106,7 +106,7 @@ static struct usb_gadget_strings *dev_strings[] = { /****************************** Configurations ******************************/ -static int __init do_config(struct usb_configuration *c) +static int do_config(struct usb_configuration *c) { struct hidg_func_node *e, *n; int status = 0; @@ -147,7 +147,7 @@ static struct usb_configuration config_driver = { /****************************** Gadget Bind ******************************/ -static int __init hid_bind(struct usb_composite_dev *cdev) +static int hid_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct list_head *tmp; @@ -205,7 +205,7 @@ put: return status; } -static int __exit hid_unbind(struct usb_composite_dev *cdev) +static int hid_unbind(struct usb_composite_dev *cdev) { struct hidg_func_node *n; @@ -216,7 +216,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev) return 0; } -static int __init hidg_plat_driver_probe(struct platform_device *pdev) +static int hidg_plat_driver_probe(struct platform_device *pdev) { struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev); struct hidg_func_node *entry; @@ -252,13 +252,13 @@ static int hidg_plat_driver_remove(struct platform_device *pdev) /****************************** Some noise ******************************/ -static __refdata struct usb_composite_driver hidg_driver = { +static struct usb_composite_driver hidg_driver = { .name = "g_hid", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = hid_bind, - .unbind = __exit_p(hid_unbind), + .unbind = hid_unbind, }; static struct platform_driver hidg_plat_driver = { diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index 8e27a8c..e7bfb08 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -130,7 +130,7 @@ static int msg_thread_exits(struct fsg_common *common) return 0; } -static int __init msg_do_config(struct usb_configuration *c) +static int msg_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int ret; @@ -170,7 +170,7 @@ static struct usb_configuration msg_config_driver = { /****************************** Gadget Bind ******************************/ -static int __init msg_bind(struct usb_composite_dev *cdev) +static int msg_bind(struct usb_composite_dev *cdev) { static const struct fsg_operations ops = { .thread_exits = msg_thread_exits, @@ -248,7 +248,7 @@ static int msg_unbind(struct usb_composite_dev *cdev) /****************************** Some noise ******************************/ -static __refdata struct usb_composite_driver msg_driver = { +static struct usb_composite_driver msg_driver = { .name = "g_mass_storage", .dev = &msg_device_desc, .max_speed = USB_SPEED_SUPER, diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index 39d27bb..b21b51f 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -149,7 +149,7 @@ static struct usb_function *f_acm_rndis; static struct usb_function *f_rndis; static struct usb_function *f_msg_rndis; -static __init int rndis_do_config(struct usb_configuration *c) +static int rndis_do_config(struct usb_configuration *c) { struct fsg_opts *fsg_opts; int ret; @@ -237,7 +237,7 @@ static struct usb_function *f_acm_multi; static struct usb_function *f_ecm; static struct usb_function *f_msg_multi; -static __init int cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { struct fsg_opts *fsg_opts; int ret; @@ -466,7 +466,7 @@ fail: return status; } -static int __exit multi_unbind(struct usb_composite_dev *cdev) +static int multi_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_USB_G_MULTI_CDC usb_put_function(f_msg_multi); @@ -497,13 +497,13 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev) /****************************** Some noise ******************************/ -static __refdata struct usb_composite_driver multi_driver = { +static struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = multi_bind, - .unbind = __exit_p(multi_unbind), + .unbind = multi_unbind, .needs_serial = 1, }; diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c index e90e23d..6ce7421 100644 --- a/drivers/usb/gadget/legacy/ncm.c +++ b/drivers/usb/gadget/legacy/ncm.c @@ -107,7 +107,7 @@ static struct usb_function *f_ncm; /*-------------------------------------------------------------------------*/ -static int __init ncm_do_config(struct usb_configuration *c) +static int ncm_do_config(struct usb_configuration *c) { int status; @@ -143,7 +143,7 @@ static struct usb_configuration ncm_config_driver = { /*-------------------------------------------------------------------------*/ -static int __init gncm_bind(struct usb_composite_dev *cdev) +static int gncm_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct f_ncm_opts *ncm_opts; @@ -186,7 +186,7 @@ fail: return status; } -static int __exit gncm_unbind(struct usb_composite_dev *cdev) +static int gncm_unbind(struct usb_composite_dev *cdev) { if (!IS_ERR_OR_NULL(f_ncm)) usb_put_function(f_ncm); @@ -195,13 +195,13 @@ static int __exit gncm_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver ncm_driver = { +static struct usb_composite_driver ncm_driver = { .name = "g_ncm", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = gncm_bind, - .unbind = __exit_p(gncm_unbind), + .unbind = gncm_unbind, }; module_usb_composite_driver(ncm_driver); diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 9b8fd70..4bb498a 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -118,7 +118,7 @@ static struct usb_function_instance *fi_obex1; static struct usb_function_instance *fi_obex2; static struct usb_function_instance *fi_phonet; -static int __init nokia_bind_config(struct usb_configuration *c) +static int nokia_bind_config(struct usb_configuration *c) { struct usb_function *f_acm; struct usb_function *f_phonet = NULL; @@ -224,7 +224,7 @@ err_get_acm: return status; } -static int __init nokia_bind(struct usb_composite_dev *cdev) +static int nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; int status; @@ -307,7 +307,7 @@ err_usb: return status; } -static int __exit nokia_unbind(struct usb_composite_dev *cdev) +static int nokia_unbind(struct usb_composite_dev *cdev) { if (!IS_ERR_OR_NULL(f_obex1_cfg2)) usb_put_function(f_obex1_cfg2); @@ -338,13 +338,13 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver nokia_driver = { +static struct usb_composite_driver nokia_driver = { .name = "g_nokia", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = nokia_bind, - .unbind = __exit_p(nokia_unbind), + .unbind = nokia_unbind, }; module_usb_composite_driver(nokia_driver); diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index d5b6ee7..1ce7df1 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -126,7 +126,7 @@ static struct usb_configuration printer_cfg_driver = { .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, }; -static int __init printer_do_config(struct usb_configuration *c) +static int printer_do_config(struct usb_configuration *c) { struct usb_gadget *gadget = c->cdev->gadget; int status = 0; @@ -152,7 +152,7 @@ static int __init printer_do_config(struct usb_configuration *c) return status; } -static int __init printer_bind(struct usb_composite_dev *cdev) +static int printer_bind(struct usb_composite_dev *cdev) { struct f_printer_opts *opts; int ret, len; @@ -191,7 +191,7 @@ static int __init printer_bind(struct usb_composite_dev *cdev) return ret; } -static int __exit printer_unbind(struct usb_composite_dev *cdev) +static int printer_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_printer); usb_put_function_instance(fi_printer); @@ -199,7 +199,7 @@ static int __exit printer_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver printer_driver = { +static struct usb_composite_driver printer_driver = { .name = shortname, .dev = &device_desc, .strings = dev_strings, diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c index 1f5f978..8b7528f 100644 --- a/drivers/usb/gadget/legacy/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -174,7 +174,7 @@ out: return ret; } -static int __init gs_bind(struct usb_composite_dev *cdev) +static int gs_bind(struct usb_composite_dev *cdev) { int status; @@ -230,7 +230,7 @@ static int gs_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver gserial_driver = { +static struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 8b80add..f9b4882 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -2397,7 +2397,7 @@ static int usb_target_bind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver usbg_driver = { +static struct usb_composite_driver usbg_driver = { .name = "g_target", .dev = &usbg_device_desc, .strings = usbg_strings, diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index 04a3da2..72c976b 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -334,7 +334,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { * USB configuration */ -static int __init +static int webcam_config_bind(struct usb_configuration *c) { int status = 0; @@ -358,7 +358,7 @@ static struct usb_configuration webcam_config_driver = { .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, }; -static int /* __init_or_exit */ +static int webcam_unbind(struct usb_composite_dev *cdev) { if (!IS_ERR_OR_NULL(f_uvc)) @@ -368,7 +368,7 @@ webcam_unbind(struct usb_composite_dev *cdev) return 0; } -static int __init +static int webcam_bind(struct usb_composite_dev *cdev) { struct f_uvc_opts *uvc_opts; @@ -422,7 +422,7 @@ error: * Driver */ -static __refdata struct usb_composite_driver webcam_driver = { +static struct usb_composite_driver webcam_driver = { .name = "g_webcam", .dev = &webcam_device_descriptor, .strings = webcam_device_strings, diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c index 5ee9515..c986e8a 100644 --- a/drivers/usb/gadget/legacy/zero.c +++ b/drivers/usb/gadget/legacy/zero.c @@ -272,7 +272,7 @@ static struct usb_function_instance *func_inst_lb; module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(qlen, "depth of loopback queue"); -static int __init zero_bind(struct usb_composite_dev *cdev) +static int zero_bind(struct usb_composite_dev *cdev) { struct f_ss_opts *ss_opts; struct f_lb_opts *lb_opts; @@ -400,7 +400,7 @@ static int zero_unbind(struct usb_composite_dev *cdev) return 0; } -static __refdata struct usb_composite_driver zero_driver = { +static struct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 2fbedca..fc42264 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1942,7 +1942,7 @@ err_unprepare_fclk: return retval; } -static int __exit at91udc_remove(struct platform_device *pdev) +static int at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); unsigned long flags; @@ -2018,7 +2018,7 @@ static int at91udc_resume(struct platform_device *pdev) #endif static struct platform_driver at91_udc_driver = { - .remove = __exit_p(at91udc_remove), + .remove = at91udc_remove, .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume, diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 4c01953..351d485 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2186,7 +2186,7 @@ static int usba_udc_probe(struct platform_device *pdev) return 0; } -static int __exit usba_udc_remove(struct platform_device *pdev) +static int usba_udc_remove(struct platform_device *pdev) { struct usba_udc *udc; int i; @@ -2258,7 +2258,7 @@ static int usba_udc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume); static struct platform_driver udc_driver = { - .remove = __exit_p(usba_udc_remove), + .remove = usba_udc_remove, .driver = { .name = "atmel_usba_udc", .pm = &usba_udc_pm_ops, diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 55fcb93..c60022b 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2525,7 +2525,7 @@ err_kfree: /* Driver removal function * Free resources and finish pending transactions */ -static int __exit fsl_udc_remove(struct platform_device *pdev) +static int fsl_udc_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -2663,7 +2663,7 @@ static const struct platform_device_id fsl_udc_devtype[] = { }; MODULE_DEVICE_TABLE(platform, fsl_udc_devtype); static struct platform_driver udc_driver = { - .remove = __exit_p(fsl_udc_remove), + .remove = fsl_udc_remove, /* Just for FSL i.mx SoC currently */ .id_table = fsl_udc_devtype, /* these suspend and resume are not usb suspend and resume */ diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index fb4df15..3970f45 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1342,7 +1342,7 @@ static const struct usb_gadget_ops fusb300_gadget_ops = { .udc_stop = fusb300_udc_stop, }; -static int __exit fusb300_remove(struct platform_device *pdev) +static int fusb300_remove(struct platform_device *pdev) { struct fusb300 *fusb300 = platform_get_drvdata(pdev); @@ -1492,7 +1492,7 @@ clean_up: } static struct platform_driver fusb300_driver = { - .remove = __exit_p(fusb300_remove), + .remove = fusb300_remove, .driver = { .name = (char *) udc_name, }, diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 8c7c83c..309706f 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1528,7 +1528,7 @@ static const struct usb_gadget_ops m66592_gadget_ops = { .pullup = m66592_pullup, }; -static int __exit m66592_remove(struct platform_device *pdev) +static int m66592_remove(struct platform_device *pdev) { struct m66592 *m66592 = platform_get_drvdata(pdev); @@ -1695,7 +1695,7 @@ clean_up: /*-------------------------------------------------------------------------*/ static struct platform_driver m66592_driver = { - .remove = __exit_p(m66592_remove), + .remove = m66592_remove, .driver = { .name = (char *) udc_name, }, diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 2495fe9..0293f71 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1820,7 +1820,7 @@ static const struct usb_gadget_ops r8a66597_gadget_ops = { .set_selfpowered = r8a66597_set_selfpowered, }; -static int __exit r8a66597_remove(struct platform_device *pdev) +static int r8a66597_remove(struct platform_device *pdev) { struct r8a66597 *r8a66597 = platform_get_drvdata(pdev); @@ -1974,7 +1974,7 @@ clean_up2: /*-------------------------------------------------------------------------*/ static struct platform_driver r8a66597_driver = { - .remove = __exit_p(r8a66597_remove), + .remove = r8a66597_remove, .driver = { .name = (char *) udc_name, }, diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index dd3e9fd..1f24274 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2071,8 +2071,8 @@ static int xudc_probe(struct platform_device *pdev) /* Map the registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); udc->addr = devm_ioremap_resource(&pdev->dev, res); - if (!udc->addr) - return -ENOMEM; + if (IS_ERR(udc->addr)) + return PTR_ERR(udc->addr); irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f5397a5..7d34cbf 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2026,8 +2026,13 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, break; case COMP_DEV_ERR: case COMP_STALL: + frame->status = -EPROTO; + skip_td = true; + break; case COMP_TX_ERR: frame->status = -EPROTO; + if (event_trb != td->last_trb) + return 0; skip_td = true; break; case COMP_STOP: @@ -2640,7 +2645,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) xhci_halt(xhci); hw_died: spin_unlock(&xhci->lock); - return -ESHUTDOWN; + return IRQ_HANDLED; } /* diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8e421b8..ea75e8c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1267,7 +1267,7 @@ union xhci_trb { * since the command ring is 64-byte aligned. * It must also be greater than 16. */ -#define TRBS_PER_SEGMENT 64 +#define TRBS_PER_SEGMENT 256 /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) #define TRB_SEGMENT_SIZE (TRBS_PER_SEGMENT*16) diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 1e0e10d..3af263c 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -94,7 +94,7 @@ struct isp1301 { #if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) -#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) +#if defined(CONFIG_TPS65010) || (defined(CONFIG_TPS65010_MODULE) && defined(MODULE)) #include <linux/i2c/tps65010.h> diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 84ce2d7..9031750 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -127,6 +127,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ + { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 829604d..f5257af 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -61,7 +61,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 71fd9da..e3b7af8 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -62,10 +62,6 @@ #define ALCATEL_VENDOR_ID 0x11f7 #define ALCATEL_PRODUCT_ID 0x02df -/* Samsung I330 phone cradle */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_ID 0x8001 - #define SIEMENS_VENDOR_ID 0x11f5 #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index bf2bd40..60afb39 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -95,7 +95,7 @@ static const struct usb_device_id id_table[] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), + { USB_DEVICE_INTERFACE_CLASS(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID, 0xff), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d684b4b..caf1888 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -766,6 +766,13 @@ UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_GO_SLOW ), +/* Reported by Christian Schaller <cschalle@redhat.com> */ +UNUSUAL_DEV( 0x059f, 0x0651, 0x0000, 0x0000, + "LaCie", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT ), + /* Submitted by Joel Bourquard <numlock@freesurf.ch> * Some versions of this device need the SubClass and Protocol overrides * while others don't. diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 69fab0f..e9851ad 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -907,8 +907,14 @@ static void vfio_pci_request(void *device_data, unsigned int count) mutex_lock(&vdev->igate); if (vdev->req_trigger) { - dev_dbg(&vdev->pdev->dev, "Requesting device from user\n"); + if (!(count % 10)) + dev_notice_ratelimited(&vdev->pdev->dev, + "Relaying device request to user (#%u)\n", + count); eventfd_signal(vdev->req_trigger, 1); + } else if (count == 0) { + dev_warn(&vdev->pdev->dev, + "No device request channel registered, blocked until released by user\n"); } mutex_unlock(&vdev->igate); diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 0d33662..e1278fe 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -710,6 +710,8 @@ void *vfio_del_group_dev(struct device *dev) void *device_data = device->device_data; struct vfio_unbound_dev *unbound; unsigned int i = 0; + long ret; + bool interrupted = false; /* * The group exists so long as we have a device reference. Get @@ -755,9 +757,22 @@ void *vfio_del_group_dev(struct device *dev) vfio_device_put(device); - } while (wait_event_interruptible_timeout(vfio.release_q, - !vfio_dev_present(group, dev), - HZ * 10) <= 0); + if (interrupted) { + ret = wait_event_timeout(vfio.release_q, + !vfio_dev_present(group, dev), HZ * 10); + } else { + ret = wait_event_interruptible_timeout(vfio.release_q, + !vfio_dev_present(group, dev), HZ * 10); + if (ret == -ERESTARTSYS) { + interrupted = true; + dev_warn(dev, + "Device is currently in use, task" + " \"%s\" (%d) " + "blocked until device is released", + current->comm, task_pid_nr(current)); + } + } + } while (ret <= 0); vfio_group_put(group); diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c index 5db43fc..7dd4631 100644 --- a/drivers/xen/events/events_2l.c +++ b/drivers/xen/events/events_2l.c @@ -345,6 +345,15 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void evtchn_2l_resume(void) +{ + int i; + + for_each_online_cpu(i) + memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) * + EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD); +} + static const struct evtchn_ops evtchn_ops_2l = { .max_channels = evtchn_2l_max_channels, .nr_channels = evtchn_2l_max_channels, @@ -356,6 +365,7 @@ static const struct evtchn_ops evtchn_ops_2l = { .mask = evtchn_2l_mask, .unmask = evtchn_2l_unmask, .handle_events = evtchn_2l_handle_events, + .resume = evtchn_2l_resume, }; void __init xen_evtchn_2l_init(void) diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 70fba97..2b8553b 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -529,8 +529,8 @@ static unsigned int __startup_pirq(unsigned int irq) if (rc) goto err; - bind_evtchn_to_cpu(evtchn, 0); info->evtchn = evtchn; + bind_evtchn_to_cpu(evtchn, 0); rc = xen_evtchn_port_setup(info); if (rc) @@ -1279,8 +1279,9 @@ void rebind_evtchn_irq(int evtchn, int irq) mutex_unlock(&irq_mapping_update_lock); - /* new event channels are always bound to cpu 0 */ - irq_set_affinity(irq, cpumask_of(0)); + bind_evtchn_to_cpu(evtchn, info->cpu); + /* This will be deferred until interrupt is processed */ + irq_set_affinity(irq, cpumask_of(info->cpu)); /* Unmask the event channel. */ enable_irq(irq); diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index d5bb1a3..8927485 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -327,30 +327,10 @@ static int map_grant_pages(struct grant_map *map) return err; } -struct unmap_grant_pages_callback_data -{ - struct completion completion; - int result; -}; - -static void unmap_grant_callback(int result, - struct gntab_unmap_queue_data *data) -{ - struct unmap_grant_pages_callback_data* d = data->data; - - d->result = result; - complete(&d->completion); -} - static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) { int i, err = 0; struct gntab_unmap_queue_data unmap_data; - struct unmap_grant_pages_callback_data data; - - init_completion(&data.completion); - unmap_data.data = &data; - unmap_data.done= &unmap_grant_callback; if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { int pgno = (map->notify.addr >> PAGE_SHIFT); @@ -367,11 +347,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) unmap_data.pages = map->pages + offset; unmap_data.count = pages; - gnttab_unmap_refs_async(&unmap_data); - - wait_for_completion(&data.completion); - if (data.result) - return data.result; + err = gnttab_unmap_refs_sync(&unmap_data); + if (err) + return err; for (i = 0; i < pages; i++) { if (map->unmap_ops[offset+i].status) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 17972fb..b1c7170 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -123,6 +123,11 @@ struct gnttab_ops { int (*query_foreign_access)(grant_ref_t ref); }; +struct unmap_refs_callback_data { + struct completion completion; + int result; +}; + static struct gnttab_ops *gnttab_interface; static int grant_table_version; @@ -863,6 +868,29 @@ void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item) } EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async); +static void unmap_refs_callback(int result, + struct gntab_unmap_queue_data *data) +{ + struct unmap_refs_callback_data *d = data->data; + + d->result = result; + complete(&d->completion); +} + +int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item) +{ + struct unmap_refs_callback_data data; + + init_completion(&data.completion); + item->data = &data; + item->done = &unmap_refs_callback; + gnttab_unmap_refs_async(item); + wait_for_completion(&data.completion); + + return data.result; +} +EXPORT_SYMBOL_GPL(gnttab_unmap_refs_sync); + static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes) { int rc; diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index bf19407..9e6a851 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -131,6 +131,8 @@ static void do_suspend(void) goto out_resume; } + xen_arch_suspend(); + si.cancelled = 1; err = stop_machine(xen_suspend, &si, cpumask_of(0)); @@ -148,11 +150,12 @@ static void do_suspend(void) si.cancelled = 1; } + xen_arch_resume(); + out_resume: - if (!si.cancelled) { - xen_arch_resume(); + if (!si.cancelled) xs_resume(); - } else + else xs_suspend_cancel(); dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 810ad41..4c54932 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -235,7 +235,7 @@ retry: #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT)) #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT) while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { - xen_io_tlb_start = (void *)__get_free_pages(__GFP_NOWARN, order); + xen_io_tlb_start = (void *)xen_get_swiotlb_free_pages(order); if (xen_io_tlb_start) break; order--; diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c index 75fe3d4..9c23420 100644 --- a/drivers/xen/xen-pciback/conf_space.c +++ b/drivers/xen/xen-pciback/conf_space.c @@ -16,8 +16,8 @@ #include "conf_space.h" #include "conf_space_quirks.h" -bool permissive; -module_param(permissive, bool, 0644); +bool xen_pcibk_permissive; +module_param_named(permissive, xen_pcibk_permissive, bool, 0644); /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, * xen_pcibk_write_config_word, and xen_pcibk_write_config_byte are created. */ @@ -262,7 +262,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value) * This means that some fields may still be read-only because * they have entries in the config_field list that intercept * the write and do nothing. */ - if (dev_data->permissive || permissive) { + if (dev_data->permissive || xen_pcibk_permissive) { switch (size) { case 1: err = pci_write_config_byte(dev, offset, diff --git a/drivers/xen/xen-pciback/conf_space.h b/drivers/xen/xen-pciback/conf_space.h index 2e1d73d..62461a8 100644 --- a/drivers/xen/xen-pciback/conf_space.h +++ b/drivers/xen/xen-pciback/conf_space.h @@ -64,7 +64,7 @@ struct config_field_entry { void *data; }; -extern bool permissive; +extern bool xen_pcibk_permissive; #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index c2260a0..ad3d17d 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c @@ -118,7 +118,7 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) cmd->val = value; - if (!permissive && (!dev_data || !dev_data->permissive)) + if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive)) return 0; /* Only allow the guest to control certain bits. */ diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 564b315..5390a67 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -57,6 +57,7 @@ #include <xen/xen.h> #include <xen/xenbus.h> #include <xen/events.h> +#include <xen/xen-ops.h> #include <xen/page.h> #include <xen/hvm.h> @@ -735,6 +736,30 @@ static int __init xenstored_local_init(void) return err; } +static int xenbus_resume_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + int err = 0; + + if (xen_hvm_domain()) { + uint64_t v; + + err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); + if (!err && v) + xen_store_evtchn = v; + else + pr_warn("Cannot update xenstore event channel: %d\n", + err); + } else + xen_store_evtchn = xen_start_info->store_evtchn; + + return err; +} + +static struct notifier_block xenbus_resume_nb = { + .notifier_call = xenbus_resume_cb, +}; + static int __init xenbus_init(void) { int err = 0; @@ -793,6 +818,10 @@ static int __init xenbus_init(void) goto out_error; } + if ((xen_store_domain_type != XS_LOCAL) && + (xen_store_domain_type != XS_UNKNOWN)) + xen_resume_notifier_register(&xenbus_resume_nb); + #ifdef CONFIG_XEN_COMPAT_XENFS /* * Create xenfs mountpoint in /proc for compatibility with diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0ec8e22..7effed6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3180,8 +3180,6 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); fail: btrfs_release_path(path); - if (ret) - btrfs_abort_transaction(trans, root, ret); return ret; } @@ -3487,8 +3485,30 @@ again: ret = 0; } } - if (!ret) + if (!ret) { ret = write_one_cache_group(trans, root, path, cache); + /* + * Our block group might still be attached to the list + * of new block groups in the transaction handle of some + * other task (struct btrfs_trans_handle->new_bgs). This + * means its block group item isn't yet in the extent + * tree. If this happens ignore the error, as we will + * try again later in the critical section of the + * transaction commit. + */ + if (ret == -ENOENT) { + ret = 0; + spin_lock(&cur_trans->dirty_bgs_lock); + if (list_empty(&cache->dirty_list)) { + list_add_tail(&cache->dirty_list, + &cur_trans->dirty_bgs); + btrfs_get_block_group(cache); + } + spin_unlock(&cur_trans->dirty_bgs_lock); + } else if (ret) { + btrfs_abort_transaction(trans, root, ret); + } + } /* if its not on the io list, we need to put the block group */ if (should_put) @@ -3597,8 +3617,11 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, ret = 0; } } - if (!ret) + if (!ret) { ret = write_one_cache_group(trans, root, path, cache); + if (ret) + btrfs_abort_transaction(trans, root, ret); + } /* if its not on the io list, we need to put the block group */ if (should_put) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 43af5a6..c32d226 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4772,6 +4772,25 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, start >> PAGE_CACHE_SHIFT); if (eb && atomic_inc_not_zero(&eb->refs)) { rcu_read_unlock(); + /* + * Lock our eb's refs_lock to avoid races with + * free_extent_buffer. When we get our eb it might be flagged + * with EXTENT_BUFFER_STALE and another task running + * free_extent_buffer might have seen that flag set, + * eb->refs == 2, that the buffer isn't under IO (dirty and + * writeback flags not set) and it's still in the tree (flag + * EXTENT_BUFFER_TREE_REF set), therefore being in the process + * of decrementing the extent buffer's reference count twice. + * So here we could race and increment the eb's reference count, + * clear its stale flag, mark it as dirty and drop our reference + * before the other task finishes executing free_extent_buffer, + * which would later result in an attempt to free an extent + * buffer that is dirty. + */ + if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) { + spin_lock(&eb->refs_lock); + spin_unlock(&eb->refs_lock); + } mark_extent_buffer_accessed(eb, NULL); return eb; } diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 41c510b..9dbe5b5 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -86,7 +86,7 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root, mapping_set_gfp_mask(inode->i_mapping, mapping_gfp_mask(inode->i_mapping) & - ~(GFP_NOFS & ~__GFP_HIGHMEM)); + ~(__GFP_FS | __GFP_HIGHMEM)); return inode; } @@ -3466,6 +3466,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root, struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; int ret; struct btrfs_io_ctl io_ctl; + bool release_metadata = true; if (!btrfs_test_opt(root, INODE_MAP_CACHE)) return 0; @@ -3473,11 +3474,20 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root, memset(&io_ctl, 0, sizeof(io_ctl)); ret = __btrfs_write_out_cache(root, inode, ctl, NULL, &io_ctl, trans, path, 0); - if (!ret) + if (!ret) { + /* + * At this point writepages() didn't error out, so our metadata + * reservation is released when the writeback finishes, at + * inode.c:btrfs_finish_ordered_io(), regardless of it finishing + * with or without an error. + */ + release_metadata = false; ret = btrfs_wait_cache_io(root, trans, NULL, &io_ctl, path, 0); + } if (ret) { - btrfs_delalloc_release_metadata(inode, inode->i_size); + if (release_metadata) + btrfs_delalloc_release_metadata(inode, inode->i_size); #ifdef DEBUG btrfs_err(root->fs_info, "failed to write free ino cache for root %llu", diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 157cc54..760c4a5 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -722,6 +722,7 @@ void btrfs_start_ordered_extent(struct inode *inode, int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) { int ret = 0; + int ret_wb = 0; u64 end; u64 orig_end; struct btrfs_ordered_extent *ordered; @@ -741,9 +742,14 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) if (ret) return ret; - ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end); - if (ret) - return ret; + /* + * If we have a writeback error don't return immediately. Wait first + * for any ordered extents that haven't completed yet. This is to make + * sure no one can dirty the same page ranges and call writepages() + * before the ordered extents complete - to avoid failures (-EEXIST) + * when adding the new ordered extents to the ordered tree. + */ + ret_wb = filemap_fdatawait_range(inode->i_mapping, start, orig_end); end = orig_end; while (1) { @@ -767,7 +773,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) break; end--; } - return ret; + return ret_wb ? ret_wb : ret; } /* diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index da94e41..5373567 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -173,5 +173,5 @@ MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); -module_init(configfs_init); +core_initcall(configfs_init); module_exit(configfs_exit); diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 59fedbc..86a2121 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -121,7 +121,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, int len, i; int err = -ENOMEM; - entry = kmalloc(sizeof(*entry), GFP_KERNEL); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return err; @@ -659,6 +659,9 @@ int setup_arg_pages(struct linux_binprm *bprm, if (stack_base > STACK_SIZE_MAX) stack_base = STACK_SIZE_MAX; + /* Add space for stack randomization. */ + stack_base += (STACK_RND_MASK << PAGE_SHIFT); + /* Make sure we didn't let the argument array grow too large. */ if (vma->vm_end - vma->vm_start > stack_base) return -ENOMEM; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 009a059..9a83f14 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2889,7 +2889,6 @@ extern int ext4_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags); extern int ext4_ext_calc_metadata_amount(struct inode *inode, ext4_lblk_t lblocks); -extern int ext4_extent_tree_init(handle_t *, struct inode *); extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int num, struct ext4_ext_path *path); diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 3445035..d418431 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -87,6 +87,12 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) ext4_put_nojournal(handle); return 0; } + + if (!handle->h_transaction) { + err = jbd2_journal_stop(handle); + return handle->h_err ? handle->h_err : err; + } + sb = handle->h_transaction->t_journal->j_private; err = handle->h_err; rc = jbd2_journal_stop(handle); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index d74e0802..e003a1e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -377,7 +377,7 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext) ext4_lblk_t lblock = le32_to_cpu(ext->ee_block); ext4_lblk_t last = lblock + len - 1; - if (lblock > last) + if (len == 0 || lblock > last) return 0; return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len); } @@ -5396,6 +5396,14 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) loff_t new_size, ioffset; int ret; + /* + * We need to test this early because xfstests assumes that a + * collapse range of (0, 1) will return EOPNOTSUPP if the file + * system does not support collapse range. + */ + if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + return -EOPNOTSUPP; + /* Collapse range works only on fs block size aligned offsets. */ if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) || len & (EXT4_CLUSTER_SIZE(sb) - 1)) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 55b187c..0554b0b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4345,7 +4345,7 @@ static void ext4_update_other_inodes_time(struct super_block *sb, int inode_size = EXT4_INODE_SIZE(sb); oi.orig_ino = orig_ino; - ino = orig_ino & ~(inodes_per_block - 1); + ino = (orig_ino & ~(inodes_per_block - 1)) + 1; for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) { if (ino == orig_ino) continue; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f06d058..ca9d4a2 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -294,6 +294,8 @@ static void __save_error_info(struct super_block *sb, const char *func, struct ext4_super_block *es = EXT4_SB(sb)->s_es; EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + if (bdev_read_only(sb->s_bdev)) + return; es->s_state |= cpu_to_le16(EXT4_ERROR_FS); es->s_last_error_time = cpu_to_le32(get_seconds()); strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index b91b0e1..1e1aae6 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1513,6 +1513,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, { struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + bool locked = false; int ret; long diff; @@ -1533,7 +1534,13 @@ static int f2fs_write_data_pages(struct address_space *mapping, diff = nr_pages_to_write(sbi, DATA, wbc); + if (!S_ISDIR(inode->i_mode)) { + mutex_lock(&sbi->writepages); + locked = true; + } ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping); + if (locked) + mutex_unlock(&sbi->writepages); f2fs_submit_merged_bio(sbi, DATA, WRITE); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d8921cf..8de34ab 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -625,6 +625,7 @@ struct f2fs_sb_info { struct mutex cp_mutex; /* checkpoint procedure lock */ struct rw_semaphore cp_rwsem; /* blocking FS operations */ struct rw_semaphore node_write; /* locking node writes */ + struct mutex writepages; /* mutex for writepages() */ wait_queue_head_t cp_wait; struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 7e3794e..658e807 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -298,16 +298,14 @@ fail: static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct page *page; + struct page *page = page_follow_link_light(dentry, nd); - page = page_follow_link_light(dentry, nd); - if (IS_ERR(page)) + if (IS_ERR_OR_NULL(page)) return page; /* this is broken symlink case */ if (*nd_get_link(nd) == 0) { - kunmap(page); - page_cache_release(page); + page_put_link(dentry, nd, page); return ERR_PTR(-ENOENT); } return page; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 160b883..b2dd1b0 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1035,6 +1035,7 @@ try_onemore: sbi->raw_super = raw_super; sbi->raw_super_buf = raw_super_buf; mutex_init(&sbi->gc_mutex); + mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); init_rwsem(&sbi->node_write); clear_sbi_flag(sbi, SBI_POR_DOING); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index ef26317..07d8d8f 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -581,7 +581,7 @@ static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, if (name == NULL) goto out_put; - fd = file_create(name, mode & S_IFMT); + fd = file_create(name, mode & 0777); if (fd < 0) error = fd; else diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index b5128c6..a9079d0 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -842,15 +842,23 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, { jbd2_journal_revoke_header_t *header; int offset, max; + int csum_size = 0; + __u32 rcount; int record_len = 4; header = (jbd2_journal_revoke_header_t *) bh->b_data; offset = sizeof(jbd2_journal_revoke_header_t); - max = be32_to_cpu(header->r_count); + rcount = be32_to_cpu(header->r_count); if (!jbd2_revoke_block_csum_verify(journal, header)) return -EINVAL; + if (jbd2_journal_has_csum_v2or3(journal)) + csum_size = sizeof(struct jbd2_journal_revoke_tail); + if (rcount > journal->j_blocksize - csum_size) + return -EINVAL; + max = rcount; + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) record_len = 8; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index c6cbaef..14214da 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -577,7 +577,7 @@ static void write_one_revoke_record(journal_t *journal, { int csum_size = 0; struct buffer_head *descriptor; - int offset; + int sz, offset; journal_header_t *header; /* If we are already aborting, this all becomes a noop. We @@ -594,9 +594,14 @@ static void write_one_revoke_record(journal_t *journal, if (jbd2_journal_has_csum_v2or3(journal)) csum_size = sizeof(struct jbd2_journal_revoke_tail); + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + sz = 8; + else + sz = 4; + /* Make sure we have a descriptor with space left for the record */ if (descriptor) { - if (offset >= journal->j_blocksize - csum_size) { + if (offset + sz > journal->j_blocksize - csum_size) { flush_descriptor(journal, descriptor, offset, write_op); descriptor = NULL; } @@ -619,16 +624,13 @@ static void write_one_revoke_record(journal_t *journal, *descriptorp = descriptor; } - if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) { + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) * ((__be64 *)(&descriptor->b_data[offset])) = cpu_to_be64(record->blocknr); - offset += 8; - - } else { + else * ((__be32 *)(&descriptor->b_data[offset])) = cpu_to_be32(record->blocknr); - offset += 4; - } + offset += sz; *offsetp = offset; } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 5f09370..ff2f2e6 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -551,7 +551,6 @@ int jbd2_journal_extend(handle_t *handle, int nblocks) int result; int wanted; - WARN_ON(!transaction); if (is_handle_aborted(handle)) return -EROFS; journal = transaction->t_journal; @@ -627,7 +626,6 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) tid_t tid; int need_to_start, ret; - WARN_ON(!transaction); /* If we've had an abort of any type, don't even think about * actually doing the restart! */ if (is_handle_aborted(handle)) @@ -785,7 +783,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, int need_copy = 0; unsigned long start_lock, time_lock; - WARN_ON(!transaction); if (is_handle_aborted(handle)) return -EROFS; journal = transaction->t_journal; @@ -1051,7 +1048,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) int err; jbd_debug(5, "journal_head %p\n", jh); - WARN_ON(!transaction); err = -EROFS; if (is_handle_aborted(handle)) goto out; @@ -1266,7 +1262,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) struct journal_head *jh; int ret = 0; - WARN_ON(!transaction); if (is_handle_aborted(handle)) return -EROFS; journal = transaction->t_journal; @@ -1397,7 +1392,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) int err = 0; int was_modified = 0; - WARN_ON(!transaction); if (is_handle_aborted(handle)) return -EROFS; journal = transaction->t_journal; @@ -1530,8 +1524,22 @@ int jbd2_journal_stop(handle_t *handle) tid_t tid; pid_t pid; - if (!transaction) - goto free_and_exit; + if (!transaction) { + /* + * Handle is already detached from the transaction so + * there is nothing to do other than decrease a refcount, + * or free the handle if refcount drops to zero + */ + if (--handle->h_ref > 0) { + jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, + handle->h_ref); + return err; + } else { + if (handle->h_rsv_handle) + jbd2_free_handle(handle->h_rsv_handle); + goto free_and_exit; + } + } journal = transaction->t_journal; J_ASSERT(journal_current_handle() == handle); @@ -2373,7 +2381,6 @@ int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode) transaction_t *transaction = handle->h_transaction; journal_t *journal; - WARN_ON(!transaction); if (is_handle_aborted(handle)) return -EROFS; journal = transaction->t_journal; diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index f131fc2..fffca95 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -518,7 +518,14 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, if (!kn) goto err_out1; - ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); + /* + * If the ino of the sysfs entry created for a kmem cache gets + * allocated from an ida layer, which is accounted to the memcg that + * owns the cache, the memcg will get pinned forever. So do not account + * ino ida allocations. + */ + ret = ida_simple_get(&root->ino_ida, 1, 0, + GFP_KERNEL | __GFP_NOACCOUNT); if (ret < 0) goto err_out2; kn->ino = ret; @@ -1415,6 +1415,7 @@ static int lookup_fast(struct nameidata *nd, */ if (nd->flags & LOOKUP_RCU) { unsigned seq; + bool negative; dentry = __d_lookup_rcu(parent, &nd->last, &seq); if (!dentry) goto unlazy; @@ -1424,8 +1425,11 @@ static int lookup_fast(struct nameidata *nd, * the dentry name information from lookup. */ *inode = dentry->d_inode; + negative = d_is_negative(dentry); if (read_seqcount_retry(&dentry->d_seq, seq)) return -ECHILD; + if (negative) + return -ENOENT; /* * This sequence count validates that the parent had no @@ -1472,6 +1476,10 @@ unlazy: goto need_lookup; } + if (unlikely(d_is_negative(dentry))) { + dput(dentry); + return -ENOENT; + } path->mnt = mnt; path->dentry = dentry; err = follow_managed(path, nd->flags); @@ -1583,10 +1591,10 @@ static inline int walk_component(struct nameidata *nd, struct path *path, goto out_err; inode = path->dentry->d_inode; + err = -ENOENT; + if (d_is_negative(path->dentry)) + goto out_path_put; } - err = -ENOENT; - if (d_is_negative(path->dentry)) - goto out_path_put; if (should_follow_link(path->dentry, follow)) { if (nd->flags & LOOKUP_RCU) { @@ -3036,14 +3044,13 @@ retry_lookup: BUG_ON(nd->flags & LOOKUP_RCU); inode = path->dentry->d_inode; -finish_lookup: - /* we _can_ be in RCU mode here */ error = -ENOENT; if (d_is_negative(path->dentry)) { path_to_nameidata(path, nd); goto out; } - +finish_lookup: + /* we _can_ be in RCU mode here */ if (should_follow_link(path->dentry, !symlink_ok)) { if (nd->flags & LOOKUP_RCU) { if (unlikely(nd->path.mnt != path->mnt || @@ -3226,7 +3233,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, if (unlikely(file->f_flags & __O_TMPFILE)) { error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened); - goto out; + goto out2; } error = path_init(dfd, pathname, flags, nd); @@ -3256,6 +3263,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, } out: path_cleanup(nd); +out2: if (!(opened & FILE_OPENED)) { BUG_ON(!error); put_filp(file); diff --git a/fs/namespace.c b/fs/namespace.c index 1f4f9da..1b9e111 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3179,6 +3179,12 @@ bool fs_fully_visible(struct file_system_type *type) if (mnt->mnt.mnt_sb->s_type != type) continue; + /* This mount is not fully visible if it's root directory + * is not the root directory of the filesystem. + */ + if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) + continue; + /* This mount is not fully visible if there are any child mounts * that cover anything except for empty directories. */ diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index 03d647b..cdefaa3 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -181,6 +181,17 @@ nfsd4_block_proc_layoutcommit(struct inode *inode, } const struct nfsd4_layout_ops bl_layout_ops = { + /* + * Pretend that we send notification to the client. This is a blatant + * lie to force recent Linux clients to cache our device IDs. + * We rarely ever change the device ID, so the harm of leaking deviceids + * for a while isn't too bad. Unfortunately RFC5661 is a complete mess + * in this regard, but I filed errata 4119 for this a while ago, and + * hopefully the Linux client will eventually start caching deviceids + * without this again. + */ + .notify_types = + NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE, .proc_getdeviceinfo = nfsd4_block_proc_getdeviceinfo, .encode_getdeviceinfo = nfsd4_block_encode_getdeviceinfo, .proc_layoutget = nfsd4_block_proc_layoutget, diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 5827785..5694cfb 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -224,7 +224,7 @@ static int nfs_cb_stat_to_errno(int status) } static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, - enum nfsstat4 *status) + int *status) { __be32 *p; u32 op; @@ -235,7 +235,7 @@ static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, op = be32_to_cpup(p++); if (unlikely(op != expected)) goto out_unexpected; - *status = be32_to_cpup(p); + *status = nfs_cb_stat_to_errno(be32_to_cpup(p)); return 0; out_overflow: print_overflow_msg(__func__, xdr); @@ -446,22 +446,16 @@ out_overflow: static int decode_cb_sequence4res(struct xdr_stream *xdr, struct nfsd4_callback *cb) { - enum nfsstat4 nfserr; int status; if (cb->cb_minorversion == 0) return 0; - status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); - if (unlikely(status)) - goto out; - if (unlikely(nfserr != NFS4_OK)) - goto out_default; - status = decode_cb_sequence4resok(xdr, cb); -out: - return status; -out_default: - return nfs_cb_stat_to_errno(nfserr); + status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &cb->cb_status); + if (unlikely(status || cb->cb_status)) + return status; + + return decode_cb_sequence4resok(xdr, cb); } /* @@ -524,26 +518,19 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, struct nfsd4_callback *cb) { struct nfs4_cb_compound_hdr hdr; - enum nfsstat4 nfserr; int status; status = decode_cb_compound4res(xdr, &hdr); if (unlikely(status)) - goto out; + return status; if (cb != NULL) { status = decode_cb_sequence4res(xdr, cb); - if (unlikely(status)) - goto out; + if (unlikely(status || cb->cb_status)) + return status; } - status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr); - if (unlikely(status)) - goto out; - if (unlikely(nfserr != NFS4_OK)) - status = nfs_cb_stat_to_errno(nfserr); -out: - return status; + return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status); } #ifdef CONFIG_NFSD_PNFS @@ -621,24 +608,18 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp, struct nfsd4_callback *cb) { struct nfs4_cb_compound_hdr hdr; - enum nfsstat4 nfserr; int status; status = decode_cb_compound4res(xdr, &hdr); if (unlikely(status)) - goto out; + return status; + if (cb) { status = decode_cb_sequence4res(xdr, cb); - if (unlikely(status)) - goto out; + if (unlikely(status || cb->cb_status)) + return status; } - status = decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &nfserr); - if (unlikely(status)) - goto out; - if (unlikely(nfserr != NFS4_OK)) - status = nfs_cb_stat_to_errno(nfserr); -out: - return status; + return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status); } #endif /* CONFIG_NFSD_PNFS */ @@ -898,13 +879,6 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) if (!nfsd41_cb_get_slot(clp, task)) return; } - spin_lock(&clp->cl_lock); - if (list_empty(&cb->cb_per_client)) { - /* This is the first call, not a restart */ - cb->cb_done = false; - list_add(&cb->cb_per_client, &clp->cl_callbacks); - } - spin_unlock(&clp->cl_lock); rpc_call_start(task); } @@ -918,22 +892,33 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) if (clp->cl_minorversion) { /* No need for lock, access serialized in nfsd4_cb_prepare */ - ++clp->cl_cb_session->se_cb_seq_nr; + if (!task->tk_status) + ++clp->cl_cb_session->se_cb_seq_nr; clear_bit(0, &clp->cl_cb_slot_busy); rpc_wake_up_next(&clp->cl_cb_waitq); dprintk("%s: freed slot, new seqid=%d\n", __func__, clp->cl_cb_session->se_cb_seq_nr); } - if (clp->cl_cb_client != task->tk_client) { - /* We're shutting down or changing cl_cb_client; leave - * it to nfsd4_process_cb_update to restart the call if - * necessary. */ + /* + * If the backchannel connection was shut down while this + * task was queued, we need to resubmit it after setting up + * a new backchannel connection. + * + * Note that if we lost our callback connection permanently + * the submission code will error out, so we don't need to + * handle that case here. + */ + if (task->tk_flags & RPC_TASK_KILLED) { + task->tk_status = 0; + cb->cb_need_restart = true; return; } - if (cb->cb_done) - return; + if (cb->cb_status) { + WARN_ON_ONCE(task->tk_status); + task->tk_status = cb->cb_status; + } switch (cb->cb_ops->done(cb, task)) { case 0: @@ -949,21 +934,17 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) default: BUG(); } - cb->cb_done = true; } static void nfsd4_cb_release(void *calldata) { struct nfsd4_callback *cb = calldata; - struct nfs4_client *clp = cb->cb_clp; - - if (cb->cb_done) { - spin_lock(&clp->cl_lock); - list_del(&cb->cb_per_client); - spin_unlock(&clp->cl_lock); + if (cb->cb_need_restart) + nfsd4_run_cb(cb); + else cb->cb_ops->release(cb); - } + } static const struct rpc_call_ops nfsd4_cb_ops = { @@ -1058,9 +1039,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) nfsd4_mark_cb_down(clp, err); return; } - /* Yay, the callback channel's back! Restart any callbacks: */ - list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client) - queue_work(callback_wq, &cb->cb_work); } static void @@ -1071,8 +1049,12 @@ nfsd4_run_cb_work(struct work_struct *work) struct nfs4_client *clp = cb->cb_clp; struct rpc_clnt *clnt; - if (cb->cb_ops && cb->cb_ops->prepare) - cb->cb_ops->prepare(cb); + if (cb->cb_need_restart) { + cb->cb_need_restart = false; + } else { + if (cb->cb_ops && cb->cb_ops->prepare) + cb->cb_ops->prepare(cb); + } if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) nfsd4_process_cb_update(cb); @@ -1084,6 +1066,15 @@ nfsd4_run_cb_work(struct work_struct *work) cb->cb_ops->release(cb); return; } + + /* + * Don't send probe messages for 4.1 or later. + */ + if (!cb->cb_ops && clp->cl_minorversion) { + clp->cl_cb_state = NFSD4_CB_UP; + return; + } + cb->cb_msg.rpc_cred = clp->cl_cb_cred; rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb); @@ -1098,8 +1089,8 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, cb->cb_msg.rpc_resp = cb; cb->cb_ops = ops; INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); - INIT_LIST_HEAD(&cb->cb_per_client); - cb->cb_done = true; + cb->cb_status = 0; + cb->cb_need_restart = false; } void nfsd4_run_cb(struct nfsd4_callback *cb) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 38f2d7a..039f9c8a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -94,6 +94,7 @@ static struct kmem_cache *lockowner_slab; static struct kmem_cache *file_slab; static struct kmem_cache *stateid_slab; static struct kmem_cache *deleg_slab; +static struct kmem_cache *odstate_slab; static void free_session(struct nfsd4_session *); @@ -281,6 +282,7 @@ put_nfs4_file(struct nfs4_file *fi) if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { hlist_del_rcu(&fi->fi_hash); spin_unlock(&state_lock); + WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); } @@ -471,6 +473,86 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) __nfs4_file_put_access(fp, O_RDONLY); } +/* + * Allocate a new open/delegation state counter. This is needed for + * pNFS for proper return on close semantics. + * + * Note that we only allocate it for pNFS-enabled exports, otherwise + * all pointers to struct nfs4_clnt_odstate are always NULL. + */ +static struct nfs4_clnt_odstate * +alloc_clnt_odstate(struct nfs4_client *clp) +{ + struct nfs4_clnt_odstate *co; + + co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); + if (co) { + co->co_client = clp; + atomic_set(&co->co_odcount, 1); + } + return co; +} + +static void +hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) +{ + struct nfs4_file *fp = co->co_file; + + lockdep_assert_held(&fp->fi_lock); + list_add(&co->co_perfile, &fp->fi_clnt_odstate); +} + +static inline void +get_clnt_odstate(struct nfs4_clnt_odstate *co) +{ + if (co) + atomic_inc(&co->co_odcount); +} + +static void +put_clnt_odstate(struct nfs4_clnt_odstate *co) +{ + struct nfs4_file *fp; + + if (!co) + return; + + fp = co->co_file; + if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { + list_del(&co->co_perfile); + spin_unlock(&fp->fi_lock); + + nfsd4_return_all_file_layouts(co->co_client, fp); + kmem_cache_free(odstate_slab, co); + } +} + +static struct nfs4_clnt_odstate * +find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) +{ + struct nfs4_clnt_odstate *co; + struct nfs4_client *cl; + + if (!new) + return NULL; + + cl = new->co_client; + + spin_lock(&fp->fi_lock); + list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { + if (co->co_client == cl) { + get_clnt_odstate(co); + goto out; + } + } + co = new; + co->co_file = fp; + hash_clnt_odstate_locked(new); +out: + spin_unlock(&fp->fi_lock); + return co; +} + struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab) { @@ -606,7 +688,8 @@ static void block_delegations(struct knfsd_fh *fh) } static struct nfs4_delegation * -alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) +alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, + struct nfs4_clnt_odstate *odstate) { struct nfs4_delegation *dp; long n; @@ -631,6 +714,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) INIT_LIST_HEAD(&dp->dl_perfile); INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_recall_lru); + dp->dl_clnt_odstate = odstate; + get_clnt_odstate(odstate); dp->dl_type = NFS4_OPEN_DELEGATE_READ; dp->dl_retries = 1; nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, @@ -714,6 +799,7 @@ static void destroy_delegation(struct nfs4_delegation *dp) spin_lock(&state_lock); unhash_delegation_locked(dp); spin_unlock(&state_lock); + put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); nfs4_put_stid(&dp->dl_stid); } @@ -724,6 +810,7 @@ static void revoke_delegation(struct nfs4_delegation *dp) WARN_ON(!list_empty(&dp->dl_recall_lru)); + put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); if (clp->cl_minorversion == 0) @@ -933,6 +1020,7 @@ static void nfs4_free_ol_stateid(struct nfs4_stid *stid) { struct nfs4_ol_stateid *stp = openlockstateid(stid); + put_clnt_odstate(stp->st_clnt_odstate); release_all_access(stp); if (stp->st_stateowner) nfs4_put_stateowner(stp->st_stateowner); @@ -1538,7 +1626,6 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) INIT_LIST_HEAD(&clp->cl_openowners); INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_lru); - INIT_LIST_HEAD(&clp->cl_callbacks); INIT_LIST_HEAD(&clp->cl_revoked); #ifdef CONFIG_NFSD_PNFS INIT_LIST_HEAD(&clp->cl_lo_states); @@ -1634,6 +1721,7 @@ __destroy_client(struct nfs4_client *clp) while (!list_empty(&reaplist)) { dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); + put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); nfs4_put_stid(&dp->dl_stid); } @@ -3057,6 +3145,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, spin_lock_init(&fp->fi_lock); INIT_LIST_HEAD(&fp->fi_stateids); INIT_LIST_HEAD(&fp->fi_delegations); + INIT_LIST_HEAD(&fp->fi_clnt_odstate); fh_copy_shallow(&fp->fi_fhandle, fh); fp->fi_deleg_file = NULL; fp->fi_had_conflict = false; @@ -3073,6 +3162,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, void nfsd4_free_slabs(void) { + kmem_cache_destroy(odstate_slab); kmem_cache_destroy(openowner_slab); kmem_cache_destroy(lockowner_slab); kmem_cache_destroy(file_slab); @@ -3103,8 +3193,14 @@ nfsd4_init_slabs(void) sizeof(struct nfs4_delegation), 0, 0, NULL); if (deleg_slab == NULL) goto out_free_stateid_slab; + odstate_slab = kmem_cache_create("nfsd4_odstate", + sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); + if (odstate_slab == NULL) + goto out_free_deleg_slab; return 0; +out_free_deleg_slab: + kmem_cache_destroy(deleg_slab); out_free_stateid_slab: kmem_cache_destroy(stateid_slab); out_free_file_slab: @@ -3581,6 +3677,14 @@ alloc_stateid: open->op_stp = nfs4_alloc_open_stateid(clp); if (!open->op_stp) return nfserr_jukebox; + + if (nfsd4_has_session(cstate) && + (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { + open->op_odstate = alloc_clnt_odstate(clp); + if (!open->op_odstate) + return nfserr_jukebox; + } + return nfs_ok; } @@ -3869,7 +3973,7 @@ out_fput: static struct nfs4_delegation * nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, - struct nfs4_file *fp) + struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) { int status; struct nfs4_delegation *dp; @@ -3877,7 +3981,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, if (fp->fi_had_conflict) return ERR_PTR(-EAGAIN); - dp = alloc_init_deleg(clp, fh); + dp = alloc_init_deleg(clp, fh, odstate); if (!dp) return ERR_PTR(-ENOMEM); @@ -3903,6 +4007,7 @@ out_unlock: spin_unlock(&state_lock); out: if (status) { + put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_stid(&dp->dl_stid); return ERR_PTR(status); } @@ -3980,7 +4085,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, default: goto out_no_deleg; } - dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file); + dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); if (IS_ERR(dp)) goto out_no_deleg; @@ -4069,6 +4174,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf release_open_stateid(stp); goto out; } + + stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, + open->op_odstate); + if (stp->st_clnt_odstate == open->op_odstate) + open->op_odstate = NULL; } update_stateid(&stp->st_stid.sc_stateid); memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); @@ -4129,6 +4239,8 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, kmem_cache_free(file_slab, open->op_file); if (open->op_stp) nfs4_put_stid(&open->op_stp->st_stid); + if (open->op_odstate) + kmem_cache_free(odstate_slab, open->op_odstate); } __be32 @@ -4385,10 +4497,17 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s return nfserr_old_stateid; } +static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) +{ + if (ols->st_stateowner->so_is_open_owner && + !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) + return nfserr_bad_stateid; + return nfs_ok; +} + static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) { struct nfs4_stid *s; - struct nfs4_ol_stateid *ols; __be32 status = nfserr_bad_stateid; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) @@ -4418,13 +4537,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) break; case NFS4_OPEN_STID: case NFS4_LOCK_STID: - ols = openlockstateid(s); - if (ols->st_stateowner->so_is_open_owner - && !(openowner(ols->st_stateowner)->oo_flags - & NFS4_OO_CONFIRMED)) - status = nfserr_bad_stateid; - else - status = nfs_ok; + status = nfsd4_check_openowner_confirmed(openlockstateid(s)); break; default: printk("unknown stateid type %x\n", s->sc_type); @@ -4516,8 +4629,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, status = nfs4_check_fh(current_fh, stp); if (status) goto out; - if (stp->st_stateowner->so_is_open_owner - && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) + status = nfsd4_check_openowner_confirmed(stp); + if (status) goto out; status = nfs4_check_openmode(stp, flags); if (status) @@ -4852,9 +4965,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, update_stateid(&stp->st_stid.sc_stateid); memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); - nfsd4_return_all_file_layouts(stp->st_stateowner->so_client, - stp->st_stid.sc_file); - nfsd4_close_open_stateid(stp); /* put reference from nfs4_preprocess_seqid_op */ @@ -6488,6 +6598,7 @@ nfs4_state_shutdown_net(struct net *net) list_for_each_safe(pos, next, &reaplist) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); + put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); nfs4_put_stid(&dp->dl_stid); } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4f3bfeb..dbc4f85 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -63,12 +63,12 @@ typedef struct { struct nfsd4_callback { struct nfs4_client *cb_clp; - struct list_head cb_per_client; u32 cb_minorversion; struct rpc_message cb_msg; struct nfsd4_callback_ops *cb_ops; struct work_struct cb_work; - bool cb_done; + int cb_status; + bool cb_need_restart; }; struct nfsd4_callback_ops { @@ -126,6 +126,7 @@ struct nfs4_delegation { struct list_head dl_perfile; struct list_head dl_perclnt; struct list_head dl_recall_lru; /* delegation recalled */ + struct nfs4_clnt_odstate *dl_clnt_odstate; u32 dl_type; time_t dl_time; /* For recall: */ @@ -332,7 +333,6 @@ struct nfs4_client { int cl_cb_state; struct nfsd4_callback cl_cb_null; struct nfsd4_session *cl_cb_session; - struct list_head cl_callbacks; /* list of in-progress callbacks */ /* for all client information that callback code might need: */ spinlock_t cl_lock; @@ -465,6 +465,17 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) } /* + * Per-client state indicating no. of opens and outstanding delegations + * on a file from a particular client.'od' stands for 'open & delegation' + */ +struct nfs4_clnt_odstate { + struct nfs4_client *co_client; + struct nfs4_file *co_file; + struct list_head co_perfile; + atomic_t co_odcount; +}; + +/* * nfs4_file: a file opened by some number of (open) nfs4_stateowners. * * These objects are global. nfsd keeps one instance of a nfs4_file per @@ -485,6 +496,7 @@ struct nfs4_file { struct list_head fi_delegations; struct rcu_head fi_rcu; }; + struct list_head fi_clnt_odstate; /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ struct file * fi_fds[3]; /* @@ -526,6 +538,7 @@ struct nfs4_ol_stateid { struct list_head st_perstateowner; struct list_head st_locks; struct nfs4_stateowner * st_stateowner; + struct nfs4_clnt_odstate * st_clnt_odstate; unsigned char st_access_bmap; unsigned char st_deny_bmap; struct nfs4_ol_stateid * st_openstp; diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index f982ae8..2f8c092 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -247,6 +247,7 @@ struct nfsd4_open { struct nfs4_openowner *op_openowner; /* used during processing */ struct nfs4_file *op_file; /* used during processing */ struct nfs4_ol_stateid *op_stp; /* used during processing */ + struct nfs4_clnt_odstate *op_odstate; /* used during processing */ struct nfs4_acl *op_acl; struct xdr_netobj op_label; }; diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 059f371..919fd5b 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -388,7 +388,7 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node, nchildren = nilfs_btree_node_get_nchildren(node); if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN || - level > NILFS_BTREE_LEVEL_MAX || + level >= NILFS_BTREE_LEVEL_MAX || nchildren < 0 || nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) { pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n", diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index a6944b2..fdf4b41 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -757,6 +757,19 @@ lookup: if (tmpres) { spin_unlock(&dlm->spinlock); spin_lock(&tmpres->spinlock); + + /* + * Right after dlm spinlock was released, dlm_thread could have + * purged the lockres. Check if lockres got unhashed. If so + * start over. + */ + if (hlist_unhashed(&tmpres->hash_node)) { + spin_unlock(&tmpres->spinlock); + dlm_lockres_put(tmpres); + tmpres = NULL; + goto lookup; + } + /* Wait on the thread that is mastering the resource */ if (tmpres->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { __dlm_wait_on_lockres(tmpres); diff --git a/fs/splice.c b/fs/splice.c index 476024b..bfe62ae 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1161,7 +1161,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, long ret, bytes; umode_t i_mode; size_t len; - int i, flags; + int i, flags, more; /* * We require the input being a regular file, as we don't want to @@ -1204,6 +1204,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, * Don't block on output, we have to drain the direct pipe. */ sd->flags &= ~SPLICE_F_NONBLOCK; + more = sd->flags & SPLICE_F_MORE; while (len) { size_t read_len; @@ -1217,6 +1218,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, sd->total_len = read_len; /* + * If more data is pending, set SPLICE_F_MORE + * If this is the last data and SPLICE_F_MORE was not set + * initially, clears it. + */ + if (read_len < len) + sd->flags |= SPLICE_F_MORE; + else if (!more) + sd->flags &= ~SPLICE_F_MORE; + /* * NOTE: nonblocking mode only applies to the input. We * must not do the output in nonblocking mode as then we * could get stuck data in the internal pipe: diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 2dd405c..45c39a3 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -186,6 +186,7 @@ {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x665f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index a1b25e3..b7299fe 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -220,7 +220,7 @@ enum rq_flag_bits { /* This mask is used for both bio and request merge checking */ #define REQ_NOMERGE_FLAGS \ - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA) + (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ) #define REQ_RAHEAD (1ULL << __REQ_RAHEAD) #define REQ_THROTTLED (1ULL << __REQ_THROTTLED) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index cdf13ca..371e560 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -9,10 +9,24 @@ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) - /* Optimization barrier */ + /* The "volatile" is due to gcc bugs */ #define barrier() __asm__ __volatile__("": : :"memory") +/* + * This version is i.e. to prevent dead stores elimination on @ptr + * where gcc and llvm may behave differently when otherwise using + * normal barrier(): while gcc behavior gets along with a normal + * barrier(), llvm needs an explicit input variable to be assumed + * clobbered. The issue is as follows: while the inline asm might + * access any memory it wants, the compiler could have fit all of + * @ptr into memory registers instead, and since @ptr never escaped + * from that, it proofed that the inline asm wasn't touching any of + * it. This version works well with both compilers, i.e. we're telling + * the compiler that the inline asm absolutely may see the contents + * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495 + */ +#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory") /* * This macro obfuscates arithmetic on a variable address so that gcc diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index ba147a1..0c9a2f2 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -13,9 +13,12 @@ /* Intel ECC compiler doesn't support gcc specific asm stmts. * It uses intrinsics to do the equivalent things. */ +#undef barrier_data #undef RELOC_HIDE #undef OPTIMIZER_HIDE_VAR +#define barrier_data(ptr) barrier() + #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ __ptr = (unsigned long) (ptr); \ diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 0e41ca0..8677225 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -169,6 +169,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # define barrier() __memory_barrier() #endif +#ifndef barrier_data +# define barrier_data(ptr) barrier() +#endif + /* Unreachable code */ #ifndef unreachable # define unreachable() do { } while (1) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 46e83c2..f9ecf63 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -46,7 +46,7 @@ const char *ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int len); const char *ftrace_print_array_seq(struct trace_seq *p, - const void *buf, int buf_len, + const void *buf, int count, size_t el_size); struct trace_iterator; diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 97a9373..15928f0 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -30,6 +30,7 @@ struct vm_area_struct; #define ___GFP_HARDWALL 0x20000u #define ___GFP_THISNODE 0x40000u #define ___GFP_RECLAIMABLE 0x80000u +#define ___GFP_NOACCOUNT 0x100000u #define ___GFP_NOTRACK 0x200000u #define ___GFP_NO_KSWAPD 0x400000u #define ___GFP_OTHER_NODE 0x800000u @@ -87,6 +88,7 @@ struct vm_area_struct; #define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */ #define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */ #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */ +#define __GFP_NOACCOUNT ((__force gfp_t)___GFP_NOACCOUNT) /* Don't account to kmemcg */ #define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) /* Don't track with kmemcheck */ #define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 36ec4ae..9de976b 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -95,8 +95,6 @@ struct device_node; -extern struct irq_chip gic_arch_extn; - void gic_set_irqchip_flags(unsigned long flags); void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); diff --git a/include/linux/libata.h b/include/linux/libata.h index 8dad4a3..28aeae4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -205,6 +205,7 @@ enum { ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ + ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -309,6 +310,12 @@ enum { */ ATA_TMOUT_PMP_SRST_WAIT = 5000, + /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might + * be a spurious PHY event, so ignore the first PHY event that + * occurs within 10s after the policy change. + */ + ATA_TMOUT_SPURIOUS_PHY = 10000, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -788,6 +795,8 @@ struct ata_link { struct ata_eh_context eh_context; struct ata_device device[ATA_MAX_DEVICES]; + + unsigned long last_lpm_change; /* when last LPM change happened */ }; #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) @@ -1201,6 +1210,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); +extern bool sata_lpm_ignore_phy_events(struct ata_link *link); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 72dff5f..6c89181 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -463,6 +463,8 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order) if (!memcg_kmem_enabled()) return true; + if (gfp & __GFP_NOACCOUNT) + return true; /* * __GFP_NOFAIL allocations will move on even if charging is not * possible. Therefore we don't even try, and have this allocation @@ -522,6 +524,8 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp) { if (!memcg_kmem_enabled()) return cachep; + if (gfp & __GFP_NOACCOUNT) + return cachep; if (gfp & __GFP_NOFAIL) return cachep; if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD)) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1899c74..05b9a69 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -25,7 +25,6 @@ #ifndef _LINUX_NETDEVICE_H #define _LINUX_NETDEVICE_H -#include <linux/pm_qos.h> #include <linux/timer.h> #include <linux/bug.h> #include <linux/delay.h> @@ -1499,8 +1498,6 @@ enum netdev_priv_flags { * * @qdisc_tx_busylock: XXX: need comments on this one * - * @pm_qos_req: Power Management QoS object - * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index ff3fea3..9abb763 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -460,7 +460,7 @@ struct nilfs_btree_node { /* level */ #define NILFS_BTREE_LEVEL_DATA 0 #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1) -#define NILFS_BTREE_LEVEL_MAX 14 +#define NILFS_BTREE_LEVEL_MAX 14 /* Max level (exclusive) */ /** * struct nilfs_palloc_group_desc - block group descriptor diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 38cff8f..2f7b9a4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2541,10 +2541,6 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 -#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 -#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 -#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150 -#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h index 6341f5b..a30b172 100644 --- a/include/linux/sched/rt.h +++ b/include/linux/sched/rt.h @@ -18,7 +18,7 @@ static inline int rt_task(struct task_struct *p) #ifdef CONFIG_RT_MUTEXES extern int rt_mutex_getprio(struct task_struct *p); extern void rt_mutex_setprio(struct task_struct *p, int prio); -extern int rt_mutex_check_prio(struct task_struct *task, int newprio); +extern int rt_mutex_get_effective_prio(struct task_struct *task, int newprio); extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task); extern void rt_mutex_adjust_pi(struct task_struct *p); static inline bool tsk_is_pi_blocked(struct task_struct *tsk) @@ -31,9 +31,10 @@ static inline int rt_mutex_getprio(struct task_struct *p) return p->normal_prio; } -static inline int rt_mutex_check_prio(struct task_struct *task, int newprio) +static inline int rt_mutex_get_effective_prio(struct task_struct *task, + int newprio) { - return 0; + return newprio; } static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0caa3a2..3b29115 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -145,11 +145,19 @@ struct tcp_sock { * read the code and the spec side by side (and laugh ...) * See RFC793 and RFC1122. The RFC writes these in capitals. */ + u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived + * sum(delta(rcv_nxt)), or how many bytes + * were acked. + */ u32 rcv_nxt; /* What we want to receive next */ u32 copied_seq; /* Head of yet unread data */ u32 rcv_wup; /* rcv_nxt on last window update sent */ u32 snd_nxt; /* Next sequence we send */ + u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked + * sum(delta(snd_una)), or how many bytes + * were acked. + */ u32 snd_una; /* First byte we want an ack for */ u32 snd_sml; /* Last byte of the most recently transmitted small packet */ u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ diff --git a/include/linux/tty.h b/include/linux/tty.h index fe5623c..d76631f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -339,6 +339,7 @@ struct tty_file_private { #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ #define TTY_DEBUG 4 /* Debugging */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ +#define TTY_OTHER_DONE 6 /* Closed pty has completed input processing */ #define TTY_LDISC_OPEN 11 /* Line discipline is open */ #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ @@ -462,7 +463,6 @@ extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); extern void __do_SAK(struct tty_struct *tty); extern void no_tty(void); -extern void tty_flush_to_ldisc(struct tty_struct *tty); extern void tty_buffer_free_all(struct tty_port *port); extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); extern void tty_buffer_init(struct tty_port *port); diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 0ee05da..0383552 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -109,12 +109,12 @@ static inline bool gid_lte(kgid_t left, kgid_t right) static inline bool uid_valid(kuid_t uid) { - return !uid_eq(uid, INVALID_UID); + return __kuid_val(uid) != (uid_t) -1; } static inline bool gid_valid(kgid_t gid) { - return !gid_eq(gid, INVALID_GID); + return __kgid_val(gid) != (gid_t) -1; } #ifdef CONFIG_USER_NS diff --git a/include/linux/util_macros.h b/include/linux/util_macros.h index d5f4fb6..f9b2ce5 100644 --- a/include/linux/util_macros.h +++ b/include/linux/util_macros.h @@ -5,7 +5,7 @@ ({ \ typeof(as) __fc_i, __fc_as = (as) - 1; \ typeof(x) __fc_x = (x); \ - typeof(*a) *__fc_a = (a); \ + typeof(*a) const *__fc_a = (a); \ for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) { \ if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] + \ __fc_a[__fc_i + 1], 2)) \ diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index eeda676..6ea16c8 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -30,11 +30,13 @@ struct wpan_phy_cca; struct cfg802154_ops { struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); int (*add_virtual_intf)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr); int (*del_virtual_intf)(struct wpan_phy *wpan_phy, diff --git a/include/net/codel.h b/include/net/codel.h index aeee280..1e18005 100644 --- a/include/net/codel.h +++ b/include/net/codel.h @@ -120,11 +120,13 @@ static inline u32 codel_time_to_us(codel_time_t val) * struct codel_params - contains codel parameters * @target: target queue size (in time units) * @interval: width of moving time window + * @mtu: device mtu, or minimal queue backlog in bytes. * @ecn: is Explicit Congestion Notification enabled */ struct codel_params { codel_time_t target; codel_time_t interval; + u32 mtu; bool ecn; }; @@ -166,10 +168,12 @@ struct codel_stats { u32 ecn_mark; }; -static void codel_params_init(struct codel_params *params) +static void codel_params_init(struct codel_params *params, + const struct Qdisc *sch) { params->interval = MS2TIME(100); params->target = MS2TIME(5); + params->mtu = psched_mtu(qdisc_dev(sch)); params->ecn = false; } @@ -180,7 +184,7 @@ static void codel_vars_init(struct codel_vars *vars) static void codel_stats_init(struct codel_stats *stats) { - stats->maxpacket = 256; + stats->maxpacket = 0; } /* @@ -234,7 +238,7 @@ static bool codel_should_drop(const struct sk_buff *skb, stats->maxpacket = qdisc_pkt_len(skb); if (codel_time_before(vars->ldelay, params->target) || - sch->qstats.backlog <= stats->maxpacket) { + sch->qstats.backlog <= params->mtu) { /* went below - stay below for at least interval */ vars->first_above_time = 0; return false; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b4bef11..8e3668b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1666,6 +1666,8 @@ struct ieee80211_tx_control { * @sta: station table entry, %NULL for per-vif queue * @tid: the TID for this queue (unused for per-vif queue) * @ac: the AC for this queue + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). * * The driver can obtain packets from this queue by calling * ieee80211_tx_dequeue(). diff --git a/include/net/mac802154.h b/include/net/mac802154.h index e18e7fd..7df28a4 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -247,19 +247,109 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) __put_unaligned_memmove64(swab64p(le64_src), be64_dst); } -/* Basic interface to register ieee802154 device */ +/** + * ieee802154_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac802154 allocates a private data area for the driver pointed to by + * @priv in &struct ieee802154_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device + * + * Return: A pointer to the new hardware device, or %NULL on error. + */ struct ieee802154_hw * ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); + +/** + * ieee802154_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee802154_unregister_hw() + * before calling this function. + * + * @hw: the hardware to free + */ void ieee802154_free_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_register_hw - Register hardware device + * + * You must call this function before any other functions in + * mac802154. Note that before a hardware can be registered, you + * need to fill the contained wpan_phy's information. + * + * @hw: the device to register as returned by ieee802154_alloc_hw() + * + * Return: 0 on success. An error code otherwise. + */ int ieee802154_register_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_unregister_hw - Unregister a hardware device + * + * This function instructs mac802154 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ void ieee802154_unregister_hw(struct ieee802154_hw *hw); +/** + * ieee802154_rx - receive frame + * + * Use this function to hand received frames to mac802154. The receive + * buffer in @skb must start with an IEEE 802.15.4 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee802154 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + */ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); + +/** + * ieee802154_rx_irqsafe - receive frame + * + * Like ieee802154_rx() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + * @lqi: link quality indicator + */ void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi); - +/** + * ieee802154_wake_queue - wake ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_wake_queue. + */ void ieee802154_wake_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_stop_queue - stop ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_stop_queue. + */ void ieee802154_stop_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_xmit_complete - frame transmission complete + * + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * @skb: buffer for transmission + * @ifs_handling: indicate interframe space handling + */ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, bool ifs_handling); diff --git a/include/net/tcp.h b/include/net/tcp.h index 051dc5c2..6d204f3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -576,7 +576,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) } /* tcp.c */ -void tcp_get_info(const struct sock *, struct tcp_info *); +void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, @@ -804,6 +804,8 @@ enum tcp_ca_ack_event_flags { /* Requires ECN/ECT set on all packets */ #define TCP_CONG_NEEDS_ECN 0x2 +union tcp_cc_info; + struct tcp_congestion_ops { struct list_head list; u32 key; @@ -829,7 +831,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); /* get info for inet_diag (optional) */ - int (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); + size_t (*get_info)(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); char name[TCP_CA_NAME_MAX]; struct module *owner; diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index ce55906..ac54c27 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -160,7 +160,7 @@ static inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid) } /* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ -static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) +static inline void rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) { if (ipv6_addr_v4mapped((struct in6_addr *)gid)) { struct sockaddr_in *out_in = (struct sockaddr_in *)out; @@ -173,7 +173,6 @@ static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) out_in->sin6_family = AF_INET6; memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); } - return 0; } static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 0e3ff30..39ed2d2 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -105,7 +105,8 @@ enum ib_cm_data_size { IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, IB_CM_SIDR_REP_INFO_LENGTH = 72, - IB_CM_COMPARE_SIZE = 64 + /* compare done u32 at a time */ + IB_CM_COMPARE_SIZE = (64 / sizeof(u32)) }; struct ib_cm_id; @@ -337,8 +338,8 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); #define IB_SDP_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFFFF0000ULL) struct ib_cm_compare_data { - u8 data[IB_CM_COMPARE_SIZE]; - u8 mask[IB_CM_COMPARE_SIZE]; + u32 data[IB_CM_COMPARE_SIZE]; + u32 mask[IB_CM_COMPARE_SIZE]; }; /** diff --git a/include/rdma/iw_portmap.h b/include/rdma/iw_portmap.h index 928b277..fda3167 100644 --- a/include/rdma/iw_portmap.h +++ b/include/rdma/iw_portmap.h @@ -148,6 +148,16 @@ int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *); int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *); /** + * iwpm_remote_info_cb - Process remote connecting peer address info, which + * the port mapper has received from the connecting peer + * + * @cb: Contains the received message (payload and netlink header) + * + * Stores the IPv4/IPv6 address info in a hash table + */ +int iwpm_remote_info_cb(struct sk_buff *, struct netlink_callback *); + +/** * iwpm_mapping_error_cb - Process port mapper notification for error * * @skb: @@ -175,6 +185,21 @@ int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *); int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *); /** + * iwpm_get_remote_info - Get the remote connecting peer address info + * + * @mapped_loc_addr: Mapped local address of the listening peer + * @mapped_rem_addr: Mapped remote address of the connecting peer + * @remote_addr: To store the remote address of the connecting peer + * @nl_client: The index of the netlink client + * + * The remote address info is retrieved and provided to the client in + * the remote_addr. After that it is removed from the hash table + */ +int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr, + struct sockaddr_storage *mapped_rem_addr, + struct sockaddr_storage *remote_addr, u8 nl_client); + +/** * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address * info in a hash table * @local_addr: Local ip/tcp address diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index d65c0a0..c7093c7 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h @@ -143,4 +143,8 @@ struct tcp_dctcp_info { __u32 dctcp_ab_tot; }; +union tcp_cc_info { + struct tcpvegas_info vegas; + struct tcp_dctcp_info dctcp; +}; #endif /* _UAPI_INET_DIAG_H_ */ diff --git a/include/uapi/linux/mpls.h b/include/uapi/linux/mpls.h index bc9abfe..139d4dd 100644 --- a/include/uapi/linux/mpls.h +++ b/include/uapi/linux/mpls.h @@ -31,4 +31,14 @@ struct mpls_label { #define MPLS_LS_TTL_MASK 0x000000FF #define MPLS_LS_TTL_SHIFT 0 +/* Reserved labels */ +#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */ +#define MPLS_LABEL_RTALERT 1 /* RFC3032 */ +#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */ +#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */ +#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */ +#define MPLS_LABEL_GAL 13 /* RFC5586 */ +#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */ +#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ + #endif /* _UAPI_MPLS_H */ diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 3b97183..faa72f4 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -112,6 +112,7 @@ enum { #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ #define TCP_TIMESTAMP 24 #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ +#define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ struct tcp_repair_opt { __u32 opt_code; @@ -189,6 +190,8 @@ struct tcp_info { __u64 tcpi_pacing_rate; __u64 tcpi_max_pacing_rate; + __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ + __u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ }; /* for TCP_MD5SIG socket option */ diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index de69170..6e4bb42 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -37,6 +37,7 @@ enum { RDMA_NL_IWPM_ADD_MAPPING, RDMA_NL_IWPM_QUERY_MAPPING, RDMA_NL_IWPM_REMOVE_MAPPING, + RDMA_NL_IWPM_REMOTE_INFO, RDMA_NL_IWPM_HANDLE_ERR, RDMA_NL_IWPM_MAPINFO, RDMA_NL_IWPM_MAPINFO_NUM, diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 143ca5f..4478f4b 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -191,6 +191,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count); void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item); +int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item); /* Perform a batch of grant map/copy operations. Retry every batch slot diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index c643e6a..0ce4f32 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -13,6 +13,7 @@ void xen_arch_post_suspend(int suspend_cancelled); void xen_timer_resume(void); void xen_arch_resume(void); +void xen_arch_suspend(void); void xen_resume_notifier_register(struct notifier_block *nb); void xen_resume_notifier_unregister(struct notifier_block *nb); diff --git a/init/do_mounts.c b/init/do_mounts.c index 8369ffa..a95bbdb 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -225,10 +225,11 @@ dev_t name_to_dev_t(const char *name) #endif if (strncmp(name, "/dev/", 5) != 0) { - unsigned maj, min; + unsigned maj, min, offset; char dummy; - if (sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) { + if ((sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) || + (sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3)) { res = MKDEV(maj, min); if (maj != MAJOR(res) || min != MINOR(res)) goto fail; diff --git a/kernel/events/core.c b/kernel/events/core.c index 81aa3a4..1a3bf48 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -913,10 +913,30 @@ static void put_ctx(struct perf_event_context *ctx) * Those places that change perf_event::ctx will hold both * perf_event_ctx::mutex of the 'old' and 'new' ctx value. * - * Lock ordering is by mutex address. There is one other site where - * perf_event_context::mutex nests and that is put_event(). But remember that - * that is a parent<->child context relation, and migration does not affect - * children, therefore these two orderings should not interact. + * Lock ordering is by mutex address. There are two other sites where + * perf_event_context::mutex nests and those are: + * + * - perf_event_exit_task_context() [ child , 0 ] + * __perf_event_exit_task() + * sync_child_event() + * put_event() [ parent, 1 ] + * + * - perf_event_init_context() [ parent, 0 ] + * inherit_task_group() + * inherit_group() + * inherit_event() + * perf_event_alloc() + * perf_init_event() + * perf_try_init_event() [ child , 1 ] + * + * While it appears there is an obvious deadlock here -- the parent and child + * nesting levels are inverted between the two. This is in fact safe because + * life-time rules separate them. That is an exiting task cannot fork, and a + * spawning task cannot (yet) exit. + * + * But remember that that these are parent<->child context relations, and + * migration does not affect children, therefore these two orderings should not + * interact. * * The change in perf_event::ctx does not affect children (as claimed above) * because the sys_perf_event_open() case will install a new event and break @@ -3657,9 +3677,6 @@ static void perf_remove_from_owner(struct perf_event *event) } } -/* - * Called when the last reference to the file is gone. - */ static void put_event(struct perf_event *event) { struct perf_event_context *ctx; @@ -3697,6 +3714,9 @@ int perf_event_release_kernel(struct perf_event *event) } EXPORT_SYMBOL_GPL(perf_event_release_kernel); +/* + * Called when the last reference to the file is gone. + */ static int perf_release(struct inode *inode, struct file *file) { put_event(file->private_data); @@ -7364,7 +7384,12 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) return -ENODEV; if (event->group_leader != event) { - ctx = perf_event_ctx_lock(event->group_leader); + /* + * This ctx->mutex can nest when we're called through + * inheritance. See the perf_event_ctx_lock_nested() comment. + */ + ctx = perf_event_ctx_lock_nested(event->group_leader, + SINGLE_DEPTH_NESTING); BUG_ON(!ctx); } diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c index 988dc58..2feb6fe 100644 --- a/kernel/irq/dummychip.c +++ b/kernel/irq/dummychip.c @@ -57,5 +57,6 @@ struct irq_chip dummy_irq_chip = { .irq_ack = noop, .irq_mask = noop, .irq_unmask = noop, + .flags = IRQCHIP_SKIP_SET_WAKE, }; EXPORT_SYMBOL_GPL(dummy_irq_chip); diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index b732793..b025295 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -265,15 +265,17 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task) } /* - * Called by sched_setscheduler() to check whether the priority change - * is overruled by a possible priority boosting. + * Called by sched_setscheduler() to get the priority which will be + * effective after the change. */ -int rt_mutex_check_prio(struct task_struct *task, int newprio) +int rt_mutex_get_effective_prio(struct task_struct *task, int newprio) { if (!task_has_pi_waiters(task)) - return 0; + return newprio; - return task_top_pi_waiter(task)->task->prio <= newprio; + if (task_top_pi_waiter(task)->task->prio <= newprio) + return task_top_pi_waiter(task)->task->prio; + return newprio; } /* diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 233165d..8cf7304 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -162,11 +162,14 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp); static int kthread_prio = CONFIG_RCU_KTHREAD_PRIO; module_param(kthread_prio, int, 0644); -/* Delay in jiffies for grace-period initialization delays. */ -static int gp_init_delay = IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT) - ? CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY - : 0; +/* Delay in jiffies for grace-period initialization delays, debug only. */ +#ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT +static int gp_init_delay = CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY; module_param(gp_init_delay, int, 0644); +#else /* #ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT */ +static const int gp_init_delay; +#endif /* #else #ifdef CONFIG_RCU_TORTURE_TEST_SLOW_INIT */ +#define PER_RCU_NODE_PERIOD 10 /* Number of grace periods between delays. */ /* * Track the rcutorture test sequence number and the update version @@ -1843,9 +1846,8 @@ static int rcu_gp_init(struct rcu_state *rsp) raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); ACCESS_ONCE(rsp->gp_activity) = jiffies; - if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_SLOW_INIT) && - gp_init_delay > 0 && - !(rsp->gpnum % (rcu_num_nodes * 10))) + if (gp_init_delay > 0 && + !(rsp->gpnum % (rcu_num_nodes * PER_RCU_NODE_PERIOD))) schedule_timeout_uninterruptible(gp_init_delay); } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index fe22f75..57bd333 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3300,15 +3300,18 @@ static void __setscheduler_params(struct task_struct *p, /* Actually do priority change: must hold pi & rq lock. */ static void __setscheduler(struct rq *rq, struct task_struct *p, - const struct sched_attr *attr) + const struct sched_attr *attr, bool keep_boost) { __setscheduler_params(p, attr); /* - * If we get here, there was no pi waiters boosting the - * task. It is safe to use the normal prio. + * Keep a potential priority boosting if called from + * sched_setscheduler(). */ - p->prio = normal_prio(p); + if (keep_boost) + p->prio = rt_mutex_get_effective_prio(p, normal_prio(p)); + else + p->prio = normal_prio(p); if (dl_prio(p->prio)) p->sched_class = &dl_sched_class; @@ -3408,7 +3411,7 @@ static int __sched_setscheduler(struct task_struct *p, int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 : MAX_RT_PRIO - 1 - attr->sched_priority; int retval, oldprio, oldpolicy = -1, queued, running; - int policy = attr->sched_policy; + int new_effective_prio, policy = attr->sched_policy; unsigned long flags; const struct sched_class *prev_class; struct rq *rq; @@ -3590,15 +3593,14 @@ change: oldprio = p->prio; /* - * Special case for priority boosted tasks. - * - * If the new priority is lower or equal (user space view) - * than the current (boosted) priority, we just store the new + * Take priority boosted tasks into account. If the new + * effective priority is unchanged, we just store the new * normal parameters and do not touch the scheduler class and * the runqueue. This will be done when the task deboost * itself. */ - if (rt_mutex_check_prio(p, newprio)) { + new_effective_prio = rt_mutex_get_effective_prio(p, newprio); + if (new_effective_prio == oldprio) { __setscheduler_params(p, attr); task_rq_unlock(rq, p, &flags); return 0; @@ -3612,7 +3614,7 @@ change: put_prev_task(rq, p); prev_class = p->sched_class; - __setscheduler(rq, p, attr); + __setscheduler(rq, p, attr, true); if (running) p->sched_class->set_curr_task(rq); @@ -6997,27 +6999,23 @@ static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action, unsigned long flags; long cpu = (long)hcpu; struct dl_bw *dl_b; + bool overflow; + int cpus; - switch (action & ~CPU_TASKS_FROZEN) { + switch (action) { case CPU_DOWN_PREPARE: - /* explicitly allow suspend */ - if (!(action & CPU_TASKS_FROZEN)) { - bool overflow; - int cpus; - - rcu_read_lock_sched(); - dl_b = dl_bw_of(cpu); + rcu_read_lock_sched(); + dl_b = dl_bw_of(cpu); - raw_spin_lock_irqsave(&dl_b->lock, flags); - cpus = dl_bw_cpus(cpu); - overflow = __dl_overflow(dl_b, cpus, 0, 0); - raw_spin_unlock_irqrestore(&dl_b->lock, flags); + raw_spin_lock_irqsave(&dl_b->lock, flags); + cpus = dl_bw_cpus(cpu); + overflow = __dl_overflow(dl_b, cpus, 0, 0); + raw_spin_unlock_irqrestore(&dl_b->lock, flags); - rcu_read_unlock_sched(); + rcu_read_unlock_sched(); - if (overflow) - return notifier_from_errno(-EBUSY); - } + if (overflow) + return notifier_from_errno(-EBUSY); cpuset_update_active_cpus(false); break; case CPU_DOWN_PREPARE_FROZEN: @@ -7346,7 +7344,7 @@ static void normalize_task(struct rq *rq, struct task_struct *p) queued = task_on_rq_queued(p); if (queued) dequeue_task(rq, p, 0); - __setscheduler(rq, p, &attr); + __setscheduler(rq, p, &attr, false); if (queued) { enqueue_task(rq, p, 0); resched_curr(rq); diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 11dc22a..637a094 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -117,11 +117,7 @@ static int __clockevents_set_state(struct clock_event_device *dev, /* Transition with new state-specific callbacks */ switch (state) { case CLOCK_EVT_STATE_DETACHED: - /* - * This is an internal state, which is guaranteed to go from - * SHUTDOWN to DETACHED. No driver interaction required. - */ - return 0; + /* The clockevent device is getting replaced. Shut it down. */ case CLOCK_EVT_STATE_SHUTDOWN: return dev->set_state_shutdown(dev); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 692bf71..25a086b 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -178,12 +178,13 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) EXPORT_SYMBOL(ftrace_print_hex_seq); const char * -ftrace_print_array_seq(struct trace_seq *p, const void *buf, int buf_len, +ftrace_print_array_seq(struct trace_seq *p, const void *buf, int count, size_t el_size) { const char *ret = trace_seq_buffer_ptr(p); const char *prefix = ""; void *ptr = (void *)buf; + size_t buf_len = count * el_size; trace_seq_putc(p, '{'); diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 2316f50..506edcc5 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -41,6 +41,8 @@ #define NMI_WATCHDOG_ENABLED (1 << NMI_WATCHDOG_ENABLED_BIT) #define SOFT_WATCHDOG_ENABLED (1 << SOFT_WATCHDOG_ENABLED_BIT) +static DEFINE_MUTEX(watchdog_proc_mutex); + #ifdef CONFIG_HARDLOCKUP_DETECTOR static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED; #else @@ -608,26 +610,36 @@ void watchdog_nmi_enable_all(void) { int cpu; - if (!watchdog_user_enabled) - return; + mutex_lock(&watchdog_proc_mutex); + + if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) + goto unlock; get_online_cpus(); for_each_online_cpu(cpu) watchdog_nmi_enable(cpu); put_online_cpus(); + +unlock: + mutex_lock(&watchdog_proc_mutex); } void watchdog_nmi_disable_all(void) { int cpu; + mutex_lock(&watchdog_proc_mutex); + if (!watchdog_running) - return; + goto unlock; get_online_cpus(); for_each_online_cpu(cpu) watchdog_nmi_disable(cpu); put_online_cpus(); + +unlock: + mutex_unlock(&watchdog_proc_mutex); } #else static int watchdog_nmi_enable(unsigned int cpu) { return 0; } @@ -744,8 +756,6 @@ static int proc_watchdog_update(void) } -static DEFINE_MUTEX(watchdog_proc_mutex); - /* * common function for watchdog, nmi_watchdog and soft_watchdog parameter * diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1767057..ba2b0c8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1281,6 +1281,7 @@ config RCU_TORTURE_TEST_SLOW_INIT_DELAY int "How much to slow down RCU grace-period initialization" range 0 5 default 3 + depends on RCU_TORTURE_TEST_SLOW_INIT help This option specifies the number of jiffies to wait between each rcu_node structure initialization. diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index 4fecaedc..777eda7 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -10,8 +10,11 @@ config KASAN help Enables kernel address sanitizer - runtime memory debugger, designed to find out-of-bounds accesses and use-after-free bugs. - This is strictly debugging feature. It consumes about 1/8 - of available memory and brings about ~x3 performance slowdown. + This is strictly a debugging feature and it requires a gcc version + of 4.9.2 or later. Detection of out of bounds accesses to stack or + global variables requires gcc 5.0 or later. + This feature consumes about 1/8 of available memory and brings about + ~x3 performance slowdown. For better error detection enable CONFIG_STACKTRACE, and add slub_debug=U to boot cmdline. @@ -40,6 +43,7 @@ config KASAN_INLINE memory accesses. This is faster than outline (in some workloads it gives about x2 boost over outline instrumentation), but make kernel's .text size much bigger. + This requires a gcc version of 5.0 or later. endchoice diff --git a/lib/find_last_bit.c b/lib/find_last_bit.c deleted file mode 100644 index 3e3be40..0000000 --- a/lib/find_last_bit.c +++ /dev/null @@ -1,41 +0,0 @@ -/* find_last_bit.c: fallback find next bit implementation - * - * Copyright (C) 2008 IBM Corporation - * Written by Rusty Russell <rusty@rustcorp.com.au> - * (Inspired by David Howell's find_next_bit implementation) - * - * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease - * size and improve performance, 2015. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/bitops.h> -#include <linux/bitmap.h> -#include <linux/export.h> -#include <linux/kernel.h> - -#ifndef find_last_bit - -unsigned long find_last_bit(const unsigned long *addr, unsigned long size) -{ - if (size) { - unsigned long val = BITMAP_LAST_WORD_MASK(size); - unsigned long idx = (size-1) / BITS_PER_LONG; - - do { - val &= addr[idx]; - if (val) - return idx * BITS_PER_LONG + __fls(val); - - val = ~0ul; - } while (idx--); - } - return size; -} -EXPORT_SYMBOL(find_last_bit); - -#endif diff --git a/lib/string.c b/lib/string.c index a579201..bb3d4b6 100644 --- a/lib/string.c +++ b/lib/string.c @@ -607,7 +607,7 @@ EXPORT_SYMBOL(memset); void memzero_explicit(void *s, size_t count) { memset(s, 0, count); - barrier(); + barrier_data(s); } EXPORT_SYMBOL(memzero_explicit); diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c index 329caf5..4ca5fe0 100644 --- a/mm/hwpoison-inject.c +++ b/mm/hwpoison-inject.c @@ -34,13 +34,13 @@ static int hwpoison_inject(void *data, u64 val) if (!hwpoison_filter_enable) goto inject; - if (!PageLRU(p) && !PageHuge(p)) - shake_page(p, 0); + if (!PageLRU(hpage) && !PageHuge(p)) + shake_page(hpage, 0); /* * This implies unable to support non-LRU pages. */ - if (!PageLRU(p) && !PageHuge(p)) - return 0; + if (!PageLRU(hpage) && !PageHuge(p)) + goto put_out; /* * do a racy check with elevated page count, to make sure PG_hwpoison @@ -52,11 +52,14 @@ static int hwpoison_inject(void *data, u64 val) err = hwpoison_filter(hpage); unlock_page(hpage); if (err) - return 0; + goto put_out; inject: pr_info("Injecting memory failure at pfn %#lx\n", pfn); return memory_failure(pfn, 18, MF_COUNT_INCREASED); +put_out: + put_page(hpage); + return 0; } static int hwpoison_unpoison(void *data, u64 val) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 5405aff..f0fe4f2 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -115,7 +115,8 @@ #define BYTES_PER_POINTER sizeof(void *) /* GFP bitmask for kmemleak internal allocations */ -#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \ +#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC | \ + __GFP_NOACCOUNT)) | \ __GFP_NORETRY | __GFP_NOMEMALLOC | \ __GFP_NOWARN) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index d9359b7..501820c 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1187,10 +1187,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags) * The check (unnecessarily) ignores LRU pages being isolated and * walked by the page reclaim code, however that's not a big loss. */ - if (!PageHuge(p) && !PageTransTail(p)) { - if (!PageLRU(p)) - shake_page(p, 0); - if (!PageLRU(p)) { + if (!PageHuge(p)) { + if (!PageLRU(hpage)) + shake_page(hpage, 0); + if (!PageLRU(hpage)) { /* * shake_page could have turned it free. */ @@ -1777,12 +1777,12 @@ int soft_offline_page(struct page *page, int flags) } else if (ret == 0) { /* for free pages */ if (PageHuge(page)) { set_page_hwpoison_huge_page(hpage); - dequeue_hwpoisoned_huge_page(hpage); - atomic_long_add(1 << compound_order(hpage), + if (!dequeue_hwpoisoned_huge_page(hpage)) + atomic_long_add(1 << compound_order(hpage), &num_poisoned_pages); } else { - SetPageHWPoison(page); - atomic_long_inc(&num_poisoned_pages); + if (!TestSetPageHWPoison(page)) + atomic_long_inc(&num_poisoned_pages); } } unset_migratetype_isolate(page, MIGRATE_MOVABLE); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index ede2629..7477432 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2518,7 +2518,7 @@ static void __init check_numabalancing_enable(void) if (numabalancing_override) set_numabalancing_state(numabalancing_override == 1); - if (nr_node_ids > 1 && !numabalancing_override) { + if (num_online_nodes() > 1 && !numabalancing_override) { pr_info("%s automatic NUMA balancing. " "Configure with numa_balancing= or the " "kernel.numa_balancing sysctl", diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 5daf556..eb59f7e 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -580,7 +580,7 @@ static long long pos_ratio_polynom(unsigned long setpoint, long x; x = div64_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT, - limit - setpoint + 1); + (limit - setpoint) | 1); pos_ratio = x; pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; @@ -807,7 +807,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, * scale global setpoint to bdi's: * bdi_setpoint = setpoint * bdi_thresh / thresh */ - x = div_u64((u64)bdi_thresh << 16, thresh + 1); + x = div_u64((u64)bdi_thresh << 16, thresh | 1); bdi_setpoint = setpoint * (u64)x >> 16; /* * Use span=(8*write_bw) in single bdi case as indicated by @@ -822,7 +822,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, if (bdi_dirty < x_intercept - span / 4) { pos_ratio = div64_u64(pos_ratio * (x_intercept - bdi_dirty), - x_intercept - bdi_setpoint + 1); + (x_intercept - bdi_setpoint) | 1); } else pos_ratio /= 4; diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 755a42c..303c908 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -101,7 +101,8 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype) buddy_idx = __find_buddy_index(page_idx, order); buddy = page + (buddy_idx - page_idx); - if (!is_migrate_isolate_page(buddy)) { + if (pfn_valid_within(page_to_pfn(buddy)) && + !is_migrate_isolate_page(buddy)) { __isolate_free_page(page, order); kernel_map_pages(page, (1 << order), 1); set_page_refcounted(page); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 476709b..4663c3d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1557,7 +1557,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); - if (!hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) && + test_bit(HCI_UP, &hdev->flags)) { /* Execute vendor specific shutdown routine */ if (hdev->shutdown) hdev->shutdown(hdev); diff --git a/net/core/dev.c b/net/core/dev.c index c7ba038..2c1c67f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5209,7 +5209,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, if (__netdev_find_adj(upper_dev, dev, &upper_dev->all_adj_list.upper)) return -EBUSY; - if (__netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper)) + if (__netdev_find_adj(dev, upper_dev, &dev->adj_list.upper)) return -EEXIST; if (master && netdev_master_upper_dev_get(dev)) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 78fc04a..572af00 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -601,7 +601,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) } err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - RTM_GETNSID, net, peer, -1); + RTM_NEWNSID, net, peer, -1); if (err < 0) goto err_out; diff --git a/net/core/sock.c b/net/core/sock.c index e891bcf..292f422 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1474,8 +1474,8 @@ void sk_release_kernel(struct sock *sk) return; sock_hold(sk); - sock_net_set(sk, get_net(&init_net)); sock_release(sk->sk_socket); + sock_net_set(sk, get_net(&init_net)); sock_put(sk); } EXPORT_SYMBOL(sk_release_kernel); diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 05dab29..4adfd4d 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -3,7 +3,9 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o obj-y += 6lowpan/ ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ - header_ops.o sysfs.o nl802154.o + header_ops.o sysfs.o nl802154.o trace.o ieee802154_socket-y := socket.o +CFLAGS_trace.o := -I$(src) + ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 1b9d25f6..346c666 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -175,6 +175,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) int rc = -ENOBUFS; struct net_device *dev; int type = __IEEE802154_DEV_INVALID; + unsigned char name_assign_type; pr_debug("%s\n", __func__); @@ -190,8 +191,10 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') return -EINVAL; /* phy name should be null-terminated */ + name_assign_type = NET_NAME_USER; } else { devname = "wpan%d"; + name_assign_type = NET_NAME_ENUM; } if (strlen(devname) >= IFNAMSIZ) @@ -221,7 +224,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) } dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, - type); + name_assign_type, type); if (IS_ERR(dev)) { rc = PTR_ERR(dev); goto nla_put_failure; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index a4daf91..f3c12f6 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -589,7 +589,7 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) return rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL802154_ATTR_IFNAME]), - type, extended_addr); + NET_NAME_USER, type, extended_addr); } static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 7c46732..7b5a9dd 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -4,13 +4,16 @@ #include <net/cfg802154.h> #include "core.h" +#include "trace.h" static inline struct net_device * rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, - const char *name, int type) + const char *name, + unsigned char name_assign_type, + int type) { return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name, - type); + name_assign_type, type); } static inline void @@ -22,75 +25,131 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, static inline int rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { - return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type, + int ret; + + trace_802154_rdev_add_virtual_intf(&rdev->wpan_phy, name, type, extended_addr); + ret = rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, + name_assign_type, type, + extended_addr); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_del_virtual_intf(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev) { - return rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev); + int ret; + + trace_802154_rdev_del_virtual_intf(&rdev->wpan_phy, wpan_dev); + ret = rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) { - return rdev->ops->set_channel(&rdev->wpan_phy, page, channel); + int ret; + + trace_802154_rdev_set_channel(&rdev->wpan_phy, page, channel); + ret = rdev->ops->set_channel(&rdev->wpan_phy, page, channel); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_cca_mode(struct cfg802154_registered_device *rdev, const struct wpan_phy_cca *cca) { - return rdev->ops->set_cca_mode(&rdev->wpan_phy, cca); + int ret; + + trace_802154_rdev_set_cca_mode(&rdev->wpan_phy, cca); + ret = rdev->ops->set_cca_mode(&rdev->wpan_phy, cca); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_pan_id(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, __le16 pan_id) { - return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + int ret; + + trace_802154_rdev_set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + ret = rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_short_addr(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, __le16 short_addr) { - return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + int ret; + + trace_802154_rdev_set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + ret = rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, u8 min_be, u8 max_be) { - return rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, + int ret; + + trace_802154_rdev_set_backoff_exponent(&rdev->wpan_phy, wpan_dev, min_be, max_be); + ret = rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, + min_be, max_be); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, u8 max_csma_backoffs) { - return rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, - max_csma_backoffs); + int ret; + + trace_802154_rdev_set_csma_backoffs(&rdev->wpan_phy, wpan_dev, + max_csma_backoffs); + ret = rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, + max_csma_backoffs); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, s8 max_frame_retries) { - return rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, + int ret; + + trace_802154_rdev_set_max_frame_retries(&rdev->wpan_phy, wpan_dev, max_frame_retries); + ret = rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, + max_frame_retries); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_lbt_mode(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, bool mode) { - return rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + int ret; + + trace_802154_rdev_set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + ret = rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/ieee802154/trace.c b/net/ieee802154/trace.c new file mode 100644 index 0000000..95f997f --- /dev/null +++ b/net/ieee802154/trace.c @@ -0,0 +1,7 @@ +#include <linux/module.h> + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h new file mode 100644 index 0000000..5ac25eb --- /dev/null +++ b/net/ieee802154/trace.h @@ -0,0 +1,247 @@ +/* Based on net/wireless/tracing.h */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cfg802154 + +#if !defined(__RDEV_CFG802154_OPS_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __RDEV_CFG802154_OPS_TRACE + +#include <linux/tracepoint.h> + +#include <net/cfg802154.h> + +#define MAXNAME 32 +#define WPAN_PHY_ENTRY __array(char, wpan_phy_name, MAXNAME) +#define WPAN_PHY_ASSIGN strlcpy(__entry->wpan_phy_name, \ + wpan_phy_name(wpan_phy), \ + MAXNAME) +#define WPAN_PHY_PR_FMT "%s" +#define WPAN_PHY_PR_ARG __entry->wpan_phy_name + +#define WPAN_DEV_ENTRY __field(u32, identifier) +#define WPAN_DEV_ASSIGN (__entry->identifier) = (!IS_ERR_OR_NULL(wpan_dev) \ + ? wpan_dev->identifier : 0) +#define WPAN_DEV_PR_FMT "wpan_dev(%u)" +#define WPAN_DEV_PR_ARG (__entry->identifier) + +#define WPAN_CCA_ENTRY __field(enum nl802154_cca_modes, cca_mode) \ + __field(enum nl802154_cca_opts, cca_opt) +#define WPAN_CCA_ASSIGN \ + do { \ + (__entry->cca_mode) = cca->mode; \ + (__entry->cca_opt) = cca->opt; \ + } while (0) +#define WPAN_CCA_PR_FMT "cca_mode: %d, cca_opt: %d" +#define WPAN_CCA_PR_ARG __entry->cca_mode, __entry->cca_opt + +#define BOOL_TO_STR(bo) (bo) ? "true" : "false" + +/************************************************************* + * rdev->ops traces * + *************************************************************/ + +TRACE_EVENT(802154_rdev_add_virtual_intf, + TP_PROTO(struct wpan_phy *wpan_phy, char *name, + enum nl802154_iftype type, __le64 extended_addr), + TP_ARGS(wpan_phy, name, type, extended_addr), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __string(vir_intf_name, name ? name : "<noname>") + __field(enum nl802154_iftype, type) + __field(__le64, extended_addr) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __assign_str(vir_intf_name, name ? name : "<noname>"); + __entry->type = type; + __entry->extended_addr = extended_addr; + ), + TP_printk(WPAN_PHY_PR_FMT ", virtual intf name: %s, type: %d, ea %llx", + WPAN_PHY_PR_ARG, __get_str(vir_intf_name), __entry->type, + __le64_to_cpu(__entry->extended_addr)) +); + +TRACE_EVENT(802154_rdev_del_virtual_intf, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), + TP_ARGS(wpan_phy, wpan_dev), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT, WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG) +); + +TRACE_EVENT(802154_rdev_set_channel, + TP_PROTO(struct wpan_phy *wpan_phy, u8 page, u8 channel), + TP_ARGS(wpan_phy, page, channel), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(u8, page) + __field(u8, channel) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->page = page; + __entry->channel = channel; + ), + TP_printk(WPAN_PHY_PR_FMT ", page: %d, channel: %d", WPAN_PHY_PR_ARG, + __entry->page, __entry->channel) +); + +TRACE_EVENT(802154_rdev_set_cca_mode, + TP_PROTO(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca), + TP_ARGS(wpan_phy, cca), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_CCA_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_CCA_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_CCA_PR_FMT, WPAN_PHY_PR_ARG, + WPAN_CCA_PR_ARG) +); + +DECLARE_EVENT_CLASS(802154_le16_template, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(__le16, le16arg) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->le16arg = le16arg; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", pan id: 0x%04x", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, + __le16_to_cpu(__entry->le16arg)) +); + +DEFINE_EVENT(802154_le16_template, 802154_rdev_set_pan_id, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg) +); + +DEFINE_EVENT_PRINT(802154_le16_template, 802154_rdev_set_short_addr, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", sa: 0x%04x", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, + __le16_to_cpu(__entry->le16arg)) +); + +TRACE_EVENT(802154_rdev_set_backoff_exponent, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + u8 min_be, u8 max_be), + TP_ARGS(wpan_phy, wpan_dev, min_be, max_be), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(u8, min_be) + __field(u8, max_be) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->min_be = min_be; + __entry->max_be = max_be; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", min be: %d, max_be: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->min_be, __entry->max_be) +); + +TRACE_EVENT(802154_rdev_set_csma_backoffs, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + u8 max_csma_backoffs), + TP_ARGS(wpan_phy, wpan_dev, max_csma_backoffs), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(u8, max_csma_backoffs) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->max_csma_backoffs = max_csma_backoffs; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", max csma backoffs: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->max_csma_backoffs) +); + +TRACE_EVENT(802154_rdev_set_max_frame_retries, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + s8 max_frame_retries), + TP_ARGS(wpan_phy, wpan_dev, max_frame_retries), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(s8, max_frame_retries) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->max_frame_retries = max_frame_retries; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", max frame retries: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->max_frame_retries) +); + +TRACE_EVENT(802154_rdev_set_lbt_mode, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + bool mode), + TP_ARGS(wpan_phy, wpan_dev, mode), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(bool, mode) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->mode = mode; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", lbt mode: %s", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->mode)) +); + +TRACE_EVENT(802154_rdev_return_int, + TP_PROTO(struct wpan_phy *wpan_phy, int ret), + TP_ARGS(wpan_phy, ret), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(int, ret) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->ret = ret; + ), + TP_printk(WPAN_PHY_PR_FMT ", returned: %d", WPAN_PHY_PR_ARG, + __entry->ret) +); + +#endif /* !__RDEV_CFG802154_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#include <trace/define_trace.h> diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index bb77ebd..4d32262 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -224,14 +224,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, handler->idiag_get_info(sk, r, info); if (sk->sk_state < TCP_TIME_WAIT) { - int err = 0; + union tcp_cc_info info; + size_t sz = 0; + int attr; rcu_read_lock(); ca_ops = READ_ONCE(icsk->icsk_ca_ops); if (ca_ops && ca_ops->get_info) - err = ca_ops->get_info(sk, ext, skb); + sz = ca_ops->get_info(sk, ext, &attr, &info); rcu_read_unlock(); - if (err < 0) + if (sz && nla_put(skb, attr, sz, &info) < 0) goto errout; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8c5cd9e..46efa03 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -252,6 +252,7 @@ #include <linux/types.h> #include <linux/fcntl.h> #include <linux/poll.h> +#include <linux/inet_diag.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/skbuff.h> @@ -2592,7 +2593,7 @@ EXPORT_SYMBOL(compat_tcp_setsockopt); #endif /* Return information about state of tcp endpoint in API format. */ -void tcp_get_info(const struct sock *sk, struct tcp_info *info) +void tcp_get_info(struct sock *sk, struct tcp_info *info) { const struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); @@ -2663,6 +2664,11 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info) rate = READ_ONCE(sk->sk_max_pacing_rate); info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL; + + spin_lock_bh(&sk->sk_lock.slock); + info->tcpi_bytes_acked = tp->bytes_acked; + info->tcpi_bytes_received = tp->bytes_received; + spin_unlock_bh(&sk->sk_lock.slock); } EXPORT_SYMBOL_GPL(tcp_get_info); @@ -2734,6 +2740,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level, return -EFAULT; return 0; } + case TCP_CC_INFO: { + const struct tcp_congestion_ops *ca_ops; + union tcp_cc_info info; + size_t sz = 0; + int attr; + + if (get_user(len, optlen)) + return -EFAULT; + + ca_ops = icsk->icsk_ca_ops; + if (ca_ops && ca_ops->get_info) + sz = ca_ops->get_info(sk, ~0U, &attr, &info); + + len = min_t(unsigned int, len, sz); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &info, len)) + return -EFAULT; + return 0; + } case TCP_QUICKACK: val = !icsk->icsk_ack.pingpong; break; diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 4376016..4c41c12 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -277,7 +277,8 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) } } -static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct dctcp *ca = inet_csk_ca(sk); @@ -286,18 +287,17 @@ static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) */ if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcp_dctcp_info info; - - memset(&info, 0, sizeof(info)); + memset(info, 0, sizeof(struct tcp_dctcp_info)); if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { - info.dctcp_enabled = 1; - info.dctcp_ce_state = (u16) ca->ce_state; - info.dctcp_alpha = ca->dctcp_alpha; - info.dctcp_ab_ecn = ca->acked_bytes_ecn; - info.dctcp_ab_tot = ca->acked_bytes_total; + info->dctcp.dctcp_enabled = 1; + info->dctcp.dctcp_ce_state = (u16) ca->ce_state; + info->dctcp.dctcp_alpha = ca->dctcp_alpha; + info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; + info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; } - return nla_put(skb, INET_DIAG_DCTCPINFO, sizeof(info), &info); + *attr = INET_DIAG_DCTCPINFO; + return sizeof(*info); } return 0; } diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index e3d87ac..3c673d5 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -206,6 +206,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, skb_set_owner_r(skb2, child); __skb_queue_tail(&child->sk_receive_queue, skb2); tp->syn_data_acked = 1; + tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1; } else { end_seq = TCP_SKB_CB(skb)->seq + 1; } diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 67476f0..f71002e 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -300,24 +300,25 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) } /* Extract info for Tcp socket info provided via netlink. */ -static int tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t tcp_illinois_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct illinois *ca = inet_csk_ca(sk); if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = 1, - .tcpv_rttcnt = ca->cnt_rtt, - .tcpv_minrtt = ca->base_rtt, - }; + info->vegas.tcpv_enabled = 1; + info->vegas.tcpv_rttcnt = ca->cnt_rtt; + info->vegas.tcpv_minrtt = ca->base_rtt; + info->vegas.tcpv_rtt = 0; - if (info.tcpv_rttcnt > 0) { + if (info->vegas.tcpv_rttcnt > 0) { u64 t = ca->sum_rtt; - do_div(t, info.tcpv_rttcnt); - info.tcpv_rtt = t; + do_div(t, info->vegas.tcpv_rttcnt); + info->vegas.tcpv_rtt = t; } - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3a4d9b34..bc790ea 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1820,14 +1820,12 @@ advance_sp: for (j = 0; j < used_sacks; j++) tp->recv_sack_cache[i++] = sp[j]; - tcp_mark_lost_retrans(sk); - - tcp_verify_left_out(tp); - if ((state.reord < tp->fackets_out) && ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker)) tcp_update_reordering(sk, tp->fackets_out - state.reord, 0); + tcp_mark_lost_retrans(sk); + tcp_verify_left_out(tp); out: #if FASTRETRANS_DEBUG > 0 @@ -3280,6 +3278,24 @@ static inline bool tcp_may_update_window(const struct tcp_sock *tp, (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd); } +/* If we update tp->snd_una, also update tp->bytes_acked */ +static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) +{ + u32 delta = ack - tp->snd_una; + + tp->bytes_acked += delta; + tp->snd_una = ack; +} + +/* If we update tp->rcv_nxt, also update tp->bytes_received */ +static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) +{ + u32 delta = seq - tp->rcv_nxt; + + tp->bytes_received += delta; + tp->rcv_nxt = seq; +} + /* Update our send window. * * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 @@ -3315,7 +3331,7 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 } } - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); return flag; } @@ -3497,7 +3513,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) * Note, we use the fact that SND.UNA>=SND.WL2. */ tcp_update_wl(tp, ack_seq); - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); flag |= FLAG_WIN_UPDATE; tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); @@ -4236,7 +4252,7 @@ static void tcp_ofo_queue(struct sock *sk) tail = skb_peek_tail(&sk->sk_receive_queue); eaten = tail && tcp_try_coalesce(sk, tail, skb, &fragstolen); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (!eaten) __skb_queue_tail(&sk->sk_receive_queue, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -4404,7 +4420,7 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int __skb_pull(skb, hdrlen); eaten = (tail && tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0; - tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq); if (!eaten) { __skb_queue_tail(&sk->sk_receive_queue, skb); skb_set_owner_r(skb, sk); @@ -4497,7 +4513,7 @@ queue_and_out: eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); } - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (skb->len) tcp_event_data_recv(sk, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -5245,7 +5261,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_rcv_rtt_measure_ts(sk, skb); __skb_pull(skb, tcp_header_len); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER); eaten = 1; } diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index c71a1b8..a6cea1d 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -286,18 +286,19 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) } /* Extract info for Tcp socket info provided via netlink. */ -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct vegas *ca = inet_csk_ca(sk); + if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = ca->doing_vegas_now, - .tcpv_rttcnt = ca->cntRTT, - .tcpv_rtt = ca->baseRTT, - .tcpv_minrtt = ca->minRTT, - }; - - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + info->vegas.tcpv_enabled = ca->doing_vegas_now, + info->vegas.tcpv_rttcnt = ca->cntRTT, + info->vegas.tcpv_rtt = ca->baseRTT, + info->vegas.tcpv_minrtt = ca->minRTT, + + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_vegas.h b/net/ipv4/tcp_vegas.h index e8a6b33..ef9da53 100644 --- a/net/ipv4/tcp_vegas.h +++ b/net/ipv4/tcp_vegas.h @@ -19,6 +19,7 @@ void tcp_vegas_init(struct sock *sk); void tcp_vegas_state(struct sock *sk, u8 ca_state); void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, s32 rtt_us); void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event); -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb); +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); #endif /* __TCP_VEGAS_H */ diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index b3c57cc..c10732e 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c @@ -256,18 +256,19 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) } /* Extract info for Tcp socket info provided via netlink. */ -static int tcp_westwood_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t tcp_westwood_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct westwood *ca = inet_csk_ca(sk); if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = 1, - .tcpv_rtt = jiffies_to_usecs(ca->rtt), - .tcpv_minrtt = jiffies_to_usecs(ca->rtt_min), - }; + info->vegas.tcpv_enabled = 1; + info->vegas.tcpv_rttcnt = 0; + info->vegas.tcpv_rtt = jiffies_to_usecs(ca->rtt), + info->vegas.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min), - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7fde1f2..c217775 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -886,22 +886,45 @@ static int ip6_dst_lookup_tail(struct sock *sk, #endif int err; - if (!*dst) - *dst = ip6_route_output(net, sk, fl6); - - err = (*dst)->error; - if (err) - goto out_err_release; + /* The correct way to handle this would be to do + * ip6_route_get_saddr, and then ip6_route_output; however, + * the route-specific preferred source forces the + * ip6_route_output call _before_ ip6_route_get_saddr. + * + * In source specific routing (no src=any default route), + * ip6_route_output will fail given src=any saddr, though, so + * that's why we try it again later. + */ + if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { + struct rt6_info *rt; + bool had_dst = *dst != NULL; - if (ipv6_addr_any(&fl6->saddr)) { - struct rt6_info *rt = (struct rt6_info *) *dst; + if (!had_dst) + *dst = ip6_route_output(net, sk, fl6); + rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; err = ip6_route_get_saddr(net, rt, &fl6->daddr, sk ? inet6_sk(sk)->srcprefs : 0, &fl6->saddr); if (err) goto out_err_release; + + /* If we had an erroneous initial result, pretend it + * never existed and let the SA-enabled version take + * over. + */ + if (!had_dst && (*dst)->error) { + dst_release(*dst); + *dst = NULL; + } } + if (!*dst) + *dst = ip6_route_output(net, sk, fl6); + + err = (*dst)->error; + if (err) + goto out_err_release; + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD /* * Here if the dst entry we've looked up diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5c48293..d358888 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2245,9 +2245,10 @@ int ip6_route_get_saddr(struct net *net, unsigned int prefs, struct in6_addr *saddr) { - struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); + struct inet6_dev *idev = + rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; int err = 0; - if (rt->rt6i_prefsrc.plen) + if (rt && rt->rt6i_prefsrc.plen) *saddr = rt->rt6i_prefsrc.addr; else err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b4ac596..bab5c63 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -819,13 +819,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, * (because if we remove a STA after ops->remove_interface() * the driver will have removed the vif info already!) * - * This is relevant only in WDS mode, in all other modes we've - * already removed all stations when disconnecting or similar, - * so warn otherwise. + * In WDS mode a station must exist here and be flushed, for + * AP_VLANs stations may exist since there's nothing else that + * would have removed them, but in other modes there shouldn't + * be any stations. */ flushed = sta_info_flush(sdata); - WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || - (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); + WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || + (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1))); /* don't count this interface for promisc/allmulti while it is down */ if (sdata->flags & IEEE80211_SDATA_ALLMULTI) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 12971b7..2880f2a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -66,6 +66,7 @@ static const struct rhashtable_params sta_rht_params = { .nelem_hint = 3, /* start small */ + .automatic_shrinking = true, .head_offset = offsetof(struct sta_info, hash_node), .key_offset = offsetof(struct sta_info, sta.addr), .key_len = ETH_ALEN, @@ -157,8 +158,24 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, const u8 *addr) { struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + struct rhash_head *tmp; + const struct bucket_table *tbl; + + rcu_read_lock(); + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); - return rhashtable_lookup_fast(&local->sta_hash, addr, sta_rht_params); + for_each_sta_info(local, tbl, addr, sta, tmp) { + if (sta->sdata == sdata) { + rcu_read_unlock(); + /* this is safe as the caller must already hold + * another rcu read section or the mutex + */ + return sta; + } + } + rcu_read_unlock(); + return NULL; } /* diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 5d9f68c..70be9c7 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -22,13 +22,14 @@ static struct net_device * ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy, - const char *name, int type) + const char *name, + unsigned char name_assign_type, int type) { struct ieee802154_local *local = wpan_phy_priv(wpan_phy); struct net_device *dev; rtnl_lock(); - dev = ieee802154_if_add(local, name, type, + dev = ieee802154_if_add(local, name, name_assign_type, type, cpu_to_le64(0x0000000000000000ULL)); rtnl_unlock(); @@ -45,12 +46,14 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, static int ieee802154_add_iface(struct wpan_phy *phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { struct ieee802154_local *local = wpan_phy_priv(phy); struct net_device *err; - err = ieee802154_if_add(local, name, type, extended_addr); + err = ieee802154_if_add(local, name, name_assign_type, type, + extended_addr); return PTR_ERR_OR_ZERO(err); } diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index bebd70f..127ba18 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -182,7 +182,8 @@ void ieee802154_iface_exit(void); void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata); struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr); + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr); void ieee802154_remove_interfaces(struct ieee802154_local *local); #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 38b56f9..91b75ab 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -522,7 +522,8 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr) + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr) { struct net_device *ndev = NULL; struct ieee802154_sub_if_data *sdata = NULL; @@ -531,7 +532,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, ASSERT_RTNL(); ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, - NET_NAME_UNKNOWN, ieee802154_if_setup); + name_assign_type, ieee802154_if_setup); if (!ndev) return ERR_PTR(-ENOMEM); diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index dcf7395..5b2be12 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c @@ -134,7 +134,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template) for (i = 0; i < ARRAY_SIZE(key->tfm); i++) { key->tfm[i] = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); - if (!key->tfm[i]) + if (IS_ERR(key->tfm[i])) goto err_tfm; if (crypto_aead_setkey(key->tfm[i], template->key, IEEE802154_LLSEC_KEY_SIZE)) @@ -144,7 +144,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template) } key->tfm0 = crypto_alloc_blkcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC); - if (!key->tfm0) + if (IS_ERR(key->tfm0)) goto err_tfm; if (crypto_blkcipher_setkey(key->tfm0, template->key, diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 8500378..08cb32d 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -161,18 +161,21 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) rtnl_lock(); - dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE, + dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM, + NL802154_IFTYPE_NODE, cpu_to_le64(0x0000000000000000ULL)); if (IS_ERR(dev)) { rtnl_unlock(); rc = PTR_ERR(dev); - goto out_wq; + goto out_phy; } rtnl_unlock(); return 0; +out_phy: + wpan_phy_unregister(local->phy); out_wq: destroy_workqueue(local->workqueue); out: diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 954810c..7b3f732 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -647,7 +647,7 @@ int nla_get_labels(const struct nlattr *nla, return -EINVAL; switch (dec.label) { - case LABEL_IMPLICIT_NULL: + case MPLS_LABEL_IMPLNULL: /* RFC3032: This is a label that an LSR may * assign and distribute, but which never * actually appears in the encapsulation. @@ -935,7 +935,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) } /* In case the predefined labels need to be populated */ - if (limit > LABEL_IPV4_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV4NULL) { struct net_device *lo = net->loopback_dev; rt0 = mpls_rt_alloc(lo->addr_len); if (!rt0) @@ -945,7 +945,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt0->rt_via_table = NEIGH_LINK_TABLE; memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); } - if (limit > LABEL_IPV6_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV6NULL) { struct net_device *lo = net->loopback_dev; rt2 = mpls_rt_alloc(lo->addr_len); if (!rt2) @@ -973,15 +973,15 @@ static int resize_platform_label_table(struct net *net, size_t limit) memcpy(labels, old, cp_size); /* If needed set the predefined labels */ - if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && - (limit > LABEL_IPV6_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2); + if ((old_limit <= MPLS_LABEL_IPV6NULL) && + (limit > MPLS_LABEL_IPV6NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2); rt2 = NULL; } - if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && - (limit > LABEL_IPV4_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0); + if ((old_limit <= MPLS_LABEL_IPV4NULL) && + (limit > MPLS_LABEL_IPV4NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0); rt0 = NULL; } diff --git a/net/mpls/internal.h b/net/mpls/internal.h index 693877d..b064c34 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -1,16 +1,6 @@ #ifndef MPLS_INTERNAL_H #define MPLS_INTERNAL_H -#define LABEL_IPV4_EXPLICIT_NULL 0 /* RFC3032 */ -#define LABEL_ROUTER_ALERT_LABEL 1 /* RFC3032 */ -#define LABEL_IPV6_EXPLICIT_NULL 2 /* RFC3032 */ -#define LABEL_IMPLICIT_NULL 3 /* RFC3032 */ -#define LABEL_ENTROPY_INDICATOR 7 /* RFC6790 */ -#define LABEL_GAL 13 /* RFC5586 */ -#define LABEL_OAM_ALERT 14 /* RFC3429 */ -#define LABEL_EXTENSION 15 /* RFC7274 */ - - struct mpls_shim_hdr { __be32 label_stack_entry; }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ec4adbd..daa0b81 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -3139,7 +3139,6 @@ static const struct rhashtable_params netlink_rhashtable_params = { .key_len = netlink_compare_arg_len, .obj_hashfn = netlink_hash, .obj_cmpfn = netlink_compare, - .max_size = 65536, .automatic_shrinking = true, }; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5102c3c..b5989c6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2311,11 +2311,14 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) tlen = dev->needed_tailroom; skb = sock_alloc_send_skb(&po->sk, hlen + tlen + sizeof(struct sockaddr_ll), - 0, &err); + !need_wait, &err); - if (unlikely(skb == NULL)) + if (unlikely(skb == NULL)) { + /* we assume the socket was initially writeable ... */ + if (likely(len_sum > 0)) + err = len_sum; goto out_status; - + } tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, addr, hlen); if (tp_len > dev->mtu + dev->hard_header_len) { diff --git a/net/rds/connection.c b/net/rds/connection.c index 14f04139..da6da57 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -126,7 +126,10 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, struct rds_transport *loop_trans; unsigned long flags; int ret; + struct rds_transport *otrans = trans; + if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) + goto new_conn; rcu_read_lock(); conn = rds_conn_lookup(head, laddr, faddr, trans); if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && @@ -142,6 +145,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, if (conn) goto out; +new_conn: conn = kmem_cache_zalloc(rds_conn_slab, gfp); if (!conn) { conn = ERR_PTR(-ENOMEM); @@ -230,13 +234,22 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, /* Creating normal conn */ struct rds_connection *found; - found = rds_conn_lookup(head, laddr, faddr, trans); + if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) + found = NULL; + else + found = rds_conn_lookup(head, laddr, faddr, trans); if (found) { trans->conn_free(conn->c_transport_data); kmem_cache_free(rds_conn_slab, conn); conn = found; } else { - hlist_add_head_rcu(&conn->c_hash_node, head); + if ((is_outgoing && otrans->t_type == RDS_TRANS_TCP) || + (otrans->t_type != RDS_TRANS_TCP)) { + /* Only the active side should be added to + * reconnect list for TCP. + */ + hlist_add_head_rcu(&conn->c_hash_node, head); + } rds_cong_add_conn(conn); rds_conn_count++; } diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 31b74f5..8a09ee7 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -183,8 +183,17 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even /* If the peer gave us the last packet it saw, process this as if * we had received a regular ACK. */ - if (dp && dp->dp_ack_seq) - rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL); + if (dp) { + /* dp structure start is not guaranteed to be 8 bytes aligned. + * Since dp_ack_seq is 64-bit extended load operations can be + * used so go through get_unaligned to avoid unaligned errors. + */ + __be64 dp_ack_seq = get_unaligned(&dp->dp_ack_seq); + + if (dp_ack_seq) + rds_send_drop_acked(conn, be64_to_cpu(dp_ack_seq), + NULL); + } rds_connect_complete(conn); } diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c index f9f564a..973109c7 100644 --- a/net/rds/tcp_connect.c +++ b/net/rds/tcp_connect.c @@ -62,6 +62,7 @@ void rds_tcp_state_change(struct sock *sk) case TCP_ESTABLISHED: rds_connect_complete(conn); break; + case TCP_CLOSE_WAIT: case TCP_CLOSE: rds_conn_drop(conn); default: diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index 23ab4dcd..0da49e3 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -45,12 +45,45 @@ static void rds_tcp_accept_worker(struct work_struct *work); static DECLARE_WORK(rds_tcp_listen_work, rds_tcp_accept_worker); static struct socket *rds_tcp_listen_sock; +static int rds_tcp_keepalive(struct socket *sock) +{ + /* values below based on xs_udp_default_timeout */ + int keepidle = 5; /* send a probe 'keepidle' secs after last data */ + int keepcnt = 5; /* number of unack'ed probes before declaring dead */ + int keepalive = 1; + int ret = 0; + + ret = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keepalive, sizeof(keepalive)); + if (ret < 0) + goto bail; + + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, + (char *)&keepcnt, sizeof(keepcnt)); + if (ret < 0) + goto bail; + + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, + (char *)&keepidle, sizeof(keepidle)); + if (ret < 0) + goto bail; + + /* KEEPINTVL is the interval between successive probes. We follow + * the model in xs_tcp_finish_connecting() and re-use keepidle. + */ + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, + (char *)&keepidle, sizeof(keepidle)); +bail: + return ret; +} + static int rds_tcp_accept_one(struct socket *sock) { struct socket *new_sock = NULL; struct rds_connection *conn; int ret; struct inet_sock *inet; + struct rds_tcp_connection *rs_tcp; ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, sock->sk->sk_protocol, &new_sock); @@ -63,6 +96,10 @@ static int rds_tcp_accept_one(struct socket *sock) if (ret < 0) goto out; + ret = rds_tcp_keepalive(new_sock); + if (ret < 0) + goto out; + rds_tcp_tune(new_sock); inet = inet_sk(new_sock->sk); @@ -77,6 +114,15 @@ static int rds_tcp_accept_one(struct socket *sock) ret = PTR_ERR(conn); goto out; } + /* An incoming SYN request came in, and TCP just accepted it. + * We always create a new conn for listen side of TCP, and do not + * add it to the c_hash_list. + * + * If the client reboots, this conn will need to be cleaned up. + * rds_tcp_state_change() will do that cleanup + */ + rs_tcp = (struct rds_tcp_connection *)conn->c_transport_data; + WARN_ON(!rs_tcp || rs_tcp->t_sock); /* * see the comment above rds_queue_delayed_reconnect() diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8b0470e..b6ef9a0 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -308,12 +308,11 @@ replay: case RTM_DELTFILTER: err = tp->ops->delete(tp, fh); if (err == 0) { - tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); - if (tcf_destroy(tp, false)) { - struct tcf_proto *next = rtnl_dereference(tp->next); + struct tcf_proto *next = rtnl_dereference(tp->next); + tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); + if (tcf_destroy(tp, false)) RCU_INIT_POINTER(*back, next); - } } goto errout; case RTM_GETTFILTER: diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index de28f8e..7a0bdb1 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -164,7 +164,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt) sch->limit = DEFAULT_CODEL_LIMIT; - codel_params_init(&q->params); + codel_params_init(&q->params, sch); codel_vars_init(&q->vars); codel_stats_init(&q->stats); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 1e52dec..c244c45b 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -391,7 +391,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) q->perturbation = prandom_u32(); INIT_LIST_HEAD(&q->new_flows); INIT_LIST_HEAD(&q->old_flows); - codel_params_init(&q->cparams); + codel_params_init(&q->cparams, sch); codel_stats_init(&q->cstats); q->cparams.ecn = true; diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index a4ca451..634529e 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -229,7 +229,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) break; } - if (q->backlog + qdisc_pkt_len(skb) <= q->limit) { + if (gred_backlog(t, q, sch) + qdisc_pkt_len(skb) <= q->limit) { q->backlog += qdisc_pkt_len(skb); return qdisc_enqueue_tail(skb, sch); } @@ -553,7 +553,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) opt.limit = q->limit; opt.DP = q->DP; - opt.backlog = q->backlog; + opt.backlog = gred_backlog(table, q, sch); opt.prio = q->prio; opt.qth_min = q->parms.qth_min >> q->parms.Wlog; opt.qth_max = q->parms.qth_max >> q->parms.Wlog; diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index 1ec19f6..eeeba5a 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -793,20 +793,26 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, { u32 value_follows; int err; + struct page *scratch; + + scratch = alloc_page(GFP_KERNEL); + if (!scratch) + return -ENOMEM; + xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE); /* res->status */ err = gssx_dec_status(xdr, &res->status); if (err) - return err; + goto out_free; /* res->context_handle */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { err = gssx_dec_ctx(xdr, res->context_handle); if (err) - return err; + goto out_free; } else { res->context_handle = NULL; } @@ -814,11 +820,11 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, /* res->output_token */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { err = gssx_dec_buffer(xdr, res->output_token); if (err) - return err; + goto out_free; } else { res->output_token = NULL; } @@ -826,14 +832,17 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, /* res->delegated_cred_handle */ err = gssx_dec_bool(xdr, &value_follows); if (err) - return err; + goto out_free; if (value_follows) { /* we do not support upcall servers sending this data. */ - return -EINVAL; + err = -EINVAL; + goto out_free; } /* res->options */ err = gssx_dec_option_array(xdr, &res->options); +out_free: + __free_page(scratch); return err; } diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index d8fe29f..8bd9606 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -16,7 +16,7 @@ MAKEFLAGS += --no-print-directory LIBFILE = $(OUTPUT)libapi.a CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 -fPIC +CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 RM = rm -f diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 0c356fb..18ffccf 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile @@ -14,9 +14,10 @@ define allow-override $(eval $(1) = $(2))) endef -# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. +# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix. $(call allow-override,CC,$(CROSS_COMPILE)gcc) $(call allow-override,AR,$(CROSS_COMPILE)ar) +$(call allow-override,LD,$(CROSS_COMPILE)ld) INSTALL = install diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h index a11e3c3..cd2cc59 100644 --- a/tools/lib/lockdep/uinclude/linux/kernel.h +++ b/tools/lib/lockdep/uinclude/linux/kernel.h @@ -28,6 +28,9 @@ #define __init #define noinline #define list_add_tail_rcu list_add_tail +#define list_for_each_entry_rcu list_for_each_entry +#define barrier() +#define synchronize_sched() #ifndef CALLER_ADDR0 #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index e0917c0..29f94f6 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -3865,7 +3865,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, } else if (el_size == 4) { trace_seq_printf(s, "%u", *(uint32_t *)num); } else if (el_size == 8) { - trace_seq_printf(s, "%lu", *(uint64_t *)num); + trace_seq_printf(s, "%"PRIu64, *(uint64_t *)num); } else { trace_seq_printf(s, "BAD SIZE:%d 0x%x", el_size, *(uint8_t *)num); diff --git a/tools/perf/Makefile b/tools/perf/Makefile index c699dc3..d31a7bb 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -24,7 +24,7 @@ unexport MAKEFLAGS # (To override it, run 'make JOBS=1' and similar.) # ifeq ($(JOBS),) - JOBS := $(shell egrep -c '^processor|^CPU' /proc/cpuinfo 2>/dev/null) + JOBS := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null) ifeq ($(JOBS),0) JOBS := 1 endif diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index bedff6b..ad0d9b5 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -132,6 +132,9 @@ int bench_futex_requeue(int argc, const char **argv, if (!fshared) futex_flag = FUTEX_PRIVATE_FLAG; + if (nrequeue > nthreads) + nrequeue = nthreads; + printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), " "%d at a time.\n\n", getpid(), nthreads, fshared ? "shared":"private", &futex1, &futex2, nrequeue); @@ -161,20 +164,18 @@ int bench_futex_requeue(int argc, const char **argv, /* Ok, all threads are patiently blocked, start requeueing */ gettimeofday(&start, NULL); - for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) { + while (nrequeued < nthreads) { /* * Do not wakeup any tasks blocked on futex1, allowing * us to really measure futex_wait functionality. */ - futex_cmp_requeue(&futex1, 0, &futex2, 0, - nrequeue, futex_flag); + nrequeued += futex_cmp_requeue(&futex1, 0, &futex2, 0, + nrequeue, futex_flag); } + gettimeofday(&end, NULL); timersub(&end, &start, &runtime); - if (nrequeued > nthreads) - nrequeued = nthreads; - update_stats(&requeued_stats, nrequeued); update_stats(&requeuetime_stats, runtime.tv_usec); @@ -184,7 +185,7 @@ int bench_futex_requeue(int argc, const char **argv, } /* everybody should be blocked on futex2, wake'em up */ - nrequeued = futex_wake(&futex2, nthreads, futex_flag); + nrequeued = futex_wake(&futex2, nrequeued, futex_flag); if (nthreads != nrequeued) warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads); diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index ebfa163..ba5efa47 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -180,7 +180,7 @@ static const struct option options[] = { OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"), OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"), OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"), - OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "bzero the initial allocations"), + OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"), OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"), /* Special option string parsing callbacks: */ @@ -828,6 +828,9 @@ static int count_process_nodes(int process_nr) td = g->threads + task_nr; node = numa_node_of_cpu(td->curr_cpu); + if (node < 0) /* curr_cpu was likely still -1 */ + return 0; + node_present[node] = 1; } @@ -882,6 +885,11 @@ static void calc_convergence_compression(int *strong) for (p = 0; p < g->p.nr_proc; p++) { unsigned int nodes = count_process_nodes(p); + if (!nodes) { + *strong = 0; + return; + } + nodes_min = min(nodes, nodes_min); nodes_max = max(nodes, nodes_max); } @@ -1395,7 +1403,7 @@ static void print_res(const char *name, double val, if (!name) name = "main,"; - if (g->p.show_quiet) + if (!g->p.show_quiet) printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short); else printf(" %14.3f %s\n", val, txt_long); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 63ea013..1634186 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -319,7 +319,7 @@ static int page_stat_cmp(struct page_stat *a, struct page_stat *b) return 0; } -static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool create) +static struct page_stat *search_page_alloc_stat(struct page_stat *pstat, bool create) { struct rb_node **node = &page_alloc_tree.rb_node; struct rb_node *parent = NULL; @@ -331,7 +331,7 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre parent = *node; data = rb_entry(*node, struct page_stat, node); - cmp = page_stat_cmp(data, stat); + cmp = page_stat_cmp(data, pstat); if (cmp < 0) node = &parent->rb_left; else if (cmp > 0) @@ -345,10 +345,10 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre data = zalloc(sizeof(*data)); if (data != NULL) { - data->page = stat->page; - data->order = stat->order; - data->gfp_flags = stat->gfp_flags; - data->migrate_type = stat->migrate_type; + data->page = pstat->page; + data->order = pstat->order; + data->gfp_flags = pstat->gfp_flags; + data->migrate_type = pstat->migrate_type; rb_link_node(&data->node, parent, node); rb_insert_color(&data->node, &page_alloc_tree); @@ -375,7 +375,7 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, unsigned int migrate_type = perf_evsel__intval(evsel, sample, "migratetype"); u64 bytes = kmem_page_size << order; - struct page_stat *stat; + struct page_stat *pstat; struct page_stat this = { .order = order, .gfp_flags = gfp_flags, @@ -401,21 +401,21 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, * This is to find the current page (with correct gfp flags and * migrate type) at free event. */ - stat = search_page(page, true); - if (stat == NULL) + pstat = search_page(page, true); + if (pstat == NULL) return -ENOMEM; - stat->order = order; - stat->gfp_flags = gfp_flags; - stat->migrate_type = migrate_type; + pstat->order = order; + pstat->gfp_flags = gfp_flags; + pstat->migrate_type = migrate_type; this.page = page; - stat = search_page_alloc_stat(&this, true); - if (stat == NULL) + pstat = search_page_alloc_stat(&this, true); + if (pstat == NULL) return -ENOMEM; - stat->nr_alloc++; - stat->alloc_bytes += bytes; + pstat->nr_alloc++; + pstat->alloc_bytes += bytes; order_stats[order][migrate_type]++; @@ -428,7 +428,7 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel, u64 page; unsigned int order = perf_evsel__intval(evsel, sample, "order"); u64 bytes = kmem_page_size << order; - struct page_stat *stat; + struct page_stat *pstat; struct page_stat this = { .order = order, }; @@ -441,8 +441,8 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel, nr_page_frees++; total_page_free_bytes += bytes; - stat = search_page(page, false); - if (stat == NULL) { + pstat = search_page(page, false); + if (pstat == NULL) { pr_debug2("missing free at page %"PRIx64" (order: %d)\n", page, order); @@ -453,18 +453,18 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel, } this.page = page; - this.gfp_flags = stat->gfp_flags; - this.migrate_type = stat->migrate_type; + this.gfp_flags = pstat->gfp_flags; + this.migrate_type = pstat->migrate_type; - rb_erase(&stat->node, &page_tree); - free(stat); + rb_erase(&pstat->node, &page_tree); + free(pstat); - stat = search_page_alloc_stat(&this, false); - if (stat == NULL) + pstat = search_page_alloc_stat(&this, false); + if (pstat == NULL) return -ENOENT; - stat->nr_free++; - stat->free_bytes += bytes; + pstat->nr_free++; + pstat->free_bytes += bytes; return 0; } @@ -640,9 +640,9 @@ static void print_page_summary(void) nr_page_frees, total_page_free_bytes / 1024); printf("\n"); - printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests", + printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests", nr_alloc_freed, (total_alloc_freed_bytes) / 1024); - printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc-only requests", + printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc-only requests", nr_page_allocs - nr_alloc_freed, (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024); printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests", diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 476cdf7..b63aeda 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -329,7 +329,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, fprintf(stdout, "\n\n"); } - if (sort_order == default_sort_order && + if (sort_order == NULL && parent_pattern == default_parent_pattern) { fprintf(stdout, "#\n# (%s)\n#\n", help); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1cb3436..6a4d5d4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -733,7 +733,7 @@ static void perf_event__process_sample(struct perf_tool *tool, "Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" "Check /proc/sys/kernel/kptr_restrict.\n\n" "Kernel%s samples will not be resolved.\n", - !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? + al.map && !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? " modules" : ""); if (use_browser <= 0) sleep(5); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e124741..e122970 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2241,10 +2241,11 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (err < 0) goto out_error_mmap; + if (!target__none(&trace->opts.target)) + perf_evlist__enable(evlist); + if (forks) perf_evlist__start_workload(evlist); - else - perf_evlist__enable(evlist); trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1 || @@ -2272,6 +2273,11 @@ next_event: if (interrupted) goto out_disable; + + if (done && !draining) { + perf_evlist__disable(evlist); + draining = true; + } } } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d8bb616..d05b77c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1084,6 +1084,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) * * TODO:Group name support */ + if (!arg) + return -EINVAL; ptr = strpbrk(arg, ";=@+%"); if (ptr && *ptr == '=') { /* Event name */ diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index b5bf9d5..2a76e14 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -578,10 +578,12 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) /* Search child die for local variables and parameters. */ if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { /* Search again in global variables */ - if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) + if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, + 0, &vr_die)) { pr_warning("Failed to find '%s' in this function.\n", pf->pvar->var); ret = -ENOENT; + } } if (ret >= 0) ret = convert_variable(&vr_die, pf); diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index ddf6356..5bdb781 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -1,4 +1,8 @@ -.PHONY: all all_32 all_64 check_build32 clean run_tests +all: + +include ../lib.mk + +.PHONY: all all_32 all_64 warn_32bit_failure clean TARGETS_C_BOTHBITS := sigreturn single_step_syscall @@ -7,42 +11,47 @@ BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -UNAME_P := $(shell uname -p) +UNAME_M := $(shell uname -m) +CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) -# Always build 32-bit tests +ifeq ($(CAN_BUILD_I386),1) all: all_32 +TEST_PROGS += $(BINARIES_32) +endif -# If we're on a 64-bit host, build 64-bit tests as well -ifeq ($(shell uname -p),x86_64) +ifeq ($(CAN_BUILD_X86_64),1) all: all_64 +TEST_PROGS += $(BINARIES_64) endif -all_32: check_build32 $(BINARIES_32) +all_32: $(BINARIES_32) all_64: $(BINARIES_64) clean: $(RM) $(BINARIES_32) $(BINARIES_64) -run_tests: - ./run_x86_tests.sh - $(TARGETS_C_BOTHBITS:%=%_32): %_32: %.c $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -check_build32: - @if ! $(CC) -m32 -o /dev/null trivial_32bit_program.c; then \ - echo "Warning: you seem to have a broken 32-bit build" 2>&1; \ - echo "environment. If you are using a Debian-like"; \ - echo " distribution, try:"; \ - echo ""; \ - echo " apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \ - echo ""; \ - echo "If you are using a Fedora-like distribution, try:"; \ - echo ""; \ - echo " yum install glibc-devel.*i686"; \ - exit 1; \ - fi +# x86_64 users should be encouraged to install 32-bit libraries +ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),01) +all: warn_32bit_failure + +warn_32bit_failure: + @echo "Warning: you seem to have a broken 32-bit build" 2>&1; \ + echo "environment. This will reduce test coverage of 64-bit" 2>&1; \ + echo "kernels. If you are using a Debian-like distribution," 2>&1; \ + echo "try:"; 2>&1; \ + echo ""; \ + echo " apt-get install gcc-multilib libc6-i386 libc6-dev-i386"; \ + echo ""; \ + echo "If you are using a Fedora-like distribution, try:"; \ + echo ""; \ + echo " yum install glibc-devel.*i686"; \ + exit 0; +endif diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selftests/x86/check_cc.sh new file mode 100755 index 0000000..172d329 --- /dev/null +++ b/tools/testing/selftests/x86/check_cc.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# check_cc.sh - Helper to test userspace compilation support +# Copyright (c) 2015 Andrew Lutomirski +# GPL v2 + +CC="$1" +TESTPROG="$2" +shift 2 + +if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then + echo 1 +else + echo 0 +fi + +exit 0 diff --git a/tools/testing/selftests/x86/run_x86_tests.sh b/tools/testing/selftests/x86/run_x86_tests.sh deleted file mode 100644 index 3fc19b3..0000000 --- a/tools/testing/selftests/x86/run_x86_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# This is deliberately minimal. IMO kselftests should provide a standard -# script here. -./sigreturn_32 || exit 1 -./single_step_syscall_32 || exit 1 - -if [[ "$uname -p" -eq "x86_64" ]]; then - ./sigreturn_64 || exit 1 - ./single_step_syscall_64 || exit 1 -fi - -exit 0 diff --git a/tools/testing/selftests/x86/trivial_32bit_program.c b/tools/testing/selftests/x86/trivial_32bit_program.c index 2e231be..fabdf0f 100644 --- a/tools/testing/selftests/x86/trivial_32bit_program.c +++ b/tools/testing/selftests/x86/trivial_32bit_program.c @@ -4,6 +4,10 @@ * GPL v2 */ +#ifndef __i386__ +# error wrong architecture +#endif + #include <stdio.h> int main() diff --git a/tools/testing/selftests/x86/trivial_64bit_program.c b/tools/testing/selftests/x86/trivial_64bit_program.c new file mode 100644 index 0000000..b994946 --- /dev/null +++ b/tools/testing/selftests/x86/trivial_64bit_program.c @@ -0,0 +1,18 @@ +/* + * Trivial program to check that we have a valid 32-bit build environment. + * Copyright (c) 2015 Andy Lutomirski + * GPL v2 + */ + +#ifndef __x86_64__ +# error wrong architecture +#endif + +#include <stdio.h> + +int main() +{ + printf("\n"); + + return 0; +} diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 0788621..2e83dd3 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile @@ -12,10 +12,6 @@ TARGET=tmon INSTALL_PROGRAM=install -m 755 -p DEL_FILE=rm -f -INSTALL_CONFIGFILE=install -m 644 -p -CONFIG_FILE= -CONFIG_PATH= - # Static builds might require -ltinfo, for instance ifneq ($(findstring -static, $(LDFLAGS)),) STATIC := --static @@ -38,13 +34,9 @@ valgrind: tmon install: - mkdir -p $(INSTALL_ROOT)/$(BINDIR) - $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" - - mkdir -p $(INSTALL_ROOT)/$(CONFIG_PATH) - - $(INSTALL_CONFIGFILE) "$(CONFIG_FILE)" "$(INSTALL_ROOT)/$(CONFIG_PATH)" uninstall: $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" - $(CONFIG_FILE) "$(CONFIG_PATH)" - clean: find . -name "*.o" | xargs $(DEL_FILE) diff --git a/tools/vm/Makefile b/tools/vm/Makefile index ac884b6..93aadaf 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile @@ -3,7 +3,7 @@ TARGETS=page-types slabinfo page_owner_sort LIB_DIR = ../lib/api -LIBS = $(LIB_DIR)/libapikfs.a +LIBS = $(LIB_DIR)/libapi.a CC = $(CROSS_COMPILE)gcc CFLAGS = -Wall -Wextra -I../lib/ |