diff options
400 files changed, 4787 insertions, 3415 deletions
diff --git a/Documentation/DocBook/filesystems.tmpl b/Documentation/DocBook/filesystems.tmpl index 3fca32c..25b58ef 100644 --- a/Documentation/DocBook/filesystems.tmpl +++ b/Documentation/DocBook/filesystems.tmpl @@ -224,8 +224,8 @@ all your transactions. </para> <para> -Then at umount time , in your put_super() (2.4) or write_super() (2.5) -you can then call journal_destroy() to clean up your in-core journal object. +Then at umount time , in your put_super() you can then call journal_destroy() +to clean up your in-core journal object. </para> <para> diff --git a/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/Documentation/devicetree/bindings/arm/mrvl/intc.txt index 80b9a94..8b53273 100644 --- a/Documentation/devicetree/bindings/arm/mrvl/intc.txt +++ b/Documentation/devicetree/bindings/arm/mrvl/intc.txt @@ -38,3 +38,23 @@ Example: reg-names = "mux status", "mux mask"; mrvl,intc-nr-irqs = <2>; }; + +* Marvell Orion Interrupt controller + +Required properties +- compatible : Should be "marvell,orion-intc". +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. Supported value is <1>. +- interrupt-controller : Declare this node to be an interrupt controller. +- reg : Interrupt mask address. A list of 4 byte ranges, one per controller. + One entry in the list represents 32 interrupts. + +Example: + + intc: interrupt-controller { + compatible = "marvell,orion-intc", "marvell,intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xfed20204 0x04>, + <0xfed20214 0x04>; + }; diff --git a/Documentation/devicetree/bindings/ata/marvell.txt b/Documentation/devicetree/bindings/ata/marvell.txt new file mode 100644 index 0000000..b5cdd20 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/marvell.txt @@ -0,0 +1,16 @@ +* Marvell Orion SATA + +Required Properties: +- compatibility : "marvell,orion-sata" +- reg : Address range of controller +- interrupts : Interrupt controller is using +- nr-ports : Number of SATA ports in use. + +Example: + + sata@80000 { + compatible = "marvell,orion-sata"; + reg = <0x80000 0x5000>; + interrupts = <21>; + nr-ports = <2>; + } diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 05428f3..e137874 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -27,3 +27,26 @@ Example: interrupt-controller; #interrupt-cells = <1>; }; + +* Marvell Orion GPIO Controller + +Required properties: +- compatible : Should be "marvell,orion-gpio" +- reg : Address and length of the register set for controller. +- gpio-controller : So we know this is a gpio controller. +- ngpio : How many gpios this controller has. +- interrupts : Up to 4 Interrupts for the controller. + +Optional properties: +- mask-offset : For SMP Orions, offset for Nth CPU + +Example: + + gpio0: gpio@10100 { + compatible = "marvell,orion-gpio"; + #gpio-cells = <2>; + gpio-controller; + reg = <0x10100 0x40>; + ngpio = <32>; + interrupts = <35>, <36>, <37>, <38>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt new file mode 100644 index 0000000..0b2503a --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -0,0 +1,14 @@ +* Marvell Orion Watchdog Time + +Required Properties: + +- Compatibility : "marvell,orion-wdt" +- reg : Address of the timer registers + +Example: + + wdt@20300 { + compatible = "marvell,orion-wdt"; + reg = <0x20300 0x28>; + status = "okay"; + }; diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 0f103e3..e540a24 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -114,7 +114,6 @@ prototypes: int (*drop_inode) (struct inode *); void (*evict_inode) (struct inode *); void (*put_super) (struct super_block *); - void (*write_super) (struct super_block *); int (*sync_fs)(struct super_block *sb, int wait); int (*freeze_fs) (struct super_block *); int (*unfreeze_fs) (struct super_block *); @@ -136,7 +135,6 @@ write_inode: drop_inode: !!!inode->i_lock!!! evict_inode: put_super: write -write_super: read sync_fs: read freeze_fs: write unfreeze_fs: write diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 2bef2b3..0742fee 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -94,9 +94,8 @@ protected. --- [mandatory] -BKL is also moved from around sb operations. ->write_super() Is now called -without BKL held. BKL should have been shifted into individual fs sb_op -functions. If you don't need it, remove it. +BKL is also moved from around sb operations. BKL should have been shifted into +individual fs sb_op functions. If you don't need it, remove it. --- [informational] diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 065aa2d..2ee133e 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -216,7 +216,6 @@ struct super_operations { void (*drop_inode) (struct inode *); void (*delete_inode) (struct inode *); void (*put_super) (struct super_block *); - void (*write_super) (struct super_block *); int (*sync_fs)(struct super_block *sb, int wait); int (*freeze_fs) (struct super_block *); int (*unfreeze_fs) (struct super_block *); @@ -273,9 +272,6 @@ or bottom half). put_super: called when the VFS wishes to free the superblock (i.e. unmount). This is called with the superblock lock held - write_super: called when the VFS superblock needs to be written to - disc. This method is optional - sync_fs: called when VFS is writing out all dirty data associated with a superblock. The second parameter indicates whether the method should wait until the write out has been completed. Optional. diff --git a/Documentation/laptops/laptop-mode.txt b/Documentation/laptops/laptop-mode.txt index 0bf25ee..4ebbfc3 100644 --- a/Documentation/laptops/laptop-mode.txt +++ b/Documentation/laptops/laptop-mode.txt @@ -262,9 +262,9 @@ MINIMUM_BATTERY_MINUTES=10 # # Allowed dirty background ratio, in percent. Once DIRTY_RATIO has been -# exceeded, the kernel will wake pdflush which will then reduce the amount -# of dirty memory to dirty_background_ratio. Set this nice and low, so once -# some writeout has commenced, we do a lot of it. +# exceeded, the kernel will wake flusher threads which will then reduce the +# amount of dirty memory to dirty_background_ratio. Set this nice and low, +# so once some writeout has commenced, we do a lot of it. # #DIRTY_BACKGROUND_RATIO=5 @@ -384,9 +384,9 @@ CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'} # # Allowed dirty background ratio, in percent. Once DIRTY_RATIO has been -# exceeded, the kernel will wake pdflush which will then reduce the amount -# of dirty memory to dirty_background_ratio. Set this nice and low, so once -# some writeout has commenced, we do a lot of it. +# exceeded, the kernel will wake flusher threads which will then reduce the +# amount of dirty memory to dirty_background_ratio. Set this nice and low, +# so once some writeout has commenced, we do a lot of it. # DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'} diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index dcc2a94..078701f 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -76,8 +76,8 @@ huge pages although processes will also directly compact memory as required. dirty_background_bytes -Contains the amount of dirty memory at which the pdflush background writeback -daemon will start writeback. +Contains the amount of dirty memory at which the background kernel +flusher threads will start writeback. Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only one of them may be specified at a time. When one sysctl is written it is @@ -89,7 +89,7 @@ other appears as 0 when read. dirty_background_ratio Contains, as a percentage of total system memory, the number of pages at which -the pdflush background writeback daemon will start writing out dirty data. +the background kernel flusher threads will start writing out dirty data. ============================================================== @@ -112,9 +112,9 @@ retained. dirty_expire_centisecs This tunable is used to define when dirty data is old enough to be eligible -for writeout by the pdflush daemons. It is expressed in 100'ths of a second. -Data which has been dirty in-memory for longer than this interval will be -written out next time a pdflush daemon wakes up. +for writeout by the kernel flusher threads. It is expressed in 100'ths +of a second. Data which has been dirty in-memory for longer than this +interval will be written out next time a flusher thread wakes up. ============================================================== @@ -128,7 +128,7 @@ data. dirty_writeback_centisecs -The pdflush writeback daemons will periodically wake up and write `old' data +The kernel flusher threads will periodically wake up and write `old' data out to disk. This tunable expresses the interval between those wakeups, in 100'ths of a second. diff --git a/MAINTAINERS b/MAINTAINERS index 94b823f..63ce3a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5329,14 +5329,15 @@ PIN CONTROL SUBSYSTEM M: Linus Walleij <linus.walleij@linaro.org> S: Maintained F: drivers/pinctrl/ +F: include/linux/pinctrl/ PIN CONTROLLER - ST SPEAR -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.st.com/spear S: Maintained -F: driver/pinctrl/spear/ +F: drivers/pinctrl/spear/ PKTCDVD DRIVER M: Peter Osterlund <petero2@telia.com> @@ -1,7 +1,7 @@ VERSION = 3 -PATCHLEVEL = 5 +PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7980873..e91c7cd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1151,6 +1151,7 @@ config PLAT_ORION bool select CLKSRC_MMIO select GENERIC_IRQ_CHIP + select IRQ_DOMAIN select COMMON_CLK config PLAT_PXA diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi index e1fa7e6..71d6b5d 100644 --- a/arch/arm/boot/dts/armada-xp.dtsi +++ b/arch/arm/boot/dts/armada-xp.dtsi @@ -12,7 +12,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. * - * Contains definitions specific to the Armada 370 SoC that are not + * Contains definitions specific to the Armada XP SoC that are not * common to all Armada SoCs. */ diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts index 9a33077..5bb0bf3 100644 --- a/arch/arm/boot/dts/kirkwood-dns320.dts +++ b/arch/arm/boot/dts/kirkwood-dns320.dts @@ -1,6 +1,6 @@ /dts-v1/; -/include/ "kirkwood.dtsi" +/include/ "kirkwood-dnskw.dtsi" / { model = "D-Link DNS-320 NAS (Rev A1)"; @@ -15,6 +15,31 @@ bootargs = "console=ttyS0,115200n8 earlyprintk"; }; + gpio-leds { + compatible = "gpio-leds"; + blue-power { + label = "dns320:blue:power"; + gpios = <&gpio0 26 1>; /* GPIO 26 Active Low */ + linux,default-trigger = "default-on"; + }; + blue-usb { + label = "dns320:blue:usb"; + gpios = <&gpio1 11 1>; /* GPIO 43 Active Low */ + }; + orange-l_hdd { + label = "dns320:orange:l_hdd"; + gpios = <&gpio0 28 1>; /* GPIO 28 Active Low */ + }; + orange-r_hdd { + label = "dns320:orange:r_hdd"; + gpios = <&gpio0 27 1>; /* GPIO 27 Active Low */ + }; + orange-usb { + label = "dns320:orange:usb"; + gpios = <&gpio1 3 1>; /* GPIO 35 Active Low */ + }; + }; + ocp@f1000000 { serial@12000 { clock-frequency = <166666667>; @@ -25,40 +50,5 @@ clock-frequency = <166666667>; status = "okay"; }; - - nand@3000000 { - status = "okay"; - - partition@0 { - label = "u-boot"; - reg = <0x0000000 0x100000>; - read-only; - }; - - partition@100000 { - label = "uImage"; - reg = <0x0100000 0x500000>; - }; - - partition@600000 { - label = "ramdisk"; - reg = <0x0600000 0x500000>; - }; - - partition@b00000 { - label = "image"; - reg = <0x0b00000 0x6600000>; - }; - - partition@7100000 { - label = "mini firmware"; - reg = <0x7100000 0xa00000>; - }; - - partition@7b00000 { - label = "config"; - reg = <0x7b00000 0x500000>; - }; - }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts index 16734c1..d430713 100644 --- a/arch/arm/boot/dts/kirkwood-dns325.dts +++ b/arch/arm/boot/dts/kirkwood-dns325.dts @@ -1,6 +1,6 @@ /dts-v1/; -/include/ "kirkwood.dtsi" +/include/ "kirkwood-dnskw.dtsi" / { model = "D-Link DNS-325 NAS (Rev A1)"; @@ -15,45 +15,43 @@ bootargs = "console=ttyS0,115200n8 earlyprintk"; }; - ocp@f1000000 { - serial@12000 { - clock-frequency = <200000000>; - status = "okay"; + gpio-leds { + compatible = "gpio-leds"; + white-power { + label = "dns325:white:power"; + gpios = <&gpio0 26 1>; /* GPIO 26 Active Low */ + linux,default-trigger = "default-on"; + }; + white-usb { + label = "dns325:white:usb"; + gpios = <&gpio1 11 1>; /* GPIO 43 Active Low */ + }; + red-l_hdd { + label = "dns325:red:l_hdd"; + gpios = <&gpio0 28 1>; /* GPIO 28 Active Low */ }; + red-r_hdd { + label = "dns325:red:r_hdd"; + gpios = <&gpio0 27 1>; /* GPIO 27 Active Low */ + }; + red-usb { + label = "dns325:red:usb"; + gpios = <&gpio0 29 1>; /* GPIO 29 Active Low */ + }; + }; - nand@3000000 { + ocp@f1000000 { + i2c@11000 { status = "okay"; - partition@0 { - label = "u-boot"; - reg = <0x0000000 0x100000>; - read-only; - }; - - partition@100000 { - label = "uImage"; - reg = <0x0100000 0x500000>; - }; - - partition@600000 { - label = "ramdisk"; - reg = <0x0600000 0x500000>; - }; - - partition@b00000 { - label = "image"; - reg = <0x0b00000 0x6600000>; - }; - - partition@7100000 { - label = "mini firmware"; - reg = <0x7100000 0xa00000>; - }; - - partition@7b00000 { - label = "config"; - reg = <0x7b00000 0x500000>; + lm75: lm75@48 { + compatible = "national,lm75"; + reg = <0x48>; }; }; + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-dnskw.dtsi b/arch/arm/boot/dts/kirkwood-dnskw.dtsi new file mode 100644 index 0000000..7408655 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-dnskw.dtsi @@ -0,0 +1,69 @@ +/include/ "kirkwood.dtsi" + +/ { + model = "D-Link DNS NASes (kirkwood-based)"; + compatible = "dlink,dns-kirkwood", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button@1 { + label = "Power button"; + linux,code = <116>; + gpios = <&gpio1 2 1>; + }; + button@2 { + label = "USB unmount button"; + linux,code = <161>; + gpios = <&gpio1 15 1>; + }; + button@3 { + label = "Reset button"; + linux,code = <0x198>; + gpios = <&gpio1 16 1>; + }; + }; + + ocp@f1000000 { + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + + nand@3000000 { + status = "okay"; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x500000>; + }; + + partition@600000 { + label = "ramdisk"; + reg = <0x0600000 0x500000>; + }; + + partition@b00000 { + label = "image"; + reg = <0x0b00000 0x6600000>; + }; + + partition@7100000 { + label = "mini firmware"; + reg = <0x7100000 0xa00000>; + }; + + partition@7b00000 { + label = "config"; + reg = <0x7b00000 0x500000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts index 78b0f06..26e281f 100644 --- a/arch/arm/boot/dts/kirkwood-dreamplug.dts +++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts @@ -20,5 +20,55 @@ clock-frequency = <200000000>; status = "ok"; }; + + spi@10600 { + status = "okay"; + + m25p40@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mx25l1606e"; + reg = <0>; + spi-max-frequency = <50000000>; + mode = <0>; + + partition@0 { + reg = <0x0 0x80000>; + label = "u-boot"; + }; + + partition@100000 { + reg = <0x100000 0x10000>; + label = "u-boot env"; + }; + + partition@180000 { + reg = <0x180000 0x10000>; + label = "dtb"; + }; + }; + }; + + sata@80000 { + status = "okay"; + nr-ports = <1>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + bluetooth { + label = "dreamplug:blue:bluetooth"; + gpios = <&gpio1 15 1>; + }; + wifi { + label = "dreamplug:green:wifi"; + gpios = <&gpio1 16 1>; + }; + wifi-ap { + label = "dreamplug:green:wifi_ap"; + gpios = <&gpio1 17 1>; + }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-goflexnet.dts b/arch/arm/boot/dts/kirkwood-goflexnet.dts new file mode 100644 index 0000000..7c8238f --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-goflexnet.dts @@ -0,0 +1,99 @@ +/dts-v1/; + +/include/ "kirkwood.dtsi" + +/ { + model = "Seagate GoFlex Net"; + compatible = "seagate,goflexnet", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk root=/dev/sda1 rootdelay=10"; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <200000000>; + status = "ok"; + }; + + nand@3000000 { + status = "okay"; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x400000>; + }; + + partition@500000 { + label = "pogoplug"; + reg = <0x0500000 0x2000000>; + }; + + partition@2500000 { + label = "root"; + reg = <0x02500000 0xd800000>; + }; + }; + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + + }; + gpio-leds { + compatible = "gpio-leds"; + + health { + label = "status:green:health"; + gpios = <&gpio1 14 1>; + linux,default-trigger = "default-on"; + }; + fault { + label = "status:orange:fault"; + gpios = <&gpio1 15 1>; + }; + left0 { + label = "status:white:left0"; + gpios = <&gpio1 10 0>; + }; + left1 { + label = "status:white:left1"; + gpios = <&gpio1 11 0>; + }; + left2 { + label = "status:white:left2"; + gpios = <&gpio1 12 0>; + }; + left3 { + label = "status:white:left3"; + gpios = <&gpio1 13 0>; + }; + right0 { + label = "status:white:right0"; + gpios = <&gpio1 6 0>; + }; + right1 { + label = "status:white:right1"; + gpios = <&gpio1 7 0>; + }; + right2 { + label = "status:white:right2"; + gpios = <&gpio1 8 0>; + }; + right3 { + label = "status:white:right3"; + gpios = <&gpio1 9 0>; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts index f59dcf6..66794ed 100644 --- a/arch/arm/boot/dts/kirkwood-ib62x0.dts +++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts @@ -21,6 +21,11 @@ status = "okay"; }; + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + nand@3000000 { status = "okay"; @@ -41,4 +46,37 @@ }; }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button@1 { + label = "USB Copy"; + linux,code = <133>; + gpios = <&gpio0 29 1>; + }; + button@2 { + label = "Reset"; + linux,code = <0x198>; + gpios = <&gpio0 28 1>; + }; + }; + gpio-leds { + compatible = "gpio-leds"; + + green-os { + label = "ib62x0:green:os"; + gpios = <&gpio0 25 0>; + linux,default-trigger = "default-on"; + }; + red-os { + label = "ib62x0:red:os"; + gpios = <&gpio0 22 0>; + }; + usb-copy { + label = "ib62x0:red:usb_copy"; + gpios = <&gpio0 27 0>; + }; + }; }; diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts index 026a1f8..52d9470 100644 --- a/arch/arm/boot/dts/kirkwood-iconnect.dts +++ b/arch/arm/boot/dts/kirkwood-iconnect.dts @@ -18,9 +18,51 @@ }; ocp@f1000000 { + i2c@11000 { + status = "okay"; + + lm63: lm63@4c { + compatible = "national,lm63"; + reg = <0x4c>; + }; + }; serial@12000 { clock-frequency = <200000000>; status = "ok"; }; }; + gpio-leds { + compatible = "gpio-leds"; + + led-level { + label = "led_level"; + gpios = <&gpio1 9 0>; + linux,default-trigger = "default-on"; + }; + power-blue { + label = "power:blue"; + gpios = <&gpio1 11 0>; + linux,default-trigger = "timer"; + }; + usb1 { + label = "usb1:blue"; + gpios = <&gpio1 12 0>; + }; + usb2 { + label = "usb2:blue"; + gpios = <&gpio1 13 0>; + }; + usb3 { + label = "usb3:blue"; + gpios = <&gpio1 14 0>; + }; + usb4 { + label = "usb4:blue"; + gpios = <&gpio1 15 0>; + }; + otb { + label = "otb:blue"; + gpios = <&gpio1 16 0>; + }; + }; }; diff --git a/arch/arm/boot/dts/kirkwood-lschlv2.dts b/arch/arm/boot/dts/kirkwood-lschlv2.dts new file mode 100644 index 0000000..9510c9e --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-lschlv2.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +/include/ "kirkwood-lsxl.dtsi" + +/ { + model = "Buffalo Linkstation LS-CHLv2"; + compatible = "buffalo,lschlv2", "buffalo,lsxl", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x4000000>; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <166666667>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-lsxhl.dts b/arch/arm/boot/dts/kirkwood-lsxhl.dts new file mode 100644 index 0000000..739019c --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-lsxhl.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +/include/ "kirkwood-lsxl.dtsi" + +/ { + model = "Buffalo Linkstation LS-XHL"; + compatible = "buffalo,lsxhl", "buffalo,lsxl", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-lsxl.dtsi b/arch/arm/boot/dts/kirkwood-lsxl.dtsi new file mode 100644 index 0000000..8ac51c0 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-lsxl.dtsi @@ -0,0 +1,95 @@ +/include/ "kirkwood.dtsi" + +/ { + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + }; + + ocp@f1000000 { + sata@80000 { + status = "okay"; + nr-ports = <1>; + }; + + spi@10600 { + status = "okay"; + + m25p40@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p40"; + reg = <0>; + spi-max-frequency = <25000000>; + mode = <0>; + + partition@0 { + reg = <0x0 0x60000>; + label = "uboot"; + read-only; + }; + + partition@60000 { + reg = <0x60000 0x10000>; + label = "dtb"; + read-only; + }; + + partition@70000 { + reg = <0x70000 0x10000>; + label = "uboot_env"; + }; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button@1 { + label = "Function Button"; + linux,code = <132>; + gpios = <&gpio1 9 1>; + }; + button@2 { + label = "Power-on Switch"; + linux,code = <116>; + gpios = <&gpio1 10 1>; + }; + button@3 { + label = "Power-auto Switch"; + linux,code = <142>; + gpios = <&gpio1 11 1>; + }; + }; + + gpio_leds { + compatible = "gpio-leds"; + + led@1 { + label = "lschlv2:blue:func"; + gpios = <&gpio1 4 1>; + }; + + led@2 { + label = "lschlv2:red:alarm"; + gpios = <&gpio1 5 1>; + }; + + led@3 { + label = "lschlv2:amber:info"; + gpios = <&gpio1 6 1>; + }; + + led@4 { + label = "lschlv2:blue:power"; + gpios = <&gpio1 7 1>; + linux,default-trigger = "default-on"; + }; + + led@5 { + label = "lschlv2:red:func"; + gpios = <&gpio1 16 1>; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-ts219-6281.dts b/arch/arm/boot/dts/kirkwood-ts219-6281.dts new file mode 100644 index 0000000..ccbf327 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts219-6281.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +/include/ "kirkwood-ts219.dtsi" + +/ { + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button@1 { + label = "USB Copy"; + linux,code = <133>; + gpios = <&gpio0 15 1>; + }; + button@2 { + label = "Reset"; + linux,code = <0x198>; + gpios = <&gpio0 16 1>; + }; + }; +};
\ No newline at end of file diff --git a/arch/arm/boot/dts/kirkwood-ts219-6282.dts b/arch/arm/boot/dts/kirkwood-ts219-6282.dts new file mode 100644 index 0000000..fbe9932 --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts219-6282.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +/include/ "kirkwood-ts219.dtsi" + +/ { + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button@1 { + label = "USB Copy"; + linux,code = <133>; + gpios = <&gpio1 11 1>; + }; + button@2 { + label = "Reset"; + linux,code = <0x198>; + gpios = <&gpio1 5 1>; + }; + }; +};
\ No newline at end of file diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi new file mode 100644 index 0000000..64ea27c --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi @@ -0,0 +1,78 @@ +/include/ "kirkwood.dtsi" + +/ { + model = "QNAP TS219 family"; + compatible = "qnap,ts219", "marvell,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + ocp@f1000000 { + i2c@11000 { + status = "okay"; + clock-frequency = <400000>; + + s35390a: s35390a@30 { + compatible = "s35390a"; + reg = <0x30>; + }; + }; + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; + serial@12100 { + clock-frequency = <200000000>; + status = "okay"; + }; + spi@10600 { + status = "okay"; + + m25p128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p128"; + reg = <0>; + spi-max-frequency = <20000000>; + mode = <0>; + + partition@0000000 { + reg = <0x00000000 0x00080000>; + label = "U-Boot"; + }; + + partition@00200000 { + reg = <0x00200000 0x00200000>; + label = "Kernel"; + }; + + partition@00400000 { + reg = <0x00400000 0x00900000>; + label = "RootFS1"; + }; + partition@00d00000 { + reg = <0x00d00000 0x00300000>; + label = "RootFS2"; + }; + partition@00040000 { + reg = <0x00080000 0x00040000>; + label = "U-Boot Config"; + }; + partition@000c0000 { + reg = <0x000c0000 0x00140000>; + label = "NAS Config"; + }; + }; + }; + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi index f95dbc1..cef9616 100644 --- a/arch/arm/boot/dts/kirkwood.dtsi +++ b/arch/arm/boot/dts/kirkwood.dtsi @@ -2,6 +2,15 @@ / { compatible = "marvell,kirkwood"; + interrupt-parent = <&intc>; + + intc: interrupt-controller { + compatible = "marvell,orion-intc", "marvell,intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xf1020204 0x04>, + <0xf1020214 0x04>; + }; ocp@f1000000 { compatible = "simple-bus"; @@ -9,6 +18,24 @@ #address-cells = <1>; #size-cells = <1>; + gpio0: gpio@10100 { + compatible = "marvell,orion-gpio"; + #gpio-cells = <2>; + gpio-controller; + reg = <0x10100 0x40>; + ngpio = <32>; + interrupts = <35>, <36>, <37>, <38>; + }; + + gpio1: gpio@10140 { + compatible = "marvell,orion-gpio"; + #gpio-cells = <2>; + gpio-controller; + reg = <0x10140 0x40>; + ngpio = <18>; + interrupts = <39>, <40>, <41>; + }; + serial@12000 { compatible = "ns16550a"; reg = <0x12000 0x100>; @@ -33,6 +60,29 @@ interrupts = <53>; }; + spi@10600 { + compatible = "marvell,orion-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + interrupts = <23>; + reg = <0x10600 0x28>; + status = "disabled"; + }; + + wdt@20300 { + compatible = "marvell,orion-wdt"; + reg = <0x20300 0x28>; + status = "okay"; + }; + + sata@80000 { + compatible = "marvell,orion-sata"; + reg = <0x80000 0x5000>; + interrupts = <21>; + status = "disabled"; + }; + nand@3000000 { #address-cells = <1>; #size-cells = <1>; @@ -45,5 +95,15 @@ /* set partition map and/or chip-delay in board dts */ status = "disabled"; }; + + i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <29>; + clock-frequency = <100000>; + status = "disabled"; + }; }; }; diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index f07fd16..9bc97a5 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -20,22 +20,6 @@ #include <mach/bridge-regs.h> #include "common.h" -static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - int irqoff; - BUG_ON(irq < IRQ_DOVE_GPIO_0_7 || irq > IRQ_DOVE_HIGH_GPIO); - - irqoff = irq <= IRQ_DOVE_GPIO_16_23 ? irq - IRQ_DOVE_GPIO_0_7 : - 3 + irq - IRQ_DOVE_GPIO_24_31; - - orion_gpio_irq_handler(irqoff << 3); - if (irq == IRQ_DOVE_HIGH_GPIO) { - orion_gpio_irq_handler(40); - orion_gpio_irq_handler(48); - orion_gpio_irq_handler(56); - } -} - static void pmu_irq_mask(struct irq_data *d) { int pin = irq_to_pmu(d->irq); @@ -90,6 +74,27 @@ static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc) } } +static int __initdata gpio0_irqs[4] = { + IRQ_DOVE_GPIO_0_7, + IRQ_DOVE_GPIO_8_15, + IRQ_DOVE_GPIO_16_23, + IRQ_DOVE_GPIO_24_31, +}; + +static int __initdata gpio1_irqs[4] = { + IRQ_DOVE_HIGH_GPIO, + 0, + 0, + 0, +}; + +static int __initdata gpio2_irqs[4] = { + 0, + 0, + 0, + 0, +}; + void __init dove_init_irq(void) { int i; @@ -100,19 +105,14 @@ void __init dove_init_irq(void) /* * Initialize gpiolib for GPIOs 0-71. */ - orion_gpio_init(0, 32, DOVE_GPIO_LO_VIRT_BASE, 0, - IRQ_DOVE_GPIO_START); - irq_set_chained_handler(IRQ_DOVE_GPIO_0_7, gpio_irq_handler); - irq_set_chained_handler(IRQ_DOVE_GPIO_8_15, gpio_irq_handler); - irq_set_chained_handler(IRQ_DOVE_GPIO_16_23, gpio_irq_handler); - irq_set_chained_handler(IRQ_DOVE_GPIO_24_31, gpio_irq_handler); - - orion_gpio_init(32, 32, DOVE_GPIO_HI_VIRT_BASE, 0, - IRQ_DOVE_GPIO_START + 32); - irq_set_chained_handler(IRQ_DOVE_HIGH_GPIO, gpio_irq_handler); - - orion_gpio_init(64, 8, DOVE_GPIO2_VIRT_BASE, 0, - IRQ_DOVE_GPIO_START + 64); + orion_gpio_init(NULL, 0, 32, (void __iomem *)DOVE_GPIO_LO_VIRT_BASE, 0, + IRQ_DOVE_GPIO_START, gpio0_irqs); + + orion_gpio_init(NULL, 32, 32, (void __iomem *)DOVE_GPIO_HI_VIRT_BASE, 0, + IRQ_DOVE_GPIO_START + 32, gpio1_irqs); + + orion_gpio_init(NULL, 64, 8, (void __iomem *)DOVE_GPIO2_VIRT_BASE, 0, + IRQ_DOVE_GPIO_START + 64, gpio2_irqs); /* * Mask and clear PMU interrupts diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig index 199764f..ca5c15a 100644 --- a/arch/arm/mach-kirkwood/Kconfig +++ b/arch/arm/mach-kirkwood/Kconfig @@ -80,6 +80,35 @@ config MACH_IB62X0_DT RaidSonic IB-NAS6210 & IB-NAS6220 devices, using Flattened Device Tree. +config MACH_TS219_DT + bool "Device Tree for QNAP TS-11X, TS-21X NAS" + select ARCH_KIRKWOOD_DT + select ARM_APPENDED_DTB + select ARM_ATAG_DTB_COMPAT + help + Say 'Y' here if you want your kernel to support the QNAP + TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and + TS-219P+ Turbo NAS devices using Fattened Device Tree. + There are two different Device Tree descriptions, depending + on if the device is based on an if the board uses the MV6281 + or MV6282. If you have the wrong one, the buttons will not + work. + +config MACH_GOFLEXNET_DT + bool "Seagate GoFlex Net (Flattened Device Tree)" + select ARCH_KIRKWOOD_DT + help + Say 'Y' here if you want your kernel to support the + Seagate GoFlex Net (Flattened Device Tree). + +config MACH_LSXL_DT + bool "Buffalo Linkstation LS-XHL, LS-CHLv2 (Flattened Device Tree)" + select ARCH_KIRKWOOD_DT + help + Say 'Y' here if you want your kernel to support the + Buffalo Linkstation LS-XHL & LS-CHLv2 devices, using + Flattened Device Tree. + config MACH_TS219 bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS" help diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile index d2b0590..055c85a 100644 --- a/arch/arm/mach-kirkwood/Makefile +++ b/arch/arm/mach-kirkwood/Makefile @@ -25,3 +25,6 @@ obj-$(CONFIG_MACH_DREAMPLUG_DT) += board-dreamplug.o obj-$(CONFIG_MACH_ICONNECT_DT) += board-iconnect.o obj-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += board-dnskw.o obj-$(CONFIG_MACH_IB62X0_DT) += board-ib62x0.o +obj-$(CONFIG_MACH_TS219_DT) += board-ts219.o tsx1x-common.o +obj-$(CONFIG_MACH_GOFLEXNET_DT) += board-goflexnet.o +obj-$(CONFIG_MACH_LSXL_DT) += board-lsxl.o diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot index 02edbdf..2a576ab 100644 --- a/arch/arm/mach-kirkwood/Makefile.boot +++ b/arch/arm/mach-kirkwood/Makefile.boot @@ -7,3 +7,7 @@ dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb +dtb-$(CONFIG_MACH_TS219_DT) += kirkwood-qnap-ts219.dtb +dtb-$(CONFIG_MACH_GOFLEXNET_DT) += kirkwood-goflexnet.dtb +dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb +dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb diff --git a/arch/arm/mach-kirkwood/board-dnskw.c b/arch/arm/mach-kirkwood/board-dnskw.c index 58c2d68..4ab3506 100644 --- a/arch/arm/mach-kirkwood/board-dnskw.c +++ b/arch/arm/mach-kirkwood/board-dnskw.c @@ -14,13 +14,11 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/i2c.h> #include <linux/ata_platform.h> #include <linux/mv643xx_eth.h> #include <linux/of.h> #include <linux/gpio.h> #include <linux/input.h> -#include <linux/gpio_keys.h> #include <linux/gpio-fan.h> #include <linux/leds.h> #include <asm/mach-types.h> @@ -35,10 +33,6 @@ static struct mv643xx_eth_platform_data dnskw_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(8), }; -static struct mv_sata_platform_data dnskw_sata_data = { - .n_ports = 2, -}; - static unsigned int dnskw_mpp_config[] __initdata = { MPP13_UART1_TXD, /* Custom ... */ MPP14_UART1_RXD, /* ... Controller (DNS-320 only) */ @@ -73,132 +67,6 @@ static unsigned int dnskw_mpp_config[] __initdata = { 0 }; -static struct gpio_led dns325_led_pins[] = { - { - .name = "dns325:white:power", - .gpio = 26, - .active_low = 1, - .default_trigger = "default-on", - }, - { - .name = "dns325:white:usb", - .gpio = 43, - .active_low = 1, - }, - { - .name = "dns325:red:l_hdd", - .gpio = 28, - .active_low = 1, - }, - { - .name = "dns325:red:r_hdd", - .gpio = 27, - .active_low = 1, - }, - { - .name = "dns325:red:usb", - .gpio = 29, - .active_low = 1, - }, -}; - -static struct gpio_led_platform_data dns325_led_data = { - .num_leds = ARRAY_SIZE(dns325_led_pins), - .leds = dns325_led_pins, -}; - -static struct platform_device dns325_led_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &dns325_led_data, - }, -}; - -static struct gpio_led dns320_led_pins[] = { - { - .name = "dns320:blue:power", - .gpio = 26, - .active_low = 1, - .default_trigger = "default-on", - }, - { - .name = "dns320:blue:usb", - .gpio = 43, - .active_low = 1, - }, - { - .name = "dns320:orange:l_hdd", - .gpio = 28, - .active_low = 1, - }, - { - .name = "dns320:orange:r_hdd", - .gpio = 27, - .active_low = 1, - }, - { - .name = "dns320:orange:usb", - .gpio = 35, - .active_low = 1, - }, -}; - -static struct gpio_led_platform_data dns320_led_data = { - .num_leds = ARRAY_SIZE(dns320_led_pins), - .leds = dns320_led_pins, -}; - -static struct platform_device dns320_led_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &dns320_led_data, - }, -}; - -static struct i2c_board_info dns325_i2c_board_info[] __initdata = { - { - I2C_BOARD_INFO("lm75", 0x48), - }, - /* Something at 0x0c also */ -}; - -static struct gpio_keys_button dnskw_button_pins[] = { - { - .code = KEY_POWER, - .gpio = 34, - .desc = "Power button", - .active_low = 1, - }, - { - .code = KEY_EJECTCD, - .gpio = 47, - .desc = "USB unmount button", - .active_low = 1, - }, - { - .code = KEY_RESTART, - .gpio = 48, - .desc = "Reset button", - .active_low = 1, - }, -}; - -static struct gpio_keys_platform_data dnskw_button_data = { - .buttons = dnskw_button_pins, - .nbuttons = ARRAY_SIZE(dnskw_button_pins), -}; - -static struct platform_device dnskw_button_device = { - .name = "gpio-keys", - .id = -1, - .num_resources = 0, - .dev = { - .platform_data = &dnskw_button_data, - } -}; - /* Fan: ADDA AD045HB-G73 40mm 6000rpm@5v */ static struct gpio_fan_speed dnskw_fan_speed[] = { { 0, 0 }, @@ -245,20 +113,9 @@ void __init dnskw_init(void) kirkwood_ehci_init(); kirkwood_ge00_init(&dnskw_ge00_data); - kirkwood_sata_init(&dnskw_sata_data); - kirkwood_i2c_init(); - platform_device_register(&dnskw_button_device); platform_device_register(&dnskw_fan_device); - if (of_machine_is_compatible("dlink,dns-325")) { - i2c_register_board_info(0, dns325_i2c_board_info, - ARRAY_SIZE(dns325_i2c_board_info)); - platform_device_register(&dns325_led_device); - - } else if (of_machine_is_compatible("dlink,dns-320")) - platform_device_register(&dns320_led_device); - /* Register power-off GPIO. */ if (gpio_request(36, "dnskw:power:off") == 0 && gpio_direction_output(36, 0) == 0) diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c index 55e357a..aeb234d 100644 --- a/arch/arm/mach-kirkwood/board-dreamplug.c +++ b/arch/arm/mach-kirkwood/board-dreamplug.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/mtd/partitions.h> #include <linux/ata_platform.h> #include <linux/mv643xx_eth.h> #include <linux/of.h> @@ -23,7 +22,6 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio.h> -#include <linux/leds.h> #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> @@ -36,42 +34,6 @@ #include "common.h" #include "mpp.h" -struct mtd_partition dreamplug_partitions[] = { - { - .name = "u-boot", - .size = SZ_512K, - .offset = 0, - }, - { - .name = "u-boot env", - .size = SZ_64K, - .offset = SZ_512K + SZ_512K, - }, - { - .name = "dtb", - .size = SZ_64K, - .offset = SZ_512K + SZ_512K + SZ_512K, - }, -}; - -static const struct flash_platform_data dreamplug_spi_slave_data = { - .type = "mx25l1606e", - .name = "spi_flash", - .parts = dreamplug_partitions, - .nr_parts = ARRAY_SIZE(dreamplug_partitions), -}; - -static struct spi_board_info __initdata dreamplug_spi_slave_info[] = { - { - .modalias = "m25p80", - .platform_data = &dreamplug_spi_slave_data, - .irq = -1, - .max_speed_hz = 50000000, - .bus_num = 0, - .chip_select = 0, - }, -}; - static struct mv643xx_eth_platform_data dreamplug_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(0), }; @@ -80,45 +42,10 @@ static struct mv643xx_eth_platform_data dreamplug_ge01_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(1), }; -static struct mv_sata_platform_data dreamplug_sata_data = { - .n_ports = 1, -}; - static struct mvsdio_platform_data dreamplug_mvsdio_data = { /* unfortunately the CD signal has not been connected */ }; -static struct gpio_led dreamplug_led_pins[] = { - { - .name = "dreamplug:blue:bluetooth", - .gpio = 47, - .active_low = 1, - }, - { - .name = "dreamplug:green:wifi", - .gpio = 48, - .active_low = 1, - }, - { - .name = "dreamplug:green:wifi_ap", - .gpio = 49, - .active_low = 1, - }, -}; - -static struct gpio_led_platform_data dreamplug_led_data = { - .leds = dreamplug_led_pins, - .num_leds = ARRAY_SIZE(dreamplug_led_pins), -}; - -static struct platform_device dreamplug_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &dreamplug_led_data, - } -}; - static unsigned int dreamplug_mpp_config[] __initdata = { MPP0_SPI_SCn, MPP1_SPI_MOSI, @@ -137,15 +64,8 @@ void __init dreamplug_init(void) */ kirkwood_mpp_conf(dreamplug_mpp_config); - spi_register_board_info(dreamplug_spi_slave_info, - ARRAY_SIZE(dreamplug_spi_slave_info)); - kirkwood_spi_init(); - kirkwood_ehci_init(); kirkwood_ge00_init(&dreamplug_ge00_data); kirkwood_ge01_init(&dreamplug_ge01_data); - kirkwood_sata_init(&dreamplug_sata_data); kirkwood_sdio_init(&dreamplug_mvsdio_data); - - platform_device_register(&dreamplug_leds); } diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index edc3f8a..e4eb450 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -18,6 +18,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <mach/bridge-regs.h> +#include <plat/irq.h> #include "common.h" static struct of_device_id kirkwood_dt_match_table[] __initdata = { @@ -25,6 +26,16 @@ static struct of_device_id kirkwood_dt_match_table[] __initdata = { { } }; +struct of_dev_auxdata kirkwood_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL), + OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0", + NULL), + OF_DEV_AUXDATA("marvell,orion-wdt", 0xf1020300, "orion_wdt", NULL), + OF_DEV_AUXDATA("marvell,orion-sata", 0xf1080000, "sata_mv.0", NULL), + OF_DEV_AUXDATA("marvell,orion-nand", 0xf4000000, "orion_nand", NULL), + {}, +}; + static void __init kirkwood_dt_init(void) { pr_info("Kirkwood: %s, TCLK=%d.\n", kirkwood_id(), kirkwood_tclk); @@ -47,7 +58,6 @@ static void __init kirkwood_dt_init(void) kirkwood_clk_init(); /* internal devices that every board has */ - kirkwood_wdt_init(); kirkwood_xor0_init(); kirkwood_xor1_init(); kirkwood_crypto_init(); @@ -68,7 +78,17 @@ static void __init kirkwood_dt_init(void) if (of_machine_is_compatible("raidsonic,ib-nas62x0")) ib62x0_init(); - of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL); + if (of_machine_is_compatible("qnap,ts219")) + qnap_dt_ts219_init(); + + if (of_machine_is_compatible("seagate,goflexnet")) + goflexnet_init(); + + if (of_machine_is_compatible("buffalo,lsxl")) + lsxl_init(); + + of_platform_populate(NULL, kirkwood_dt_match_table, + kirkwood_auxdata_lookup, NULL); } static const char *kirkwood_dt_board_compat[] = { @@ -77,6 +97,9 @@ static const char *kirkwood_dt_board_compat[] = { "dlink,dns-325", "iom,iconnect", "raidsonic,ib-nas62x0", + "qnap,ts219", + "seagate,goflexnet", + "buffalo,lsxl", NULL }; @@ -84,7 +107,7 @@ DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)") /* Maintainer: Jason Cooper <jason@lakedaemon.net> */ .map_io = kirkwood_map_io, .init_early = kirkwood_init_early, - .init_irq = kirkwood_init_irq, + .init_irq = orion_dt_init_irq, .timer = &kirkwood_timer, .init_machine = kirkwood_dt_init, .restart = kirkwood_restart, diff --git a/arch/arm/mach-kirkwood/board-goflexnet.c b/arch/arm/mach-kirkwood/board-goflexnet.c new file mode 100644 index 0000000..413e2c8 --- /dev/null +++ b/arch/arm/mach-kirkwood/board-goflexnet.c @@ -0,0 +1,71 @@ +/* + * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net> + * + * arch/arm/mach-kirkwood/board-goflexnet.c + * + * Seagate GoFlext Net Board Init for drivers not converted to + * flattened device tree yet. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * Copied and modified for Seagate GoFlex Net support by + * Joshua Coombs <josh.coombs@gmail.com> based on ArchLinux ARM's + * GoFlex kernel patches. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/ata_platform.h> +#include <linux/mv643xx_eth.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/gpio.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <mach/kirkwood.h> +#include <mach/bridge-regs.h> +#include <plat/mvsdio.h> +#include "common.h" +#include "mpp.h" + +static struct mv643xx_eth_platform_data goflexnet_ge00_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(0), +}; + +static unsigned int goflexnet_mpp_config[] __initdata = { + MPP29_GPIO, /* USB Power Enable */ + MPP47_GPIO, /* LED Orange */ + MPP46_GPIO, /* LED Green */ + MPP45_GPIO, /* LED Left Capacity 3 */ + MPP44_GPIO, /* LED Left Capacity 2 */ + MPP43_GPIO, /* LED Left Capacity 1 */ + MPP42_GPIO, /* LED Left Capacity 0 */ + MPP41_GPIO, /* LED Right Capacity 3 */ + MPP40_GPIO, /* LED Right Capacity 2 */ + MPP39_GPIO, /* LED Right Capacity 1 */ + MPP38_GPIO, /* LED Right Capacity 0 */ + 0 +}; + +void __init goflexnet_init(void) +{ + /* + * Basic setup. Needs to be called early. + */ + kirkwood_mpp_conf(goflexnet_mpp_config); + + if (gpio_request(29, "USB Power Enable") != 0 || + gpio_direction_output(29, 1) != 0) + pr_err("can't setup GPIO 29 (USB Power Enable)\n"); + kirkwood_ehci_init(); + + kirkwood_ge00_init(&goflexnet_ge00_data); +} diff --git a/arch/arm/mach-kirkwood/board-ib62x0.c b/arch/arm/mach-kirkwood/board-ib62x0.c index eddf1df..cfc47f8 100644 --- a/arch/arm/mach-kirkwood/board-ib62x0.c +++ b/arch/arm/mach-kirkwood/board-ib62x0.c @@ -18,9 +18,7 @@ #include <linux/ata_platform.h> #include <linux/mv643xx_eth.h> #include <linux/gpio.h> -#include <linux/gpio_keys.h> #include <linux/input.h> -#include <linux/leds.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/kirkwood.h> @@ -33,10 +31,6 @@ static struct mv643xx_eth_platform_data ib62x0_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(8), }; -static struct mv_sata_platform_data ib62x0_sata_data = { - .n_ports = 2, -}; - static unsigned int ib62x0_mpp_config[] __initdata = { MPP0_NF_IO2, MPP1_NF_IO3, @@ -55,69 +49,6 @@ static unsigned int ib62x0_mpp_config[] __initdata = { 0 }; -static struct gpio_led ib62x0_led_pins[] = { - { - .name = "ib62x0:green:os", - .default_trigger = "default-on", - .gpio = 25, - .active_low = 0, - }, - { - .name = "ib62x0:red:os", - .default_trigger = "none", - .gpio = 22, - .active_low = 0, - }, - { - .name = "ib62x0:red:usb_copy", - .default_trigger = "none", - .gpio = 27, - .active_low = 0, - }, -}; - -static struct gpio_led_platform_data ib62x0_led_data = { - .leds = ib62x0_led_pins, - .num_leds = ARRAY_SIZE(ib62x0_led_pins), -}; - -static struct platform_device ib62x0_led_device = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &ib62x0_led_data, - } -}; - -static struct gpio_keys_button ib62x0_button_pins[] = { - { - .code = KEY_COPY, - .gpio = 29, - .desc = "USB Copy", - .active_low = 1, - }, - { - .code = KEY_RESTART, - .gpio = 28, - .desc = "Reset", - .active_low = 1, - }, -}; - -static struct gpio_keys_platform_data ib62x0_button_data = { - .buttons = ib62x0_button_pins, - .nbuttons = ARRAY_SIZE(ib62x0_button_pins), -}; - -static struct platform_device ib62x0_button_device = { - .name = "gpio-keys", - .id = -1, - .num_resources = 0, - .dev = { - .platform_data = &ib62x0_button_data, - } -}; - static void ib62x0_power_off(void) { gpio_set_value(IB62X0_GPIO_POWER_OFF, 1); @@ -132,9 +63,6 @@ void __init ib62x0_init(void) kirkwood_ehci_init(); kirkwood_ge00_init(&ib62x0_ge00_data); - kirkwood_sata_init(&ib62x0_sata_data); - platform_device_register(&ib62x0_led_device); - platform_device_register(&ib62x0_button_device); if (gpio_request(IB62X0_GPIO_POWER_OFF, "ib62x0:power:off") == 0 && gpio_direction_output(IB62X0_GPIO_POWER_OFF, 0) == 0) pm_power_off = ib62x0_power_off; diff --git a/arch/arm/mach-kirkwood/board-iconnect.c b/arch/arm/mach-kirkwood/board-iconnect.c index b0d3cc4..d7a9198 100644 --- a/arch/arm/mach-kirkwood/board-iconnect.c +++ b/arch/arm/mach-kirkwood/board-iconnect.c @@ -19,8 +19,6 @@ #include <linux/mtd/partitions.h> #include <linux/mv643xx_eth.h> #include <linux/gpio.h> -#include <linux/leds.h> -#include <linux/i2c.h> #include <linux/input.h> #include <linux/gpio_keys.h> #include <asm/mach/arch.h> @@ -32,50 +30,6 @@ static struct mv643xx_eth_platform_data iconnect_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(11), }; -static struct gpio_led iconnect_led_pins[] = { - { - .name = "led_level", - .gpio = 41, - .default_trigger = "default-on", - }, { - .name = "power:blue", - .gpio = 42, - .default_trigger = "timer", - }, { - .name = "power:red", - .gpio = 43, - }, { - .name = "usb1:blue", - .gpio = 44, - }, { - .name = "usb2:blue", - .gpio = 45, - }, { - .name = "usb3:blue", - .gpio = 46, - }, { - .name = "usb4:blue", - .gpio = 47, - }, { - .name = "otb:blue", - .gpio = 48, - }, -}; - -static struct gpio_led_platform_data iconnect_led_data = { - .leds = iconnect_led_pins, - .num_leds = ARRAY_SIZE(iconnect_led_pins), - .gpio_blink_set = orion_gpio_led_blink_set, -}; - -static struct platform_device iconnect_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &iconnect_led_data, - } -}; - static unsigned int iconnect_mpp_config[] __initdata = { MPP12_GPIO, MPP35_GPIO, @@ -90,12 +44,6 @@ static unsigned int iconnect_mpp_config[] __initdata = { 0 }; -static struct i2c_board_info __initdata iconnect_board_info[] = { - { - I2C_BOARD_INFO("lm63", 0x4c), - }, -}; - static struct mtd_partition iconnect_nand_parts[] = { { .name = "flash", @@ -142,15 +90,11 @@ void __init iconnect_init(void) { kirkwood_mpp_conf(iconnect_mpp_config); kirkwood_nand_init(ARRAY_AND_SIZE(iconnect_nand_parts), 25); - kirkwood_i2c_init(); - i2c_register_board_info(0, iconnect_board_info, - ARRAY_SIZE(iconnect_board_info)); kirkwood_ehci_init(); kirkwood_ge00_init(&iconnect_ge00_data); platform_device_register(&iconnect_button_device); - platform_device_register(&iconnect_leds); } static int __init iconnect_pci_init(void) diff --git a/arch/arm/mach-kirkwood/board-lsxl.c b/arch/arm/mach-kirkwood/board-lsxl.c new file mode 100644 index 0000000..83d8975 --- /dev/null +++ b/arch/arm/mach-kirkwood/board-lsxl.c @@ -0,0 +1,135 @@ +/* + * Copyright 2012 (C), Michael Walle <michael@walle.cc> + * + * arch/arm/mach-kirkwood/board-lsxl.c + * + * Buffalo Linkstation LS-XHL and LS-CHLv2 init for drivers not + * converted to flattened device tree yet. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/partitions.h> +#include <linux/ata_platform.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/mv643xx_eth.h> +#include <linux/gpio.h> +#include <linux/gpio-fan.h> +#include <linux/input.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <mach/kirkwood.h> +#include "common.h" +#include "mpp.h" + +static struct mv643xx_eth_platform_data lsxl_ge00_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(0), +}; + +static struct mv643xx_eth_platform_data lsxl_ge01_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), +}; + +static unsigned int lsxl_mpp_config[] __initdata = { + MPP10_GPO, /* HDD Power Enable */ + MPP11_GPIO, /* USB Vbus Enable */ + MPP18_GPO, /* FAN High Enable# */ + MPP19_GPO, /* FAN Low Enable# */ + MPP36_GPIO, /* Function Blue LED */ + MPP37_GPIO, /* Alarm LED */ + MPP38_GPIO, /* Info LED */ + MPP39_GPIO, /* Power LED */ + MPP40_GPIO, /* Fan Lock */ + MPP41_GPIO, /* Function Button */ + MPP42_GPIO, /* Power Switch */ + MPP43_GPIO, /* Power Auto Switch */ + MPP48_GPIO, /* Function Red LED */ + 0 +}; + +#define LSXL_GPIO_FAN_HIGH 18 +#define LSXL_GPIO_FAN_LOW 19 +#define LSXL_GPIO_FAN_LOCK 40 + +static struct gpio_fan_alarm lsxl_alarm = { + .gpio = LSXL_GPIO_FAN_LOCK, +}; + +static struct gpio_fan_speed lsxl_speeds[] = { + { + .rpm = 0, + .ctrl_val = 3, + }, { + .rpm = 1500, + .ctrl_val = 1, + }, { + .rpm = 3250, + .ctrl_val = 2, + }, { + .rpm = 5000, + .ctrl_val = 0, + } +}; + +static int lsxl_gpio_list[] = { + LSXL_GPIO_FAN_HIGH, LSXL_GPIO_FAN_LOW, +}; + +static struct gpio_fan_platform_data lsxl_fan_data = { + .num_ctrl = ARRAY_SIZE(lsxl_gpio_list), + .ctrl = lsxl_gpio_list, + .alarm = &lsxl_alarm, + .num_speed = ARRAY_SIZE(lsxl_speeds), + .speed = lsxl_speeds, +}; + +static struct platform_device lsxl_fan_device = { + .name = "gpio-fan", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &lsxl_fan_data, + }, +}; + +/* + * On the LS-XHL/LS-CHLv2, the shutdown process is following: + * - Userland monitors key events until the power switch goes to off position + * - The board reboots + * - U-boot starts and goes into an idle mode waiting for the user + * to move the switch to ON position + * + */ +static void lsxl_power_off(void) +{ + kirkwood_restart('h', NULL); +} + +#define LSXL_GPIO_HDD_POWER 10 +#define LSXL_GPIO_USB_POWER 11 + +void __init lsxl_init(void) +{ + /* + * Basic setup. Needs to be called early. + */ + kirkwood_mpp_conf(lsxl_mpp_config); + + /* usb and sata power on */ + gpio_set_value(LSXL_GPIO_USB_POWER, 1); + gpio_set_value(LSXL_GPIO_HDD_POWER, 1); + + kirkwood_ehci_init(); + kirkwood_ge00_init(&lsxl_ge00_data); + kirkwood_ge01_init(&lsxl_ge01_data); + platform_device_register(&lsxl_fan_device); + + /* register power-off method */ + pm_power_off = lsxl_power_off; +} diff --git a/arch/arm/mach-kirkwood/board-ts219.c b/arch/arm/mach-kirkwood/board-ts219.c new file mode 100644 index 0000000..1750e68 --- /dev/null +++ b/arch/arm/mach-kirkwood/board-ts219.c @@ -0,0 +1,82 @@ +/* + * + * QNAP TS-11x/TS-21x Turbo NAS Board Setup via DT + * + * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch> + * + * Based on the board file ts219-setup.c: + * + * Copyright (C) 2009 Martin Michlmayr <tbm@cyrius.com> + * Copyright (C) 2008 Byron Bradley <byron.bbradley@gmail.com> + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mv643xx_eth.h> +#include <linux/ata_platform.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <mach/kirkwood.h> +#include "common.h" +#include "mpp.h" +#include "tsx1x-common.h" + +static struct mv643xx_eth_platform_data qnap_ts219_ge00_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), +}; + +static unsigned int qnap_ts219_mpp_config[] __initdata = { + MPP0_SPI_SCn, + MPP1_SPI_MOSI, + MPP2_SPI_SCK, + MPP3_SPI_MISO, + MPP4_SATA1_ACTn, + MPP5_SATA0_ACTn, + MPP8_TW0_SDA, + MPP9_TW0_SCK, + MPP10_UART0_TXD, + MPP11_UART0_RXD, + MPP13_UART1_TXD, /* PIC controller */ + MPP14_UART1_RXD, /* PIC controller */ + MPP15_GPIO, /* USB Copy button (on devices with 88F6281) */ + MPP16_GPIO, /* Reset button (on devices with 88F6281) */ + MPP36_GPIO, /* RAM: 0: 256 MB, 1: 512 MB */ + MPP37_GPIO, /* Reset button (on devices with 88F6282) */ + MPP43_GPIO, /* USB Copy button (on devices with 88F6282) */ + MPP44_GPIO, /* Board ID: 0: TS-11x, 1: TS-21x */ + 0 +}; + +void __init qnap_dt_ts219_init(void) +{ + u32 dev, rev; + + kirkwood_mpp_conf(qnap_ts219_mpp_config); + + kirkwood_pcie_id(&dev, &rev); + if (dev == MV88F6282_DEV_ID) + qnap_ts219_ge00_data.phy_addr = MV643XX_ETH_PHY_ADDR(0); + + kirkwood_ge00_init(&qnap_ts219_ge00_data); + kirkwood_ehci_init(); + + pm_power_off = qnap_tsx1x_power_off; +} + +/* FIXME: Will not work with DT. Maybe use MPP40_GPIO? */ +static int __init ts219_pci_init(void) +{ + if (machine_is_ts219()) + kirkwood_pcie_init(KW_PCIE0); + + return 0; +} +subsys_initcall(ts219_pci_init); diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index c920153..c4b64ad 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -17,6 +17,7 @@ #include <linux/dma-mapping.h> #include <linux/clk-provider.h> #include <linux/spinlock.h> +#include <linux/mv643xx_i2c.h> #include <net/dsa.h> #include <asm/page.h> #include <asm/timex.h> @@ -276,6 +277,7 @@ void __init kirkwood_clk_init(void) orion_clkdev_add("0", "pcie", pex0); orion_clkdev_add("1", "pcie", pex1); orion_clkdev_add(NULL, "kirkwood-i2s", audio); + orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", runit); /* Marvell says runit is used by SPI, UART, NAND, TWSI, ..., * so should never be gated. diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index 9248fa2..304dd1a 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -58,6 +58,11 @@ void dreamplug_init(void); #else static inline void dreamplug_init(void) {}; #endif +#ifdef CONFIG_MACH_TS219_DT +void qnap_dt_ts219_init(void); +#else +static inline void qnap_dt_ts219_init(void) {}; +#endif #ifdef CONFIG_MACH_DLINK_KIRKWOOD_DT void dnskw_init(void); @@ -77,6 +82,18 @@ void ib62x0_init(void); static inline void ib62x0_init(void) {}; #endif +#ifdef CONFIG_MACH_GOFLEXNET_DT +void goflexnet_init(void); +#else +static inline void goflexnet_init(void) {}; +#endif + +#ifdef CONFIG_MACH_LSXL_DT +void lsxl_init(void); +#else +static inline void lsxl_init(void) {}; +#endif + /* early init functions not converted to fdt yet */ char *kirkwood_id(void); void kirkwood_l2_init(void); diff --git a/arch/arm/mach-kirkwood/irq.c b/arch/arm/mach-kirkwood/irq.c index c4c68e5..720063f 100644 --- a/arch/arm/mach-kirkwood/irq.c +++ b/arch/arm/mach-kirkwood/irq.c @@ -9,20 +9,23 @@ */ #include <linux/gpio.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/irq.h> -#include <linux/io.h> #include <mach/bridge-regs.h> #include <plat/irq.h> -#include "common.h" -static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - BUG_ON(irq < IRQ_KIRKWOOD_GPIO_LOW_0_7); - BUG_ON(irq > IRQ_KIRKWOOD_GPIO_HIGH_16_23); +static int __initdata gpio0_irqs[4] = { + IRQ_KIRKWOOD_GPIO_LOW_0_7, + IRQ_KIRKWOOD_GPIO_LOW_8_15, + IRQ_KIRKWOOD_GPIO_LOW_16_23, + IRQ_KIRKWOOD_GPIO_LOW_24_31, +}; - orion_gpio_irq_handler((irq - IRQ_KIRKWOOD_GPIO_LOW_0_7) << 3); -} +static int __initdata gpio1_irqs[4] = { + IRQ_KIRKWOOD_GPIO_HIGH_0_7, + IRQ_KIRKWOOD_GPIO_HIGH_8_15, + IRQ_KIRKWOOD_GPIO_HIGH_16_23, + 0, +}; void __init kirkwood_init_irq(void) { @@ -32,17 +35,8 @@ void __init kirkwood_init_irq(void) /* * Initialize gpiolib for GPIOs 0-49. */ - orion_gpio_init(0, 32, GPIO_LOW_VIRT_BASE, 0, - IRQ_KIRKWOOD_GPIO_START); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_0_7, gpio_irq_handler); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_8_15, gpio_irq_handler); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_16_23, gpio_irq_handler); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_24_31, gpio_irq_handler); - - orion_gpio_init(32, 18, GPIO_HIGH_VIRT_BASE, 0, - IRQ_KIRKWOOD_GPIO_START + 32); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_0_7, gpio_irq_handler); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_8_15, gpio_irq_handler); - irq_set_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_16_23, - gpio_irq_handler); + orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_LOW_VIRT_BASE, 0, + IRQ_KIRKWOOD_GPIO_START, gpio0_irqs); + orion_gpio_init(NULL, 32, 18, (void __iomem *)GPIO_HIGH_VIRT_BASE, 0, + IRQ_KIRKWOOD_GPIO_START + 32, gpio1_irqs); } diff --git a/arch/arm/mach-mmp/gplugd.c b/arch/arm/mach-mmp/gplugd.c index f516e74..5c3d61e 100644 --- a/arch/arm/mach-mmp/gplugd.c +++ b/arch/arm/mach-mmp/gplugd.c @@ -14,6 +14,7 @@ #include <asm/mach/arch.h> #include <asm/mach-types.h> +#include <mach/irqs.h> #include <mach/pxa168.h> #include <mach/mfp-pxa168.h> diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c index e421b70..eff9a75 100644 --- a/arch/arm/mach-mv78xx0/irq.c +++ b/arch/arm/mach-mv78xx0/irq.c @@ -9,19 +9,17 @@ */ #include <linux/gpio.h> #include <linux/kernel.h> -#include <linux/init.h> -#include <linux/pci.h> #include <linux/irq.h> #include <mach/bridge-regs.h> #include <plat/irq.h> #include "common.h" -static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - BUG_ON(irq < IRQ_MV78XX0_GPIO_0_7 || irq > IRQ_MV78XX0_GPIO_24_31); - - orion_gpio_irq_handler((irq - IRQ_MV78XX0_GPIO_0_7) << 3); -} +static int __initdata gpio0_irqs[4] = { + IRQ_MV78XX0_GPIO_0_7, + IRQ_MV78XX0_GPIO_8_15, + IRQ_MV78XX0_GPIO_16_23, + IRQ_MV78XX0_GPIO_24_31, +}; void __init mv78xx0_init_irq(void) { @@ -34,11 +32,7 @@ void __init mv78xx0_init_irq(void) * registers for core #1 are at an offset of 0x18 from those of * core #0.) */ - orion_gpio_init(0, 32, GPIO_VIRT_BASE, + orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_VIRT_BASE, mv78xx0_core_index() ? 0x18 : 0, - IRQ_MV78XX0_GPIO_START); - irq_set_chained_handler(IRQ_MV78XX0_GPIO_0_7, gpio_irq_handler); - irq_set_chained_handler(IRQ_MV78XX0_GPIO_8_15, gpio_irq_handler); - irq_set_chained_handler(IRQ_MV78XX0_GPIO_16_23, gpio_irq_handler); - irq_set_chained_handler(IRQ_MV78XX0_GPIO_24_31, gpio_irq_handler); + IRQ_MV78XX0_GPIO_START, gpio0_irqs); } diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index dd0fbf7..dd2db02 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -62,6 +62,7 @@ config ARCH_OMAP4 select PM_OPP if PM select USB_ARCH_HAS_EHCI if USB_SUPPORT select ARM_CPU_SUSPEND if PM + select ARCH_NEEDS_CPU_IDLE_COUPLED config SOC_OMAP5 bool "TI OMAP5" diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 02d15bb..ee05e19 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -21,6 +21,7 @@ #include "common.h" #include "pm.h" #include "prm.h" +#include "clockdomain.h" /* Machine specific information */ struct omap4_idle_statedata { @@ -47,10 +48,14 @@ static struct omap4_idle_statedata omap4_idle_data[] = { }, }; -static struct powerdomain *mpu_pd, *cpu0_pd, *cpu1_pd; +static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS]; +static struct clockdomain *cpu_clkdm[NR_CPUS]; + +static atomic_t abort_barrier; +static bool cpu_done[NR_CPUS]; /** - * omap4_enter_idle - Programs OMAP4 to enter the specified state + * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions * @dev: cpuidle device * @drv: cpuidle driver * @index: the index of state to be entered @@ -59,60 +64,84 @@ static struct powerdomain *mpu_pd, *cpu0_pd, *cpu1_pd; * specified low power state selected by the governor. * Returns the amount of time spent in the low power state. */ -static int omap4_enter_idle(struct cpuidle_device *dev, +static int omap4_enter_idle_simple(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + local_fiq_disable(); + omap_do_wfi(); + local_fiq_enable(); + + return index; +} + +static int omap4_enter_idle_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct omap4_idle_statedata *cx = &omap4_idle_data[index]; - u32 cpu1_state; int cpu_id = smp_processor_id(); local_fiq_disable(); /* - * CPU0 has to stay ON (i.e in C1) until CPU1 is OFF state. + * CPU0 has to wait and stay ON until CPU1 is OFF state. * This is necessary to honour hardware recommondation * of triggeing all the possible low power modes once CPU1 is * out of coherency and in OFF mode. - * Update dev->last_state so that governor stats reflects right - * data. */ - cpu1_state = pwrdm_read_pwrst(cpu1_pd); - if (cpu1_state != PWRDM_POWER_OFF) { - index = drv->safe_state_index; - cx = &omap4_idle_data[index]; + if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { + while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) { + cpu_relax(); + + /* + * CPU1 could have already entered & exited idle + * without hitting off because of a wakeup + * or a failed attempt to hit off mode. Check for + * that here, otherwise we could spin forever + * waiting for CPU1 off. + */ + if (cpu_done[1]) + goto fail; + + } } - if (index > 0) - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); /* * Call idle CPU PM enter notifier chain so that * VFP and per CPU interrupt context is saved. */ - if (cx->cpu_state == PWRDM_POWER_OFF) - cpu_pm_enter(); - - pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); - omap_set_pwrdm_state(mpu_pd, cx->mpu_state); - - /* - * Call idle CPU cluster PM enter notifier chain - * to save GIC and wakeupgen context. - */ - if ((cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) - cpu_cluster_pm_enter(); + cpu_pm_enter(); + + if (dev->cpu == 0) { + pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); + omap_set_pwrdm_state(mpu_pd, cx->mpu_state); + + /* + * Call idle CPU cluster PM enter notifier chain + * to save GIC and wakeupgen context. + */ + if ((cx->mpu_state == PWRDM_POWER_RET) && + (cx->mpu_logic_state == PWRDM_POWER_OFF)) + cpu_cluster_pm_enter(); + } omap4_enter_lowpower(dev->cpu, cx->cpu_state); + cpu_done[dev->cpu] = true; + + /* Wakeup CPU1 only if it is not offlined */ + if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { + clkdm_wakeup(cpu_clkdm[1]); + clkdm_allow_idle(cpu_clkdm[1]); + } /* * Call idle CPU PM exit notifier chain to restore - * VFP and per CPU IRQ context. Only CPU0 state is - * considered since CPU1 is managed by CPU hotplug. + * VFP and per CPU IRQ context. */ - if (pwrdm_read_prev_pwrst(cpu0_pd) == PWRDM_POWER_OFF) - cpu_pm_exit(); + cpu_pm_exit(); /* * Call idle CPU cluster PM exit notifier chain @@ -121,8 +150,11 @@ static int omap4_enter_idle(struct cpuidle_device *dev, if (omap4_mpuss_read_prev_context_state()) cpu_cluster_pm_exit(); - if (index > 0) - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); + +fail: + cpuidle_coupled_parallel_barrier(dev, &abort_barrier); + cpu_done[dev->cpu] = false; local_fiq_enable(); @@ -141,7 +173,7 @@ struct cpuidle_driver omap4_idle_driver = { .exit_latency = 2 + 2, .target_residency = 5, .flags = CPUIDLE_FLAG_TIME_VALID, - .enter = omap4_enter_idle, + .enter = omap4_enter_idle_simple, .name = "C1", .desc = "MPUSS ON" }, @@ -149,8 +181,8 @@ struct cpuidle_driver omap4_idle_driver = { /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ .exit_latency = 328 + 440, .target_residency = 960, - .flags = CPUIDLE_FLAG_TIME_VALID, - .enter = omap4_enter_idle, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, + .enter = omap4_enter_idle_coupled, .name = "C2", .desc = "MPUSS CSWR", }, @@ -158,8 +190,8 @@ struct cpuidle_driver omap4_idle_driver = { /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ .exit_latency = 460 + 518, .target_residency = 1100, - .flags = CPUIDLE_FLAG_TIME_VALID, - .enter = omap4_enter_idle, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, + .enter = omap4_enter_idle_coupled, .name = "C3", .desc = "MPUSS OSWR", }, @@ -168,6 +200,16 @@ struct cpuidle_driver omap4_idle_driver = { .safe_state_index = 0, }; +/* + * For each cpu, setup the broadcast timer because local timers + * stops for the states above C1. + */ +static void omap_setup_broadcast_timer(void *arg) +{ + int cpu = smp_processor_id(); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); +} + /** * omap4_idle_init - Init routine for OMAP4 idle * @@ -180,19 +222,30 @@ int __init omap4_idle_init(void) unsigned int cpu_id = 0; mpu_pd = pwrdm_lookup("mpu_pwrdm"); - cpu0_pd = pwrdm_lookup("cpu0_pwrdm"); - cpu1_pd = pwrdm_lookup("cpu1_pwrdm"); - if ((!mpu_pd) || (!cpu0_pd) || (!cpu1_pd)) + cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm"); + cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm"); + if ((!mpu_pd) || (!cpu_pd[0]) || (!cpu_pd[1])) return -ENODEV; - dev = &per_cpu(omap4_idle_dev, cpu_id); - dev->cpu = cpu_id; + cpu_clkdm[0] = clkdm_lookup("mpu0_clkdm"); + cpu_clkdm[1] = clkdm_lookup("mpu1_clkdm"); + if (!cpu_clkdm[0] || !cpu_clkdm[1]) + return -ENODEV; + + /* Configure the broadcast timer on each cpu */ + on_each_cpu(omap_setup_broadcast_timer, NULL, 1); + + for_each_cpu(cpu_id, cpu_online_mask) { + dev = &per_cpu(omap4_idle_dev, cpu_id); + dev->cpu = cpu_id; + dev->coupled_cpus = *cpu_online_mask; - cpuidle_register_driver(&omap4_idle_driver); + cpuidle_register_driver(&omap4_idle_driver); - if (cpuidle_register_device(dev)) { - pr_err("%s: CPUidle register device failed\n", __func__); - return -EIO; + if (cpuidle_register_device(dev)) { + pr_err("%s: CPUidle register failed\n", __func__); + return -EIO; + } } return 0; diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 13d20c8..2ff6d41 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -130,6 +130,7 @@ static struct clock_event_device clockevent_gpt = { .name = "gp_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .shift = 32, + .rating = 300, .set_next_event = omap2_gp_timer_set_next_event, .set_mode = omap2_gp_timer_set_mode, }; @@ -223,7 +224,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, clockevent_delta2ns(3, &clockevent_gpt); /* Timer internal resynch latency. */ - clockevent_gpt.cpumask = cpumask_of(0); + clockevent_gpt.cpumask = cpu_possible_mask; + clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev); clockevents_register_device(&clockevent_gpt); pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n", diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index b1b45ff..17da709 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c @@ -11,19 +11,16 @@ */ #include <linux/gpio.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/irq.h> -#include <linux/io.h> #include <mach/bridge-regs.h> #include <plat/irq.h> -#include "common.h" -static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); - - orion_gpio_irq_handler((irq - IRQ_ORION5X_GPIO_0_7) << 3); -} +static int __initdata gpio0_irqs[4] = { + IRQ_ORION5X_GPIO_0_7, + IRQ_ORION5X_GPIO_8_15, + IRQ_ORION5X_GPIO_16_23, + IRQ_ORION5X_GPIO_24_31, +}; void __init orion5x_init_irq(void) { @@ -32,9 +29,6 @@ void __init orion5x_init_irq(void) /* * Initialize gpiolib for GPIOs 0-31. */ - orion_gpio_init(0, 32, GPIO_VIRT_BASE, 0, IRQ_ORION5X_GPIO_START); - irq_set_chained_handler(IRQ_ORION5X_GPIO_0_7, gpio_irq_handler); - irq_set_chained_handler(IRQ_ORION5X_GPIO_8_15, gpio_irq_handler); - irq_set_chained_handler(IRQ_ORION5X_GPIO_16_23, gpio_irq_handler); - irq_set_chained_handler(IRQ_ORION5X_GPIO_24_31, gpio_irq_handler); + orion_gpio_init(NULL, 0, 32, (void __iomem *)GPIO_VIRT_BASE, 0, + IRQ_ORION5X_GPIO_START, gpio0_irqs); } diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c index 0d024b1..f224107 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer.c @@ -132,11 +132,11 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs) { int i; - for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); - writel_relaxed(sirfsoc_timer_reg_val[i - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); - writel_relaxed(sirfsoc_timer_reg_val[i - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); } static struct clock_event_device sirfsoc_clockevent = { diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c index c219317..3ed1adb 100644 --- a/arch/arm/plat-mxc/tzic.c +++ b/arch/arm/plat-mxc/tzic.c @@ -23,6 +23,7 @@ #include <mach/hardware.h> #include <mach/common.h> +#include <mach/irqs.h> #include "irq-common.h" diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index c179378..d245a87 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -47,6 +47,7 @@ void __init orion_clkdev_init(struct clk *tclk) orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk); orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk); orion_clkdev_add(NULL, "orion_wdt", tclk); + orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", tclk); } /* Fill in the resources structure and link it into the platform diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index af95af2..dfda74f 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -8,15 +8,22 @@ * warranty of any kind, whether express or implied. */ +#define DEBUG + #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/bitops.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/leds.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <plat/gpio.h> /* * GPIO unit register offsets. @@ -38,6 +45,7 @@ struct orion_gpio_chip { unsigned long valid_output; int mask_offset; int secondary_irq_base; + struct irq_domain *domain; }; static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip) @@ -222,10 +230,10 @@ static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin) struct orion_gpio_chip *ochip = container_of(chip, struct orion_gpio_chip, chip); - return ochip->secondary_irq_base + pin; + return irq_create_mapping(ochip->domain, + ochip->secondary_irq_base + pin); } - /* * Orion-specific GPIO API extensions. */ @@ -353,12 +361,10 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) int pin; u32 u; - pin = d->irq - gc->irq_base; + pin = d->hwirq - ochip->secondary_irq_base; u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); if (!u) { - printk(KERN_ERR "orion gpio_irq_set_type failed " - "(irq %d, pin %d).\n", d->irq, pin); return -EINVAL; } @@ -397,17 +403,53 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) u &= ~(1 << pin); /* rising */ writel(u, GPIO_IN_POL(ochip)); } - return 0; } -void __init orion_gpio_init(int gpio_base, int ngpio, - u32 base, int mask_offset, int secondary_irq_base) +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct orion_gpio_chip *ochip = irq_get_handler_data(irq); + u32 cause, type; + int i; + + if (ochip == NULL) + return; + + cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip)); + cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip)); + + for (i = 0; i < ochip->chip.ngpio; i++) { + int irq; + + irq = ochip->secondary_irq_base + i; + + if (!(cause & (1 << i))) + continue; + + type = irqd_get_trigger_type(irq_get_irq_data(irq)); + if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + /* Swap polarity (race with GPIO line) */ + u32 polarity; + + polarity = readl(GPIO_IN_POL(ochip)); + polarity ^= 1 << i; + writel(polarity, GPIO_IN_POL(ochip)); + } + generic_handle_irq(irq); + } +} + +void __init orion_gpio_init(struct device_node *np, + int gpio_base, int ngpio, + void __iomem *base, int mask_offset, + int secondary_irq_base, + int irqs[4]) { struct orion_gpio_chip *ochip; struct irq_chip_generic *gc; struct irq_chip_type *ct; char gc_label[16]; + int i; if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) return; @@ -426,6 +468,10 @@ void __init orion_gpio_init(int gpio_base, int ngpio, ochip->chip.base = gpio_base; ochip->chip.ngpio = ngpio; ochip->chip.can_sleep = 0; +#ifdef CONFIG_OF + ochip->chip.of_node = np; +#endif + spin_lock_init(&ochip->lock); ochip->base = (void __iomem *)base; ochip->valid_input = 0; @@ -435,8 +481,6 @@ void __init orion_gpio_init(int gpio_base, int ngpio, gpiochip_add(&ochip->chip); - orion_gpio_chip_count++; - /* * Mask and clear GPIO interrupts. */ @@ -444,16 +488,28 @@ void __init orion_gpio_init(int gpio_base, int ngpio, writel(0, GPIO_EDGE_MASK(ochip)); writel(0, GPIO_LEVEL_MASK(ochip)); - gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base, + /* Setup the interrupt handlers. Each chip can have up to 4 + * interrupt handlers, with each handler dealing with 8 GPIO + * pins. */ + + for (i = 0; i < 4; i++) { + if (irqs[i]) { + irq_set_handler_data(irqs[i], ochip); + irq_set_chained_handler(irqs[i], gpio_irq_handler); + } + } + + gc = irq_alloc_generic_chip("orion_gpio_irq", 2, + secondary_irq_base, ochip->base, handle_level_irq); gc->private = ochip; - ct = gc->chip_types; ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_set_type = gpio_irq_set_type; + ct->chip.name = ochip->chip.label; ct++; ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; @@ -464,41 +520,69 @@ void __init orion_gpio_init(int gpio_base, int ngpio, ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_set_type = gpio_irq_set_type; ct->handler = handle_edge_irq; + ct->chip.name = ochip->chip.label; irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); -} -void orion_gpio_irq_handler(int pinoff) -{ - struct orion_gpio_chip *ochip; - u32 cause, type; - int i; - - ochip = orion_gpio_chip_find(pinoff); - if (ochip == NULL) - return; - - cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip)); - cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip)); - - for (i = 0; i < ochip->chip.ngpio; i++) { - int irq; + /* Setup irq domain on top of the generic chip. */ + ochip->domain = irq_domain_add_legacy(np, + ochip->chip.ngpio, + ochip->secondary_irq_base, + ochip->secondary_irq_base, + &irq_domain_simple_ops, + ochip); + if (!ochip->domain) + panic("%s: couldn't allocate irq domain (DT).\n", + ochip->chip.label); - irq = ochip->secondary_irq_base + i; + orion_gpio_chip_count++; +} - if (!(cause & (1 << i))) - continue; +#ifdef CONFIG_OF +static void __init orion_gpio_of_init_one(struct device_node *np, + int irq_gpio_base) +{ + int ngpio, gpio_base, mask_offset; + void __iomem *base; + int ret, i; + int irqs[4]; + int secondary_irq_base; + + ret = of_property_read_u32(np, "ngpio", &ngpio); + if (ret) + goto out; + ret = of_property_read_u32(np, "mask-offset", &mask_offset); + if (ret == -EINVAL) + mask_offset = 0; + else + goto out; + base = of_iomap(np, 0); + if (!base) + goto out; + + secondary_irq_base = irq_gpio_base + (32 * orion_gpio_chip_count); + gpio_base = 32 * orion_gpio_chip_count; + + /* Get the interrupt numbers. Each chip can have up to 4 + * interrupt handlers, with each handler dealing with 8 GPIO + * pins. */ + + for (i = 0; i < 4; i++) + irqs[i] = irq_of_parse_and_map(np, i); + + orion_gpio_init(np, gpio_base, ngpio, base, mask_offset, + secondary_irq_base, irqs); + return; +out: + pr_err("%s: %s: missing mandatory property\n", __func__, np->name); +} - type = irqd_get_trigger_type(irq_get_irq_data(irq)); - if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { - /* Swap polarity (race with GPIO line) */ - u32 polarity; +void __init orion_gpio_of_init(int irq_gpio_base) +{ + struct device_node *np; - polarity = readl(GPIO_IN_POL(ochip)); - polarity ^= 1 << i; - writel(polarity, GPIO_IN_POL(ochip)); - } - generic_handle_irq(irq); - } + for_each_compatible_node(np, NULL, "marvell,orion-gpio") + orion_gpio_of_init_one(np, irq_gpio_base); } +#endif diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h index bec0c98..81c6fc8 100644 --- a/arch/arm/plat-orion/include/plat/gpio.h +++ b/arch/arm/plat-orion/include/plat/gpio.h @@ -13,7 +13,7 @@ #include <linux/init.h> #include <linux/types.h> - +#include <linux/irqdomain.h> /* * Orion-specific GPIO API extensions. */ @@ -27,13 +27,11 @@ int orion_gpio_led_blink_set(unsigned gpio, int state, void orion_gpio_set_valid(unsigned pin, int mode); /* Initialize gpiolib. */ -void __init orion_gpio_init(int gpio_base, int ngpio, - u32 base, int mask_offset, int secondary_irq_base); - -/* - * GPIO interrupt handling. - */ -void orion_gpio_irq_handler(int irqoff); - +void __init orion_gpio_init(struct device_node *np, + int gpio_base, int ngpio, + void __iomem *base, int mask_offset, + int secondary_irq_base, + int irq[4]); +void __init orion_gpio_of_init(int irq_gpio_base); #endif diff --git a/arch/arm/plat-orion/include/plat/irq.h b/arch/arm/plat-orion/include/plat/irq.h index f05eeab..50547e4 100644 --- a/arch/arm/plat-orion/include/plat/irq.h +++ b/arch/arm/plat-orion/include/plat/irq.h @@ -12,6 +12,5 @@ #define __PLAT_IRQ_H void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); - - +void __init orion_dt_init_irq(void); #endif diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c index 2d5b9c1..d751964 100644 --- a/arch/arm/plat-orion/irq.c +++ b/arch/arm/plat-orion/irq.c @@ -11,8 +11,12 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <plat/irq.h> +#include <plat/gpio.h> void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) { @@ -32,3 +36,39 @@ void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); } + +#ifdef CONFIG_OF +static int __init orion_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + int i = 0, irq_gpio; + void __iomem *base; + + do { + base = of_iomap(np, i); + if (base) { + orion_irq_init(i * 32, base); + i++; + } + } while (base); + + irq_domain_add_legacy(np, i * 32, 0, 0, + &irq_domain_simple_ops, NULL); + + irq_gpio = i * 32; + orion_gpio_of_init(irq_gpio); + + return 0; +} + +static const struct of_device_id orion_irq_match[] = { + { .compatible = "marvell,orion-intc", + .data = orion_add_irq_domain, }, + {}, +}; + +void __init orion_dt_init_irq(void) +{ + of_irq_init(orion_irq_match); +} +#endif diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index ada8f0f..fb96e60 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -52,7 +52,6 @@ EXPORT_SYMBOL(reserved_mem_dcache_on); #ifdef CONFIG_MTD_UCLINUX extern struct map_info uclinux_ram_map; unsigned long memory_mtd_end, memory_mtd_start, mtd_size; -unsigned long _ebss; EXPORT_SYMBOL(memory_mtd_end); EXPORT_SYMBOL(memory_mtd_start); EXPORT_SYMBOL(mtd_size); diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 6f38b61..44057885 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -497,7 +497,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) srat_num_cpus++; } -void __init +int __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { unsigned long paddr, size; @@ -512,7 +512,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) /* Ignore disabled entries */ if (!(ma->flags & ACPI_SRAT_MEM_ENABLED)) - return; + return -1; /* record this node in proximity bitmap */ pxm_bit_set(pxm); @@ -531,6 +531,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) p->size = size; p->nid = pxm; num_node_memblks++; + return 0; } void __init acpi_numa_arch_fixup(void) diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 0b0f8b8..4a46990 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -54,18 +54,6 @@ config ZONE_DMA bool default y -config CPU_HAS_NO_BITFIELDS - bool - -config CPU_HAS_NO_MULDIV64 - bool - -config CPU_HAS_ADDRESS_SPACES - bool - -config FPU - bool - config HZ int default 1000 if CLEOPATRA diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index 43a9f8f..8206834 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -37,6 +37,7 @@ config M68000 bool select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_MULDIV64 + select CPU_HAS_NO_UNALIGNED select GENERIC_CSUM help The Freescale (was Motorola) 68000 CPU is the first generation of @@ -48,6 +49,7 @@ config M68000 config MCPU32 bool select CPU_HAS_NO_BITFIELDS + select CPU_HAS_NO_UNALIGNED help The Freescale (was then Motorola) CPU32 is a CPU core that is based on the 68020 processor. For the most part it is used in @@ -376,6 +378,18 @@ config NODES_SHIFT default "3" depends on !SINGLE_MEMORY_CHUNK +config CPU_HAS_NO_BITFIELDS + bool + +config CPU_HAS_NO_MULDIV64 + bool + +config CPU_HAS_NO_UNALIGNED + bool + +config CPU_HAS_ADDRESS_SPACES + bool + config FPU bool diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c index 0a30406..f5565d6 100644 --- a/arch/m68k/apollo/config.c +++ b/arch/m68k/apollo/config.c @@ -177,8 +177,8 @@ irqreturn_t dn_timer_int(int irq, void *dev_id) timer_handler(irq, dev_id); - x=*(volatile unsigned char *)(timer+3); - x=*(volatile unsigned char *)(timer+5); + x = *(volatile unsigned char *)(apollo_timer + 3); + x = *(volatile unsigned char *)(apollo_timer + 5); return IRQ_HANDLED; } @@ -186,17 +186,17 @@ irqreturn_t dn_timer_int(int irq, void *dev_id) void dn_sched_init(irq_handler_t timer_routine) { /* program timer 1 */ - *(volatile unsigned char *)(timer+3)=0x01; - *(volatile unsigned char *)(timer+1)=0x40; - *(volatile unsigned char *)(timer+5)=0x09; - *(volatile unsigned char *)(timer+7)=0xc4; + *(volatile unsigned char *)(apollo_timer + 3) = 0x01; + *(volatile unsigned char *)(apollo_timer + 1) = 0x40; + *(volatile unsigned char *)(apollo_timer + 5) = 0x09; + *(volatile unsigned char *)(apollo_timer + 7) = 0xc4; /* enable IRQ of PIC B */ *(volatile unsigned char *)(pica+1)&=(~8); #if 0 - printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3)); - printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3)); + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3)); + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3)); #endif if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine)) diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index eafa253..a74e5d9 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild @@ -1,4 +1,29 @@ include include/asm-generic/Kbuild.asm header-y += cachectl.h +generic-y += bitsperlong.h +generic-y += cputime.h +generic-y += device.h +generic-y += emergency-restart.h +generic-y += errno.h +generic-y += futex.h +generic-y += ioctl.h +generic-y += ipcbuf.h +generic-y += irq_regs.h +generic-y += kdebug.h +generic-y += kmap_types.h +generic-y += kvm_para.h +generic-y += local64.h +generic-y += local.h +generic-y += mman.h +generic-y += mutex.h +generic-y += percpu.h +generic-y += resource.h +generic-y += scatterlist.h +generic-y += sections.h +generic-y += siginfo.h +generic-y += statfs.h +generic-y += topology.h +generic-y += types.h generic-y += word-at-a-time.h +generic-y += xor.h diff --git a/arch/m68k/include/asm/MC68332.h b/arch/m68k/include/asm/MC68332.h deleted file mode 100644 index 6bb8f02..0000000 --- a/arch/m68k/include/asm/MC68332.h +++ /dev/null @@ -1,152 +0,0 @@ - -/* include/asm-m68knommu/MC68332.h: '332 control registers - * - * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>, - * - */ - -#ifndef _MC68332_H_ -#define _MC68332_H_ - -#define BYTE_REF(addr) (*((volatile unsigned char*)addr)) -#define WORD_REF(addr) (*((volatile unsigned short*)addr)) - -#define PORTE_ADDR 0xfffa11 -#define PORTE BYTE_REF(PORTE_ADDR) -#define DDRE_ADDR 0xfffa15 -#define DDRE BYTE_REF(DDRE_ADDR) -#define PEPAR_ADDR 0xfffa17 -#define PEPAR BYTE_REF(PEPAR_ADDR) - -#define PORTF_ADDR 0xfffa19 -#define PORTF BYTE_REF(PORTF_ADDR) -#define DDRF_ADDR 0xfffa1d -#define DDRF BYTE_REF(DDRF_ADDR) -#define PFPAR_ADDR 0xfffa1f -#define PFPAR BYTE_REF(PFPAR_ADDR) - -#define PORTQS_ADDR 0xfffc15 -#define PORTQS BYTE_REF(PORTQS_ADDR) -#define DDRQS_ADDR 0xfffc17 -#define DDRQS BYTE_REF(DDRQS_ADDR) -#define PQSPAR_ADDR 0xfffc16 -#define PQSPAR BYTE_REF(PQSPAR_ADDR) - -#define CSPAR0_ADDR 0xFFFA44 -#define CSPAR0 WORD_REF(CSPAR0_ADDR) -#define CSPAR1_ADDR 0xFFFA46 -#define CSPAR1 WORD_REF(CSPAR1_ADDR) -#define CSARBT_ADDR 0xFFFA48 -#define CSARBT WORD_REF(CSARBT_ADDR) -#define CSOPBT_ADDR 0xFFFA4A -#define CSOPBT WORD_REF(CSOPBT_ADDR) -#define CSBAR0_ADDR 0xFFFA4C -#define CSBAR0 WORD_REF(CSBAR0_ADDR) -#define CSOR0_ADDR 0xFFFA4E -#define CSOR0 WORD_REF(CSOR0_ADDR) -#define CSBAR1_ADDR 0xFFFA50 -#define CSBAR1 WORD_REF(CSBAR1_ADDR) -#define CSOR1_ADDR 0xFFFA52 -#define CSOR1 WORD_REF(CSOR1_ADDR) -#define CSBAR2_ADDR 0xFFFA54 -#define CSBAR2 WORD_REF(CSBAR2_ADDR) -#define CSOR2_ADDR 0xFFFA56 -#define CSOR2 WORD_REF(CSOR2_ADDR) -#define CSBAR3_ADDR 0xFFFA58 -#define CSBAR3 WORD_REF(CSBAR3_ADDR) -#define CSOR3_ADDR 0xFFFA5A -#define CSOR3 WORD_REF(CSOR3_ADDR) -#define CSBAR4_ADDR 0xFFFA5C -#define CSBAR4 WORD_REF(CSBAR4_ADDR) -#define CSOR4_ADDR 0xFFFA5E -#define CSOR4 WORD_REF(CSOR4_ADDR) -#define CSBAR5_ADDR 0xFFFA60 -#define CSBAR5 WORD_REF(CSBAR5_ADDR) -#define CSOR5_ADDR 0xFFFA62 -#define CSOR5 WORD_REF(CSOR5_ADDR) -#define CSBAR6_ADDR 0xFFFA64 -#define CSBAR6 WORD_REF(CSBAR6_ADDR) -#define CSOR6_ADDR 0xFFFA66 -#define CSOR6 WORD_REF(CSOR6_ADDR) -#define CSBAR7_ADDR 0xFFFA68 -#define CSBAR7 WORD_REF(CSBAR7_ADDR) -#define CSOR7_ADDR 0xFFFA6A -#define CSOR7 WORD_REF(CSOR7_ADDR) -#define CSBAR8_ADDR 0xFFFA6C -#define CSBAR8 WORD_REF(CSBAR8_ADDR) -#define CSOR8_ADDR 0xFFFA6E -#define CSOR8 WORD_REF(CSOR8_ADDR) -#define CSBAR9_ADDR 0xFFFA70 -#define CSBAR9 WORD_REF(CSBAR9_ADDR) -#define CSOR9_ADDR 0xFFFA72 -#define CSOR9 WORD_REF(CSOR9_ADDR) -#define CSBAR10_ADDR 0xFFFA74 -#define CSBAR10 WORD_REF(CSBAR10_ADDR) -#define CSOR10_ADDR 0xFFFA76 -#define CSOR10 WORD_REF(CSOR10_ADDR) - -#define CSOR_MODE_ASYNC 0x0000 -#define CSOR_MODE_SYNC 0x8000 -#define CSOR_MODE_MASK 0x8000 -#define CSOR_BYTE_DISABLE 0x0000 -#define CSOR_BYTE_UPPER 0x4000 -#define CSOR_BYTE_LOWER 0x2000 -#define CSOR_BYTE_BOTH 0x6000 -#define CSOR_BYTE_MASK 0x6000 -#define CSOR_RW_RSVD 0x0000 -#define CSOR_RW_READ 0x0800 -#define CSOR_RW_WRITE 0x1000 -#define CSOR_RW_BOTH 0x1800 -#define CSOR_RW_MASK 0x1800 -#define CSOR_STROBE_DS 0x0400 -#define CSOR_STROBE_AS 0x0000 -#define CSOR_STROBE_MASK 0x0400 -#define CSOR_DSACK_WAIT(x) (wait << 6) -#define CSOR_DSACK_FTERM (14 << 6) -#define CSOR_DSACK_EXTERNAL (15 << 6) -#define CSOR_DSACK_MASK 0x03c0 -#define CSOR_SPACE_CPU 0x0000 -#define CSOR_SPACE_USER 0x0010 -#define CSOR_SPACE_SU 0x0020 -#define CSOR_SPACE_BOTH 0x0030 -#define CSOR_SPACE_MASK 0x0030 -#define CSOR_IPL_ALL 0x0000 -#define CSOR_IPL_PRIORITY(x) (x << 1) -#define CSOR_IPL_MASK 0x000e -#define CSOR_AVEC_ON 0x0001 -#define CSOR_AVEC_OFF 0x0000 -#define CSOR_AVEC_MASK 0x0001 - -#define CSBAR_ADDR(x) ((addr >> 11) << 3) -#define CSBAR_ADDR_MASK 0xfff8 -#define CSBAR_BLKSIZE_2K 0x0000 -#define CSBAR_BLKSIZE_8K 0x0001 -#define CSBAR_BLKSIZE_16K 0x0002 -#define CSBAR_BLKSIZE_64K 0x0003 -#define CSBAR_BLKSIZE_128K 0x0004 -#define CSBAR_BLKSIZE_256K 0x0005 -#define CSBAR_BLKSIZE_512K 0x0006 -#define CSBAR_BLKSIZE_1M 0x0007 -#define CSBAR_BLKSIZE_MASK 0x0007 - -#define CSPAR_DISC 0 -#define CSPAR_ALT 1 -#define CSPAR_CS8 2 -#define CSPAR_CS16 3 -#define CSPAR_MASK 3 - -#define CSPAR0_CSBOOT(x) (x << 0) -#define CSPAR0_CS0(x) (x << 2) -#define CSPAR0_CS1(x) (x << 4) -#define CSPAR0_CS2(x) (x << 6) -#define CSPAR0_CS3(x) (x << 8) -#define CSPAR0_CS4(x) (x << 10) -#define CSPAR0_CS5(x) (x << 12) - -#define CSPAR1_CS6(x) (x << 0) -#define CSPAR1_CS7(x) (x << 2) -#define CSPAR1_CS8(x) (x << 4) -#define CSPAR1_CS9(x) (x << 6) -#define CSPAR1_CS10(x) (x << 8) - -#endif diff --git a/arch/m68k/include/asm/apollodma.h b/arch/m68k/include/asm/apollodma.h deleted file mode 100644 index 954adc8..0000000 --- a/arch/m68k/include/asm/apollodma.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - * Written by Hennus Bergman, 1992. - * High DMA channel support & info by Hannu Savolainen - * and John Boyd, Nov. 1992. - */ - -#ifndef _ASM_APOLLO_DMA_H -#define _ASM_APOLLO_DMA_H - -#include <asm/apollohw.h> /* need byte IO */ -#include <linux/spinlock.h> /* And spinlocks */ -#include <linux/delay.h> - - -#define dma_outb(val,addr) (*((volatile unsigned char *)(addr+IO_BASE)) = (val)) -#define dma_inb(addr) (*((volatile unsigned char *)(addr+IO_BASE))) - -/* - * NOTES about DMA transfers: - * - * controller 1: channels 0-3, byte operations, ports 00-1F - * controller 2: channels 4-7, word operations, ports C0-DF - * - * - ALL registers are 8 bits only, regardless of transfer size - * - channel 4 is not used - cascades 1 into 2. - * - channels 0-3 are byte - addresses/counts are for physical bytes - * - channels 5-7 are word - addresses/counts are for physical words - * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries - * - transfer count loaded to registers is 1 less than actual count - * - controller 2 offsets are all even (2x offsets for controller 1) - * - page registers for 5-7 don't use data bit 0, represent 128K pages - * - page registers for 0-3 use bit 0, represent 64K pages - * - * DMA transfers are limited to the lower 16MB of _physical_ memory. - * Note that addresses loaded into registers must be _physical_ addresses, - * not logical addresses (which may differ if paging is active). - * - * Address mapping for channels 0-3: - * - * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * | ... | | ... | | ... | - * P7 ... P0 A7 ... A0 A7 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Address mapping for channels 5-7: - * - * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) - * | ... | \ \ ... \ \ \ ... \ \ - * | ... | \ \ ... \ \ \ ... \ (not used) - * | ... | \ \ ... \ \ \ ... \ - * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 - * | Page | Addr MSB | Addr LSB | (DMA registers) - * - * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses - * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at - * the hardware level, so odd-byte transfers aren't possible). - * - * Transfer count (_not # bytes_) is limited to 64K, represented as actual - * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, - * and up to 128K bytes may be transferred on channels 5-7 in one operation. - * - */ - -#define MAX_DMA_CHANNELS 8 - -/* The maximum address that we can perform a DMA transfer to on this platform */#define MAX_DMA_ADDRESS (PAGE_OFFSET+0x1000000) - -/* 8237 DMA controllers */ -#define IO_DMA1_BASE 0x10C00 /* 8 bit slave DMA, channels 0..3 */ -#define IO_DMA2_BASE 0x10D00 /* 16 bit master DMA, ch 4(=slave input)..7 */ - -/* DMA controller registers */ -#define DMA1_CMD_REG (IO_DMA1_BASE+0x08) /* command register (w) */ -#define DMA1_STAT_REG (IO_DMA1_BASE+0x08) /* status register (r) */ -#define DMA1_REQ_REG (IO_DMA1_BASE+0x09) /* request register (w) */ -#define DMA1_MASK_REG (IO_DMA1_BASE+0x0A) /* single-channel mask (w) */ -#define DMA1_MODE_REG (IO_DMA1_BASE+0x0B) /* mode register (w) */ -#define DMA1_CLEAR_FF_REG (IO_DMA1_BASE+0x0C) /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG (IO_DMA1_BASE+0x0D) /* Temporary Register (r) */ -#define DMA1_RESET_REG (IO_DMA1_BASE+0x0D) /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG (IO_DMA1_BASE+0x0E) /* Clear Mask */ -#define DMA1_MASK_ALL_REG (IO_DMA1_BASE+0x0F) /* all-channels mask (w) */ - -#define DMA2_CMD_REG (IO_DMA2_BASE+0x10) /* command register (w) */ -#define DMA2_STAT_REG (IO_DMA2_BASE+0x10) /* status register (r) */ -#define DMA2_REQ_REG (IO_DMA2_BASE+0x12) /* request register (w) */ -#define DMA2_MASK_REG (IO_DMA2_BASE+0x14) /* single-channel mask (w) */ -#define DMA2_MODE_REG (IO_DMA2_BASE+0x16) /* mode register (w) */ -#define DMA2_CLEAR_FF_REG (IO_DMA2_BASE+0x18) /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG (IO_DMA2_BASE+0x1A) /* Temporary Register (r) */ -#define DMA2_RESET_REG (IO_DMA2_BASE+0x1A) /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG (IO_DMA2_BASE+0x1C) /* Clear Mask */ -#define DMA2_MASK_ALL_REG (IO_DMA2_BASE+0x1E) /* all-channels mask (w) */ - -#define DMA_ADDR_0 (IO_DMA1_BASE+0x00) /* DMA address registers */ -#define DMA_ADDR_1 (IO_DMA1_BASE+0x02) -#define DMA_ADDR_2 (IO_DMA1_BASE+0x04) -#define DMA_ADDR_3 (IO_DMA1_BASE+0x06) -#define DMA_ADDR_4 (IO_DMA2_BASE+0x00) -#define DMA_ADDR_5 (IO_DMA2_BASE+0x04) -#define DMA_ADDR_6 (IO_DMA2_BASE+0x08) -#define DMA_ADDR_7 (IO_DMA2_BASE+0x0C) - -#define DMA_CNT_0 (IO_DMA1_BASE+0x01) /* DMA count registers */ -#define DMA_CNT_1 (IO_DMA1_BASE+0x03) -#define DMA_CNT_2 (IO_DMA1_BASE+0x05) -#define DMA_CNT_3 (IO_DMA1_BASE+0x07) -#define DMA_CNT_4 (IO_DMA2_BASE+0x02) -#define DMA_CNT_5 (IO_DMA2_BASE+0x06) -#define DMA_CNT_6 (IO_DMA2_BASE+0x0A) -#define DMA_CNT_7 (IO_DMA2_BASE+0x0E) - -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ -#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ - -#define DMA_AUTOINIT 0x10 - -#define DMA_8BIT 0 -#define DMA_16BIT 1 -#define DMA_BUSMASTER 2 - -extern spinlock_t dma_spin_lock; - -static __inline__ unsigned long claim_dma_lock(void) -{ - unsigned long flags; - spin_lock_irqsave(&dma_spin_lock, flags); - return flags; -} - -static __inline__ void release_dma_lock(unsigned long flags) -{ - spin_unlock_irqrestore(&dma_spin_lock, flags); -} - -/* enable/disable a specific DMA channel */ -static __inline__ void enable_dma(unsigned int dmanr) -{ - if (dmanr<=3) - dma_outb(dmanr, DMA1_MASK_REG); - else - dma_outb(dmanr & 3, DMA2_MASK_REG); -} - -static __inline__ void disable_dma(unsigned int dmanr) -{ - if (dmanr<=3) - dma_outb(dmanr | 4, DMA1_MASK_REG); - else - dma_outb((dmanr & 3) | 4, DMA2_MASK_REG); -} - -/* Clear the 'DMA Pointer Flip Flop'. - * Write 0 for LSB/MSB, 1 for MSB/LSB access. - * Use this once to initialize the FF to a known state. - * After that, keep track of it. :-) - * --- In order to do that, the DMA routines below should --- - * --- only be used while holding the DMA lock ! --- - */ -static __inline__ void clear_dma_ff(unsigned int dmanr) -{ - if (dmanr<=3) - dma_outb(0, DMA1_CLEAR_FF_REG); - else - dma_outb(0, DMA2_CLEAR_FF_REG); -} - -/* set mode (above) for a specific DMA channel */ -static __inline__ void set_dma_mode(unsigned int dmanr, char mode) -{ - if (dmanr<=3) - dma_outb(mode | dmanr, DMA1_MODE_REG); - else - dma_outb(mode | (dmanr&3), DMA2_MODE_REG); -} - -/* Set transfer address & page bits for specific DMA channel. - * Assumes dma flipflop is clear. - */ -static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) -{ - if (dmanr <= 3) { - dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - } else { - dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - } -} - - -/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for - * a specific DMA channel. - * You must ensure the parameters are valid. - * NOTE: from a manual: "the number of transfers is one more - * than the initial word count"! This is taken into account. - * Assumes dma flip-flop is clear. - * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. - */ -static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) -{ - count--; - if (dmanr <= 3) { - dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - } else { - dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - } -} - - -/* Get DMA residue count. After a DMA transfer, this - * should return zero. Reading this while a DMA transfer is - * still in progress will return unpredictable results. - * If called before the channel has been used, it may return 1. - * Otherwise, it returns the number of _bytes_ left to transfer. - * - * Assumes DMA flip-flop is clear. - */ -static __inline__ int get_dma_residue(unsigned int dmanr) -{ - unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE - : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; - - /* using short to get 16-bit wrap around */ - unsigned short count; - - count = 1 + dma_inb(io_port); - count += dma_inb(io_port) << 8; - - return (dmanr<=3)? count : (count<<1); -} - - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it again */ - -/* These are in arch/m68k/apollo/dma.c: */ -extern unsigned short dma_map_page(unsigned long phys_addr,int count,int type); -extern void dma_unmap_page(unsigned short dma_addr); - -#endif /* _ASM_APOLLO_DMA_H */ diff --git a/arch/m68k/include/asm/apollohw.h b/arch/m68k/include/asm/apollohw.h index a1373b9..635ef4f 100644 --- a/arch/m68k/include/asm/apollohw.h +++ b/arch/m68k/include/asm/apollohw.h @@ -98,7 +98,7 @@ extern u_long timer_physaddr; #define cpuctrl (*(volatile unsigned int *)(IO_BASE + cpuctrl_physaddr)) #define pica (IO_BASE + pica_physaddr) #define picb (IO_BASE + picb_physaddr) -#define timer (IO_BASE + timer_physaddr) +#define apollo_timer (IO_BASE + timer_physaddr) #define addr_xlat_map ((unsigned short *)(IO_BASE + 0x17000)) #define isaIO2mem(x) (((((x) & 0x3f8) << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE) diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h deleted file mode 100644 index 6dc0bb0..0000000 --- a/arch/m68k/include/asm/bitsperlong.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/bitsperlong.h> diff --git a/arch/m68k/include/asm/cputime.h b/arch/m68k/include/asm/cputime.h deleted file mode 100644 index c79c5e8..0000000 --- a/arch/m68k/include/asm/cputime.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __M68K_CPUTIME_H -#define __M68K_CPUTIME_H - -#include <asm-generic/cputime.h> - -#endif /* __M68K_CPUTIME_H */ diff --git a/arch/m68k/include/asm/delay.h b/arch/m68k/include/asm/delay.h index 9c09bec..12d8fe4 100644 --- a/arch/m68k/include/asm/delay.h +++ b/arch/m68k/include/asm/delay.h @@ -43,7 +43,7 @@ static inline void __delay(unsigned long loops) extern void __bad_udelay(void); -#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE) +#ifdef CONFIG_CPU_HAS_NO_MULDIV64 /* * The simpler m68k and ColdFire processors do not have a 32*32->64 * multiply instruction. So we need to handle them a little differently. diff --git a/arch/m68k/include/asm/device.h b/arch/m68k/include/asm/device.h deleted file mode 100644 index d8f9872..0000000 --- a/arch/m68k/include/asm/device.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Arch specific extensions to struct device - * - * This file is released under the GPLv2 - */ -#include <asm-generic/device.h> - diff --git a/arch/m68k/include/asm/emergency-restart.h b/arch/m68k/include/asm/emergency-restart.h deleted file mode 100644 index 108d8c4..0000000 --- a/arch/m68k/include/asm/emergency-restart.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_EMERGENCY_RESTART_H -#define _ASM_EMERGENCY_RESTART_H - -#include <asm-generic/emergency-restart.h> - -#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/arch/m68k/include/asm/errno.h b/arch/m68k/include/asm/errno.h deleted file mode 100644 index 0d4e188..0000000 --- a/arch/m68k/include/asm/errno.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M68K_ERRNO_H -#define _M68K_ERRNO_H - -#include <asm-generic/errno.h> - -#endif /* _M68K_ERRNO_H */ diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h deleted file mode 100644 index 6a332a9..0000000 --- a/arch/m68k/include/asm/futex.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_FUTEX_H -#define _ASM_FUTEX_H - -#include <asm-generic/futex.h> - -#endif diff --git a/arch/m68k/include/asm/ioctl.h b/arch/m68k/include/asm/ioctl.h deleted file mode 100644 index b279fe0..0000000 --- a/arch/m68k/include/asm/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/ioctl.h> diff --git a/arch/m68k/include/asm/ipcbuf.h b/arch/m68k/include/asm/ipcbuf.h deleted file mode 100644 index 84c7e51..0000000 --- a/arch/m68k/include/asm/ipcbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/ipcbuf.h> diff --git a/arch/m68k/include/asm/irq_regs.h b/arch/m68k/include/asm/irq_regs.h deleted file mode 100644 index 3dd9c0b..0000000 --- a/arch/m68k/include/asm/irq_regs.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/irq_regs.h> diff --git a/arch/m68k/include/asm/kdebug.h b/arch/m68k/include/asm/kdebug.h deleted file mode 100644 index 6ece1b0..0000000 --- a/arch/m68k/include/asm/kdebug.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/kdebug.h> diff --git a/arch/m68k/include/asm/kmap_types.h b/arch/m68k/include/asm/kmap_types.h deleted file mode 100644 index 3413cc1..0000000 --- a/arch/m68k/include/asm/kmap_types.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_M68K_KMAP_TYPES_H -#define __ASM_M68K_KMAP_TYPES_H - -#include <asm-generic/kmap_types.h> - -#endif /* __ASM_M68K_KMAP_TYPES_H */ diff --git a/arch/m68k/include/asm/kvm_para.h b/arch/m68k/include/asm/kvm_para.h deleted file mode 100644 index 14fab8f..0000000 --- a/arch/m68k/include/asm/kvm_para.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/kvm_para.h> diff --git a/arch/m68k/include/asm/local.h b/arch/m68k/include/asm/local.h deleted file mode 100644 index 6c25926..0000000 --- a/arch/m68k/include/asm/local.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_M68K_LOCAL_H -#define _ASM_M68K_LOCAL_H - -#include <asm-generic/local.h> - -#endif /* _ASM_M68K_LOCAL_H */ diff --git a/arch/m68k/include/asm/local64.h b/arch/m68k/include/asm/local64.h deleted file mode 100644 index 36c93b5..0000000 --- a/arch/m68k/include/asm/local64.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/local64.h> diff --git a/arch/m68k/include/asm/mac_mouse.h b/arch/m68k/include/asm/mac_mouse.h deleted file mode 100644 index 39a5c29..0000000 --- a/arch/m68k/include/asm/mac_mouse.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _ASM_MAC_MOUSE_H -#define _ASM_MAC_MOUSE_H - -/* - * linux/include/asm-m68k/mac_mouse.h - * header file for Macintosh ADB mouse driver - * 27-10-97 Michael Schmitz - * copied from: - * header file for Atari Mouse driver - * by Robert de Vries (robert@and.nl) on 19Jul93 - */ - -struct mouse_status { - char buttons; - short dx; - short dy; - int ready; - int active; - wait_queue_head_t wait; - struct fasync_struct *fasyncptr; -}; - -#endif diff --git a/arch/m68k/include/asm/mcfmbus.h b/arch/m68k/include/asm/mcfmbus.h deleted file mode 100644 index 319899c..0000000 --- a/arch/m68k/include/asm/mcfmbus.h +++ /dev/null @@ -1,77 +0,0 @@ -/****************************************************************************/ - -/* - * mcfmbus.h -- Coldfire MBUS support defines. - * - * (C) Copyright 1999, Martin Floeer (mfloeer@axcent.de) - */ - -/****************************************************************************/ - - -#ifndef mcfmbus_h -#define mcfmbus_h - - -#define MCFMBUS_BASE 0x280 -#define MCFMBUS_IRQ_VECTOR 0x19 -#define MCFMBUS_IRQ 0x1 -#define MCFMBUS_CLK 0x3f -#define MCFMBUS_IRQ_LEVEL 0x07 /*IRQ Level 1*/ -#define MCFMBUS_ADDRESS 0x01 - - -/* -* Define the 5307 MBUS register set addresses -*/ - -#define MCFMBUS_MADR 0x00 -#define MCFMBUS_MFDR 0x04 -#define MCFMBUS_MBCR 0x08 -#define MCFMBUS_MBSR 0x0C -#define MCFMBUS_MBDR 0x10 - - -#define MCFMBUS_MADR_ADDR(a) (((a)&0x7F)<<0x01) /*Slave Address*/ - -#define MCFMBUS_MFDR_MBC(a) ((a)&0x3F) /*M-Bus Clock*/ - -/* -* Define bit flags in Control Register -*/ - -#define MCFMBUS_MBCR_MEN (0x80) /* M-Bus Enable */ -#define MCFMBUS_MBCR_MIEN (0x40) /* M-Bus Interrupt Enable */ -#define MCFMBUS_MBCR_MSTA (0x20) /* Master/Slave Mode Select Bit */ -#define MCFMBUS_MBCR_MTX (0x10) /* Transmit/Rcv Mode Select Bit */ -#define MCFMBUS_MBCR_TXAK (0x08) /* Transmit Acknowledge Enable */ -#define MCFMBUS_MBCR_RSTA (0x04) /* Repeat Start */ - -/* -* Define bit flags in Status Register -*/ - -#define MCFMBUS_MBSR_MCF (0x80) /* Data Transfer Complete */ -#define MCFMBUS_MBSR_MAAS (0x40) /* Addressed as a Slave */ -#define MCFMBUS_MBSR_MBB (0x20) /* Bus Busy */ -#define MCFMBUS_MBSR_MAL (0x10) /* Arbitration Lost */ -#define MCFMBUS_MBSR_SRW (0x04) /* Slave Transmit */ -#define MCFMBUS_MBSR_MIF (0x02) /* M-Bus Interrupt */ -#define MCFMBUS_MBSR_RXAK (0x01) /* No Acknowledge Received */ - -/* -* Define bit flags in DATA I/O Register -*/ - -#define MCFMBUS_MBDR_READ (0x01) /* 1=read 0=write MBUS */ - -#define MBUSIOCSCLOCK 1 -#define MBUSIOCGCLOCK 2 -#define MBUSIOCSADDR 3 -#define MBUSIOCGADDR 4 -#define MBUSIOCSSLADDR 5 -#define MBUSIOCGSLADDR 6 -#define MBUSIOCSSUBADDR 7 -#define MBUSIOCGSUBADDR 8 - -#endif diff --git a/arch/m68k/include/asm/mman.h b/arch/m68k/include/asm/mman.h deleted file mode 100644 index 8eebf89..0000000 --- a/arch/m68k/include/asm/mman.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/mman.h> diff --git a/arch/m68k/include/asm/mutex.h b/arch/m68k/include/asm/mutex.h deleted file mode 100644 index 458c1f7..0000000 --- a/arch/m68k/include/asm/mutex.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Pull in the generic implementation for the mutex fastpath. - * - * TODO: implement optimized primitives instead, or leave the generic - * implementation in place, or pick the atomic_xchg() based generic - * implementation. (see asm-generic/mutex-xchg.h for details) - */ - -#include <asm-generic/mutex-dec.h> diff --git a/arch/m68k/include/asm/percpu.h b/arch/m68k/include/asm/percpu.h deleted file mode 100644 index 0859d04..0000000 --- a/arch/m68k/include/asm/percpu.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_M68K_PERCPU_H -#define __ASM_M68K_PERCPU_H - -#include <asm-generic/percpu.h> - -#endif /* __ASM_M68K_PERCPU_H */ diff --git a/arch/m68k/include/asm/resource.h b/arch/m68k/include/asm/resource.h deleted file mode 100644 index e7d3501..0000000 --- a/arch/m68k/include/asm/resource.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M68K_RESOURCE_H -#define _M68K_RESOURCE_H - -#include <asm-generic/resource.h> - -#endif /* _M68K_RESOURCE_H */ diff --git a/arch/m68k/include/asm/sbus.h b/arch/m68k/include/asm/sbus.h deleted file mode 100644 index bfe3ba1..0000000 --- a/arch/m68k/include/asm/sbus.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * some sbus structures and macros to make usage of sbus drivers possible - */ - -#ifndef __M68K_SBUS_H -#define __M68K_SBUS_H - -struct sbus_dev { - struct { - unsigned int which_io; - unsigned int phys_addr; - } reg_addrs[1]; -}; - -/* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */ -/* No SBUS on the Sun3, kludge -- sam */ - -static inline void _sbus_writeb(unsigned char val, unsigned long addr) -{ - *(volatile unsigned char *)addr = val; -} - -static inline unsigned char _sbus_readb(unsigned long addr) -{ - return *(volatile unsigned char *)addr; -} - -static inline void _sbus_writel(unsigned long val, unsigned long addr) -{ - *(volatile unsigned long *)addr = val; - -} - -extern inline unsigned long _sbus_readl(unsigned long addr) -{ - return *(volatile unsigned long *)addr; -} - - -#define sbus_readb(a) _sbus_readb((unsigned long)a) -#define sbus_writeb(v, a) _sbus_writeb(v, (unsigned long)a) -#define sbus_readl(a) _sbus_readl((unsigned long)a) -#define sbus_writel(v, a) _sbus_writel(v, (unsigned long)a) - -#endif diff --git a/arch/m68k/include/asm/scatterlist.h b/arch/m68k/include/asm/scatterlist.h deleted file mode 100644 index 3125054..0000000 --- a/arch/m68k/include/asm/scatterlist.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M68K_SCATTERLIST_H -#define _M68K_SCATTERLIST_H - -#include <asm-generic/scatterlist.h> - -#endif /* !(_M68K_SCATTERLIST_H) */ diff --git a/arch/m68k/include/asm/sections.h b/arch/m68k/include/asm/sections.h deleted file mode 100644 index 5277e52..0000000 --- a/arch/m68k/include/asm/sections.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASM_M68K_SECTIONS_H -#define _ASM_M68K_SECTIONS_H - -#include <asm-generic/sections.h> - -extern char _sbss[], _ebss[]; - -#endif /* _ASM_M68K_SECTIONS_H */ diff --git a/arch/m68k/include/asm/shm.h b/arch/m68k/include/asm/shm.h deleted file mode 100644 index fa56ec8..0000000 --- a/arch/m68k/include/asm/shm.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _M68K_SHM_H -#define _M68K_SHM_H - - -/* format of page table entries that correspond to shared memory pages - currently out in swap space (see also mm/swap.c): - bits 0-1 (PAGE_PRESENT) is = 0 - bits 8..2 (SWP_TYPE) are = SHM_SWP_TYPE - bits 31..9 are used like this: - bits 15..9 (SHM_ID) the id of the shared memory segment - bits 30..16 (SHM_IDX) the index of the page within the shared memory segment - (actually only bits 25..16 get used since SHMMAX is so low) - bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach -*/ -/* on the m68k both bits 0 and 1 must be zero */ -/* format on the sun3 is similar, but bits 30, 31 are set to zero and all - others are reduced by 2. --m */ - -#ifndef CONFIG_SUN3 -#define SHM_ID_SHIFT 9 -#else -#define SHM_ID_SHIFT 7 -#endif -#define _SHM_ID_BITS 7 -#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) - -#define SHM_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS) -#define _SHM_IDX_BITS 15 -#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) - -#endif /* _M68K_SHM_H */ diff --git a/arch/m68k/include/asm/siginfo.h b/arch/m68k/include/asm/siginfo.h deleted file mode 100644 index 851d3d7..0000000 --- a/arch/m68k/include/asm/siginfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M68K_SIGINFO_H -#define _M68K_SIGINFO_H - -#include <asm-generic/siginfo.h> - -#endif diff --git a/arch/m68k/include/asm/statfs.h b/arch/m68k/include/asm/statfs.h deleted file mode 100644 index 08d93f1..0000000 --- a/arch/m68k/include/asm/statfs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _M68K_STATFS_H -#define _M68K_STATFS_H - -#include <asm-generic/statfs.h> - -#endif /* _M68K_STATFS_H */ diff --git a/arch/m68k/include/asm/topology.h b/arch/m68k/include/asm/topology.h deleted file mode 100644 index ca173e9..0000000 --- a/arch/m68k/include/asm/topology.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_M68K_TOPOLOGY_H -#define _ASM_M68K_TOPOLOGY_H - -#include <asm-generic/topology.h> - -#endif /* _ASM_M68K_TOPOLOGY_H */ diff --git a/arch/m68k/include/asm/types.h b/arch/m68k/include/asm/types.h deleted file mode 100644 index 89705ad..0000000 --- a/arch/m68k/include/asm/types.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _M68K_TYPES_H -#define _M68K_TYPES_H - -/* - * This file is never included by application software unless - * explicitly requested (e.g., via linux/types.h) in which case the - * application is Linux specific so (user-) name space pollution is - * not a major issue. However, for interoperability, libraries still - * need to be careful to avoid a name clashes. - */ -#include <asm-generic/int-ll64.h> - -/* - * These aren't exported outside the kernel to avoid name space clashes - */ -#ifdef __KERNEL__ - -#define BITS_PER_LONG 32 - -#endif /* __KERNEL__ */ - -#endif /* _M68K_TYPES_H */ diff --git a/arch/m68k/include/asm/unaligned.h b/arch/m68k/include/asm/unaligned.h index f4043ae..2b3ca0b 100644 --- a/arch/m68k/include/asm/unaligned.h +++ b/arch/m68k/include/asm/unaligned.h @@ -2,7 +2,7 @@ #define _ASM_M68K_UNALIGNED_H -#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68000) +#ifdef CONFIG_CPU_HAS_NO_UNALIGNED #include <linux/unaligned/be_struct.h> #include <linux/unaligned/le_byteshift.h> #include <linux/unaligned/generic.h> @@ -12,7 +12,7 @@ #else /* - * The m68k can do unaligned accesses itself. + * The m68k can do unaligned accesses itself. */ #include <linux/unaligned/access_ok.h> #include <linux/unaligned/generic.h> diff --git a/arch/m68k/include/asm/xor.h b/arch/m68k/include/asm/xor.h deleted file mode 100644 index c82eb12..0000000 --- a/arch/m68k/include/asm/xor.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/xor.h> diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index 7dc186b..71fb299 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -218,13 +218,10 @@ void __init setup_arch(char **cmdline_p) printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n"); #endif - pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " - "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, - (int) &_sdata, (int) &_edata, - (int) &_sbss, (int) &_ebss); - pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ", - (int) &_ebss, (int) memory_start, - (int) memory_start, (int) memory_end); + pr_debug("KERNEL -> TEXT=0x%p-0x%p DATA=0x%p-0x%p BSS=0x%p-0x%p\n", + _stext, _etext, _sdata, _edata, __bss_start, __bss_stop); + pr_debug("MEMORY -> ROMFS=0x%p-0x%06lx MEM=0x%06lx-0x%06lx\n ", + __bss_stop, memory_start, memory_start, memory_end); /* Keep a copy of command line */ *cmdline_p = &command_line[0]; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 8623f8d..9a5932e 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -479,9 +479,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, goto bad_access; } - mem_value = *mem; + /* + * No need to check for EFAULT; we know that the page is + * present and writable. + */ + __get_user(mem_value, mem); if (mem_value == oldval) - *mem = newval; + __put_user(newval, mem); pte_unmap_unlock(pte, ptl); up_read(&mm->mmap_sem); diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds index 40e02d9..06a763f 100644 --- a/arch/m68k/kernel/vmlinux-nommu.lds +++ b/arch/m68k/kernel/vmlinux-nommu.lds @@ -78,9 +78,7 @@ SECTIONS { __init_end = .; } - _sbss = .; BSS_SECTION(0, 0, 0) - _ebss = .; _end = .; diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 63407c8..d099359 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -31,9 +31,7 @@ SECTIONS RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) - _sbss = .; BSS_SECTION(0, 0, 0) - _ebss = .; _edata = .; /* End of data section */ diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index ad0f46d..8080469 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -44,9 +44,7 @@ __init_begin = .; . = ALIGN(PAGE_SIZE); __init_end = .; - _sbss = .; BSS_SECTION(0, 0, 0) - _ebss = .; _end = . ; diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c index 79e928a..ee5f0b1 100644 --- a/arch/m68k/lib/muldi3.c +++ b/arch/m68k/lib/muldi3.c @@ -19,7 +19,7 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE) +#ifdef CONFIG_CPU_HAS_NO_MULDIV64 #define SI_TYPE_SIZE 32 #define __BITS4 (SI_TYPE_SIZE / 4) diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c index f77f258..282f9de 100644 --- a/arch/m68k/mm/init_mm.c +++ b/arch/m68k/mm/init_mm.c @@ -104,7 +104,7 @@ void __init print_memmap(void) MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(_stext, _etext), MLK_ROUNDUP(_sdata, _edata), - MLK_ROUNDUP(_sbss, _ebss)); + MLK_ROUNDUP(__bss_start, __bss_stop)); } void __init mem_init(void) diff --git a/arch/m68k/mm/init_no.c b/arch/m68k/mm/init_no.c index 345ec0d..688e366 100644 --- a/arch/m68k/mm/init_no.c +++ b/arch/m68k/mm/init_no.c @@ -91,7 +91,7 @@ void __init mem_init(void) totalram_pages = free_all_bootmem(); codek = (_etext - _stext) >> 10; - datak = (_ebss - _sdata) >> 10; + datak = (__bss_stop - _sdata) >> 10; initk = (__init_begin - __init_end) >> 10; tmp = nr_free_pages() << PAGE_SHIFT; diff --git a/arch/m68k/platform/68328/head-de2.S b/arch/m68k/platform/68328/head-de2.S index f632fdc..537d324 100644 --- a/arch/m68k/platform/68328/head-de2.S +++ b/arch/m68k/platform/68328/head-de2.S @@ -60,8 +60,8 @@ _start: * Move ROM filesystem above bss :-) */ - moveal #_sbss, %a0 /* romfs at the start of bss */ - moveal #_ebss, %a1 /* Set up destination */ + moveal #__bss_start, %a0 /* romfs at the start of bss */ + moveal #__bss_stop, %a1 /* Set up destination */ movel %a0, %a2 /* Copy of bss start */ movel 8(%a0), %d1 /* Get size of ROMFS */ @@ -84,8 +84,8 @@ _start: * Initialize BSS segment to 0 */ - lea _sbss, %a0 - lea _ebss, %a1 + lea __bss_start, %a0 + lea __bss_stop, %a1 /* Copy 0 to %a0 until %a0 == %a1 */ 2: cmpal %a0, %a1 diff --git a/arch/m68k/platform/68328/head-pilot.S b/arch/m68k/platform/68328/head-pilot.S index 2ebfd64..45a9dad 100644 --- a/arch/m68k/platform/68328/head-pilot.S +++ b/arch/m68k/platform/68328/head-pilot.S @@ -110,7 +110,7 @@ L0: movel #CONFIG_VECTORBASE, %d7 addl #16, %d7 moveal %d7, %a0 - moveal #_ebss, %a1 + moveal #__bss_stop, %a1 lea %a1@(512), %a2 DBG_PUTC('C') @@ -138,8 +138,8 @@ LD1: DBG_PUTC('E') - moveal #_sbss, %a0 - moveal #_ebss, %a1 + moveal #__bss_start, %a0 + moveal #__bss_stop, %a1 /* Copy 0 to %a0 until %a0 == %a1 */ L1: @@ -150,7 +150,7 @@ L1: DBG_PUTC('F') /* Copy command line from end of bss to command line */ - moveal #_ebss, %a0 + moveal #__bss_stop, %a0 moveal #command_line, %a1 lea %a1@(512), %a2 @@ -165,7 +165,7 @@ L3: movel #_sdata, %d0 movel %d0, _rambase - movel #_ebss, %d0 + movel #__bss_stop, %d0 movel %d0, _ramstart movel %a4, %d0 diff --git a/arch/m68k/platform/68328/head-ram.S b/arch/m68k/platform/68328/head-ram.S index 7f1aeea..5189ef9 100644 --- a/arch/m68k/platform/68328/head-ram.S +++ b/arch/m68k/platform/68328/head-ram.S @@ -76,8 +76,8 @@ pclp3: beq pclp3 #endif /* DEBUG */ moveal #0x007ffff0, %ssp - moveal #_sbss, %a0 - moveal #_ebss, %a1 + moveal #__bss_start, %a0 + moveal #__bss_stop, %a1 /* Copy 0 to %a0 until %a0 >= %a1 */ L1: diff --git a/arch/m68k/platform/68328/head-rom.S b/arch/m68k/platform/68328/head-rom.S index a5ff96d..3dff98b 100644 --- a/arch/m68k/platform/68328/head-rom.S +++ b/arch/m68k/platform/68328/head-rom.S @@ -59,8 +59,8 @@ _stext: movew #0x2700,%sr cmpal %a1, %a2 bhi 1b - moveal #_sbss, %a0 - moveal #_ebss, %a1 + moveal #__bss_start, %a0 + moveal #__bss_stop, %a1 /* Copy 0 to %a0 until %a0 == %a1 */ 1: @@ -70,7 +70,7 @@ _stext: movew #0x2700,%sr movel #_sdata, %d0 movel %d0, _rambase - movel #_ebss, %d0 + movel #__bss_stop, %d0 movel %d0, _ramstart movel #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0 movel %d0, _ramend diff --git a/arch/m68k/platform/68360/head-ram.S b/arch/m68k/platform/68360/head-ram.S index 8eb94fb..acd2131 100644 --- a/arch/m68k/platform/68360/head-ram.S +++ b/arch/m68k/platform/68360/head-ram.S @@ -219,8 +219,8 @@ LD1: cmp.l #_edata, %a1 blt LD1 - moveal #_sbss, %a0 - moveal #_ebss, %a1 + moveal #__bss_start, %a0 + moveal #__bss_stop, %a1 /* Copy 0 to %a0 until %a0 == %a1 */ L1: @@ -234,7 +234,7 @@ load_quicc: store_ram_size: /* Set ram size information */ move.l #_sdata, _rambase - move.l #_ebss, _ramstart + move.l #__bss_stop, _ramstart move.l #RAMEND, %d0 sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ move.l %d0, _ramend /* Different from RAMEND.*/ diff --git a/arch/m68k/platform/68360/head-rom.S b/arch/m68k/platform/68360/head-rom.S index 97510e5..dfc756d 100644 --- a/arch/m68k/platform/68360/head-rom.S +++ b/arch/m68k/platform/68360/head-rom.S @@ -13,7 +13,7 @@ */ .global _stext -.global _sbss +.global __bss_start .global _start .global _rambase @@ -229,8 +229,8 @@ LD1: cmp.l #_edata, %a1 blt LD1 - moveal #_sbss, %a0 - moveal #_ebss, %a1 + moveal #__bss_start, %a0 + moveal #__bss_stop, %a1 /* Copy 0 to %a0 until %a0 == %a1 */ L1: @@ -244,7 +244,7 @@ load_quicc: store_ram_size: /* Set ram size information */ move.l #_sdata, _rambase - move.l #_ebss, _ramstart + move.l #__bss_stop, _ramstart move.l #RAMEND, %d0 sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ move.l %d0, _ramend /* Different from RAMEND.*/ diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S index 4e0c9eb..b88f571 100644 --- a/arch/m68k/platform/coldfire/head.S +++ b/arch/m68k/platform/coldfire/head.S @@ -230,8 +230,8 @@ _vstart: /* * Move ROM filesystem above bss :-) */ - lea _sbss,%a0 /* get start of bss */ - lea _ebss,%a1 /* set up destination */ + lea __bss_start,%a0 /* get start of bss */ + lea __bss_stop,%a1 /* set up destination */ movel %a0,%a2 /* copy of bss start */ movel 8(%a0),%d0 /* get size of ROMFS */ @@ -249,7 +249,7 @@ _copy_romfs: bne _copy_romfs #else /* CONFIG_ROMFS_FS */ - lea _ebss,%a1 + lea __bss_stop,%a1 movel %a1,_ramstart #endif /* CONFIG_ROMFS_FS */ @@ -257,8 +257,8 @@ _copy_romfs: /* * Zero out the bss region. */ - lea _sbss,%a0 /* get start of bss */ - lea _ebss,%a1 /* get end of bss */ + lea __bss_start,%a0 /* get start of bss */ + lea __bss_stop,%a1 /* get end of bss */ clrl %d0 /* set value */ _clear_bss: movel %d0,(%a0)+ /* clear each word */ diff --git a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c index d8e6349..eeba067 100644 --- a/arch/m68k/sun3/prom/init.c +++ b/arch/m68k/sun3/prom/init.c @@ -22,57 +22,13 @@ int prom_root_node; struct linux_nodeops *prom_nodeops; /* You must call prom_init() before you attempt to use any of the - * routines in the prom library. It returns 0 on success, 1 on - * failure. It gets passed the pointer to the PROM vector. + * routines in the prom library. + * It gets passed the pointer to the PROM vector. */ -extern void prom_meminit(void); -extern void prom_ranges_init(void); - void __init prom_init(struct linux_romvec *rp) { romvec = rp; -#ifndef CONFIG_SUN3 - switch(romvec->pv_romvers) { - case 0: - prom_vers = PROM_V0; - break; - case 2: - prom_vers = PROM_V2; - break; - case 3: - prom_vers = PROM_V3; - break; - case 4: - prom_vers = PROM_P1275; - prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n"); - prom_halt(); - break; - default: - prom_printf("PROMLIB: Bad PROM version %d\n", - romvec->pv_romvers); - prom_halt(); - break; - }; - - prom_rev = romvec->pv_plugin_revision; - prom_prev = romvec->pv_printrev; - prom_nodeops = romvec->pv_nodeops; - - prom_root_node = prom_getsibling(0); - if((prom_root_node == 0) || (prom_root_node == -1)) - prom_halt(); - - if((((unsigned long) prom_nodeops) == 0) || - (((unsigned long) prom_nodeops) == -1)) - prom_halt(); - - prom_meminit(); - - prom_ranges_init(); -#endif -// printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n", -// romvec->pv_romvers, prom_rev); /* Initialization successful. */ return; diff --git a/arch/microblaze/include/asm/sections.h b/arch/microblaze/include/asm/sections.h index 4487e15..c07ed5d 100644 --- a/arch/microblaze/include/asm/sections.h +++ b/arch/microblaze/include/asm/sections.h @@ -18,10 +18,6 @@ extern char _ssbss[], _esbss[]; extern unsigned long __ivt_start[], __ivt_end[]; extern char _etext[], _stext[]; -# ifdef CONFIG_MTD_UCLINUX -extern char *_ebss; -# endif - extern u32 _fdt_start[], _fdt_end[]; # endif /* !__ASSEMBLY__ */ diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c index bb4907c..2b25bcf 100644 --- a/arch/microblaze/kernel/microblaze_ksyms.c +++ b/arch/microblaze/kernel/microblaze_ksyms.c @@ -21,9 +21,6 @@ #include <linux/ftrace.h> #include <linux/uaccess.h> -extern char *_ebss; -EXPORT_SYMBOL_GPL(_ebss); - #ifdef CONFIG_FUNCTION_TRACER extern void _mcount(void); EXPORT_SYMBOL(_mcount); diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 16d8dfd..4da971d 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -121,7 +121,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, /* Move ROMFS out of BSS before clearing it */ if (romfs_size > 0) { - memmove(&_ebss, (int *)romfs_base, romfs_size); + memmove(&__bss_stop, (int *)romfs_base, romfs_size); klimit += romfs_size; } #endif @@ -165,7 +165,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, BUG_ON(romfs_size < 0); /* What else can we do? */ printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", - romfs_size, romfs_base, (unsigned)&_ebss); + romfs_size, romfs_base, (unsigned)&__bss_stop); printk("New klimit: 0x%08x\n", (unsigned)klimit); #endif diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index 109e9d8..936d01a 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -131,7 +131,6 @@ SECTIONS { *(COMMON) . = ALIGN (4) ; __bss_stop = . ; - _ebss = . ; } . = ALIGN(PAGE_SIZE); _end = .; diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 7048c03..fb58057 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -57,6 +57,7 @@ config SH_7724_SOLUTION_ENGINE depends on CPU_SUBTYPE_SH7724 select ARCH_REQUIRE_GPIOLIB select SND_SOC_AK4642 if SND_SIMPLE_CARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Select 7724 SolutionEngine if configuring for a Hitachi SH7724 evaluation board. @@ -140,6 +141,7 @@ config SH_RSK bool "Renesas Starter Kit" depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203 || \ CPU_SUBTYPE_SH7264 || CPU_SUBTYPE_SH7269 + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Select this option if configuring for any of the RSK+ MCU evaluation platforms. @@ -159,6 +161,7 @@ config SH_SDK7786 select NO_IOPORT if !PCI select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_SRAM_POOL + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Select SDK7786 if configuring for a Renesas Technology Europe SH7786-65nm board. @@ -173,6 +176,7 @@ config SH_SH7757LCR bool "SH7757LCR" depends on CPU_SUBTYPE_SH7757 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR config SH_SH7785LCR bool "SH7785LCR" @@ -206,6 +210,7 @@ config SH_MIGOR bool "Migo-R" depends on CPU_SUBTYPE_SH7722 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Select Migo-R if configuring for the SH7722 Migo-R platform by Renesas System Solutions Asia Pte. Ltd. @@ -214,6 +219,7 @@ config SH_AP325RXA bool "AP-325RXA" depends on CPU_SUBTYPE_SH7723 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Renesas "AP-325RXA" support. Compatible with ALGO SYSTEM CO.,LTD. "AP-320A" @@ -222,6 +228,7 @@ config SH_KFR2R09 bool "KFR2R09" depends on CPU_SUBTYPE_SH7724 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR help "Kit For R2R for 2009" support. @@ -230,6 +237,7 @@ config SH_ECOVEC depends on CPU_SUBTYPE_SH7724 select ARCH_REQUIRE_GPIOLIB select SND_SOC_DA7210 if SND_SIMPLE_CARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Renesas "R0P7724LC0011/21RL (EcoVec)" support. @@ -305,6 +313,7 @@ config SH_MAGIC_PANEL_R2 bool "Magic Panel R2" depends on CPU_SUBTYPE_SH7720 select ARCH_REQUIRE_GPIOLIB + select REGULATOR_FIXED_VOLTAGE if REGULATOR help Select Magic Panel R2 if configuring for Magic Panel R2. @@ -316,6 +325,7 @@ config SH_CAYMAN config SH_POLARIS bool "SMSC Polaris" select CPU_HAS_IPR_IRQ + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on CPU_SUBTYPE_SH7709 help Select if configuring for an SMSC Polaris development board @@ -323,6 +333,7 @@ config SH_POLARIS config SH_SH2007 bool "SH-2007 board" select NO_IOPORT + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on CPU_SUBTYPE_SH7780 help SH-2007 is a single-board computer based around SH7780 chip @@ -334,6 +345,7 @@ config SH_SH2007 config SH_APSH4A3A bool "AP-SH4A-3A" select SH_ALPHA_BOARD + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on CPU_SUBTYPE_SH7785 help Select AP-SH4A-3A if configuring for an ALPHAPROJECT AP-SH4A-3A. @@ -342,6 +354,7 @@ config SH_APSH4AD0A bool "AP-SH4AD-0A" select SH_ALPHA_BOARD select SYS_SUPPORTS_PCI + select REGULATOR_FIXED_VOLTAGE if REGULATOR depends on CPU_SUBTYPE_SH7786 help Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A. diff --git a/arch/sh/boards/board-apsh4a3a.c b/arch/sh/boards/board-apsh4a3a.c index 2823619..0a39c24 100644 --- a/arch/sh/boards/board-apsh4a3a.c +++ b/arch/sh/boards/board-apsh4a3a.c @@ -13,6 +13,8 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/mtd/physmap.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/irq.h> #include <linux/clk.h> @@ -66,6 +68,12 @@ static struct platform_device nor_flash_device = { .resource = nor_flash_resources, }; +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static struct resource smsc911x_resources[] = { [0] = { .name = "smsc911x-memory", @@ -105,6 +113,8 @@ static struct platform_device *apsh4a3a_devices[] __initdata = { static int __init apsh4a3a_devices_setup(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + return platform_add_devices(apsh4a3a_devices, ARRAY_SIZE(apsh4a3a_devices)); } diff --git a/arch/sh/boards/board-apsh4ad0a.c b/arch/sh/boards/board-apsh4ad0a.c index b4d6292a..92eac3a 100644 --- a/arch/sh/boards/board-apsh4ad0a.c +++ b/arch/sh/boards/board-apsh4ad0a.c @@ -12,12 +12,20 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/irq.h> #include <linux/clk.h> #include <asm/machvec.h> #include <asm/sizes.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static struct resource smsc911x_resources[] = { [0] = { .name = "smsc911x-memory", @@ -56,6 +64,8 @@ static struct platform_device *apsh4ad0a_devices[] __initdata = { static int __init apsh4ad0a_devices_setup(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + return platform_add_devices(apsh4ad0a_devices, ARRAY_SIZE(apsh4ad0a_devices)); } diff --git a/arch/sh/boards/board-magicpanelr2.c b/arch/sh/boards/board-magicpanelr2.c index 90568f9..2050085 100644 --- a/arch/sh/boards/board-magicpanelr2.c +++ b/arch/sh/boards/board-magicpanelr2.c @@ -14,6 +14,8 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -24,6 +26,12 @@ #include <asm/heartbeat.h> #include <cpu/sh7720.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + #define LAN9115_READY (__raw_readl(0xA8000084UL) & 0x00000001UL) /* Wait until reset finished. Timeout is 100ms. */ @@ -348,6 +356,8 @@ static struct platform_device *mpr2_devices[] __initdata = { static int __init mpr2_devices_setup(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices)); } device_initcall(mpr2_devices_setup); diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c index 0978ae2..37a08d0 100644 --- a/arch/sh/boards/board-polaris.c +++ b/arch/sh/boards/board-polaris.c @@ -9,6 +9,8 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/io.h> #include <asm/irq.h> @@ -22,6 +24,12 @@ #define AREA5_WAIT_CTRL (0x1C00) #define WAIT_STATES_10 (0x7) +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x.0"), + REGULATOR_SUPPLY("vdd33a", "smsc911x.0"), +}; + static struct resource smsc911x_resources[] = { [0] = { .name = "smsc911x-memory", @@ -88,6 +96,8 @@ static int __init polaris_initialise(void) printk(KERN_INFO "Configuring Polaris external bus\n"); + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + /* Configure area 5 with 2 wait states */ wcr = __raw_readw(WCR2); wcr &= (~AREA5_WAIT_CTRL); diff --git a/arch/sh/boards/board-sh2007.c b/arch/sh/boards/board-sh2007.c index b90b78f..1980bb7 100644 --- a/arch/sh/boards/board-sh2007.c +++ b/arch/sh/boards/board-sh2007.c @@ -6,6 +6,8 @@ */ #include <linux/init.h> #include <linux/irq.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/platform_device.h> #include <linux/ata_platform.h> @@ -13,6 +15,14 @@ #include <asm/machvec.h> #include <mach/sh2007.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x.0"), + REGULATOR_SUPPLY("vdd33a", "smsc911x.0"), + REGULATOR_SUPPLY("vddvario", "smsc911x.1"), + REGULATOR_SUPPLY("vdd33a", "smsc911x.1"), +}; + struct smsc911x_platform_config smc911x_info = { .flags = SMSC911X_USE_32BIT, .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, @@ -98,6 +108,8 @@ static struct platform_device *sh2007_devices[] __initdata = { static int __init sh2007_io_init(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + platform_add_devices(sh2007_devices, ARRAY_SIZE(sh2007_devices)); return 0; } diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c index 5087f8b..41f8670 100644 --- a/arch/sh/boards/board-sh7757lcr.c +++ b/arch/sh/boards/board-sh7757lcr.c @@ -12,6 +12,8 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/irq.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> #include <linux/io.h> @@ -199,6 +201,15 @@ static struct platform_device sh7757_eth_giga1_device = { }, }; +/* Fixed 3.3V regulator to be used by SDHI0, MMCIF */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + /* SH_MMCIF */ static struct resource sh_mmcif_resources[] = { [0] = { @@ -329,6 +340,9 @@ static struct spi_board_info spi_board_info[] = { static int __init sh7757lcr_devices_setup(void) { + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + /* RGMII (PTA) */ gpio_request(GPIO_FN_ET0_MDC, NULL); gpio_request(GPIO_FN_ET0_MDIO, NULL); diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index f33ebf4..9e963c1 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -20,6 +20,8 @@ #include <linux/mtd/sh_flctl.h> #include <linux/delay.h> #include <linux/i2c.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/gpio.h> #include <linux/videodev2.h> @@ -34,6 +36,12 @@ #include <asm/suspend.h> #include <cpu/sh7723.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static struct smsc911x_platform_config smsc911x_config = { .phy_interface = PHY_INTERFACE_MODE_MII, .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, @@ -423,6 +431,15 @@ static struct platform_device ceu_device = { }, }; +/* Fixed 3.3V regulators to be used by SDHI0, SDHI1 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + static struct resource sdhi0_cn3_resources[] = { [0] = { .name = "SDHI0", @@ -544,6 +561,10 @@ static int __init ap325rxa_devices_setup(void) &ap325rxa_sdram_leave_start, &ap325rxa_sdram_leave_end); + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + regulator_register_fixed(1, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + /* LD3 and LD4 LEDs */ gpio_request(GPIO_PTX5, NULL); /* RUN */ gpio_direction_output(GPIO_PTX5, 1); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 4158d70..64559e8a 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -19,6 +19,8 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/usb/r8a66597.h> #include <linux/usb/renesas_usbhs.h> #include <linux/i2c.h> @@ -242,9 +244,17 @@ static int usbhs_get_id(struct platform_device *pdev) return gpio_get_value(GPIO_PTB3); } +static void usbhs_phy_reset(struct platform_device *pdev) +{ + /* enable vbus if HOST */ + if (!gpio_get_value(GPIO_PTB3)) + gpio_set_value(GPIO_PTB5, 1); +} + static struct renesas_usbhs_platform_info usbhs_info = { .platform_callback = { .get_id = usbhs_get_id, + .phy_reset = usbhs_phy_reset, }, .driver_param = { .buswait_bwait = 4, @@ -518,10 +528,86 @@ static struct i2c_board_info ts_i2c_clients = { .irq = IRQ0, }; +static struct regulator_consumer_supply cn12_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + +static struct regulator_init_data cn12_power_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(cn12_power_consumers), + .consumer_supplies = cn12_power_consumers, +}; + +static struct fixed_voltage_config cn12_power_info = { + .supply_name = "CN12 SD/MMC Vdd", + .microvolts = 3300000, + .gpio = GPIO_PTB7, + .enable_high = 1, + .init_data = &cn12_power_init_data, +}; + +static struct platform_device cn12_power = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &cn12_power_info, + }, +}; + #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) /* SDHI0 */ +static struct regulator_consumer_supply sdhi0_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), +}; + +static struct regulator_init_data sdhi0_power_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdhi0_power_consumers), + .consumer_supplies = sdhi0_power_consumers, +}; + +static struct fixed_voltage_config sdhi0_power_info = { + .supply_name = "CN11 SD/MMC Vdd", + .microvolts = 3300000, + .gpio = GPIO_PTB6, + .enable_high = 1, + .init_data = &sdhi0_power_init_data, +}; + +static struct platform_device sdhi0_power = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &sdhi0_power_info, + }, +}; + static void sdhi0_set_pwr(struct platform_device *pdev, int state) { + static int power_gpio = -EINVAL; + + if (power_gpio < 0) { + int ret = gpio_request(GPIO_PTB6, NULL); + if (!ret) { + power_gpio = GPIO_PTB6; + gpio_direction_output(power_gpio, 0); + } + } + + /* + * Toggle the GPIO regardless, whether we managed to grab it above or + * the fixed regulator driver did. + */ gpio_set_value(GPIO_PTB6, state); } @@ -562,13 +648,27 @@ static struct platform_device sdhi0_device = { }, }; -#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) -/* SDHI1 */ -static void sdhi1_set_pwr(struct platform_device *pdev, int state) +static void cn12_set_pwr(struct platform_device *pdev, int state) { + static int power_gpio = -EINVAL; + + if (power_gpio < 0) { + int ret = gpio_request(GPIO_PTB7, NULL); + if (!ret) { + power_gpio = GPIO_PTB7; + gpio_direction_output(power_gpio, 0); + } + } + + /* + * Toggle the GPIO regardless, whether we managed to grab it above or + * the fixed regulator driver did. + */ gpio_set_value(GPIO_PTB7, state); } +#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) +/* SDHI1 */ static int sdhi1_get_cd(struct platform_device *pdev) { return !gpio_get_value(GPIO_PTW7); @@ -579,7 +679,7 @@ static struct sh_mobile_sdhi_info sdhi1_info = { .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, .tmio_caps = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | MMC_CAP_NEEDS_POLL, - .set_pwr = sdhi1_set_pwr, + .set_pwr = cn12_set_pwr, .get_cd = sdhi1_get_cd, }; @@ -899,14 +999,9 @@ static struct platform_device vou_device = { #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE) /* SH_MMCIF */ -static void mmcif_set_pwr(struct platform_device *pdev, int state) -{ - gpio_set_value(GPIO_PTB7, state); -} - static void mmcif_down_pwr(struct platform_device *pdev) { - gpio_set_value(GPIO_PTB7, 0); + cn12_set_pwr(pdev, 0); } static struct resource sh_mmcif_resources[] = { @@ -929,7 +1024,7 @@ static struct resource sh_mmcif_resources[] = { }; static struct sh_mmcif_plat_data sh_mmcif_plat = { - .set_pwr = mmcif_set_pwr, + .set_pwr = cn12_set_pwr, .down_pwr = mmcif_down_pwr, .sup_pclk = 0, /* SH7724: Max Pclk/2 */ .caps = MMC_CAP_4_BIT_DATA | @@ -960,7 +1055,9 @@ static struct platform_device *ecovec_devices[] __initdata = { &ceu0_device, &ceu1_device, &keysc_device, + &cn12_power, #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) + &sdhi0_power, &sdhi0_device, #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) &sdhi1_device, @@ -1258,8 +1355,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_SDHI0D2, NULL); gpio_request(GPIO_FN_SDHI0D1, NULL); gpio_request(GPIO_FN_SDHI0D0, NULL); - gpio_request(GPIO_PTB6, NULL); - gpio_direction_output(GPIO_PTB6, 0); #else /* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */ gpio_request(GPIO_FN_MSIOF0_TXD, NULL); @@ -1288,8 +1383,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_MMC_D0, NULL); gpio_request(GPIO_FN_MMC_CLK, NULL); gpio_request(GPIO_FN_MMC_CMD, NULL); - gpio_request(GPIO_PTB7, NULL); - gpio_direction_output(GPIO_PTB7, 0); cn12_enabled = true; #elif defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) @@ -1301,8 +1394,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_SDHI1D2, NULL); gpio_request(GPIO_FN_SDHI1D1, NULL); gpio_request(GPIO_FN_SDHI1D0, NULL); - gpio_request(GPIO_PTB7, NULL); - gpio_direction_output(GPIO_PTB7, 0); /* Card-detect, used on CN12 with SDHI1 */ gpio_request(GPIO_PTW7, NULL); diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 43a179c..f2a4304 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -21,6 +21,8 @@ #include <linux/input.h> #include <linux/input/sh_keysc.h> #include <linux/i2c.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/usb/r8a66597.h> #include <linux/videodev2.h> #include <linux/sh_intc.h> @@ -341,6 +343,13 @@ static struct platform_device kfr2r09_camera = { }, }; +/* Fixed 3.3V regulator to be used by SDHI0 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), +}; + static struct resource kfr2r09_sh_sdhi0_resources[] = { [0] = { .name = "SDHI0", @@ -523,6 +532,9 @@ static int __init kfr2r09_devices_setup(void) &kfr2r09_sdram_leave_start, &kfr2r09_sdram_leave_end); + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + /* enable SCIF1 serial port for YC401 console support */ gpio_request(GPIO_FN_SCIF1_RXD, NULL); gpio_request(GPIO_FN_SCIF1_TXD, NULL); diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index a8a1ca7..8b73194 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -17,6 +17,8 @@ #include <linux/mtd/physmap.h> #include <linux/mtd/nand.h> #include <linux/i2c.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smc91x.h> #include <linux/delay.h> #include <linux/clk.h> @@ -386,6 +388,13 @@ static struct platform_device migor_ceu_device = { }, }; +/* Fixed 3.3V regulator to be used by SDHI0 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), +}; + static struct resource sdhi_cn9_resources[] = { [0] = { .name = "SDHI", @@ -498,6 +507,10 @@ static int __init migor_devices_setup(void) &migor_sdram_enter_end, &migor_sdram_leave_start, &migor_sdram_leave_end); + + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + /* Let D11 LED show STATUS0 */ gpio_request(GPIO_FN_STATUS0, NULL); diff --git a/arch/sh/boards/mach-rsk/setup.c b/arch/sh/boards/mach-rsk/setup.c index 895f030..2685ea0 100644 --- a/arch/sh/boards/mach-rsk/setup.c +++ b/arch/sh/boards/mach-rsk/setup.c @@ -16,9 +16,17 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> #include <linux/mtd/map.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <asm/machvec.h> #include <asm/io.h> +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static const char *part_probes[] = { "cmdlinepart", NULL }; static struct mtd_partition rsk_partitions[] = { @@ -67,6 +75,8 @@ static struct platform_device *rsk_devices[] __initdata = { static int __init rsk_devices_setup(void) { + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + return platform_add_devices(rsk_devices, ARRAY_SIZE(rsk_devices)); } diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index 27a2314..c29268b 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -11,6 +11,8 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/i2c.h> #include <linux/irq.h> @@ -38,6 +40,12 @@ static struct platform_device heartbeat_device = { .resource = &heartbeat_resource, }; +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + static struct resource smsc911x_resources[] = { [0] = { .name = "smsc911x-memory", @@ -236,6 +244,8 @@ static void __init sdk7786_setup(char **cmdline_p) { pr_info("Renesas Technology Europe SDK7786 support:\n"); + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + sdk7786_fpga_init(); sdk7786_nmi_init(); diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index ffbf5bc..35f6efa 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -18,6 +18,8 @@ #include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mtd/physmap.h> #include <linux/delay.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smc91x.h> #include <linux/gpio.h> #include <linux/input.h> @@ -454,6 +456,15 @@ static struct platform_device sh7724_usb1_gadget_device = { .resource = sh7724_usb1_gadget_resources, }; +/* Fixed 3.3V regulator to be used by SDHI0, SDHI1 */ +static struct regulator_consumer_supply fixed3v3_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"), +}; + static struct resource sdhi0_cn7_resources[] = { [0] = { .name = "SDHI0", @@ -684,6 +695,10 @@ static int __init devices_setup(void) &ms7724se_sdram_enter_end, &ms7724se_sdram_leave_start, &ms7724se_sdram_leave_end); + + regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, + ARRAY_SIZE(fixed3v3_power_consumers), 3300000); + /* Reset Release */ fpga_out = __raw_readw(FPGA_OUT); /* bit4: NTSC_PDN, bit5: NTSC_RESET */ diff --git a/arch/sh/include/asm/sections.h b/arch/sh/include/asm/sections.h index 4a53500..1b61997 100644 --- a/arch/sh/include/asm/sections.h +++ b/arch/sh/include/asm/sections.h @@ -6,7 +6,6 @@ extern long __nosave_begin, __nosave_end; extern long __machvec_start, __machvec_end; extern char __uncached_start, __uncached_end; -extern char _ebss[]; extern char __start_eh_frame[], __stop_eh_frame[]; #endif /* __ASM_SH_SECTIONS_H */ diff --git a/arch/sh/include/cpu-sh4/cpu/sh7757.h b/arch/sh/include/cpu-sh4/cpu/sh7757.h index 41f9f8b..5340f3b 100644 --- a/arch/sh/include/cpu-sh4/cpu/sh7757.h +++ b/arch/sh/include/cpu-sh4/cpu/sh7757.h @@ -283,5 +283,7 @@ enum { SHDMA_SLAVE_RIIC8_RX, SHDMA_SLAVE_RIIC9_TX, SHDMA_SLAVE_RIIC9_RX, + SHDMA_SLAVE_RSPI_TX, + SHDMA_SLAVE_RSPI_RX, }; #endif /* __ASM_SH7757_H__ */ diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index c87e78f..5f30f80 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -334,8 +334,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]), CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]), CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]), - CLKDEV_CON_ID("usb1", &mstp_clks[HWBLK_USB1]), - CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB0]), + CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[HWBLK_USB1]), + CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[HWBLK_USB0]), CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]), CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]), CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]), diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index 65786c7..6a868b0 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -12,6 +12,7 @@ #include <linux/platform_device.h> #include <linux/serial.h> #include <linux/serial_sci.h> +#include <linux/sh_dma.h> #include <linux/sh_timer.h> #include <linux/sh_intc.h> #include <linux/uio_driver.h> diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c index a770842..4a2f357 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c @@ -216,6 +216,20 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = { TS_INDEX2VAL(XMIT_SZ_8BIT), .mid_rid = 0x42, }, + { + .slave_id = SHDMA_SLAVE_RSPI_TX, + .addr = 0xfe480004, + .chcr = SM_INC | 0x800 | 0x40000000 | + TS_INDEX2VAL(XMIT_SZ_16BIT), + .mid_rid = 0xc1, + }, + { + .slave_id = SHDMA_SLAVE_RSPI_RX, + .addr = 0xfe480004, + .chcr = DM_INC | 0x800 | 0x40000000 | + TS_INDEX2VAL(XMIT_SZ_16BIT), + .mid_rid = 0xc2, + }, }; static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = { diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 7b57bf1..ebe7a7d 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -273,7 +273,7 @@ void __init setup_arch(char **cmdline_p) data_resource.start = virt_to_phys(_etext); data_resource.end = virt_to_phys(_edata)-1; bss_resource.start = virt_to_phys(__bss_start); - bss_resource.end = virt_to_phys(_ebss)-1; + bss_resource.end = virt_to_phys(__bss_stop)-1; #ifdef CONFIG_CMDLINE_OVERWRITE strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 3896f26..2a0a596 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c @@ -19,7 +19,6 @@ EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(_ebss); EXPORT_SYMBOL(empty_zero_page); #define DECLARE_EXPORT(name) \ diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index c98905f..db88cbf 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -78,7 +78,6 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_end = .; BSS_SECTION(0, PAGE_SIZE, 4) - _ebss = .; /* uClinux MTD sucks */ _end = . ; STABS_DEBUG diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S index 84a5776..60164e6 100644 --- a/arch/sh/lib/mcount.S +++ b/arch/sh/lib/mcount.S @@ -39,7 +39,7 @@ * * Make sure the stack pointer contains a valid address. Valid * addresses for kernel stacks are anywhere after the bss - * (after _ebss) and anywhere in init_thread_union (init_stack). + * (after __bss_stop) and anywhere in init_thread_union (init_stack). */ #define STACK_CHECK() \ mov #(THREAD_SIZE >> 10), r0; \ @@ -60,7 +60,7 @@ cmp/hi r2, r1; \ bf stack_panic; \ \ - /* If sp > _ebss then we're OK. */ \ + /* If sp > __bss_stop then we're OK. */ \ mov.l .L_ebss, r1; \ cmp/hi r1, r15; \ bt 1f; \ @@ -70,7 +70,7 @@ cmp/hs r1, r15; \ bf stack_panic; \ \ - /* If sp > init_stack && sp < _ebss, not OK. */ \ + /* If sp > init_stack && sp < __bss_stop, not OK. */ \ add r0, r1; \ cmp/hs r1, r15; \ bt stack_panic; \ @@ -292,8 +292,6 @@ stack_panic: nop .align 2 -.L_ebss: - .long _ebss .L_init_thread_union: .long init_thread_union .Lpanic: diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 1fc25d8..3bdc1ad 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -58,11 +58,15 @@ static void show_pte(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; - if (mm) + if (mm) { pgd = mm->pgd; - else + } else { pgd = get_TTB(); + if (unlikely(!pgd)) + pgd = swapper_pg_dir; + } + printk(KERN_ALERT "pgd = %p\n", pgd); pgd += pgd_index(addr); printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr, diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ba2657c..8ec3a1a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1527,7 +1527,7 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. config CC_STACKPROTECTOR - bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" + bool "Enable -fstack-protector buffer overflow detection" ---help--- This option turns on the -fstack-protector GCC feature. This feature puts, at the beginning of functions, a canary value on diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 441520e..a3ac52b 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -33,6 +33,14 @@ #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ #define MCI_STATUS_AR (1ULL<<55) /* Action required */ +#define MCACOD 0xffff /* MCA Error Code */ + +/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ +#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ +#define MCACOD_SCRUBMSK 0xfff0 +#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ +#define MCACOD_DATA 0x0134 /* Data Load */ +#define MCACOD_INSTR 0x0150 /* Instruction Fetch */ /* MCi_MISC register defines */ #define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f) diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h index 87bdbca..72f9adf6 100644 --- a/arch/x86/include/asm/olpc.h +++ b/arch/x86/include/asm/olpc.h @@ -100,25 +100,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value); extern int pci_olpc_init(void); -/* EC related functions */ - -extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, - unsigned char *outbuf, size_t outlen); - -/* EC commands */ - -#define EC_FIRMWARE_REV 0x08 -#define EC_WRITE_SCI_MASK 0x1b -#define EC_WAKE_UP_WLAN 0x24 -#define EC_WLAN_LEAVE_RESET 0x25 -#define EC_READ_EB_MODE 0x2a -#define EC_SET_SCI_INHIBIT 0x32 -#define EC_SET_SCI_INHIBIT_RELEASE 0x34 -#define EC_WLAN_ENTER_RESET 0x35 -#define EC_WRITE_EXT_SCI_MASK 0x38 -#define EC_SCI_QUERY 0x84 -#define EC_EXT_SCI_QUERY 0x85 - /* SCI source values */ #define EC_SCI_SRC_EMPTY 0x00 diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index dab3935..cb4e43b 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -196,11 +196,16 @@ static inline u32 get_ibs_caps(void) { return 0; } extern void perf_events_lapic_init(void); /* - * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups. - * This flag is otherwise unused and ABI specified to be 0, so nobody should - * care what we do with it. + * Abuse bits {3,5} of the cpu eflags register. These flags are otherwise + * unused and ABI specified to be 0, so nobody should care what we do with + * them. + * + * EXACT - the IP points to the exact instruction that triggered the + * event (HW bugs exempt). + * VM - original X86_VM_MASK; see set_linear_ip(). */ #define PERF_EFLAGS_EXACT (1UL << 3) +#define PERF_EFLAGS_VM (1UL << 5) struct pt_regs; extern unsigned long perf_instruction_pointer(struct pt_regs *regs); diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 95bf99d..1b8e5a0 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -25,10 +25,6 @@ unsigned long acpi_realmode_flags; static char temp_stack[4096]; #endif -asmlinkage void acpi_enter_s3(void) -{ - acpi_enter_sleep_state(3, wake_sleep_flags); -} /** * acpi_suspend_lowlevel - save kernel state * diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h index 5653a57..67f59f8 100644 --- a/arch/x86/kernel/acpi/sleep.h +++ b/arch/x86/kernel/acpi/sleep.h @@ -2,7 +2,6 @@ * Variables and functions used by the code in sleep.c */ -#include <linux/linkage.h> #include <asm/realmode.h> extern unsigned long saved_video_mode; @@ -11,7 +10,6 @@ extern long saved_magic; extern int wakeup_pmode_return; extern u8 wake_sleep_flags; -extern asmlinkage void acpi_enter_s3(void); extern unsigned long acpi_copy_wakeup_routine(unsigned long); extern void wakeup_long64(void); diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index 7261083..13ab7205 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S @@ -74,7 +74,9 @@ restore_registers: ENTRY(do_suspend_lowlevel) call save_processor_state call save_registers - call acpi_enter_s3 + pushl $3 + call acpi_enter_sleep_state + addl $4, %esp # In case of S3 failure, we'll emerge here. Jump # to ret_point to recover diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 014d1d2..8ea5164 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -71,7 +71,9 @@ ENTRY(do_suspend_lowlevel) movq %rsi, saved_rsi addq $8, %rsp - call acpi_enter_s3 + movl $3, %edi + xorl %eax, %eax + call acpi_enter_sleep_state /* in case something went wrong, restore the machine status and go on */ jmp resume_point diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 931280f..afb7ff7 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -224,7 +224,7 @@ void __init arch_init_ideal_nops(void) ideal_nops = intel_nops; #endif } - + break; default: #ifdef CONFIG_X86_64 ideal_nops = k8_nops; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 406eee7..a6c64aa 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1204,7 +1204,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) BUG_ON(!cfg->vector); vector = cfg->vector; - for_each_cpu(cpu, cfg->domain) + for_each_cpu_and(cpu, cfg->domain, cpu_online_mask) per_cpu(vector_irq, cpu)[vector] = -1; cfg->vector = 0; @@ -1212,7 +1212,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) if (likely(!cfg->move_in_progress)) return; - for_each_cpu(cpu, cfg->old_domain) { + for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) { for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { if (per_cpu(vector_irq, cpu)[vector] != irq) diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 413c2ce..1301762 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -55,13 +55,6 @@ static struct severity { #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) #define MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV) -#define MCACOD 0xffff -/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ -#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ -#define MCACOD_SCRUBMSK 0xfff0 -#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ -#define MCACOD_DATA 0x0134 /* Data Load */ -#define MCACOD_INSTR 0x0150 /* Instruction Fetch */ MCESEV( NO, "Invalid", diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 5e095f8..292d025 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -103,6 +103,8 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { static DEFINE_PER_CPU(struct work_struct, mce_work); +static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs); + /* * CPU/chipset specific EDAC code can register a notifier call here to print * MCE errors in a human-readable form. @@ -650,14 +652,18 @@ EXPORT_SYMBOL_GPL(machine_check_poll); * Do a quick check if any of the events requires a panic. * This decides if we keep the events around or clear them. */ -static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp) +static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp, + struct pt_regs *regs) { int i, ret = 0; for (i = 0; i < banks; i++) { m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i)); - if (m->status & MCI_STATUS_VAL) + if (m->status & MCI_STATUS_VAL) { __set_bit(i, validp); + if (quirk_no_way_out) + quirk_no_way_out(i, m, regs); + } if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY) ret = 1; } @@ -1040,7 +1046,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) *final = m; memset(valid_banks, 0, sizeof(valid_banks)); - no_way_out = mce_no_way_out(&m, &msg, valid_banks); + no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs); barrier(); @@ -1418,6 +1424,34 @@ static void __mcheck_cpu_init_generic(void) } } +/* + * During IFU recovery Sandy Bridge -EP4S processors set the RIPV and + * EIPV bits in MCG_STATUS to zero on the affected logical processor (SDM + * Vol 3B Table 15-20). But this confuses both the code that determines + * whether the machine check occurred in kernel or user mode, and also + * the severity assessment code. Pretend that EIPV was set, and take the + * ip/cs values from the pt_regs that mce_gather_info() ignored earlier. + */ +static void quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs) +{ + if (bank != 0) + return; + if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0) + return; + if ((m->status & (MCI_STATUS_OVER|MCI_STATUS_UC| + MCI_STATUS_EN|MCI_STATUS_MISCV|MCI_STATUS_ADDRV| + MCI_STATUS_PCC|MCI_STATUS_S|MCI_STATUS_AR| + MCACOD)) != + (MCI_STATUS_UC|MCI_STATUS_EN| + MCI_STATUS_MISCV|MCI_STATUS_ADDRV|MCI_STATUS_S| + MCI_STATUS_AR|MCACOD_INSTR)) + return; + + m->mcgstatus |= MCG_STATUS_EIPV; + m->ip = regs->ip; + m->cs = regs->cs; +} + /* Add per CPU specific workarounds here */ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) { @@ -1515,6 +1549,9 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) */ if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0) mce_bootlog = 0; + + if (c->x86 == 6 && c->x86_model == 45) + quirk_no_way_out = quirk_sandybridge_ifu; } if (monarch_timeout < 0) monarch_timeout = 0; diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 29557aa..915b876 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -32,6 +32,8 @@ #include <asm/smp.h> #include <asm/alternative.h> #include <asm/timer.h> +#include <asm/desc.h> +#include <asm/ldt.h> #include "perf_event.h" @@ -1738,6 +1740,29 @@ valid_user_frame(const void __user *fp, unsigned long size) return (__range_not_ok(fp, size, TASK_SIZE) == 0); } +static unsigned long get_segment_base(unsigned int segment) +{ + struct desc_struct *desc; + int idx = segment >> 3; + + if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) { + if (idx > LDT_ENTRIES) + return 0; + + if (idx > current->active_mm->context.size) + return 0; + + desc = current->active_mm->context.ldt; + } else { + if (idx > GDT_ENTRIES) + return 0; + + desc = __this_cpu_ptr(&gdt_page.gdt[0]); + } + + return get_desc_base(desc + idx); +} + #ifdef CONFIG_COMPAT #include <asm/compat.h> @@ -1746,13 +1771,17 @@ static inline int perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) { /* 32-bit process in 64-bit kernel. */ + unsigned long ss_base, cs_base; struct stack_frame_ia32 frame; const void __user *fp; if (!test_thread_flag(TIF_IA32)) return 0; - fp = compat_ptr(regs->bp); + cs_base = get_segment_base(regs->cs); + ss_base = get_segment_base(regs->ss); + + fp = compat_ptr(ss_base + regs->bp); while (entry->nr < PERF_MAX_STACK_DEPTH) { unsigned long bytes; frame.next_frame = 0; @@ -1765,8 +1794,8 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) if (!valid_user_frame(fp, sizeof(frame))) break; - perf_callchain_store(entry, frame.return_address); - fp = compat_ptr(frame.next_frame); + perf_callchain_store(entry, cs_base + frame.return_address); + fp = compat_ptr(ss_base + frame.next_frame); } return 1; } @@ -1789,6 +1818,12 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) return; } + /* + * We don't know what to do with VM86 stacks.. ignore them for now. + */ + if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM)) + return; + fp = (void __user *)regs->bp; perf_callchain_store(entry, regs->ip); @@ -1816,16 +1851,50 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) } } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +/* + * Deal with code segment offsets for the various execution modes: + * + * VM86 - the good olde 16 bit days, where the linear address is + * 20 bits and we use regs->ip + 0x10 * regs->cs. + * + * IA32 - Where we need to look at GDT/LDT segment descriptor tables + * to figure out what the 32bit base address is. + * + * X32 - has TIF_X32 set, but is running in x86_64 + * + * X86_64 - CS,DS,SS,ES are all zero based. + */ +static unsigned long code_segment_base(struct pt_regs *regs) { - unsigned long ip; + /* + * If we are in VM86 mode, add the segment offset to convert to a + * linear address. + */ + if (regs->flags & X86_VM_MASK) + return 0x10 * regs->cs; + + /* + * For IA32 we look at the GDT/LDT segment base to convert the + * effective IP to a linear address. + */ +#ifdef CONFIG_X86_32 + if (user_mode(regs) && regs->cs != __USER_CS) + return get_segment_base(regs->cs); +#else + if (test_thread_flag(TIF_IA32)) { + if (user_mode(regs) && regs->cs != __USER32_CS) + return get_segment_base(regs->cs); + } +#endif + return 0; +} +unsigned long perf_instruction_pointer(struct pt_regs *regs) +{ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - ip = perf_guest_cbs->get_guest_ip(); - else - ip = instruction_pointer(regs); + return perf_guest_cbs->get_guest_ip(); - return ip; + return regs->ip + code_segment_base(regs); } unsigned long perf_misc_flags(struct pt_regs *regs) @@ -1838,7 +1907,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs) else misc |= PERF_RECORD_MISC_GUEST_KERNEL; } else { - if (!kernel_ip(regs->ip)) + if (user_mode(regs)) misc |= PERF_RECORD_MISC_USER; else misc |= PERF_RECORD_MISC_KERNEL; diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 821d53b..6605a81 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -516,6 +516,26 @@ static inline bool kernel_ip(unsigned long ip) #endif } +/* + * Not all PMUs provide the right context information to place the reported IP + * into full context. Specifically segment registers are typically not + * supplied. + * + * Assuming the address is a linear address (it is for IBS), we fake the CS and + * vm86 mode using the known zero-based code segment and 'fix up' the registers + * to reflect this. + * + * Intel PEBS/LBR appear to typically provide the effective address, nothing + * much we can do about that but pray and treat it like a linear address. + */ +static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip) +{ + regs->cs = kernel_ip(ip) ? __KERNEL_CS : __USER_CS; + if (regs->flags & X86_VM_MASK) + regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK); + regs->ip = ip; +} + #ifdef CONFIG_CPU_SUP_AMD int amd_pmu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c index da9bcdc..7bfb5be 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c +++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c @@ -13,6 +13,8 @@ #include <asm/apic.h> +#include "perf_event.h" + static u32 ibs_caps; #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) @@ -536,7 +538,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) { regs.flags &= ~PERF_EFLAGS_EXACT; } else { - instruction_pointer_set(®s, ibs_data.regs[1]); + set_linear_ip(®s, ibs_data.regs[1]); regs.flags |= PERF_EFLAGS_EXACT; } diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 629ae0b..e38d97b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -499,7 +499,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) * We sampled a branch insn, rewind using the LBR stack */ if (ip == to) { - regs->ip = from; + set_linear_ip(regs, from); return 1; } @@ -529,7 +529,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) } while (to < ip); if (to == ip) { - regs->ip = old_to; + set_linear_ip(regs, old_to); return 1; } @@ -569,7 +569,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event, * A possible PERF_SAMPLE_REGS will have to transfer all regs. */ regs = *iregs; - regs.ip = pebs->ip; + regs.flags = pebs->flags; + set_linear_ip(®s, pebs->ip); regs.bp = pebs->bp; regs.sp = pebs->sp; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index f385189..c9e5dc5 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -5,7 +5,7 @@ #include "perf_event.h" #define UNCORE_PMU_NAME_LEN 32 -#define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC) +#define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC) #define UNCORE_FIXED_EVENT 0xff #define UNCORE_PMC_IDX_MAX_GENERIC 8 diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 1f5f1d5..7ad683d 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -328,6 +328,7 @@ void fixup_irqs(void) chip->irq_retrigger(data); raw_spin_unlock(&desc->lock); } + __this_cpu_write(vector_irq[vector], -1); } } #endif diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c index 1d5d31e..dc1404b 100644 --- a/arch/x86/kernel/kdebugfs.c +++ b/arch/x86/kernel/kdebugfs.c @@ -107,7 +107,7 @@ static int __init create_setup_data_nodes(struct dentry *parent) { struct setup_data_node *node; struct setup_data *data; - int error = -ENOMEM; + int error; struct dentry *d; struct page *pg; u64 pa_data; @@ -121,8 +121,10 @@ static int __init create_setup_data_nodes(struct dentry *parent) while (pa_data) { node = kmalloc(sizeof(*node), GFP_KERNEL); - if (!node) + if (!node) { + error = -ENOMEM; goto err_dir; + } pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT); if (PageHighMem(pg)) { diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 1df8fb9..e498b18 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -316,6 +316,11 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) addr &= 1; if (addr == 0) { if (val & 0x10) { + u8 edge_irr = s->irr & ~s->elcr; + int i; + bool found; + struct kvm_vcpu *vcpu; + s->init4 = val & 1; s->last_irr = 0; s->irr &= s->elcr; @@ -333,6 +338,18 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) if (val & 0x08) pr_pic_unimpl( "level sensitive irq not supported"); + + kvm_for_each_vcpu(i, vcpu, s->pics_state->kvm) + if (kvm_apic_accept_pic_intr(vcpu)) { + found = true; + break; + } + + + if (found) + for (irq = 0; irq < PIC_NUM_PINS/2; irq++) + if (edge_irr & (1 << irq)) + pic_clear_isr(s, irq); } else if (val & 0x08) { if (val & 0x04) s->poll = 1; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c39b607..c00f03d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1488,13 +1488,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) loadsegment(ds, vmx->host_state.ds_sel); loadsegment(es, vmx->host_state.es_sel); } -#else - /* - * The sysexit path does not restore ds/es, so we must set them to - * a reasonable value ourselves. - */ - loadsegment(ds, __USER_DS); - loadsegment(es, __USER_DS); #endif reload_tss(); #ifdef CONFIG_X86_64 @@ -6370,6 +6363,19 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) #endif ); +#ifndef CONFIG_X86_64 + /* + * The sysexit path does not restore ds/es, so we must set them to + * a reasonable value ourselves. + * + * We can't defer this to vmx_load_host_state() since that function + * may be executed in interrupt context, which saves and restore segments + * around it, nullifying its effect. + */ + loadsegment(ds, __USER_DS); + loadsegment(es, __USER_DS); +#endif + vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) | (1 << VCPU_EXREG_RFLAGS) | (1 << VCPU_EXREG_CPL) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 59b5950..42bce48 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -925,6 +925,10 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock) */ getboottime(&boot); + if (kvm->arch.kvmclock_offset) { + struct timespec ts = ns_to_timespec(kvm->arch.kvmclock_offset); + boot = timespec_sub(boot, ts); + } wc.sec = boot.tv_sec; wc.nsec = boot.tv_nsec; wc.version = version; diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index 4599c3e..4ddf497 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -142,23 +142,23 @@ static inline int save_add_info(void) {return 0;} #endif /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ -void __init +int __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { u64 start, end; int node, pxm; if (srat_disabled()) - return; + return -1; if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { bad_srat(); - return; + return -1; } if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) - return; + return -1; if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) - return; + return -1; start = ma->base_address; end = start + ma->length; pxm = ma->proximity_domain; @@ -168,12 +168,12 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains.\n"); bad_srat(); - return; + return -1; } if (numa_add_memblk(node, start, end) < 0) { bad_srat(); - return; + return -1; } node_set(node, numa_nodes_parsed); @@ -181,6 +181,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", node, pxm, (unsigned long long) start, (unsigned long long) end - 1); + return 0; } void __init acpi_numa_arch_fixup(void) {} diff --git a/arch/x86/platform/olpc/olpc-xo1-pm.c b/arch/x86/platform/olpc/olpc-xo1-pm.c index 0ce8616c..d75582d 100644 --- a/arch/x86/platform/olpc/olpc-xo1-pm.c +++ b/arch/x86/platform/olpc/olpc-xo1-pm.c @@ -18,6 +18,7 @@ #include <linux/pm.h> #include <linux/mfd/core.h> #include <linux/suspend.h> +#include <linux/olpc-ec.h> #include <asm/io.h> #include <asm/olpc.h> @@ -51,16 +52,11 @@ EXPORT_SYMBOL_GPL(olpc_xo1_pm_wakeup_clear); static int xo1_power_state_enter(suspend_state_t pm_state) { unsigned long saved_sci_mask; - int r; /* Only STR is supported */ if (pm_state != PM_SUSPEND_MEM) return -EINVAL; - r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0); - if (r) - return r; - /* * Save SCI mask (this gets lost since PM1_EN is used as a mask for * wakeup events, which is not necessarily the same event set) @@ -76,16 +72,6 @@ static int xo1_power_state_enter(suspend_state_t pm_state) /* Restore SCI mask (using dword access to CS5536_PM1_EN) */ outl(saved_sci_mask, acpi_base + CS5536_PM1_STS); - /* Tell the EC to stop inhibiting SCIs */ - olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0); - - /* - * Tell the wireless module to restart USB communication. - * Must be done twice. - */ - olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); - olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); - return 0; } diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c index 04b8c73..63d4aa4 100644 --- a/arch/x86/platform/olpc/olpc-xo1-sci.c +++ b/arch/x86/platform/olpc/olpc-xo1-sci.c @@ -23,6 +23,7 @@ #include <linux/power_supply.h> #include <linux/suspend.h> #include <linux/workqueue.h> +#include <linux/olpc-ec.h> #include <asm/io.h> #include <asm/msr.h> diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index 599be49..2fdca25 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/power_supply.h> +#include <linux/olpc-ec.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c index a4bee53..2737608 100644 --- a/arch/x86/platform/olpc/olpc.c +++ b/arch/x86/platform/olpc/olpc.c @@ -14,14 +14,13 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/spinlock.h> #include <linux/io.h> #include <linux/string.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/syscore_ops.h> -#include <linux/debugfs.h> #include <linux/mutex.h> +#include <linux/olpc-ec.h> #include <asm/geode.h> #include <asm/setup.h> @@ -31,17 +30,6 @@ struct olpc_platform_t olpc_platform_info; EXPORT_SYMBOL_GPL(olpc_platform_info); -static DEFINE_SPINLOCK(ec_lock); - -/* debugfs interface to EC commands */ -#define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */ -#define EC_MAX_CMD_REPLY (8) - -static struct dentry *ec_debugfs_dir; -static DEFINE_MUTEX(ec_debugfs_cmd_lock); -static unsigned char ec_debugfs_resp[EC_MAX_CMD_REPLY]; -static unsigned int ec_debugfs_resp_bytes; - /* EC event mask to be applied during suspend (defining wakeup sources). */ static u16 ec_wakeup_mask; @@ -125,16 +113,13 @@ static int __wait_on_obf(unsigned int line, unsigned int port, int desired) * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while * OpenFirmware's source is available, the EC's is not. */ -int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, - unsigned char *outbuf, size_t outlen) +static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, + size_t outlen, void *arg) { - unsigned long flags; int ret = -EIO; int i; int restarts = 0; - spin_lock_irqsave(&ec_lock, flags); - /* Clear OBF */ for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++) inb(0x68); @@ -198,10 +183,8 @@ restart: ret = 0; err: - spin_unlock_irqrestore(&ec_lock, flags); return ret; } -EXPORT_SYMBOL_GPL(olpc_ec_cmd); void olpc_ec_wakeup_set(u16 value) { @@ -280,96 +263,6 @@ int olpc_ec_sci_query(u16 *sci_value) } EXPORT_SYMBOL_GPL(olpc_ec_sci_query); -static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf, - size_t size, loff_t *ppos) -{ - int i, m; - unsigned char ec_cmd[EC_MAX_CMD_ARGS]; - unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; - char cmdbuf[64]; - int ec_cmd_bytes; - - mutex_lock(&ec_debugfs_cmd_lock); - - size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size); - - m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0], - &ec_debugfs_resp_bytes, - &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3], - &ec_cmd_int[4], &ec_cmd_int[5]); - if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) { - /* reset to prevent overflow on read */ - ec_debugfs_resp_bytes = 0; - - printk(KERN_DEBUG "olpc-ec: bad ec cmd: " - "cmd:response-count [arg1 [arg2 ...]]\n"); - size = -EINVAL; - goto out; - } - - /* convert scanf'd ints to char */ - ec_cmd_bytes = m - 2; - for (i = 0; i <= ec_cmd_bytes; i++) - ec_cmd[i] = ec_cmd_int[i]; - - printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args " - "%02x %02x %02x %02x %02x, want %d returns\n", - ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3], - ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes); - - olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], - ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes); - - printk(KERN_DEBUG "olpc-ec: response " - "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n", - ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2], - ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5], - ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes); - -out: - mutex_unlock(&ec_debugfs_cmd_lock); - return size; -} - -static ssize_t ec_debugfs_cmd_read(struct file *file, char __user *buf, - size_t size, loff_t *ppos) -{ - unsigned int i, r; - char *rp; - char respbuf[64]; - - mutex_lock(&ec_debugfs_cmd_lock); - rp = respbuf; - rp += sprintf(rp, "%02x", ec_debugfs_resp[0]); - for (i = 1; i < ec_debugfs_resp_bytes; i++) - rp += sprintf(rp, ", %02x", ec_debugfs_resp[i]); - mutex_unlock(&ec_debugfs_cmd_lock); - rp += sprintf(rp, "\n"); - - r = rp - respbuf; - return simple_read_from_buffer(buf, size, ppos, respbuf, r); -} - -static const struct file_operations ec_debugfs_genops = { - .write = ec_debugfs_cmd_write, - .read = ec_debugfs_cmd_read, -}; - -static void setup_debugfs(void) -{ - ec_debugfs_dir = debugfs_create_dir("olpc-ec", 0); - if (ec_debugfs_dir == ERR_PTR(-ENODEV)) - return; - - debugfs_create_file("cmd", 0600, ec_debugfs_dir, NULL, - &ec_debugfs_genops); -} - -static int olpc_ec_suspend(void) -{ - return olpc_ec_mask_write(ec_wakeup_mask); -} - static bool __init check_ofw_architecture(struct device_node *root) { const char *olpc_arch; @@ -424,8 +317,59 @@ static int __init add_xo1_platform_devices(void) return 0; } -static struct syscore_ops olpc_syscore_ops = { - .suspend = olpc_ec_suspend, +static int olpc_xo1_ec_probe(struct platform_device *pdev) +{ + /* get the EC revision */ + olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, + (unsigned char *) &olpc_platform_info.ecver, 1); + + /* EC version 0x5f adds support for wide SCI mask */ + if (olpc_platform_info.ecver >= 0x5f) + olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI; + + pr_info("OLPC board revision %s%X (EC=%x)\n", + ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", + olpc_platform_info.boardrev >> 4, + olpc_platform_info.ecver); + + return 0; +} +static int olpc_xo1_ec_suspend(struct platform_device *pdev) +{ + olpc_ec_mask_write(ec_wakeup_mask); + + /* + * Squelch SCIs while suspended. This is a fix for + * <http://dev.laptop.org/ticket/1835>. + */ + return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0); +} + +static int olpc_xo1_ec_resume(struct platform_device *pdev) +{ + /* Tell the EC to stop inhibiting SCIs */ + olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0); + + /* + * Tell the wireless module to restart USB communication. + * Must be done twice. + */ + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); + + return 0; +} + +static struct olpc_ec_driver ec_xo1_driver = { + .probe = olpc_xo1_ec_probe, + .suspend = olpc_xo1_ec_suspend, + .resume = olpc_xo1_ec_resume, + .ec_cmd = olpc_xo1_ec_cmd, +}; + +static struct olpc_ec_driver ec_xo1_5_driver = { + .probe = olpc_xo1_ec_probe, + .ec_cmd = olpc_xo1_ec_cmd, }; static int __init olpc_init(void) @@ -435,16 +379,17 @@ static int __init olpc_init(void) if (!olpc_ofw_present() || !platform_detect()) return 0; - spin_lock_init(&ec_lock); + /* register the XO-1 and 1.5-specific EC handler */ + if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */ + olpc_ec_driver_register(&ec_xo1_driver, NULL); + else + olpc_ec_driver_register(&ec_xo1_5_driver, NULL); + platform_device_register_simple("olpc-ec", -1, NULL, 0); /* assume B1 and above models always have a DCON */ if (olpc_board_at_least(olpc_board(0xb1))) olpc_platform_info.flags |= OLPC_F_DCON; - /* get the EC revision */ - olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, - (unsigned char *) &olpc_platform_info.ecver, 1); - #ifdef CONFIG_PCI_OLPC /* If the VSA exists let it emulate PCI, if not emulate in kernel. * XO-1 only. */ @@ -452,14 +397,6 @@ static int __init olpc_init(void) !cs5535_has_vsa2()) x86_init.pci.arch_init = pci_olpc_init; #endif - /* EC version 0x5f adds support for wide SCI mask */ - if (olpc_platform_info.ecver >= 0x5f) - olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI; - - printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", - ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", - olpc_platform_info.boardrev >> 4, - olpc_platform_info.ecver); if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */ r = add_xo1_platform_devices(); @@ -467,9 +404,6 @@ static int __init olpc_init(void) return r; } - register_syscore_ops(&olpc_syscore_ops); - setup_debugfs(); - return 0; } diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index 51171ae..29aed7a 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl @@ -318,7 +318,7 @@ 309 common getcpu sys_getcpu 310 64 process_vm_readv sys_process_vm_readv 311 64 process_vm_writev sys_process_vm_writev -312 64 kcmp sys_kcmp +312 common kcmp sys_kcmp # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 5ccb99a..5de4ec7 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -83,22 +83,22 @@ acpi_status acpi_hw_clear_acpi_status(void); /* * hwsleep - sleep/wake support (Legacy sleep registers) */ -acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags); +acpi_status acpi_hw_legacy_sleep(u8 sleep_state); -acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags); +acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state); -acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags); +acpi_status acpi_hw_legacy_wake(u8 sleep_state); /* * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers) */ void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument); -acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags); +acpi_status acpi_hw_extended_sleep(u8 sleep_state); -acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags); +acpi_status acpi_hw_extended_wake_prep(u8 sleep_state); -acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags); +acpi_status acpi_hw_extended_wake(u8 sleep_state); /* * hwvalid - Port I/O with validation diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 48518da..94996f9 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -90,7 +90,6 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) * FUNCTION: acpi_hw_extended_sleep * * PARAMETERS: sleep_state - Which sleep state to enter - * flags - ACPI_EXECUTE_GTS to run optional method * * RETURN: Status * @@ -100,7 +99,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) * ******************************************************************************/ -acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags) +acpi_status acpi_hw_extended_sleep(u8 sleep_state) { acpi_status status; u8 sleep_type_value; @@ -125,12 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags) acpi_gbl_system_awake_and_running = FALSE; - /* Optionally execute _GTS (Going To Sleep) */ - - if (flags & ACPI_EXECUTE_GTS) { - acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state); - } - /* Flush caches, as per ACPI specification */ ACPI_FLUSH_CPU_CACHE(); @@ -172,7 +165,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags) * FUNCTION: acpi_hw_extended_wake_prep * * PARAMETERS: sleep_state - Which sleep state we just exited - * flags - ACPI_EXECUTE_BFS to run optional method * * RETURN: Status * @@ -181,7 +173,7 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags) * ******************************************************************************/ -acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags) +acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) { acpi_status status; u8 sleep_type_value; @@ -200,11 +192,6 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags) &acpi_gbl_FADT.sleep_control); } - /* Optionally execute _BFS (Back From Sleep) */ - - if (flags & ACPI_EXECUTE_BFS) { - acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state); - } return_ACPI_STATUS(AE_OK); } @@ -222,7 +209,7 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags) * ******************************************************************************/ -acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags) +acpi_status acpi_hw_extended_wake(u8 sleep_state) { ACPI_FUNCTION_TRACE(hw_extended_wake); diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 9960fe9..3fddde0 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -56,7 +56,6 @@ ACPI_MODULE_NAME("hwsleep") * FUNCTION: acpi_hw_legacy_sleep * * PARAMETERS: sleep_state - Which sleep state to enter - * flags - ACPI_EXECUTE_GTS to run optional method * * RETURN: Status * @@ -64,7 +63,7 @@ ACPI_MODULE_NAME("hwsleep") * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ -acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) +acpi_status acpi_hw_legacy_sleep(u8 sleep_state) { struct acpi_bit_register_info *sleep_type_reg_info; struct acpi_bit_register_info *sleep_enable_reg_info; @@ -110,12 +109,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) return_ACPI_STATUS(status); } - /* Optionally execute _GTS (Going To Sleep) */ - - if (flags & ACPI_EXECUTE_GTS) { - acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state); - } - /* Get current value of PM1A control */ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, @@ -214,7 +207,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) * FUNCTION: acpi_hw_legacy_wake_prep * * PARAMETERS: sleep_state - Which sleep state we just exited - * flags - ACPI_EXECUTE_BFS to run optional method * * RETURN: Status * @@ -224,7 +216,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) * ******************************************************************************/ -acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags) +acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) { acpi_status status; struct acpi_bit_register_info *sleep_type_reg_info; @@ -275,11 +267,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags) } } - /* Optionally execute _BFS (Back From Sleep) */ - - if (flags & ACPI_EXECUTE_BFS) { - acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state); - } return_ACPI_STATUS(status); } @@ -288,7 +275,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags) * FUNCTION: acpi_hw_legacy_wake * * PARAMETERS: sleep_state - Which sleep state we just exited - * flags - Reserved, set to zero * * RETURN: Status * @@ -297,7 +283,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags) * ******************************************************************************/ -acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags) +acpi_status acpi_hw_legacy_wake(u8 sleep_state) { acpi_status status; diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index f8684bf..1f165a7 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -50,7 +50,7 @@ ACPI_MODULE_NAME("hwxfsleep") /* Local prototypes */ static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id); +acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* * Dispatch table used to efficiently branch to the various sleep @@ -235,7 +235,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) * ******************************************************************************/ static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id) +acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) { acpi_status status; struct acpi_sleep_functions *sleep_functions = @@ -248,11 +248,11 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id) * use the extended sleep registers */ if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) { - status = sleep_functions->extended_function(sleep_state, flags); + status = sleep_functions->extended_function(sleep_state); } else { /* Legacy sleep */ - status = sleep_functions->legacy_function(sleep_state, flags); + status = sleep_functions->legacy_function(sleep_state); } return (status); @@ -262,7 +262,7 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id) * For the case where reduced-hardware-only code is being generated, * we know that only the extended sleep registers are available */ - status = sleep_functions->extended_function(sleep_state, flags); + status = sleep_functions->extended_function(sleep_state); return (status); #endif /* !ACPI_REDUCED_HARDWARE */ @@ -349,7 +349,6 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) * FUNCTION: acpi_enter_sleep_state * * PARAMETERS: sleep_state - Which sleep state to enter - * flags - ACPI_EXECUTE_GTS to run optional method * * RETURN: Status * @@ -357,7 +356,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ -acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags) +acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) { acpi_status status; @@ -371,7 +370,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags) } status = - acpi_hw_sleep_dispatch(sleep_state, flags, ACPI_SLEEP_FUNCTION_ID); + acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); return_ACPI_STATUS(status); } @@ -391,14 +390,14 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) * Called with interrupts DISABLED. * ******************************************************************************/ -acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags) +acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) { acpi_status status; ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); status = - acpi_hw_sleep_dispatch(sleep_state, flags, + acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID); return_ACPI_STATUS(status); } @@ -423,8 +422,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); - - status = acpi_hw_sleep_dispatch(sleep_state, 0, ACPI_WAKE_FUNCTION_ID); + status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index e56f3be..cb31298 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -237,6 +237,8 @@ acpi_parse_processor_affinity(struct acpi_subtable_header *header, return 0; } +static int __initdata parsed_numa_memblks; + static int __init acpi_parse_memory_affinity(struct acpi_subtable_header * header, const unsigned long end) @@ -250,8 +252,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, acpi_table_print_srat_entry(header); /* let architecture-dependent part to do it */ - acpi_numa_memory_affinity_init(memory_affinity); - + if (!acpi_numa_memory_affinity_init(memory_affinity)) + parsed_numa_memblks++; return 0; } @@ -304,8 +306,10 @@ int __init acpi_numa_init(void) acpi_numa_arch_fixup(); - if (cnt <= 0) - return cnt ?: -ENOENT; + if (cnt < 0) + return cnt; + else if (!parsed_numa_memblks) + return -ENOENT; return 0; } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ec54014c..72a2c98 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -573,8 +573,15 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) OSC_CLOCK_PWR_CAPABILITY_SUPPORT; if (pci_msi_enabled()) flags |= OSC_MSI_SUPPORT; - if (flags != base_flags) - acpi_pci_osc_support(root, flags); + if (flags != base_flags) { + status = acpi_pci_osc_support(root, flags); + if (ACPI_FAILURE(status)) { + dev_info(root->bus->bridge, "ACPI _OSC support " + "notification failed, disabling PCIe ASPM\n"); + pcie_no_aspm(); + flags = base_flags; + } + } if (!pcie_ports_disabled && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index ff8e04f..bfc31cb 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -437,7 +437,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, /* Normal CPU soft online event */ } else { acpi_processor_ppc_has_changed(pr, 0); - acpi_processor_cst_has_changed(pr); + acpi_processor_hotplug(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 7a7a9c9..fdcdbb6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -28,36 +28,7 @@ #include "internal.h" #include "sleep.h" -u8 wake_sleep_flags = ACPI_NO_OPTIONAL_METHODS; -static unsigned int gts, bfs; -static int set_param_wake_flag(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - - if (ret) - return ret; - - if (kp->arg == (const char *)>s) { - if (gts) - wake_sleep_flags |= ACPI_EXECUTE_GTS; - else - wake_sleep_flags &= ~ACPI_EXECUTE_GTS; - } - if (kp->arg == (const char *)&bfs) { - if (bfs) - wake_sleep_flags |= ACPI_EXECUTE_BFS; - else - wake_sleep_flags &= ~ACPI_EXECUTE_BFS; - } - return ret; -} -module_param_call(gts, set_param_wake_flag, param_get_int, >s, 0644); -module_param_call(bfs, set_param_wake_flag, param_get_int, &bfs, 0644); -MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); -MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); - static u8 sleep_states[ACPI_S_STATE_COUNT]; -static bool pwr_btn_event_pending; static void acpi_sleep_tts_switch(u32 acpi_state) { @@ -110,6 +81,7 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; +static bool pwr_btn_event_pending; /* * The ACPI specification wants us to save NVS memory regions during hibernation @@ -305,7 +277,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) switch (acpi_state) { case ACPI_STATE_S1: barrier(); - status = acpi_enter_sleep_state(acpi_state, wake_sleep_flags); + status = acpi_enter_sleep_state(acpi_state); break; case ACPI_STATE_S3: @@ -319,8 +291,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* This violates the spec but is required for bug compatibility. */ acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); - /* Reprogram control registers and execute _BFS */ - acpi_leave_sleep_state_prep(acpi_state, wake_sleep_flags); + /* Reprogram control registers */ + acpi_leave_sleep_state_prep(acpi_state); /* ACPI 3.0 specs (P62) says that it's the responsibility * of the OSPM to clear the status bit [ implying that the @@ -603,9 +575,9 @@ static int acpi_hibernation_enter(void) ACPI_FLUSH_CPU_CACHE(); /* This shouldn't return. If it returns, we have a problem */ - status = acpi_enter_sleep_state(ACPI_STATE_S4, wake_sleep_flags); - /* Reprogram control registers and execute _BFS */ - acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags); + status = acpi_enter_sleep_state(ACPI_STATE_S4); + /* Reprogram control registers */ + acpi_leave_sleep_state_prep(ACPI_STATE_S4); return ACPI_SUCCESS(status) ? 0 : -EFAULT; } @@ -617,8 +589,8 @@ static void acpi_hibernation_leave(void) * enable it here. */ acpi_enable(); - /* Reprogram control registers and execute _BFS */ - acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags); + /* Reprogram control registers */ + acpi_leave_sleep_state_prep(ACPI_STATE_S4); /* Check the hardware signature */ if (facs && s4_hardware_signature != facs->hardware_signature) { printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " @@ -892,33 +864,7 @@ static void acpi_power_off(void) /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ printk(KERN_DEBUG "%s called\n", __func__); local_irq_disable(); - acpi_enter_sleep_state(ACPI_STATE_S5, wake_sleep_flags); -} - -/* - * ACPI 2.0 created the optional _GTS and _BFS, - * but industry adoption has been neither rapid nor broad. - * - * Linux gets into trouble when it executes poorly validated - * paths through the BIOS, so disable _GTS and _BFS by default, - * but do speak up and offer the option to enable them. - */ -static void __init acpi_gts_bfs_check(void) -{ - acpi_handle dummy; - - if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy))) - { - printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n"); - printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, " - "please notify linux-acpi@vger.kernel.org\n"); - } - if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy))) - { - printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n"); - printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, " - "please notify linux-acpi@vger.kernel.org\n"); - } + acpi_enter_sleep_state(ACPI_STATE_S5); } int __init acpi_sleep_init(void) @@ -979,6 +925,5 @@ int __init acpi_sleep_init(void) * object can also be evaluated when the system enters S5. */ register_reboot_notifier(&tts_notifier); - acpi_gts_bfs_check(); return 0; } diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 240a244..7c3f98b 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -173,7 +173,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) { int result = 0; - if (!strncmp(val, "enable", strlen("enable"))) { + if (!strncmp(val, "enable", sizeof("enable") - 1)) { result = acpi_debug_trace(trace_method_name, trace_debug_level, trace_debug_layer, 0); if (result) @@ -181,7 +181,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) goto exit; } - if (!strncmp(val, "disable", strlen("disable"))) { + if (!strncmp(val, "disable", sizeof("disable") - 1)) { int name = 0; result = acpi_debug_trace((char *)&name, trace_debug_level, trace_debug_layer, 0); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 24712ad..311be18 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -65,6 +65,8 @@ #include <linux/mbus.h> #include <linux/bitops.h> #include <linux/gfp.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -4026,7 +4028,7 @@ static int mv_platform_probe(struct platform_device *pdev) struct ata_host *host; struct mv_host_priv *hpriv; struct resource *res; - int n_ports = 0; + int n_ports = 0, irq = 0; int rc; #if defined(CONFIG_HAVE_CLK) int port; @@ -4050,8 +4052,14 @@ static int mv_platform_probe(struct platform_device *pdev) return -EINVAL; /* allocate host */ - mv_platform_data = pdev->dev.platform_data; - n_ports = mv_platform_data->n_ports; + if (pdev->dev.of_node) { + of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports); + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + } else { + mv_platform_data = pdev->dev.platform_data; + n_ports = mv_platform_data->n_ports; + irq = platform_get_irq(pdev, 0); + } host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); @@ -4109,8 +4117,7 @@ static int mv_platform_probe(struct platform_device *pdev) dev_info(&pdev->dev, "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH, host->n_ports); - rc = ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt, - IRQF_SHARED, &mv6_sht); + rc = ata_host_activate(host, irq, mv_interrupt, IRQF_SHARED, &mv6_sht); if (!rc) return 0; @@ -4205,15 +4212,24 @@ static int mv_platform_resume(struct platform_device *pdev) #define mv_platform_resume NULL #endif +#ifdef CONFIG_OF +static struct of_device_id mv_sata_dt_ids[] __devinitdata = { + { .compatible = "marvell,orion-sata", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mv_sata_dt_ids); +#endif + static struct platform_driver mv_platform_driver = { - .probe = mv_platform_probe, - .remove = __devexit_p(mv_platform_remove), - .suspend = mv_platform_suspend, - .resume = mv_platform_resume, - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, + .probe = mv_platform_probe, + .remove = __devexit_p(mv_platform_remove), + .suspend = mv_platform_suspend, + .resume = mv_platform_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mv_sata_dt_ids), + }, }; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index d438601..96cce6d 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2362,7 +2362,7 @@ static int __devinit ia_init(struct atm_dev *dev) { printk(DEV_LABEL " (itf %d): can't set up page mapping\n", dev->number); - return error; + return -ENOMEM; } IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=%p,irq=%d\n", dev->number, iadev->pci->revision, base, iadev->irq);) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2e0e7fc..dbe6135 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3537,9 +3537,9 @@ static void drbd_cleanup(void) } /** - * drbd_congested() - Callback for pdflush + * drbd_congested() - Callback for the flusher thread * @congested_data: User data - * @bdi_bits: Bits pdflush is currently interested in + * @bdi_bits: Bits the BDI flusher thread is currently interested in * * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested. */ diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 27f5c78..f4cd946 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -483,6 +483,7 @@ static struct shdma_desc *shdma_add_desc(struct shdma_chan *schan, new->mark = DESC_PREPARED; new->async_tx.flags = flags; new->direction = direction; + new->partial = 0; *len -= copy_size; if (direction == DMA_MEM_TO_MEM || direction == DMA_MEM_TO_DEV) @@ -644,6 +645,14 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, case DMA_TERMINATE_ALL: spin_lock_irqsave(&schan->chan_lock, flags); ops->halt_channel(schan); + + if (ops->get_partial && !list_empty(&schan->ld_queue)) { + /* Record partial transfer */ + struct shdma_desc *desc = list_first_entry(&schan->ld_queue, + struct shdma_desc, node); + desc->partial = ops->get_partial(schan, desc); + } + spin_unlock_irqrestore(&schan->chan_lock, flags); shdma_chan_ld_cleanup(schan, true); diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index 027c9be..f41bcc5 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -381,6 +381,17 @@ static bool sh_dmae_chan_irq(struct shdma_chan *schan, int irq) return true; } +static size_t sh_dmae_get_partial(struct shdma_chan *schan, + struct shdma_desc *sdesc) +{ + struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan, + shdma_chan); + struct sh_dmae_desc *sh_desc = container_of(sdesc, + struct sh_dmae_desc, shdma_desc); + return (sh_desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) << + sh_chan->xmit_shift; +} + /* Called from error IRQ or NMI */ static bool sh_dmae_reset(struct sh_dmae_device *shdev) { @@ -632,6 +643,7 @@ static const struct shdma_ops sh_dmae_shdma_ops = { .start_xfer = sh_dmae_start_xfer, .embedded_desc = sh_dmae_embedded_desc, .chan_irq = sh_dmae_chan_irq, + .get_partial = sh_dmae_get_partial, }; static int __devinit sh_dmae_probe(struct platform_device *pdev) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 6d1cbdf..b64502d 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -296,8 +296,13 @@ static int iommu_init_device(struct device *dev) } else dma_pdev = pci_dev_get(pdev); + /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); + /* + * If it's a multifunction device that does not support our + * required ACS flags, add to the same group as function 0. + */ if (dma_pdev->multifunction && !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) swap_pci_ref(&dma_pdev, @@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev) PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 0))); + /* + * Devices on the root bus go through the iommu. If that's not us, + * find the next upstream device and test ACS up to the root bus. + * Finding the next device may require skipping virtual buses. + */ while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) + struct pci_bus *bus = dma_pdev->bus; + + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + goto root_bus; + } + + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); + swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } +root_bus: group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) { diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 500e7f1..0a2ea31 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1131,9 +1131,6 @@ static int __init amd_iommu_init_pci(void) break; } - /* Make sure ACS will be enabled */ - pci_request_acs(); - ret = amd_iommu_init_devices(); print_iommu_info(); @@ -1652,6 +1649,9 @@ static bool detect_ivrs(void) early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + /* Make sure ACS will be enabled during PCI probe */ + pci_request_acs(); + return true; } diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 45350ff..80bad32 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -732,9 +732,9 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain) spin_lock_init(&priv->pgtablelock); INIT_LIST_HEAD(&priv->clients); - dom->geometry.aperture_start = 0; - dom->geometry.aperture_end = ~0UL; - dom->geometry.force_aperture = true; + domain->geometry.aperture_start = 0; + domain->geometry.aperture_end = ~0UL; + domain->geometry.force_aperture = true; domain->priv = priv; return 0; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 7469b53..2297ec1 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2008,6 +2008,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) if (!drhd) { printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", pci_name(pdev)); + free_domain_mem(domain); return NULL; } iommu = drhd->iommu; @@ -4124,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev) } else dma_pdev = pci_dev_get(pdev); + /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); + /* + * If it's a multifunction device that does not support our + * required ACS flags, add to the same group as function 0. + */ if (dma_pdev->multifunction && !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) swap_pci_ref(&dma_pdev, @@ -4133,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev) PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 0))); + /* + * Devices on the root bus go through the iommu. If that's not us, + * find the next upstream device and test ACS up to the root bus. + * Finding the next device may require skipping virtual buses. + */ while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) + struct pci_bus *bus = dma_pdev->bus; + + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + goto root_bus; + } + + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); + swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } +root_bus: group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) { diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 4ba325a..2a4bb36 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -799,14 +799,14 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain, goto out; } } - dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev)); + dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev)); out: spin_unlock(&as->client_lock); } static int smmu_iommu_domain_init(struct iommu_domain *domain) { - int i, err = -ENODEV; + int i, err = -EAGAIN; unsigned long flags; struct smmu_as *as; struct smmu_device *smmu = smmu_handle; @@ -814,11 +814,14 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain) /* Look for a free AS with lock held */ for (i = 0; i < smmu->num_as; i++) { as = &smmu->as[i]; - if (!as->pdir_page) { - err = alloc_pdir(as); - if (!err) - goto found; - } + + if (as->pdir_page) + continue; + + err = alloc_pdir(as); + if (!err) + goto found; + if (err != -EAGAIN) break; } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 5405ec6..baf2686 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -16,7 +16,6 @@ #include <linux/sched.h> #include "isdnloop.h" -static char *revision = "$Revision: 1.11.6.7 $"; static char *isdnloop_id = "loop0"; MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); @@ -1494,17 +1493,6 @@ isdnloop_addcard(char *id1) static int __init isdnloop_init(void) { - char *p; - char rev[10]; - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else - strcpy(rev, " ??? "); - printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev); - if (isdnloop_id) return (isdnloop_addcard(isdnloop_id)); diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 0dc8abc..949cabb 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -2222,7 +2222,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei, InitWin(l2); l2->l2m.fsm = &l2fsm; if (test_bit(FLG_LAPB, &l2->flag) || - test_bit(FLG_PTP, &l2->flag) || + test_bit(FLG_FIXED_TEI, &l2->flag) || test_bit(FLG_LAPD_NET, &l2->flag)) l2->l2m.state = ST_L2_4; else diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 1eee45b..d949b78 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -268,13 +268,14 @@ config DM_MIRROR needed for live data migration tools such as 'pvmove'. config DM_RAID - tristate "RAID 1/4/5/6 target" + tristate "RAID 1/4/5/6/10 target" depends on BLK_DEV_DM select MD_RAID1 + select MD_RAID10 select MD_RAID456 select BLK_DEV_MD ---help--- - A dm target that supports RAID1, RAID4, RAID5 and RAID6 mappings + A dm target that supports RAID1, RAID10, RAID4, RAID5 and RAID6 mappings A RAID-5 set of N drives with a capacity of C MB per drive provides the capacity of C * (N - 1) MB, and protects against a failure diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 15dbe03..94e7f6b 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1305,7 +1305,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect prepare_to_wait(&bitmap->overflow_wait, &__wait, TASK_UNINTERRUPTIBLE); spin_unlock_irq(&bitmap->counts.lock); - io_schedule(); + schedule(); finish_wait(&bitmap->overflow_wait, &__wait); continue; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9f7f8be..611b5f7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -944,6 +944,44 @@ do_sync_io: pr_debug("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); } +struct raid1_plug_cb { + struct blk_plug_cb cb; + struct bio_list pending; + int pending_cnt; +}; + +static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) +{ + struct raid1_plug_cb *plug = container_of(cb, struct raid1_plug_cb, + cb); + struct mddev *mddev = plug->cb.data; + struct r1conf *conf = mddev->private; + struct bio *bio; + + if (from_schedule) { + spin_lock_irq(&conf->device_lock); + bio_list_merge(&conf->pending_bio_list, &plug->pending); + conf->pending_count += plug->pending_cnt; + spin_unlock_irq(&conf->device_lock); + md_wakeup_thread(mddev->thread); + kfree(plug); + return; + } + + /* we aren't scheduling, so we can do the write-out directly. */ + bio = bio_list_get(&plug->pending); + bitmap_unplug(mddev->bitmap); + wake_up(&conf->wait_barrier); + + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = next; + } + kfree(plug); +} + static void make_request(struct mddev *mddev, struct bio * bio) { struct r1conf *conf = mddev->private; @@ -957,6 +995,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); struct md_rdev *blocked_rdev; + struct blk_plug_cb *cb; + struct raid1_plug_cb *plug = NULL; int first_clone; int sectors_handled; int max_sectors; @@ -1259,11 +1299,22 @@ read_again: mbio->bi_private = r1_bio; atomic_inc(&r1_bio->remaining); + + cb = blk_check_plugged(raid1_unplug, mddev, sizeof(*plug)); + if (cb) + plug = container_of(cb, struct raid1_plug_cb, cb); + else + plug = NULL; spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; + if (plug) { + bio_list_add(&plug->pending, mbio); + plug->pending_cnt++; + } else { + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + } spin_unlock_irqrestore(&conf->device_lock, flags); - if (!mddev_check_plugged(mddev)) + if (!plug) md_wakeup_thread(mddev->thread); } /* Mustn't call r1_bio_write_done before this next test, diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 87a2d0b..adda94d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -484,7 +484,8 @@ get_active_stripe(struct r5conf *conf, sector_t sector, } else { if (atomic_read(&sh->count)) { BUG_ON(!list_empty(&sh->lru) - && !test_bit(STRIPE_EXPANDING, &sh->state)); + && !test_bit(STRIPE_EXPANDING, &sh->state) + && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)); } else { if (!test_bit(STRIPE_HANDLE, &sh->state)) atomic_inc(&conf->active_stripes); @@ -4010,6 +4011,62 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf) return sh; } +struct raid5_plug_cb { + struct blk_plug_cb cb; + struct list_head list; +}; + +static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule) +{ + struct raid5_plug_cb *cb = container_of( + blk_cb, struct raid5_plug_cb, cb); + struct stripe_head *sh; + struct mddev *mddev = cb->cb.data; + struct r5conf *conf = mddev->private; + + if (cb->list.next && !list_empty(&cb->list)) { + spin_lock_irq(&conf->device_lock); + while (!list_empty(&cb->list)) { + sh = list_first_entry(&cb->list, struct stripe_head, lru); + list_del_init(&sh->lru); + /* + * avoid race release_stripe_plug() sees + * STRIPE_ON_UNPLUG_LIST clear but the stripe + * is still in our list + */ + smp_mb__before_clear_bit(); + clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state); + __release_stripe(conf, sh); + } + spin_unlock_irq(&conf->device_lock); + } + kfree(cb); +} + +static void release_stripe_plug(struct mddev *mddev, + struct stripe_head *sh) +{ + struct blk_plug_cb *blk_cb = blk_check_plugged( + raid5_unplug, mddev, + sizeof(struct raid5_plug_cb)); + struct raid5_plug_cb *cb; + + if (!blk_cb) { + release_stripe(sh); + return; + } + + cb = container_of(blk_cb, struct raid5_plug_cb, cb); + + if (cb->list.next == NULL) + INIT_LIST_HEAD(&cb->list); + + if (!test_and_set_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)) + list_add_tail(&sh->lru, &cb->list); + else + release_stripe(sh); +} + static void make_request(struct mddev *mddev, struct bio * bi) { struct r5conf *conf = mddev->private; @@ -4138,8 +4195,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) if ((bi->bi_rw & REQ_NOIDLE) && !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) atomic_inc(&conf->preread_active_stripes); - mddev_check_plugged(mddev); - release_stripe(sh); + release_stripe_plug(mddev, sh); } else { /* cannot get stripe for read-ahead, just give-up */ clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -4537,6 +4593,30 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) return handled; } +#define MAX_STRIPE_BATCH 8 +static int handle_active_stripes(struct r5conf *conf) +{ + struct stripe_head *batch[MAX_STRIPE_BATCH], *sh; + int i, batch_size = 0; + + while (batch_size < MAX_STRIPE_BATCH && + (sh = __get_priority_stripe(conf)) != NULL) + batch[batch_size++] = sh; + + if (batch_size == 0) + return batch_size; + spin_unlock_irq(&conf->device_lock); + + for (i = 0; i < batch_size; i++) + handle_stripe(batch[i]); + + cond_resched(); + + spin_lock_irq(&conf->device_lock); + for (i = 0; i < batch_size; i++) + __release_stripe(conf, batch[i]); + return batch_size; +} /* * This is our raid5 kernel thread. @@ -4547,7 +4627,6 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) */ static void raid5d(struct mddev *mddev) { - struct stripe_head *sh; struct r5conf *conf = mddev->private; int handled; struct blk_plug plug; @@ -4561,6 +4640,7 @@ static void raid5d(struct mddev *mddev) spin_lock_irq(&conf->device_lock); while (1) { struct bio *bio; + int batch_size; if ( !list_empty(&conf->bitmap_list)) { @@ -4584,21 +4664,16 @@ static void raid5d(struct mddev *mddev) handled++; } - sh = __get_priority_stripe(conf); - - if (!sh) + batch_size = handle_active_stripes(conf); + if (!batch_size) break; - spin_unlock_irq(&conf->device_lock); - - handled++; - handle_stripe(sh); - release_stripe(sh); - cond_resched(); + handled += batch_size; - if (mddev->flags & ~(1<<MD_CHANGE_PENDING)) + if (mddev->flags & ~(1<<MD_CHANGE_PENDING)) { + spin_unlock_irq(&conf->device_lock); md_check_recovery(mddev); - - spin_lock_irq(&conf->device_lock); + spin_lock_irq(&conf->device_lock); + } } pr_debug("%d stripes handled\n", handled); diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 61dbb61..a9fc249 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -321,6 +321,7 @@ enum { STRIPE_BIOFILL_RUN, STRIPE_COMPUTE_RUN, STRIPE_OPS_REQ_PENDING, + STRIPE_ON_UNPLUG_LIST, }; /* diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index cfff454..c3bb304 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -19,14 +19,13 @@ #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <asm/io.h> +#include <asm/sections.h> /****************************************************************************/ -extern char _ebss; - struct map_info uclinux_ram_map = { .name = "RAM", - .phys = (unsigned long)&_ebss, + .phys = (unsigned long)__bss_stop, .size = 0, }; diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 545c09e..cff6f02 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -996,9 +996,7 @@ static int __init cops_module_init(void) printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", cardname); cops_dev = cops_probe(-1); - if (IS_ERR(cops_dev)) - return PTR_ERR(cops_dev); - return 0; + return PTR_RET(cops_dev); } static void __exit cops_module_exit(void) diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 0910dce..b5782cd 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1243,9 +1243,7 @@ static int __init ltpc_module_init(void) "ltpc: Autoprobing is not recommended for modules\n"); dev_ltpc = ltpc_probe(); - if (IS_ERR(dev_ltpc)) - return PTR_ERR(dev_ltpc); - return 0; + return PTR_RET(dev_ltpc); } module_init(ltpc_module_init); #endif diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index f0c8bd5..021d69c 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1712,7 +1712,7 @@ e100_set_network_leds(int active) static void e100_netpoll(struct net_device* netdev) { - e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL); + e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev); } #endif diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index dd451c3..02b5a34 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -4041,20 +4041,6 @@ static bool bnx2x_get_load_status(struct bnx2x *bp, int engine) return val != 0; } -/* - * Reset the load status for the current engine. - */ -static void bnx2x_clear_load_status(struct bnx2x *bp) -{ - u32 val; - u32 mask = (BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK : - BNX2X_PATH0_LOAD_CNT_MASK); - bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG); - val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); - REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~mask)); - bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG); -} - static void _print_next_block(int idx, const char *blk) { pr_cont("%s%s", idx ? ", " : "", blk); @@ -9384,32 +9370,24 @@ static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp) return rc; } -static bool __devinit bnx2x_can_flr(struct bnx2x *bp) -{ - int pos; - u32 cap; - struct pci_dev *dev = bp->pdev; - - pos = pci_pcie_cap(dev); - if (!pos) - return false; - - pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); - if (!(cap & PCI_EXP_DEVCAP_FLR)) - return false; - - return true; -} - static int __devinit bnx2x_do_flr(struct bnx2x *bp) { int i, pos; u16 status; struct pci_dev *dev = bp->pdev; - /* probe the capability first */ - if (bnx2x_can_flr(bp)) - return -ENOTTY; + + if (CHIP_IS_E1x(bp)) { + BNX2X_DEV_INFO("FLR not supported in E1/E1H\n"); + return -EINVAL; + } + + /* only bootcode REQ_BC_VER_4_INITIATE_FLR and onwards support flr */ + if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) { + BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n", + bp->common.bc_ver); + return -EINVAL; + } pos = pci_pcie_cap(dev); if (!pos) @@ -9429,12 +9407,8 @@ static int __devinit bnx2x_do_flr(struct bnx2x *bp) "transaction is not cleared; proceeding with reset anyway\n"); clear: - if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) { - BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n", - bp->common.bc_ver); - return -EINVAL; - } + BNX2X_DEV_INFO("Initiating FLR\n"); bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0); return 0; @@ -9454,8 +9428,21 @@ static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp) * the one required, then FLR will be sufficient to clean any residue * left by previous driver */ - if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp)) - return bnx2x_do_flr(bp); + rc = bnx2x_test_firmware_version(bp, false); + + if (!rc) { + /* fw version is good */ + BNX2X_DEV_INFO("FW version matches our own. Attempting FLR\n"); + rc = bnx2x_do_flr(bp); + } + + if (!rc) { + /* FLR was performed */ + BNX2X_DEV_INFO("FLR successful\n"); + return 0; + } + + BNX2X_DEV_INFO("Could not FLR\n"); /* Close the MCP request, return failure*/ rc = bnx2x_prev_mcp_done(bp); @@ -11427,9 +11414,6 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, if (!chip_is_e1x) REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1); - /* Reset the load counter */ - bnx2x_clear_load_status(bp); - dev->watchdog_timeo = TX_TIMEOUT; dev->netdev_ops = &bnx2x_netdev_ops; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c60de89..90a903d8 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1948,7 +1948,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter) if (adapter->num_rx_qs != MAX_RX_QS) dev_info(&adapter->pdev->dev, - "Created only %d receive queues", adapter->num_rx_qs); + "Created only %d receive queues\n", adapter->num_rx_qs); return 0; } diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 0b3bade..080c890 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -999,7 +999,7 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) **/ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) { - u32 ctrl, ctrl_ext, eecd; + u32 ctrl, ctrl_ext, eecd, tctl; s32 ret_val; /* @@ -1014,7 +1014,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(IMC, 0xffffffff); ew32(RCTL, 0); - ew32(TCTL, E1000_TCTL_PSP); + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_EN; + ew32(TCTL, tctl); e1e_flush(); usleep_range(10000, 20000); @@ -1601,10 +1603,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) * auto-negotiation in the TXCW register and disable * forced link in the Device Control register in an * attempt to auto-negotiate with our link partner. - * If the partner code word is null, stop forcing - * and restart auto negotiation. */ - if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) { + if (rxcw & E1000_RXCW_C) { /* Enable autoneg, and unforce link up */ ew32(TXCW, mac->txcw); ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 95b2453..46c3b1f 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -178,6 +178,24 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo) pr_info("%-15s %08x %08x\n", rname, regs[0], regs[1]); } +static void e1000e_dump_ps_pages(struct e1000_adapter *adapter, + struct e1000_buffer *bi) +{ + int i; + struct e1000_ps_page *ps_page; + + for (i = 0; i < adapter->rx_ps_pages; i++) { + ps_page = &bi->ps_pages[i]; + + if (ps_page->page) { + pr_info("packet dump for ps_page %d:\n", i); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, + 16, 1, page_address(ps_page->page), + PAGE_SIZE, true); + } + } +} + /* * e1000e_dump - Print registers, Tx-ring and Rx-ring */ @@ -299,10 +317,10 @@ static void e1000e_dump(struct e1000_adapter *adapter) (unsigned long long)buffer_info->time_stamp, buffer_info->skb, next_desc); - if (netif_msg_pktdata(adapter) && buffer_info->dma != 0) + if (netif_msg_pktdata(adapter) && buffer_info->skb) print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, - 16, 1, phys_to_virt(buffer_info->dma), - buffer_info->length, true); + 16, 1, buffer_info->skb->data, + buffer_info->skb->len, true); } /* Print Rx Ring Summary */ @@ -381,10 +399,8 @@ rx_ring_summary: buffer_info->skb, next_desc); if (netif_msg_pktdata(adapter)) - print_hex_dump(KERN_INFO, "", - DUMP_PREFIX_ADDRESS, 16, 1, - phys_to_virt(buffer_info->dma), - adapter->rx_ps_bsize0, true); + e1000e_dump_ps_pages(adapter, + buffer_info); } } break; @@ -444,12 +460,12 @@ rx_ring_summary: (unsigned long long)buffer_info->dma, buffer_info->skb, next_desc); - if (netif_msg_pktdata(adapter)) + if (netif_msg_pktdata(adapter) && + buffer_info->skb) print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, - phys_to_virt - (buffer_info->dma), + buffer_info->skb->data, adapter->rx_buffer_len, true); } diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 5e84eaa..ba994fb 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -254,6 +254,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) */ size += NVM_WORD_SIZE_BASE_SHIFT; + /* + * Check for invalid size + */ + if ((hw->mac.type == e1000_82576) && (size > 15)) { + pr_notice("The NVM size is not valid, defaulting to 32K\n"); + size = 15; + } + nvm->word_size = 1 << size; if (hw->mac.type < e1000_i210) { nvm->opcode_bits = 8; @@ -281,14 +289,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) } else nvm->type = e1000_nvm_flash_hw; - /* - * Check for invalid size - */ - if ((hw->mac.type == e1000_82576) && (size > 15)) { - pr_notice("The NVM size is not valid, defaulting to 32K\n"); - size = 15; - } - /* NVM Function Pointers */ switch (hw->mac.type) { case e1000_82580: diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index 10efcd8..28394be 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -156,8 +156,12 @@ : (0x0E018 + ((_n) * 0x40))) #define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \ : (0x0E028 + ((_n) * 0x40))) -#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) -#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) +#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \ + (0x0C014 + ((_n) * 0x40))) +#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n) +#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \ + (0x0E014 + ((_n) * 0x40))) +#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n) #define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \ : (0x0E038 + ((_n) * 0x40))) #define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \ diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index a19c84c..7059111 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -209,8 +209,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) /* When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (igb_check_reset_block(hw)) { - dev_err(&adapter->pdev->dev, "Cannot change link " - "characteristics when SoL/IDER is active.\n"); + dev_err(&adapter->pdev->dev, + "Cannot change link characteristics when SoL/IDER is active.\n"); return -EINVAL; } @@ -1089,8 +1089,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data, wr32(reg, (_test[pat] & write)); val = rd32(reg) & mask; if (val != (_test[pat] & write & mask)) { - dev_err(&adapter->pdev->dev, "pattern test reg %04X " - "failed: got 0x%08X expected 0x%08X\n", + dev_err(&adapter->pdev->dev, + "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", reg, val, (_test[pat] & write & mask)); *data = reg; return 1; @@ -1108,8 +1108,8 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, wr32(reg, write & mask); val = rd32(reg); if ((write & mask) != (val & mask)) { - dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:" - " got 0x%08X expected 0x%08X\n", reg, + dev_err(&adapter->pdev->dev, + "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg, (val & mask), (write & mask)); *data = reg; return 1; @@ -1171,8 +1171,9 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_STATUS, toggle); after = rd32(E1000_STATUS) & toggle; if (value != after) { - dev_err(&adapter->pdev->dev, "failed STATUS register test " - "got: 0x%08X expected: 0x%08X\n", after, value); + dev_err(&adapter->pdev->dev, + "failed STATUS register test got: 0x%08X expected: 0x%08X\n", + after, value); *data = 1; return 1; } @@ -1497,6 +1498,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) break; } + /* add small delay to avoid loopback test failure */ + msleep(50); + /* force 1000, set loopback */ igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); @@ -1777,16 +1781,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data) * sessions are active */ if (igb_check_reset_block(&adapter->hw)) { dev_err(&adapter->pdev->dev, - "Cannot do PHY loopback test " - "when SoL/IDER is active.\n"); + "Cannot do PHY loopback test when SoL/IDER is active.\n"); *data = 0; goto out; } if ((adapter->hw.mac.type == e1000_i210) - || (adapter->hw.mac.type == e1000_i210)) { + || (adapter->hw.mac.type == e1000_i211)) { dev_err(&adapter->pdev->dev, - "Loopback test not supported " - "on this part at this time.\n"); + "Loopback test not supported on this part at this time.\n"); *data = 0; goto out; } diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index b7c2d50..48cc4fb 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -462,10 +462,10 @@ static void igb_dump(struct igb_adapter *adapter) (u64)buffer_info->time_stamp, buffer_info->skb, next_desc); - if (netif_msg_pktdata(adapter) && buffer_info->dma != 0) + if (netif_msg_pktdata(adapter) && buffer_info->skb) print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, - 16, 1, phys_to_virt(buffer_info->dma), + 16, 1, buffer_info->skb->data, buffer_info->length, true); } } @@ -547,18 +547,17 @@ rx_ring_summary: (u64)buffer_info->dma, buffer_info->skb, next_desc); - if (netif_msg_pktdata(adapter)) { + if (netif_msg_pktdata(adapter) && + buffer_info->dma && buffer_info->skb) { print_hex_dump(KERN_INFO, "", - DUMP_PREFIX_ADDRESS, - 16, 1, - phys_to_virt(buffer_info->dma), - IGB_RX_HDR_LEN, true); + DUMP_PREFIX_ADDRESS, + 16, 1, buffer_info->skb->data, + IGB_RX_HDR_LEN, true); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, - phys_to_virt( - buffer_info->page_dma + - buffer_info->page_offset), + page_address(buffer_info->page) + + buffer_info->page_offset, PAGE_SIZE/2, true); } } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index f32e703..5aba5ec 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -614,8 +614,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* If source MAC is equal to our own MAC and not performing * the selftest or flb disabled - drop the packet */ if (s_mac == priv->mac && - (!(dev->features & NETIF_F_LOOPBACK) || - !priv->validate_loopback)) + !((dev->features & NETIF_F_LOOPBACK) || + priv->validate_loopback)) goto next; /* diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 019d856..10bba09 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -164,7 +164,6 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, ring->cons = 0xffffffff; ring->last_nr_txbb = 1; ring->poll_cnt = 0; - ring->blocked = 0; memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info)); memset(ring->buf, 0, ring->buf_size); @@ -365,14 +364,13 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) ring->cons += txbbs_skipped; netdev_tx_completed_queue(ring->tx_queue, packets, bytes); - /* Wakeup Tx queue if this ring stopped it */ - if (unlikely(ring->blocked)) { - if ((u32) (ring->prod - ring->cons) <= - ring->size - HEADROOM - MAX_DESC_TXBBS) { - ring->blocked = 0; - netif_tx_wake_queue(ring->tx_queue); - priv->port_stats.wake_queue++; - } + /* + * Wakeup Tx queue if this stopped, and at least 1 packet + * was completed + */ + if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) { + netif_tx_wake_queue(ring->tx_queue); + priv->port_stats.wake_queue++; } } @@ -592,7 +590,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->size - HEADROOM - MAX_DESC_TXBBS)) { /* every full Tx ring stops queue */ netif_tx_stop_queue(ring->tx_queue); - ring->blocked = 1; priv->port_stats.queue_stopped++; return NETDEV_TX_BUSY; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 48d0e90..827b72d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -157,9 +157,6 @@ int mlx4_check_port_params(struct mlx4_dev *dev, "on this HCA, aborting.\n"); return -EINVAL; } - if (port_type[i] == MLX4_PORT_TYPE_ETH && - port_type[i + 1] == MLX4_PORT_TYPE_IB) - return -EINVAL; } } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 5f1ab10..9d27e42 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -248,7 +248,6 @@ struct mlx4_en_tx_ring { u32 doorbell_qpn; void *buf; u16 poll_cnt; - int blocked; struct mlx4_en_tx_info *tx_info; u8 *bounce_buf; u32 last_nr_txbb; diff --git a/drivers/net/ethernet/mellanox/mlx4/sense.c b/drivers/net/ethernet/mellanox/mlx4/sense.c index 8024982..34ee09b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/sense.c +++ b/drivers/net/ethernet/mellanox/mlx4/sense.c @@ -81,20 +81,6 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev, } /* - * Adjust port configuration: - * If port 1 sensed nothing and port 2 is IB, set both as IB - * If port 2 sensed nothing and port 1 is Eth, set both as Eth - */ - if (stype[0] == MLX4_PORT_TYPE_ETH) { - for (i = 1; i < dev->caps.num_ports; i++) - stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH; - } - if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) { - for (i = 0; i < dev->caps.num_ports - 1; i++) - stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB; - } - - /* * If sensed nothing, remain in current configuration. */ for (i = 0; i < dev->caps.num_ports; i++) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 4069eda..53743f7 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -346,28 +346,15 @@ static phy_interface_t lpc_phy_interface_mode(struct device *dev) "phy-mode", NULL); if (mode && !strcmp(mode, "mii")) return PHY_INTERFACE_MODE_MII; - return PHY_INTERFACE_MODE_RMII; } - - /* non-DT */ -#ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT - return PHY_INTERFACE_MODE_MII; -#else return PHY_INTERFACE_MODE_RMII; -#endif } static bool use_iram_for_net(struct device *dev) { if (dev && dev->of_node) return of_property_read_bool(dev->of_node, "use-iram"); - - /* non-DT */ -#ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET - return true; -#else return false; -#endif } /* Receive Status information word */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index cd01ee7..b93245c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -74,7 +74,7 @@ static int __devinit stmmac_probe_config_dt(struct platform_device *pdev, * the necessary resources and invokes the main to init * the net device, register the mdio bus etc. */ -static int stmmac_pltfr_probe(struct platform_device *pdev) +static int __devinit stmmac_pltfr_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 482648f..98934bd 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1003,6 +1003,7 @@ static int ixp4xx_nway_reset(struct net_device *dev) } int ixp46x_phc_index = -1; +EXPORT_SYMBOL_GPL(ixp46x_phc_index); static int ixp4xx_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 6cee291..4a1a5f5 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -383,13 +383,6 @@ int netvsc_device_remove(struct hv_device *device) unsigned long flags; net_device = hv_get_drvdata(device); - spin_lock_irqsave(&device->channel->inbound_lock, flags); - net_device->destroy = true; - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* Wait for all send completions */ - wait_event(net_device->wait_drain, - atomic_read(&net_device->num_outstanding_sends) == 0); netvsc_disconnect_vsp(net_device); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index e5d6146..1e88a10 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -718,6 +718,9 @@ static void rndis_filter_halt_device(struct rndis_device *dev) { struct rndis_request *request; struct rndis_halt_request *halt; + struct netvsc_device *nvdev = dev->net_dev; + struct hv_device *hdev = nvdev->dev; + ulong flags; /* Attempt to do a rndis device halt */ request = get_rndis_request(dev, RNDIS_MSG_HALT, @@ -735,6 +738,14 @@ static void rndis_filter_halt_device(struct rndis_device *dev) dev->state = RNDIS_DEV_UNINITIALIZED; cleanup: + spin_lock_irqsave(&hdev->channel->inbound_lock, flags); + nvdev->destroy = true; + spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags); + + /* Wait for all send completions */ + wait_event(nvdev->wait_drain, + atomic_read(&nvdev->num_outstanding_sends) == 0); + if (request) put_rndis_request(dev, request); return; diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c index a561ae4..c6a0299 100644 --- a/drivers/net/irda/bfin_sir.c +++ b/drivers/net/irda/bfin_sir.c @@ -158,7 +158,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) /* If not add the 'RPOLC', we can't catch the receive interrupt. * It's related with the HW layout and the IR transiver. */ - val |= IREN | RPOLC; + val |= UMOD_IRDA | RPOLC; UART_PUT_GCTL(port, val); return ret; } @@ -432,7 +432,7 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev bfin_sir_stop_rx(port); val = UART_GET_GCTL(port); - val &= ~(UCEN | IREN | RPOLC); + val &= ~(UCEN | UMOD_MASK | RPOLC); UART_PUT_GCTL(port, val); #ifdef CONFIG_SIR_BFIN_DMA @@ -518,10 +518,10 @@ static void bfin_sir_send_work(struct work_struct *work) * reset all the UART. */ val = UART_GET_GCTL(port); - val &= ~(IREN | RPOLC); + val &= ~(UMOD_MASK | RPOLC); UART_PUT_GCTL(port, val); SSYNC(); - val |= IREN | RPOLC; + val |= UMOD_IRDA | RPOLC; UART_PUT_GCTL(port, val); SSYNC(); /* bfin_sir_set_speed(port, self->speed); */ diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index e0cc4ef..eefe49e 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -101,7 +101,6 @@ err: n--; gpio_free(s->gpio[n]); } - devm_kfree(&pdev->dev, s); return r; } diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 1c98321..162464f 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -189,7 +189,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (sk_pppox(po)->sk_state & PPPOX_DEAD) goto tx_error; - rt = ip_route_output_ports(&init_net, &fl4, NULL, + rt = ip_route_output_ports(sock_net(sk), &fl4, NULL, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, IPPROTO_GRE, @@ -468,7 +468,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.private = sk; po->chan.ops = &pptp_chan_ops; - rt = ip_route_output_ports(&init_net, &fl4, sk, + rt = ip_route_output_ports(sock_net(sk), &fl4, sk, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 926d4db..3a16d4f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -187,7 +187,6 @@ static void __tun_detach(struct tun_struct *tun) netif_tx_lock_bh(tun->dev); netif_carrier_off(tun->dev); tun->tfile = NULL; - tun->socket.file = NULL; netif_tx_unlock_bh(tun->dev); /* Drop read queue */ diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 6461004..7d78669 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -232,6 +232,7 @@ static int usbpn_open(struct net_device *dev) struct urb *req = usb_alloc_urb(0, GFP_KERNEL); if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) { + usb_free_urb(req); usbpn_close(dev); return -ENOMEM; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index f4ce5957..4cd582a 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1225,6 +1225,26 @@ static const struct usb_device_id cdc_devs[] = { .driver_info = (unsigned long) &wwan_info, }, + /* Dell branded MBM devices like DW5550 */ + { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_VENDOR, + .idVendor = 0x413c, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long) &wwan_info, + }, + + /* Toshiba branded MBM devices */ + { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_VENDOR, + .idVendor = 0x0930, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long) &wwan_info, + }, + /* Generic CDC-NCM devices */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 55a77e4..2798077 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -10,6 +10,7 @@ #include <linux/netdevice.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/olpc-ec.h> #ifdef CONFIG_OLPC #include <asm/olpc.h> diff --git a/drivers/pinctrl/pinctrl-imx23.c b/drivers/pinctrl/pinctrl-imx23.c index 75d3eff..3674d87 100644 --- a/drivers/pinctrl/pinctrl-imx23.c +++ b/drivers/pinctrl/pinctrl-imx23.c @@ -292,7 +292,7 @@ static int __init imx23_pinctrl_init(void) { return platform_driver_register(&imx23_pinctrl_driver); } -arch_initcall(imx23_pinctrl_init); +postcore_initcall(imx23_pinctrl_init); static void __exit imx23_pinctrl_exit(void) { diff --git a/drivers/pinctrl/pinctrl-imx28.c b/drivers/pinctrl/pinctrl-imx28.c index b973026..0f5b212 100644 --- a/drivers/pinctrl/pinctrl-imx28.c +++ b/drivers/pinctrl/pinctrl-imx28.c @@ -408,7 +408,7 @@ static int __init imx28_pinctrl_init(void) { return platform_driver_register(&imx28_pinctrl_driver); } -arch_initcall(imx28_pinctrl_init); +postcore_initcall(imx28_pinctrl_init); static void __exit imx28_pinctrl_exit(void) { diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index 6f99769..5f3e9d0 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -766,7 +766,7 @@ DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1", DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1"); -DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1", "hsit_a_2"); +DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1"); DB8500_FUNC_GROUPS(usb, "usb_a_1"); DB8500_FUNC_GROUPS(trig, "trig_b_1"); diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 53b0d49..ec6ac50 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -1731,7 +1731,6 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) for (i = 0; i < npct->soc->gpio_num_ranges; i++) { if (!nmk_gpio_chips[i]) { dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); - devm_kfree(&pdev->dev, npct); return -EPROBE_DEFER; } npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip; diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 2aae8a8..7fca6ce 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -1217,7 +1217,6 @@ out_no_rsc_remap: iounmap(spmx->gpio_virtbase); out_no_gpio_remap: platform_set_drvdata(pdev, NULL); - devm_kfree(&pdev->dev, spmx); return ret; } diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index a7ad8c1..309f5b9 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -1121,10 +1121,8 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) upmx->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENOENT; - goto out_no_resource; - } + if (!res) + return -ENOENT; upmx->phybase = res->start; upmx->physize = resource_size(res); @@ -1165,8 +1163,6 @@ out_no_remap: platform_set_drvdata(pdev, NULL); out_no_memregion: release_mem_region(upmx->phybase, upmx->physize); -out_no_resource: - devm_kfree(&pdev->dev, upmx); return ret; } diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 782953a..b17c16c 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_X86) += x86/ +obj-$(CONFIG_OLPC) += olpc/ diff --git a/drivers/platform/olpc/Makefile b/drivers/platform/olpc/Makefile new file mode 100644 index 0000000..dc8b26b --- /dev/null +++ b/drivers/platform/olpc/Makefile @@ -0,0 +1,4 @@ +# +# OLPC XO platform-specific drivers +# +obj-$(CONFIG_OLPC) += olpc-ec.o diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c new file mode 100644 index 0000000..0f9f859 --- /dev/null +++ b/drivers/platform/olpc/olpc-ec.c @@ -0,0 +1,336 @@ +/* + * Generic driver for the OLPC Embedded Controller. + * + * Copyright (C) 2011-2012 One Laptop per Child Foundation. + * + * Licensed under the GPL v2 or later. + */ +#include <linux/completion.h> +#include <linux/debugfs.h> +#include <linux/spinlock.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/olpc-ec.h> +#include <asm/olpc.h> + +struct ec_cmd_desc { + u8 cmd; + u8 *inbuf, *outbuf; + size_t inlen, outlen; + + int err; + struct completion finished; + struct list_head node; + + void *priv; +}; + +struct olpc_ec_priv { + struct olpc_ec_driver *drv; + struct work_struct worker; + struct mutex cmd_lock; + + /* Pending EC commands */ + struct list_head cmd_q; + spinlock_t cmd_q_lock; + + struct dentry *dbgfs_dir; + + /* + * Running an EC command while suspending means we don't always finish + * the command before the machine suspends. This means that the EC + * is expecting the command protocol to finish, but we after a period + * of time (while the OS is asleep) the EC times out and restarts its + * idle loop. Meanwhile, the OS wakes up, thinks it's still in the + * middle of the command protocol, starts throwing random things at + * the EC... and everyone's uphappy. + */ + bool suspended; +}; + +static struct olpc_ec_driver *ec_driver; +static struct olpc_ec_priv *ec_priv; +static void *ec_cb_arg; + +void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg) +{ + ec_driver = drv; + ec_cb_arg = arg; +} +EXPORT_SYMBOL_GPL(olpc_ec_driver_register); + +static void olpc_ec_worker(struct work_struct *w) +{ + struct olpc_ec_priv *ec = container_of(w, struct olpc_ec_priv, worker); + struct ec_cmd_desc *desc = NULL; + unsigned long flags; + + /* Grab the first pending command from the queue */ + spin_lock_irqsave(&ec->cmd_q_lock, flags); + if (!list_empty(&ec->cmd_q)) { + desc = list_first_entry(&ec->cmd_q, struct ec_cmd_desc, node); + list_del(&desc->node); + } + spin_unlock_irqrestore(&ec->cmd_q_lock, flags); + + /* Do we actually have anything to do? */ + if (!desc) + return; + + /* Protect the EC hw with a mutex; only run one cmd at a time */ + mutex_lock(&ec->cmd_lock); + desc->err = ec_driver->ec_cmd(desc->cmd, desc->inbuf, desc->inlen, + desc->outbuf, desc->outlen, ec_cb_arg); + mutex_unlock(&ec->cmd_lock); + + /* Finished, wake up olpc_ec_cmd() */ + complete(&desc->finished); + + /* Run the worker thread again in case there are more cmds pending */ + schedule_work(&ec->worker); +} + +/* + * Throw a cmd descripter onto the list. We now have SMP OLPC machines, so + * locking is pretty critical. + */ +static void queue_ec_descriptor(struct ec_cmd_desc *desc, + struct olpc_ec_priv *ec) +{ + unsigned long flags; + + INIT_LIST_HEAD(&desc->node); + + spin_lock_irqsave(&ec->cmd_q_lock, flags); + list_add_tail(&desc->node, &ec->cmd_q); + spin_unlock_irqrestore(&ec->cmd_q_lock, flags); + + schedule_work(&ec->worker); +} + +int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen) +{ + struct olpc_ec_priv *ec = ec_priv; + struct ec_cmd_desc desc; + + /* Ensure a driver and ec hook have been registered */ + if (WARN_ON(!ec_driver || !ec_driver->ec_cmd)) + return -ENODEV; + + if (!ec) + return -ENOMEM; + + /* Suspending in the middle of a command hoses things really badly */ + if (WARN_ON(ec->suspended)) + return -EBUSY; + + might_sleep(); + + desc.cmd = cmd; + desc.inbuf = inbuf; + desc.outbuf = outbuf; + desc.inlen = inlen; + desc.outlen = outlen; + desc.err = 0; + init_completion(&desc.finished); + + queue_ec_descriptor(&desc, ec); + + /* Timeouts must be handled in the platform-specific EC hook */ + wait_for_completion(&desc.finished); + + /* The worker thread dequeues the cmd; no need to do anything here */ + return desc.err; +} +EXPORT_SYMBOL_GPL(olpc_ec_cmd); + +#ifdef CONFIG_DEBUG_FS + +/* + * debugfs support for "generic commands", to allow sending + * arbitrary EC commands from userspace. + */ + +#define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */ +#define EC_MAX_CMD_REPLY (8) + +static DEFINE_MUTEX(ec_dbgfs_lock); +static unsigned char ec_dbgfs_resp[EC_MAX_CMD_REPLY]; +static unsigned int ec_dbgfs_resp_bytes; + +static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf, + size_t size, loff_t *ppos) +{ + int i, m; + unsigned char ec_cmd[EC_MAX_CMD_ARGS]; + unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; + char cmdbuf[64]; + int ec_cmd_bytes; + + mutex_lock(&ec_dbgfs_lock); + + size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size); + + m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0], + &ec_dbgfs_resp_bytes, &ec_cmd_int[1], &ec_cmd_int[2], + &ec_cmd_int[3], &ec_cmd_int[4], &ec_cmd_int[5]); + if (m < 2 || ec_dbgfs_resp_bytes > EC_MAX_CMD_REPLY) { + /* reset to prevent overflow on read */ + ec_dbgfs_resp_bytes = 0; + + pr_debug("olpc-ec: bad ec cmd: cmd:response-count [arg1 [arg2 ...]]\n"); + size = -EINVAL; + goto out; + } + + /* convert scanf'd ints to char */ + ec_cmd_bytes = m - 2; + for (i = 0; i <= ec_cmd_bytes; i++) + ec_cmd[i] = ec_cmd_int[i]; + + pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %02x %02x %02x %02x %02x, want %d returns\n", + ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], + ec_cmd[3], ec_cmd[4], ec_cmd[5], ec_dbgfs_resp_bytes); + + olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], + ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes); + + pr_debug("olpc-ec: response %02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n", + ec_dbgfs_resp[0], ec_dbgfs_resp[1], ec_dbgfs_resp[2], + ec_dbgfs_resp[3], ec_dbgfs_resp[4], ec_dbgfs_resp[5], + ec_dbgfs_resp[6], ec_dbgfs_resp[7], + ec_dbgfs_resp_bytes); + +out: + mutex_unlock(&ec_dbgfs_lock); + return size; +} + +static ssize_t ec_dbgfs_cmd_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + unsigned int i, r; + char *rp; + char respbuf[64]; + + mutex_lock(&ec_dbgfs_lock); + rp = respbuf; + rp += sprintf(rp, "%02x", ec_dbgfs_resp[0]); + for (i = 1; i < ec_dbgfs_resp_bytes; i++) + rp += sprintf(rp, ", %02x", ec_dbgfs_resp[i]); + mutex_unlock(&ec_dbgfs_lock); + rp += sprintf(rp, "\n"); + + r = rp - respbuf; + return simple_read_from_buffer(buf, size, ppos, respbuf, r); +} + +static const struct file_operations ec_dbgfs_ops = { + .write = ec_dbgfs_cmd_write, + .read = ec_dbgfs_cmd_read, +}; + +static struct dentry *olpc_ec_setup_debugfs(void) +{ + struct dentry *dbgfs_dir; + + dbgfs_dir = debugfs_create_dir("olpc-ec", NULL); + if (IS_ERR_OR_NULL(dbgfs_dir)) + return NULL; + + debugfs_create_file("cmd", 0600, dbgfs_dir, NULL, &ec_dbgfs_ops); + + return dbgfs_dir; +} + +#else + +static struct dentry *olpc_ec_setup_debugfs(void) +{ + return NULL; +} + +#endif /* CONFIG_DEBUG_FS */ + +static int olpc_ec_probe(struct platform_device *pdev) +{ + struct olpc_ec_priv *ec; + int err; + + if (!ec_driver) + return -ENODEV; + + ec = kzalloc(sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + ec->drv = ec_driver; + INIT_WORK(&ec->worker, olpc_ec_worker); + mutex_init(&ec->cmd_lock); + + INIT_LIST_HEAD(&ec->cmd_q); + spin_lock_init(&ec->cmd_q_lock); + + ec_priv = ec; + platform_set_drvdata(pdev, ec); + + err = ec_driver->probe ? ec_driver->probe(pdev) : 0; + if (err) { + ec_priv = NULL; + kfree(ec); + } else { + ec->dbgfs_dir = olpc_ec_setup_debugfs(); + } + + return err; +} + +static int olpc_ec_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct olpc_ec_priv *ec = platform_get_drvdata(pdev); + int err = 0; + + if (ec_driver->suspend) + err = ec_driver->suspend(pdev); + if (!err) + ec->suspended = true; + + return err; +} + +static int olpc_ec_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct olpc_ec_priv *ec = platform_get_drvdata(pdev); + + ec->suspended = false; + return ec_driver->resume ? ec_driver->resume(pdev) : 0; +} + +static const struct dev_pm_ops olpc_ec_pm_ops = { + .suspend_late = olpc_ec_suspend, + .resume_early = olpc_ec_resume, +}; + +static struct platform_driver olpc_ec_plat_driver = { + .probe = olpc_ec_probe, + .driver = { + .name = "olpc-ec", + .pm = &olpc_ec_pm_ops, + }, +}; + +static int __init olpc_ec_init_module(void) +{ + return platform_driver_register(&olpc_ec_plat_driver); +} + +module_init(olpc_ec_init_module); + +MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c index b57ad86..1da13ed 100644 --- a/drivers/platform/x86/xo1-rfkill.c +++ b/drivers/platform/x86/xo1-rfkill.c @@ -12,8 +12,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/rfkill.h> - -#include <asm/olpc.h> +#include <linux/olpc-ec.h> static bool card_blocked; diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 55b10b8..a89a41a 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -17,6 +17,7 @@ #include <linux/power_supply.h> #include <linux/jiffies.h> #include <linux/sched.h> +#include <linux/olpc-ec.h> #include <asm/olpc.h> diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig index c88cbcc..a305731 100644 --- a/drivers/sh/intc/Kconfig +++ b/drivers/sh/intc/Kconfig @@ -1,3 +1,7 @@ +config SH_INTC + def_bool y + select IRQ_DOMAIN + comment "Interrupt controller options" config INTC_USERIMASK diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile index 44f006d..54ec2a0 100644 --- a/drivers/sh/intc/Makefile +++ b/drivers/sh/intc/Makefile @@ -1,4 +1,4 @@ -obj-y := access.o chip.o core.o handle.o virq.o +obj-y := access.o chip.o core.o handle.o irqdomain.o virq.o obj-$(CONFIG_INTC_BALANCING) += balancing.o obj-$(CONFIG_INTC_USERIMASK) += userimask.o diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 7e562cc..2374468 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -25,6 +25,7 @@ #include <linux/stat.h> #include <linux/interrupt.h> #include <linux/sh_intc.h> +#include <linux/irqdomain.h> #include <linux/device.h> #include <linux/syscore_ops.h> #include <linux/list.h> @@ -310,6 +311,8 @@ int __init register_intc_controller(struct intc_desc *desc) BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ + intc_irq_domain_init(d, hw); + /* register the vectors one by one */ for (i = 0; i < hw->nr_vectors; i++) { struct intc_vect *vect = hw->vectors + i; @@ -319,8 +322,8 @@ int __init register_intc_controller(struct intc_desc *desc) if (!vect->enum_id) continue; - res = irq_alloc_desc_at(irq, numa_node_id()); - if (res != irq && res != -EEXIST) { + res = irq_create_identity_mapping(d->domain, irq); + if (unlikely(res)) { pr_err("can't get irq_desc for %d\n", irq); continue; } @@ -340,8 +343,8 @@ int __init register_intc_controller(struct intc_desc *desc) * IRQ support, each vector still needs to have * its own backing irq_desc. */ - res = irq_alloc_desc_at(irq2, numa_node_id()); - if (res != irq2 && res != -EEXIST) { + res = irq_create_identity_mapping(d->domain, irq2); + if (unlikely(res)) { pr_err("can't get irq_desc for %d\n", irq2); continue; } diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h index f034a97..7dff08e 100644 --- a/drivers/sh/intc/internals.h +++ b/drivers/sh/intc/internals.h @@ -1,5 +1,6 @@ #include <linux/sh_intc.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/list.h> #include <linux/kernel.h> #include <linux/types.h> @@ -66,6 +67,7 @@ struct intc_desc_int { unsigned int nr_sense; struct intc_window *window; unsigned int nr_windows; + struct irq_domain *domain; struct irq_chip chip; bool skip_suspend; }; @@ -187,6 +189,9 @@ unsigned long intc_get_ack_handle(unsigned int irq); void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int enable); +/* irqdomain.c */ +void intc_irq_domain_init(struct intc_desc_int *d, struct intc_hw_desc *hw); + /* virq.c */ void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d); void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d); diff --git a/drivers/sh/intc/irqdomain.c b/drivers/sh/intc/irqdomain.c new file mode 100644 index 0000000..3968f1c --- /dev/null +++ b/drivers/sh/intc/irqdomain.c @@ -0,0 +1,68 @@ +/* + * IRQ domain support for SH INTC subsystem + * + * Copyright (C) 2012 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#define pr_fmt(fmt) "intc: " fmt + +#include <linux/irqdomain.h> +#include <linux/sh_intc.h> +#include <linux/export.h> +#include "internals.h" + +/** + * intc_irq_domain_evt_xlate() - Generic xlate for vectored IRQs. + * + * This takes care of exception vector to hwirq translation through + * by way of evt2irq() translation. + * + * Note: For platforms that use a flat vector space without INTEVT this + * basically just mimics irq_domain_xlate_onecell() by way of a nopped + * out evt2irq() implementation. + */ +static int intc_evt_xlate(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (WARN_ON(intsize < 1)) + return -EINVAL; + + *out_hwirq = evt2irq(intspec[0]); + *out_type = IRQ_TYPE_NONE; + + return 0; +} + +static const struct irq_domain_ops intc_evt_ops = { + .xlate = intc_evt_xlate, +}; + +void __init intc_irq_domain_init(struct intc_desc_int *d, + struct intc_hw_desc *hw) +{ + unsigned int irq_base, irq_end; + + /* + * Quick linear revmap check + */ + irq_base = evt2irq(hw->vectors[0].vect); + irq_end = evt2irq(hw->vectors[hw->nr_vectors - 1].vect); + + /* + * Linear domains have a hard-wired assertion that IRQs start at + * 0 in order to make some performance optimizations. Lamely + * restrict the linear case to these conditions here, taking the + * tree penalty for linear cases with non-zero hwirq bases. + */ + if (irq_base == 0 && irq_end == (irq_base + hw->nr_vectors - 1)) + d->domain = irq_domain_add_linear(NULL, hw->nr_vectors, + &intc_evt_ops, NULL); + else + d->domain = irq_domain_add_tree(NULL, &intc_evt_ops, NULL); + + BUG_ON(!d->domain); +} diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c index 0802b6c..2804eaa 100644 --- a/drivers/sh/pfc/pinctrl.c +++ b/drivers/sh/pfc/pinctrl.c @@ -276,7 +276,6 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long config) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); - struct sh_pfc *pfc = pmx->pfc; /* Validate the new type */ if (config >= PINMUX_FLAG_TYPE) @@ -326,20 +325,6 @@ static struct pinctrl_desc sh_pfc_pinctrl_desc = { .confops = &sh_pfc_pinconf_ops, }; -int sh_pfc_register_pinctrl(struct sh_pfc *pfc) -{ - sh_pfc_pmx = kzalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL); - if (unlikely(!sh_pfc_pmx)) - return -ENOMEM; - - spin_lock_init(&sh_pfc_pmx->lock); - - sh_pfc_pmx->pfc = pfc; - - return 0; -} -EXPORT_SYMBOL_GPL(sh_pfc_register_pinctrl); - static inline void __devinit sh_pfc_map_one_gpio(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx, struct pinmux_gpio *gpio, @@ -481,7 +466,6 @@ static int __devexit sh_pfc_pinctrl_remove(struct platform_device *pdev) { struct sh_pfc_pinctrl *pmx = platform_get_drvdata(pdev); - pinctrl_remove_gpio_range(pmx->pctl, &sh_pfc_gpio_range); pinctrl_unregister(pmx->pctl); platform_set_drvdata(pdev, NULL); @@ -507,7 +491,7 @@ static struct platform_device sh_pfc_pinctrl_device = { .id = -1, }; -static int __init sh_pfc_pinctrl_init(void) +static int sh_pfc_pinctrl_init(void) { int rc; @@ -521,10 +505,22 @@ static int __init sh_pfc_pinctrl_init(void) return rc; } +int sh_pfc_register_pinctrl(struct sh_pfc *pfc) +{ + sh_pfc_pmx = kzalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL); + if (unlikely(!sh_pfc_pmx)) + return -ENOMEM; + + spin_lock_init(&sh_pfc_pmx->lock); + + sh_pfc_pmx->pfc = pfc; + + return sh_pfc_pinctrl_init(); +} +EXPORT_SYMBOL_GPL(sh_pfc_register_pinctrl); + static void __exit sh_pfc_pinctrl_exit(void) { platform_driver_unregister(&sh_pfc_pinctrl_driver); } - -subsys_initcall(sh_pfc_pinctrl_init); module_exit(sh_pfc_pinctrl_exit); diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 992275c..2c4bd74 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -27,6 +27,7 @@ #include <linux/uaccess.h> #include <linux/ctype.h> #include <linux/reboot.h> +#include <linux/olpc-ec.h> #include <asm/tsc.h> #include <asm/olpc.h> diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d4d8c94..9be296c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/errno.h> +#include <linux/sh_dma.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> @@ -1410,8 +1411,8 @@ static void work_fn_rx(struct work_struct *work) /* Handle incomplete DMA receive */ struct tty_struct *tty = port->state->port.tty; struct dma_chan *chan = s->chan_rx; - struct sh_desc *sh_desc = container_of(desc, struct sh_desc, - async_tx); + struct shdma_desc *sh_desc = container_of(desc, + struct shdma_desc, async_tx); unsigned long flags; int count; diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index ee0ebac..89dcf15 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -450,7 +450,7 @@ static int dbgp_ehci_startup(void) writel(FLAG_CF, &ehci_regs->configured_flag); /* Wait until the controller is no longer halted */ - loop = 10; + loop = 1000; do { status = readl(&ehci_regs->status); if (!(status & STS_HALT)) diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index a73bea4..c20f96b 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/of.h> #include <mach/bridge-regs.h> /* @@ -192,6 +193,12 @@ static void orion_wdt_shutdown(struct platform_device *pdev) orion_wdt_stop(&orion_wdt); } +static const struct of_device_id orion_wdt_of_match_table[] __devinitdata = { + { .compatible = "marvell,orion-wdt", }, + {}, +}; +MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); + static struct platform_driver orion_wdt_driver = { .probe = orion_wdt_probe, .remove = __devexit_p(orion_wdt_remove), @@ -199,6 +206,7 @@ static struct platform_driver orion_wdt_driver = { .driver = { .owner = THIS_MODULE, .name = "orion_wdt", + .of_match_table = of_match_ptr(orion_wdt_of_match_table), }, }; diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 181fa81..858c971 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -37,7 +37,6 @@ struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO]; */ struct zorro_bus { - struct list_head devices; /* list of devices on this bus */ struct device dev; }; @@ -136,7 +135,6 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) if (!bus) return -ENOMEM; - INIT_LIST_HEAD(&bus->devices); bus->dev.parent = &pdev->dev; dev_set_name(&bus->dev, "zorro"); error = device_register(&bus->dev); @@ -1312,7 +1312,7 @@ EXPORT_SYMBOL(bio_copy_kern); * Note that this code is very hard to test under normal circumstances because * direct-io pins the pages with get_user_pages(). This makes * is_page_cache_freeable return false, and the VM will not clean the pages. - * But other code (eg, pdflush) could clean the pages if they are mapped + * But other code (eg, flusher threads) could clean the pages if they are mapped * pagecache. * * Simply disabling the call to bio_set_pages_dirty() is a good way to test the diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 83baec2..6e8f416 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -324,7 +324,8 @@ static noinline int add_async_extent(struct async_cow *cow, * If this code finds it can't get good compression, it puts an * entry onto the work queue to write the uncompressed bytes. This * makes sure that both compressed inodes and uncompressed inodes - * are written in the same order that pdflush sent them down. + * are written in the same order that the flusher thread sent them + * down. */ static noinline int compress_file_range(struct inode *inode, struct page *locked_page, diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 643335a..051c7fe 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -596,7 +596,7 @@ void btrfs_start_ordered_extent(struct inode *inode, /* * pages in the range can be dirty, clean or writeback. We * start IO on any dirty ones so the wait doesn't stall waiting - * for pdflush to find them + * for the flusher thread to find them */ if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags)) filemap_fdatawrite_range(inode->i_mapping, start, end); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 8c6e61d..f2eb24c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -100,10 +100,6 @@ static void __save_error_info(struct btrfs_fs_info *fs_info) fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR; } -/* NOTE: - * We move write_super stuff at umount in order to avoid deadlock - * for umount hold all lock. - */ static void save_error_info(struct btrfs_fs_info *fs_info) { __save_error_info(fs_info); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b8708f9..e86ae04 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1744,10 +1744,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) device->fs_devices = root->fs_info->fs_devices; - /* - * we don't want write_supers to jump in here with our device - * half setup - */ mutex_lock(&root->fs_info->fs_devices->device_list_mutex); list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices); list_add(&device->dev_alloc_list, diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index f391f1e..e5b7731 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -633,44 +633,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, return dentry; } -int ceph_atomic_open(struct inode *dir, struct dentry *dentry, - struct file *file, unsigned flags, umode_t mode, - int *opened) -{ - int err; - struct dentry *res = NULL; - - if (!(flags & O_CREAT)) { - if (dentry->d_name.len > NAME_MAX) - return -ENAMETOOLONG; - - err = ceph_init_dentry(dentry); - if (err < 0) - return err; - - return ceph_lookup_open(dir, dentry, file, flags, mode, opened); - } - - if (d_unhashed(dentry)) { - res = ceph_lookup(dir, dentry, 0); - if (IS_ERR(res)) - return PTR_ERR(res); - - if (res) - dentry = res; - } - - /* We don't deal with positive dentries here */ - if (dentry->d_inode) - return finish_no_open(file, res); - - *opened |= FILE_CREATED; - err = ceph_lookup_open(dir, dentry, file, flags, mode, opened); - dput(res); - - return err; -} - /* * If we do a create but get no trace back from the MDS, follow up with * a lookup (the VFS expects us to link up the provided dentry). diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 1b81d6c..ecebbc0 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -4,6 +4,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/file.h> +#include <linux/mount.h> #include <linux/namei.h> #include <linux/writeback.h> @@ -106,9 +107,6 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode) } /* - * If the filp already has private_data, that means the file was - * already opened by intent during lookup, and we do nothing. - * * If we already have the requisite capabilities, we can satisfy * the open request locally (no need to request new caps from the * MDS). We do, however, need to inform the MDS (asynchronously) @@ -207,24 +205,29 @@ out: /* - * Do a lookup + open with a single request. - * - * If this succeeds, but some subsequent check in the vfs - * may_open() fails, the struct *file gets cleaned up (i.e. - * ceph_release gets called). So fear not! + * Do a lookup + open with a single request. If we get a non-existent + * file or symlink, return 1 so the VFS can retry. */ -int ceph_lookup_open(struct inode *dir, struct dentry *dentry, +int ceph_atomic_open(struct inode *dir, struct dentry *dentry, struct file *file, unsigned flags, umode_t mode, int *opened) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_request *req; - struct dentry *ret; + struct dentry *dn; int err; - dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", - dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); + dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n", + dir, dentry, dentry->d_name.len, dentry->d_name.name, + d_unhashed(dentry) ? "unhashed" : "hashed", flags, mode); + + if (dentry->d_name.len > NAME_MAX) + return -ENAMETOOLONG; + + err = ceph_init_dentry(dentry); + if (err < 0) + return err; /* do the open */ req = prepare_open_request(dir->i_sb, flags, mode); @@ -241,22 +244,31 @@ int ceph_lookup_open(struct inode *dir, struct dentry *dentry, (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, req); err = ceph_handle_snapdir(req, dentry, err); - if (err) - goto out; - if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) + if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); - if (err) - goto out; - err = finish_open(file, req->r_dentry, ceph_open, opened); -out: - ret = ceph_finish_lookup(req, dentry, err); - ceph_mdsc_put_request(req); - dout("ceph_lookup_open result=%p\n", ret); - if (IS_ERR(ret)) - return PTR_ERR(ret); + if (d_unhashed(dentry)) { + dn = ceph_finish_lookup(req, dentry, err); + if (IS_ERR(dn)) + err = PTR_ERR(dn); + } else { + /* we were given a hashed negative dentry */ + dn = NULL; + } + if (err) + goto out_err; + if (dn || dentry->d_inode == NULL || S_ISLNK(dentry->d_inode->i_mode)) { + /* make vfs retry on splice, ENOENT, or symlink */ + dout("atomic_open finish_no_open on dn %p\n", dn); + err = finish_no_open(file, dn); + } else { + dout("atomic_open finish_open on dn %p\n", dn); + err = finish_open(file, dentry, ceph_open, opened); + } - dput(ret); +out_err: + ceph_mdsc_put_request(req); + dout("atomic_open result=%d\n", err); return err; } diff --git a/fs/ceph/super.h b/fs/ceph/super.h index ebc95cc..66ebe72 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -806,9 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages, loff_t off, size_t len); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern int ceph_open(struct inode *inode, struct file *file); -extern int ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct file *od, unsigned flags, - umode_t mode, int *opened); +extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry, + struct file *file, unsigned flags, umode_t mode, + int *opened); extern int ceph_release(struct inode *inode, struct file *filp); /* dir.c */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 497da5c..977dc0e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -246,6 +246,16 @@ struct smb_version_operations { bool (*can_echo)(struct TCP_Server_Info *); /* send echo request */ int (*echo)(struct TCP_Server_Info *); + /* create directory */ + int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, + struct cifs_sb_info *); + /* set info on created directory */ + void (*mkdir_setinfo)(struct inode *, const char *, + struct cifs_sb_info *, struct cifs_tcon *, + const unsigned int); + /* remove directory */ + int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *, + struct cifs_sb_info *); }; struct smb_version_values { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index cf7fb18..f1bbf83 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -289,18 +289,15 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid, u16 fid, u32 pid_of_opener); extern int CIFSSMBUnixSetPathInfo(const unsigned int xid, - struct cifs_tcon *tcon, char *file_name, + struct cifs_tcon *tcon, const char *file_name, const struct cifs_unix_set_info_args *args, const struct nls_table *nls_codepage, - int remap_special_chars); + int remap); extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *newName, - const struct nls_table *nls_codepage, - int remap_special_chars); + const char *name, struct cifs_sb_info *cifs_sb); extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, const struct nls_table *nls_codepage, - int remap_special_chars); + const char *name, struct cifs_sb_info *cifs_sb); extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, __u16 type, const struct nls_table *nls_codepage, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index cabc7a0..074923c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -948,15 +948,15 @@ DelFileRetry: } int -CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *dirName, const struct nls_table *nls_codepage, - int remap) +CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; int rc = 0; int bytes_returned; int name_len; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; cFYI(1, "In CIFSSMBRmDir"); RmDirRetry: @@ -966,14 +966,15 @@ RmDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, + PATH_MAX, cifs_sb->local_nls, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ - name_len = strnlen(dirName, PATH_MAX); + name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->DirName, dirName, name_len); + strncpy(pSMB->DirName, name, name_len); } pSMB->BufferFormat = 0x04; @@ -992,14 +993,15 @@ RmDirRetry: } int -CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, const struct nls_table *nls_codepage, int remap) +CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) { int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; CREATE_DIRECTORY_RSP *pSMBr = NULL; int bytes_returned; int name_len; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; cFYI(1, "In CIFSSMBMkDir"); MkDirRetry: @@ -1010,7 +1012,8 @@ MkDirRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, - PATH_MAX, nls_codepage, remap); + PATH_MAX, cifs_sb->local_nls, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -5943,7 +5946,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, int CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, - char *fileName, + const char *file_name, const struct cifs_unix_set_info_args *args, const struct nls_table *nls_codepage, int remap) { @@ -5964,14 +5967,14 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fileName, PATH_MAX); + name_len = strnlen(file_name, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, fileName, name_len); + strncpy(pSMB->FileName, file_name, name_len); } params = 6 + name_len; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 35cb6a3..7354877 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1219,16 +1219,153 @@ unlink_out: return rc; } +static int +cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode, + const char *full_path, struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon, const unsigned int xid) +{ + int rc = 0; + struct inode *newinode = NULL; + + if (tcon->unix_ext) + rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, + xid); + else + rc = cifs_get_inode_info(&newinode, full_path, NULL, + inode->i_sb, xid, NULL); + if (rc) + return rc; + + d_instantiate(dentry, newinode); + /* + * setting nlink not necessary except in cases where we failed to get it + * from the server or was set bogus + */ + if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) + set_nlink(dentry->d_inode, 2); + + mode &= ~current_umask(); + /* must turn on setgid bit if parent dir has it */ + if (inode->i_mode & S_ISGID) + mode |= S_ISGID; + + if (tcon->unix_ext) { + struct cifs_unix_set_info_args args = { + .mode = mode, + .ctime = NO_CHANGE_64, + .atime = NO_CHANGE_64, + .mtime = NO_CHANGE_64, + .device = 0, + }; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + args.uid = (__u64)current_fsuid(); + if (inode->i_mode & S_ISGID) + args.gid = (__u64)inode->i_gid; + else + args.gid = (__u64)current_fsgid(); + } else { + args.uid = NO_CHANGE_64; + args.gid = NO_CHANGE_64; + } + CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + } else { + struct TCP_Server_Info *server = tcon->ses->server; + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && + (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) + server->ops->mkdir_setinfo(newinode, full_path, cifs_sb, + tcon, xid); + if (dentry->d_inode) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) + dentry->d_inode->i_mode = (mode | S_IFDIR); + + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + dentry->d_inode->i_uid = current_fsuid(); + if (inode->i_mode & S_ISGID) + dentry->d_inode->i_gid = inode->i_gid; + else + dentry->d_inode->i_gid = + current_fsgid(); + } + } + } + return rc; +} + +static int +cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, + const char *full_path, struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon, const unsigned int xid) +{ + int rc = 0; + u32 oplock = 0; + FILE_UNIX_BASIC_INFO *info = NULL; + struct inode *newinode = NULL; + struct cifs_fattr fattr; + + info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); + if (info == NULL) { + rc = -ENOMEM; + goto posix_mkdir_out; + } + + mode &= ~current_umask(); + rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, + NULL /* netfid */, info, &oplock, full_path, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc == -EOPNOTSUPP) + goto posix_mkdir_out; + else if (rc) { + cFYI(1, "posix mkdir returned 0x%x", rc); + d_drop(dentry); + goto posix_mkdir_out; + } + + if (info->Type == cpu_to_le32(-1)) + /* no return info, go query for it */ + goto posix_mkdir_get_info; + /* + * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if + * need to set uid/gid. + */ + + cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); + cifs_fill_uniqueid(inode->i_sb, &fattr); + newinode = cifs_iget(inode->i_sb, &fattr); + if (!newinode) + goto posix_mkdir_get_info; + + d_instantiate(dentry, newinode); + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, "instantiated dentry %p %s to inode %p", dentry, + dentry->d_name.name, newinode); + + if (newinode->i_nlink != 2) + cFYI(1, "unexpected number of links %d", newinode->i_nlink); +#endif + +posix_mkdir_out: + kfree(info); + return rc; +posix_mkdir_get_info: + rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, + xid); + goto posix_mkdir_out; +} + int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) { - int rc = 0, tmprc; + int rc = 0; unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *tcon; - char *full_path = NULL; - struct inode *newinode = NULL; - struct cifs_fattr fattr; + struct TCP_Server_Info *server; + char *full_path; cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); @@ -1248,145 +1385,29 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { - u32 oplock = 0; - FILE_UNIX_BASIC_INFO *pInfo = - kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); - if (pInfo == NULL) { - rc = -ENOMEM; + rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, + tcon, xid); + if (rc != -EOPNOTSUPP) goto mkdir_out; - } - - mode &= ~current_umask(); - rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, - mode, NULL /* netfid */, pInfo, &oplock, - full_path, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc == -EOPNOTSUPP) { - kfree(pInfo); - goto mkdir_retry_old; - } else if (rc) { - cFYI(1, "posix mkdir returned 0x%x", rc); - d_drop(direntry); - } else { - if (pInfo->Type == cpu_to_le32(-1)) { - /* no return info, go query for it */ - kfree(pInfo); - goto mkdir_get_info; - } -/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need - to set uid/gid */ - - cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); - cifs_fill_uniqueid(inode->i_sb, &fattr); - newinode = cifs_iget(inode->i_sb, &fattr); - if (!newinode) { - kfree(pInfo); - goto mkdir_get_info; - } - - d_instantiate(direntry, newinode); + } -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, "instantiated dentry %p %s to inode %p", - direntry, direntry->d_name.name, newinode); + server = tcon->ses->server; - if (newinode->i_nlink != 2) - cFYI(1, "unexpected number of links %d", - newinode->i_nlink); -#endif - } - kfree(pInfo); + if (!server->ops->mkdir) { + rc = -ENOSYS; goto mkdir_out; } -mkdir_retry_old: + /* BB add setting the equivalent of mode via CreateX w/ACLs */ - rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb); if (rc) { cFYI(1, "cifs_mkdir returned 0x%x", rc); d_drop(direntry); - } else { -mkdir_get_info: - if (tcon->unix_ext) - rc = cifs_get_inode_info_unix(&newinode, full_path, - inode->i_sb, xid); - else - rc = cifs_get_inode_info(&newinode, full_path, NULL, - inode->i_sb, xid, NULL); - - d_instantiate(direntry, newinode); - /* setting nlink not necessary except in cases where we - * failed to get it from the server or was set bogus */ - if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) - set_nlink(direntry->d_inode, 2); - - mode &= ~current_umask(); - /* must turn on setgid bit if parent dir has it */ - if (inode->i_mode & S_ISGID) - mode |= S_ISGID; - - if (tcon->unix_ext) { - struct cifs_unix_set_info_args args = { - .mode = mode, - .ctime = NO_CHANGE_64, - .atime = NO_CHANGE_64, - .mtime = NO_CHANGE_64, - .device = 0, - }; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - args.uid = (__u64)current_fsuid(); - if (inode->i_mode & S_ISGID) - args.gid = (__u64)inode->i_gid; - else - args.gid = (__u64)current_fsgid(); - } else { - args.uid = NO_CHANGE_64; - args.gid = NO_CHANGE_64; - } - CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - } else { - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && - (mode & S_IWUGO) == 0) { - FILE_BASIC_INFO pInfo; - struct cifsInodeInfo *cifsInode; - u32 dosattrs; - - memset(&pInfo, 0, sizeof(pInfo)); - cifsInode = CIFS_I(newinode); - dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; - pInfo.Attributes = cpu_to_le32(dosattrs); - tmprc = CIFSSMBSetPathInfo(xid, tcon, - full_path, &pInfo, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (tmprc == 0) - cifsInode->cifsAttrs = dosattrs; - } - if (direntry->d_inode) { - if (cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_DYNPERM) - direntry->d_inode->i_mode = - (mode | S_IFDIR); - - if (cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_SET_UID) { - direntry->d_inode->i_uid = - current_fsuid(); - if (inode->i_mode & S_ISGID) - direntry->d_inode->i_gid = - inode->i_gid; - else - direntry->d_inode->i_gid = - current_fsgid(); - } - } - } + goto mkdir_out; } + + rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, + xid); mkdir_out: /* * Force revalidate to get parent dir info when needed since cached @@ -1405,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; - struct cifs_tcon *pTcon; + struct cifs_tcon *tcon; + struct TCP_Server_Info *server; char *full_path = NULL; struct cifsInodeInfo *cifsInode; @@ -1425,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) rc = PTR_ERR(tlink); goto rmdir_exit; } - pTcon = tlink_tcon(tlink); + tcon = tlink_tcon(tlink); + server = tcon->ses->server; + + if (!server->ops->rmdir) { + rc = -ENOSYS; + cifs_put_tlink(tlink); + goto rmdir_exit; + } - rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); cifs_put_tlink(tlink); if (!rc) { diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index c40356d..3129ac7 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) #endif } +static void +cifs_mkdir_setinfo(struct inode *inode, const char *full_path, + struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, + const unsigned int xid) +{ + FILE_BASIC_INFO info; + struct cifsInodeInfo *cifsInode; + u32 dosattrs; + int rc; + + memset(&info, 0, sizeof(info)); + cifsInode = CIFS_I(inode); + dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; + info.Attributes = cpu_to_le32(dosattrs); + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc == 0) + cifsInode->cifsAttrs = dosattrs; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -620,6 +641,9 @@ struct smb_version_operations smb1_operations = { .get_srv_inum = cifs_get_srv_inum, .build_path_to_root = cifs_build_path_to_root, .echo = CIFSSMBEcho, + .mkdir = CIFSSMBMkDir, + .mkdir_setinfo = cifs_mkdir_setinfo, + .rmdir = CIFSSMBRmDir, }; struct smb_version_values smb1_values = { diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 1ba5c40..2aa5cb0 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -122,3 +122,42 @@ out: kfree(smb2_data); return rc; } + +int +smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) +{ + return smb2_open_op_close(xid, tcon, cifs_sb, name, + FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, + CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); +} + +void +smb2_mkdir_setinfo(struct inode *inode, const char *name, + struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, + const unsigned int xid) +{ + FILE_BASIC_INFO data; + struct cifsInodeInfo *cifs_i; + u32 dosattrs; + int tmprc; + + memset(&data, 0, sizeof(data)); + cifs_i = CIFS_I(inode); + dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; + data.Attributes = cpu_to_le32(dosattrs); + tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name, + FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, + CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); + if (tmprc == 0) + cifs_i->cifsAttrs = dosattrs; +} + +int +smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, + struct cifs_sb_info *cifs_sb) +{ + return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, + 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE, + NULL, SMB2_OP_DELETE); +} diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 410cf92..826209b 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -318,6 +318,9 @@ struct smb_version_operations smb21_operations = { .query_path_info = smb2_query_path_info, .get_srv_inum = smb2_get_srv_inum, .build_path_to_root = smb2_build_path_to_root, + .mkdir = smb2_mkdir, + .mkdir_setinfo = smb2_mkdir_setinfo, + .rmdir = smb2_rmdir, }; struct smb_version_values smb21_values = { diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 902bbe2..bfaa7b1 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -52,6 +52,14 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, FILE_ALL_INFO *data, bool *adjust_tz); +extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, + const char *name, struct cifs_sb_info *cifs_sb); +extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, + struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon, const unsigned int xid); +extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, + const char *name, struct cifs_sb_info *cifs_sb); + /* * SMB2 Worker functions - most of protocol specific implementation details * are contained within these calls. diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 989e034..cfb4b9f 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -385,8 +385,6 @@ struct ecryptfs_msg_ctx { struct mutex mux; }; -struct ecryptfs_daemon; - struct ecryptfs_daemon { #define ECRYPTFS_DAEMON_IN_READ 0x00000001 #define ECRYPTFS_DAEMON_IN_POLL 0x00000002 @@ -394,10 +392,7 @@ struct ecryptfs_daemon { #define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008 u32 flags; u32 num_queued_msg_ctx; - struct pid *pid; - uid_t euid; - struct user_namespace *user_ns; - struct task_struct *task; + struct file *file; struct mutex mux; struct list_head msg_ctx_out_queue; wait_queue_head_t wait; @@ -554,6 +549,8 @@ extern struct kmem_cache *ecryptfs_key_tfm_cache; struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb); void ecryptfs_i_size_init(const char *page_virt, struct inode *inode); +int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, + struct inode *ecryptfs_inode); int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, size_t *decrypted_name_size, struct dentry *ecryptfs_dentry, @@ -607,13 +604,8 @@ int ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode); -int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns, - struct pid *pid); -int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns, - struct pid *pid); -int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, - struct user_namespace *user_ns, struct pid *pid, - u32 seq); +int ecryptfs_process_response(struct ecryptfs_daemon *daemon, + struct ecryptfs_message *msg, u32 seq); int ecryptfs_send_message(char *data, int data_len, struct ecryptfs_msg_ctx **msg_ctx); int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx, @@ -658,8 +650,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, struct inode *ecryptfs_inode); struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index); int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon); -int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid, - struct user_namespace *user_ns); +int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon); int ecryptfs_parse_packet_length(unsigned char *data, size_t *size, size_t *length_size); int ecryptfs_write_packet_length(char *dest, size_t size, @@ -671,8 +662,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, u16 msg_flags, struct ecryptfs_daemon *daemon); void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx); int -ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, - struct user_namespace *user_ns, struct pid *pid); +ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file); int ecryptfs_init_kthread(void); void ecryptfs_destroy_kthread(void); int ecryptfs_privileged_open(struct file **lower_file, diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 2b17f2f..44ce5c6 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -138,29 +138,50 @@ out: return rc; } -static void ecryptfs_vma_close(struct vm_area_struct *vma) -{ - filemap_write_and_wait(vma->vm_file->f_mapping); -} - -static const struct vm_operations_struct ecryptfs_file_vm_ops = { - .close = ecryptfs_vma_close, - .fault = filemap_fault, -}; +struct kmem_cache *ecryptfs_file_info_cache; -static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) +static int read_or_initialize_metadata(struct dentry *dentry) { + struct inode *inode = dentry->d_inode; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct ecryptfs_crypt_stat *crypt_stat; int rc; - rc = generic_file_mmap(file, vma); + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + mount_crypt_stat = &ecryptfs_superblock_to_private( + inode->i_sb)->mount_crypt_stat; + mutex_lock(&crypt_stat->cs_mutex); + + if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && + crypt_stat->flags & ECRYPTFS_KEY_VALID) { + rc = 0; + goto out; + } + + rc = ecryptfs_read_metadata(dentry); if (!rc) - vma->vm_ops = &ecryptfs_file_vm_ops; + goto out; + + if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) { + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + rc = 0; + goto out; + } + if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) && + !i_size_read(ecryptfs_inode_to_lower(inode))) { + rc = ecryptfs_initialize_file(dentry, inode); + if (!rc) + goto out; + } + + rc = -EIO; +out: + mutex_unlock(&crypt_stat->cs_mutex); return rc; } -struct kmem_cache *ecryptfs_file_info_cache; - /** * ecryptfs_open * @inode: inode speciying file to open @@ -236,32 +257,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file) rc = 0; goto out; } - mutex_lock(&crypt_stat->cs_mutex); - if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) - || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { - rc = ecryptfs_read_metadata(ecryptfs_dentry); - if (rc) { - ecryptfs_printk(KERN_DEBUG, - "Valid headers not found\n"); - if (!(mount_crypt_stat->flags - & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { - rc = -EIO; - printk(KERN_WARNING "Either the lower file " - "is not in a valid eCryptfs format, " - "or the key could not be retrieved. " - "Plaintext passthrough mode is not " - "enabled; returning -EIO\n"); - mutex_unlock(&crypt_stat->cs_mutex); - goto out_put; - } - rc = 0; - crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED - | ECRYPTFS_ENCRYPTED); - mutex_unlock(&crypt_stat->cs_mutex); - goto out; - } - } - mutex_unlock(&crypt_stat->cs_mutex); + rc = read_or_initialize_metadata(ecryptfs_dentry); + if (rc) + goto out_put; ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); @@ -292,15 +290,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file) static int ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) { - int rc = 0; - - rc = generic_file_fsync(file, start, end, datasync); - if (rc) - goto out; - rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, - datasync); -out: - return rc; + return vfs_fsync(ecryptfs_file_to_lower(file), datasync); } static int ecryptfs_fasync(int fd, struct file *file, int flag) @@ -369,7 +359,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = ecryptfs_file_mmap, + .mmap = generic_file_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index c3ca12c..534b129 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -143,6 +143,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, return 0; } +static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, + struct inode *inode) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); + struct dentry *lower_dir_dentry; + int rc; + + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + rc = vfs_unlink(lower_dir_inode, lower_dentry); + if (rc) { + printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); + goto out_unlock; + } + fsstack_copy_attr_times(dir, lower_dir_inode); + set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); + inode->i_ctime = dir->i_ctime; + d_drop(dentry); +out_unlock: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + return rc; +} + /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs @@ -182,8 +207,10 @@ ecryptfs_do_create(struct inode *directory_inode, } inode = __ecryptfs_get_inode(lower_dentry->d_inode, directory_inode->i_sb); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + vfs_unlink(lower_dir_dentry->d_inode, lower_dentry); goto out_lock; + } fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); out_lock: @@ -200,8 +227,8 @@ out: * * Returns zero on success */ -static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, - struct inode *ecryptfs_inode) +int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, + struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; @@ -264,7 +291,9 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { - drop_nlink(ecryptfs_inode); + ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, + ecryptfs_inode); + make_bad_inode(ecryptfs_inode); unlock_new_inode(ecryptfs_inode); iput(ecryptfs_inode); goto out; @@ -466,27 +495,7 @@ out_lock: static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { - int rc = 0; - struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); - struct dentry *lower_dir_dentry; - - dget(lower_dentry); - lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_unlink(lower_dir_inode, lower_dentry); - if (rc) { - printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); - goto out_unlock; - } - fsstack_copy_attr_times(dir, lower_dir_inode); - set_nlink(dentry->d_inode, - ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink); - dentry->d_inode->i_ctime = dir->i_ctime; - d_drop(dentry); -out_unlock: - unlock_dir(lower_dir_dentry); - dput(lower_dentry); - return rc; + return ecryptfs_do_unlink(dir, dentry, dentry->d_inode); } static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, @@ -961,12 +970,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) goto out; } - if (S_ISREG(inode->i_mode)) { - rc = filemap_write_and_wait(inode->i_mapping); - if (rc) - goto out; - fsstack_copy_attr_all(inode, lower_inode); - } memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 1c0b3b6..2768138 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -279,6 +279,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, char *fnek_src; char *cipher_key_bytes_src; char *fn_cipher_key_bytes_src; + u8 cipher_code; *check_ruid = 0; @@ -420,6 +421,18 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, && !fn_cipher_key_bytes_set) mount_crypt_stat->global_default_fn_cipher_key_bytes = mount_crypt_stat->global_default_cipher_key_size; + + cipher_code = ecryptfs_code_for_cipher_string( + mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); + if (!cipher_code) { + ecryptfs_printk(KERN_ERR, + "eCryptfs doesn't support cipher: %s", + mount_crypt_stat->global_default_cipher_name); + rc = -EINVAL; + goto out; + } + mutex_lock(&key_tfm_list_mutex); if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, NULL)) { @@ -540,6 +553,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags } ecryptfs_set_superblock_lower(s, path.dentry->d_sb); + + /** + * Set the POSIX ACL flag based on whether they're enabled in the lower + * mount. Force a read-only eCryptfs mount if the lower mount is ro. + * Allow a ro eCryptfs mount even when the lower mount is rw. + */ + s->s_flags = flags & ~MS_POSIXACL; + s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL); + s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index a750f95..b29bb8b 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -32,8 +32,8 @@ static struct mutex ecryptfs_msg_ctx_lists_mux; static struct hlist_head *ecryptfs_daemon_hash; struct mutex ecryptfs_daemon_hash_mux; static int ecryptfs_hash_bits; -#define ecryptfs_uid_hash(uid) \ - hash_long((unsigned long)uid, ecryptfs_hash_bits) +#define ecryptfs_current_euid_hash(uid) \ + hash_long((unsigned long)current_euid(), ecryptfs_hash_bits) static u32 ecryptfs_msg_counter; static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; @@ -105,26 +105,24 @@ void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx) /** * ecryptfs_find_daemon_by_euid - * @euid: The effective user id which maps to the desired daemon id - * @user_ns: The namespace in which @euid applies * @daemon: If return value is zero, points to the desired daemon pointer * * Must be called with ecryptfs_daemon_hash_mux held. * - * Search the hash list for the given user id. + * Search the hash list for the current effective user id. * * Returns zero if the user id exists in the list; non-zero otherwise. */ -int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid, - struct user_namespace *user_ns) +int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) { struct hlist_node *elem; int rc; hlist_for_each_entry(*daemon, elem, - &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)], - euid_chain) { - if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) { + &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()], + euid_chain) { + if ((*daemon)->file->f_cred->euid == current_euid() && + (*daemon)->file->f_cred->user_ns == current_user_ns()) { rc = 0; goto out; } @@ -137,9 +135,7 @@ out: /** * ecryptfs_spawn_daemon - Create and initialize a new daemon struct * @daemon: Pointer to set to newly allocated daemon struct - * @euid: Effective user id for the daemon - * @user_ns: The namespace in which @euid applies - * @pid: Process id for the daemon + * @file: File used when opening /dev/ecryptfs * * Must be called ceremoniously while in possession of * ecryptfs_sacred_daemon_hash_mux @@ -147,8 +143,7 @@ out: * Returns zero on success; non-zero otherwise */ int -ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, - struct user_namespace *user_ns, struct pid *pid) +ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file) { int rc = 0; @@ -159,16 +154,13 @@ ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, "GFP_KERNEL memory\n", __func__, sizeof(**daemon)); goto out; } - (*daemon)->euid = euid; - (*daemon)->user_ns = get_user_ns(user_ns); - (*daemon)->pid = get_pid(pid); - (*daemon)->task = current; + (*daemon)->file = file; mutex_init(&(*daemon)->mux); INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue); init_waitqueue_head(&(*daemon)->wait); (*daemon)->num_queued_msg_ctx = 0; hlist_add_head(&(*daemon)->euid_chain, - &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]); + &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]); out: return rc; } @@ -188,9 +180,6 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ) || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) { rc = -EBUSY; - printk(KERN_WARNING "%s: Attempt to destroy daemon with pid " - "[0x%p], but it is in the midst of a read or a poll\n", - __func__, daemon->pid); mutex_unlock(&daemon->mux); goto out; } @@ -203,12 +192,6 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) ecryptfs_msg_ctx_alloc_to_free(msg_ctx); } hlist_del(&daemon->euid_chain); - if (daemon->task) - wake_up_process(daemon->task); - if (daemon->pid) - put_pid(daemon->pid); - if (daemon->user_ns) - put_user_ns(daemon->user_ns); mutex_unlock(&daemon->mux); kzfree(daemon); out: @@ -216,42 +199,9 @@ out: } /** - * ecryptfs_process_quit - * @euid: The user ID owner of the message - * @user_ns: The namespace in which @euid applies - * @pid: The process ID for the userspace program that sent the - * message - * - * Deletes the corresponding daemon for the given euid and pid, if - * it is the registered that is requesting the deletion. Returns zero - * after deleting the desired daemon; non-zero otherwise. - */ -int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns, - struct pid *pid) -{ - struct ecryptfs_daemon *daemon; - int rc; - - mutex_lock(&ecryptfs_daemon_hash_mux); - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns); - if (rc || !daemon) { - rc = -EINVAL; - printk(KERN_ERR "Received request from user [%d] to " - "unregister unrecognized daemon [0x%p]\n", euid, pid); - goto out_unlock; - } - rc = ecryptfs_exorcise_daemon(daemon); -out_unlock: - mutex_unlock(&ecryptfs_daemon_hash_mux); - return rc; -} - -/** * ecryptfs_process_reponse * @msg: The ecryptfs message received; the caller should sanity check * msg->data_len and free the memory - * @pid: The process ID of the userspace application that sent the - * message * @seq: The sequence number of the message; must match the sequence * number for the existing message context waiting for this * response @@ -270,16 +220,11 @@ out_unlock: * * Returns zero on success; non-zero otherwise */ -int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, - struct user_namespace *user_ns, struct pid *pid, - u32 seq) +int ecryptfs_process_response(struct ecryptfs_daemon *daemon, + struct ecryptfs_message *msg, u32 seq) { - struct ecryptfs_daemon *uninitialized_var(daemon); struct ecryptfs_msg_ctx *msg_ctx; size_t msg_size; - struct nsproxy *nsproxy; - struct user_namespace *tsk_user_ns; - uid_t ctx_euid; int rc; if (msg->index >= ecryptfs_message_buf_len) { @@ -292,51 +237,6 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, } msg_ctx = &ecryptfs_msg_ctx_arr[msg->index]; mutex_lock(&msg_ctx->mux); - mutex_lock(&ecryptfs_daemon_hash_mux); - rcu_read_lock(); - nsproxy = task_nsproxy(msg_ctx->task); - if (nsproxy == NULL) { - rc = -EBADMSG; - printk(KERN_ERR "%s: Receiving process is a zombie. Dropping " - "message.\n", __func__); - rcu_read_unlock(); - mutex_unlock(&ecryptfs_daemon_hash_mux); - goto wake_up; - } - tsk_user_ns = __task_cred(msg_ctx->task)->user_ns; - ctx_euid = task_euid(msg_ctx->task); - rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns); - rcu_read_unlock(); - mutex_unlock(&ecryptfs_daemon_hash_mux); - if (rc) { - rc = -EBADMSG; - printk(KERN_WARNING "%s: User [%d] received a " - "message response from process [0x%p] but does " - "not have a registered daemon\n", __func__, - ctx_euid, pid); - goto wake_up; - } - if (ctx_euid != euid) { - rc = -EBADMSG; - printk(KERN_WARNING "%s: Received message from user " - "[%d]; expected message from user [%d]\n", __func__, - euid, ctx_euid); - goto unlock; - } - if (tsk_user_ns != user_ns) { - rc = -EBADMSG; - printk(KERN_WARNING "%s: Received message from user_ns " - "[0x%p]; expected message from user_ns [0x%p]\n", - __func__, user_ns, tsk_user_ns); - goto unlock; - } - if (daemon->pid != pid) { - rc = -EBADMSG; - printk(KERN_ERR "%s: User [%d] sent a message response " - "from an unrecognized process [0x%p]\n", - __func__, ctx_euid, pid); - goto unlock; - } if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) { rc = -EINVAL; printk(KERN_WARNING "%s: Desired context element is not " @@ -359,9 +259,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, } memcpy(msg_ctx->msg, msg, msg_size); msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE; - rc = 0; -wake_up: wake_up_process(msg_ctx->task); + rc = 0; unlock: mutex_unlock(&msg_ctx->mux); out: @@ -383,14 +282,11 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx) { struct ecryptfs_daemon *daemon; - uid_t euid = current_euid(); int rc; - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); + rc = ecryptfs_find_daemon_by_euid(&daemon); if (rc || !daemon) { rc = -ENOTCONN; - printk(KERN_ERR "%s: User [%d] does not have a daemon " - "registered\n", __func__, euid); goto out; } mutex_lock(&ecryptfs_msg_ctx_lists_mux); diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index c0038f6..412e6ed 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -33,7 +33,7 @@ static atomic_t ecryptfs_num_miscdev_opens; /** * ecryptfs_miscdev_poll - * @file: dev file (ignored) + * @file: dev file * @pt: dev poll table (ignored) * * Returns the poll mask @@ -41,20 +41,10 @@ static atomic_t ecryptfs_num_miscdev_opens; static unsigned int ecryptfs_miscdev_poll(struct file *file, poll_table *pt) { - struct ecryptfs_daemon *daemon; + struct ecryptfs_daemon *daemon = file->private_data; unsigned int mask = 0; - uid_t euid = current_euid(); - int rc; - mutex_lock(&ecryptfs_daemon_hash_mux); - /* TODO: Just use file->private_data? */ - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - if (rc || !daemon) { - mutex_unlock(&ecryptfs_daemon_hash_mux); - return -EINVAL; - } mutex_lock(&daemon->mux); - mutex_unlock(&ecryptfs_daemon_hash_mux); if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { printk(KERN_WARNING "%s: Attempt to poll on zombified " "daemon\n", __func__); @@ -79,7 +69,7 @@ out_unlock_daemon: /** * ecryptfs_miscdev_open * @inode: inode of miscdev handle (ignored) - * @file: file for miscdev handle (ignored) + * @file: file for miscdev handle * * Returns zero on success; non-zero otherwise */ @@ -87,7 +77,6 @@ static int ecryptfs_miscdev_open(struct inode *inode, struct file *file) { struct ecryptfs_daemon *daemon = NULL; - uid_t euid = current_euid(); int rc; mutex_lock(&ecryptfs_daemon_hash_mux); @@ -98,30 +87,20 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) "count; rc = [%d]\n", __func__, rc); goto out_unlock_daemon_list; } - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - if (rc || !daemon) { - rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(), - task_pid(current)); - if (rc) { - printk(KERN_ERR "%s: Error attempting to spawn daemon; " - "rc = [%d]\n", __func__, rc); - goto out_module_put_unlock_daemon_list; - } - } - mutex_lock(&daemon->mux); - if (daemon->pid != task_pid(current)) { + rc = ecryptfs_find_daemon_by_euid(&daemon); + if (!rc) { rc = -EINVAL; - printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], " - "but pid [0x%p] has attempted to open the handle " - "instead\n", __func__, daemon->pid, daemon->euid, - task_pid(current)); - goto out_unlock_daemon; + goto out_unlock_daemon_list; + } + rc = ecryptfs_spawn_daemon(&daemon, file); + if (rc) { + printk(KERN_ERR "%s: Error attempting to spawn daemon; " + "rc = [%d]\n", __func__, rc); + goto out_module_put_unlock_daemon_list; } + mutex_lock(&daemon->mux); if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) { rc = -EBUSY; - printk(KERN_ERR "%s: Miscellaneous device handle may only be " - "opened once per daemon; pid [0x%p] already has this " - "handle open\n", __func__, daemon->pid); goto out_unlock_daemon; } daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN; @@ -140,7 +119,7 @@ out_unlock_daemon_list: /** * ecryptfs_miscdev_release * @inode: inode of fs/ecryptfs/euid handle (ignored) - * @file: file for fs/ecryptfs/euid handle (ignored) + * @file: file for fs/ecryptfs/euid handle * * This keeps the daemon registered until the daemon sends another * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters. @@ -150,20 +129,18 @@ out_unlock_daemon_list: static int ecryptfs_miscdev_release(struct inode *inode, struct file *file) { - struct ecryptfs_daemon *daemon = NULL; - uid_t euid = current_euid(); + struct ecryptfs_daemon *daemon = file->private_data; int rc; - mutex_lock(&ecryptfs_daemon_hash_mux); - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - if (rc || !daemon) - daemon = file->private_data; mutex_lock(&daemon->mux); BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN)); daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN; atomic_dec(&ecryptfs_num_miscdev_opens); mutex_unlock(&daemon->mux); + + mutex_lock(&ecryptfs_daemon_hash_mux); rc = ecryptfs_exorcise_daemon(daemon); + mutex_unlock(&ecryptfs_daemon_hash_mux); if (rc) { printk(KERN_CRIT "%s: Fatal error whilst attempting to " "shut down daemon; rc = [%d]. Please report this " @@ -171,7 +148,6 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) BUG(); } module_put(THIS_MODULE); - mutex_unlock(&ecryptfs_daemon_hash_mux); return rc; } @@ -248,7 +224,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, /** * ecryptfs_miscdev_read - format and send message from queue - * @file: fs/ecryptfs/euid miscdevfs handle (ignored) + * @file: miscdevfs handle * @buf: User buffer into which to copy the next message on the daemon queue * @count: Amount of space available in @buf * @ppos: Offset in file (ignored) @@ -262,43 +238,27 @@ static ssize_t ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct ecryptfs_daemon *daemon; + struct ecryptfs_daemon *daemon = file->private_data; struct ecryptfs_msg_ctx *msg_ctx; size_t packet_length_size; char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE]; size_t i; size_t total_length; - uid_t euid = current_euid(); int rc; - mutex_lock(&ecryptfs_daemon_hash_mux); - /* TODO: Just use file->private_data? */ - rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); - if (rc || !daemon) { - mutex_unlock(&ecryptfs_daemon_hash_mux); - return -EINVAL; - } mutex_lock(&daemon->mux); - if (task_pid(current) != daemon->pid) { - mutex_unlock(&daemon->mux); - mutex_unlock(&ecryptfs_daemon_hash_mux); - return -EPERM; - } if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { rc = 0; - mutex_unlock(&ecryptfs_daemon_hash_mux); printk(KERN_WARNING "%s: Attempt to read from zombified " "daemon\n", __func__); goto out_unlock_daemon; } if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) { rc = 0; - mutex_unlock(&ecryptfs_daemon_hash_mux); goto out_unlock_daemon; } /* This daemon will not go away so long as this flag is set */ daemon->flags |= ECRYPTFS_DAEMON_IN_READ; - mutex_unlock(&ecryptfs_daemon_hash_mux); check_list: if (list_empty(&daemon->msg_ctx_out_queue)) { mutex_unlock(&daemon->mux); @@ -382,16 +342,12 @@ out_unlock_daemon: * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon * @data: Bytes comprising struct ecryptfs_message * @data_size: sizeof(struct ecryptfs_message) + data len - * @euid: Effective user id of miscdevess sending the miscdev response - * @user_ns: The namespace in which @euid applies - * @pid: Miscdevess id of miscdevess sending the miscdev response * @seq: Sequence number for miscdev response packet * * Returns zero on success; non-zero otherwise */ -static int ecryptfs_miscdev_response(char *data, size_t data_size, - uid_t euid, struct user_namespace *user_ns, - struct pid *pid, u32 seq) +static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data, + size_t data_size, u32 seq) { struct ecryptfs_message *msg = (struct ecryptfs_message *)data; int rc; @@ -403,7 +359,7 @@ static int ecryptfs_miscdev_response(char *data, size_t data_size, rc = -EINVAL; goto out; } - rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq); + rc = ecryptfs_process_response(daemon, msg, seq); if (rc) printk(KERN_ERR "Error processing response message; rc = [%d]\n", rc); @@ -413,7 +369,7 @@ out: /** * ecryptfs_miscdev_write - handle write to daemon miscdev handle - * @file: File for misc dev handle (ignored) + * @file: File for misc dev handle * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) @@ -428,7 +384,6 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, u32 seq; size_t packet_size, packet_size_length; char *data; - uid_t euid = current_euid(); unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE]; ssize_t rc; @@ -488,10 +443,9 @@ memdup: } memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE); seq = be32_to_cpu(counter_nbo); - rc = ecryptfs_miscdev_response( + rc = ecryptfs_miscdev_response(file->private_data, &data[PKT_LEN_OFFSET + packet_size_length], - packet_size, euid, current_user_ns(), - task_pid(current), seq); + packet_size, seq); if (rc) { printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%zd]\n", diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index a46b3a8..bd1d57f 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -66,18 +66,6 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) { int rc; - /* - * Refuse to write the page out if we are called from reclaim context - * since our writepage() path may potentially allocate memory when - * calling into the lower fs vfs_write() which may in turn invoke - * us again. - */ - if (current->flags & PF_MEMALLOC) { - redirty_page_for_writepage(wbc, page); - rc = 0; - goto out; - } - rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " @@ -498,7 +486,6 @@ static int ecryptfs_write_end(struct file *file, struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc; - int need_unlock_page = 1; ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); @@ -519,26 +506,26 @@ static int ecryptfs_write_end(struct file *file, "zeros in page with index = [0x%.16lx]\n", index); goto out; } - set_page_dirty(page); - unlock_page(page); - need_unlock_page = 0; + rc = ecryptfs_encrypt_page(page); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " + "index [0x%.16lx])\n", index); + goto out; + } if (pos + copied > i_size_read(ecryptfs_inode)) { i_size_write(ecryptfs_inode, pos + copied); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " "[0x%.16llx]\n", (unsigned long long)i_size_read(ecryptfs_inode)); - balance_dirty_pages_ratelimited(mapping); - rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); - if (rc) { - printk(KERN_ERR "Error writing inode size to metadata; " - "rc = [%d]\n", rc); - goto out; - } } - rc = copied; + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); + if (rc) + printk(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + else + rc = copied; out: - if (need_unlock_page) - unlock_page(page); + unlock_page(page); page_cache_release(page); return rc; } diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 5badb0c..1562c27 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -37,15 +37,12 @@ #define EXOFS_DBGMSG2(M...) do {} while (0) -enum {MAX_PAGES_KMALLOC = PAGE_SIZE / sizeof(struct page *), }; - unsigned exofs_max_io_pages(struct ore_layout *layout, unsigned expected_pages) { - unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC); + unsigned pages = min_t(unsigned, expected_pages, + layout->max_io_length / PAGE_SIZE); - /* TODO: easily support bio chaining */ - pages = min_t(unsigned, pages, layout->max_io_length / PAGE_SIZE); return pages; } @@ -101,7 +98,8 @@ static void _pcol_reset(struct page_collect *pcol) * it might not end here. don't be left with nothing */ if (!pcol->expected_pages) - pcol->expected_pages = MAX_PAGES_KMALLOC; + pcol->expected_pages = + exofs_max_io_pages(&pcol->sbi->layout, ~0); } static int pcol_try_alloc(struct page_collect *pcol) @@ -389,6 +387,8 @@ static int readpage_strip(void *data, struct page *page) size_t len; int ret; + BUG_ON(!PageLocked(page)); + /* FIXME: Just for debugging, will be removed */ if (PageUptodate(page)) EXOFS_ERR("PageUptodate(0x%lx, 0x%lx)\n", pcol->inode->i_ino, @@ -572,8 +572,16 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) if (!pcol->that_locked_page || (pcol->that_locked_page->index != index)) { - struct page *page = find_get_page(pcol->inode->i_mapping, index); + struct page *page; + loff_t i_size = i_size_read(pcol->inode); + + if (offset >= i_size) { + *uptodate = true; + EXOFS_DBGMSG("offset >= i_size index=0x%lx\n", index); + return ZERO_PAGE(0); + } + page = find_get_page(pcol->inode->i_mapping, index); if (!page) { page = find_or_create_page(pcol->inode->i_mapping, index, GFP_NOFS); @@ -602,12 +610,13 @@ static void __r4w_put_page(void *priv, struct page *page) { struct page_collect *pcol = priv; - if (pcol->that_locked_page != page) { + if ((pcol->that_locked_page != page) && (ZERO_PAGE(0) != page)) { EXOFS_DBGMSG("index=0x%lx\n", page->index); page_cache_release(page); return; } - EXOFS_DBGMSG("that_locked_page index=0x%lx\n", page->index); + EXOFS_DBGMSG("that_locked_page index=0x%lx\n", + ZERO_PAGE(0) == page ? -1 : page->index); } static const struct _ore_r4w_op _r4w_op = { diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c index 24a49d4..1585db1 100644 --- a/fs/exofs/ore.c +++ b/fs/exofs/ore.c @@ -837,11 +837,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp) bio->bi_rw |= REQ_WRITE; } - osd_req_write(or, _ios_obj(ios, dev), per_dev->offset, - bio, per_dev->length); + osd_req_write(or, _ios_obj(ios, cur_comp), + per_dev->offset, bio, per_dev->length); ORE_DBGMSG("write(0x%llx) offset=0x%llx " "length=0x%llx dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), _LLU(per_dev->offset), _LLU(per_dev->length), dev); } else if (ios->kern_buff) { @@ -853,20 +853,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp) (ios->si.unit_off + ios->length > ios->layout->stripe_unit)); - ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev), + ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp), per_dev->offset, ios->kern_buff, ios->length); if (unlikely(ret)) goto out; ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx " "length=0x%llx dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), _LLU(per_dev->offset), _LLU(ios->length), per_dev->dev); } else { - osd_req_set_attributes(or, _ios_obj(ios, dev)); + osd_req_set_attributes(or, _ios_obj(ios, cur_comp)); ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n", - _LLU(_ios_obj(ios, dev)->id), + _LLU(_ios_obj(ios, cur_comp)->id), ios->out_attr_len, dev); } diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 4337836..dde41a7 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -400,8 +400,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait) ret = ore_write(ios); if (unlikely(ret)) EXOFS_ERR("%s: ore_write failed.\n", __func__); - else - sb->s_dirt = 0; unlock_super(sb); @@ -412,14 +410,6 @@ out: return ret; } -static void exofs_write_super(struct super_block *sb) -{ - if (!(sb->s_flags & MS_RDONLY)) - exofs_sync_fs(sb, 1); - else - sb->s_dirt = 0; -} - static void _exofs_print_device(const char *msg, const char *dev_path, struct osd_dev *od, u64 pid) { @@ -952,7 +942,6 @@ static const struct super_operations exofs_sops = { .write_inode = exofs_write_inode, .evict_inode = exofs_evict_inode, .put_super = exofs_put_super, - .write_super = exofs_write_super, .sync_fs = exofs_sync_fs, .statfs = exofs_statfs, }; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 9a4a5c4..a075973 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3459,14 +3459,6 @@ ext3_reserve_inode_write(handle_t *handle, struct inode *inode, * inode out, but prune_icache isn't a user-visible syncing function. * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) * we start and wait on commits. - * - * Is this efficient/effective? Well, we're being nice to the system - * by cleaning up our inodes proactively so they can be reaped - * without I/O. But we are potentially leaving up to five seconds' - * worth of inodes floating about which prune_icache wants us to - * write out. One way to fix that would be to get prune_icache() - * to do a write_super() to free up some memory. It has the desired - * effect. */ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) { diff --git a/fs/ext3/super.c b/fs/ext3/super.c index ff9bcdc..8c892e9 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -64,11 +64,6 @@ static int ext3_freeze(struct super_block *sb); /* * Wrappers for journal_start/end. - * - * The only special thing we need to do here is to make sure that all - * journal_end calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate. */ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) { @@ -90,12 +85,6 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) return journal_start(journal, nblocks); } -/* - * The only special thing we need to do here is to make sure that all - * journal_stop calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate. - */ int __ext3_journal_stop(const char *where, handle_t *handle) { struct super_block *sb; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 6324f74e..dff171c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1970,7 +1970,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate); * This function can get called via... * - ext4_da_writepages after taking page lock (have journal handle) * - journal_submit_inode_data_buffers (no journal handle) - * - shrink_page_list via pdflush (no journal handle) + * - shrink_page_list via the kswapd/direct reclaim (no journal handle) * - grab_page_cache when doing write_begin (have journal handle) * * We don't do any block allocation in this function. If we have page with @@ -4589,14 +4589,6 @@ static int ext4_expand_extra_isize(struct inode *inode, * inode out, but prune_icache isn't a user-visible syncing function. * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) * we start and wait on commits. - * - * Is this efficient/effective? Well, we're being nice to the system - * by cleaning up our inodes proactively so they can be reaped - * without I/O. But we are potentially leaving up to five seconds' - * worth of inodes floating about which prune_icache wants us to - * write out. One way to fix that would be to get prune_icache() - * to do a write_super() to free up some memory. It has the desired - * effect. */ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d76ec82..3e0851e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -326,11 +326,6 @@ static void ext4_put_nojournal(handle_t *handle) /* * Wrappers for jbd2_journal_start/end. - * - * The only special thing we need to do here is to make sure that all - * journal_end calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate. */ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) { @@ -356,12 +351,6 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) return jbd2_journal_start(journal, nblocks); } -/* - * The only special thing we need to do here is to make sure that all - * jbd2_journal_stop calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate. - */ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) { struct super_block *sb; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 3a56c8d..22255d9 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -52,7 +52,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb /* * If it's a fully non-blocking write attempt and we cannot * lock the buffer then redirty the page. Note that this can - * potentially cause a busy-wait loop from pdflush and kswapd + * potentially cause a busy-wait loop from flusher thread and kswapd * activity, but those code paths have their own higher-level * throttling. */ diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 5fd51a5..b7ec224 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c @@ -236,10 +236,10 @@ out: * hfs_mdb_commit() * * Description: - * This updates the MDB on disk (look also at hfs_write_super()). + * This updates the MDB on disk. * It does not check, if the superblock has been modified, or * if the filesystem has been mounted read-only. It is mainly - * called by hfs_write_super() and hfs_btree_extend(). + * called by hfs_sync_fs() and flush_mdb(). * Input Variable(s): * struct hfs_mdb *mdb: Pointer to the hfs MDB * int backup; diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 425c2f2..0935750 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -534,8 +534,8 @@ int journal_start_commit(journal_t *journal, tid_t *ptid) ret = 1; } else if (journal->j_committing_transaction) { /* - * If ext3_write_super() recently started a commit, then we - * have to wait for completion of that transaction + * If commit has been started, then we have to wait for + * completion of that transaction. */ if (ptid) *ptid = journal->j_committing_transaction->t_tid; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index e9a3c4c..8625da2 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -612,8 +612,8 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid) ret = 1; } else if (journal->j_committing_transaction) { /* - * If ext3_write_super() recently started a commit, then we - * have to wait for completion of that transaction + * If commit has been started, then we have to wait for + * completion of that transaction. */ if (ptid) *ptid = journal->j_committing_transaction->t_tid; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 6522cac..6a10812 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -676,17 +676,13 @@ static const struct super_operations nilfs_sops = { .alloc_inode = nilfs_alloc_inode, .destroy_inode = nilfs_destroy_inode, .dirty_inode = nilfs_dirty_inode, - /* .write_inode = nilfs_write_inode, */ - /* .drop_inode = nilfs_drop_inode, */ .evict_inode = nilfs_evict_inode, .put_super = nilfs_put_super, - /* .write_super = nilfs_write_super, */ .sync_fs = nilfs_sync_fs, .freeze_fs = nilfs_freeze, .unfreeze_fs = nilfs_unfreeze, .statfs = nilfs_statfs, .remount_fs = nilfs_remount, - /* .umount_begin */ .show_options = nilfs_show_options }; diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 6eee417..be1267a 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -107,8 +107,6 @@ struct the_nilfs { * used for * - loading the latest checkpoint exclusively. * - allocating a new full segment. - * - protecting s_dirt in the super_block struct - * (see nilfs_write_super) and the following fields. */ struct buffer_head *ns_sbh[2]; struct nilfs_super_block *ns_sbp[2]; @@ -717,7 +717,7 @@ cleanup_all: * here, so just reset the state. */ file_reset_write(f); - mnt_drop_write(f->f_path.mnt); + __mnt_drop_write(f->f_path.mnt); } } cleanup_file: @@ -537,46 +537,6 @@ void drop_super(struct super_block *sb) EXPORT_SYMBOL(drop_super); /** - * sync_supers - helper for periodic superblock writeback - * - * Call the write_super method if present on all dirty superblocks in - * the system. This is for the periodic writeback used by most older - * filesystems. For data integrity superblock writeback use - * sync_filesystems() instead. - * - * Note: check the dirty flag before waiting, so we don't - * hold up the sync while mounting a device. (The newly - * mounted device won't need syncing.) - */ -void sync_supers(void) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - if (sb->s_op->write_super && sb->s_dirt) { - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN)) - sb->s_op->write_super(sb); - up_read(&sb->s_umount); - - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); -} - -/** * iterate_supers - call function for all active superblocks * @f: function to call * @arg: argument to pass to it diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 35389ca..7bd6e72 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -37,11 +37,11 @@ * * A thing to keep in mind: inode @i_mutex is locked in most VFS operations we * implement. However, this is not true for 'ubifs_writepage()', which may be - * called with @i_mutex unlocked. For example, when pdflush is doing background - * write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. At "normal" - * work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. in the - * "sys_write -> alloc_pages -> direct reclaim path". So, in 'ubifs_writepage()' - * we are only guaranteed that the page is locked. + * called with @i_mutex unlocked. For example, when flusher thread is doing + * background write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. + * At "normal" work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. + * in the "sys_write -> alloc_pages -> direct reclaim path". So, in + * 'ubifs_writepage()' we are only guaranteed that the page is locked. * * Similarly, @i_mutex is not always locked in 'ubifs_readpage()', e.g., the * read-ahead path does not lock it ("sys_read -> generic_file_aio_read -> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 1c766c3..c3fa6c5 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -303,7 +303,7 @@ static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc) mutex_lock(&ui->ui_mutex); /* * Due to races between write-back forced by budgeting - * (see 'sync_some_inodes()') and pdflush write-back, the inode may + * (see 'sync_some_inodes()') and background write-back, the inode may * have already been synchronized, do not do this again. This might * also happen if it was synchronized in an VFS operation, e.g. * 'ubifs_link()'. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2c744c7..26a92fc 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -491,11 +491,11 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b); acpi_status acpi_enter_sleep_state_prep(u8 sleep_state); -acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags); +acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state); ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)) -acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags); +acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); acpi_status acpi_leave_sleep_state(u8 sleep_state); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 3af87de..3d00bd5 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -803,7 +803,7 @@ typedef u8 acpi_adr_space_type; /* Sleep function dispatch */ -typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state, u8 flags); +typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state); struct acpi_sleep_functions { ACPI_SLEEP_FUNCTION legacy_function; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3ad510b..4f2a762 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -96,7 +96,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_numa_slit_init (struct acpi_table_slit *slit); void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); -void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); +int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); void acpi_numa_arch_fixup(void); #ifdef CONFIG_ACPI_HOTPLUG_CPU diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index c97c6b9..2a9a9ab 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -124,7 +124,6 @@ void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, void bdi_start_background_writeback(struct backing_dev_info *bdi); int bdi_writeback_thread(void *data); int bdi_has_dirty_io(struct backing_dev_info *bdi); -void bdi_arm_supers_timer(void); void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi); void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2); diff --git a/include/linux/can.h b/include/linux/can.h index 018055e..e52958d 100644 --- a/include/linux/can.h +++ b/include/linux/can.h @@ -74,20 +74,21 @@ struct can_frame { /* * defined bits for canfd_frame.flags * - * As the default for CAN FD should be to support the high data rate in the - * payload section of the frame (HDR) and to support up to 64 byte in the - * data section (EDL) the bits are only set in the non-default case. - * Btw. as long as there's no real implementation for CAN FD network driver - * these bits are only preliminary. + * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to + * be set in the CAN frame bitstream on the wire. The EDL bit switch turns + * the CAN controllers bitstream processor into the CAN FD mode which creates + * two new options within the CAN FD frame specification: * - * RX: NOHDR/NOEDL - info about received CAN FD frame - * ESI - bit from originating CAN controller - * TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller - * ESI - bit is set by local CAN controller + * Bit Rate Switch - to indicate a second bitrate is/was used for the payload + * Error State Indicator - represents the error state of the transmitting node + * + * As the CANFD_ESI bit is internally generated by the transmitting CAN + * controller only the CANFD_BRS bit is relevant for real CAN controllers when + * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make + * sense for virtual CAN interfaces to test applications with echoed frames. */ -#define CANFD_NOHDR 0x01 /* frame without high data rate */ -#define CANFD_NOEDL 0x02 /* frame without extended data length */ -#define CANFD_ESI 0x04 /* error state indicator */ +#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ +#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ /** * struct canfd_frame - CAN flexible data rate frame structure diff --git a/include/linux/fs.h b/include/linux/fs.h index 38dba16..aa11047 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1491,7 +1491,6 @@ struct sb_writers { struct super_block { struct list_head s_list; /* Keep this first */ dev_t s_dev; /* search index; _not_ kdev_t */ - unsigned char s_dirt; unsigned char s_blocksize_bits; unsigned long s_blocksize; loff_t s_maxbytes; /* Max file size */ @@ -1861,7 +1860,6 @@ struct super_operations { int (*drop_inode) (struct inode *); void (*evict_inode) (struct inode *); void (*put_super) (struct super_block *); - void (*write_super) (struct super_block *); int (*sync_fs)(struct super_block *sb, int wait); int (*freeze_fs) (struct super_block *); int (*unfreeze_fs) (struct super_block *); @@ -2397,7 +2395,6 @@ extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync); extern int vfs_fsync(struct file *file, int datasync); extern int generic_write_sync(struct file *file, loff_t pos, loff_t count); -extern void sync_supers(void); extern void emergency_sync(void); extern void emergency_remount(void); #ifdef CONFIG_BLOCK diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index af961d6..642928c 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -306,9 +306,10 @@ extern void *perf_trace_buf_prepare(int size, unsigned short type, static inline void perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, - u64 count, struct pt_regs *regs, void *head) + u64 count, struct pt_regs *regs, void *head, + struct task_struct *task) { - perf_tp_event(addr, count, raw_data, size, regs, head, rctx); + perf_tp_event(addr, count, raw_data, size, regs, head, rctx, task); } #endif diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index bb7f309..305f23c 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -22,7 +22,7 @@ * * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024) * - bit 26 is the NMI_MASK - * - bit 28 is the PREEMPT_ACTIVE flag + * - bit 27 is the PREEMPT_ACTIVE flag * * PREEMPT_MASK: 0x000000ff * SOFTIRQ_MASK: 0x0000ff00 diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 54d6d69..7e83370 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -20,6 +20,7 @@ #define __LINUX_IOMMU_H #include <linux/errno.h> +#include <linux/types.h> #define IOMMU_READ (1) #define IOMMU_WRITE (2) @@ -30,6 +31,7 @@ struct iommu_group; struct bus_type; struct device; struct iommu_domain; +struct notifier_block; /* iommu fault flags */ #define IOMMU_FAULT_READ 0x0 diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 379e433..879db26 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -369,6 +369,7 @@ struct ipv6_pinfo { __u8 rcv_tclass; __u32 dst_cookie; + __u32 rx_dst_cookie; struct ipv6_mc_socklist __rcu *ipv6_mc_list; struct ipv6_ac_socklist *ipv6_ac_list; diff --git a/include/linux/irq.h b/include/linux/irq.h index 553fb66..216b0ba 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -349,6 +349,7 @@ enum { IRQCHIP_MASK_ON_SUSPEND = (1 << 2), IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), IRQCHIP_SKIP_SET_WAKE = (1 << 4), + IRQCHIP_ONESHOT_SAFE = (1 << 5), }; /* This include will go away once we isolated irq_desc usage to core code */ diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 265e2c3..8268054 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -39,9 +39,6 @@ # error Invalid value of HZ. #endif -/* LATCH is used in the interval timer and ftape setup. */ -#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ - /* Suppose we want to divide two numbers NOM and DEN: NOM/DEN, then we can * improve accuracy by shifting LSH bits, hence calculating: * (NOM << LSH) / DEN @@ -54,18 +51,30 @@ #define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \ + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN)) -/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ -#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) +#ifdef CLOCK_TICK_RATE +/* LATCH is used in the interval timer and ftape setup. */ +# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ + +/* + * HZ is the requested value. However the CLOCK_TICK_RATE may not allow + * for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy) + */ +# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8)) +#else +# define SHIFTED_HZ (HZ << 8) +#endif -/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */ -#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) +/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ +#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8)) /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) -/* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */ -/* a value TUSEC for TICK_USEC (can be set bij adjtimex) */ -#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8)) +/* + * TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and + * a value TUSEC for TICK_USEC (can be set bij adjtimex) + */ +#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8)) /* some arch's have a small-data section that can be accessed register-relative * but that can only take up to, say, 4-byte variables. jiffies being part of diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 0647258..42d9e86 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -75,8 +75,6 @@ extern const char *kdb_diemsg; #define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */ #define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */ #define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */ -#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when - * kdb is off */ #define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available, * kdb is disabled */ #define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do diff --git a/include/linux/olpc-ec.h b/include/linux/olpc-ec.h new file mode 100644 index 0000000..5bb6e76 --- /dev/null +++ b/include/linux/olpc-ec.h @@ -0,0 +1,41 @@ +#ifndef _LINUX_OLPC_EC_H +#define _LINUX_OLPC_EC_H + +/* XO-1 EC commands */ +#define EC_FIRMWARE_REV 0x08 +#define EC_WRITE_SCI_MASK 0x1b +#define EC_WAKE_UP_WLAN 0x24 +#define EC_WLAN_LEAVE_RESET 0x25 +#define EC_READ_EB_MODE 0x2a +#define EC_SET_SCI_INHIBIT 0x32 +#define EC_SET_SCI_INHIBIT_RELEASE 0x34 +#define EC_WLAN_ENTER_RESET 0x35 +#define EC_WRITE_EXT_SCI_MASK 0x38 +#define EC_SCI_QUERY 0x84 +#define EC_EXT_SCI_QUERY 0x85 + +struct platform_device; + +struct olpc_ec_driver { + int (*probe)(struct platform_device *); + int (*suspend)(struct platform_device *); + int (*resume)(struct platform_device *); + + int (*ec_cmd)(u8, u8 *, size_t, u8 *, size_t, void *); +}; + +#ifdef CONFIG_OLPC + +extern void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg); + +extern int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, + size_t outlen); + +#else + +static inline int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, + size_t outlen) { return -ENODEV; } + +#endif /* CONFIG_OLPC */ + +#endif /* _LINUX_OLPC_EC_H */ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 76c5c8b..7602ccb 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1272,7 +1272,8 @@ static inline bool perf_paranoid_kernel(void) extern void perf_event_init(void); extern void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, struct pt_regs *regs, - struct hlist_head *head, int rctx); + struct hlist_head *head, int rctx, + struct task_struct *task); extern void perf_bp_event(struct perf_event *event, void *data); #ifndef perf_misc_flags diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index 93f9821..a3728bf 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -50,6 +50,7 @@ struct shdma_desc { struct list_head node; struct dma_async_tx_descriptor async_tx; enum dma_transfer_direction direction; + size_t partial; dma_cookie_t cookie; int chunks; int mark; @@ -98,6 +99,7 @@ struct shdma_ops { void (*start_xfer)(struct shdma_chan *, struct shdma_desc *); struct shdma_desc *(*embedded_desc)(void *, int); bool (*chan_irq)(struct shdma_chan *, int); + size_t (*get_partial)(struct shdma_chan *, struct shdma_desc *); }; struct shdma_dev { diff --git a/include/linux/timex.h b/include/linux/timex.h index 99bc88b..7c5ceb2 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -232,7 +232,7 @@ struct timex { * estimated error = NTP dispersion. */ extern unsigned long tick_usec; /* USER_HZ period (usec) */ -extern unsigned long tick_nsec; /* ACTHZ period (nsec) */ +extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */ extern void ntp_init(void); extern void ntp_clear(void); diff --git a/include/linux/topology.h b/include/linux/topology.h index e91cd43..fec12d6 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -164,6 +164,7 @@ int arch_update_cpu_topology(void); | 0*SD_SHARE_CPUPOWER \ | 0*SD_SHARE_PKG_RESOURCES \ | 0*SD_SERIALIZE \ + | 1*SD_PREFER_SIBLING \ , \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/linux/writeback.h b/include/linux/writeback.h index c66fe33..50c3e8f 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -104,7 +104,6 @@ static inline void wait_on_inode(struct inode *inode) wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE); } - /* * mm/page-writeback.c */ diff --git a/include/net/dst.h b/include/net/dst.h index baf5978..621e351 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -110,7 +110,7 @@ struct dst_entry { }; extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); -extern const u32 dst_default_metrics[RTAX_MAX]; +extern const u32 dst_default_metrics[]; #define DST_METRICS_READ_ONLY 0x1UL #define __DST_METRICS_PTR(Y) \ diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 5ee66f5..ba1d361 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops { int (*queue_xmit)(struct sk_buff *skb, struct flowi *fl); void (*send_check)(struct sock *sk, struct sk_buff *skb); int (*rebuild_header)(struct sock *sk); + void (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb); int (*conn_request)(struct sock *sk, struct sk_buff *skb); struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb, struct request_sock *req, diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 83b567f..613cfa4 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk) return flags; } -static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - - dst_hold(dst); - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; -} - #endif /* _INET_SOCK_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h index e19124b..1f000ff 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -464,6 +464,7 @@ extern int tcp_disconnect(struct sock *sk, int flags); void tcp_connect_init(struct sock *sk); void tcp_finish_connect(struct sock *sk, struct sk_buff *skb); int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size); +void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); /* From syncookies.c */ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index ea7a203..5a8671e 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -73,6 +73,9 @@ DECLARE_EVENT_CLASS(sched_wakeup_template, __entry->prio = p->prio; __entry->success = success; __entry->target_cpu = task_cpu(p); + ) + TP_perf_assign( + __perf_task(p); ), TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d", @@ -325,6 +328,7 @@ DECLARE_EVENT_CLASS(sched_stat_template, ) TP_perf_assign( __perf_count(delay); + __perf_task(tsk); ), TP_printk("comm=%s pid=%d delay=%Lu [ns]", diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index c6bc2fa..a763888 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -712,6 +712,9 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call #undef __perf_count #define __perf_count(c) __count = (c) +#undef __perf_task +#define __perf_task(t) __task = (t) + #undef TP_perf_assign #define TP_perf_assign(args...) args @@ -725,6 +728,7 @@ perf_trace_##call(void *__data, proto) \ struct ftrace_raw_##call *entry; \ struct pt_regs __regs; \ u64 __addr = 0, __count = 1; \ + struct task_struct *__task = NULL; \ struct hlist_head *head; \ int __entry_size; \ int __data_size; \ @@ -752,7 +756,7 @@ perf_trace_##call(void *__data, proto) \ \ head = this_cpu_ptr(event_call->perf_events); \ perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ - __count, &__regs, head); \ + __count, &__regs, head, __task); \ } /* diff --git a/kernel/debug/kdb/kdb_debugger.c b/kernel/debug/kdb/kdb_debugger.c index 8b68ce7..be7b33b 100644 --- a/kernel/debug/kdb/kdb_debugger.c +++ b/kernel/debug/kdb/kdb_debugger.c @@ -12,6 +12,7 @@ #include <linux/kdb.h> #include <linux/kdebug.h> #include <linux/export.h> +#include <linux/hardirq.h> #include "kdb_private.h" #include "../debug_core.h" @@ -52,6 +53,9 @@ int kdb_stub(struct kgdb_state *ks) if (atomic_read(&kgdb_setting_breakpoint)) reason = KDB_REASON_KEYBOARD; + if (in_nmi()) + reason = KDB_REASON_NMI; + for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { if ((bp->bp_enabled) && (bp->bp_addr == addr)) { reason = KDB_REASON_BREAK; diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index bb9520f..0a69d2a 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -715,9 +715,6 @@ kdb_printit: /* check for having reached the LINES number of printed lines */ if (kdb_nextline == linecount) { char buf1[16] = ""; -#if defined(CONFIG_SMP) - char buf2[32]; -#endif /* Watch out for recursion here. Any routine that calls * kdb_printf will come back through here. And kdb_read @@ -732,14 +729,6 @@ kdb_printit: if (moreprompt == NULL) moreprompt = "more> "; -#if defined(CONFIG_SMP) - if (strchr(moreprompt, '%')) { - sprintf(buf2, moreprompt, get_cpu()); - put_cpu(); - moreprompt = buf2; - } -#endif - kdb_input_flush(); c = console_drivers; diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 1f91413..31df170 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -139,11 +139,10 @@ static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); static char *__env[] = { #if defined(CONFIG_SMP) "PROMPT=[%d]kdb> ", - "MOREPROMPT=[%d]more> ", #else "PROMPT=kdb> ", - "MOREPROMPT=more> ", #endif + "MOREPROMPT=more> ", "RADIX=16", "MDCOUNT=8", /* lines of md output */ KDB_PLATFORM_ENV, @@ -1236,18 +1235,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, *cmdbuf = '\0'; *(cmd_hist[cmd_head]) = '\0'; - if (KDB_FLAG(ONLY_DO_DUMP)) { - /* kdb is off but a catastrophic error requires a dump. - * Take the dump and reboot. - * Turn on logging so the kdb output appears in the log - * buffer in the dump. - */ - const char *setargs[] = { "set", "LOGGING", "1" }; - kdb_set(2, setargs); - kdb_reboot(0, NULL); - /*NOTREACHED*/ - } - do_full_getstr: #if defined(CONFIG_SMP) snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"), diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 6581a04..98d4597 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -153,7 +153,8 @@ put_callchain_entry(int rctx) put_recursion_context(__get_cpu_var(callchain_recursion), rctx); } -struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +struct perf_callchain_entry * +perf_callchain(struct perf_event *event, struct pt_regs *regs) { int rctx; struct perf_callchain_entry *entry; @@ -178,6 +179,12 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) } if (regs) { + /* + * Disallow cross-task user callchains. + */ + if (event->ctx->task && event->ctx->task != current) + goto exit_put; + perf_callchain_store(entry, PERF_CONTEXT_USER); perf_callchain_user(entry, regs); } diff --git a/kernel/events/core.c b/kernel/events/core.c index f1cf0ed..b7935fc 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4039,7 +4039,7 @@ void perf_prepare_sample(struct perf_event_header *header, if (sample_type & PERF_SAMPLE_CALLCHAIN) { int size = 1; - data->callchain = perf_callchain(regs); + data->callchain = perf_callchain(event, regs); if (data->callchain) size += data->callchain->nr; @@ -5209,7 +5209,8 @@ static int perf_tp_event_match(struct perf_event *event, } void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, - struct pt_regs *regs, struct hlist_head *head, int rctx) + struct pt_regs *regs, struct hlist_head *head, int rctx, + struct task_struct *task) { struct perf_sample_data data; struct perf_event *event; @@ -5228,6 +5229,31 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, perf_swevent_event(event, count, &data, regs); } + /* + * If we got specified a target task, also iterate its context and + * deliver this event there too. + */ + if (task && task != current) { + struct perf_event_context *ctx; + struct trace_entry *entry = record; + + rcu_read_lock(); + ctx = rcu_dereference(task->perf_event_ctxp[perf_sw_context]); + if (!ctx) + goto unlock; + + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { + if (event->attr.type != PERF_TYPE_TRACEPOINT) + continue; + if (event->attr.config != entry->type) + continue; + if (perf_tp_event_match(event, &data, regs)) + perf_swevent_event(event, count, &data, regs); + } +unlock: + rcu_read_unlock(); + } + perf_swevent_put_recursion_context(rctx); } EXPORT_SYMBOL_GPL(perf_tp_event); diff --git a/kernel/events/internal.h b/kernel/events/internal.h index b0b107f..a096c19 100644 --- a/kernel/events/internal.h +++ b/kernel/events/internal.h @@ -101,7 +101,8 @@ __output_copy(struct perf_output_handle *handle, } /* Callchain handling */ -extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs); +extern struct perf_callchain_entry * +perf_callchain(struct perf_event *event, struct pt_regs *regs); extern int get_callchain_buffers(void); extern void put_callchain_buffers(void); diff --git a/kernel/futex.c b/kernel/futex.c index e2b0fb9..3717e7b 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, * @uaddr2: the pi futex we will take prior to returning to user-space * * The caller will wait on uaddr and will be requeued by futex_requeue() to - * uaddr2 which must be PI aware. Normal wakeup will wake on uaddr2 and - * complete the acquisition of the rt_mutex prior to returning to userspace. - * This ensures the rt_mutex maintains an owner when it has waiters; without - * one, the pi logic wouldn't know which task to boost/deboost, if there was a - * need to. + * uaddr2 which must be PI aware and unique from uaddr. Normal wakeup will wake + * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to + * userspace. This ensures the rt_mutex maintains an owner when it has waiters; + * without one, the pi logic would not know which task to boost/deboost, if + * there was a need to. * * We call schedule in futex_wait_queue_me() when we enqueue and return there * via the following: @@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, struct futex_q q = futex_q_init; int res, ret; + if (uaddr == uaddr2) + return -EINVAL; + if (!bitset) return -EINVAL; @@ -2343,7 +2346,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, * signal. futex_unlock_pi() will not destroy the lock_ptr nor * the pi_state. */ - WARN_ON(!&q.pi_state); + WARN_ON(!q.pi_state); pi_mutex = &q.pi_state->pi_mutex; ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1); debug_rt_mutex_free_waiter(&rt_waiter); @@ -2370,7 +2373,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, * fault, unlock the rt_mutex and return the fault to userspace. */ if (ret == -EFAULT) { - if (rt_mutex_owner(pi_mutex) == current) + if (pi_mutex && rt_mutex_owner(pi_mutex) == current) rt_mutex_unlock(pi_mutex); } else if (ret == -EINTR) { /* diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a8e8f0..4c69326 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -944,6 +944,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) } /* + * Drivers are often written to work w/o knowledge about the + * underlying irq chip implementation, so a request for a + * threaded irq without a primary hard irq context handler + * requires the ONESHOT flag to be set. Some irq chips like + * MSI based interrupts are per se one shot safe. Check the + * chip flags, so we can avoid the unmask dance at the end of + * the threaded handler for those. + */ + if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE) + new->flags &= ~IRQF_ONESHOT; + + /* * The following block of code has to be executed atomically */ raw_spin_lock_irqsave(&desc->lock, flags); @@ -1017,7 +1029,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ new->thread_mask = 1 << ffz(thread_mask); - } else if (new->handler == irq_default_primary_handler) { + } else if (new->handler == irq_default_primary_handler && + !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) { /* * The interrupt was requested with handler = NULL, so * we use the default primary handler for it. But it diff --git a/kernel/sched/core.c b/kernel/sched/core.c index d325c4b..82ad284 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4340,9 +4340,7 @@ recheck: */ if (unlikely(policy == p->policy && (!rt_policy(policy) || param->sched_priority == p->rt_priority))) { - - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); return 0; } diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index d72586f..23aa789 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -65,8 +65,8 @@ static int convert_prio(int prio) int cpupri_find(struct cpupri *cp, struct task_struct *p, struct cpumask *lowest_mask) { - int idx = 0; - int task_pri = convert_prio(p->prio); + int idx = 0; + int task_pri = convert_prio(p->prio); if (task_pri >= MAX_RT_PRIO) return 0; @@ -137,9 +137,9 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, */ void cpupri_set(struct cpupri *cp, int cpu, int newpri) { - int *currpri = &cp->cpu_to_pri[cpu]; - int oldpri = *currpri; - int do_mb = 0; + int *currpri = &cp->cpu_to_pri[cpu]; + int oldpri = *currpri; + int do_mb = 0; newpri = convert_prio(newpri); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 22321db..d0cc03b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3069,6 +3069,9 @@ struct lb_env { int new_dst_cpu; enum cpu_idle_type idle; long imbalance; + /* The set of CPUs under consideration for load-balancing */ + struct cpumask *cpus; + unsigned int flags; unsigned int loop; @@ -3653,8 +3656,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group) */ static inline void update_sg_lb_stats(struct lb_env *env, struct sched_group *group, int load_idx, - int local_group, const struct cpumask *cpus, - int *balance, struct sg_lb_stats *sgs) + int local_group, int *balance, struct sg_lb_stats *sgs) { unsigned long nr_running, max_nr_running, min_nr_running; unsigned long load, max_cpu_load, min_cpu_load; @@ -3671,7 +3673,7 @@ static inline void update_sg_lb_stats(struct lb_env *env, max_nr_running = 0; min_nr_running = ~0UL; - for_each_cpu_and(i, sched_group_cpus(group), cpus) { + for_each_cpu_and(i, sched_group_cpus(group), env->cpus) { struct rq *rq = cpu_rq(i); nr_running = rq->nr_running; @@ -3800,8 +3802,7 @@ static bool update_sd_pick_busiest(struct lb_env *env, * @sds: variable to hold the statistics for this sched_domain. */ static inline void update_sd_lb_stats(struct lb_env *env, - const struct cpumask *cpus, - int *balance, struct sd_lb_stats *sds) + int *balance, struct sd_lb_stats *sds) { struct sched_domain *child = env->sd->child; struct sched_group *sg = env->sd->groups; @@ -3818,8 +3819,7 @@ static inline void update_sd_lb_stats(struct lb_env *env, local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg)); memset(&sgs, 0, sizeof(sgs)); - update_sg_lb_stats(env, sg, load_idx, local_group, - cpus, balance, &sgs); + update_sg_lb_stats(env, sg, load_idx, local_group, balance, &sgs); if (local_group && !(*balance)) return; @@ -4055,7 +4055,6 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s * to restore balance. * * @env: The load balancing environment. - * @cpus: The set of CPUs under consideration for load-balancing. * @balance: Pointer to a variable indicating if this_cpu * is the appropriate cpu to perform load balancing at this_level. * @@ -4065,7 +4064,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s * put to idle by rebalancing its tasks onto our group. */ static struct sched_group * -find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance) +find_busiest_group(struct lb_env *env, int *balance) { struct sd_lb_stats sds; @@ -4075,7 +4074,7 @@ find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance) * Compute the various statistics relavent for load balancing at * this level. */ - update_sd_lb_stats(env, cpus, balance, &sds); + update_sd_lb_stats(env, balance, &sds); /* * this_cpu is not the appropriate cpu to perform load balancing at @@ -4155,8 +4154,7 @@ ret: * find_busiest_queue - find the busiest runqueue among the cpus in group. */ static struct rq *find_busiest_queue(struct lb_env *env, - struct sched_group *group, - const struct cpumask *cpus) + struct sched_group *group) { struct rq *busiest = NULL, *rq; unsigned long max_load = 0; @@ -4171,7 +4169,7 @@ static struct rq *find_busiest_queue(struct lb_env *env, if (!capacity) capacity = fix_small_capacity(env->sd, group); - if (!cpumask_test_cpu(i, cpus)) + if (!cpumask_test_cpu(i, env->cpus)) continue; rq = cpu_rq(i); @@ -4252,6 +4250,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, .dst_grpmask = sched_group_cpus(sd->groups), .idle = idle, .loop_break = sched_nr_migrate_break, + .cpus = cpus, }; cpumask_copy(cpus, cpu_active_mask); @@ -4260,7 +4259,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, schedstat_inc(sd, lb_count[idle]); redo: - group = find_busiest_group(&env, cpus, balance); + group = find_busiest_group(&env, balance); if (*balance == 0) goto out_balanced; @@ -4270,7 +4269,7 @@ redo: goto out_balanced; } - busiest = find_busiest_queue(&env, group, cpus); + busiest = find_busiest_queue(&env, group); if (!busiest) { schedstat_inc(sd, lb_nobusyq[idle]); goto out_balanced; diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index a470154..46da053 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -37,7 +37,7 @@ * requested HZ value. It is also not recommended * for "tick-less" systems. */ -#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ)) +#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ)) /* Since jiffies uses a simple NSEC_PER_JIFFY multiplier * conversion, the .shift value could be zero. However diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index b7fbadc..24174b4 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -28,7 +28,7 @@ DEFINE_SPINLOCK(ntp_lock); /* USER_HZ period (usecs): */ unsigned long tick_usec = TICK_USEC; -/* ACTHZ period (nsecs): */ +/* SHIFTED_HZ period (nsecs): */ unsigned long tick_nsec; static u64 tick_length; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index f045cc5..e16af19 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -65,14 +65,14 @@ struct timekeeper { * used instead. */ struct timespec wall_to_monotonic; - /* time spent in suspend */ - struct timespec total_sleep_time; - /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ - struct timespec raw_time; /* Offset clock monotonic -> clock realtime */ ktime_t offs_real; + /* time spent in suspend */ + struct timespec total_sleep_time; /* Offset clock monotonic -> clock boottime */ ktime_t offs_boot; + /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ + struct timespec raw_time; /* Seqlock for all timekeeper values */ seqlock_t lock; }; @@ -108,13 +108,38 @@ static struct timespec tk_xtime(struct timekeeper *tk) static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts) { tk->xtime_sec = ts->tv_sec; - tk->xtime_nsec = ts->tv_nsec << tk->shift; + tk->xtime_nsec = (u64)ts->tv_nsec << tk->shift; } static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts) { tk->xtime_sec += ts->tv_sec; - tk->xtime_nsec += ts->tv_nsec << tk->shift; + tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; +} + +static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) +{ + struct timespec tmp; + + /* + * Verify consistency of: offset_real = -wall_to_monotonic + * before modifying anything + */ + set_normalized_timespec(&tmp, -tk->wall_to_monotonic.tv_sec, + -tk->wall_to_monotonic.tv_nsec); + WARN_ON_ONCE(tk->offs_real.tv64 != timespec_to_ktime(tmp).tv64); + tk->wall_to_monotonic = wtm; + set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); + tk->offs_real = timespec_to_ktime(tmp); +} + +static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) +{ + /* Verify consistency before modifying */ + WARN_ON_ONCE(tk->offs_boot.tv64 != timespec_to_ktime(tk->total_sleep_time).tv64); + + tk->total_sleep_time = t; + tk->offs_boot = timespec_to_ktime(t); } /** @@ -217,14 +242,6 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) return nsec + arch_gettimeoffset(); } -static void update_rt_offset(struct timekeeper *tk) -{ - struct timespec tmp, *wtm = &tk->wall_to_monotonic; - - set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec); - tk->offs_real = timespec_to_ktime(tmp); -} - /* must hold write on timekeeper.lock */ static void timekeeping_update(struct timekeeper *tk, bool clearntp) { @@ -234,12 +251,10 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp) tk->ntp_error = 0; ntp_clear(); } - update_rt_offset(tk); xt = tk_xtime(tk); update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); } - /** * timekeeping_forward_now - update clock to the current time * @@ -277,18 +292,19 @@ static void timekeeping_forward_now(struct timekeeper *tk) */ void getnstimeofday(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; unsigned long seq; s64 nsecs = 0; WARN_ON(timekeeping_suspended); do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - ts->tv_sec = timekeeper.xtime_sec; - ts->tv_nsec = timekeeping_get_ns(&timekeeper); + ts->tv_sec = tk->xtime_sec; + ts->tv_nsec = timekeeping_get_ns(tk); - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); timespec_add_ns(ts, nsecs); } @@ -296,19 +312,18 @@ EXPORT_SYMBOL(getnstimeofday); ktime_t ktime_get(void) { + struct timekeeper *tk = &timekeeper; unsigned int seq; s64 secs, nsecs; WARN_ON(timekeeping_suspended); do { - seq = read_seqbegin(&timekeeper.lock); - secs = timekeeper.xtime_sec + - timekeeper.wall_to_monotonic.tv_sec; - nsecs = timekeeping_get_ns(&timekeeper) + - timekeeper.wall_to_monotonic.tv_nsec; + seq = read_seqbegin(&tk->lock); + secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; + nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); /* * Use ktime_set/ktime_add_ns to create a proper ktime on * 32-bit architectures without CONFIG_KTIME_SCALAR. @@ -327,18 +342,19 @@ EXPORT_SYMBOL_GPL(ktime_get); */ void ktime_get_ts(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; struct timespec tomono; unsigned int seq; WARN_ON(timekeeping_suspended); do { - seq = read_seqbegin(&timekeeper.lock); - ts->tv_sec = timekeeper.xtime_sec; - ts->tv_nsec = timekeeping_get_ns(&timekeeper); - tomono = timekeeper.wall_to_monotonic; + seq = read_seqbegin(&tk->lock); + ts->tv_sec = tk->xtime_sec; + ts->tv_nsec = timekeeping_get_ns(tk); + tomono = tk->wall_to_monotonic; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec, ts->tv_nsec + tomono.tv_nsec); @@ -358,22 +374,23 @@ EXPORT_SYMBOL_GPL(ktime_get_ts); */ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real) { + struct timekeeper *tk = &timekeeper; unsigned long seq; s64 nsecs_raw, nsecs_real; WARN_ON_ONCE(timekeeping_suspended); do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - *ts_raw = timekeeper.raw_time; - ts_real->tv_sec = timekeeper.xtime_sec; + *ts_raw = tk->raw_time; + ts_real->tv_sec = tk->xtime_sec; ts_real->tv_nsec = 0; - nsecs_raw = timekeeping_get_ns_raw(&timekeeper); - nsecs_real = timekeeping_get_ns(&timekeeper); + nsecs_raw = timekeeping_get_ns_raw(tk); + nsecs_real = timekeeping_get_ns(tk); - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); timespec_add_ns(ts_raw, nsecs_raw); timespec_add_ns(ts_real, nsecs_real); @@ -406,28 +423,28 @@ EXPORT_SYMBOL(do_gettimeofday); */ int do_settimeofday(const struct timespec *tv) { + struct timekeeper *tk = &timekeeper; struct timespec ts_delta, xt; unsigned long flags; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); - timekeeping_forward_now(&timekeeper); + timekeeping_forward_now(tk); - xt = tk_xtime(&timekeeper); + xt = tk_xtime(tk); ts_delta.tv_sec = tv->tv_sec - xt.tv_sec; ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec; - timekeeper.wall_to_monotonic = - timespec_sub(timekeeper.wall_to_monotonic, ts_delta); + tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, ts_delta)); - tk_set_xtime(&timekeeper, tv); + tk_set_xtime(tk, tv); - timekeeping_update(&timekeeper, true); + timekeeping_update(tk, true); - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); /* signal hrtimers about time change */ clock_was_set(); @@ -436,7 +453,6 @@ int do_settimeofday(const struct timespec *tv) } EXPORT_SYMBOL(do_settimeofday); - /** * timekeeping_inject_offset - Adds or subtracts from the current time. * @tv: pointer to the timespec variable containing the offset @@ -445,23 +461,23 @@ EXPORT_SYMBOL(do_settimeofday); */ int timekeeping_inject_offset(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; unsigned long flags; if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) return -EINVAL; - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); - timekeeping_forward_now(&timekeeper); + timekeeping_forward_now(tk); - tk_xtime_add(&timekeeper, ts); - timekeeper.wall_to_monotonic = - timespec_sub(timekeeper.wall_to_monotonic, *ts); + tk_xtime_add(tk, ts); + tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); - timekeeping_update(&timekeeper, true); + timekeeping_update(tk, true); - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); /* signal hrtimers about time change */ clock_was_set(); @@ -477,23 +493,24 @@ EXPORT_SYMBOL(timekeeping_inject_offset); */ static int change_clocksource(void *data) { + struct timekeeper *tk = &timekeeper; struct clocksource *new, *old; unsigned long flags; new = (struct clocksource *) data; - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); - timekeeping_forward_now(&timekeeper); + timekeeping_forward_now(tk); if (!new->enable || new->enable(new) == 0) { - old = timekeeper.clock; - tk_setup_internals(&timekeeper, new); + old = tk->clock; + tk_setup_internals(tk, new); if (old->disable) old->disable(old); } - timekeeping_update(&timekeeper, true); + timekeeping_update(tk, true); - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); return 0; } @@ -507,7 +524,9 @@ static int change_clocksource(void *data) */ void timekeeping_notify(struct clocksource *clock) { - if (timekeeper.clock == clock) + struct timekeeper *tk = &timekeeper; + + if (tk->clock == clock) return; stop_machine(change_clocksource, clock, NULL); tick_clock_notify(); @@ -536,35 +555,36 @@ EXPORT_SYMBOL_GPL(ktime_get_real); */ void getrawmonotonic(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; unsigned long seq; s64 nsecs; do { - seq = read_seqbegin(&timekeeper.lock); - nsecs = timekeeping_get_ns_raw(&timekeeper); - *ts = timekeeper.raw_time; + seq = read_seqbegin(&tk->lock); + nsecs = timekeeping_get_ns_raw(tk); + *ts = tk->raw_time; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); timespec_add_ns(ts, nsecs); } EXPORT_SYMBOL(getrawmonotonic); - /** * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres */ int timekeeping_valid_for_hres(void) { + struct timekeeper *tk = &timekeeper; unsigned long seq; int ret; do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - ret = timekeeper.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; + ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); return ret; } @@ -574,15 +594,16 @@ int timekeeping_valid_for_hres(void) */ u64 timekeeping_max_deferment(void) { + struct timekeeper *tk = &timekeeper; unsigned long seq; u64 ret; do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - ret = timekeeper.clock->max_idle_ns; + ret = tk->clock->max_idle_ns; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); return ret; } @@ -622,46 +643,43 @@ void __attribute__((weak)) read_boot_clock(struct timespec *ts) */ void __init timekeeping_init(void) { + struct timekeeper *tk = &timekeeper; struct clocksource *clock; unsigned long flags; - struct timespec now, boot; + struct timespec now, boot, tmp; read_persistent_clock(&now); read_boot_clock(&boot); - seqlock_init(&timekeeper.lock); + seqlock_init(&tk->lock); ntp_init(); - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); clock = clocksource_default_clock(); if (clock->enable) clock->enable(clock); - tk_setup_internals(&timekeeper, clock); + tk_setup_internals(tk, clock); - tk_set_xtime(&timekeeper, &now); - timekeeper.raw_time.tv_sec = 0; - timekeeper.raw_time.tv_nsec = 0; + tk_set_xtime(tk, &now); + tk->raw_time.tv_sec = 0; + tk->raw_time.tv_nsec = 0; if (boot.tv_sec == 0 && boot.tv_nsec == 0) - boot = tk_xtime(&timekeeper); - - set_normalized_timespec(&timekeeper.wall_to_monotonic, - -boot.tv_sec, -boot.tv_nsec); - update_rt_offset(&timekeeper); - timekeeper.total_sleep_time.tv_sec = 0; - timekeeper.total_sleep_time.tv_nsec = 0; - write_sequnlock_irqrestore(&timekeeper.lock, flags); + boot = tk_xtime(tk); + + set_normalized_timespec(&tmp, -boot.tv_sec, -boot.tv_nsec); + tk_set_wall_to_mono(tk, tmp); + + tmp.tv_sec = 0; + tmp.tv_nsec = 0; + tk_set_sleep_time(tk, tmp); + + write_sequnlock_irqrestore(&tk->lock, flags); } /* time in seconds when suspend began */ static struct timespec timekeeping_suspend_time; -static void update_sleep_time(struct timespec t) -{ - timekeeper.total_sleep_time = t; - timekeeper.offs_boot = timespec_to_ktime(t); -} - /** * __timekeeping_inject_sleeptime - Internal function to add sleep interval * @delta: pointer to a timespec delta value @@ -677,13 +695,11 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, "sleep delta value!\n"); return; } - tk_xtime_add(tk, delta); - tk->wall_to_monotonic = timespec_sub(tk->wall_to_monotonic, *delta); - update_sleep_time(timespec_add(tk->total_sleep_time, *delta)); + tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta)); + tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta)); } - /** * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values * @delta: pointer to a timespec delta value @@ -696,6 +712,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, */ void timekeeping_inject_sleeptime(struct timespec *delta) { + struct timekeeper *tk = &timekeeper; unsigned long flags; struct timespec ts; @@ -704,21 +721,20 @@ void timekeeping_inject_sleeptime(struct timespec *delta) if (!(ts.tv_sec == 0 && ts.tv_nsec == 0)) return; - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); - timekeeping_forward_now(&timekeeper); + timekeeping_forward_now(tk); - __timekeeping_inject_sleeptime(&timekeeper, delta); + __timekeeping_inject_sleeptime(tk, delta); - timekeeping_update(&timekeeper, true); + timekeeping_update(tk, true); - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); /* signal hrtimers about time change */ clock_was_set(); } - /** * timekeeping_resume - Resumes the generic timekeeping subsystem. * @@ -728,6 +744,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta) */ static void timekeeping_resume(void) { + struct timekeeper *tk = &timekeeper; unsigned long flags; struct timespec ts; @@ -735,18 +752,18 @@ static void timekeeping_resume(void) clocksource_resume(); - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { ts = timespec_sub(ts, timekeeping_suspend_time); - __timekeeping_inject_sleeptime(&timekeeper, &ts); + __timekeeping_inject_sleeptime(tk, &ts); } /* re-base the last cycle value */ - timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); - timekeeper.ntp_error = 0; + tk->clock->cycle_last = tk->clock->read(tk->clock); + tk->ntp_error = 0; timekeeping_suspended = 0; - timekeeping_update(&timekeeper, false); - write_sequnlock_irqrestore(&timekeeper.lock, flags); + timekeeping_update(tk, false); + write_sequnlock_irqrestore(&tk->lock, flags); touch_softlockup_watchdog(); @@ -758,14 +775,15 @@ static void timekeeping_resume(void) static int timekeeping_suspend(void) { + struct timekeeper *tk = &timekeeper; unsigned long flags; struct timespec delta, delta_delta; static struct timespec old_delta; read_persistent_clock(&timekeeping_suspend_time); - write_seqlock_irqsave(&timekeeper.lock, flags); - timekeeping_forward_now(&timekeeper); + write_seqlock_irqsave(&tk->lock, flags); + timekeeping_forward_now(tk); timekeeping_suspended = 1; /* @@ -774,7 +792,7 @@ static int timekeeping_suspend(void) * try to compensate so the difference in system time * and persistent_clock time stays close to constant. */ - delta = timespec_sub(tk_xtime(&timekeeper), timekeeping_suspend_time); + delta = timespec_sub(tk_xtime(tk), timekeeping_suspend_time); delta_delta = timespec_sub(delta, old_delta); if (abs(delta_delta.tv_sec) >= 2) { /* @@ -787,7 +805,7 @@ static int timekeeping_suspend(void) timekeeping_suspend_time = timespec_add(timekeeping_suspend_time, delta_delta); } - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); clocksource_suspend(); @@ -898,27 +916,29 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) * the error. This causes the likely below to be unlikely. * * The proper fix is to avoid rounding up by using - * the high precision timekeeper.xtime_nsec instead of + * the high precision tk->xtime_nsec instead of * xtime.tv_nsec everywhere. Fixing this will take some * time. */ if (likely(error <= interval)) adj = 1; else - adj = timekeeping_bigadjust(tk, error, &interval, - &offset); - } else if (error < -interval) { - /* See comment above, this is just switched for the negative */ - error >>= 2; - if (likely(error >= -interval)) { - adj = -1; - interval = -interval; - offset = -offset; - } else - adj = timekeeping_bigadjust(tk, error, &interval, - &offset); - } else - return; + adj = timekeeping_bigadjust(tk, error, &interval, &offset); + } else { + if (error < -interval) { + /* See comment above, this is just switched for the negative */ + error >>= 2; + if (likely(error >= -interval)) { + adj = -1; + interval = -interval; + offset = -offset; + } else { + adj = timekeeping_bigadjust(tk, error, &interval, &offset); + } + } else { + goto out_adjust; + } + } if (unlikely(tk->clock->maxadj && (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) { @@ -981,6 +1001,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) tk->xtime_nsec -= offset; tk->ntp_error -= (interval - offset) << tk->ntp_error_shift; +out_adjust: /* * It may be possible that when we entered this function, xtime_nsec * was very small. Further, if we're slightly speeding the clocksource @@ -1003,7 +1024,6 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) } - /** * accumulate_nsecs_to_secs - Accumulates nsecs into secs * @@ -1024,15 +1044,21 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) /* Figure out if its a leap sec and apply if needed */ leap = second_overflow(tk->xtime_sec); - tk->xtime_sec += leap; - tk->wall_to_monotonic.tv_sec -= leap; - if (leap) - clock_was_set_delayed(); + if (unlikely(leap)) { + struct timespec ts; + + tk->xtime_sec += leap; + + ts.tv_sec = leap; + ts.tv_nsec = 0; + tk_set_wall_to_mono(tk, + timespec_sub(tk->wall_to_monotonic, ts)); + clock_was_set_delayed(); + } } } - /** * logarithmic_accumulation - shifted accumulation of cycles * @@ -1076,7 +1102,6 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, return offset; } - /** * update_wall_time - Uses the current clocksource to increment the wall time * @@ -1084,21 +1109,22 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, static void update_wall_time(void) { struct clocksource *clock; + struct timekeeper *tk = &timekeeper; cycle_t offset; int shift = 0, maxshift; unsigned long flags; s64 remainder; - write_seqlock_irqsave(&timekeeper.lock, flags); + write_seqlock_irqsave(&tk->lock, flags); /* Make sure we're fully resumed: */ if (unlikely(timekeeping_suspended)) goto out; - clock = timekeeper.clock; + clock = tk->clock; #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET - offset = timekeeper.cycle_interval; + offset = tk->cycle_interval; #else offset = (clock->read(clock) - clock->cycle_last) & clock->mask; #endif @@ -1111,19 +1137,19 @@ static void update_wall_time(void) * chunk in one go, and then try to consume the next smaller * doubled multiple. */ - shift = ilog2(offset) - ilog2(timekeeper.cycle_interval); + shift = ilog2(offset) - ilog2(tk->cycle_interval); shift = max(0, shift); /* Bound shift to one less than what overflows tick_length */ maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1; shift = min(shift, maxshift); - while (offset >= timekeeper.cycle_interval) { - offset = logarithmic_accumulation(&timekeeper, offset, shift); - if(offset < timekeeper.cycle_interval<<shift) + while (offset >= tk->cycle_interval) { + offset = logarithmic_accumulation(tk, offset, shift); + if (offset < tk->cycle_interval<<shift) shift--; } /* correct the clock when NTP error is too big */ - timekeeping_adjust(&timekeeper, offset); + timekeeping_adjust(tk, offset); /* @@ -1135,21 +1161,21 @@ static void update_wall_time(void) * the vsyscall implementations are converted to use xtime_nsec * (shifted nanoseconds), this can be killed. */ - remainder = timekeeper.xtime_nsec & ((1 << timekeeper.shift) - 1); - timekeeper.xtime_nsec -= remainder; - timekeeper.xtime_nsec += 1 << timekeeper.shift; - timekeeper.ntp_error += remainder << timekeeper.ntp_error_shift; + remainder = tk->xtime_nsec & ((1 << tk->shift) - 1); + tk->xtime_nsec -= remainder; + tk->xtime_nsec += 1 << tk->shift; + tk->ntp_error += remainder << tk->ntp_error_shift; /* * Finally, make sure that after the rounding * xtime_nsec isn't larger than NSEC_PER_SEC */ - accumulate_nsecs_to_secs(&timekeeper); + accumulate_nsecs_to_secs(tk); - timekeeping_update(&timekeeper, false); + timekeeping_update(tk, false); out: - write_sequnlock_irqrestore(&timekeeper.lock, flags); + write_sequnlock_irqrestore(&tk->lock, flags); } @@ -1166,18 +1192,18 @@ out: */ void getboottime(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; struct timespec boottime = { - .tv_sec = timekeeper.wall_to_monotonic.tv_sec + - timekeeper.total_sleep_time.tv_sec, - .tv_nsec = timekeeper.wall_to_monotonic.tv_nsec + - timekeeper.total_sleep_time.tv_nsec + .tv_sec = tk->wall_to_monotonic.tv_sec + + tk->total_sleep_time.tv_sec, + .tv_nsec = tk->wall_to_monotonic.tv_nsec + + tk->total_sleep_time.tv_nsec }; set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec); } EXPORT_SYMBOL_GPL(getboottime); - /** * get_monotonic_boottime - Returns monotonic time since boot * @ts: pointer to the timespec to be set @@ -1189,19 +1215,20 @@ EXPORT_SYMBOL_GPL(getboottime); */ void get_monotonic_boottime(struct timespec *ts) { + struct timekeeper *tk = &timekeeper; struct timespec tomono, sleep; unsigned int seq; WARN_ON(timekeeping_suspended); do { - seq = read_seqbegin(&timekeeper.lock); - ts->tv_sec = timekeeper.xtime_sec; - ts->tv_nsec = timekeeping_get_ns(&timekeeper); - tomono = timekeeper.wall_to_monotonic; - sleep = timekeeper.total_sleep_time; + seq = read_seqbegin(&tk->lock); + ts->tv_sec = tk->xtime_sec; + ts->tv_nsec = timekeeping_get_ns(tk); + tomono = tk->wall_to_monotonic; + sleep = tk->total_sleep_time; - } while (read_seqretry(&timekeeper.lock, seq)); + } while (read_seqretry(&tk->lock, seq)); set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec); @@ -1231,31 +1258,38 @@ EXPORT_SYMBOL_GPL(ktime_get_boottime); */ void monotonic_to_bootbased(struct timespec *ts) { - *ts = timespec_add(*ts, timekeeper.total_sleep_time); + struct timekeeper *tk = &timekeeper; + + *ts = timespec_add(*ts, tk->total_sleep_time); } EXPORT_SYMBOL_GPL(monotonic_to_bootbased); unsigned long get_seconds(void) { - return timekeeper.xtime_sec; + struct timekeeper *tk = &timekeeper; + + return tk->xtime_sec; } EXPORT_SYMBOL(get_seconds); struct timespec __current_kernel_time(void) { - return tk_xtime(&timekeeper); + struct timekeeper *tk = &timekeeper; + + return tk_xtime(tk); } struct timespec current_kernel_time(void) { + struct timekeeper *tk = &timekeeper; struct timespec now; unsigned long seq; do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - now = tk_xtime(&timekeeper); - } while (read_seqretry(&timekeeper.lock, seq)); + now = tk_xtime(tk); + } while (read_seqretry(&tk->lock, seq)); return now; } @@ -1263,15 +1297,16 @@ EXPORT_SYMBOL(current_kernel_time); struct timespec get_monotonic_coarse(void) { + struct timekeeper *tk = &timekeeper; struct timespec now, mono; unsigned long seq; do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - now = tk_xtime(&timekeeper); - mono = timekeeper.wall_to_monotonic; - } while (read_seqretry(&timekeeper.lock, seq)); + now = tk_xtime(tk); + mono = tk->wall_to_monotonic; + } while (read_seqretry(&tk->lock, seq)); set_normalized_timespec(&now, now.tv_sec + mono.tv_sec, now.tv_nsec + mono.tv_nsec); @@ -1300,14 +1335,15 @@ void do_timer(unsigned long ticks) void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, struct timespec *wtom, struct timespec *sleep) { + struct timekeeper *tk = &timekeeper; unsigned long seq; do { - seq = read_seqbegin(&timekeeper.lock); - *xtim = tk_xtime(&timekeeper); - *wtom = timekeeper.wall_to_monotonic; - *sleep = timekeeper.total_sleep_time; - } while (read_seqretry(&timekeeper.lock, seq)); + seq = read_seqbegin(&tk->lock); + *xtim = tk_xtime(tk); + *wtom = tk->wall_to_monotonic; + *sleep = tk->total_sleep_time; + } while (read_seqretry(&tk->lock, seq)); } #ifdef CONFIG_HIGH_RES_TIMERS @@ -1321,19 +1357,20 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, */ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot) { + struct timekeeper *tk = &timekeeper; ktime_t now; unsigned int seq; u64 secs, nsecs; do { - seq = read_seqbegin(&timekeeper.lock); + seq = read_seqbegin(&tk->lock); - secs = timekeeper.xtime_sec; - nsecs = timekeeping_get_ns(&timekeeper); + secs = tk->xtime_sec; + nsecs = timekeeping_get_ns(tk); - *offs_real = timekeeper.offs_real; - *offs_boot = timekeeper.offs_boot; - } while (read_seqretry(&timekeeper.lock, seq)); + *offs_real = tk->offs_real; + *offs_boot = tk->offs_boot; + } while (read_seqretry(&tk->lock, seq)); now = ktime_add_ns(ktime_set(secs, 0), nsecs); now = ktime_sub(now, *offs_real); @@ -1346,19 +1383,19 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot) */ ktime_t ktime_get_monotonic_offset(void) { + struct timekeeper *tk = &timekeeper; unsigned long seq; struct timespec wtom; do { - seq = read_seqbegin(&timekeeper.lock); - wtom = timekeeper.wall_to_monotonic; - } while (read_seqretry(&timekeeper.lock, seq)); + seq = read_seqbegin(&tk->lock); + wtom = tk->wall_to_monotonic; + } while (read_seqretry(&tk->lock, seq)); return timespec_to_ktime(wtom); } EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset); - /** * xtime_update() - advances the timekeeping infrastructure * @ticks: number of ticks, that have elapsed since the last call. diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index fee3752..8a6d2ee 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -281,7 +281,7 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip) head = this_cpu_ptr(event_function.perf_events); perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, - 1, ®s, head); + 1, ®s, head, NULL); #undef ENTRY_SIZE } diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index b31d3d5..1a21170 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1002,7 +1002,8 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); head = this_cpu_ptr(call->perf_events); - perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head); + perf_trace_buf_submit(entry, size, rctx, + entry->ip, 1, regs, head, NULL); } /* Kretprobe profile handler */ @@ -1033,7 +1034,8 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); head = this_cpu_ptr(call->perf_events); - perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head); + perf_trace_buf_submit(entry, size, rctx, + entry->ret_ip, 1, regs, head, NULL); } #endif /* CONFIG_PERF_EVENTS */ diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 96fc733..60e4d78 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -532,7 +532,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) (unsigned long *)&rec->args); head = this_cpu_ptr(sys_data->enter_event->perf_events); - perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); + perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); } int perf_sysenter_enable(struct ftrace_event_call *call) @@ -608,7 +608,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) rec->ret = syscall_get_return_value(current, regs); head = this_cpu_ptr(sys_data->exit_event->perf_events); - perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); + perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); } int perf_sysexit_enable(struct ftrace_event_call *call) diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 2b36ac6..03003cd 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -670,7 +670,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); head = this_cpu_ptr(call->perf_events); - perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head); + perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head, NULL); out: preempt_enable(); diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6b4718e..b41823c 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -39,12 +39,6 @@ DEFINE_SPINLOCK(bdi_lock); LIST_HEAD(bdi_list); LIST_HEAD(bdi_pending_list); -static struct task_struct *sync_supers_tsk; -static struct timer_list sync_supers_timer; - -static int bdi_sync_supers(void *); -static void sync_supers_timer_fn(unsigned long); - void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2) { if (wb1 < wb2) { @@ -250,12 +244,6 @@ static int __init default_bdi_init(void) { int err; - sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers"); - BUG_ON(IS_ERR(sync_supers_tsk)); - - setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0); - bdi_arm_supers_timer(); - err = bdi_init(&default_backing_dev_info); if (!err) bdi_register(&default_backing_dev_info, NULL, "default"); @@ -270,46 +258,6 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi) return wb_has_dirty_io(&bdi->wb); } -/* - * kupdated() used to do this. We cannot do it from the bdi_forker_thread() - * or we risk deadlocking on ->s_umount. The longer term solution would be - * to implement sync_supers_bdi() or similar and simply do it from the - * bdi writeback thread individually. - */ -static int bdi_sync_supers(void *unused) -{ - set_user_nice(current, 0); - - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - - /* - * Do this periodically, like kupdated() did before. - */ - sync_supers(); - } - - return 0; -} - -void bdi_arm_supers_timer(void) -{ - unsigned long next; - - if (!dirty_writeback_interval) - return; - - next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies; - mod_timer(&sync_supers_timer, round_jiffies_up(next)); -} - -static void sync_supers_timer_fn(unsigned long unused) -{ - wake_up_process(sync_supers_tsk); - bdi_arm_supers_timer(); -} - static void wakeup_timer_fn(unsigned long data) { struct backing_dev_info *bdi = (struct backing_dev_info *)data; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index e5363f3..5ad5ce2 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1532,7 +1532,6 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { proc_dointvec(table, write, buffer, length, ppos); - bdi_arm_supers_timer(); return 0; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 889532b..009ac28 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4511,7 +4511,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, pg_data_t *pgdat = NODE_DATA(nid); /* pg_data_t should be reset to zero when it's allocated */ - WARN_ON(pgdat->nr_zones || pgdat->node_start_pfn || pgdat->classzone_idx); + WARN_ON(pgdat->nr_zones || pgdat->classzone_idx); pgdat->node_id = nid; pgdat->node_start_pfn = node_start_pfn; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index b421cc4..fc866f2 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -200,11 +200,11 @@ void batadv_gw_election(struct batadv_priv *bat_priv) if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) goto out; - if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect)) - goto out; - curr_gw = batadv_gw_get_selected_gw_node(bat_priv); + if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect) && curr_gw) + goto out; + next_gw = batadv_gw_get_best_gw_node(bat_priv); if (curr_gw == next_gw) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index a438f4b..99dd8f7 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -197,6 +197,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, del: list_del(&entry->list); kfree(entry); + kfree(tt_change_node); event_removed = true; goto unlock; } diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index b780cb7..9da7fdd 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -466,6 +466,7 @@ void ceph_key_destroy(struct key *key) { struct ceph_crypto_key *ckey = key->payload.data; ceph_crypto_key_destroy(ckey); + kfree(ckey); } struct key_type key_type_ceph = { diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h index 1919d15..3572dc5 100644 --- a/net/ceph/crypto.h +++ b/net/ceph/crypto.h @@ -16,7 +16,8 @@ struct ceph_crypto_key { static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key) { - kfree(key->key); + if (key) + kfree(key->key); } extern int ceph_crypto_key_clone(struct ceph_crypto_key *dst, diff --git a/net/core/dev.c b/net/core/dev.c index f91abf8..a39354e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1055,6 +1055,8 @@ rollback: */ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) { + char *new_ifalias; + ASSERT_RTNL(); if (len >= IFALIASZ) @@ -1068,9 +1070,10 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) return 0; } - dev->ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); - if (!dev->ifalias) + new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); + if (!new_ifalias) return -ENOMEM; + dev->ifalias = new_ifalias; strlcpy(dev->ifalias, alias, len+1); return len; diff --git a/net/core/dst.c b/net/core/dst.c index 069d51d..56d6361 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -149,7 +149,15 @@ int dst_discard(struct sk_buff *skb) } EXPORT_SYMBOL(dst_discard); -const u32 dst_default_metrics[RTAX_MAX]; +const u32 dst_default_metrics[RTAX_MAX + 1] = { + /* This initializer is needed to force linker to place this variable + * into const section. Otherwise it might end into bss section. + * We really want to avoid false sharing on this variable, and catch + * any writes on it. + */ + [RTAX_MAX] = 0xdeadbeef, +}; + void *dst_alloc(struct dst_ops *ops, struct net_device *dev, int initial_ref, int initial_obsolete, unsigned short flags) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index f0cdb30..57bd978 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -367,7 +367,7 @@ static void __leaf_free_rcu(struct rcu_head *head) static inline void free_leaf(struct leaf *l) { - call_rcu_bh(&l->rcu, __leaf_free_rcu); + call_rcu(&l->rcu, __leaf_free_rcu); } static inline void free_leaf_info(struct leaf_info *leaf) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ba39a52..ec410e0 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -197,7 +197,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) neigh = __ipv4_neigh_lookup_noref(dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); - if (neigh) { + if (!IS_ERR(neigh)) { int res = dst_neigh_output(dst, neigh, skb); rcu_read_unlock_bh(); @@ -1536,6 +1536,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, arg->csumoffset) = csum_fold(csum_add(nskb->csum, arg->csum)); nskb->ip_summed = CHECKSUM_NONE; + skb_orphan(nskb); skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb)); ip_push_pending_frames(sk, &fl4); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2fd2bc9..85308b9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, { struct tcp_sock *tp = tcp_sk(sk); + if (unlikely(sk->sk_rx_dst == NULL)) + inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb); /* * Header prediction. * The code loosely follows the one in the famous @@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) tcp_set_state(sk, TCP_ESTABLISHED); if (skb != NULL) { - inet_sk_rx_dst_set(sk, skb); + icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); security_inet_conn_established(sk, skb); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 42b2a6a..7678237 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) sk->sk_rx_dst = NULL; } } - if (unlikely(sk->sk_rx_dst == NULL)) - inet_sk_rx_dst_set(sk, skb); - if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { rsk = sk; goto reset; @@ -1872,10 +1869,21 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { .twsk_destructor= tcp_twsk_destructor, }; +void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + + dst_hold(dst); + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; +} +EXPORT_SYMBOL(inet_sk_rx_dst_set); + const struct inet_connection_sock_af_ops ipv4_specific = { .queue_xmit = ip_queue_xmit, .send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, + .sk_rx_dst_set = inet_sk_rx_dst_set, .conn_request = tcp_v4_conn_request, .syn_recv_sock = tcp_v4_syn_recv_sock, .net_header_len = sizeof(struct iphdr), diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 2288a63..0abe67b 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -731,6 +731,18 @@ static int __net_init tcp_net_metrics_init(struct net *net) static void __net_exit tcp_net_metrics_exit(struct net *net) { + unsigned int i; + + for (i = 0; i < (1U << net->ipv4.tcp_metrics_hash_log) ; i++) { + struct tcp_metrics_block *tm, *next; + + tm = rcu_dereference_protected(net->ipv4.tcp_metrics_hash[i].chain, 1); + while (tm) { + next = rcu_dereference_protected(tm->tcpm_next, 1); + kfree(tm); + tm = next; + } + } kfree(net->ipv4.tcp_metrics_hash); } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 232a90c..d9c9dce 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct tcp_sock *oldtp = tcp_sk(sk); struct tcp_cookie_values *oldcvp = oldtp->cookie_values; - inet_sk_rx_dst_set(newsk, skb); + newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb); /* TCP Cookie Transactions require space for the cookie pair, * as it differs for each connection. There is no need to diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a7b3ec9..20dfd89 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -940,7 +940,7 @@ void __init tcp_tasklet_init(void) * We cant xmit new skbs from this context, as we might already * hold qdisc lock. */ -void tcp_wfree(struct sk_buff *skb) +static void tcp_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; struct tcp_sock *tp = tcp_sk(sk); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c66b90f..bb9ce2b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst = sk->sk_rx_dst; + sock_rps_save_rxhash(sk, skb); + if (dst) { + if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || + dst->ops->check(dst, np->rx_dst_cookie) == NULL) { + dst_release(dst); + sk->sk_rx_dst = NULL; + } + } + if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) goto reset; if (opt_skb) @@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb) struct dst_entry *dst = sk->sk_rx_dst; struct inet_sock *icsk = inet_sk(sk); if (dst) - dst = dst_check(dst, 0); + dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); if (dst && - icsk->rx_dst_ifindex == inet6_iif(skb)) + icsk->rx_dst_ifindex == skb->skb_iif) skb_dst_set_noref(skb, dst); } } @@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { .twsk_destructor= tcp_twsk_destructor, }; +static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + const struct rt6_info *rt = (const struct rt6_info *)dst; + + dst_hold(dst); + sk->sk_rx_dst = dst; + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; + if (rt->rt6i_node) + inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; +} + static const struct inet_connection_sock_af_ops ipv6_specific = { .queue_xmit = inet6_csk_xmit, .send_check = tcp_v6_send_check, .rebuild_header = inet6_sk_rebuild_header, + .sk_rx_dst_set = inet6_sk_rx_dst_set, .conn_request = tcp_v6_conn_request, .syn_recv_sock = tcp_v6_syn_recv_sock, .net_header_len = sizeof(struct ipv6hdr), @@ -1754,6 +1777,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { .queue_xmit = ip_queue_xmit, .send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, + .sk_rx_dst_set = inet_sk_rx_dst_set, .conn_request = tcp_v6_conn_request, .syn_recv_sock = tcp_v6_syn_recv_sock, .net_header_len = sizeof(struct iphdr), diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c index 39a8d89..6828e39 100644 --- a/net/llc/llc_station.c +++ b/net/llc/llc_station.c @@ -268,7 +268,7 @@ static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb) out: return rc; free: - kfree_skb(skb); + kfree_skb(nskb); goto out; } @@ -293,7 +293,7 @@ static int llc_station_ac_send_xid_r(struct sk_buff *skb) out: return rc; free: - kfree_skb(skb); + kfree_skb(nskb); goto out; } @@ -322,7 +322,7 @@ static int llc_station_ac_send_test_r(struct sk_buff *skb) out: return rc; free: - kfree_skb(skb); + kfree_skb(nskb); goto out; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ceaca7c..f016f66 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1079,7 +1079,7 @@ static void *packet_current_rx_frame(struct packet_sock *po, default: WARN(1, "TPACKET version not supported\n"); BUG(); - return 0; + return NULL; } } diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index f10fb82..05d60859 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -67,6 +67,9 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, struct tcf_common *pc; int ret = 0; int err; +#ifdef CONFIG_GACT_PROB + struct tc_gact_p *p_parm = NULL; +#endif if (nla == NULL) return -EINVAL; @@ -82,6 +85,12 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, #ifndef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) return -EOPNOTSUPP; +#else + if (tb[TCA_GACT_PROB]) { + p_parm = nla_data(tb[TCA_GACT_PROB]); + if (p_parm->ptype >= MAX_RAND) + return -EINVAL; + } #endif pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); @@ -103,8 +112,7 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, spin_lock_bh(&gact->tcf_lock); gact->tcf_action = parm->action; #ifdef CONFIG_GACT_PROB - if (tb[TCA_GACT_PROB] != NULL) { - struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]); + if (p_parm) { gact->tcfg_paction = p_parm->paction; gact->tcfg_pval = p_parm->pval; gact->tcfg_ptype = p_parm->ptype; @@ -133,7 +141,7 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, spin_lock(&gact->tcf_lock); #ifdef CONFIG_GACT_PROB - if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL) + if (gact->tcfg_ptype) action = gact_rand[gact->tcfg_ptype](gact); else action = gact->tcf_action; diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 60e281a..58fb3c7 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -185,7 +185,12 @@ err3: err2: kfree(tname); err1: - kfree(pc); + if (ret == ACT_P_CREATED) { + if (est) + gen_kill_estimator(&pc->tcfc_bstats, + &pc->tcfc_rate_est); + kfree_rcu(pc, tcfc_rcu); + } return err; } diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 26aa2f6..45c53ab 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -74,7 +74,10 @@ static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est, p = to_pedit(pc); keys = kmalloc(ksize, GFP_KERNEL); if (keys == NULL) { - kfree(pc); + if (est) + gen_kill_estimator(&pc->tcfc_bstats, + &pc->tcfc_rate_est); + kfree_rcu(pc, tcfc_rcu); return -ENOMEM; } ret = ACT_P_CREATED; diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 3922f2a..3714f60 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -131,7 +131,10 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, d = to_defact(pc); ret = alloc_defdata(d, defdata); if (ret < 0) { - kfree(pc); + if (est) + gen_kill_estimator(&pc->tcfc_bstats, + &pc->tcfc_rate_est); + kfree_rcu(pc, tcfc_rcu); return ret; } d->tcf_action = parm->action; diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 9af01f3..e4723d3 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -203,6 +203,34 @@ out: return index; } +/* Length of the next packet (0 if the queue is empty). */ +static unsigned int qdisc_peek_len(struct Qdisc *sch) +{ + struct sk_buff *skb; + + skb = sch->ops->peek(sch); + return skb ? qdisc_pkt_len(skb) : 0; +} + +static void qfq_deactivate_class(struct qfq_sched *, struct qfq_class *); +static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, + unsigned int len); + +static void qfq_update_class_params(struct qfq_sched *q, struct qfq_class *cl, + u32 lmax, u32 inv_w, int delta_w) +{ + int i; + + /* update qfq-specific data */ + cl->lmax = lmax; + cl->inv_w = inv_w; + i = qfq_calc_index(cl->inv_w, cl->lmax); + + cl->grp = &q->groups[i]; + + q->wsum += delta_w; +} + static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca, unsigned long *arg) { @@ -250,6 +278,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, lmax = 1UL << QFQ_MTU_SHIFT; if (cl != NULL) { + bool need_reactivation = false; + if (tca[TCA_RATE]) { err = gen_replace_estimator(&cl->bstats, &cl->rate_est, qdisc_root_sleeping_lock(sch), @@ -258,12 +288,29 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, return err; } - if (inv_w != cl->inv_w) { - sch_tree_lock(sch); - q->wsum += delta_w; - cl->inv_w = inv_w; - sch_tree_unlock(sch); + if (lmax == cl->lmax && inv_w == cl->inv_w) + return 0; /* nothing to update */ + + i = qfq_calc_index(inv_w, lmax); + sch_tree_lock(sch); + if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) { + /* + * shift cl->F back, to not charge the + * class for the not-yet-served head + * packet + */ + cl->F = cl->S; + /* remove class from its slot in the old group */ + qfq_deactivate_class(q, cl); + need_reactivation = true; } + + qfq_update_class_params(q, cl, lmax, inv_w, delta_w); + + if (need_reactivation) /* activate in new group */ + qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc)); + sch_tree_unlock(sch); + return 0; } @@ -273,11 +320,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->refcnt = 1; cl->common.classid = classid; - cl->lmax = lmax; - cl->inv_w = inv_w; - i = qfq_calc_index(cl->inv_w, cl->lmax); - cl->grp = &q->groups[i]; + qfq_update_class_params(q, cl, lmax, inv_w, delta_w); cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); @@ -294,7 +338,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, return err; } } - q->wsum += weight; sch_tree_lock(sch); qdisc_class_hash_insert(&q->clhash, &cl->common); @@ -711,15 +754,6 @@ static void qfq_update_eligible(struct qfq_sched *q, u64 old_V) } } -/* What is length of next packet in queue (0 if queue is empty) */ -static unsigned int qdisc_peek_len(struct Qdisc *sch) -{ - struct sk_buff *skb; - - skb = sch->ops->peek(sch); - return skb ? qdisc_pkt_len(skb) : 0; -} - /* * Updates the class, returns true if also the group needs to be updated. */ @@ -843,11 +877,8 @@ static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct qfq_sched *q = qdisc_priv(sch); - struct qfq_group *grp; struct qfq_class *cl; int err; - u64 roundedS; - int s; cl = qfq_classify(skb, sch, &err); if (cl == NULL) { @@ -876,11 +907,25 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) return err; /* If reach this point, queue q was idle */ - grp = cl->grp; + qfq_activate_class(q, cl, qdisc_pkt_len(skb)); + + return err; +} + +/* + * Handle class switch from idle to backlogged. + */ +static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl, + unsigned int pkt_len) +{ + struct qfq_group *grp = cl->grp; + u64 roundedS; + int s; + qfq_update_start(q, cl); /* compute new finish time and rounded start. */ - cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w; + cl->F = cl->S + (u64)pkt_len * cl->inv_w; roundedS = qfq_round_down(cl->S, grp->slot_shift); /* @@ -917,8 +962,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) skip_update: qfq_slot_insert(grp, cl, roundedS); - - return err; } diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 4e7ec2b..d0f0035 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -101,7 +101,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device, chunk, &tmpb) < 0) { if (!sgbuf->pages) - return NULL; + goto _failed; if (!res_size) goto _failed; size = sgbuf->pages * PAGE_SIZE; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 4f502a2..0a43662 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -326,7 +326,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst for (page = blk->first_page; page <= blk->last_page; page++, idx++) { unsigned long ofs = idx << PAGE_SHIFT; dma_addr_t addr; - addr = snd_pcm_sgbuf_get_addr(substream, ofs); + if (ofs >= runtime->dma_bytes) + addr = emu->silent_page.addr; + else + addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (! is_valid_page(emu, addr)) { printk(KERN_ERR "emu: failure page = %d\n", idx); mutex_unlock(&hdr->block_mutex); diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 647218d..4f7d2df 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -332,13 +332,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, if (cfg->dig_outs) snd_printd(" dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs:"); + snd_printd(" inputs:\n"); for (i = 0; i < cfg->num_inputs; i++) { - snd_printd(" %s=0x%x", + snd_printd(" %s=0x%x\n", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } - snd_printd("\n"); if (cfg->dig_in_pin) snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1436118..5e22a8f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2967,12 +2967,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { }; static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO), SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), @@ -2988,14 +2986,10 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO), - SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), - SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO), {} }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 69b9284..8f23374 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -877,8 +877,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; - hinfo->nid = 0; /* clear the leftover value */ - /* Validate hinfo */ pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) @@ -1163,6 +1161,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } +static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + return 0; +} + static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -1202,6 +1208,7 @@ static const struct hda_pcm_ops generic_ops = { .open = hdmi_pcm_open, .close = hdmi_pcm_close, .prepare = generic_hdmi_playback_pcm_prepare, + .cleanup = generic_hdmi_playback_pcm_cleanup, }; static int generic_hdmi_build_pcms(struct hda_codec *codec) @@ -1220,7 +1227,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr->substreams = 1; pstr->ops = generic_ops; - pstr->nid = 1; /* FIXME: just for avoiding a debug WARNING */ /* other pstr fields are set in open */ } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 344b221..4f81dd4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6099,6 +6099,8 @@ static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_PCM_44K] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, + .chained = true, + .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_STEREO_DMIC] = { .type = ALC_FIXUP_FUNC, @@ -6206,9 +6208,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), #if 0 diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 3c79592..23b4018 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2406,6 +2406,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) /* Setup AB8500 according to board-settings */ pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); + + /* Inform SoC Core that we have our own I/O arrangements. */ + codec->control_data = (void *)true; + status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); if (status < 0) { pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 8c39ddd..11b1b71 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -186,6 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) printk(KERN_INFO "AD1980 SoC Audio Codec\n"); + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 6276e35..8f726c0 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -581,6 +581,8 @@ static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); + codec->control_data = priv->mc13xxx; + mc13xxx_lock(priv->mc13xxx); /* these are the reset values */ diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 8af6a52..df2f99d 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -239,6 +239,7 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = { {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */ {"LO", NULL, "DAC"}, /* dac --> line_out */ + {"LINE_IN", NULL, "VAG_POWER"}, {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */ {"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */ @@ -1357,8 +1358,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) if (ret) goto err; - snd_soc_dapm_new_widgets(&codec->dapm); - return 0; err: diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 982e437..33c0f3d 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -340,6 +340,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) goto codec_err; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index eaf6586..aa9ce9d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2501,6 +2501,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, /* VMID 2*250k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x100); + + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + msleep(100); break; case SND_SOC_BIAS_OFF: diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bb62f4b..04ef031 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2649,7 +2649,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - bclk_rate = params_rate(params) * 2; + bclk_rate = params_rate(params) * 4; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: bclk_rate *= 16; @@ -3253,10 +3253,13 @@ static void wm8994_mic_work(struct work_struct *work) int ret; int report; + pm_runtime_get_sync(dev); + ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, ®); if (ret < 0) { dev_err(dev, "Failed to read microphone status: %d\n", ret); + pm_runtime_put(dev); return; } @@ -3299,6 +3302,8 @@ static void wm8994_mic_work(struct work_struct *work) snd_soc_jack_report(priv->micdet[1].jack, report, SND_JACK_HEADSET | SND_JACK_BTN_0); + + pm_runtime_put(dev); } static irqreturn_t wm8994_mic_irq(int irq, void *data) @@ -3421,12 +3426,15 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) int reg; bool present; + pm_runtime_get_sync(codec->dev); + mutex_lock(&wm8994->accdet_lock); reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); if (reg < 0) { dev_err(codec->dev, "Failed to read jack status: %d\n", reg); mutex_unlock(&wm8994->accdet_lock); + pm_runtime_put(codec->dev); return IRQ_NONE; } @@ -3491,6 +3499,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) SND_JACK_MECHANICAL | SND_JACK_HEADSET | wm8994->btn_mask); + pm_runtime_put(codec->dev); return IRQ_HANDLED; } @@ -3602,6 +3611,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) return IRQ_HANDLED; + pm_runtime_get_sync(codec->dev); + /* We may occasionally read a detection without an impedence * range being provided - if that happens loop again. */ @@ -3612,6 +3623,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) dev_err(codec->dev, "Failed to read mic detect status: %d\n", reg); + pm_runtime_put(codec->dev); return IRQ_NONE; } @@ -3639,6 +3651,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) dev_warn(codec->dev, "Accessory detection with no callback\n"); out: + pm_runtime_put(codec->dev); return IRQ_HANDLED; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 099e6ec..f16fb36 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -619,6 +619,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) { int ret = 0; + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 3eb19fb..d0b8a32 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1196,6 +1196,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) if (wm9713 == NULL) return -ENOMEM; snd_soc_codec_set_drvdata(codec, wm9713); + codec->control_data = wm9713; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index aba71bf..b303071 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -394,9 +394,14 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + struct mxs_saif *master_saif; u32 scr, stat; int ret; + master_saif = mxs_saif_get_master(saif); + if (!master_saif) + return -EINVAL; + /* mclk should already be set */ if (!saif->mclk && saif->mclk_in_use) { dev_err(cpu_dai->dev, "set mclk first\n"); @@ -420,6 +425,25 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, return ret; } + /* prepare clk in hw_param, enable in trigger */ + clk_prepare(saif->clk); + if (saif != master_saif) { + /* + * Set an initial clock rate for the saif internal logic to work + * properly. This is important when working in EXTMASTER mode + * that uses the other saif's BITCLK&LRCLK but it still needs a + * basic clock which should be fast enough for the internal + * logic. + */ + clk_enable(saif->clk); + ret = clk_set_rate(saif->clk, 24000000); + clk_disable(saif->clk); + if (ret) + return ret; + + clk_prepare(master_saif->clk); + } + scr = __raw_readl(saif->base + SAIF_CTRL); scr &= ~BM_SAIF_CTRL_WORD_LENGTH; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 1046083..acdd3ef 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -820,3 +820,4 @@ module_platform_driver(asoc_mcbsp_driver); MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-mcbsp"); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5a649da..f0feb06 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -441,3 +441,4 @@ module_platform_driver(omap_pcm_driver); MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-pcm-audio"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f219b2f..f81c597 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1096,7 +1096,7 @@ static int soc_probe_codec(struct snd_soc_card *card, } /* If the driver didn't set I/O up try regmap */ - if (!codec->control_data) + if (!codec->write && dev_get_regmap(codec->dev, NULL)) snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (driver->controls) diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index d684df2..e463529 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -177,7 +177,7 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) } alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (alc5632->gpio_hp_det == -ENODEV) + if (alc5632->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; ret = snd_soc_of_parse_card_name(card, "nvidia,model"); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 0c5bb33..d4f14e4 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -284,27 +284,27 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) } else if (np) { pdata->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios", 0); - if (pdata->gpio_spkr_en == -ENODEV) + if (pdata->gpio_spkr_en == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios", 0); - if (pdata->gpio_hp_mute == -ENODEV) + if (pdata->gpio_hp_mute == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (pdata->gpio_hp_det == -ENODEV) + if (pdata->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_int_mic_en = of_get_named_gpio(np, "nvidia,int-mic-en-gpios", 0); - if (pdata->gpio_int_mic_en == -ENODEV) + if (pdata->gpio_int_mic_en == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_ext_mic_en = of_get_named_gpio(np, "nvidia,ext-mic-en-gpios", 0); - if (pdata->gpio_ext_mic_en == -ENODEV) + if (pdata->gpio_ext_mic_en == -EPROBE_DEFER) return -EPROBE_DEFER; } diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 62ac028..057e28e 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -21,7 +21,7 @@ #include <linux/mfd/dbx500-prcmu.h> #include <mach/hardware.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #include <sound/soc.h> #include <sound/soc-dai.h> diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index ee14d2d..5c472f3 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <mach/hardware.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #include <sound/soc.h> diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 7f71b4a..2d9136d 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -17,7 +17,7 @@ #include <linux/platform_device.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #define MSP_INPUT_FREQ_APB 48000000 diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 77f124f..35655c3 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -319,6 +319,8 @@ LIB_H += $(ARCH_INCLUDE) LIB_H += util/cgroup.h LIB_H += $(TRACE_EVENT_DIR)event-parse.h LIB_H += util/target.h +LIB_H += util/rblist.h +LIB_H += util/intlist.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o @@ -383,6 +385,8 @@ LIB_OBJS += $(OUTPUT)util/xyarray.o LIB_OBJS += $(OUTPUT)util/cpumap.o LIB_OBJS += $(OUTPUT)util/cgroup.o LIB_OBJS += $(OUTPUT)util/target.o +LIB_OBJS += $(OUTPUT)util/rblist.o +LIB_OBJS += $(OUTPUT)util/intlist.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o @@ -983,7 +987,8 @@ clean: $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(MAKE) -C Documentation/ clean $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS - $(RM) $(OUTPUT)util/*-{bison,flex}* + $(RM) $(OUTPUT)util/*-bison* + $(RM) $(OUTPUT)util/*-flex* $(python-clean) .PHONY: all install clean strip $(LIBTRACEEVENT) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f5a6452..4db6e1b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -313,7 +313,7 @@ try_again: } } - perf_session__update_sample_type(session); + perf_session__set_id_hdr_size(session); } static int process_buildids(struct perf_record *rec) @@ -844,8 +844,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) struct perf_record *rec = &record; char errbuf[BUFSIZ]; - perf_header__set_cmdline(argc, argv); - evsel_list = perf_evlist__new(NULL, NULL); if (evsel_list == NULL) return -ENOMEM; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 69b1c11..7c88a24 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -249,8 +249,9 @@ static int process_read_event(struct perf_tool *tool, static int perf_report__setup_sample_type(struct perf_report *rep) { struct perf_session *self = rep->session; + u64 sample_type = perf_evlist__sample_type(self->evlist); - if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { + if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { ui__error("Selected --sort parent, but no " "callchain data. Did you call " @@ -274,7 +275,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep) if (sort__branch_mode == 1) { if (!self->fd_pipe && - !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { + !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { ui__error("Selected -b but no branch data. " "Did you call perf record without -b?\n"); return -1; diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index d909eb7..1d592f5 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -478,7 +478,6 @@ static int test__basic_mmap(void) unsigned int nr_events[nsyscalls], expected_nr_events[nsyscalls], i, j; struct perf_evsel *evsels[nsyscalls], *evsel; - int sample_size = __perf_evsel__sample_size(attr.sample_type); for (i = 0; i < nsyscalls; ++i) { char name[64]; @@ -563,8 +562,7 @@ static int test__basic_mmap(void) goto out_munmap; } - err = perf_event__parse_sample(event, attr.sample_type, sample_size, - false, &sample, false); + err = perf_evlist__parse_sample(evlist, event, &sample, false); if (err) { pr_err("Can't parse sample, err = %d\n", err); goto out_munmap; @@ -661,12 +659,12 @@ static int test__PERF_RECORD(void) const char *cmd = "sleep"; const char *argv[] = { cmd, "1", NULL, }; char *bname; - u64 sample_type, prev_time = 0; + u64 prev_time = 0; bool found_cmd_mmap = false, found_libc_mmap = false, found_vdso_mmap = false, found_ld_mmap = false; - int err = -1, errs = 0, i, wakeups = 0, sample_size; + int err = -1, errs = 0, i, wakeups = 0; u32 cpu; int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; @@ -757,13 +755,6 @@ static int test__PERF_RECORD(void) } /* - * We'll need these two to parse the PERF_SAMPLE_* fields in each - * event. - */ - sample_type = perf_evlist__sample_type(evlist); - sample_size = __perf_evsel__sample_size(sample_type); - - /* * Now that all is properly set up, enable the events, they will * count just on workload.pid, which will start... */ @@ -788,9 +779,7 @@ static int test__PERF_RECORD(void) if (type < PERF_RECORD_MAX) nr_events[type]++; - err = perf_event__parse_sample(event, sample_type, - sample_size, true, - &sample, false); + err = perf_evlist__parse_sample(evlist, event, &sample, false); if (err < 0) { if (verbose) perf_event__fprintf(event, stderr); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 35e86c6..68cd61e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -38,6 +38,7 @@ #include "util/cpumap.h" #include "util/xyarray.h" #include "util/sort.h" +#include "util/intlist.h" #include "util/debug.h" @@ -706,8 +707,16 @@ static void perf_event__process_sample(struct perf_tool *tool, int err; if (!machine && perf_guest) { - pr_err("Can't find guest [%d]'s kernel information\n", - event->ip.pid); + static struct intlist *seen; + + if (!seen) + seen = intlist__new(); + + if (!intlist__has_entry(seen, event->ip.pid)) { + pr_err("Can't find guest [%d]'s kernel information\n", + event->ip.pid); + intlist__add(seen, event->ip.pid); + } return; } @@ -811,7 +820,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) int ret; while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { - ret = perf_session__parse_sample(session, event, &sample); + ret = perf_evlist__parse_sample(top->evlist, event, &sample, false); if (ret) { pr_err("Can't parse sample, err = %d\n", ret); continue; @@ -943,8 +952,10 @@ try_again: * based cpu-clock-tick sw counter, which * is always available even if no PMU support: */ - if (attr->type == PERF_TYPE_HARDWARE && - attr->config == PERF_COUNT_HW_CPU_CYCLES) { + if ((err == ENOENT || err == ENXIO) && + (attr->type == PERF_TYPE_HARDWARE) && + (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { + if (verbose) ui__warning("Cycles event not supported,\n" "trying to fall back to cpu-clock-ticks\n"); @@ -1032,7 +1043,7 @@ static int __cmd_top(struct perf_top *top) &top->session->host_machine); perf_top__start_counters(top); top->session->evlist = top->evlist; - perf_session__update_sample_type(top->session); + perf_session__set_id_hdr_size(top->session); /* Wait for a minimal set of events before starting the snapshot */ poll(top->evlist->pollfd, top->evlist->nr_fds, 100); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1b19728..d84870b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -197,9 +197,6 @@ int perf_event__preprocess_sample(const union perf_event *self, const char *perf_event__name(unsigned int id); -int perf_event__parse_sample(const union perf_event *event, u64 type, - int sample_size, bool sample_id_all, - struct perf_sample *sample, bool swapped); int perf_event__synthesize_sample(union perf_event *event, u64 type, const struct perf_sample *sample, bool swapped); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3edfd34..9b38681 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -881,3 +881,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) return 0; } + +int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, + struct perf_sample *sample, bool swapped) +{ + struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node); + return perf_evsel__parse_sample(e, event, sample, swapped); +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 40d4d3c..528c1ac 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -122,6 +122,9 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist); bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); +int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, + struct perf_sample *sample, bool swapped); + bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e817713..2eaae14 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -20,7 +20,7 @@ #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) -int __perf_evsel__sample_size(u64 sample_type) +static int __perf_evsel__sample_size(u64 sample_type) { u64 mask = sample_type & PERF_SAMPLE_MASK; int size = 0; @@ -53,6 +53,7 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->attr = *attr; INIT_LIST_HEAD(&evsel->node); hists__init(&evsel->hists); + evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); } struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) @@ -728,10 +729,10 @@ static bool sample_overlap(const union perf_event *event, return false; } -int perf_event__parse_sample(const union perf_event *event, u64 type, - int sample_size, bool sample_id_all, +int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, struct perf_sample *data, bool swapped) { + u64 type = evsel->attr.sample_type; const u64 *array; /* @@ -746,14 +747,14 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, data->period = 1; if (event->header.type != PERF_RECORD_SAMPLE) { - if (!sample_id_all) + if (!evsel->attr.sample_id_all) return 0; return perf_event__parse_id_sample(event, type, data, swapped); } array = event->sample.array; - if (sample_size + sizeof(event->header) > event->header.size) + if (evsel->sample_size + sizeof(event->header) > event->header.size) return -EFAULT; if (type & PERF_SAMPLE_IP) { @@ -895,7 +896,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u.val32[1] = sample->tid; if (swapped) { /* - * Inverse of what is done in perf_event__parse_sample + * Inverse of what is done in perf_evsel__parse_sample */ u.val32[0] = bswap_32(u.val32[0]); u.val32[1] = bswap_32(u.val32[1]); @@ -930,7 +931,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u.val32[0] = sample->cpu; if (swapped) { /* - * Inverse of what is done in perf_event__parse_sample + * Inverse of what is done in perf_evsel__parse_sample */ u.val32[0] = bswap_32(u.val32[0]); u.val64 = bswap_64(u.val64); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 67cc503..b559929 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -65,6 +65,7 @@ struct perf_evsel { void *func; void *data; } handler; + unsigned int sample_size; bool supported; }; @@ -177,13 +178,8 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel, return __perf_evsel__read(evsel, ncpus, nthreads, true); } -int __perf_evsel__sample_size(u64 sample_type); - -static inline int perf_evsel__sample_size(struct perf_evsel *evsel) -{ - return __perf_evsel__sample_size(evsel->attr.sample_type); -} - void hists__init(struct hists *hists); +int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, + struct perf_sample *sample, bool swapped); #endif /* __PERF_EVSEL_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 3a6d204..74ea3c2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -174,6 +174,15 @@ perf_header__set_cmdline(int argc, const char **argv) { int i; + /* + * If header_argv has already been set, do not override it. + * This allows a command to set the cmdline, parse args and + * then call another builtin function that implements a + * command -- e.g, cmd_kvm calling cmd_record. + */ + if (header_argv) + return 0; + header_argc = (u32)argc; /* do not include NULL termination */ diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c new file mode 100644 index 0000000..fd530dc --- /dev/null +++ b/tools/perf/util/intlist.c @@ -0,0 +1,101 @@ +/* + * Based on intlist.c by: + * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com> + * + * Licensed under the GPLv2. + */ + +#include <errno.h> +#include <stdlib.h> +#include <linux/compiler.h> + +#include "intlist.h" + +static struct rb_node *intlist__node_new(struct rblist *rblist __used, + const void *entry) +{ + int i = (int)((long)entry); + struct rb_node *rc = NULL; + struct int_node *node = malloc(sizeof(*node)); + + if (node != NULL) { + node->i = i; + rc = &node->rb_node; + } + + return rc; +} + +static void int_node__delete(struct int_node *ilist) +{ + free(ilist); +} + +static void intlist__node_delete(struct rblist *rblist __used, + struct rb_node *rb_node) +{ + struct int_node *node = container_of(rb_node, struct int_node, rb_node); + + int_node__delete(node); +} + +static int intlist__node_cmp(struct rb_node *rb_node, const void *entry) +{ + int i = (int)((long)entry); + struct int_node *node = container_of(rb_node, struct int_node, rb_node); + + return node->i - i; +} + +int intlist__add(struct intlist *ilist, int i) +{ + return rblist__add_node(&ilist->rblist, (void *)((long)i)); +} + +void intlist__remove(struct intlist *ilist __used, struct int_node *node) +{ + int_node__delete(node); +} + +struct int_node *intlist__find(struct intlist *ilist, int i) +{ + struct int_node *node = NULL; + struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); + + if (rb_node) + node = container_of(rb_node, struct int_node, rb_node); + + return node; +} + +struct intlist *intlist__new(void) +{ + struct intlist *ilist = malloc(sizeof(*ilist)); + + if (ilist != NULL) { + rblist__init(&ilist->rblist); + ilist->rblist.node_cmp = intlist__node_cmp; + ilist->rblist.node_new = intlist__node_new; + ilist->rblist.node_delete = intlist__node_delete; + } + + return ilist; +} + +void intlist__delete(struct intlist *ilist) +{ + if (ilist != NULL) + rblist__delete(&ilist->rblist); +} + +struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx) +{ + struct int_node *node = NULL; + struct rb_node *rb_node; + + rb_node = rblist__entry(&ilist->rblist, idx); + if (rb_node) + node = container_of(rb_node, struct int_node, rb_node); + + return node; +} diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h new file mode 100644 index 0000000..6d63ab9 --- /dev/null +++ b/tools/perf/util/intlist.h @@ -0,0 +1,75 @@ +#ifndef __PERF_INTLIST_H +#define __PERF_INTLIST_H + +#include <linux/rbtree.h> +#include <stdbool.h> + +#include "rblist.h" + +struct int_node { + struct rb_node rb_node; + int i; +}; + +struct intlist { + struct rblist rblist; +}; + +struct intlist *intlist__new(void); +void intlist__delete(struct intlist *ilist); + +void intlist__remove(struct intlist *ilist, struct int_node *in); +int intlist__add(struct intlist *ilist, int i); + +struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx); +struct int_node *intlist__find(struct intlist *ilist, int i); + +static inline bool intlist__has_entry(struct intlist *ilist, int i) +{ + return intlist__find(ilist, i) != NULL; +} + +static inline bool intlist__empty(const struct intlist *ilist) +{ + return rblist__empty(&ilist->rblist); +} + +static inline unsigned int intlist__nr_entries(const struct intlist *ilist) +{ + return rblist__nr_entries(&ilist->rblist); +} + +/* For intlist iteration */ +static inline struct int_node *intlist__first(struct intlist *ilist) +{ + struct rb_node *rn = rb_first(&ilist->rblist.entries); + return rn ? rb_entry(rn, struct int_node, rb_node) : NULL; +} +static inline struct int_node *intlist__next(struct int_node *in) +{ + struct rb_node *rn; + if (!in) + return NULL; + rn = rb_next(&in->rb_node); + return rn ? rb_entry(rn, struct int_node, rb_node) : NULL; +} + +/** + * intlist_for_each - iterate over a intlist + * @pos: the &struct int_node to use as a loop cursor. + * @ilist: the &struct intlist for loop. + */ +#define intlist__for_each(pos, ilist) \ + for (pos = intlist__first(ilist); pos; pos = intlist__next(pos)) + +/** + * intlist_for_each_safe - iterate over a intlist safe against removal of + * int_node + * @pos: the &struct int_node to use as a loop cursor. + * @n: another &struct int_node to use as temporary storage. + * @ilist: the &struct intlist for loop. + */ +#define intlist__for_each_safe(pos, n, ilist) \ + for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\ + pos = n, n = intlist__next(n)) +#endif /* __PERF_INTLIST_H */ diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index 1b997d2..127d648 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c @@ -13,6 +13,9 @@ do { \ } \ } while (0) +#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ + PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) + static int test__checkevent_tracepoint(struct perf_evlist *evlist) { struct perf_evsel *evsel = list_entry(evlist->entries.next, @@ -21,8 +24,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); TEST_ASSERT_VAL("wrong sample_type", - (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == - evsel->attr.sample_type); + PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); return 0; } @@ -37,8 +39,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); TEST_ASSERT_VAL("wrong sample_type", - (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) - == evsel->attr.sample_type); + PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); } @@ -428,8 +429,7 @@ static int test__checkevent_list(struct perf_evlist *evlist) evsel = list_entry(evsel->node.next, struct perf_evsel, node); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); TEST_ASSERT_VAL("wrong sample_type", - (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == - evsel->attr.sample_type); + PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 99d02aa..594f8fa 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -1,6 +1,7 @@ #include "util.h" #include "parse-options.h" #include "cache.h" +#include "header.h" #define OPT_SHORT 1 #define OPT_UNSET 2 @@ -413,6 +414,8 @@ int parse_options(int argc, const char **argv, const struct option *options, { struct parse_opt_ctx_t ctx; + perf_header__set_cmdline(argc, argv); + parse_options_start(&ctx, argc, argv, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index e03b58a..0688bfb 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -797,17 +797,13 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, event = perf_evlist__mmap_read(evlist, cpu); if (event != NULL) { - struct perf_evsel *first; PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; if (pyevent == NULL) return PyErr_NoMemory(); - first = list_entry(evlist->entries.next, struct perf_evsel, node); - err = perf_event__parse_sample(event, first->attr.sample_type, - perf_evsel__sample_size(first), - sample_id_all, &pevent->sample, false); + err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false); if (err) return PyErr_Format(PyExc_OSError, "perf: can't parse sample, err=%d", err); diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c new file mode 100644 index 0000000..0171fb6 --- /dev/null +++ b/tools/perf/util/rblist.c @@ -0,0 +1,107 @@ +/* + * Based on strlist.c by: + * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com> + * + * Licensed under the GPLv2. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "rblist.h" + +int rblist__add_node(struct rblist *rblist, const void *new_entry) +{ + struct rb_node **p = &rblist->entries.rb_node; + struct rb_node *parent = NULL, *new_node; + + while (*p != NULL) { + int rc; + + parent = *p; + + rc = rblist->node_cmp(parent, new_entry); + if (rc > 0) + p = &(*p)->rb_left; + else if (rc < 0) + p = &(*p)->rb_right; + else + return -EEXIST; + } + + new_node = rblist->node_new(rblist, new_entry); + if (new_node == NULL) + return -ENOMEM; + + rb_link_node(new_node, parent, p); + rb_insert_color(new_node, &rblist->entries); + ++rblist->nr_entries; + + return 0; +} + +void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) +{ + rb_erase(rb_node, &rblist->entries); + rblist->node_delete(rblist, rb_node); +} + +struct rb_node *rblist__find(struct rblist *rblist, const void *entry) +{ + struct rb_node **p = &rblist->entries.rb_node; + struct rb_node *parent = NULL; + + while (*p != NULL) { + int rc; + + parent = *p; + + rc = rblist->node_cmp(parent, entry); + if (rc > 0) + p = &(*p)->rb_left; + else if (rc < 0) + p = &(*p)->rb_right; + else + return parent; + } + + return NULL; +} + +void rblist__init(struct rblist *rblist) +{ + if (rblist != NULL) { + rblist->entries = RB_ROOT; + rblist->nr_entries = 0; + } + + return; +} + +void rblist__delete(struct rblist *rblist) +{ + if (rblist != NULL) { + struct rb_node *pos, *next = rb_first(&rblist->entries); + + while (next) { + pos = next; + next = rb_next(pos); + rb_erase(pos, &rblist->entries); + rblist->node_delete(rblist, pos); + } + free(rblist); + } +} + +struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx) +{ + struct rb_node *node; + + for (node = rb_first(&rblist->entries); node; node = rb_next(node)) { + if (!idx--) + return node; + } + + return NULL; +} diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h new file mode 100644 index 0000000..6d0cae5 --- /dev/null +++ b/tools/perf/util/rblist.h @@ -0,0 +1,47 @@ +#ifndef __PERF_RBLIST_H +#define __PERF_RBLIST_H + +#include <linux/rbtree.h> +#include <stdbool.h> + +/* + * create node structs of the form: + * struct my_node { + * struct rb_node rb_node; + * ... my data ... + * }; + * + * create list structs of the form: + * struct mylist { + * struct rblist rblist; + * ... my data ... + * }; + */ + +struct rblist { + struct rb_root entries; + unsigned int nr_entries; + + int (*node_cmp)(struct rb_node *rbn, const void *entry); + struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry); + void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node); +}; + +void rblist__init(struct rblist *rblist); +void rblist__delete(struct rblist *rblist); +int rblist__add_node(struct rblist *rblist, const void *new_entry); +void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node); +struct rb_node *rblist__find(struct rblist *rblist, const void *entry); +struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx); + +static inline bool rblist__empty(const struct rblist *rblist) +{ + return rblist->nr_entries == 0; +} + +static inline unsigned int rblist__nr_entries(const struct rblist *rblist) +{ + return rblist->nr_entries; +} + +#endif /* __PERF_RBLIST_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8e4f075..2437fb0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -80,14 +80,12 @@ out_close: return -1; } -void perf_session__update_sample_type(struct perf_session *self) +void perf_session__set_id_hdr_size(struct perf_session *session) { - self->sample_type = perf_evlist__sample_type(self->evlist); - self->sample_size = __perf_evsel__sample_size(self->sample_type); - self->sample_id_all = perf_evlist__sample_id_all(self->evlist); - self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); - self->host_machine.id_hdr_size = self->id_hdr_size; - machines__set_id_hdr_size(&self->machines, self->id_hdr_size); + u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); + + session->host_machine.id_hdr_size = id_hdr_size; + machines__set_id_hdr_size(&session->machines, id_hdr_size); } int perf_session__create_kernel_maps(struct perf_session *self) @@ -147,7 +145,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, if (mode == O_RDONLY) { if (perf_session__open(self, force) < 0) goto out_delete; - perf_session__update_sample_type(self); + perf_session__set_id_hdr_size(self); } else if (mode == O_WRONLY) { /* * In O_RDONLY mode this will be performed when reading the @@ -158,7 +156,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, } if (tool && tool->ordering_requires_timestamps && - tool->ordered_samples && !self->sample_id_all) { + tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_samples = false; } @@ -673,7 +671,8 @@ static void flush_sample_queue(struct perf_session *s, if (iter->timestamp > limit) break; - ret = perf_session__parse_sample(s, iter->event, &sample); + ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample, + s->header.needs_swap); if (ret) pr_err("Can't parse sample, err = %d\n", ret); else @@ -865,16 +864,18 @@ static void perf_session__print_tstamp(struct perf_session *session, union perf_event *event, struct perf_sample *sample) { + u64 sample_type = perf_evlist__sample_type(session->evlist); + if (event->header.type != PERF_RECORD_SAMPLE && - !session->sample_id_all) { + !perf_evlist__sample_id_all(session->evlist)) { fputs("-1 -1 ", stdout); return; } - if ((session->sample_type & PERF_SAMPLE_CPU)) + if ((sample_type & PERF_SAMPLE_CPU)) printf("%u ", sample->cpu); - if (session->sample_type & PERF_SAMPLE_TIME) + if (sample_type & PERF_SAMPLE_TIME) printf("%" PRIu64 " ", sample->time); } @@ -899,6 +900,8 @@ static void dump_event(struct perf_session *session, union perf_event *event, static void dump_sample(struct perf_session *session, union perf_event *event, struct perf_sample *sample) { + u64 sample_type; + if (!dump_trace) return; @@ -906,10 +909,12 @@ static void dump_sample(struct perf_session *session, union perf_event *event, event->header.misc, sample->pid, sample->tid, sample->ip, sample->period, sample->addr); - if (session->sample_type & PERF_SAMPLE_CALLCHAIN) + sample_type = perf_evlist__sample_type(session->evlist); + + if (sample_type & PERF_SAMPLE_CALLCHAIN) callchain__printf(sample); - if (session->sample_type & PERF_SAMPLE_BRANCH_STACK) + if (sample_type & PERF_SAMPLE_BRANCH_STACK) branch_stack__printf(sample); } @@ -1006,7 +1011,7 @@ static int perf_session__preprocess_sample(struct perf_session *session, union perf_event *event, struct perf_sample *sample) { if (event->header.type != PERF_RECORD_SAMPLE || - !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) + !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN)) return 0; if (!ip_callchain__valid(sample->callchain, event)) { @@ -1030,7 +1035,7 @@ static int perf_session__process_user_event(struct perf_session *session, union case PERF_RECORD_HEADER_ATTR: err = tool->attr(event, &session->evlist); if (err == 0) - perf_session__update_sample_type(session); + perf_session__set_id_hdr_size(session); return err; case PERF_RECORD_HEADER_EVENT_TYPE: return tool->event_type(tool, event); @@ -1065,7 +1070,7 @@ static int perf_session__process_event(struct perf_session *session, int ret; if (session->header.needs_swap) - event_swap(event, session->sample_id_all); + event_swap(event, perf_evlist__sample_id_all(session->evlist)); if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; @@ -1078,7 +1083,8 @@ static int perf_session__process_event(struct perf_session *session, /* * For all kernel events we get the sample data */ - ret = perf_session__parse_sample(session, event, &sample); + ret = perf_evlist__parse_sample(session->evlist, event, &sample, + session->header.needs_swap); if (ret) return ret; @@ -1389,9 +1395,9 @@ int perf_session__process_events(struct perf_session *self, return err; } -bool perf_session__has_traces(struct perf_session *self, const char *msg) +bool perf_session__has_traces(struct perf_session *session, const char *msg) { - if (!(self->sample_type & PERF_SAMPLE_RAW)) { + if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); return false; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 7c435bd..1f7ec87 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -41,13 +41,9 @@ struct perf_session { * perf.data file. */ struct hists hists; - u64 sample_type; - int sample_size; int fd; bool fd_pipe; bool repipe; - bool sample_id_all; - u16 id_hdr_size; int cwdlen; char *cwd; struct ordered_samples ordered_samples; @@ -86,7 +82,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr); int perf_session__create_kernel_maps(struct perf_session *self); -void perf_session__update_sample_type(struct perf_session *self); +void perf_session__set_id_hdr_size(struct perf_session *session); void perf_session__remove_thread(struct perf_session *self, struct thread *th); static inline @@ -130,24 +126,6 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); -static inline int perf_session__parse_sample(struct perf_session *session, - const union perf_event *event, - struct perf_sample *sample) -{ - return perf_event__parse_sample(event, session->sample_type, - session->sample_size, - session->sample_id_all, sample, - session->header.needs_swap); -} - -static inline int perf_session__synthesize_sample(struct perf_session *session, - union perf_event *event, - const struct perf_sample *sample) -{ - return perf_event__synthesize_sample(event, session->sample_type, - sample, session->header.needs_swap); -} - struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 6783a20..95856ff 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c @@ -10,23 +10,28 @@ #include <stdlib.h> #include <string.h> -static struct str_node *str_node__new(const char *s, bool dupstr) +static +struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry) { - struct str_node *self = malloc(sizeof(*self)); + const char *s = entry; + struct rb_node *rc = NULL; + struct strlist *strlist = container_of(rblist, struct strlist, rblist); + struct str_node *snode = malloc(sizeof(*snode)); - if (self != NULL) { - if (dupstr) { + if (snode != NULL) { + if (strlist->dupstr) { s = strdup(s); if (s == NULL) goto out_delete; } - self->s = s; + snode->s = s; + rc = &snode->rb_node; } - return self; + return rc; out_delete: - free(self); + free(snode); return NULL; } @@ -37,36 +42,26 @@ static void str_node__delete(struct str_node *self, bool dupstr) free(self); } -int strlist__add(struct strlist *self, const char *new_entry) +static +void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node) { - struct rb_node **p = &self->entries.rb_node; - struct rb_node *parent = NULL; - struct str_node *sn; - - while (*p != NULL) { - int rc; - - parent = *p; - sn = rb_entry(parent, struct str_node, rb_node); - rc = strcmp(sn->s, new_entry); - - if (rc > 0) - p = &(*p)->rb_left; - else if (rc < 0) - p = &(*p)->rb_right; - else - return -EEXIST; - } + struct strlist *slist = container_of(rblist, struct strlist, rblist); + struct str_node *snode = container_of(rb_node, struct str_node, rb_node); - sn = str_node__new(new_entry, self->dupstr); - if (sn == NULL) - return -ENOMEM; + str_node__delete(snode, slist->dupstr); +} - rb_link_node(&sn->rb_node, parent, p); - rb_insert_color(&sn->rb_node, &self->entries); - ++self->nr_entries; +static int strlist__node_cmp(struct rb_node *rb_node, const void *entry) +{ + const char *str = entry; + struct str_node *snode = container_of(rb_node, struct str_node, rb_node); + + return strcmp(snode->s, str); +} - return 0; +int strlist__add(struct strlist *self, const char *new_entry) +{ + return rblist__add_node(&self->rblist, new_entry); } int strlist__load(struct strlist *self, const char *filename) @@ -96,34 +91,20 @@ out: return err; } -void strlist__remove(struct strlist *self, struct str_node *sn) +void strlist__remove(struct strlist *slist, struct str_node *snode) { - rb_erase(&sn->rb_node, &self->entries); - str_node__delete(sn, self->dupstr); + str_node__delete(snode, slist->dupstr); } -struct str_node *strlist__find(struct strlist *self, const char *entry) +struct str_node *strlist__find(struct strlist *slist, const char *entry) { - struct rb_node **p = &self->entries.rb_node; - struct rb_node *parent = NULL; - - while (*p != NULL) { - struct str_node *sn; - int rc; - - parent = *p; - sn = rb_entry(parent, struct str_node, rb_node); - rc = strcmp(sn->s, entry); - - if (rc > 0) - p = &(*p)->rb_left; - else if (rc < 0) - p = &(*p)->rb_right; - else - return sn; - } + struct str_node *snode = NULL; + struct rb_node *rb_node = rblist__find(&slist->rblist, entry); - return NULL; + if (rb_node) + snode = container_of(rb_node, struct str_node, rb_node); + + return snode; } static int strlist__parse_list_entry(struct strlist *self, const char *s) @@ -156,9 +137,12 @@ struct strlist *strlist__new(bool dupstr, const char *slist) struct strlist *self = malloc(sizeof(*self)); if (self != NULL) { - self->entries = RB_ROOT; + rblist__init(&self->rblist); + self->rblist.node_cmp = strlist__node_cmp; + self->rblist.node_new = strlist__node_new; + self->rblist.node_delete = strlist__node_delete; + self->dupstr = dupstr; - self->nr_entries = 0; if (slist && strlist__parse_list(self, slist) != 0) goto out_error; } @@ -171,30 +155,18 @@ out_error: void strlist__delete(struct strlist *self) { - if (self != NULL) { - struct str_node *pos; - struct rb_node *next = rb_first(&self->entries); - - while (next) { - pos = rb_entry(next, struct str_node, rb_node); - next = rb_next(&pos->rb_node); - strlist__remove(self, pos); - } - self->entries = RB_ROOT; - free(self); - } + if (self != NULL) + rblist__delete(&self->rblist); } -struct str_node *strlist__entry(const struct strlist *self, unsigned int idx) +struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) { - struct rb_node *nd; + struct str_node *snode = NULL; + struct rb_node *rb_node; - for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { - struct str_node *pos = rb_entry(nd, struct str_node, rb_node); + rb_node = rblist__entry(&slist->rblist, idx); + if (rb_node) + snode = container_of(rb_node, struct str_node, rb_node); - if (!idx--) - return pos; - } - - return NULL; + return snode; } diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index 3ba8390..dd9f922 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h @@ -4,14 +4,15 @@ #include <linux/rbtree.h> #include <stdbool.h> +#include "rblist.h" + struct str_node { struct rb_node rb_node; const char *s; }; struct strlist { - struct rb_root entries; - unsigned int nr_entries; + struct rblist rblist; bool dupstr; }; @@ -32,18 +33,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry) static inline bool strlist__empty(const struct strlist *self) { - return self->nr_entries == 0; + return rblist__empty(&self->rblist); } static inline unsigned int strlist__nr_entries(const struct strlist *self) { - return self->nr_entries; + return rblist__nr_entries(&self->rblist); } /* For strlist iteration */ static inline struct str_node *strlist__first(struct strlist *self) { - struct rb_node *rn = rb_first(&self->entries); + struct rb_node *rn = rb_first(&self->rblist.entries); return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; } static inline struct str_node *strlist__next(struct str_node *sn) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fdad4eee..8b63b67 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -64,7 +64,7 @@ static enum dso_binary_type binary_type_symtab[] = { DSO_BINARY_TYPE__NOT_FOUND, }; -#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab) +#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) static enum dso_binary_type binary_type_data[] = { DSO_BINARY_TYPE__BUILD_ID_CACHE, @@ -72,7 +72,7 @@ static enum dso_binary_type binary_type_data[] = { DSO_BINARY_TYPE__NOT_FOUND, }; -#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data) +#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data) int dso__name_len(const struct dso *dso) { @@ -2875,6 +2875,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines) int i, items = 0; char path[PATH_MAX]; pid_t pid; + char *endp; if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_modules || @@ -2891,7 +2892,14 @@ int machines__create_guest_kernel_maps(struct rb_root *machines) /* Filter out . and .. */ continue; } - pid = atoi(namelist[i]->d_name); + pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); + if ((*endp != '\0') || + (endp == namelist[i]->d_name) || + (errno == ERANGE)) { + pr_debug("invalid directory (%s). Skipping.\n", + namelist[i]->d_name); + continue; + } sprintf(path, "%s/%s/proc/kallsyms", symbol_conf.guestmount, namelist[i]->d_name); diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 3f59c49..051eaa6 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -110,7 +110,7 @@ int perf_target__strerror(struct perf_target *target, int errnum, int idx; const char *msg; - BUG_ON(buflen > 0); + BUG_ON(buflen == 0); if (errnum >= 0) { const char *err = strerror_r(errnum, buf, buflen); |