diff options
816 files changed, 29493 insertions, 12161 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 01e769d6984d..37559a06393b 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -1,13 +1,13 @@ What: /config/usb-gadget Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains sub-groups corresponding to created USB gadgets. What: /config/usb-gadget/gadget Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes of a gadget: @@ -27,7 +27,7 @@ Description: What: /config/usb-gadget/gadget/configs Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains a USB gadget's configurations @@ -58,20 +58,20 @@ Description: What: /config/usb-gadget/gadget/functions Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains functions available to this USB gadget. What: /config/usb-gadget/gadget/strings Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This group contains subdirectories for language-specific strings for this gadget. What: /config/usb-gadget/gadget/strings/language Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-acm b/Documentation/ABI/testing/configfs-usb-gadget-acm index 5708a568b5f6..d21092d75a05 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-acm +++ b/Documentation/ABI/testing/configfs-usb-gadget-acm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/acm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ecm b/Documentation/ABI/testing/configfs-usb-gadget-ecm index 6b9a582ce0b5..0addf7704b4c 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ecm +++ b/Documentation/ABI/testing/configfs-usb-gadget-ecm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ecm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-eem b/Documentation/ABI/testing/configfs-usb-gadget-eem index dbddf36b48b3..a4c57158fcde 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-eem +++ b/Documentation/ABI/testing/configfs-usb-gadget-eem @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/eem.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ffs b/Documentation/ABI/testing/configfs-usb-gadget-ffs index 14343e237e83..e39b27653c65 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ffs +++ b/Documentation/ABI/testing/configfs-usb-gadget-ffs @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ffs.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The purpose of this directory is to create and remove it. A corresponding USB function instance is created/removed. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-loopback b/Documentation/ABI/testing/configfs-usb-gadget-loopback index 852b2365a5b5..9aae5bfb9908 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-loopback +++ b/Documentation/ABI/testing/configfs-usb-gadget-loopback @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/Loopback.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage index ad72a37ee9ff..9931fb0d63ba 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage +++ b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/mass_storage.name Date: Oct 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: @@ -13,7 +13,7 @@ Description: What: /config/usb-gadget/gadget/functions/mass_storage.name/lun.name Date: Oct 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ncm b/Documentation/ABI/testing/configfs-usb-gadget-ncm index bc309f42357d..6fe723effc78 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-ncm +++ b/Documentation/ABI/testing/configfs-usb-gadget-ncm @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/ncm.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-obex b/Documentation/ABI/testing/configfs-usb-gadget-obex index aaa5c96fb7c6..a6a9327ed9ba 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-obex +++ b/Documentation/ABI/testing/configfs-usb-gadget-obex @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/obex.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-phonet b/Documentation/ABI/testing/configfs-usb-gadget-phonet index 3e3b742cdfd7..7037a358e6c4 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-phonet +++ b/Documentation/ABI/testing/configfs-usb-gadget-phonet @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/phonet.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: ifname. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index 822e6dad8fc0..e32879b84b4d 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/rndis.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-serial b/Documentation/ABI/testing/configfs-usb-gadget-serial index 16f130c1501f..474d249f760b 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-serial +++ b/Documentation/ABI/testing/configfs-usb-gadget-serial @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/gser.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: This item contains just one readonly attribute: port_num. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink index a30f3093ef6c..29477c319f61 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink +++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/SourceSink.name Date: Nov 2013 -KenelVersion: 3.13 +KernelVersion: 3.13 Description: The attributes: diff --git a/Documentation/ABI/testing/configfs-usb-gadget-subset b/Documentation/ABI/testing/configfs-usb-gadget-subset index 154ae597cd99..9373e2c51ea4 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-subset +++ b/Documentation/ABI/testing/configfs-usb-gadget-subset @@ -1,6 +1,6 @@ What: /config/usb-gadget/gadget/functions/geth.name Date: Jun 2013 -KenelVersion: 3.11 +KernelVersion: 3.11 Description: The attributes: diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index 0a306476424e..501adc2a9ec7 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -18,6 +18,28 @@ Removal of a device: $ echo <dev-id> > /sys/bus/rbd/remove +What: /sys/bus/rbd/add_single_major +Date: December 2013 +KernelVersion: 3.14 +Contact: Sage Weil <sage@inktank.com> +Description: Available only if rbd module is inserted with single_major + parameter set to true. + Usage is the same as for /sys/bus/rbd/add. If present, + should be used instead of the latter: any attempts to use + /sys/bus/rbd/add if /sys/bus/rbd/add_single_major is + available will fail for backwards compatibility reasons. + +What: /sys/bus/rbd/remove_single_major +Date: December 2013 +KernelVersion: 3.14 +Contact: Sage Weil <sage@inktank.com> +Description: Available only if rbd module is inserted with single_major + parameter set to true. + Usage is the same as for /sys/bus/rbd/remove. If present, + should be used instead of the latter: any attempts to use + /sys/bus/rbd/remove if /sys/bus/rbd/remove_single_major is + available will fail for backwards compatibility reasons. + Entries under /sys/bus/rbd/devices/<dev-id>/ -------------------------------------------- @@ -33,6 +55,10 @@ major The block device major number. +minor + + The block device minor number. (December 2013, since 3.14.) + name The name of the rbd image. diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt index 611f5a5499b1..fa0151a712f9 100644 --- a/Documentation/debugging-via-ohci1394.txt +++ b/Documentation/debugging-via-ohci1394.txt @@ -22,10 +22,12 @@ locations such as buffers like the printk buffer or the process table. Retrieving a full system memory dump is also possible over the FireWire, using data transfer rates in the order of 10MB/s or more. -Memory access is currently limited to the low 4G of physical address -space which can be a problem on IA64 machines where memory is located -mostly above that limit, but it is rarely a problem on more common -hardware such as hardware based on x86, x86-64 and PowerPC. +With most FireWire controllers, memory access is limited to the low 4 GB +of physical address space. This can be a problem on IA64 machines where +memory is located mostly above that limit, but it is rarely a problem on +more common hardware such as x86, x86-64 and PowerPC. However, at least +Agere/LSI FW643e and FW643e2 controllers are known to support access to +physical addresses above 4 GB. Together with a early initialization of the OHCI-1394 controller for debugging, this facility proved most useful for examining long debugs logs in the printk @@ -36,17 +38,11 @@ available (notebooks) or too slow for extensive debug information (like ACPI). Drivers ------- -The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers -to a working state and enables physical DMA by default for all remote nodes. -This can be turned off by ohci1394's module parameter phys_dma=0. - -The alternative firewire-ohci driver in drivers/firewire uses filtered physical +The firewire-ohci driver in drivers/firewire uses filtered physical DMA by default, which is more secure but not suitable for remote debugging. -Compile the driver with CONFIG_FIREWIRE_OHCI_REMOTE_DMA (Kernel hacking menu: -Remote debugging over FireWire with firewire-ohci) to get unfiltered physical -DMA. +Pass the remote_dma=1 parameter to the driver to get unfiltered physical DMA. -Because ohci1394 and firewire-ohci depend on the PCI enumeration to be +Because the firewire-ohci driver depends on the PCI enumeration to be completed, an initialization routine which runs pretty early has been implemented for x86. This routine runs long before console_init() can be called, i.e. before the printk buffer appears on the console. @@ -64,7 +60,7 @@ be used to view the printk buffer of a remote machine, even with live update. Bernhard Kaindl enhanced firescope to support accessing 64-bit machines from 32-bit firescope and vice versa: -- http://halobates.de/firewire/firescope-0.2.2.tar.bz2 +- http://v3.sk/~lkundrak/firescope/ and he implemented fast system dump (alpha version - read README.txt): - http://halobates.de/firewire/firedump-0.1.tar.bz2 @@ -92,11 +88,11 @@ Step-by-step instructions for using firescope with early OHCI initialization: 1) Verify that your hardware is supported: - Load the ohci1394 or the fw-ohci module and check your kernel logs. + Load the firewire-ohci module and check your kernel logs. You should see a line similar to - ohci1394: fw-host0: OHCI-1394 1.1 (PCI): IRQ=[18] MMIO=[fe9ff800-fe9fffff] - ... Max Packet=[2048] IR/IT contexts=[4/8] + firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT + ... contexts, quirks 0x11 when loading the driver. If you have no supported controller, many PCI, CardBus and even some Express cards which are fully compliant to OHCI-1394 @@ -105,6 +101,9 @@ Step-by-step instructions for using firescope with early OHCI initialization: compliant, they are based on TI PCILynx chips and require drivers for Win- dows operating systems. + The mentioned kernel log message contains ">4 GB phys DMA" in case of + OHCI-1394 controllers which support accesses above this limit. + 2) Establish a working FireWire cable connection: Any FireWire cable, as long at it provides electrically and mechanically @@ -113,20 +112,18 @@ Step-by-step instructions for using firescope with early OHCI initialization: If an driver is running on both machines you should see a line like - ieee1394: Node added: ID:BUS[0-01:1023] GUID[0090270001b84bba] + firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400 on both machines in the kernel log when the cable is plugged in and connects the two machines. 3) Test physical DMA using firescope: - On the debug host, - - load the raw1394 module, - - make sure that /dev/raw1394 is accessible, + On the debug host, make sure that /dev/fw* is accessible, then start firescope: $ firescope - Port 0 (ohci1394) opened, 2 nodes detected + Port 0 (/dev/fw1) opened, 2 nodes detected FireScope --------- diff --git a/Documentation/devicetree/bindings/arm/davinci/nand.txt b/Documentation/devicetree/bindings/arm/davinci/nand.txt deleted file mode 100644 index 3545ea704b50..000000000000 --- a/Documentation/devicetree/bindings/arm/davinci/nand.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Texas Instruments Davinci NAND - -This file provides information, what the device node for the -davinci nand interface contain. - -Required properties: -- compatible: "ti,davinci-nand"; -- reg : contain 2 offset/length values: - - offset and length for the access window - - offset and length for accessing the aemif control registers -- ti,davinci-chipselect: Indicates on the davinci_nand driver which - chipselect is used for accessing the nand. - -Recommended properties : -- ti,davinci-mask-ale: mask for ale -- ti,davinci-mask-cle: mask for cle -- ti,davinci-mask-chipsel: mask for chipselect -- ti,davinci-ecc-mode: ECC mode valid values for davinci driver: - - "none" - - "soft" - - "hw" -- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. -- ti,davinci-nand-buswidth: buswidth 8 or 16 -- ti,davinci-nand-use-bbt: use flash based bad block table support. - -nand device bindings may contain additional sub-nodes describing -partitions of the address space. See partition.txt for more detail. - -Example(da850 EVM ): -nand_cs3@62000000 { - compatible = "ti,davinci-nand"; - reg = <0x62000000 0x807ff - 0x68000000 0x8000>; - ti,davinci-chipselect = <1>; - ti,davinci-mask-ale = <0>; - ti,davinci-mask-cle = <0>; - ti,davinci-mask-chipsel = <0>; - ti,davinci-ecc-mode = "hw"; - ti,davinci-ecc-bits = <4>; - ti,davinci-nand-use-bbt; - - partition@180000 { - label = "ubifs"; - reg = <0x180000 0x7e80000>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/ti/apll.txt b/Documentation/devicetree/bindings/clock/ti/apll.txt new file mode 100644 index 000000000000..7faf5a68b3be --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/apll.txt @@ -0,0 +1,31 @@ +Binding for Texas Instruments APLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped APLL with usually two selectable input clocks +(reference clock and bypass clock), with analog phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) APLL mostly behaves like +a subtype of a DPLL [2], although a simplified one at that. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/dpll.txt + +Required properties: +- compatible : shall be "ti,dra7-apll-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks (clk-ref and clk-bypass) +- reg : address and length of the register set for controlling the APLL. + It contains the information of registers in the following order: + "control" - contains the control register base address + "idlest" - contains the idlest register base address + +Examples: + apll_pcie_ck: apll_pcie_ck@4a008200 { + #clock-cells = <0>; + clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; + reg = <0x4a00821c 0x4>, <0x4a008220 0x4>; + compatible = "ti,dra7-apll-clock"; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/autoidle.txt b/Documentation/devicetree/bindings/clock/ti/autoidle.txt new file mode 100644 index 000000000000..7c735dde9fe9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/autoidle.txt @@ -0,0 +1,39 @@ +Binding for Texas Instruments autoidle clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a register mapped +clock which can be put to idle automatically by hardware based on the usage +and a configuration bit setting. Autoidle clock is never an individual +clock, it is always a derivative of some basic clock like a gate, divider, +or fixed-factor. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- reg : offset for the register controlling the autoidle +- ti,autoidle-shift : bit shift of the autoidle enable bit +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0 + +Examples: + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d38>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt new file mode 100644 index 000000000000..cb76b3f2b341 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt @@ -0,0 +1,24 @@ +Binding for Texas Instruments clockdomain. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1] in consumer role. +Every clock on TI SoC belongs to one clockdomain, but software +only needs this information for specific clocks which require +their parent clockdomain to be controlled when the clock is +enabled/disabled. This binding doesn't define a new clock +binding type, it is used to group existing clock nodes under +hardware hierarchy. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,clockdomain" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of clocks within this domain + +Examples: + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/composite.txt b/Documentation/devicetree/bindings/clock/ti/composite.txt new file mode 100644 index 000000000000..5f43c4706b09 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/composite.txt @@ -0,0 +1,54 @@ +Binding for TI composite clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped composite clock with multiple different sub-types; + +a multiplexer clock with multiple input clock signals or parents, one +of which can be selected as output, this behaves exactly as [2] + +an adjustable clock rate divider, this behaves exactly as [3] + +a gating function which can be used to enable and disable the output +clock, this behaves exactly as [4] + +The binding must provide a list of the component clocks that shall be +merged to this clock. The component clocks shall be of one of the +"ti,*composite*-clock" types. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/mux.txt +[3] Documentation/devicetree/bindings/clock/ti/divider.txt +[4] Documentation/devicetree/bindings/clock/ti/gate.txt + +Required properties: +- compatible : shall be: "ti,composite-clock" +- clocks : link phandles of component clocks +- #clock-cells : from common clock binding; shall be set to 0. + +Examples: + +usb_l4_gate_ick: usb_l4_gate_ick { + #clock-cells = <0>; + compatible = "ti,composite-interface-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <5>; + reg = <0x0a10>; +}; + +usb_l4_div_ick: usb_l4_div_ick { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <4>; + ti,max-div = <1>; + reg = <0x0a40>; + ti,index-starts-at-one; +}; + +usb_l4_ick: usb_l4_ick { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; +}; diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt new file mode 100644 index 000000000000..35a6f5c7e5c2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/divider.txt @@ -0,0 +1,114 @@ +Binding for TI divider clock + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped adjustable clock rate divider that does not gate and has +only one input clock or parent. By default the value programmed into +the register is one less than the actual divisor value. E.g: + +register value actual divisor value +0 1 +1 2 +2 3 + +This assumption may be modified by the following optional properties: + +ti,index-starts-at-one - valid divisor values start at 1, not the default +of 0. E.g: +register value actual divisor value +1 1 +2 2 +3 3 + +ti,index-power-of-two - valid divisor values are powers of two. E.g: +register value actual divisor value +0 1 +1 2 +2 4 + +Additionally an array of valid dividers may be supplied like so: + + ti,dividers = <4>, <8>, <0>, <16>; + +Which will map the resulting values to a divisor table by their index: +register value actual divisor value +0 4 +1 8 +2 <invalid divisor, skipped> +3 16 + +Any zero value in this array means the corresponding bit-value is invalid +and must not be used. + +The binding must also provide the register to control the divider and +unless the divider array is provided, min and max dividers. Optionally +the number of bits to shift that mask, if necessary. If the shift value +is missing it is the same as supplying a zero shift. + +This binding can also optionally provide support to the hardware autoidle +feature, see [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable divider + +Optional properties: +- clock-output-names : from common clock binding. +- ti,dividers : array of integers defining divisors +- ti,bit-shift : number of bits to shift the divider value, defaults to 0 +- ti,min-div : min divisor for dividing the input clock rate, only + needed if the first divisor is offset from the default value (1) +- ti,max-div : max divisor for dividing the input clock rate, only needed + if ti,dividers is not defined. +- ti,index-starts-at-one : valid divisor programming starts at 1, not zero, + only valid if ti,dividers is not defined. +- ti,index-power-of-two : valid divisor programming must be a power of two, + only valid if ti,dividers is not defined. +- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock, + see [2] +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, + see [2] +- ti,set-rate-parent : clk_set_rate is propagated to parent + +Examples: +dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + reg = <0x190>; + ti,index-starts-at-one; +}; + +aess_fclk: aess_fclk@4a004528 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + reg = <0x528>; + ti,max-div = <2>; +}; + +dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0134>; + ti,index-starts-at-one; +}; + +ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; +}; diff --git a/Documentation/devicetree/bindings/clock/ti/dpll.txt b/Documentation/devicetree/bindings/clock/ti/dpll.txt new file mode 100644 index 000000000000..30bfdb7c9f18 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/dpll.txt @@ -0,0 +1,75 @@ +Binding for Texas Instruments DPLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped DPLL with usually two selectable input clocks +(reference clock and bypass clock), with digital phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) This binding has several +sub-types, which effectively result in slightly different setup +for the actual DPLL clock. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-dpll-clock", + "ti,omap3-dpll-core-clock", + "ti,omap3-dpll-per-clock", + "ti,omap3-dpll-per-j-type-clock", + "ti,omap4-dpll-clock", + "ti,omap4-dpll-x2-clock", + "ti,omap4-dpll-core-clock", + "ti,omap4-dpll-m4xen-clock", + "ti,omap4-dpll-j-type-clock", + "ti,am3-dpll-no-gate-clock", + "ti,am3-dpll-j-type-clock", + "ti,am3-dpll-no-gate-j-type-clock", + "ti,am3-dpll-clock", + "ti,am3-dpll-core-clock", + "ti,am3-dpll-x2-clock", + +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks, first entry lists reference clock + and second entry bypass clock +- reg : offsets for the register set for controlling the DPLL. + Registers are listed in following order: + "control" - contains the control register base address + "idlest" - contains the idle status register base address + "mult-div1" - contains the multiplier / divider register base address + "autoidle" - contains the autoidle register base address (optional) + ti,am3-* dpll types do not have autoidle register + +Optional properties: +- DPLL mode setting - defining any one or more of the following overrides + default setting. + - ti,low-power-stop : DPLL supports low power stop mode, gating output + - ti,low-power-bypass : DPLL output matches rate of parent bypass clock + - ti,lock : DPLL locks in programmed rate + +Examples: + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x490>, <0x45c>, <0x488>, <0x468>; + }; + + dpll2_ck: dpll2_ck@48004004 { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll2_fck>; + ti,low-power-stop; + ti,low-power-bypass; + ti,lock; + reg = <0x4>, <0x24>, <0x34>, <0x40>; + }; + + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x90>, <0x5c>, <0x68>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt new file mode 100644 index 000000000000..662b36d53bf0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt @@ -0,0 +1,43 @@ +Binding for TI fixed factor rate clock sources. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1], and also uses the autoidle +support from TI autoidle clock [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,fixed-factor-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- ti,clock-div: fixed divider. +- ti,clock-mult: fixed multiplier. +- clocks: parent clock. + +Optional properties: +- ti,autoidle-shift: bit shift of the autoidle enable bit for the clock, + see [2] +- reg: offset for the autoidle register of this clock, see [2] +- ti,invert-autoidle-bit: autoidle is enabled by setting the bit to 0, see [2] +- ti,set-rate-parent: clk_set_rate is propagated to parent + +Example: + clock { + compatible = "ti,fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + ti,clock-div = <2>; + ti,clock-mult = <1>; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/gate.txt b/Documentation/devicetree/bindings/clock/ti/gate.txt new file mode 100644 index 000000000000..125281aaa4ca --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/gate.txt @@ -0,0 +1,85 @@ +Binding for Texas Instruments gate clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features. If no register +is provided for this clock, the code assumes that a clockdomain +will be controlled instead and the corresponding hw-ops for +that is used. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gate-clock.txt +[3] Documentation/devicetree/bindings/clock/ti/clockdomain.txt + +Required properties: +- compatible : shall be one of: + "ti,gate-clock" - basic gate clock + "ti,wait-gate-clock" - gate clock which waits until clock is active before + returning from clk_enable() + "ti,dss-gate-clock" - gate clock with DSS specific hardware handling + "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling + "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional + clock directly from a clockdomain, see [3] how + to map clockdomains properly + "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling, + required for a hardware errata +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable gate, not needed for + ti,clkdm-gate-clock type + +Optional properties: +- ti,bit-shift : bit shift for programming the clock gate, invalid for + ti,clkdm-gate-clock type +- ti,set-bit-to-disable : inverts default gate programming. Setting the bit + gates the clock and clearing the bit ungates the clock. + +Examples: + mmchs2_fck: mmchs2_fck@48004a00 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x48004a00 0x4>; + ti,bit-shift = <25>; + }; + + uart4_fck_am35xx: uart4_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; + + dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2@48004e00 { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&dpll4_m4x2_ck>; + reg = <0x48004e00 0x4>; + ti,bit-shift = <0>; + }; + + emac_ick: emac_ick@4800259c { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x4800259c 0x4>; + ti,bit-shift = <1>; + }; + + emu_src_ck: emu_src_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&emu_src_mux_ck>; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck@48004d00 { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x48004d00 0x4>; + ti,set-bit-to-disable; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/interface.txt b/Documentation/devicetree/bindings/clock/ti/interface.txt new file mode 100644 index 000000000000..064e8caccac3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/interface.txt @@ -0,0 +1,54 @@ +Binding for Texas Instruments interface clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features, including +companion clock finding (match corresponding functional gate +clock) and hardware autoidle enable / disable. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gate-clock.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-interface-clock" - basic OMAP3 interface clock + "ti,omap3-no-wait-interface-clock" - interface clock which has no hardware + capability for waiting clock to be ready + "ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW + handling + "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling + "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling + "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : base address for the control register + +Optional properties: +- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0) + +Examples: + aes1_ick: aes1_ick@48004a14 { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x48004a14 0x4>; + ti,bit-shift = <3>; + }; + + cam_ick: cam_ick@48004f10 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x48004f10 0x4>; + ti,bit-shift = <0>; + }; + + ssi_ick_3430es2: ssi_ick_3430es2@48004a10 { + #clock-cells = <0>; + compatible = "ti,omap3-ssi-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x48004a10 0x4>; + ti,bit-shift = <0>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt new file mode 100644 index 000000000000..2d0d170f8001 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/mux.txt @@ -0,0 +1,76 @@ +Binding for TI mux clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped multiplexer with multiple input clock signals or +parents, one of which can be selected as output. This clock does not +gate or adjust the parent rate via a divider or multiplier. + +By default the "clocks" property lists the parents in the same order +as they are programmed into the regster. E.g: + + clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>; + +results in programming the register as follows: + +register value selected parent clock +0 foo_clock +1 bar_clock +2 baz_clock + +Some clock controller IPs do not allow a value of zero to be programmed +into the register, instead indexing begins at 1. The optional property +"index-starts-at-one" modified the scheme as follows: + +register value selected clock parent +1 foo_clock +2 bar_clock +3 baz_clock + +The binding must provide the register to control the mux. Optionally +the number of bits to shift the control field in the register can be +supplied. If the shift value is missing it is the same as supplying +a zero shift. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks +- reg : register offset for register controlling adjustable mux + +Optional properties: +- ti,bit-shift : number of bits to shift the bit-mask, defaults to + 0 if not present +- ti,index-starts-at-one : valid input select programming starts at 1, not + zero +- ti,set-rate-parent : clk_set_rate is propagated to parent clock, + not supported by the composite-mux-clock subtype + +Examples: + +sys_clkin_ck: sys_clkin_ck@4a306110 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; +}; + +abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0108>; +}; + +mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; +}; diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt index 80ff3dfb1f32..d7221b84987c 100644 --- a/Documentation/devicetree/bindings/leds/tca6507.txt +++ b/Documentation/devicetree/bindings/leds/tca6507.txt @@ -2,6 +2,13 @@ LEDs connected to tca6507 Required properties: - compatible : should be : "ti,tca6507". +- #address-cells: must be 1 +- #size-cells: must be 0 +- reg: typically 0x45. + +Optional properties: +- gpio-controller: allows lines to be used as output-only GPIOs. +- #gpio-cells: if present, must be 0. Each led is represented as a sub-node of the ti,tca6507 device. @@ -10,6 +17,7 @@ LED sub-node properties: - reg : number of LED line (could be from 0 to 6) - linux,default-trigger : (optional) see Documentation/devicetree/bindings/leds/common.txt +- compatible: either "led" (the default) or "gpio". Examples: @@ -19,6 +27,9 @@ tca6507@45 { #size-cells = <0>; reg = <0x45>; + gpio-controller; + #gpio-cells = <2>; + led0: red-aux@0 { label = "red:aux"; reg = <0x0>; @@ -29,5 +40,10 @@ tca6507@45 { reg = <0x5>; linux,default-trigger = "default-on"; }; + + wifi-reset@6 { + reg = <0x6>; + compatible = "gpio"; + }; }; diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt new file mode 100644 index 000000000000..cfb18abe6001 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/davinci-nand.txt @@ -0,0 +1,94 @@ +Device tree bindings for Texas instruments Davinci/Keystone NAND controller + +This file provides information, what the device node for the davinci/keystone +NAND interface contains. + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf + +Required properties: + +- compatible: "ti,davinci-nand" + "ti,keystone-nand" + +- reg: Contains 2 offset/length values: + - offset and length for the access window. + - offset and length for accessing the AEMIF + control registers. + +- ti,davinci-chipselect: number of chipselect. Indicates on the + davinci_nand driver which chipselect is used + for accessing the nand. + Can be in the range [0-3]. + +Recommended properties : + +- ti,davinci-mask-ale: mask for ALE. Needed for executing address + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x08. + +- ti,davinci-mask-cle: mask for CLE. Needed for executing command + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x10. + +- ti,davinci-mask-chipsel: mask for chipselect address. Needed to mask + addresses for given chipselect. + +- nand-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. + +- nand-bus-width: buswidth 8 or 16. If not present 8. + +- nand-on-flash-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Deprecated properties: + +- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-nand-buswidth: buswidth 8 or 16. If not present 8. + +- ti,davinci-nand-use-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Nand device bindings may contain additional sub-nodes describing partitions of +the address space. See partition.txt for more detail. The NAND Flash timing +values must be programmed in the chip select’s node of AEMIF +memory-controller (see Documentation/devicetree/bindings/memory-controllers/ +davinci-aemif.txt). + +Example(da850 EVM ): + +nand_cs3@62000000 { + compatible = "ti,davinci-nand"; + reg = <0x62000000 0x807ff + 0x68000000 0x8000>; + ti,davinci-chipselect = <1>; + ti,davinci-mask-ale = <0>; + ti,davinci-mask-cle = <0>; + ti,davinci-mask-chipsel = <0>; + nand-ecc-mode = "hw"; + ti,davinci-ecc-bits = <4>; + nand-on-flash-bbt; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x7e80000>; + }; +}; diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt index 551b2a179d01..458d59634688 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt @@ -17,6 +17,14 @@ Required properties: Optional properties: - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC + strength required. The required ECC strength is + automatically discoverable for some flash + (e.g., according to the ONFI standard). + However, note that if this strength is not + discoverable or this property is not enabled, + the software may chooses an implementation-defined + ECC scheme. The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index f1421e2bbab7..86e0a5601ff5 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -2,7 +2,9 @@ PXA3xx NAND DT bindings Required properties: - - compatible: Should be "marvell,pxa3xx-nand" + - compatible: Should be set to one of the following: + marvell,pxa3xx-nand + marvell,armada370-nand - reg: The register base for the controller - interrupts: The interrupt to map - #address-cells: Set to <1> if the node includes partitions @@ -13,6 +15,8 @@ Optional properties: - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader - num-cs: Number of chipselect lines to usw + - nand-on-flash-bbt: boolean to enable on flash bbt option if + not present false Example: diff --git a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt new file mode 100644 index 000000000000..02331b904d4e --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt @@ -0,0 +1,33 @@ +Atmel PWM controller + +Required properties: + - compatible: should be one of: + - "atmel,at91sam9rl-pwm" + - "atmel,sama5d3-pwm" + - reg: physical base address and length of the controller's registers + - #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Example: + + pwm0: pwm@f8034000 { + compatible = "atmel,at91sam9rl-pwm"; + reg = <0xf8034000 0x400>; + #pwm-cells = <3>; + }; + + pwmleds { + compatible = "pwm-leds"; + + d1 { + label = "d1"; + pwms = <&pwm0 3 5000 0> + max-brightness = <255>; + }; + + d2 { + label = "d2"; + pwms = <&pwm0 1 5000 1> + max-brightness = <255>; + }; + }; diff --git a/Documentation/devicetree/bindings/pwm/pxa-pwm.txt b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt new file mode 100644 index 000000000000..5ae9f1e3c338 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt @@ -0,0 +1,30 @@ +Marvell PWM controller + +Required properties: +- compatible: should be one or more of: + - "marvell,pxa250-pwm" + - "marvell,pxa270-pwm" + - "marvell,pxa168-pwm" + - "marvell,pxa910-pwm" +- reg: Physical base address and length of the registers used by the PWM channel + Note that one device instance must be created for each PWM that is used, so the + length covers only the register window for one PWM output, not that of the + entire PWM controller. Currently length is 0x10 for all supported devices. +- #pwm-cells: Should be 1. This cell is used to specify the period in + nanoseconds. + +Example PWM device node: + +pwm0: pwm@40b00000 { + compatible = "marvell,pxa250-pwm"; + reg = <0x40b00000 0x10>; + #pwm-cells = <1>; +}; + +Example PWM client node: + +backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 5000000>; + ... +} diff --git a/Documentation/devicetree/bindings/video/ssd1289fb.txt b/Documentation/devicetree/bindings/video/ssd1289fb.txt new file mode 100644 index 000000000000..4fcd5e68cb6e --- /dev/null +++ b/Documentation/devicetree/bindings/video/ssd1289fb.txt @@ -0,0 +1,13 @@ +* Solomon SSD1289 Framebuffer Driver + +Required properties: + - compatible: Should be "solomon,ssd1289fb". The only supported bus for + now is lbc. + - reg: Should contain address of the controller on the LBC bus. The detail + was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt + +Examples: +display@2,0 { + compatible = "solomon,ssd1289fb"; + reg = <0x2 0x0000 0x0004>; +}; diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 7cbfa3c4fc3d..d7e43fa88575 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -73,6 +73,7 @@ Code Seq#(hex) Include File Comments 0x09 all linux/raid/md_u.h 0x10 00-0F drivers/char/s390/vmcp.h 0x10 10-1F arch/s390/include/uapi/sclp_ctl.h +0x10 20-2F arch/s390/include/uapi/asm/hypfs.h 0x12 all linux/fs.h linux/blkpg.h 0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index be6ba33d4ff1..8f441dab0396 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3124,7 +3124,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. controller if no parameter or 1 is given or disable it if 0 is given (See Documentation/cgroups/memory.txt) - swiotlb= [IA-64] Number of I/O TLB slabs + swiotlb= [ARM,IA-64,PPC,MIPS,X86] + Format: { <int> | force } + <int> -- Number of I/O TLB slabs + force -- force using of bounce buffers even if they + wouldn't be automatically used by the kernel switches= [HW,M68k] diff --git a/Documentation/kmsg/s390/zcrypt b/Documentation/kmsg/s390/zcrypt deleted file mode 100644 index 7fb2087409d6..000000000000 --- a/Documentation/kmsg/s390/zcrypt +++ /dev/null @@ -1,20 +0,0 @@ -/*? - * Text: "Cryptographic device %x failed and was set offline\n" - * Severity: Error - * Parameter: - * @1: device index - * Description: - * A cryptographic device failed to process a cryptographic request. - * The cryptographic device driver could not correct the error and - * set the device offline. The application that issued the - * request received an indication that the request has failed. - * User action: - * Use the lszcrypt command to confirm that the cryptographic - * hardware is still configured to your LPAR or z/VM guest virtual - * machine. If the device is available to your Linux instance the - * command output contains a line that begins with 'card<device index>', - * where <device index> is the two-digit decimal number in the message text. - * After ensuring that the device is available, use the chzcrypt command to - * set it online again. - * If the error persists, contact your support organization. - */ diff --git a/Documentation/leds/leds-lp55xx.txt b/Documentation/leds/leds-lp55xx.txt index 82713ff92eb3..bcea12a0c584 100644 --- a/Documentation/leds/leds-lp55xx.txt +++ b/Documentation/leds/leds-lp55xx.txt @@ -73,6 +73,10 @@ select_engine : Select which engine is used for running program run_engine : Start program which is loaded via the firmware interface firmware : Load program data +In case of LP5523, one more command is required, 'enginex_leds'. +It is used for selecting LED output(s) at each engine number. +In more details, please refer to 'leds-lp5523.txt'. + For example, run blinking pattern in engine #1 of LP5521 echo 1 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp5521/loading @@ -81,10 +85,12 @@ echo 0 > /sys/class/firmware/lp5521/loading echo 1 > /sys/bus/i2c/devices/xxxx/run_engine For example, run blinking pattern in engine #3 of LP55231 +Two LEDs are configured as pattern output channels. echo 3 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp55231/loading echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data echo 0 > /sys/class/firmware/lp55231/loading +echo "000001100" > /sys/bus/i2c/devices/xxxx/engine3_leds echo 1 > /sys/bus/i2c/devices/xxxx/run_engine To start blinking patterns in engine #2 and #3 simultaneously, @@ -99,17 +105,19 @@ done echo 1 > /sys/class/leds/red/device/run_engine Here is another example for LP5523. +Full LED strings are selected by 'engine2_leds'. echo 2 > /sys/bus/i2c/devices/xxxx/select_engine echo 1 > /sys/class/firmware/lp5523/loading echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data echo 0 > /sys/class/firmware/lp5523/loading +echo "111111111" > /sys/bus/i2c/devices/xxxx/engine2_leds echo 1 > /sys/bus/i2c/devices/xxxx/run_engine As soon as 'loading' is set to 0, registered callback is called. Inside the callback, the selected engine is loaded and memory is updated. To run programmed pattern, 'run_engine' attribute should be enabled. -The pattern sqeuence of LP8501 is same as LP5523. +The pattern sqeuence of LP8501 is similar to LP5523. However pattern data is specific. Ex 1) Engine 1 is used echo 1 > /sys/bus/i2c/devices/xxxx/select_engine diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt new file mode 100644 index 000000000000..840fd41c181b --- /dev/null +++ b/Documentation/mtd/nand/pxa3xx-nand.txt @@ -0,0 +1,113 @@ + +About this document +=================== + +Some notes about Marvell's NAND controller available in PXA and Armada 370/XP +SoC (aka NFCv1 and NFCv2), with an emphasis on the latter. + +NFCv2 controller background +=========================== + +The controller has a 2176 bytes FIFO buffer. Therefore, in order to support +larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of +chunked transfers. + +For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below) +we'll have this layout in the pages: + + ------------------------------------------------------------------------------ + | 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... | + ------------------------------------------------------------------------------ + +The driver reads the data and spare portions independently and builds an internal +buffer with this layout (in the 4 KiB page case): + + ------------------------------------------ + | 4096B data | 64B spare | + ------------------------------------------ + +Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC' +OOB, one per chunk read. + + ------------------------------------------------------------------- + | 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC | + ------------------------------------------------------------------- + +So, in order to achieve reading (for instance), we issue several READ0 commands +(with some additional controller-specific magic) and read two chunks of 2080B +(2048 data + 32 spare) each. +The driver accommodates this data to expose the NAND core a contiguous buffer +(4096 data + spare) or (4096 + spare + ECC + spare + ECC). + +ECC +=== + +The controller has built-in hardware ECC capabilities. In addition it is +configurable between two modes: 1) Hamming, 2) BCH. + +Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way +the controller is configured to transfer the data. + +In the BCH mode the ECC code will be calculated for each transfered chunk +and expected to be located (when reading/programming) right after the spare +bytes as the figure above shows. + +So, repeating the above scheme, a 2048B data chunk will be followed by 32B +spare, and then the ECC controller will read/write the ECC code (30B in +this case): + + ------------------------------------ + | 2048B data | 32B spare | 30B ECC | + ------------------------------------ + +If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long. +If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block. +So in Hamming mode, a 2048B page will have a 24B ECC. + +Despite all of the above, the controller requires the driver to only read or +write in multiples of 8-bytes, because the data buffer is 64-bits. + +OOB +=== + +Because of the above scheme, and because the "spare" OOB is really located in +the middle of a page, spare OOB cannot be read or write independently of the +data area. In other words, in order to read the OOB (aka READOOB), the entire +page (aka READ0) has to be read. + +In the same sense, in order to write to the spare OOB the driver has to write +an *entire* page. + +Factory bad blocks handling +=========================== + +Given the ECC BCH requires to layout the device's pages in a split +data/OOB/data/OOB way, the controller has a view of the flash page that's +different from the specified (aka the manufacturer's) view. In other words, + +Factory view: + + ----------------------------------------------- + | Data |x OOB | + ----------------------------------------------- + +Driver's view: + + ----------------------------------------------- + | Data | OOB | Data x | OOB | + ----------------------------------------------- + +It can be seen from the above, that the factory bad block marker must be +searched within the 'data' region, and not in the usual OOB region. + +In addition, this means under regular usage the driver will write such +position (since it belongs to the data region) and every used block is +likely to be marked as bad. + +For this reason, marking the block as bad in the OOB is explicitly +disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale +for this is that there's no point in marking a block as bad, because good +blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage. + +Instead, the driver relies on the bad block table alone, and should only perform +the bad block scan on the very first time (when the device hasn't been used). diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt index e9b54de8fdf7..edeecd447d23 100644 --- a/Documentation/power/basic-pm-debugging.txt +++ b/Documentation/power/basic-pm-debugging.txt @@ -172,7 +172,7 @@ you can boot the kernel with the 'no_console_suspend' parameter and try to log kernel messages using the serial console. This may provide you with some information about the reasons of the suspend (resume) failure. Alternatively, it may be possible to use a FireWire port for debugging with firescope -(ftp://ftp.firstfloor.org/pub/ak/firescope/). On x86 it is also possible to +(http://v3.sk/~lkundrak/firescope/). On x86 it is also possible to use the PM_TRACE mechanism documented in Documentation/power/s2ram.txt . 2. Testing suspend to RAM (STR) diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 9f5481bdc5a4..d614a9b6a280 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -696,7 +696,9 @@ swappiness This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values -decrease the amount of swap. +decrease the amount of swap. A value of 0 instructs the kernel not to +initiate swap until the amount of free and file-backed pages is less +than the high water mark in a zone. The default value is 60. diff --git a/MAINTAINERS b/MAINTAINERS index 2507f38b208f..38b81df6701c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -309,36 +309,36 @@ F: sound/pci/ad1889.* AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD5254 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/misc/ad525x_dpot.c AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD5398 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/regulator/ad5398.c AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7142 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/misc/ad714x.c AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7877 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/touchscreen/ad7877.c AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/AD7879 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/touchscreen/ad7879.c @@ -374,8 +374,8 @@ F: include/media/adp1653.h ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP5520 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/mfd/adp5520.c F: drivers/video/backlight/adp5520_bl.c @@ -385,16 +385,16 @@ F: drivers/input/keyboard/adp5520-keys.c ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP5588 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/keyboard/adp5588-keys.c F: drivers/gpio/gpio-adp5588.c ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADP8860 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/video/backlight/adp8860_bl.c @@ -420,8 +420,8 @@ F: drivers/hwmon/adt7475.c ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346) M: Michael Hennerich <michael.hennerich@analog.com> -L: device-drivers-devel@blackfin.uclinux.org W: http://wiki.analog.com/ADXL345 +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/misc/adxl34x.c @@ -627,9 +627,9 @@ F: drivers/media/i2c/adv7842* ANALOG DEVICES INC ASOC CODEC DRIVERS M: Lars-Peter Clausen <lars@metafoo.de> -L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ +W: http://ez.analog.com/community/linux-device-drivers S: Supported F: sound/soc/codecs/adau* F: sound/soc/codecs/adav* @@ -639,7 +639,7 @@ F: sound/soc/codecs/ssm* F: sound/soc/codecs/sigmadsp.* ANALOG DEVICES INC ASOC DRIVERS -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://blackfin.uclinux.org/ S: Supported @@ -1742,56 +1742,54 @@ F: fs/bfs/ F: include/uapi/linux/bfs_fs.h BLACKFIN ARCHITECTURE -M: Mike Frysinger <vapier@gentoo.org> -L: uclinux-dist-devel@blackfin.uclinux.org +M: Steven Miao <realmz6@gmail.com> +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: arch/blackfin/ BLACKFIN EMAC DRIVER -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/net/ethernet/adi/ BLACKFIN RTC DRIVER -M: Mike Frysinger <vapier.adi@gmail.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/rtc/rtc-bfin.c BLACKFIN SDH DRIVER M: Sonic Zhang <sonic.zhang@analog.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/mmc/host/bfin_sdh.c BLACKFIN SERIAL DRIVER M: Sonic Zhang <sonic.zhang@analog.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/tty/serial/bfin_uart.c BLACKFIN WATCHDOG DRIVER -M: Mike Frysinger <vapier.adi@gmail.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org S: Supported F: drivers/watchdog/bfin_wdt.c BLACKFIN I2C TWI DRIVER M: Sonic Zhang <sonic.zhang@analog.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org/ S: Supported F: drivers/i2c/busses/i2c-bfin-twi.c BLACKFIN MEDIA DRIVER M: Scott Jiang <scott.jiang.linux@gmail.com> -L: uclinux-dist-devel@blackfin.uclinux.org +L: adi-buildroot-devel@lists.sourceforge.net W: http://blackfin.uclinux.org/ S: Supported F: drivers/media/platform/blackfin/ @@ -5622,10 +5620,11 @@ F: mm/page_cgroup.c MEMORY TECHNOLOGY DEVICES (MTD) M: David Woodhouse <dwmw2@infradead.org> +M: Brian Norris <computersforpeace@gmail.com> L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -T: git git://git.infradead.org/mtd-2.6.git +T: git git://git.infradead.org/linux-mtd.git S: Maintained F: drivers/mtd/ F: include/linux/mtd/ @@ -6942,6 +6941,12 @@ F: include/sound/pxa2xx-lib.h F: sound/arm/pxa* F: sound/soc/pxa/ +PXA3xx NAND FLASH DRIVER +M: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +L: linux-mtd@lists.infradead.org +S: Maintained +F: drivers/mtd/nand/pxa3xx-nand.c + MMP SUPPORT M: Eric Miao <eric.y.miao@gmail.com> M: Haojian Zhuang <haojian.zhuang@gmail.com> @@ -7075,7 +7080,7 @@ F: drivers/media/parport/*-qcam* RADOS BLOCK DEVICE (RBD) M: Yehuda Sadeh <yehuda@inktank.com> M: Sage Weil <sage@inktank.com> -M: Alex Elder <elder@inktank.com> +M: Alex Elder <elder@kernel.org> M: ceph-devel@vger.kernel.org W: http://ceph.com/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git diff --git a/arch/arm/boot/dts/am33xx-clocks.dtsi b/arch/arm/boot/dts/am33xx-clocks.dtsi new file mode 100644 index 000000000000..9ccfe508dea2 --- /dev/null +++ b/arch/arm/boot/dts/am33xx-clocks.dtsi @@ -0,0 +1,664 @@ +/* + * Device Tree Source for AM33xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&scrm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>; + ti,bit-shift = <22>; + reg = <0x0040>; + }; + + adc_tsc_fck: adc_tsc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan0_fck: dcan0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan1_fck: dcan1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp0_fck: mcasp0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp1_fck: mcasp1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex0_fck: smartreflex0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex1_fck: smartreflex1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sha0_fck: sha0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes0_fck: aes0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + rng_fck: rng_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + ehrpwm0_gate_tbclk: ehrpwm0_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <0>; + reg = <0x0664>; + }; + + ehrpwm0_tbclk: ehrpwm0_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm0_gate_tbclk>; + }; + + ehrpwm1_gate_tbclk: ehrpwm1_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x0664>; + }; + + ehrpwm1_tbclk: ehrpwm1_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm1_gate_tbclk>; + }; + + ehrpwm2_gate_tbclk: ehrpwm2_gate_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_m2_ck>; + ti,bit-shift = <2>; + reg = <0x0664>; + }; + + ehrpwm2_tbclk: ehrpwm2_tbclk { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ehrpwm2_gate_tbclk>; + }; +}; +&prcm_clocks { + clk_32768_ck: clk_32768_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk_rc32k_ck: clk_rc32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_24000000_ck: virt_24000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + virt_25000000_ck: virt_25000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + tclkin_ck: tclkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0490>, <0x045c>, <0x0468>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0480>; + ti,index-starts-at-one; + }; + + dpll_core_m5_ck: dpll_core_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0484>; + ti,index-starts-at-one; + }; + + dpll_core_m6_ck: dpll_core_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x04d8>; + ti,index-starts-at-one; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0488>, <0x0420>, <0x042c>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + reg = <0x04a8>; + ti,index-starts-at-one; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0494>, <0x0434>, <0x0440>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + reg = <0x04a0>; + ti,index-starts-at-one; + }; + + dpll_ddr_m2_div2_ck: dpll_ddr_m2_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_ddr_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_disp_ck: dpll_disp_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x0498>, <0x0448>, <0x0454>; + }; + + dpll_disp_m2_ck: dpll_disp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_disp_ck>; + ti,max-div = <31>; + reg = <0x04a4>; + ti,index-starts-at-one; + ti,set-rate-parent; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-no-gate-j-type-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x048c>, <0x0470>, <0x049c>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + reg = <0x04ac>; + ti,index-starts-at-one; + }; + + dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll_per_m2_div4_ck: dpll_per_m2_div4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + cefuse_fck: cefuse_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin_ck>; + ti,bit-shift = <1>; + reg = <0x0a20>; + }; + + clk_24mhz: clk_24mhz { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + clkdiv32k_ck: clkdiv32k_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&clk_24mhz>; + clock-mult = <1>; + clock-div = <732>; + }; + + clkdiv32k_ick: clkdiv32k_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ck>; + ti,bit-shift = <1>; + reg = <0x014c>; + }; + + l3_gclk: l3_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + pruss_ocp_gclk: pruss_ocp_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_gclk>, <&dpll_disp_m2_ck>; + reg = <0x0530>; + }; + + mmu_fck: mmu_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_ck>; + ti,bit-shift = <1>; + reg = <0x0914>; + }; + + timer1_fck: timer1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>; + reg = <0x0528>; + }; + + timer2_fck: timer2_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0508>; + }; + + timer3_fck: timer3_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x050c>; + }; + + timer4_fck: timer4_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0510>; + }; + + timer5_fck: timer5_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0518>; + }; + + timer6_fck: timer6_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x051c>; + }; + + timer7_fck: timer7_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x0504>; + }; + + usbotg_fck: usbotg_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_ck>; + ti,bit-shift = <8>; + reg = <0x047c>; + }; + + dpll_core_m4_div2_ck: dpll_core_m4_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + ieee5000_fck: ieee5000_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_div2_ck>; + ti,bit-shift = <1>; + reg = <0x00e4>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>; + reg = <0x0538>; + }; + + l4_rtc_gclk: l4_rtc_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l4hs_gclk: l4hs_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3s_gclk: l3s_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4fw_gclk: l4fw_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4ls_gclk: l4ls_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sysclk_div_ck: sysclk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_125mhz_gclk: cpsw_125mhz_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + cpsw_cpts_rft_clk: cpsw_cpts_rft_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m5_ck>, <&dpll_core_m4_ck>; + reg = <0x0520>; + }; + + gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>; + reg = <0x053c>; + }; + + gpio0_dbclk: gpio0_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&gpio0_dbclk_mux_ck>; + ti,bit-shift = <18>; + reg = <0x0408>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00ac>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00b0>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <18>; + reg = <0x00b4>; + }; + + lcd_gclk: lcd_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>; + reg = <0x0534>; + ti,set-rate-parent; + }; + + mmc_clk: mmc_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + gfx_fclk_clksel_ck: gfx_fclk_clksel_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m4_ck>, <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x052c>; + }; + + gfx_fck_div_ck: gfx_fck_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&gfx_fclk_clksel_ck>; + reg = <0x052c>; + ti,max-div = <2>; + }; + + sysclkout_pre_ck: sysclkout_pre_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&l3_gclk>, <&dpll_ddr_m2_ck>, <&dpll_per_m2_ck>, <&lcd_gclk>; + reg = <0x0700>; + }; + + clkout2_div_ck: clkout2_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sysclkout_pre_ck>; + ti,bit-shift = <3>; + ti,max-div = <8>; + reg = <0x0700>; + }; + + dbg_sysclk_ck: dbg_sysclk_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin_ck>; + ti,bit-shift = <19>; + reg = <0x0414>; + }; + + dbg_clka_ck: dbg_clka_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_core_m4_ck>; + ti,bit-shift = <30>; + reg = <0x0414>; + }; + + stm_pmd_clock_mux_ck: stm_pmd_clock_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; + ti,bit-shift = <22>; + reg = <0x0414>; + }; + + trace_pmd_clk_mux_ck: trace_pmd_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; + ti,bit-shift = <20>; + reg = <0x0414>; + }; + + stm_clk_div_ck: stm_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&stm_pmd_clock_mux_ck>; + ti,bit-shift = <27>; + ti,max-div = <64>; + reg = <0x0414>; + ti,index-power-of-two; + }; + + trace_clk_div_ck: trace_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&trace_pmd_clk_mux_ck>; + ti,bit-shift = <24>; + ti,max-div = <64>; + reg = <0x0414>; + ti,index-power-of-two; + }; + + clkout2_ck: clkout2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkout2_div_ck>; + ti,bit-shift = <7>; + reg = <0x0700>; + }; +}; + +&prcm_clockdomains { + clk_24mhz_clkdm: clk_24mhz_clkdm { + compatible = "ti,clockdomain"; + clocks = <&clkdiv32k_ick>; + }; +}; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index f6d8ffe98d0b..6d95d3df33c7 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -102,6 +102,32 @@ ranges; ti,hwmods = "l3_main"; + prcm: prcm@44e00000 { + compatible = "ti,am3-prcm"; + reg = <0x44e00000 0x4000>; + + prcm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prcm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@44e10000 { + compatible = "ti,am3-scrm"; + reg = <0x44e10000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + intc: interrupt-controller@48200000 { compatible = "ti,omap2-intc"; interrupt-controller; @@ -794,3 +820,5 @@ }; }; }; + +/include/ "am33xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 2fbe02faa8b1..788391f91684 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -61,3 +61,6 @@ }; }; }; + +/include/ "am35xx-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/am35xx-clocks.dtsi b/arch/arm/boot/dts/am35xx-clocks.dtsi new file mode 100644 index 000000000000..df489d310b50 --- /dev/null +++ b/arch/arm/boot/dts/am35xx-clocks.dtsi @@ -0,0 +1,128 @@ +/* + * Device Tree Source for OMAP3 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&scrm_clocks { + emac_ick: emac_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <1>; + }; + + emac_fck: emac_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&rmii_ck>; + reg = <0x059c>; + ti,bit-shift = <9>; + }; + + vpfe_ick: vpfe_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <2>; + }; + + vpfe_fck: vpfe_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pclk_ck>; + reg = <0x059c>; + ti,bit-shift = <10>; + }; + + hsotgusb_ick_am35xx: hsotgusb_ick_am35xx { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <0>; + }; + + hsotgusb_fck_am35xx: hsotgusb_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x059c>; + ti,bit-shift = <8>; + }; + + hecc_ck: hecc_ck { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&sys_ck>; + reg = <0x059c>; + ti,bit-shift = <3>; + }; +}; +&cm_clocks { + ipss_ick: ipss_ick { + #clock-cells = <0>; + compatible = "ti,am35xx-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + rmii_ck: rmii_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; + }; + + pclk_ck: pclk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + uart4_ick_am35xx: uart4_ick_am35xx { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <23>; + }; + + uart4_fck_am35xx: uart4_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&ipss_ick>, <&emac_ick>, <&vpfe_ick>, + <&hsotgusb_ick_am35xx>, <&hsotgusb_fck_am35xx>, + <&hecc_ck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>, + <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&uart4_ick_am35xx>, <&uart4_fck_am35xx>; + }; +}; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 974d103ab3b1..c6bd4d986c29 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -67,6 +67,32 @@ ranges; ti,hwmods = "l3_main"; + prcm: prcm@44df0000 { + compatible = "ti,am4-prcm"; + reg = <0x44df0000 0x11000>; + + prcm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prcm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@44e10000 { + compatible = "ti,am4-scrm"; + reg = <0x44e10000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + edma: edma@49000000 { compatible = "ti,edma3"; ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; @@ -665,3 +691,5 @@ }; }; }; + +/include/ "am43xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi new file mode 100644 index 000000000000..142009cc9332 --- /dev/null +++ b/arch/arm/boot/dts/am43xx-clocks.dtsi @@ -0,0 +1,656 @@ +/* + * Device Tree Source for AM43xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&scrm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>; + ti,bit-shift = <22>; + reg = <0x0040>; + }; + + adc_tsc_fck: adc_tsc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan0_fck: dcan0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dcan1_fck: dcan1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp0_fck: mcasp0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcasp1_fck: mcasp1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex0_fck: smartreflex0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + smartreflex1_fck: smartreflex1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sha0_fck: sha0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes0_fck: aes0_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; +&prcm_clocks { + clk_32768_ck: clk_32768_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk_rc32k_ck: clk_rc32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_24000000_ck: virt_24000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + virt_25000000_ck: virt_25000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + tclkin_ck: tclkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2d20>, <0x2d24>, <0x2d2c>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d38>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m5_ck: dpll_core_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d3c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m6_ck: dpll_core_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d40>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2d60>, <0x2d64>, <0x2d6c>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d70>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2da0>, <0x2da4>, <0x2dac>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2db0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_disp_ck: dpll_disp_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2e20>, <0x2e24>, <0x2e2c>; + }; + + dpll_disp_m2_ck: dpll_disp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_disp_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2e30>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-j-type-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2de0>, <0x2de4>, <0x2dec>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x2df0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll_per_m2_div4_ck: dpll_per_m2_div4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + clk_24mhz: clk_24mhz { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + clkdiv32k_ck: clkdiv32k_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&clk_24mhz>; + clock-mult = <1>; + clock-div = <732>; + }; + + clkdiv32k_ick: clkdiv32k_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ck>; + ti,bit-shift = <8>; + reg = <0x2a38>; + }; + + sysclk_div: sysclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + pruss_ocp_gclk: pruss_ocp_gclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_disp_m2_ck>; + reg = <0x4248>; + }; + + clk_32k_tpm_ck: clk_32k_tpm_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + timer1_fck: timer1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>, <&clk_32k_tpm_ck>; + reg = <0x4200>; + }; + + timer2_fck: timer2_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4204>; + }; + + timer3_fck: timer3_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4208>; + }; + + timer4_fck: timer4_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x420c>; + }; + + timer5_fck: timer5_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4210>; + }; + + timer6_fck: timer6_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4214>; + }; + + timer7_fck: timer7_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + reg = <0x4218>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>; + reg = <0x422c>; + }; + + l3_gclk: l3_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_core_m4_div2_ck: dpll_core_m4_div2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sysclk_div>; + clock-mult = <1>; + clock-div = <2>; + }; + + l4hs_gclk: l4hs_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3s_gclk: l3s_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4ls_gclk: l4ls_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4_div2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_125mhz_gclk: cpsw_125mhz_gclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + cpsw_cpts_rft_clk: cpsw_cpts_rft_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_core_m5_ck>, <&dpll_disp_m2_ck>; + reg = <0x4238>; + }; + + clk_32k_mosc_ck: clk_32k_mosc_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>, <&clk_32k_mosc_ck>, <&clk_32k_tpm_ck>; + reg = <0x4240>; + }; + + gpio0_dbclk: gpio0_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&gpio0_dbclk_mux_ck>; + ti,bit-shift = <8>; + reg = <0x2b68>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c78>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c80>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c88>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c90>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&clkdiv32k_ick>; + ti,bit-shift = <8>; + reg = <0x8c98>; + }; + + mmc_clk: mmc_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + gfx_fclk_clksel_ck: gfx_fclk_clksel_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sysclk_div>, <&dpll_per_m2_ck>; + ti,bit-shift = <1>; + reg = <0x423c>; + }; + + gfx_fck_div_ck: gfx_fck_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&gfx_fclk_clksel_ck>; + reg = <0x423c>; + ti,max-div = <2>; + }; + + disp_clk: disp_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>; + reg = <0x4244>; + }; + + dpll_extdev_ck: dpll_extdev_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x2e60>, <0x2e64>, <0x2e6c>; + }; + + dpll_extdev_m2_ck: dpll_extdev_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_extdev_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x2e70>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mux_synctimer32k_ck: mux_synctimer32k_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>, <&clkdiv32k_ick>; + reg = <0x4230>; + }; + + synctimer_32kclk: synctimer_32kclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&mux_synctimer32k_ck>; + ti,bit-shift = <8>; + reg = <0x2a30>; + }; + + timer8_fck: timer8_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x421c>; + }; + + timer9_fck: timer9_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4220>; + }; + + timer10_fck: timer10_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4224>; + }; + + timer11_fck: timer11_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>; + reg = <0x4228>; + }; + + cpsw_50m_clkdiv: cpsw_50m_clkdiv { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m5_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + cpsw_5m_clkdiv: cpsw_5m_clkdiv { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&cpsw_50m_clkdiv>; + clock-mult = <1>; + clock-div = <10>; + }; + + dpll_ddr_x2_ck: dpll_ddr_x2_ck { + #clock-cells = <0>; + compatible = "ti,am3-dpll-x2-clock"; + clocks = <&dpll_ddr_ck>; + }; + + dpll_ddr_m4_ck: dpll_ddr_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2db8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_clkdcoldo: dpll_per_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dll_aging_clk_div: dll_aging_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin_ck>; + reg = <0x4250>; + ti,dividers = <8>, <16>, <32>; + }; + + div_core_25m_ck: div_core_25m_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sysclk_div>; + clock-mult = <1>; + clock-div = <8>; + }; + + func_12m_clk: func_12m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + vtp_clk_div: vtp_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usbphy_32khz_clkmux: usbphy_32khz_clkmux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>; + reg = <0x4260>; + }; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index d0df4c4e8b0a..1fd75aa4639d 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -104,6 +104,45 @@ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + prm: prm@4ae06000 { + compatible = "ti,dra7-prm"; + reg = <0x4ae06000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm_core_aon: cm_core_aon@4a005000 { + compatible = "ti,dra7-cm-core-aon"; + reg = <0x4a005000 0x2000>; + + cm_core_aon_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_aon_clockdomains: clockdomains { + }; + }; + + cm_core: cm_core@4a008000 { + compatible = "ti,dra7-cm-core"; + reg = <0x4a008000 0x3000>; + + cm_core_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_clockdomains: clockdomains { + }; + }; + counter32k: counter@4ae04000 { compatible = "ti,omap-counter32k"; reg = <0x4ae04000 0x40>; @@ -584,3 +623,5 @@ }; }; }; + +/include/ "dra7xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi new file mode 100644 index 000000000000..e96da9a898ad --- /dev/null +++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi @@ -0,0 +1,2015 @@ +/* + * Device Tree Source for DRA7xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_core_aon_clocks { + atl_clkin0_ck: atl_clkin0_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atl_clkin1_ck: atl_clkin1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atl_clkin2_ck: atl_clkin2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + atlclkin3_ck: atlclkin3_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + hdmi_clkin_ck: hdmi_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + mlb_clkin_ck: mlb_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + mlbp_clkin_ck: mlbp_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + pciesref_acs_clk_ck: pciesref_acs_clk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <100000000>; + }; + + ref_clkin0_ck: ref_clkin0_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin1_ck: ref_clkin1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin2_ck: ref_clkin2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + ref_clkin3_ck: ref_clkin3_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + rmii_clk_ck: rmii_clk_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + sdvenc_clkin_ck: sdvenc_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_20000000_ck: virt_20000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <20000000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + sys_clkin2: sys_clkin2 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <22579200>; + }; + + usb_otg_clkin_ck: usb_otg_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video1_clkin_ck: video1_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video1_m2_clkin_ck: video1_m2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video2_clkin_ck: video2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + video2_m2_clkin_ck: video2_m2_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + dpll_abe_m2_ck: dpll_abe_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_h12x2_ck: dpll_core_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&mpu_dpll_hs_clk_div>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dclk_div: mpu_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_mpu_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dsp_dpll_hs_clk_div: dsp_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_dsp_ck: dpll_dsp_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>; + reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>; + }; + + dpll_dsp_m2_ck: dpll_dsp_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0244>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dpll_hs_clk_div: iva_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_m2_ck: dpll_iva_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01b0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dclk: iva_dclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_iva_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_gpu_ck: dpll_gpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>; + }; + + dpll_gpu_m2_ck: dpll_gpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02e8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + core_dpll_out_dclk_div: core_dpll_out_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_ddr_ck: dpll_ddr_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>; + }; + + dpll_ddr_m2_ck: dpll_ddr_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0220>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_ck: dpll_gmac_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>; + reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>; + }; + + dpll_gmac_m2_ck: dpll_gmac_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + video2_dclk_div: video2_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_m2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_dclk_div: video1_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_m2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdmi_dclk_div: hdmi_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + per_dpll_hs_clk_div: per_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_dpll_hs_clk_div: usb_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + eve_dpll_hs_clk_div: eve_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_eve_ck: dpll_eve_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>; + reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>; + }; + + dpll_eve_m2_ck: dpll_eve_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_eve_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0294>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + eve_dclk_div: eve_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_eve_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_core_h13x2_ck: dpll_core_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h14x2_ck: dpll_core_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h22x2_ck: dpll_core_h22x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h23x2_ck: dpll_core_h23x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h24x2_ck: dpll_core_h24x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_ddr_x2_ck: dpll_ddr_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_ddr_ck>; + }; + + dpll_ddr_h11x2_ck: dpll_ddr_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0228>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_dsp_x2_ck: dpll_dsp_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_dsp_ck>; + }; + + dpll_dsp_m3x2_ck: dpll_dsp_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0248>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_x2_ck: dpll_gmac_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_gmac_ck>; + }; + + dpll_gmac_h11x2_ck: dpll_gmac_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_h12x2_ck: dpll_gmac_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_h13x2_ck: dpll_gmac_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x02c8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_gmac_m3x2_ck: dpll_gmac_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x02bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + gmii_m_clk_div: gmii_m_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_gmac_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + hdmi_clk2_div: hdmi_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdmi_div_clk: hdmi_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&hdmi_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3_iclk_div: l3_iclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_root_clk_div: l4_root_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_clk2_div: video1_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video1_div_clk: video1_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video1_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video2_clk2_div: video2_clk2_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + video2_div_clk: video2_div_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&video2_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + ipu1_gfclk_mux: ipu1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_abe_m2x2_ck>, <&dpll_core_h22x2_ck>; + ti,bit-shift = <24>; + reg = <0x0520>; + }; + + mcasp1_ahclkr_mux: mcasp1_ahclkr_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x0550>; + }; + + mcasp1_ahclkx_mux: mcasp1_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcasp1_aux_gfclk_mux: mcasp1_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x0550>; + }; + + timer5_gfclk_mux: timer5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + timer6_gfclk_mux: timer6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0560>; + }; + + timer7_gfclk_mux: timer7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer8_gfclk_mux: timer8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + uart6_gfclk_mux: uart6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin1: sys_clkin1 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_20000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_sys_clk_mux: abe_dpll_sys_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x0118>; + }; + + abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>; + reg = <0x0114>; + }; + + abe_dpll_clk_mux: abe_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + reg = <0x011c>; + ti,dividers = <8>, <16>; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + reg = <0x0178>; + ti,max-div = <2>; + }; + + abe_giclk_div: abe_giclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&aess_fclk>; + reg = <0x0174>; + ti,max-div = <2>; + }; + + abe_lp_clk_div: abe_lp_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + reg = <0x01d8>; + ti,dividers = <16>, <32>; + }; + + abe_sys_clk_div: abe_sys_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + reg = <0x0120>; + ti,max-div = <2>; + }; + + adc_gfclk_mux: adc_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>, <&sys_32k_ck>; + reg = <0x01dc>; + }; + + sys_clk1_dclk_div: sys_clk1_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x01c8>; + ti,index-power-of-two; + }; + + sys_clk2_dclk_div: sys_clk2_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin2>; + ti,max-div = <64>; + reg = <0x01cc>; + ti,index-power-of-two; + }; + + per_abe_x1_dclk_div: per_abe_x1_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + ti,max-div = <64>; + reg = <0x01bc>; + ti,index-power-of-two; + }; + + dsp_gclk_div: dsp_gclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_dsp_m2_ck>; + ti,max-div = <64>; + reg = <0x018c>; + ti,index-power-of-two; + }; + + gpu_dclk: gpu_dclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gpu_m2_ck>; + ti,max-div = <64>; + reg = <0x01a0>; + ti,index-power-of-two; + }; + + emif_phy_dclk_div: emif_phy_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_ddr_m2_ck>; + ti,max-div = <64>; + reg = <0x0190>; + ti,index-power-of-two; + }; + + gmac_250m_dclk_div: gmac_250m_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_m2_ck>; + ti,max-div = <64>; + reg = <0x019c>; + ti,index-power-of-two; + }; + + l3init_480m_dclk_div: l3init_480m_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,max-div = <64>; + reg = <0x01ac>; + ti,index-power-of-two; + }; + + usb_otg_dclk_div: usb_otg_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&usb_otg_clkin_ck>; + ti,max-div = <64>; + reg = <0x0184>; + ti,index-power-of-two; + }; + + sata_dclk_div: sata_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x01c0>; + ti,index-power-of-two; + }; + + pcie2_dclk_div: pcie2_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_m2_ck>; + ti,max-div = <64>; + reg = <0x01b8>; + ti,index-power-of-two; + }; + + pcie_dclk_div: pcie_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&apll_pcie_m2_ck>; + ti,max-div = <64>; + reg = <0x01b4>; + ti,index-power-of-two; + }; + + emu_dclk_div: emu_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + ti,max-div = <64>; + reg = <0x0194>; + ti,index-power-of-two; + }; + + secure_32k_dclk_div: secure_32k_dclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&secure_32k_clk_src_ck>; + ti,max-div = <64>; + reg = <0x01c4>; + ti,index-power-of-two; + }; + + clkoutmux0_clk_mux: clkoutmux0_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x0158>; + }; + + clkoutmux1_clk_mux: clkoutmux1_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x015c>; + }; + + clkoutmux2_clk_mux: clkoutmux2_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>; + reg = <0x0160>; + }; + + custefuse_sys_gfclk_div: custefuse_sys_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin1>; + clock-mult = <1>; + clock-div = <2>; + }; + + eve_clk: eve_clk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_eve_m2_ck>, <&dpll_dsp_m3x2_ck>; + reg = <0x0180>; + }; + + hdmi_dpll_clk_mux: hdmi_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01a4>; + }; + + mlb_clk: mlb_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mlb_clkin_ck>; + ti,max-div = <64>; + reg = <0x0134>; + ti,index-power-of-two; + }; + + mlbp_clk: mlbp_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mlbp_clkin_ck>; + ti,max-div = <64>; + reg = <0x0130>; + ti,index-power-of-two; + }; + + per_abe_x1_gfclk2_div: per_abe_x1_gfclk2_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + ti,max-div = <64>; + reg = <0x0138>; + ti,index-power-of-two; + }; + + timer_sys_clk_div: timer_sys_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin1>; + reg = <0x0144>; + ti,max-div = <2>; + }; + + video1_dpll_clk_mux: video1_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01d0>; + }; + + video2_dpll_clk_mux: video2_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + reg = <0x01d4>; + }; + + wkupaon_iclk_mux: wkupaon_iclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&abe_lp_clk_div>; + reg = <0x0108>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1838>; + }; + + dcan1_sys_clk_mux: dcan1_sys_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin1>, <&sys_clkin2>; + ti,bit-shift = <24>; + reg = <0x1888>; + }; + + timer1_gfclk_mux: timer1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + uart10_gfclk_mux: uart10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1880>; + }; +}; +&cm_core_clocks { + dpll_pcie_ref_ck: dpll_pcie_ref_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&sys_clkin1>; + reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>; + }; + + dpll_pcie_ref_m2ldo_ck: dpll_pcie_ref_m2ldo_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + apll_pcie_in_clk_mux: apll_pcie_in_clk_mux@4ae06118 { + compatible = "ti,mux-clock"; + clocks = <&dpll_pcie_ref_ck>, <&pciesref_acs_clk_ck>; + #clock-cells = <0>; + reg = <0x021c 0x4>; + ti,bit-shift = <7>; + }; + + apll_pcie_ck: apll_pcie_ck { + #clock-cells = <0>; + compatible = "ti,dra7-apll-clock"; + clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; + reg = <0x021c>, <0x0220>; + }; + + optfclk_pciephy_div: optfclk_pciephy_div@4a00821c { + compatible = "ti,divider-clock"; + clocks = <&apll_pcie_ck>; + #clock-cells = <0>; + reg = <0x021c>; + ti,bit-shift = <8>; + ti,max-div = <2>; + }; + + optfclk_pciephy_clk: optfclk_pciephy_clk@4a0093b0 { + compatible = "ti,gate-clock"; + clocks = <&apll_pcie_ck>; + #clock-cells = <0>; + reg = <0x13b0>; + ti,bit-shift = <9>; + }; + + optfclk_pciephy_div_clk: optfclk_pciephy_div_clk@4a0093b0 { + compatible = "ti,gate-clock"; + clocks = <&optfclk_pciephy_div>; + #clock-cells = <0>; + reg = <0x13b0>; + ti,bit-shift = <10>; + }; + + apll_pcie_clkvcoldo: apll_pcie_clkvcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + apll_pcie_clkvcoldo_div: apll_pcie_clkvcoldo_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + apll_pcie_m2_ck: apll_pcie_m2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&apll_pcie_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + func_96m_aon_dclk_div: func_96m_aon_dclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_pcie_ref_m2_ck: dpll_pcie_ref_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_pcie_ref_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + }; + + dpll_per_h11x2_ck: dpll_per_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h12x2_ck: dpll_per_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h13x2_ck: dpll_per_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0160>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h14x2_ck: dpll_per_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_clkdcoldo: dpll_usb_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + func_128m_clk: func_128m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l3init_60m_fclk: l3init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + dss_32khz_clk: dss_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <11>; + reg = <0x1120>; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <9>; + reg = <0x1120>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_h12x2_ck>; + ti,bit-shift = <8>; + reg = <0x1120>; + }; + + dss_hdmi_clk: dss_hdmi_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&hdmi_dpll_clk_mux>; + ti,bit-shift = <10>; + reg = <0x1120>; + }; + + dss_video1_clk: dss_video1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&video1_dpll_clk_mux>; + ti,bit-shift = <12>; + reg = <0x1120>; + }; + + dss_video2_clk: dss_video2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&video2_dpll_clk_mux>; + ti,bit-shift = <13>; + reg = <0x1120>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1760>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1768>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1770>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1778>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1780>; + }; + + gpio7_dbclk: gpio7_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1810>; + }; + + gpio8_dbclk: gpio8_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1818>; + }; + + mmc1_clk32k: mmc1_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1328>; + }; + + mmc2_clk32k: mmc2_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1330>; + }; + + mmc3_clk32k: mmc3_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1820>; + }; + + mmc4_clk32k: mmc4_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1828>; + }; + + sata_ref_clk: sata_ref_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin1>; + ti,bit-shift = <8>; + reg = <0x1388>; + }; + + usb_otg_ss1_refclk960m: usb_otg_ss1_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x13f0>; + }; + + usb_otg_ss2_refclk960m: usb_otg_ss2_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x1340>; + }; + + usb_phy1_always_on_clk32k: usb_phy1_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_phy2_always_on_clk32k: usb_phy2_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0688>; + }; + + usb_phy3_always_on_clk32k: usb_phy3_always_on_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0698>; + }; + + atl_dpll_clk_mux: atl_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_32k_ck>, <&video1_clkin_ck>, <&video2_clkin_ck>, <&hdmi_clkin_ck>; + ti,bit-shift = <24>; + reg = <0x0c00>; + }; + + atl_gfclk_mux: atl_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_abe_m2_ck>, <&atl_dpll_clk_mux>; + ti,bit-shift = <26>; + reg = <0x0c00>; + }; + + gmac_gmii_ref_clk_div: gmac_gmii_ref_clk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_gmac_m2_ck>; + ti,bit-shift = <24>; + reg = <0x13d0>; + ti,dividers = <2>; + }; + + gmac_rft_clk_mux: gmac_rft_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&video1_clkin_ck>, <&video2_clkin_ck>, <&dpll_abe_m2_ck>, <&hdmi_clkin_ck>, <&l3_iclk_div>; + ti,bit-shift = <25>; + reg = <0x13d0>; + }; + + gpu_core_gclk_mux: gpu_core_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>; + ti,bit-shift = <24>; + reg = <0x1220>; + }; + + gpu_hyd_gclk_mux: gpu_hyd_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>; + ti,bit-shift = <26>; + reg = <0x1220>; + }; + + l3instr_ts_gclk_div: l3instr_ts_gclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&wkupaon_iclk_mux>; + ti,bit-shift = <24>; + reg = <0x0e50>; + ti,dividers = <8>, <16>, <32>; + }; + + mcasp2_ahclkr_mux: mcasp2_ahclkr_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x1860>; + }; + + mcasp2_ahclkx_mux: mcasp2_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <28>; + reg = <0x1860>; + }; + + mcasp2_aux_gfclk_mux: mcasp2_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1860>; + }; + + mcasp3_ahclkx_mux: mcasp3_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1868>; + }; + + mcasp3_aux_gfclk_mux: mcasp3_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1868>; + }; + + mcasp4_ahclkx_mux: mcasp4_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1898>; + }; + + mcasp4_aux_gfclk_mux: mcasp4_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1898>; + }; + + mcasp5_ahclkx_mux: mcasp5_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1878>; + }; + + mcasp5_aux_gfclk_mux: mcasp5_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1878>; + }; + + mcasp6_ahclkx_mux: mcasp6_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1904>; + }; + + mcasp6_aux_gfclk_mux: mcasp6_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1904>; + }; + + mcasp7_ahclkx_mux: mcasp7_ahclkx_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <24>; + reg = <0x1908>; + }; + + mcasp7_aux_gfclk_mux: mcasp7_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <22>; + reg = <0x1908>; + }; + + mcasp8_ahclk_mux: mcasp8_ahclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + ti,bit-shift = <22>; + reg = <0x1890>; + }; + + mcasp8_aux_gfclk_mux: mcasp8_aux_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; + ti,bit-shift = <24>; + reg = <0x1890>; + }; + + mmc1_fclk_mux: mmc1_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1328>; + }; + + mmc1_fclk_div: mmc1_fclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc1_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1328>; + ti,index-power-of-two; + }; + + mmc2_fclk_mux: mmc2_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1330>; + }; + + mmc2_fclk_div: mmc2_fclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc2_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1330>; + ti,index-power-of-two; + }; + + mmc3_gfclk_mux: mmc3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1820>; + }; + + mmc3_gfclk_div: mmc3_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc3_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1820>; + ti,index-power-of-two; + }; + + mmc4_gfclk_mux: mmc4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1828>; + }; + + mmc4_gfclk_div: mmc4_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc4_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1828>; + ti,index-power-of-two; + }; + + qspi_gfclk_mux: qspi_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_h13x2_ck>; + ti,bit-shift = <24>; + reg = <0x1838>; + }; + + qspi_gfclk_div: qspi_gfclk_div { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&qspi_gfclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <4>; + reg = <0x1838>; + ti,index-power-of-two; + }; + + timer10_gfclk_mux: timer10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1728>; + }; + + timer11_gfclk_mux: timer11_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1730>; + }; + + timer13_gfclk_mux: timer13_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17c8>; + }; + + timer14_gfclk_mux: timer14_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17d0>; + }; + + timer15_gfclk_mux: timer15_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x17d8>; + }; + + timer16_gfclk_mux: timer16_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1830>; + }; + + timer2_gfclk_mux: timer2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1738>; + }; + + timer3_gfclk_mux: timer3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1740>; + }; + + timer4_gfclk_mux: timer4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1748>; + }; + + timer9_gfclk_mux: timer9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; + ti,bit-shift = <24>; + reg = <0x1750>; + }; + + uart1_gfclk_mux: uart1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + uart2_gfclk_mux: uart2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1848>; + }; + + uart3_gfclk_mux: uart3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1850>; + }; + + uart4_gfclk_mux: uart4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1858>; + }; + + uart5_gfclk_mux: uart5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1870>; + }; + + uart7_gfclk_mux: uart7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18d0>; + }; + + uart8_gfclk_mux: uart8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18e0>; + }; + + uart9_gfclk_mux: uart9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x18e8>; + }; + + vip1_gclk_mux: vip1_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1020>; + }; + + vip2_gclk_mux: vip2_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1028>; + }; + + vip3_gclk_mux: vip3_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>; + ti,bit-shift = <24>; + reg = <0x1030>; + }; +}; + +&cm_core_clockdomains { + coreaon_clkdm: coreaon_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>; + }; +}; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 427395c083f5..a5fc83b9c835 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -89,6 +89,45 @@ interrupts = <0>; }; + prm: prm@48306000 { + compatible = "ti,omap3-prm"; + reg = <0x48306000 0x4000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm: cm@48004000 { + compatible = "ti,omap3-cm"; + reg = <0x48004000 0x4000>; + + cm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_clockdomains: clockdomains { + }; + }; + + scrm: scrm@48002000 { + compatible = "ti,omap3-scrm"; + reg = <0x48002000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + counter32k: counter@48320000 { compatible = "ti,omap-counter32k"; reg = <0x48320000 0x20>; @@ -632,3 +671,5 @@ }; }; }; + +/include/ "omap3xxx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi new file mode 100644 index 000000000000..02f6c7fabbec --- /dev/null +++ b/arch/arm/boot/dts/omap3430es1-clocks.dtsi @@ -0,0 +1,208 @@ +/* + * Device Tree Source for OMAP3430 ES1 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_clocks { + gfx_l3_ck: gfx_l3_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&l3_ick>; + reg = <0x0b10>; + ti,bit-shift = <0>; + }; + + gfx_l3_fck: gfx_l3_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_ick>; + ti,max-div = <7>; + reg = <0x0b40>; + ti,index-starts-at-one; + }; + + gfx_l3_ick: gfx_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&gfx_l3_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gfx_cg1_ck: gfx_cg1_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&gfx_l3_fck>; + reg = <0x0b00>; + ti,bit-shift = <1>; + }; + + gfx_cg2_ck: gfx_cg2_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&gfx_l3_fck>; + reg = <0x0b00>; + ti,bit-shift = <2>; + }; + + d2d_26m_fck: d2d_26m_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0a00>; + ti,bit-shift = <3>; + }; + + fshostusb_fck: fshostusb_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <5>; + }; + + ssi_ssr_gate_fck_3430es1: ssi_ssr_gate_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <0>; + reg = <0x0a00>; + }; + + ssi_ssr_div_fck_3430es1: ssi_ssr_div_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; + }; + + ssi_ssr_fck_3430es1: ssi_ssr_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ssi_ssr_gate_fck_3430es1>, <&ssi_ssr_div_fck_3430es1>; + }; + + ssi_sst_fck_3430es1: ssi_sst_fck_3430es1 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&ssi_ssr_fck_3430es1>; + clock-mult = <1>; + clock-div = <2>; + }; + + hsotgusb_ick_3430es1: hsotgusb_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + fac_ick: fac_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <8>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + ssi_ick_3430es1: ssi_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <0>; + }; + + usb_l4_gate_ick: usb_l4_gate_ick { + #clock-cells = <0>; + compatible = "ti,composite-interface-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <5>; + reg = <0x0a10>; + }; + + usb_l4_div_ick: usb_l4_div_ick { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <4>; + ti,max-div = <1>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + usb_l4_ick: usb_l4_ick { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; + }; + + dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m4x2_ck>; + ti,bit-shift = <0>; + reg = <0x0e00>; + ti,set-rate-parent; + }; + + dss_ick_3430es1: dss_ick_3430es1 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0e10>; + ti,bit-shift = <0>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es1>; + }; + + gfx_3430es1_clkdm: gfx_3430es1_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gfx_l3_ck>, <&gfx_cg1_ck>, <&gfx_cg2_ck>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, + <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>; + }; + + d2d_clkdm: d2d_clkdm { + compatible = "ti,clockdomain"; + clocks = <&d2d_26m_fck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&fshostusb_fck>, <&fac_ick>, <&ssi_ick_3430es1>; + }; +}; diff --git a/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi new file mode 100644 index 000000000000..b02017b7630e --- /dev/null +++ b/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi @@ -0,0 +1,268 @@ +/* + * Device Tree Source for OMAP34XX/OMAP36XX clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_clocks { + security_l4_ick2: security_l4_ick2 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + aes1_ick: aes1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + ti,bit-shift = <3>; + reg = <0x0a14>; + }; + + rng_ick: rng_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <2>; + }; + + sha11_ick: sha11_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <1>; + }; + + des1_ick: des1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x0a14>; + ti,bit-shift = <0>; + }; + + cam_mclk: cam_mclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m5x2_ck>; + ti,bit-shift = <0>; + reg = <0x0f00>; + ti,set-rate-parent; + }; + + cam_ick: cam_ick { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0f10>; + ti,bit-shift = <0>; + }; + + csi2_96m_fck: csi2_96m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0f00>; + ti,bit-shift = <1>; + }; + + security_l3_ick: security_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + pka_ick: pka_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l3_ick>; + reg = <0x0a14>; + ti,bit-shift = <4>; + }; + + icr_ick: icr_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <29>; + }; + + des2_ick: des2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <26>; + }; + + mspro_ick: mspro_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <23>; + }; + + mailboxes_ick: mailboxes_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <7>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + sr1_fck: sr1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0c00>; + ti,bit-shift = <6>; + }; + + sr2_fck: sr2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&sys_ck>; + reg = <0x0c00>; + ti,bit-shift = <7>; + }; + + sr_l4_ick: sr_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll2_fck: dpll2_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,bit-shift = <19>; + ti,max-div = <7>; + reg = <0x0040>; + ti,index-starts-at-one; + }; + + dpll2_ck: dpll2_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll2_fck>; + reg = <0x0004>, <0x0024>, <0x0040>, <0x0034>; + ti,low-power-stop; + ti,lock; + ti,low-power-bypass; + }; + + dpll2_m2_ck: dpll2_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll2_ck>; + ti,max-div = <31>; + reg = <0x0044>; + ti,index-starts-at-one; + }; + + iva2_ck: iva2_ck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&dpll2_m2_ck>; + reg = <0x0000>; + ti,bit-shift = <0>; + }; + + modem_fck: modem_fck { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&sys_ck>; + reg = <0x0a00>; + ti,bit-shift = <31>; + }; + + sad2d_ick: sad2d_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <3>; + }; + + mad2d_ick: mad2d_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&l3_ick>; + reg = <0x0a18>; + ti,bit-shift = <3>; + }; + + mspro_fck: mspro_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; +}; + +&cm_clockdomains { + cam_clkdm: cam_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cam_ick>, <&csi2_96m_fck>; + }; + + iva2_clkdm: iva2_clkdm { + compatible = "ti,clockdomain"; + clocks = <&iva2_ck>; + }; + + dpll2_clkdm: dpll2_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll2_ck>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>, <&sr1_fck>, <&sr2_fck>; + }; + + d2d_clkdm: d2d_clkdm { + compatible = "ti,clockdomain"; + clocks = <&modem_fck>, <&sad2d_ick>, <&mad2d_ick>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, <&icr_ick>, + <&des2_ick>, <&mspro_ick>, <&mailboxes_ick>, + <&mspro_fck>; + }; +}; diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index 77d124678c95..2e92360da1f3 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -39,3 +39,7 @@ }; }; }; + +/include/ "omap34xx-omap36xx-clocks.dtsi" +/include/ "omap36xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi new file mode 100644 index 000000000000..af9ae5346bf2 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi @@ -0,0 +1,242 @@ +/* + * Device Tree Source for OMAP36xx/AM35xx/OMAP34xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&prm_clocks { + corex2_d3_fck: corex2_d3_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&corex2_fck>; + clock-mult = <1>; + clock-div = <3>; + }; + + corex2_d5_fck: corex2_d5_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&corex2_fck>; + clock-mult = <1>; + clock-div = <5>; + }; +}; +&cm_clocks { + dpll5_ck: dpll5_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d04>, <0x0d24>, <0x0d4c>, <0x0d34>; + ti,low-power-stop; + ti,lock; + }; + + dpll5_m2_ck: dpll5_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll5_ck>; + ti,max-div = <31>; + reg = <0x0d50>; + ti,index-starts-at-one; + }; + + sgx_gate_fck: sgx_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <1>; + reg = <0x0b00>; + }; + + core_d3_ck: core_d3_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + core_d4_ck: core_d4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + core_d6_ck: core_d6_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <6>; + }; + + omap_192m_alwon_fck: omap_192m_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + core_d2_ck: core_d2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + sgx_mux_fck: sgx_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_d3_ck>, <&core_d4_ck>, <&core_d6_ck>, <&cm_96m_fck>, <&omap_192m_alwon_fck>, <&core_d2_ck>, <&corex2_d3_fck>, <&corex2_d5_fck>; + reg = <0x0b40>; + }; + + sgx_fck: sgx_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&sgx_gate_fck>, <&sgx_mux_fck>; + }; + + sgx_ick: sgx_ick { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&l3_ick>; + reg = <0x0b10>; + ti,bit-shift = <0>; + }; + + cpefuse_fck: cpefuse_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x0a08>; + ti,bit-shift = <0>; + }; + + ts_fck: ts_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_32k_fck>; + reg = <0x0a08>; + ti,bit-shift = <1>; + }; + + usbtll_fck: usbtll_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&dpll5_m2_ck>; + reg = <0x0a08>; + ti,bit-shift = <2>; + }; + + usbtll_ick: usbtll_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a18>; + ti,bit-shift = <2>; + }; + + mmchs3_ick: mmchs3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <30>; + }; + + mmchs3_fck: mmchs3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <30>; + }; + + dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&dpll4_m4x2_ck>; + ti,bit-shift = <0>; + reg = <0x0e00>; + ti,set-rate-parent; + }; + + dss_ick_3430es2: dss_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-dss-interface-clock"; + clocks = <&l4_ick>; + reg = <0x0e10>; + ti,bit-shift = <0>; + }; + + usbhost_120m_fck: usbhost_120m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll5_m2_ck>; + reg = <0x1400>; + ti,bit-shift = <1>; + }; + + usbhost_48m_fck: usbhost_48m_fck { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&omap_48m_fck>; + reg = <0x1400>; + ti,bit-shift = <0>; + }; + + usbhost_ick: usbhost_ick { + #clock-cells = <0>; + compatible = "ti,omap3-dss-interface-clock"; + clocks = <&l4_ick>; + reg = <0x1410>; + ti,bit-shift = <0>; + }; +}; + +&cm_clockdomains { + dpll5_clkdm: dpll5_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll5_ck>; + }; + + sgx_clkdm: sgx_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sgx_ick>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, + <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>; + }; + + usbhost_clkdm: usbhost_clkdm { + compatible = "ti,clockdomain"; + clocks = <&usbhost_120m_fck>, <&usbhost_48m_fck>, + <&usbhost_ick>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi new file mode 100644 index 000000000000..2fcf253b677c --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-clocks.dtsi @@ -0,0 +1,90 @@ +/* + * Device Tree Source for OMAP36xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_clocks { + dpll4_ck: dpll4_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-per-j-type-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>; + }; + + dpll4_m5x2_ck: dpll4_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m5x2_mul_ck>; + ti,bit-shift = <0x1e>; + reg = <0x0d00>; + ti,set-rate-parent; + ti,set-bit-to-disable; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll3_m3x2_ck: dpll3_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll3_m3x2_mul_ck>; + ti,bit-shift = <0xc>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m3x2_ck: dpll4_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m3x2_mul_ck>; + ti,bit-shift = <0x1c>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m6x2_ck: dpll4_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m6x2_mul_ck>; + ti,bit-shift = <0x1f>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + uart4_fck: uart4_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_48m_fck>; + reg = <0x1000>; + ti,bit-shift = <18>; + }; +}; + +&cm_clockdomains { + dpll4_clkdm: dpll4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll4_ck>; + }; + + per_clkdm: per_clkdm { + compatible = "ti,clockdomain"; + clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>, + <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>, + <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>, + <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>, + <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>, + <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>, + <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>, + <&mcbsp4_ick>, <&uart4_fck>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi new file mode 100644 index 000000000000..8ed475dd63c9 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi @@ -0,0 +1,198 @@ +/* + * Device Tree Source for OMAP34xx/OMAP36xx clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_clocks { + ssi_ssr_gate_fck_3430es2: ssi_ssr_gate_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <0>; + reg = <0x0a00>; + }; + + ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; + }; + + ssi_ssr_fck_3430es2: ssi_ssr_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&ssi_ssr_gate_fck_3430es2>, <&ssi_ssr_div_fck_3430es2>; + }; + + ssi_sst_fck_3430es2: ssi_sst_fck_3430es2 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&ssi_ssr_fck_3430es2>; + clock-mult = <1>; + clock-div = <2>; + }; + + hsotgusb_ick_3430es2: hsotgusb_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-hsotgusb-interface-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <4>; + }; + + ssi_l4_ick: ssi_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + ssi_ick_3430es2: ssi_ick_3430es2 { + #clock-cells = <0>; + compatible = "ti,omap3-ssi-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <0>; + }; + + usim_gate_fck: usim_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&omap_96m_fck>; + ti,bit-shift = <9>; + reg = <0x0c00>; + }; + + sys_d2_ck: sys_d2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_96m_d2_fck: omap_96m_d2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_96m_d4_fck: omap_96m_d4_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <4>; + }; + + omap_96m_d8_fck: omap_96m_d8_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <8>; + }; + + omap_96m_d10_fck: omap_96m_d10_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <10>; + }; + + dpll5_m2_d4_ck: dpll5_m2_d4_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll5_m2_d8_ck: dpll5_m2_d8_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + dpll5_m2_d16_ck: dpll5_m2_d16_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + dpll5_m2_d20_ck: dpll5_m2_d20_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll5_m2_ck>; + clock-mult = <1>; + clock-div = <20>; + }; + + usim_mux_fck: usim_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_ck>, <&sys_d2_ck>, <&omap_96m_d2_fck>, <&omap_96m_d4_fck>, <&omap_96m_d8_fck>, <&omap_96m_d10_fck>, <&dpll5_m2_d4_ck>, <&dpll5_m2_d8_ck>, <&dpll5_m2_d16_ck>, <&dpll5_m2_d20_ck>; + ti,bit-shift = <3>; + reg = <0x0c40>; + ti,index-starts-at-one; + }; + + usim_fck: usim_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usim_gate_fck>, <&usim_mux_fck>; + }; + + usim_ick: usim_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <9>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es2>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>, <&usim_ick>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>, + <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>, + <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, + <&ssi_ick_3430es2>; + }; +}; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index b7c7bd96c404..7e8dee9175d6 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -51,3 +51,8 @@ }; }; }; + +/include/ "omap36xx-clocks.dtsi" +/include/ "omap34xx-omap36xx-clocks.dtsi" +/include/ "omap36xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi new file mode 100644 index 000000000000..cb04d4b37e7f --- /dev/null +++ b/arch/arm/boot/dts/omap3xxx-clocks.dtsi @@ -0,0 +1,1660 @@ +/* + * Device Tree Source for OMAP3 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&prm_clocks { + virt_16_8m_ck: virt_16_8m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + osc_sys_ck: osc_sys_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12m_ck>, <&virt_13m_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_38_4m_ck>, <&virt_16_8m_ck>; + reg = <0x0d40>; + }; + + sys_ck: sys_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&osc_sys_ck>; + ti,bit-shift = <6>; + ti,max-div = <3>; + reg = <0x1270>; + ti,index-starts-at-one; + }; + + sys_clkout1: sys_clkout1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&osc_sys_ck>; + reg = <0x0d70>; + ti,bit-shift = <7>; + }; + + dpll3_x2_ck: dpll3_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll3_m2x2_ck: dpll3_m2x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_x2_ck: dpll4_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + corex2_fck: corex2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + wkup_l4_ick: wkup_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_ck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; +&scrm_clocks { + mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; + }; + + mcbsp5_fck: mcbsp5_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp5_gate_fck>, <&mcbsp5_mux_fck>; + }; + + mcbsp1_mux_fck: mcbsp1_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x0274>; + }; + + mcbsp1_fck: mcbsp1_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp1_gate_fck>, <&mcbsp1_mux_fck>; + }; + + mcbsp2_mux_fck: mcbsp2_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <6>; + reg = <0x0274>; + }; + + mcbsp2_fck: mcbsp2_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp2_gate_fck>, <&mcbsp2_mux_fck>; + }; + + mcbsp3_mux_fck: mcbsp3_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + reg = <0x02d8>; + }; + + mcbsp3_fck: mcbsp3_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp3_gate_fck>, <&mcbsp3_mux_fck>; + }; + + mcbsp4_mux_fck: mcbsp4_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&per_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x02d8>; + }; + + mcbsp4_fck: mcbsp4_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&mcbsp4_gate_fck>, <&mcbsp4_mux_fck>; + }; +}; +&cm_clocks { + dummy_apb_pclk: dummy_apb_pclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + omap_32k_fck: omap_32k_fck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12m_ck: virt_12m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13m_ck: virt_13m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_38_4m_ck: virt_38_4m_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + dpll4_ck: dpll4_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-per-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>; + }; + + dpll4_m2_ck: dpll4_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <63>; + reg = <0x0d48>; + ti,index-starts-at-one; + }; + + dpll4_m2x2_mul_ck: dpll4_m2x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + omap_96m_alwon_fck: omap_96m_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m2x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll3_ck: dpll3_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-core-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0d00>, <0x0d20>, <0x0d40>, <0x0d30>; + }; + + dpll3_m3_ck: dpll3_m3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll3_ck>; + ti,bit-shift = <16>; + ti,max-div = <31>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + dpll3_m3x2_mul_ck: dpll3_m3x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll3_m3x2_ck: dpll3_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll3_m3x2_mul_ck>; + ti,bit-shift = <0xc>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + emu_core_alwon_ck: emu_core_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m3x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + sys_altclk: sys_altclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + mcbsp_clks: mcbsp_clks { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0x0>; + }; + + dpll3_m2_ck: dpll3_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll3_ck>; + ti,bit-shift = <27>; + ti,max-div = <31>; + reg = <0x0d40>; + ti,index-starts-at-one; + }; + + core_ck: core_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll3_m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll1_fck: dpll1_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,bit-shift = <19>; + ti,max-div = <7>; + reg = <0x0940>; + ti,index-starts-at-one; + }; + + dpll1_ck: dpll1_ck { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll1_fck>; + reg = <0x0904>, <0x0924>, <0x0940>, <0x0934>; + }; + + dpll1_x2_ck: dpll1_x2_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll1_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll1_x2m2_ck: dpll1_x2m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll1_x2_ck>; + ti,max-div = <31>; + reg = <0x0944>; + ti,index-starts-at-one; + }; + + cm_96m_fck: cm_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_alwon_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + omap_96m_fck: omap_96m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&cm_96m_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x0d40>; + }; + + dpll4_m3_ck: dpll4_m3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,bit-shift = <8>; + ti,max-div = <32>; + reg = <0x0e40>; + ti,index-starts-at-one; + }; + + dpll4_m3x2_mul_ck: dpll4_m3x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m3_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m3x2_ck: dpll4_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m3x2_mul_ck>; + ti,bit-shift = <0x1c>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + omap_54m_fck: omap_54m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll4_m3x2_ck>, <&sys_altclk>; + ti,bit-shift = <5>; + reg = <0x0d40>; + }; + + cm_96m_d2_fck: cm_96m_d2_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&cm_96m_fck>; + clock-mult = <1>; + clock-div = <2>; + }; + + omap_48m_fck: omap_48m_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&cm_96m_d2_fck>, <&sys_altclk>; + ti,bit-shift = <3>; + reg = <0x0d40>; + }; + + omap_12m_fck: omap_12m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dpll4_m4_ck: dpll4_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <32>; + reg = <0x0e40>; + ti,index-starts-at-one; + }; + + dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m4_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m4x2_ck: dpll4_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m4x2_mul_ck>; + ti,bit-shift = <0x1d>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m5_ck: dpll4_m5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,max-div = <63>; + reg = <0x0f40>; + ti,index-starts-at-one; + }; + + dpll4_m5x2_mul_ck: dpll4_m5x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m5_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m5x2_ck: dpll4_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m5x2_mul_ck>; + ti,bit-shift = <0x1e>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + dpll4_m6_ck: dpll4_m6_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll4_ck>; + ti,bit-shift = <24>; + ti,max-div = <63>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + dpll4_m6x2_mul_ck: dpll4_m6x2_mul_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m6_ck>; + clock-mult = <2>; + clock-div = <1>; + }; + + dpll4_m6x2_ck: dpll4_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll4_m6x2_mul_ck>; + ti,bit-shift = <0x1f>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + emu_per_alwon_ck: emu_per_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll4_m6x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + clkout2_src_gate_ck: clkout2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <7>; + reg = <0x0d70>; + }; + + clkout2_src_mux_ck: clkout2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_ck>, <&sys_ck>, <&cm_96m_fck>, <&omap_54m_fck>; + reg = <0x0d70>; + }; + + clkout2_src_ck: clkout2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&clkout2_src_gate_ck>, <&clkout2_src_mux_ck>; + }; + + sys_clkout2: sys_clkout2 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&clkout2_src_ck>; + ti,bit-shift = <3>; + ti,max-div = <64>; + reg = <0x0d70>; + ti,index-power-of-two; + }; + + mpu_ck: mpu_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll1_x2m2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + arm_fck: arm_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mpu_ck>; + reg = <0x0924>; + ti,max-div = <2>; + }; + + emu_mpu_alwon_ck: emu_mpu_alwon_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&mpu_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l3_ick: l3_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&core_ck>; + ti,max-div = <3>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + l4_ick: l4_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_ick>; + ti,bit-shift = <2>; + ti,max-div = <3>; + reg = <0x0a40>; + ti,index-starts-at-one; + }; + + rm_ick: rm_ick { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <1>; + ti,max-div = <3>; + reg = <0x0c40>; + ti,index-starts-at-one; + }; + + gpt10_gate_fck: gpt10_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <11>; + reg = <0x0a00>; + }; + + gpt10_mux_fck: gpt10_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x0a40>; + }; + + gpt10_fck: gpt10_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt10_gate_fck>, <&gpt10_mux_fck>; + }; + + gpt11_gate_fck: gpt11_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <12>; + reg = <0x0a00>; + }; + + gpt11_mux_fck: gpt11_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x0a40>; + }; + + gpt11_fck: gpt11_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt11_gate_fck>, <&gpt11_mux_fck>; + }; + + core_96m_fck: core_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mmchs2_fck: mmchs2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <25>; + }; + + mmchs1_fck: mmchs1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <24>; + }; + + i2c3_fck: i2c3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <17>; + }; + + i2c2_fck: i2c2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <16>; + }; + + i2c1_fck: i2c1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <15>; + }; + + mcbsp5_gate_fck: mcbsp5_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <10>; + reg = <0x0a00>; + }; + + mcbsp1_gate_fck: mcbsp1_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <9>; + reg = <0x0a00>; + }; + + core_48m_fck: core_48m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + mcspi4_fck: mcspi4_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <21>; + }; + + mcspi3_fck: mcspi3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <20>; + }; + + mcspi2_fck: mcspi2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <19>; + }; + + mcspi1_fck: mcspi1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <18>; + }; + + uart2_fck: uart2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <14>; + }; + + uart1_fck: uart1_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <13>; + }; + + core_12m_fck: core_12m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_12m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + hdq_fck: hdq_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_12m_fck>; + reg = <0x0a00>; + ti,bit-shift = <22>; + }; + + core_l3_ick: core_l3_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + sdrc_ick: sdrc_ick { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_l3_ick>; + reg = <0x0a10>; + ti,bit-shift = <1>; + }; + + gpmc_fck: gpmc_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&core_l3_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + core_l4_ick: core_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + mmchs2_ick: mmchs2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <25>; + }; + + mmchs1_ick: mmchs1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <24>; + }; + + hdq_ick: hdq_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <22>; + }; + + mcspi4_ick: mcspi4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <21>; + }; + + mcspi3_ick: mcspi3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <20>; + }; + + mcspi2_ick: mcspi2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <19>; + }; + + mcspi1_ick: mcspi1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <18>; + }; + + i2c3_ick: i2c3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <17>; + }; + + i2c2_ick: i2c2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <16>; + }; + + i2c1_ick: i2c1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <15>; + }; + + uart2_ick: uart2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <14>; + }; + + uart1_ick: uart1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <13>; + }; + + gpt11_ick: gpt11_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <12>; + }; + + gpt10_ick: gpt10_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <11>; + }; + + mcbsp5_ick: mcbsp5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <10>; + }; + + mcbsp1_ick: mcbsp1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <9>; + }; + + omapctrl_ick: omapctrl_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <6>; + }; + + dss_tv_fck: dss_tv_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_54m_fck>; + reg = <0x0e00>; + ti,bit-shift = <2>; + }; + + dss_96m_fck: dss_96m_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&omap_96m_fck>; + reg = <0x0e00>; + ti,bit-shift = <2>; + }; + + dss2_alwon_fck: dss2_alwon_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_ck>; + reg = <0x0e00>; + ti,bit-shift = <1>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + gpt1_gate_fck: gpt1_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <0>; + reg = <0x0c00>; + }; + + gpt1_mux_fck: gpt1_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + reg = <0x0c40>; + }; + + gpt1_fck: gpt1_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt1_gate_fck>, <&gpt1_mux_fck>; + }; + + aes2_ick: aes2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + ti,bit-shift = <28>; + reg = <0x0a10>; + }; + + wkup_32k_fck: wkup_32k_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio1_dbck: gpio1_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&wkup_32k_fck>; + reg = <0x0c00>; + ti,bit-shift = <3>; + }; + + sha12_ick: sha12_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&core_l4_ick>; + reg = <0x0a10>; + ti,bit-shift = <27>; + }; + + wdt2_fck: wdt2_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&wkup_32k_fck>; + reg = <0x0c00>; + ti,bit-shift = <5>; + }; + + wdt2_ick: wdt2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <5>; + }; + + wdt1_ick: wdt1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <4>; + }; + + gpio1_ick: gpio1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <3>; + }; + + omap_32ksync_ick: omap_32ksync_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <2>; + }; + + gpt12_ick: gpt12_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <1>; + }; + + gpt1_ick: gpt1_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&wkup_l4_ick>; + reg = <0x0c10>; + ti,bit-shift = <0>; + }; + + per_96m_fck: per_96m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_96m_alwon_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + per_48m_fck: per_48m_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_48m_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + uart3_fck: uart3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_48m_fck>; + reg = <0x1000>; + ti,bit-shift = <11>; + }; + + gpt2_gate_fck: gpt2_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <3>; + reg = <0x1000>; + }; + + gpt2_mux_fck: gpt2_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + reg = <0x1040>; + }; + + gpt2_fck: gpt2_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt2_gate_fck>, <&gpt2_mux_fck>; + }; + + gpt3_gate_fck: gpt3_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <4>; + reg = <0x1000>; + }; + + gpt3_mux_fck: gpt3_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <1>; + reg = <0x1040>; + }; + + gpt3_fck: gpt3_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt3_gate_fck>, <&gpt3_mux_fck>; + }; + + gpt4_gate_fck: gpt4_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <5>; + reg = <0x1000>; + }; + + gpt4_mux_fck: gpt4_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <2>; + reg = <0x1040>; + }; + + gpt4_fck: gpt4_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt4_gate_fck>, <&gpt4_mux_fck>; + }; + + gpt5_gate_fck: gpt5_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x1000>; + }; + + gpt5_mux_fck: gpt5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <3>; + reg = <0x1040>; + }; + + gpt5_fck: gpt5_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt5_gate_fck>, <&gpt5_mux_fck>; + }; + + gpt6_gate_fck: gpt6_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x1000>; + }; + + gpt6_mux_fck: gpt6_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <4>; + reg = <0x1040>; + }; + + gpt6_fck: gpt6_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt6_gate_fck>, <&gpt6_mux_fck>; + }; + + gpt7_gate_fck: gpt7_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <8>; + reg = <0x1000>; + }; + + gpt7_mux_fck: gpt7_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <5>; + reg = <0x1040>; + }; + + gpt7_fck: gpt7_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt7_gate_fck>, <&gpt7_mux_fck>; + }; + + gpt8_gate_fck: gpt8_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <9>; + reg = <0x1000>; + }; + + gpt8_mux_fck: gpt8_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <6>; + reg = <0x1040>; + }; + + gpt8_fck: gpt8_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt8_gate_fck>, <&gpt8_mux_fck>; + }; + + gpt9_gate_fck: gpt9_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <10>; + reg = <0x1000>; + }; + + gpt9_mux_fck: gpt9_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&omap_32k_fck>, <&sys_ck>; + ti,bit-shift = <7>; + reg = <0x1040>; + }; + + gpt9_fck: gpt9_fck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&gpt9_gate_fck>, <&gpt9_mux_fck>; + }; + + per_32k_alwon_fck: per_32k_alwon_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&omap_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio6_dbck: gpio6_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <17>; + }; + + gpio5_dbck: gpio5_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <16>; + }; + + gpio4_dbck: gpio4_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <15>; + }; + + gpio3_dbck: gpio3_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <14>; + }; + + gpio2_dbck: gpio2_dbck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <13>; + }; + + wdt3_fck: wdt3_fck { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&per_32k_alwon_fck>; + reg = <0x1000>; + ti,bit-shift = <12>; + }; + + per_l4_ick: per_l4_ick { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l4_ick>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio6_ick: gpio6_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <17>; + }; + + gpio5_ick: gpio5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <16>; + }; + + gpio4_ick: gpio4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <15>; + }; + + gpio3_ick: gpio3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <14>; + }; + + gpio2_ick: gpio2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <13>; + }; + + wdt3_ick: wdt3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <12>; + }; + + uart3_ick: uart3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <11>; + }; + + uart4_ick: uart4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <18>; + }; + + gpt9_ick: gpt9_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <10>; + }; + + gpt8_ick: gpt8_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <9>; + }; + + gpt7_ick: gpt7_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <8>; + }; + + gpt6_ick: gpt6_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <7>; + }; + + gpt5_ick: gpt5_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <6>; + }; + + gpt4_ick: gpt4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <5>; + }; + + gpt3_ick: gpt3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <4>; + }; + + gpt2_ick: gpt2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <3>; + }; + + mcbsp2_ick: mcbsp2_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <0>; + }; + + mcbsp3_ick: mcbsp3_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <1>; + }; + + mcbsp4_ick: mcbsp4_ick { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&per_l4_ick>; + reg = <0x1010>; + ti,bit-shift = <2>; + }; + + mcbsp2_gate_fck: mcbsp2_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <0>; + reg = <0x1000>; + }; + + mcbsp3_gate_fck: mcbsp3_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <1>; + reg = <0x1000>; + }; + + mcbsp4_gate_fck: mcbsp4_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&mcbsp_clks>; + ti,bit-shift = <2>; + reg = <0x1000>; + }; + + emu_src_mux_ck: emu_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>; + reg = <0x1140>; + }; + + emu_src_ck: emu_src_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&emu_src_mux_ck>; + }; + + pclk_fck: pclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <8>; + ti,max-div = <7>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + pclkx2_fck: pclkx2_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <6>; + ti,max-div = <3>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + atclk_fck: atclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&emu_src_ck>; + ti,bit-shift = <4>; + ti,max-div = <3>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + traceclk_src_fck: traceclk_src_fck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>; + ti,bit-shift = <2>; + reg = <0x1140>; + }; + + traceclk_fck: traceclk_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&traceclk_src_fck>; + ti,bit-shift = <11>; + ti,max-div = <7>; + reg = <0x1140>; + ti,index-starts-at-one; + }; + + secure_32k_fck: secure_32k_fck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + gpt12_fck: gpt12_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&secure_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; + + wdt1_fck: wdt1_fck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&secure_32k_fck>; + clock-mult = <1>; + clock-div = <1>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>; + }; + + dpll3_clkdm: dpll3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll3_ck>; + }; + + dpll1_clkdm: dpll1_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll1_ck>; + }; + + per_clkdm: per_clkdm { + compatible = "ti,clockdomain"; + clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>, + <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>, + <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>, + <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>, + <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>, + <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>, + <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>, + <&mcbsp4_ick>; + }; + + emu_clkdm: emu_clkdm { + compatible = "ti,clockdomain"; + clocks = <&emu_src_ck>; + }; + + dpll4_clkdm: dpll4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll4_ck>; + }; + + wkup_clkdm: wkup_clkdm { + compatible = "ti,clockdomain"; + clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>, + <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>, + <&gpt1_ick>; + }; + + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>; + }; + + core_l4_clkdm: core_l4_clkdm { + compatible = "ti,clockdomain"; + clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>, + <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>, + <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>, + <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>, + <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>, + <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>, + <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>, + <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>, + <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>; + }; +}; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index a1e05853afcd..d3f8a6e8ca20 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -107,6 +107,58 @@ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + cm1: cm1@4a004000 { + compatible = "ti,omap4-cm1"; + reg = <0x4a004000 0x2000>; + + cm1_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm1_clockdomains: clockdomains { + }; + }; + + prm: prm@4a306000 { + compatible = "ti,omap4-prm"; + reg = <0x4a306000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm2: cm2@4a008000 { + compatible = "ti,omap4-cm2"; + reg = <0x4a008000 0x3000>; + + cm2_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm2_clockdomains: clockdomains { + }; + }; + + scrm: scrm@4a30a000 { + compatible = "ti,omap4-scrm"; + reg = <0x4a30a000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + counter32k: counter@4a304000 { compatible = "ti,omap-counter32k"; reg = <0x4a304000 0x20>; @@ -707,3 +759,5 @@ }; }; }; + +/include/ "omap44xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap443x-clocks.dtsi b/arch/arm/boot/dts/omap443x-clocks.dtsi new file mode 100644 index 000000000000..2bd2166f88d3 --- /dev/null +++ b/arch/arm/boot/dts/omap443x-clocks.dtsi @@ -0,0 +1,18 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&prm_clocks { + bandgap_fclk: bandgap_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1888>; + }; +}; diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi index ab607a19a613..8c1cfad30d60 100644 --- a/arch/arm/boot/dts/omap443x.dtsi +++ b/arch/arm/boot/dts/omap443x.dtsi @@ -44,3 +44,5 @@ }; }; }; + +/include/ "omap443x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index 11566bed0035..6b32f520741a 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -52,3 +52,5 @@ }; }; }; + +/include/ "omap446x-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap446x-clocks.dtsi b/arch/arm/boot/dts/omap446x-clocks.dtsi new file mode 100644 index 000000000000..be033e9803e9 --- /dev/null +++ b/arch/arm/boot/dts/omap446x-clocks.dtsi @@ -0,0 +1,27 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&prm_clocks { + div_ts_ck: div_ts_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <24>; + reg = <0x1888>; + ti,dividers = <8>, <16>, <32>; + }; + + bandgap_ts_fclk: bandgap_ts_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&div_ts_ck>; + ti,bit-shift = <8>; + reg = <0x1888>; + }; +}; diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi new file mode 100644 index 000000000000..c821ff5e9b8d --- /dev/null +++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi @@ -0,0 +1,1651 @@ +/* + * Device Tree Source for OMAP4 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm1_clocks { + extalt_clkin_ck: extalt_clkin_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <59000000>; + }; + + pad_clks_src_ck: pad_clks_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + pad_clks_ck: pad_clks_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_src_ck>; + ti,bit-shift = <8>; + reg = <0x0108>; + }; + + pad_slimbus_core_clks_ck: pad_slimbus_core_clks_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + slimbus_src_clk: slimbus_src_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + slimbus_clk: slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_src_clk>; + ti,bit-shift = <10>; + reg = <0x0108>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + tie_low_clock_ck: tie_low_clock_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + utmi_phy_clkout_ck: utmi_phy_clkout_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp1_ck: xclk60mhsp1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp2_ck: xclk60mhsp2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60motg_ck: xclk60motg_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_refclk_mux_ck>, <&abe_dpll_bypass_clk_mux_ck>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + reg = <0x01f0>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x0528>; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + core_hsd_byp_clk_mux_ck: core_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_abe_m3x2_ck>; + ti,bit-shift = <23>; + reg = <0x012c>; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&core_hsd_byp_clk_mux_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_m6x2_ck: dpll_core_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + ddrphy_ck: ddrphy_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_core_m5x2_ck: dpll_core_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + div_core_ck: div_core_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + reg = <0x0100>; + ti,max-div = <2>; + }; + + div_iva_hs_clk: div_iva_hs_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + ti,max-div = <4>; + reg = <0x01dc>; + ti,index-power-of-two; + }; + + div_mpu_hs_clk: div_mpu_hs_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5x2_ck>; + ti,max-div = <4>; + reg = <0x019c>; + ti,index-power-of-two; + }; + + dpll_core_m4x2_ck: dpll_core_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0138>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dll_clk_div_ck: dll_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_m4x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_abe_m2_ck: dpll_abe_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_ck>; + ti,max-div = <31>; + reg = <0x01f0>; + ti,index-starts-at-one; + }; + + dpll_core_m3x2_gate_ck: dpll_core_m3x2_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_x2_ck>; + ti,bit-shift = <8>; + reg = <0x0134>; + }; + + dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0134>; + ti,index-starts-at-one; + }; + + dpll_core_m3x2_ck: dpll_core_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&dpll_core_m3x2_gate_ck>, <&dpll_core_m3x2_div_ck>; + }; + + dpll_core_m7x2_ck: dpll_core_m7x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_hsd_byp_clk_mux_ck: iva_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&div_iva_hs_clk>; + ti,bit-shift = <23>; + reg = <0x01ac>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&iva_hsd_byp_clk_mux_ck>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_x2_ck: dpll_iva_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_iva_ck>; + }; + + dpll_iva_m4x2_ck: dpll_iva_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_iva_m5x2_ck: dpll_iva_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&div_mpu_hs_clk>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + per_hs_clk_div_ck: per_hs_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_hs_clk_div_ck: usb_hs_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + l3_div_ck: l3_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&div_core_ck>; + ti,bit-shift = <4>; + ti,max-div = <2>; + reg = <0x0100>; + }; + + l4_div_ck: l4_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <8>; + ti,max-div = <2>; + reg = <0x0100>; + }; + + lp_clk_div_ck: lp_clk_div_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + mpu_periphclk: mpu_periphclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_mpu_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + ocp_abe_iclk: ocp_abe_iclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&aess_fclk>; + ti,bit-shift = <24>; + reg = <0x0528>; + ti,dividers = <2>, <1>; + }; + + per_abe_24m_fclk: per_abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + dmic_sync_mux_ck: dmic_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0538>; + }; + + func_dmic_abe_gfclk: func_dmic_abe_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0538>; + }; + + mcasp_sync_mux_ck: mcasp_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0540>; + }; + + func_mcasp_abe_gfclk: func_mcasp_abe_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0540>; + }; + + mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0548>; + }; + + func_mcbsp1_gfclk: func_mcbsp1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0548>; + }; + + mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0550>; + }; + + func_mcbsp2_gfclk: func_mcbsp2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; + ti,bit-shift = <25>; + reg = <0x0558>; + }; + + func_mcbsp3_gfclk: func_mcbsp3_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + slimbus1_fclk_1: slimbus1_fclk_1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_24m_clk>; + ti,bit-shift = <9>; + reg = <0x0560>; + }; + + slimbus1_fclk_0: slimbus1_fclk_0 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&abe_24m_fclk>; + ti,bit-shift = <8>; + reg = <0x0560>; + }; + + slimbus1_fclk_2: slimbus1_fclk_2 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_ck>; + ti,bit-shift = <10>; + reg = <0x0560>; + }; + + slimbus1_slimbus_clk: slimbus1_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_clk>; + ti,bit-shift = <11>; + reg = <0x0560>; + }; + + timer5_sync_mux: timer5_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer6_sync_mux: timer6_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + timer7_sync_mux: timer7_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0578>; + }; + + timer8_sync_mux: timer8_sync_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin_ck: sys_clkin_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0108>; + }; + + abe_dpll_refclk_mux_ck: abe_dpll_refclk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + dbgclk_mux_ck: dbgclk_mux_ck { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_wkup_clk_mux_ck: l4_wkup_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&lp_clk_div_ck>; + reg = <0x0108>; + }; + + syc_clk_div_ck: syc_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&sys_clkin_ck>; + reg = <0x0100>; + ti,max-div = <2>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1838>; + }; + + dmt1_clk_mux: dmt1_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1840>; + }; + + usim_ck: usim_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + ti,bit-shift = <24>; + reg = <0x1858>; + ti,dividers = <14>, <18>; + }; + + usim_fclk: usim_fclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&usim_ck>; + ti,bit-shift = <8>; + reg = <0x1858>; + }; + + pmd_stm_clock_mux_ck: pmd_stm_clock_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; + ti,bit-shift = <20>; + reg = <0x1a20>; + }; + + pmd_trace_clk_mux_ck: pmd_trace_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; + ti,bit-shift = <22>; + reg = <0x1a20>; + }; + + stm_clk_div_ck: stm_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&pmd_stm_clock_mux_ck>; + ti,bit-shift = <27>; + ti,max-div = <64>; + reg = <0x1a20>; + ti,index-power-of-two; + }; + + trace_clk_div_div_ck: trace_clk_div_div_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&pmd_trace_clk_mux_ck>; + ti,bit-shift = <24>; + reg = <0x1a20>; + ti,dividers = <0>, <1>, <2>, <0>, <4>; + }; + + trace_clk_div_ck: trace_clk_div_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&trace_clk_div_div_ck>; + }; +}; + +&prm_clockdomains { + emu_sys_clkdm: emu_sys_clkdm { + compatible = "ti,clockdomain"; + clocks = <&trace_clk_div_ck>; + }; +}; + +&cm2_clocks { + per_hsd_byp_clk_mux_ck: per_hsd_byp_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&per_hs_clk_div_ck>; + ti,bit-shift = <23>; + reg = <0x014c>; + }; + + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin_ck>, <&per_hsd_byp_clk_mux_ck>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + reg = <0x0150>; + ti,index-starts-at-one; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + reg = <0x0150>; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m3x2_gate_ck: dpll_per_m3x2_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_per_x2_ck>; + ti,bit-shift = <8>; + reg = <0x0154>; + }; + + dpll_per_m3x2_div_ck: dpll_per_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + reg = <0x0154>; + ti,index-starts-at-one; + }; + + dpll_per_m3x2_ck: dpll_per_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&dpll_per_m3x2_gate_ck>, <&dpll_per_m3x2_div_ck>; + }; + + dpll_per_m4x2_ck: dpll_per_m4x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m5x2_ck: dpll_per_m5x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m6x2_ck: dpll_per_m6x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0160>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m7x2_ck: dpll_per_m7x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin_ck>, <&usb_hs_clk_div_ck>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + ducati_clk_mux_ck: ducati_clk_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&div_core_ck>, <&dpll_per_m6x2_ck>; + reg = <0x0100>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_24mc_fclk: func_24mc_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + reg = <0x0108>; + ti,dividers = <4>, <8>; + }; + + func_48mc_fclk: func_48mc_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_64m_fclk: func_64m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + reg = <0x0108>; + ti,dividers = <2>, <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + reg = <0x0108>; + ti,dividers = <2>, <4>; + }; + + init_60m_fclk: init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + per_abe_nc_fclk: per_abe_nc_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2_ck>; + reg = <0x0108>; + ti,max-div = <2>; + }; + + aes1_fck: aes1_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15a0>; + }; + + aes2_fck: aes2_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15a8>; + }; + + dss_sys_clk: dss_sys_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&syc_clk_div_ck>; + ti,bit-shift = <10>; + reg = <0x1120>; + }; + + dss_tv_clk: dss_tv_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&extalt_clkin_ck>; + ti,bit-shift = <11>; + reg = <0x1120>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_m5x2_ck>; + ti,bit-shift = <8>; + reg = <0x1120>; + ti,set-rate-parent; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <9>; + reg = <0x1120>; + }; + + dss_fck: dss_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x1120>; + }; + + fdif_fck: fdif_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m4x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <4>; + reg = <0x1028>; + ti,index-power-of-two; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1460>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1468>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1470>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1478>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1480>; + }; + + sgx_clk_mux: sgx_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_m7x2_ck>, <&dpll_per_m7x2_ck>; + ti,bit-shift = <24>; + reg = <0x1220>; + }; + + hsi_fck: hsi_fck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <4>; + reg = <0x1338>; + ti,index-power-of-two; + }; + + iss_ctrlclk: iss_ctrlclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_96m_fclk>; + ti,bit-shift = <8>; + reg = <0x1020>; + }; + + mcbsp4_sync_mux_ck: mcbsp4_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_96m_fclk>, <&per_abe_nc_fclk>; + ti,bit-shift = <25>; + reg = <0x14e0>; + }; + + per_mcbsp4_gfclk: per_mcbsp4_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp4_sync_mux_ck>, <&pad_clks_ck>; + ti,bit-shift = <24>; + reg = <0x14e0>; + }; + + hsmmc1_fclk: hsmmc1_fclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_64m_fclk>, <&func_96m_fclk>; + ti,bit-shift = <24>; + reg = <0x1328>; + }; + + hsmmc2_fclk: hsmmc2_fclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_64m_fclk>, <&func_96m_fclk>; + ti,bit-shift = <24>; + reg = <0x1330>; + }; + + ocp2scp_usb_phy_phy_48m: ocp2scp_usb_phy_phy_48m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <8>; + reg = <0x13e0>; + }; + + sha2md5_fck: sha2md5_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <1>; + reg = <0x15c8>; + }; + + slimbus2_fclk_1: slimbus2_fclk_1 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&per_abe_24m_fclk>; + ti,bit-shift = <9>; + reg = <0x1538>; + }; + + slimbus2_fclk_0: slimbus2_fclk_0 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_24mc_fclk>; + ti,bit-shift = <8>; + reg = <0x1538>; + }; + + slimbus2_slimbus_clk: slimbus2_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_slimbus_core_clks_ck>; + ti,bit-shift = <10>; + reg = <0x1538>; + }; + + smartreflex_core_fck: smartreflex_core_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0638>; + }; + + smartreflex_iva_fck: smartreflex_iva_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0630>; + }; + + smartreflex_mpu_fck: smartreflex_mpu_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_wkup_clk_mux_ck>; + ti,bit-shift = <1>; + reg = <0x0628>; + }; + + cm2_dm10_mux: cm2_dm10_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1428>; + }; + + cm2_dm11_mux: cm2_dm11_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1430>; + }; + + cm2_dm2_mux: cm2_dm2_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1438>; + }; + + cm2_dm3_mux: cm2_dm3_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1440>; + }; + + cm2_dm4_mux: cm2_dm4_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1448>; + }; + + cm2_dm9_mux: cm2_dm9_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1450>; + }; + + usb_host_fs_fck: usb_host_fs_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <1>; + reg = <0x13d0>; + }; + + utmi_p1_gfclk: utmi_p1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&init_60m_fclk>, <&xclk60mhsp1_ck>; + ti,bit-shift = <24>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p1_gfclk>; + ti,bit-shift = <8>; + reg = <0x1358>; + }; + + utmi_p2_gfclk: utmi_p2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&init_60m_fclk>, <&xclk60mhsp2_ck>; + ti,bit-shift = <25>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p2_gfclk>; + ti,bit-shift = <9>; + reg = <0x1358>; + }; + + usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1358>; + }; + + usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <13>; + reg = <0x1358>; + }; + + usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <11>; + reg = <0x1358>; + }; + + usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <12>; + reg = <0x1358>; + }; + + usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <14>; + reg = <0x1358>; + }; + + usb_host_hs_func48mclk: usb_host_hs_func48mclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48mc_fclk>; + ti,bit-shift = <15>; + reg = <0x1358>; + }; + + usb_host_hs_fck: usb_host_hs_fck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <1>; + reg = <0x1358>; + }; + + otg_60m_gfclk: otg_60m_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&utmi_phy_clkout_ck>, <&xclk60motg_ck>; + ti,bit-shift = <24>; + reg = <0x1360>; + }; + + usb_otg_hs_xclk: usb_otg_hs_xclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&otg_60m_gfclk>; + ti,bit-shift = <8>; + reg = <0x1360>; + }; + + usb_otg_hs_ick: usb_otg_hs_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3_div_ck>; + ti,bit-shift = <0>; + reg = <0x1360>; + }; + + usb_phy_cm_clk32k: usb_phy_cm_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1368>; + }; + + usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <8>; + reg = <0x1368>; + }; + + usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&init_60m_fclk>; + ti,bit-shift = <9>; + reg = <0x1368>; + }; + + usb_tll_hs_ick: usb_tll_hs_ick { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l4_div_ck>; + ti,bit-shift = <0>; + reg = <0x1368>; + }; +}; + +&cm2_clockdomains { + l3_init_clkdm: l3_init_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>, <&usb_host_fs_fck>; + }; +}; + +&scrm_clocks { + auxclk0_src_gate_ck: auxclk0_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0310>; + }; + + auxclk0_src_mux_ck: auxclk0_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0310>; + }; + + auxclk0_src_ck: auxclk0_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>; + }; + + auxclk0_ck: auxclk0_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk0_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0310>; + }; + + auxclk1_src_gate_ck: auxclk1_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0314>; + }; + + auxclk1_src_mux_ck: auxclk1_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0314>; + }; + + auxclk1_src_ck: auxclk1_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>; + }; + + auxclk1_ck: auxclk1_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk1_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0314>; + }; + + auxclk2_src_gate_ck: auxclk2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0318>; + }; + + auxclk2_src_mux_ck: auxclk2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0318>; + }; + + auxclk2_src_ck: auxclk2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>; + }; + + auxclk2_ck: auxclk2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk2_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0318>; + }; + + auxclk3_src_gate_ck: auxclk3_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x031c>; + }; + + auxclk3_src_mux_ck: auxclk3_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x031c>; + }; + + auxclk3_src_ck: auxclk3_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>; + }; + + auxclk3_ck: auxclk3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk3_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x031c>; + }; + + auxclk4_src_gate_ck: auxclk4_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0320>; + }; + + auxclk4_src_mux_ck: auxclk4_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0320>; + }; + + auxclk4_src_ck: auxclk4_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>; + }; + + auxclk4_ck: auxclk4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk4_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0320>; + }; + + auxclk5_src_gate_ck: auxclk5_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0324>; + }; + + auxclk5_src_mux_ck: auxclk5_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0324>; + }; + + auxclk5_src_ck: auxclk5_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk5_src_gate_ck>, <&auxclk5_src_mux_ck>; + }; + + auxclk5_ck: auxclk5_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk5_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0324>; + }; + + auxclkreq0_ck: auxclkreq0_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0210>; + }; + + auxclkreq1_ck: auxclkreq1_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0214>; + }; + + auxclkreq2_ck: auxclkreq2_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0218>; + }; + + auxclkreq3_ck: auxclkreq3_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x021c>; + }; + + auxclkreq4_ck: auxclkreq4_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0220>; + }; + + auxclkreq5_ck: auxclkreq5_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>; + ti,bit-shift = <2>; + reg = <0x0224>; + }; +}; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index ab9a21ae82f3..a72813a9663e 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -117,6 +117,58 @@ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + prm: prm@4ae06000 { + compatible = "ti,omap5-prm"; + reg = <0x4ae06000 0x3000>; + + prm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + prm_clockdomains: clockdomains { + }; + }; + + cm_core_aon: cm_core_aon@4a004000 { + compatible = "ti,omap5-cm-core-aon"; + reg = <0x4a004000 0x2000>; + + cm_core_aon_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_aon_clockdomains: clockdomains { + }; + }; + + scrm: scrm@4ae0a000 { + compatible = "ti,omap5-scrm"; + reg = <0x4ae0a000 0x2000>; + + scrm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + scrm_clockdomains: clockdomains { + }; + }; + + cm_core: cm_core@4a008000 { + compatible = "ti,omap5-cm-core"; + reg = <0x4a008000 0x3000>; + + cm_core_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_core_clockdomains: clockdomains { + }; + }; + counter32k: counter@4ae04000 { compatible = "ti,omap-counter32k"; reg = <0x4ae04000 0x40>; @@ -751,3 +803,5 @@ }; }; }; + +/include/ "omap54xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap54xx-clocks.dtsi b/arch/arm/boot/dts/omap54xx-clocks.dtsi new file mode 100644 index 000000000000..d487fdab3921 --- /dev/null +++ b/arch/arm/boot/dts/omap54xx-clocks.dtsi @@ -0,0 +1,1399 @@ +/* + * Device Tree Source for OMAP5 clock data + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +&cm_core_aon_clocks { + pad_clks_src_ck: pad_clks_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + pad_clks_ck: pad_clks_ck { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&pad_clks_src_ck>; + ti,bit-shift = <8>; + reg = <0x0108>; + }; + + secure_32k_clk_src_ck: secure_32k_clk_src_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + slimbus_src_clk: slimbus_src_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + slimbus_clk: slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_src_clk>; + ti,bit-shift = <10>; + reg = <0x0108>; + }; + + sys_32k_ck: sys_32k_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + virt_12000000_ck: virt_12000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + virt_13000000_ck: virt_13000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <13000000>; + }; + + virt_16800000_ck: virt_16800000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16800000>; + }; + + virt_19200000_ck: virt_19200000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19200000>; + }; + + virt_26000000_ck: virt_26000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + virt_27000000_ck: virt_27000000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + virt_38400000_ck: virt_38400000_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <38400000>; + }; + + xclk60mhsp1_ck: xclk60mhsp1_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + xclk60mhsp2_ck: xclk60mhsp2_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <60000000>; + }; + + dpll_abe_ck: dpll_abe_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-m4xen-clock"; + clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>; + reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>; + }; + + dpll_abe_x2_ck: dpll_abe_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_abe_ck>; + }; + + dpll_abe_m2x2_ck: dpll_abe_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + abe_24m_fclk: abe_24m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <8>; + }; + + abe_clk: abe_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_m2x2_ck>; + ti,max-div = <4>; + reg = <0x0108>; + ti,index-power-of-two; + }; + + abe_iclk: abe_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&abe_clk>; + clock-mult = <1>; + clock-div = <2>; + }; + + abe_lp_clk_div: abe_lp_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + dpll_abe_m3x2_ck: dpll_abe_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_abe_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x01f4>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_ck: dpll_core_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>; + reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>; + }; + + dpll_core_x2_ck: dpll_core_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_core_ck>; + }; + + dpll_core_h21x2_ck: dpll_core_h21x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + c2c_fclk: c2c_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h21x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + c2c_iclk: c2c_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&c2c_fclk>; + clock-mult = <1>; + clock-div = <2>; + }; + + dpll_core_h11x2_ck: dpll_core_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0138>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h12x2_ck: dpll_core_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x013c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h13x2_ck: dpll_core_h13x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0140>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h14x2_ck: dpll_core_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0144>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h22x2_ck: dpll_core_h22x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h23x2_ck: dpll_core_h23x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_h24x2_ck: dpll_core_h24x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m2_ck: dpll_core_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0130>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_core_m3x2_ck: dpll_core_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0134>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + iva_dpll_hs_clk_div: iva_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_iva_ck: dpll_iva_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>; + reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>; + }; + + dpll_iva_x2_ck: dpll_iva_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_iva_ck>; + }; + + dpll_iva_h11x2_ck: dpll_iva_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x01b8>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_iva_h12x2_ck: dpll_iva_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_iva_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x01bc>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_mpu_ck: dpll_mpu_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&mpu_dpll_hs_clk_div>; + reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; + }; + + dpll_mpu_m2_ck: dpll_mpu_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_mpu_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0170>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + per_dpll_hs_clk_div: per_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + usb_dpll_hs_clk_div: usb_dpll_hs_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_abe_m3x2_ck>; + clock-mult = <1>; + clock-div = <3>; + }; + + l3_iclk_div: l3_iclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_core_h12x2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpu_l3_iclk: gpu_l3_iclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + l4_root_clk_div: l4_root_clk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&l3_iclk_div>; + clock-mult = <1>; + clock-div = <1>; + }; + + slimbus1_slimbus_clk: slimbus1_slimbus_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&slimbus_clk>; + ti,bit-shift = <11>; + reg = <0x0560>; + }; + + aess_fclk: aess_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x0528>; + }; + + dmic_sync_mux_ck: dmic_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0538>; + }; + + dmic_gfclk: dmic_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0538>; + }; + + mcasp_sync_mux_ck: mcasp_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0540>; + }; + + mcasp_gfclk: mcasp_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0540>; + }; + + mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0548>; + }; + + mcbsp1_gfclk: mcbsp1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0548>; + }; + + mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0550>; + }; + + mcbsp2_gfclk: mcbsp2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0550>; + }; + + mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; + ti,bit-shift = <26>; + reg = <0x0558>; + }; + + mcbsp3_gfclk: mcbsp3_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; + ti,bit-shift = <24>; + reg = <0x0558>; + }; + + timer5_gfclk_mux: timer5_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0568>; + }; + + timer6_gfclk_mux: timer6_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0570>; + }; + + timer7_gfclk_mux: timer7_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0578>; + }; + + timer8_gfclk_mux: timer8_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0580>; + }; + + dummy_ck: dummy_ck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; +&prm_clocks { + sys_clkin: sys_clkin { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; + }; + + abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + reg = <0x0108>; + }; + + abe_dpll_clk_mux: abe_dpll_clk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + reg = <0x010c>; + }; + + custefuse_sys_gfclk_div: custefuse_sys_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin>; + clock-mult = <1>; + clock-div = <2>; + }; + + dss_syc_gfclk_div: dss_syc_gfclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&sys_clkin>; + clock-mult = <1>; + clock-div = <1>; + }; + + wkupaon_iclk_mux: wkupaon_iclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&abe_lp_clk_div>; + reg = <0x0108>; + }; + + l3instr_ts_gclk_div: l3instr_ts_gclk_div { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&wkupaon_iclk_mux>; + clock-mult = <1>; + clock-div = <1>; + }; + + gpio1_dbclk: gpio1_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1938>; + }; + + timer1_gfclk_mux: timer1_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1940>; + }; +}; +&cm_core_clocks { + dpll_per_ck: dpll_per_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>; + reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>; + }; + + dpll_per_x2_ck: dpll_per_x2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-x2-clock"; + clocks = <&dpll_per_ck>; + }; + + dpll_per_h11x2_ck: dpll_per_h11x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0158>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h12x2_ck: dpll_per_h12x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x015c>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_h14x2_ck: dpll_per_h14x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <63>; + ti,autoidle-shift = <8>; + reg = <0x0164>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2_ck: dpll_per_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m2x2_ck: dpll_per_m2x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0150>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_per_m3x2_ck: dpll_per_m3x2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x0154>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_unipro1_ck: dpll_unipro1_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&sys_clkin>; + reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>; + }; + + dpll_unipro1_clkdcoldo: dpll_unipro1_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_unipro1_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_unipro1_m2_ck: dpll_unipro1_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_unipro1_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0210>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_unipro2_ck: dpll_unipro2_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-clock"; + clocks = <&sys_clkin>, <&sys_clkin>; + reg = <0x01c0>, <0x01c4>, <0x01cc>, <0x01c8>; + }; + + dpll_unipro2_clkdcoldo: dpll_unipro2_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_unipro2_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_unipro2_m2_ck: dpll_unipro2_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_unipro2_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x01d0>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_ck: dpll_usb_ck { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-j-type-clock"; + clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>; + reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>; + }; + + dpll_usb_clkdcoldo: dpll_usb_clkdcoldo { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + clock-mult = <1>; + clock-div = <1>; + }; + + dpll_usb_m2_ck: dpll_usb_m2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + ti,autoidle-shift = <8>; + reg = <0x0190>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + func_128m_clk: func_128m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_h11x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + func_12m_fclk: func_12m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <16>; + }; + + func_24m_clk: func_24m_clk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_48m_fclk: func_48m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <4>; + }; + + func_96m_fclk: func_96m_fclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_per_m2x2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + + l3init_60m_fclk: l3init_60m_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_m2_ck>; + reg = <0x0104>; + ti,dividers = <1>, <8>; + }; + + dss_32khz_clk: dss_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <11>; + reg = <0x1420>; + }; + + dss_48mhz_clk: dss_48mhz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_48m_fclk>; + ti,bit-shift = <9>; + reg = <0x1420>; + }; + + dss_dss_clk: dss_dss_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_per_h12x2_ck>; + ti,bit-shift = <8>; + reg = <0x1420>; + }; + + dss_sys_clk: dss_sys_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dss_syc_gfclk_div>; + ti,bit-shift = <10>; + reg = <0x1420>; + }; + + gpio2_dbclk: gpio2_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1060>; + }; + + gpio3_dbclk: gpio3_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1068>; + }; + + gpio4_dbclk: gpio4_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1070>; + }; + + gpio5_dbclk: gpio5_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1078>; + }; + + gpio6_dbclk: gpio6_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1080>; + }; + + gpio7_dbclk: gpio7_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1110>; + }; + + gpio8_dbclk: gpio8_dbclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1118>; + }; + + iss_ctrlclk: iss_ctrlclk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&func_96m_fclk>; + ti,bit-shift = <8>; + reg = <0x1320>; + }; + + lli_txphy_clk: lli_txphy_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_unipro1_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x0f20>; + }; + + lli_txphy_ls_clk: lli_txphy_ls_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_unipro1_m2_ck>; + ti,bit-shift = <9>; + reg = <0x0f20>; + }; + + mmc1_32khz_clk: mmc1_32khz_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x1628>; + }; + + sata_ref_clk: sata_ref_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_clkin>; + ti,bit-shift = <8>; + reg = <0x1688>; + }; + + usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <13>; + reg = <0x1658>; + }; + + usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <14>; + reg = <0x1658>; + }; + + usb_host_hs_hsic480m_p3_clk: usb_host_hs_hsic480m_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_m2_ck>; + ti,bit-shift = <7>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <11>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <12>; + reg = <0x1658>; + }; + + usb_host_hs_hsic60m_p3_clk: usb_host_hs_hsic60m_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <6>; + reg = <0x1658>; + }; + + utmi_p1_gfclk: utmi_p1_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3init_60m_fclk>, <&xclk60mhsp1_ck>; + ti,bit-shift = <24>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p1_gfclk>; + ti,bit-shift = <8>; + reg = <0x1658>; + }; + + utmi_p2_gfclk: utmi_p2_gfclk { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&l3init_60m_fclk>, <&xclk60mhsp2_ck>; + ti,bit-shift = <25>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&utmi_p2_gfclk>; + ti,bit-shift = <9>; + reg = <0x1658>; + }; + + usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1658>; + }; + + usb_otg_ss_refclk960m: usb_otg_ss_refclk960m { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&dpll_usb_clkdcoldo>; + ti,bit-shift = <8>; + reg = <0x16f0>; + }; + + usb_phy_cm_clk32k: usb_phy_cm_clk32k { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&sys_32k_ck>; + ti,bit-shift = <8>; + reg = <0x0640>; + }; + + usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <8>; + reg = <0x1668>; + }; + + usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <9>; + reg = <0x1668>; + }; + + usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&l3init_60m_fclk>; + ti,bit-shift = <10>; + reg = <0x1668>; + }; + + fdif_fclk: fdif_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_h11x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x1328>; + }; + + gpu_core_gclk_mux: gpu_core_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>; + ti,bit-shift = <24>; + reg = <0x1520>; + }; + + gpu_hyd_gclk_mux: gpu_hyd_gclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>; + ti,bit-shift = <25>; + reg = <0x1520>; + }; + + hsi_fclk: hsi_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + ti,max-div = <2>; + reg = <0x1638>; + }; + + mmc1_fclk_mux: mmc1_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1628>; + }; + + mmc1_fclk: mmc1_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc1_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <2>; + reg = <0x1628>; + }; + + mmc2_fclk_mux: mmc2_fclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; + ti,bit-shift = <24>; + reg = <0x1630>; + }; + + mmc2_fclk: mmc2_fclk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&mmc2_fclk_mux>; + ti,bit-shift = <25>; + ti,max-div = <2>; + reg = <0x1630>; + }; + + timer10_gfclk_mux: timer10_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1028>; + }; + + timer11_gfclk_mux: timer11_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1030>; + }; + + timer2_gfclk_mux: timer2_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1038>; + }; + + timer3_gfclk_mux: timer3_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1040>; + }; + + timer4_gfclk_mux: timer4_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1048>; + }; + + timer9_gfclk_mux: timer9_gfclk_mux { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x1050>; + }; +}; + +&cm_core_clockdomains { + l3init_clkdm: l3init_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dpll_usb_ck>; + }; +}; + +&scrm_clocks { + auxclk0_src_gate_ck: auxclk0_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0310>; + }; + + auxclk0_src_mux_ck: auxclk0_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0310>; + }; + + auxclk0_src_ck: auxclk0_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>; + }; + + auxclk0_ck: auxclk0_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk0_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0310>; + }; + + auxclk1_src_gate_ck: auxclk1_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0314>; + }; + + auxclk1_src_mux_ck: auxclk1_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0314>; + }; + + auxclk1_src_ck: auxclk1_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>; + }; + + auxclk1_ck: auxclk1_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk1_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0314>; + }; + + auxclk2_src_gate_ck: auxclk2_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0318>; + }; + + auxclk2_src_mux_ck: auxclk2_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0318>; + }; + + auxclk2_src_ck: auxclk2_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>; + }; + + auxclk2_ck: auxclk2_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk2_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0318>; + }; + + auxclk3_src_gate_ck: auxclk3_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x031c>; + }; + + auxclk3_src_mux_ck: auxclk3_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x031c>; + }; + + auxclk3_src_ck: auxclk3_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>; + }; + + auxclk3_ck: auxclk3_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk3_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x031c>; + }; + + auxclk4_src_gate_ck: auxclk4_src_gate_ck { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&dpll_core_m3x2_ck>; + ti,bit-shift = <8>; + reg = <0x0320>; + }; + + auxclk4_src_mux_ck: auxclk4_src_mux_ck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>; + ti,bit-shift = <1>; + reg = <0x0320>; + }; + + auxclk4_src_ck: auxclk4_src_ck { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>; + }; + + auxclk4_ck: auxclk4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&auxclk4_src_ck>; + ti,bit-shift = <16>; + ti,max-div = <16>; + reg = <0x0320>; + }; + + auxclkreq0_ck: auxclkreq0_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0210>; + }; + + auxclkreq1_ck: auxclkreq1_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0214>; + }; + + auxclkreq2_ck: auxclkreq2_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x0218>; + }; + + auxclkreq3_ck: auxclkreq3_ck { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>; + ti,bit-shift = <2>; + reg = <0x021c>; + }; +}; diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1e8b030dbefd..b0df9761de6d 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -731,7 +731,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc) kernel_data.end = virt_to_phys(_end - 1); for_each_memblock(memory, region) { - res = memblock_virt_alloc(sizeof(*res), 0); + res = memblock_virt_alloc_low(sizeof(*res), 0); res->name = "System RAM"; res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index 6f424eced181..b3738e616f19 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -236,32 +236,26 @@ static struct mc13xxx_led_platform_data moboard_led[] = { { .id = MC13783_LED_R1, .name = "coreboard-led-4:red", - .max_current = 2, }, { .id = MC13783_LED_G1, .name = "coreboard-led-4:green", - .max_current = 2, }, { .id = MC13783_LED_B1, .name = "coreboard-led-4:blue", - .max_current = 2, }, { .id = MC13783_LED_R2, .name = "coreboard-led-5:red", - .max_current = 3, }, { .id = MC13783_LED_G2, .name = "coreboard-led-5:green", - .max_current = 3, }, { .id = MC13783_LED_B2, .name = "coreboard-led-5:blue", - .max_current = 3, }, }; @@ -271,8 +265,14 @@ static struct mc13xxx_leds_platform_data moboard_leds = { .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0), .led_control[1] = MC13783_LED_C1_SLEWLIM, .led_control[2] = MC13783_LED_C2_SLEWLIM, - .led_control[3] = MC13783_LED_C3_PERIOD(0), - .led_control[4] = MC13783_LED_C3_PERIOD(0), + .led_control[3] = MC13783_LED_C3_PERIOD(0) | + MC13783_LED_C3_CURRENT_R1(2) | + MC13783_LED_C3_CURRENT_G1(2) | + MC13783_LED_C3_CURRENT_B1(2), + .led_control[4] = MC13783_LED_C4_PERIOD(0) | + MC13783_LED_C4_CURRENT_R2(3) | + MC13783_LED_C4_CURRENT_G2(3) | + MC13783_LED_C4_CURRENT_B2(3), }; static struct mc13xxx_buttons_platform_data moboard_buttons = { diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 4191ae08f4c8..653b489479e0 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -76,6 +76,16 @@ config SOC_AM43XX select ARM_GIC select MACH_OMAP_GENERIC +config SOC_DRA7XX + bool "TI DRA7XX" + depends on ARCH_MULTI_V7 + select ARCH_OMAP2PLUS + select ARM_CPU_SUSPEND if PM + select ARM_GIC + select CPU_V7 + select HAVE_SMP + select HAVE_ARM_ARCH_TIMER + config ARCH_OMAP2PLUS bool select ARCH_HAS_BANDGAP @@ -128,14 +138,6 @@ config SOC_HAS_REALTIME_COUNTER depends on SOC_OMAP5 || SOC_DRA7XX default y -config SOC_DRA7XX - bool "TI DRA7XX" - select ARM_ARCH_TIMER - select CPU_V7 - select ARM_GIC - select HAVE_SMP - select COMMON_CLK - comment "OMAP Core Type" depends on ARCH_OMAP2 diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index f78b177e8f4f..e6eec6f72fd3 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SOC_AM33XX) += $(voltagedomain-common) obj-$(CONFIG_SOC_AM43XX) += $(voltagedomain-common) obj-$(CONFIG_SOC_OMAP5) += $(voltagedomain-common) obj-$(CONFIG_SOC_OMAP5) += voltagedomains54xx_data.o +obj-$(CONFIG_SOC_DRA7XX) += $(voltagedomain-common) # OMAP powerdomain framework powerdomain-common += powerdomain.o powerdomain-common.o @@ -184,12 +185,14 @@ obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o cclock3xxx_data.o obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o -obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) cclock44xx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o -obj-$(CONFIG_SOC_AM33XX) += cclock33xx_data.o obj-$(CONFIG_SOC_OMAP5) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) +obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o diff --git a/arch/arm/mach-omap2/cclock33xx_data.c b/arch/arm/mach-omap2/cclock33xx_data.c deleted file mode 100644 index 865d30ee812f..000000000000 --- a/arch/arm/mach-omap2/cclock33xx_data.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * AM33XX Clock data - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Vaibhav Hiremath <hvaibhav@ti.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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/clk-private.h> -#include <linux/clkdev.h> -#include <linux/io.h> - -#include "am33xx.h" -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "control.h" -#include "cm.h" -#include "cm33xx.h" -#include "cm-regbits-33xx.h" -#include "prm.h" - -/* Modulemode control */ -#define AM33XX_MODULEMODE_HWCTRL_SHIFT 0 -#define AM33XX_MODULEMODE_SWCTRL_SHIFT 1 - -/*LIST_HEAD(clocks);*/ - -/* Root clocks */ - -/* RTC 32k */ -DEFINE_CLK_FIXED_RATE(clk_32768_ck, CLK_IS_ROOT, 32768, 0x0); - -/* On-Chip 32KHz RC OSC */ -DEFINE_CLK_FIXED_RATE(clk_rc32k_ck, CLK_IS_ROOT, 32000, 0x0); - -/* Crystal input clks */ -DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_24000000_ck, CLK_IS_ROOT, 24000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_25000000_ck, CLK_IS_ROOT, 25000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0); - -/* Oscillator clock */ -/* 19.2, 24, 25 or 26 MHz */ -static const char *sys_clkin_ck_parents[] = { - "virt_19200000_ck", "virt_24000000_ck", "virt_25000000_ck", - "virt_26000000_ck", -}; - -/* - * sys_clk in: input to the dpll and also used as funtional clock for, - * adc_tsc, smartreflex0-1, timer1-7, mcasp0-1, dcan0-1, cefuse - * - */ -DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0, - AM33XX_CTRL_REGADDR(AM33XX_CONTROL_STATUS), - AM33XX_CONTROL_STATUS_SYSBOOT1_SHIFT, - AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH, - 0, NULL); - -/* External clock - 12 MHz */ -DEFINE_CLK_FIXED_RATE(tclkin_ck, CLK_IS_ROOT, 12000000, 0x0); - -/* Module clocks and DPLL outputs */ - -/* DPLL_CORE */ -static struct dpll_data dpll_core_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_CORE, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_CORE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_CORE, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKDCOLDO output */ -static const char *dpll_core_ck_parents[] = { - "sys_clkin_ck", -}; - -static struct clk dpll_core_ck; - -static const struct clk_ops dpll_core_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_core_ck_hw = { - .hw = { - .clk = &dpll_core_ck, - }, - .dpll_data = &dpll_core_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops); - -static const char *dpll_core_x2_ck_parents[] = { - "dpll_core_ck", -}; - -static struct clk dpll_core_x2_ck; - -static const struct clk_ops dpll_x2_ck_ops = { - .recalc_rate = &omap3_clkoutx2_recalc, -}; - -static struct clk_hw_omap dpll_core_x2_ck_hw = { - .hw = { - .clk = &dpll_core_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, -}; - -DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_x2_ck_ops); - -DEFINE_CLK_DIVIDER(dpll_core_m4_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M4_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT1_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT1_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, - NULL); - -DEFINE_CLK_DIVIDER(dpll_core_m5_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M5_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT2_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT2_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -DEFINE_CLK_DIVIDER(dpll_core_m6_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, - 0x0, AM33XX_CM_DIV_M6_DPLL_CORE, - AM33XX_HSDIVIDER_CLKOUT3_DIV_SHIFT, - AM33XX_HSDIVIDER_CLKOUT3_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - - -/* DPLL_MPU */ -static struct dpll_data dpll_mpu_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_MPU, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_MPU, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_MPU, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_mpu_ck; - -static const struct clk_ops dpll_mpu_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_mpu_ck_hw = { - .hw = { - .clk = &dpll_mpu_ck, - }, - .dpll_data = &dpll_mpu_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_core_ck_parents, dpll_mpu_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck, - 0x0, AM33XX_CM_DIV_M2_DPLL_MPU, AM33XX_DPLL_CLKOUT_DIV_SHIFT, - AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -/* DPLL_DDR */ -static struct dpll_data dpll_ddr_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_DDR, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_DDR, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_DDR, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_ddr_ck; - -static const struct clk_ops dpll_ddr_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, -}; - -static struct clk_hw_omap dpll_ddr_ck_hw = { - .hw = { - .clk = &dpll_ddr_ck, - }, - .dpll_data = &dpll_ddr_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_ddr_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_ddr_m2_ck, "dpll_ddr_ck", &dpll_ddr_ck, - 0x0, AM33XX_CM_DIV_M2_DPLL_DDR, - AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -/* emif_fck functional clock */ -DEFINE_CLK_FIXED_FACTOR(dpll_ddr_m2_div2_ck, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck, - 0x0, 1, 2); - -/* DPLL_DISP */ -static struct dpll_data dpll_disp_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_DISP, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_DISP, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_DISP, - .mult_mask = AM33XX_DPLL_MULT_MASK, - .div1_mask = AM33XX_DPLL_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -/* CLKOUT: fdpll/M2 */ -static struct clk dpll_disp_ck; - -static struct clk_hw_omap dpll_disp_ck_hw = { - .hw = { - .clk = &dpll_disp_ck, - }, - .dpll_data = &dpll_disp_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_disp_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* - * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2 - * and ALT_CLK1/2) - */ -DEFINE_CLK_DIVIDER(dpll_disp_m2_ck, "dpll_disp_ck", &dpll_disp_ck, - CLK_SET_RATE_PARENT, AM33XX_CM_DIV_M2_DPLL_DISP, - AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH, - CLK_DIVIDER_ONE_BASED, NULL); - -/* DPLL_PER */ -static struct dpll_data dpll_per_dd = { - .mult_div1_reg = AM33XX_CM_CLKSEL_DPLL_PERIPH, - .clk_bypass = &sys_clkin_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = AM33XX_CM_CLKMODE_DPLL_PER, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .idlest_reg = AM33XX_CM_IDLEST_DPLL_PER, - .mult_mask = AM33XX_DPLL_MULT_PERIPH_MASK, - .div1_mask = AM33XX_DPLL_PER_DIV_MASK, - .enable_mask = AM33XX_DPLL_EN_MASK, - .idlest_mask = AM33XX_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, - .flags = DPLL_J_TYPE, -}; - -/* CLKDCOLDO */ -static struct clk dpll_per_ck; - -static struct clk_hw_omap dpll_per_ck_hw = { - .hw = { - .clk = &dpll_per_ck, - }, - .dpll_data = &dpll_per_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_per_ck, dpll_core_ck_parents, dpll_ddr_ck_ops); - -/* CLKOUT: fdpll/M2 */ -DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0, - AM33XX_CM_DIV_M2_DPLL_PER, AM33XX_DPLL_CLKOUT_DIV_SHIFT, - AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, - NULL); - -DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_wkupdm_ck, "dpll_per_m2_ck", - &dpll_per_m2_ck, 0x0, 1, 4); - -DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_ck, "dpll_per_m2_ck", - &dpll_per_m2_ck, 0x0, 1, 4); - -DEFINE_CLK_FIXED_FACTOR(dpll_core_m4_div2_ck, "dpll_core_m4_ck", - &dpll_core_m4_ck, 0x0, 1, 2); - -DEFINE_CLK_FIXED_FACTOR(l4_rtc_gclk, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0, - 1, 2); - -DEFINE_CLK_FIXED_FACTOR(clk_24mhz, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1, - 8); - -/* - * Below clock nodes describes clockdomains derived out - * of core clock. - */ -static const struct clk_ops clk_ops_null = { -}; - -static const char *l3_gclk_parents[] = { - "dpll_core_m4_ck" -}; - -static struct clk l3_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l3_gclk, NULL); -DEFINE_STRUCT_CLK(l3_gclk, l3_gclk_parents, clk_ops_null); - -static struct clk l4hs_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4hs_gclk, NULL); -DEFINE_STRUCT_CLK(l4hs_gclk, l3_gclk_parents, clk_ops_null); - -static const char *l3s_gclk_parents[] = { - "dpll_core_m4_div2_ck" -}; - -static struct clk l3s_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l3s_gclk, NULL); -DEFINE_STRUCT_CLK(l3s_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk l4fw_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4fw_gclk, NULL); -DEFINE_STRUCT_CLK(l4fw_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk l4ls_gclk; -DEFINE_STRUCT_CLK_HW_OMAP(l4ls_gclk, NULL); -DEFINE_STRUCT_CLK(l4ls_gclk, l3s_gclk_parents, clk_ops_null); - -static struct clk sysclk_div_ck; -DEFINE_STRUCT_CLK_HW_OMAP(sysclk_div_ck, NULL); -DEFINE_STRUCT_CLK(sysclk_div_ck, l3_gclk_parents, clk_ops_null); - -/* - * In order to match the clock domain with hwmod clockdomain entry, - * separate clock nodes is required for the modules which are - * directly getting their funtioncal clock from sys_clkin. - */ -static struct clk adc_tsc_fck; -DEFINE_STRUCT_CLK_HW_OMAP(adc_tsc_fck, NULL); -DEFINE_STRUCT_CLK(adc_tsc_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk dcan0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(dcan0_fck, NULL); -DEFINE_STRUCT_CLK(dcan0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk dcan1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(dcan1_fck, NULL); -DEFINE_STRUCT_CLK(dcan1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk mcasp0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(mcasp0_fck, NULL); -DEFINE_STRUCT_CLK(mcasp0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk mcasp1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(mcasp1_fck, NULL); -DEFINE_STRUCT_CLK(mcasp1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk smartreflex0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(smartreflex0_fck, NULL); -DEFINE_STRUCT_CLK(smartreflex0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk smartreflex1_fck; -DEFINE_STRUCT_CLK_HW_OMAP(smartreflex1_fck, NULL); -DEFINE_STRUCT_CLK(smartreflex1_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk sha0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(sha0_fck, NULL); -DEFINE_STRUCT_CLK(sha0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk aes0_fck; -DEFINE_STRUCT_CLK_HW_OMAP(aes0_fck, NULL); -DEFINE_STRUCT_CLK(aes0_fck, dpll_core_ck_parents, clk_ops_null); - -static struct clk rng_fck; -DEFINE_STRUCT_CLK_HW_OMAP(rng_fck, NULL); -DEFINE_STRUCT_CLK(rng_fck, dpll_core_ck_parents, clk_ops_null); - -/* - * Modules clock nodes - * - * The following clock leaf nodes are added for the moment because: - * - * - hwmod data is not present for these modules, either hwmod - * control is not required or its not populated. - * - Driver code is not yet migrated to use hwmod/runtime pm - * - Modules outside kernel access (to disable them by default) - * - * - mmu (gfx domain) - * - cefuse - * - usbotg_fck (its additional clock and not really a modulemode) - * - ieee5000 - */ - -DEFINE_CLK_GATE(mmu_fck, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0, - AM33XX_CM_GFX_MMUDATA_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(cefuse_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0, - AM33XX_CM_CEFUSE_CEFUSE_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -/* - * clkdiv32 is generated from fixed division of 732.4219 - */ -DEFINE_CLK_FIXED_FACTOR(clkdiv32k_ck, "clk_24mhz", &clk_24mhz, 0x0, 1, 732); - -static struct clk clkdiv32k_ick; - -static const char *clkdiv32k_ick_parent_names[] = { - "clkdiv32k_ck", -}; - -static const struct clk_ops clkdiv32k_ick_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap clkdiv32k_ick_hw = { - .hw = { - .clk = &clkdiv32k_ick, - }, - .enable_reg = AM33XX_CM_PER_CLKDIV32K_CLKCTRL, - .enable_bit = AM33XX_MODULEMODE_SWCTRL_SHIFT, - .clkdm_name = "clk_24mhz_clkdm", -}; - -DEFINE_STRUCT_CLK(clkdiv32k_ick, clkdiv32k_ick_parent_names, clkdiv32k_ick_ops); - -/* "usbotg_fck" is an additional clock and not really a modulemode */ -DEFINE_CLK_GATE(usbotg_fck, "dpll_per_ck", &dpll_per_ck, 0x0, - AM33XX_CM_CLKDCOLDO_DPLL_PER, AM33XX_ST_DPLL_CLKDCOLDO_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(ieee5000_fck, "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck, - 0x0, AM33XX_CM_PER_IEEE5000_CLKCTRL, - AM33XX_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -/* Timers */ -static const struct clksel timer1_clkmux_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_1_rates }, - { .parent = &tclkin_ck, .rates = div_1_2_rates }, - { .parent = &clk_rc32k_ck, .rates = div_1_3_rates }, - { .parent = &clk_32768_ck, .rates = div_1_4_rates }, - { .parent = NULL }, -}; - -static const char *timer1_ck_parents[] = { - "sys_clkin_ck", "clkdiv32k_ick", "tclkin_ck", "clk_rc32k_ck", - "clk_32768_ck", -}; - -static struct clk timer1_fck; - -static const struct clk_ops timer1_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap timer1_fck_hw = { - .hw = { - .clk = &timer1_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer1_clkmux_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER1MS_CLK, - .clksel_mask = AM33XX_CLKSEL_0_2_MASK, -}; - -DEFINE_STRUCT_CLK(timer1_fck, timer1_ck_parents, timer1_fck_ops); - -static const struct clksel timer2_to_7_clk_sel[] = { - { .parent = &tclkin_ck, .rates = div_1_0_rates }, - { .parent = &sys_clkin_ck, .rates = div_1_1_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *timer2_to_7_ck_parents[] = { - "tclkin_ck", "sys_clkin_ck", "clkdiv32k_ick", -}; - -static struct clk timer2_fck; - -static struct clk_hw_omap timer2_fck_hw = { - .hw = { - .clk = &timer2_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER2_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer2_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer3_fck; - -static struct clk_hw_omap timer3_fck_hw = { - .hw = { - .clk = &timer3_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER3_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer3_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer4_fck; - -static struct clk_hw_omap timer4_fck_hw = { - .hw = { - .clk = &timer4_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER4_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer4_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer5_fck; - -static struct clk_hw_omap timer5_fck_hw = { - .hw = { - .clk = &timer5_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER5_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer5_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer6_fck; - -static struct clk_hw_omap timer6_fck_hw = { - .hw = { - .clk = &timer6_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER6_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer6_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -static struct clk timer7_fck; - -static struct clk_hw_omap timer7_fck_hw = { - .hw = { - .clk = &timer7_fck, - }, - .clkdm_name = "l4ls_clkdm", - .clksel = timer2_to_7_clk_sel, - .clksel_reg = AM33XX_CLKSEL_TIMER7_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(timer7_fck, timer2_to_7_ck_parents, timer1_fck_ops); - -DEFINE_CLK_FIXED_FACTOR(cpsw_125mhz_gclk, - "dpll_core_m5_ck", - &dpll_core_m5_ck, - 0x0, - 1, 2); - -static const struct clk_ops cpsw_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, -}; - -static const struct clksel cpsw_cpts_rft_clkmux_sel[] = { - { .parent = &dpll_core_m5_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m4_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *cpsw_cpts_rft_ck_parents[] = { - "dpll_core_m5_ck", "dpll_core_m4_ck", -}; - -static struct clk cpsw_cpts_rft_clk; - -static struct clk_hw_omap cpsw_cpts_rft_clk_hw = { - .hw = { - .clk = &cpsw_cpts_rft_clk, - }, - .clkdm_name = "cpsw_125mhz_clkdm", - .clksel = cpsw_cpts_rft_clkmux_sel, - .clksel_reg = AM33XX_CM_CPTS_RFT_CLKSEL, - .clksel_mask = AM33XX_CLKSEL_0_0_MASK, -}; - -DEFINE_STRUCT_CLK(cpsw_cpts_rft_clk, cpsw_cpts_rft_ck_parents, cpsw_fck_ops); - - -/* gpio */ -static const char *gpio0_ck_parents[] = { - "clk_rc32k_ck", "clk_32768_ck", "clkdiv32k_ick", -}; - -static const struct clksel gpio0_dbclk_mux_sel[] = { - { .parent = &clk_rc32k_ck, .rates = div_1_0_rates }, - { .parent = &clk_32768_ck, .rates = div_1_1_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const struct clk_ops gpio_fck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk gpio0_dbclk_mux_ck; - -static struct clk_hw_omap gpio0_dbclk_mux_ck_hw = { - .hw = { - .clk = &gpio0_dbclk_mux_ck, - }, - .clkdm_name = "l4_wkup_clkdm", - .clksel = gpio0_dbclk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_GPIO0_DBCLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(gpio0_dbclk_mux_ck, gpio0_ck_parents, gpio_fck_ops); - -DEFINE_CLK_GATE(gpio0_dbclk, "gpio0_dbclk_mux_ck", &gpio0_dbclk_mux_ck, 0x0, - AM33XX_CM_WKUP_GPIO0_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO0_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio1_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO1_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_1_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio2_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO2_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_2_GDBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio3_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0, - AM33XX_CM_PER_GPIO3_CLKCTRL, - AM33XX_OPTFCLKEN_GPIO_3_GDBCLK_SHIFT, 0x0, NULL); - - -static const char *pruss_ck_parents[] = { - "l3_gclk", "dpll_disp_m2_ck", -}; - -static const struct clksel pruss_ocp_clk_mux_sel[] = { - { .parent = &l3_gclk, .rates = div_1_0_rates }, - { .parent = &dpll_disp_m2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk pruss_ocp_gclk; - -static struct clk_hw_omap pruss_ocp_gclk_hw = { - .hw = { - .clk = &pruss_ocp_gclk, - }, - .clkdm_name = "pruss_ocp_clkdm", - .clksel = pruss_ocp_clk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_PRUSS_OCP_CLK, - .clksel_mask = AM33XX_CLKSEL_0_0_MASK, -}; - -DEFINE_STRUCT_CLK(pruss_ocp_gclk, pruss_ck_parents, gpio_fck_ops); - -static const char *lcd_ck_parents[] = { - "dpll_disp_m2_ck", "dpll_core_m5_ck", "dpll_per_m2_ck", -}; - -static const struct clksel lcd_clk_mux_sel[] = { - { .parent = &dpll_disp_m2_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m5_ck, .rates = div_1_1_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static struct clk lcd_gclk; - -static struct clk_hw_omap lcd_gclk_hw = { - .hw = { - .clk = &lcd_gclk, - }, - .clkdm_name = "lcdc_clkdm", - .clksel = lcd_clk_mux_sel, - .clksel_reg = AM33XX_CLKSEL_LCDC_PIXEL_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK_FLAGS(lcd_gclk, lcd_ck_parents, - gpio_fck_ops, CLK_SET_RATE_PARENT); - -DEFINE_CLK_FIXED_FACTOR(mmc_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1, 2); - -static const char *gfx_ck_parents[] = { - "dpll_core_m4_ck", "dpll_per_m2_ck", -}; - -static const struct clksel gfx_clksel_sel[] = { - { .parent = &dpll_core_m4_ck, .rates = div_1_0_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk gfx_fclk_clksel_ck; - -static struct clk_hw_omap gfx_fclk_clksel_ck_hw = { - .hw = { - .clk = &gfx_fclk_clksel_ck, - }, - .clksel = gfx_clksel_sel, - .clksel_reg = AM33XX_CLKSEL_GFX_FCLK, - .clksel_mask = AM33XX_CLKSEL_GFX_FCLK_MASK, -}; - -DEFINE_STRUCT_CLK(gfx_fclk_clksel_ck, gfx_ck_parents, gpio_fck_ops); - -static const struct clk_div_table div_1_0_2_1_rates[] = { - { .div = 1, .val = 0, }, - { .div = 2, .val = 1, }, - { .div = 0 }, -}; - -DEFINE_CLK_DIVIDER_TABLE(gfx_fck_div_ck, "gfx_fclk_clksel_ck", - &gfx_fclk_clksel_ck, 0x0, AM33XX_CLKSEL_GFX_FCLK, - AM33XX_CLKSEL_0_0_SHIFT, AM33XX_CLKSEL_0_0_WIDTH, - 0x0, div_1_0_2_1_rates, NULL); - -static const char *sysclkout_ck_parents[] = { - "clk_32768_ck", "l3_gclk", "dpll_ddr_m2_ck", "dpll_per_m2_ck", - "lcd_gclk", -}; - -static const struct clksel sysclkout_pre_sel[] = { - { .parent = &clk_32768_ck, .rates = div_1_0_rates }, - { .parent = &l3_gclk, .rates = div_1_1_rates }, - { .parent = &dpll_ddr_m2_ck, .rates = div_1_2_rates }, - { .parent = &dpll_per_m2_ck, .rates = div_1_3_rates }, - { .parent = &lcd_gclk, .rates = div_1_4_rates }, - { .parent = NULL }, -}; - -static struct clk sysclkout_pre_ck; - -static struct clk_hw_omap sysclkout_pre_ck_hw = { - .hw = { - .clk = &sysclkout_pre_ck, - }, - .clksel = sysclkout_pre_sel, - .clksel_reg = AM33XX_CM_CLKOUT_CTRL, - .clksel_mask = AM33XX_CLKOUT2SOURCE_MASK, -}; - -DEFINE_STRUCT_CLK(sysclkout_pre_ck, sysclkout_ck_parents, gpio_fck_ops); - -/* Divide by 8 clock rates with default clock is 1/1*/ -static const struct clk_div_table div8_rates[] = { - { .div = 1, .val = 0, }, - { .div = 2, .val = 1, }, - { .div = 3, .val = 2, }, - { .div = 4, .val = 3, }, - { .div = 5, .val = 4, }, - { .div = 6, .val = 5, }, - { .div = 7, .val = 6, }, - { .div = 8, .val = 7, }, - { .div = 0 }, -}; - -DEFINE_CLK_DIVIDER_TABLE(clkout2_div_ck, "sysclkout_pre_ck", &sysclkout_pre_ck, - 0x0, AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2DIV_SHIFT, - AM33XX_CLKOUT2DIV_WIDTH, 0x0, div8_rates, NULL); - -DEFINE_CLK_GATE(clkout2_ck, "clkout2_div_ck", &clkout2_div_ck, 0x0, - AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2EN_SHIFT, 0x0, NULL); - -static const char *wdt_ck_parents[] = { - "clk_rc32k_ck", "clkdiv32k_ick", -}; - -static const struct clksel wdt_clkmux_sel[] = { - { .parent = &clk_rc32k_ck, .rates = div_1_0_rates }, - { .parent = &clkdiv32k_ick, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static struct clk wdt1_fck; - -static struct clk_hw_omap wdt1_fck_hw = { - .hw = { - .clk = &wdt1_fck, - }, - .clkdm_name = "l4_wkup_clkdm", - .clksel = wdt_clkmux_sel, - .clksel_reg = AM33XX_CLKSEL_WDT1_CLK, - .clksel_mask = AM33XX_CLKSEL_0_1_MASK, -}; - -DEFINE_STRUCT_CLK(wdt1_fck, wdt_ck_parents, gpio_fck_ops); - -static const char *pwmss_clk_parents[] = { - "dpll_per_m2_ck", -}; - -static const struct clk_ops ehrpwm_tbclk_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, -}; - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm0_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS0_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm1_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS1_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -DEFINE_CLK_OMAP_MUX_GATE(ehrpwm2_tbclk, "l4ls_clkdm", - NULL, NULL, 0, - AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL), - AM33XX_PWMSS2_TBCLKEN_SHIFT, - NULL, pwmss_clk_parents, ehrpwm_tbclk_ops); - -/* - * debugss optional clocks - */ -DEFINE_CLK_GATE(dbg_sysclk_ck, "sys_clkin_ck", &sys_clkin_ck, - 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_OPTFCLKEN_DBGSYSCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dbg_clka_ck, "dpll_core_m4_ck", &dpll_core_m4_ck, - 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_OPTCLK_DEBUG_CLKA_SHIFT, 0x0, NULL); - -static const char *stm_pmd_clock_mux_ck_parents[] = { - "dbg_sysclk_ck", "dbg_clka_ck", -}; - -DEFINE_CLK_MUX(stm_pmd_clock_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0, - AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, AM33XX_STM_PMD_CLKSEL_SHIFT, - AM33XX_STM_PMD_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(trace_pmd_clk_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0, - AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_TRC_PMD_CLKSEL_SHIFT, - AM33XX_TRC_PMD_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(stm_clk_div_ck, "stm_pmd_clock_mux_ck", - &stm_pmd_clock_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_STM_PMD_CLKDIVSEL_SHIFT, - AM33XX_STM_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -DEFINE_CLK_DIVIDER(trace_clk_div_ck, "trace_pmd_clk_mux_ck", - &trace_pmd_clk_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, - AM33XX_TRC_PMD_CLKDIVSEL_SHIFT, - AM33XX_TRC_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -/* - * clkdev - */ -static struct omap_clk am33xx_clks[] = { - CLK(NULL, "clk_32768_ck", &clk_32768_ck), - CLK(NULL, "clk_rc32k_ck", &clk_rc32k_ck), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck), - CLK(NULL, "virt_24000000_ck", &virt_24000000_ck), - CLK(NULL, "virt_25000000_ck", &virt_25000000_ck), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck), - CLK(NULL, "sys_clkin_ck", &sys_clkin_ck), - CLK(NULL, "tclkin_ck", &tclkin_ck), - CLK(NULL, "dpll_core_ck", &dpll_core_ck), - CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck), - CLK(NULL, "dpll_core_m4_ck", &dpll_core_m4_ck), - CLK(NULL, "dpll_core_m5_ck", &dpll_core_m5_ck), - CLK(NULL, "dpll_core_m6_ck", &dpll_core_m6_ck), - CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck), - CLK("cpu0", NULL, &dpll_mpu_ck), - CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck), - CLK(NULL, "dpll_ddr_ck", &dpll_ddr_ck), - CLK(NULL, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck), - CLK(NULL, "dpll_ddr_m2_div2_ck", &dpll_ddr_m2_div2_ck), - CLK(NULL, "dpll_disp_ck", &dpll_disp_ck), - CLK(NULL, "dpll_disp_m2_ck", &dpll_disp_m2_ck), - CLK(NULL, "dpll_per_ck", &dpll_per_ck), - CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck), - CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", &dpll_per_m2_div4_wkupdm_ck), - CLK(NULL, "dpll_per_m2_div4_ck", &dpll_per_m2_div4_ck), - CLK(NULL, "adc_tsc_fck", &adc_tsc_fck), - CLK(NULL, "cefuse_fck", &cefuse_fck), - CLK(NULL, "clkdiv32k_ck", &clkdiv32k_ck), - CLK(NULL, "clkdiv32k_ick", &clkdiv32k_ick), - CLK(NULL, "dcan0_fck", &dcan0_fck), - CLK("481cc000.d_can", NULL, &dcan0_fck), - CLK(NULL, "dcan1_fck", &dcan1_fck), - CLK("481d0000.d_can", NULL, &dcan1_fck), - CLK(NULL, "pruss_ocp_gclk", &pruss_ocp_gclk), - CLK(NULL, "mcasp0_fck", &mcasp0_fck), - CLK(NULL, "mcasp1_fck", &mcasp1_fck), - CLK(NULL, "mmu_fck", &mmu_fck), - CLK(NULL, "smartreflex0_fck", &smartreflex0_fck), - CLK(NULL, "smartreflex1_fck", &smartreflex1_fck), - CLK(NULL, "sha0_fck", &sha0_fck), - CLK(NULL, "aes0_fck", &aes0_fck), - CLK(NULL, "rng_fck", &rng_fck), - CLK(NULL, "timer1_fck", &timer1_fck), - CLK(NULL, "timer2_fck", &timer2_fck), - CLK(NULL, "timer3_fck", &timer3_fck), - CLK(NULL, "timer4_fck", &timer4_fck), - CLK(NULL, "timer5_fck", &timer5_fck), - CLK(NULL, "timer6_fck", &timer6_fck), - CLK(NULL, "timer7_fck", &timer7_fck), - CLK(NULL, "usbotg_fck", &usbotg_fck), - CLK(NULL, "ieee5000_fck", &ieee5000_fck), - CLK(NULL, "wdt1_fck", &wdt1_fck), - CLK(NULL, "l4_rtc_gclk", &l4_rtc_gclk), - CLK(NULL, "l3_gclk", &l3_gclk), - CLK(NULL, "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck), - CLK(NULL, "l4hs_gclk", &l4hs_gclk), - CLK(NULL, "l3s_gclk", &l3s_gclk), - CLK(NULL, "l4fw_gclk", &l4fw_gclk), - CLK(NULL, "l4ls_gclk", &l4ls_gclk), - CLK(NULL, "clk_24mhz", &clk_24mhz), - CLK(NULL, "sysclk_div_ck", &sysclk_div_ck), - CLK(NULL, "cpsw_125mhz_gclk", &cpsw_125mhz_gclk), - CLK(NULL, "cpsw_cpts_rft_clk", &cpsw_cpts_rft_clk), - CLK(NULL, "gpio0_dbclk_mux_ck", &gpio0_dbclk_mux_ck), - CLK(NULL, "gpio0_dbclk", &gpio0_dbclk), - CLK(NULL, "gpio1_dbclk", &gpio1_dbclk), - CLK(NULL, "gpio2_dbclk", &gpio2_dbclk), - CLK(NULL, "gpio3_dbclk", &gpio3_dbclk), - CLK(NULL, "lcd_gclk", &lcd_gclk), - CLK(NULL, "mmc_clk", &mmc_clk), - CLK(NULL, "gfx_fclk_clksel_ck", &gfx_fclk_clksel_ck), - CLK(NULL, "gfx_fck_div_ck", &gfx_fck_div_ck), - CLK(NULL, "sysclkout_pre_ck", &sysclkout_pre_ck), - CLK(NULL, "clkout2_div_ck", &clkout2_div_ck), - CLK(NULL, "timer_32k_ck", &clkdiv32k_ick), - CLK(NULL, "timer_sys_ck", &sys_clkin_ck), - CLK(NULL, "dbg_sysclk_ck", &dbg_sysclk_ck), - CLK(NULL, "dbg_clka_ck", &dbg_clka_ck), - CLK(NULL, "stm_pmd_clock_mux_ck", &stm_pmd_clock_mux_ck), - CLK(NULL, "trace_pmd_clk_mux_ck", &trace_pmd_clk_mux_ck), - CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck), - CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck), - CLK(NULL, "clkout2_ck", &clkout2_ck), - CLK("48300200.ehrpwm", "tbclk", &ehrpwm0_tbclk), - CLK("48302200.ehrpwm", "tbclk", &ehrpwm1_tbclk), - CLK("48304200.ehrpwm", "tbclk", &ehrpwm2_tbclk), -}; - - -static const char *enable_init_clks[] = { - "dpll_ddr_m2_ck", - "dpll_mpu_m2_ck", - "l3_gclk", - "l4hs_gclk", - "l4fw_gclk", - "l4ls_gclk", - "clkout2_ck", /* Required for external peripherals like, Audio codecs */ -}; - -int __init am33xx_clk_init(void) -{ - if (soc_is_am33xx()) - cpu_mask = RATE_IN_AM33XX; - - omap_clocks_register(am33xx_clks, ARRAY_SIZE(am33xx_clks)); - - omap2_clk_disable_autoidle_all(); - - omap2_clk_enable_init_clocks(enable_init_clks, - ARRAY_SIZE(enable_init_clks)); - - /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always - * physically present, in such a case HWMOD enabling of - * clock would be failure with default parent. And timer - * probe thinks clock is already enabled, this leads to - * crash upon accessing timer 3 & 6 registers in probe. - * Fix by setting parent of both these timers to master - * oscillator clock. - */ - - clk_set_parent(&timer3_fck, &sys_clkin_ck); - clk_set_parent(&timer6_fck, &sys_clkin_ck); - /* - * The On-Chip 32K RC Osc clock is not an accurate clock-source as per - * the design/spec, so as a result, for example, timer which supposed - * to get expired @60Sec, but will expire somewhere ~@40Sec, which is - * not expected by any use-case, so change WDT1 clock source to PRCM - * 32KHz clock. - */ - clk_set_parent(&wdt1_fck, &clkdiv32k_ick); - - return 0; -} diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c deleted file mode 100644 index ec0dc0b1755e..000000000000 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ /dev/null @@ -1,1735 +0,0 @@ -/* - * OMAP4 Clock data - * - * Copyright (C) 2009-2012 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley (paul@pwsan.com) - * Rajendra Nayak (rnayak@ti.com) - * Benoit Cousson (b-cousson@ti.com) - * Mike Turquette (mturquette@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * XXX Some of the ES1 clocks have been removed/changed; once support - * is added for discriminating clocks by ES level, these should be added back - * in. - * - * XXX All of the remaining MODULEMODE clock nodes should be removed - * once the drivers are updated to use pm_runtime or to use the appropriate - * upstream clock node for rate/parent selection. - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/clk-private.h> -#include <linux/clkdev.h> -#include <linux/io.h> - -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "clock44xx.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" -#include "cm-regbits-44xx.h" -#include "prm44xx.h" -#include "prm-regbits-44xx.h" -#include "control.h" -#include "scrm44xx.h" - -/* OMAP4 modulemode control */ -#define OMAP4430_MODULEMODE_HWCTRL_SHIFT 0 -#define OMAP4430_MODULEMODE_SWCTRL_SHIFT 1 - -/* - * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section - * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK - * must be set to 196.608 MHz" and hence, the DPLL locked frequency is - * half of this value. - */ -#define OMAP4_DPLL_ABE_DEFFREQ 98304000 - -/* - * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section - * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred - * locked frequency for the USB DPLL is 960MHz. - */ -#define OMAP4_DPLL_USB_DEFFREQ 960000000 - -/* Root clocks */ - -DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0); - -DEFINE_CLK_FIXED_RATE(pad_clks_src_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_GATE(pad_clks_ck, "pad_clks_src_ck", &pad_clks_src_ck, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_PAD_CLKS_GATE_SHIFT, - 0x0, NULL); - -DEFINE_CLK_FIXED_RATE(pad_slimbus_core_clks_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_FIXED_RATE(secure_32k_clk_src_ck, CLK_IS_ROOT, 32768, 0x0); - -DEFINE_CLK_FIXED_RATE(slimbus_src_clk, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_GATE(slimbus_clk, "slimbus_src_clk", &slimbus_src_clk, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_SLIMBUS_CLK_GATE_SHIFT, - 0x0, NULL); - -DEFINE_CLK_FIXED_RATE(sys_32k_ck, CLK_IS_ROOT, 32768, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_12000000_ck, CLK_IS_ROOT, 12000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_13000000_ck, CLK_IS_ROOT, 13000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_16800000_ck, CLK_IS_ROOT, 16800000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_27000000_ck, CLK_IS_ROOT, 27000000, 0x0); - -DEFINE_CLK_FIXED_RATE(virt_38400000_ck, CLK_IS_ROOT, 38400000, 0x0); - -static const char *sys_clkin_ck_parents[] = { - "virt_12000000_ck", "virt_13000000_ck", "virt_16800000_ck", - "virt_19200000_ck", "virt_26000000_ck", "virt_27000000_ck", - "virt_38400000_ck", -}; - -DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0, - OMAP4430_CM_SYS_CLKSEL, OMAP4430_SYS_CLKSEL_SHIFT, - OMAP4430_SYS_CLKSEL_WIDTH, CLK_MUX_INDEX_ONE, NULL); - -DEFINE_CLK_FIXED_RATE(tie_low_clock_ck, CLK_IS_ROOT, 0, 0x0); - -DEFINE_CLK_FIXED_RATE(utmi_phy_clkout_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60mhsp1_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60mhsp2_ck, CLK_IS_ROOT, 60000000, 0x0); - -DEFINE_CLK_FIXED_RATE(xclk60motg_ck, CLK_IS_ROOT, 60000000, 0x0); - -/* Module clocks and DPLL outputs */ - -static const char *abe_dpll_bypass_clk_mux_ck_parents[] = { - "sys_clkin_ck", "sys_32k_ck", -}; - -DEFINE_CLK_MUX(abe_dpll_bypass_clk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents, - NULL, 0x0, OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_SHIFT, - OMAP4430_CLKSEL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(abe_dpll_refclk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_ABE_PLL_REF_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -/* DPLL_ABE */ -static struct dpll_data dpll_abe_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_ABE, - .clk_bypass = &abe_dpll_bypass_clk_mux_ck, - .clk_ref = &abe_dpll_refclk_mux_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_ABE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_ABE, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_ABE, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .m4xen_mask = OMAP4430_DPLL_REGM4XEN_MASK, - .lpmode_mask = OMAP4430_DPLL_LPMODE_EN_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - - -static const char *dpll_abe_ck_parents[] = { - "abe_dpll_refclk_mux_ck", -}; - -static struct clk dpll_abe_ck; - -static const struct clk_ops dpll_abe_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap4_dpll_regm4xen_recalc, - .round_rate = &omap4_dpll_regm4xen_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_abe_ck_hw = { - .hw = { - .clk = &dpll_abe_ck, - }, - .dpll_data = &dpll_abe_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_abe_ck, dpll_abe_ck_parents, dpll_abe_ck_ops); - -static const char *dpll_abe_x2_ck_parents[] = { - "dpll_abe_ck", -}; - -static struct clk dpll_abe_x2_ck; - -static const struct clk_ops dpll_abe_x2_ck_ops = { - .recalc_rate = &omap3_clkoutx2_recalc, -}; - -static struct clk_hw_omap dpll_abe_x2_ck_hw = { - .hw = { - .clk = &dpll_abe_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, - .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_ABE, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_abe_x2_ck, dpll_abe_x2_ck_parents, dpll_abe_x2_ck_ops); - -static const struct clk_ops omap_hsdivider_ops = { - .set_rate = &omap2_clksel_set_rate, - .recalc_rate = &omap2_clksel_recalc, - .round_rate = &omap2_clksel_round_rate, -}; - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m2x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck, - 0x0, OMAP4430_CM_DIV_M2_DPLL_ABE, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(abe_24m_fclk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, - 0x0, 1, 8); - -DEFINE_CLK_DIVIDER(abe_clk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, 0x0, - OMAP4430_CM_CLKSEL_ABE, OMAP4430_CLKSEL_OPP_SHIFT, - OMAP4430_CLKSEL_OPP_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_DIVIDER(aess_fclk, "abe_clk", &abe_clk, 0x0, - OMAP4430_CM1_ABE_AESS_CLKCTRL, - OMAP4430_CLKSEL_AESS_FCLK_SHIFT, - OMAP4430_CLKSEL_AESS_FCLK_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m3x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck, - 0x0, OMAP4430_CM_DIV_M3_DPLL_ABE, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK); - -static const char *core_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "dpll_abe_m3x2_ck", -}; - -DEFINE_CLK_MUX(core_hsd_byp_clk_mux_ck, core_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_CORE, - OMAP4430_DPLL_BYP_CLKSEL_SHIFT, OMAP4430_DPLL_BYP_CLKSEL_WIDTH, - 0x0, NULL); - -/* DPLL_CORE */ -static struct dpll_data dpll_core_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_CORE, - .clk_bypass = &core_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_CORE, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_CORE, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_CORE, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - - -static const char *dpll_core_ck_parents[] = { - "sys_clkin_ck", "core_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_core_ck; - -static const struct clk_ops dpll_core_ck_ops = { - .recalc_rate = &omap3_dpll_recalc, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_core_ck_hw = { - .hw = { - .clk = &dpll_core_ck, - }, - .dpll_data = &dpll_core_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops); - -static const char *dpll_core_x2_ck_parents[] = { - "dpll_core_ck", -}; - -static struct clk dpll_core_x2_ck; - -static struct clk_hw_omap dpll_core_x2_ck_hw = { - .hw = { - .clk = &dpll_core_x2_ck, - }, -}; - -DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m6x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M6_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m2_ck, "dpll_core_ck", &dpll_core_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_CORE, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(ddrphy_ck, "dpll_core_m2_ck", &dpll_core_m2_ck, 0x0, 1, - 2); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m5x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M5_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -DEFINE_CLK_DIVIDER(div_core_ck, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_CORE_SHIFT, - OMAP4430_CLKSEL_CORE_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, - 0x0, OMAP4430_CM_BYPCLK_DPLL_IVA, OMAP4430_CLKSEL_0_1_SHIFT, - OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_DIVIDER(div_mpu_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, - 0x0, OMAP4430_CM_BYPCLK_DPLL_MPU, OMAP4430_CLKSEL_0_1_SHIFT, - OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m4x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M4_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(dll_clk_div_ck, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck, - 0x0, 1, 2); - -DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, - OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -static const struct clk_ops dpll_hsd_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, - .init = &omap2_init_clk_clkdm, -}; - -static const struct clk_ops func_dmic_abe_gfclk_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, -}; - -static const char *dpll_core_m3x2_ck_parents[] = { - "dpll_core_x2_ck", -}; - -static const struct clksel dpll_core_m3x2_div[] = { - { .parent = &dpll_core_x2_ck, .rates = div31_1to31_rates }, - { .parent = NULL }, -}; - -/* XXX Missing round_rate, set_rate in ops */ -DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div, - OMAP4430_CM_DIV_M3_DPLL_CORE, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - OMAP4430_CM_DIV_M3_DPLL_CORE, - OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_core_m3x2_ck_parents, dpll_hsd_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck", - &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE, - OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK); - -static const char *iva_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "div_iva_hs_clk", -}; - -DEFINE_CLK_MUX(iva_hsd_byp_clk_mux_ck, iva_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_IVA, OMAP4430_DPLL_BYP_CLKSEL_SHIFT, - OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL); - -/* DPLL_IVA */ -static struct dpll_data dpll_iva_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_IVA, - .clk_bypass = &iva_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_IVA, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_IVA, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_IVA, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_iva_ck_parents[] = { - "sys_clkin_ck", "iva_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_iva_ck; - -static const struct clk_ops dpll_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, -}; - -static struct clk_hw_omap dpll_iva_ck_hw = { - .hw = { - .clk = &dpll_iva_ck, - }, - .dpll_data = &dpll_iva_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_iva_ck_parents, dpll_ck_ops); - -static const char *dpll_iva_x2_ck_parents[] = { - "dpll_iva_ck", -}; - -static struct clk dpll_iva_x2_ck; - -static struct clk_hw_omap dpll_iva_x2_ck_hw = { - .hw = { - .clk = &dpll_iva_x2_ck, - }, -}; - -DEFINE_STRUCT_CLK(dpll_iva_x2_ck, dpll_iva_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m4x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck, - 0x0, OMAP4430_CM_DIV_M4_DPLL_IVA, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m5x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck, - 0x0, OMAP4430_CM_DIV_M5_DPLL_IVA, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -/* DPLL_MPU */ -static struct dpll_data dpll_mpu_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_MPU, - .clk_bypass = &div_mpu_hs_clk, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_MPU, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_MPU, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_MPU, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_mpu_ck_parents[] = { - "sys_clkin_ck", "div_mpu_hs_clk" -}; - -static struct clk dpll_mpu_ck; - -static struct clk_hw_omap dpll_mpu_ck_hw = { - .hw = { - .clk = &dpll_mpu_ck, - }, - .dpll_data = &dpll_mpu_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_mpu_ck_parents, dpll_ck_ops); - -DEFINE_CLK_FIXED_FACTOR(mpu_periphclk, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, 1, 2); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_MPU, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(per_hs_clk_div_ck, "dpll_abe_m3x2_ck", - &dpll_abe_m3x2_ck, 0x0, 1, 2); - -static const char *per_hsd_byp_clk_mux_ck_parents[] = { - "sys_clkin_ck", "per_hs_clk_div_ck", -}; - -DEFINE_CLK_MUX(per_hsd_byp_clk_mux_ck, per_hsd_byp_clk_mux_ck_parents, NULL, - 0x0, OMAP4430_CM_CLKSEL_DPLL_PER, OMAP4430_DPLL_BYP_CLKSEL_SHIFT, - OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL); - -/* DPLL_PER */ -static struct dpll_data dpll_per_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_PER, - .clk_bypass = &per_hsd_byp_clk_mux_ck, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_PER, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_PER, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_PER, - .mult_mask = OMAP4430_DPLL_MULT_MASK, - .div1_mask = OMAP4430_DPLL_DIV_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .max_multiplier = 2047, - .max_divider = 128, - .min_divider = 1, -}; - -static const char *dpll_per_ck_parents[] = { - "sys_clkin_ck", "per_hsd_byp_clk_mux_ck" -}; - -static struct clk dpll_per_ck; - -static struct clk_hw_omap dpll_per_ck_hw = { - .hw = { - .clk = &dpll_per_ck, - }, - .dpll_data = &dpll_per_dd, - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_per_ck, dpll_per_ck_parents, dpll_ck_ops); - -DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_PER, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, - OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); - -static const char *dpll_per_x2_ck_parents[] = { - "dpll_per_ck", -}; - -static struct clk dpll_per_x2_ck; - -static struct clk_hw_omap dpll_per_x2_ck_hw = { - .hw = { - .clk = &dpll_per_x2_ck, - }, - .flags = CLOCK_CLKOUTX2, - .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_PER, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_per_x2_ck, dpll_per_x2_ck_parents, dpll_abe_x2_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m2x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M2_DPLL_PER, - OMAP4430_DPLL_CLKOUT_DIV_MASK); - -static const char *dpll_per_m3x2_ck_parents[] = { - "dpll_per_x2_ck", -}; - -static const struct clksel dpll_per_m3x2_div[] = { - { .parent = &dpll_per_x2_ck, .rates = div31_1to31_rates }, - { .parent = NULL }, -}; - -/* XXX Missing round_rate, set_rate in ops */ -DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div, - OMAP4430_CM_DIV_M3_DPLL_PER, - OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - OMAP4430_CM_DIV_M3_DPLL_PER, - OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_per_m3x2_ck_parents, dpll_hsd_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M4_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m5x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M5_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m6x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M6_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m7x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, - 0x0, OMAP4430_CM_DIV_M7_DPLL_PER, - OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK); - -DEFINE_CLK_FIXED_FACTOR(usb_hs_clk_div_ck, "dpll_abe_m3x2_ck", - &dpll_abe_m3x2_ck, 0x0, 1, 3); - -/* DPLL_USB */ -static struct dpll_data dpll_usb_dd = { - .mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_USB, - .clk_bypass = &usb_hs_clk_div_ck, - .flags = DPLL_J_TYPE, - .clk_ref = &sys_clkin_ck, - .control_reg = OMAP4430_CM_CLKMODE_DPLL_USB, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), - .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_USB, - .idlest_reg = OMAP4430_CM_IDLEST_DPLL_USB, - .mult_mask = OMAP4430_DPLL_MULT_USB_MASK, - .div1_mask = OMAP4430_DPLL_DIV_0_7_MASK, - .enable_mask = OMAP4430_DPLL_EN_MASK, - .autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK, - .idlest_mask = OMAP4430_ST_DPLL_CLK_MASK, - .sddiv_mask = OMAP4430_DPLL_SD_DIV_MASK, - .max_multiplier = 4095, - .max_divider = 256, - .min_divider = 1, -}; - -static const char *dpll_usb_ck_parents[] = { - "sys_clkin_ck", "usb_hs_clk_div_ck" -}; - -static struct clk dpll_usb_ck; - -static const struct clk_ops dpll_usb_ck_ops = { - .enable = &omap3_noncore_dpll_enable, - .disable = &omap3_noncore_dpll_disable, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, - .set_rate = &omap3_noncore_dpll_set_rate, - .get_parent = &omap2_init_dpll_parent, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap dpll_usb_ck_hw = { - .hw = { - .clk = &dpll_usb_ck, - }, - .dpll_data = &dpll_usb_dd, - .clkdm_name = "l3_init_clkdm", - .ops = &clkhwops_omap3_dpll, -}; - -DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_usb_ck_parents, dpll_usb_ck_ops); - -static const char *dpll_usb_clkdcoldo_ck_parents[] = { - "dpll_usb_ck", -}; - -static struct clk dpll_usb_clkdcoldo_ck; - -static const struct clk_ops dpll_usb_clkdcoldo_ck_ops = { -}; - -static struct clk_hw_omap dpll_usb_clkdcoldo_ck_hw = { - .hw = { - .clk = &dpll_usb_clkdcoldo_ck, - }, - .clksel_reg = OMAP4430_CM_CLKDCOLDO_DPLL_USB, - .ops = &clkhwops_omap4_dpllmx, -}; - -DEFINE_STRUCT_CLK(dpll_usb_clkdcoldo_ck, dpll_usb_clkdcoldo_ck_parents, - dpll_usb_clkdcoldo_ck_ops); - -DEFINE_CLK_OMAP_HSDIVIDER(dpll_usb_m2_ck, "dpll_usb_ck", &dpll_usb_ck, 0x0, - OMAP4430_CM_DIV_M2_DPLL_USB, - OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK); - -static const char *ducati_clk_mux_ck_parents[] = { - "div_core_ck", "dpll_per_m6x2_ck", -}; - -DEFINE_CLK_MUX(ducati_clk_mux_ck, ducati_clk_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_CLKSEL_DUCATI_ISS_ROOT, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -DEFINE_CLK_FIXED_FACTOR(func_12m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 16); - -DEFINE_CLK_FIXED_FACTOR(func_24m_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, - 1, 4); - -DEFINE_CLK_FIXED_FACTOR(func_24mc_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 8); - -static const struct clk_div_table func_48m_fclk_rates[] = { - { .div = 4, .val = 0 }, - { .div = 8, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_48m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_48m_fclk_rates, - NULL); - -DEFINE_CLK_FIXED_FACTOR(func_48mc_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, 1, 4); - -static const struct clk_div_table func_64m_fclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 4, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_64m_fclk, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_64m_fclk_rates, - NULL); - -static const struct clk_div_table func_96m_fclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 4, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(func_96m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, - 0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_96m_fclk_rates, - NULL); - -static const struct clk_div_table init_60m_fclk_rates[] = { - { .div = 1, .val = 0 }, - { .div = 8, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(init_60m_fclk, "dpll_usb_m2_ck", &dpll_usb_m2_ck, - 0x0, OMAP4430_CM_CLKSEL_USB_60MHZ, - OMAP4430_CLKSEL_0_0_SHIFT, OMAP4430_CLKSEL_0_0_WIDTH, - 0x0, init_60m_fclk_rates, NULL); - -DEFINE_CLK_DIVIDER(l3_div_ck, "div_core_ck", &div_core_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L3_SHIFT, - OMAP4430_CLKSEL_L3_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(l4_div_ck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L4_SHIFT, - OMAP4430_CLKSEL_L4_WIDTH, 0x0, NULL); - -DEFINE_CLK_FIXED_FACTOR(lp_clk_div_ck, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, - 0x0, 1, 16); - -static const char *l4_wkup_clk_mux_ck_parents[] = { - "sys_clkin_ck", "lp_clk_div_ck", -}; - -DEFINE_CLK_MUX(l4_wkup_clk_mux_ck, l4_wkup_clk_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -static const struct clk_div_table ocp_abe_iclk_rates[] = { - { .div = 2, .val = 0 }, - { .div = 1, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(ocp_abe_iclk, "aess_fclk", &aess_fclk, 0x0, - OMAP4430_CM1_ABE_AESS_CLKCTRL, - OMAP4430_CLKSEL_AESS_FCLK_SHIFT, - OMAP4430_CLKSEL_AESS_FCLK_WIDTH, - 0x0, ocp_abe_iclk_rates, NULL); - -DEFINE_CLK_FIXED_FACTOR(per_abe_24m_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck, - 0x0, 1, 4); - -DEFINE_CLK_DIVIDER(per_abe_nc_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck, 0x0, - OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT, - OMAP4430_SCALE_FCLK_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(syc_clk_div_ck, "sys_clkin_ck", &sys_clkin_ck, 0x0, - OMAP4430_CM_ABE_DSS_SYS_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT, - OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL); - -static const char *dbgclk_mux_ck_parents[] = { - "sys_clkin_ck" -}; - -static struct clk dbgclk_mux_ck; -DEFINE_STRUCT_CLK_HW_OMAP(dbgclk_mux_ck, NULL); -DEFINE_STRUCT_CLK(dbgclk_mux_ck, dbgclk_mux_ck_parents, - dpll_usb_clkdcoldo_ck_ops); - -/* Leaf clocks controlled by modules */ - -DEFINE_CLK_GATE(aes1_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_AES1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_AES2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL); - -static const struct clk_div_table div_ts_ck_rates[] = { - { .div = 8, .val = 0 }, - { .div = 16, .val = 1 }, - { .div = 32, .val = 2 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(div_ts_ck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4430_CLKSEL_24_25_SHIFT, - OMAP4430_CLKSEL_24_25_WIDTH, 0x0, div_ts_ck_rates, - NULL); - -DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0, - OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, - OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, - 0x0, NULL); - -static const char *dmic_sync_mux_ck_parents[] = { - "abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk", -}; - -DEFINE_CLK_MUX(dmic_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, - 0x0, OMAP4430_CM1_ABE_DMIC_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_dmic_abe_gfclk_sel[] = { - { .parent = &dmic_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_dmic_abe_gfclk_parents[] = { - "dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel, - OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, - OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dss_tv_clk, "extalt_clkin_ck", &extalt_clkin_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, - OMAP4430_OPTFCLKEN_TV_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(dss_dss_clk, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck, - CLK_SET_RATE_PARENT, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_DSSCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(dss_48mhz_clk, "func_48mc_fclk", &func_48mc_fclk, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, - OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT, - OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); - -DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_GPIO1_CLKCTRL, - OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO3_CLKCTRL, - OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, - 0x0, NULL); - -static const struct clksel sgx_clk_mux_sel[] = { - { .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates }, - { .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *sgx_clk_mux_parents[] = { - "dpll_core_m7x2_ck", "dpll_per_m7x2_ck", -}; - -DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel, - OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK, - sgx_clk_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0, - OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT, - OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT, - 0x0, NULL); - -DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcasp_abe_gfclk_sel[] = { - { .parent = &mcasp_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcasp_abe_gfclk_parents[] = { - "mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp1_gfclk_sel[] = { - { .parent = &mcbsp1_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp1_gfclk_parents[] = { - "mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp2_gfclk_sel[] = { - { .parent = &mcbsp2_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp2_gfclk_parents[] = { - "mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel func_mcbsp3_gfclk_sel[] = { - { .parent = &mcbsp3_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = &slimbus_clk, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *func_mcbsp3_gfclk_parents[] = { - "mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk", -}; - -DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents, - func_dmic_abe_gfclk_ops); - -static const char *mcbsp4_sync_mux_ck_parents[] = { - "func_96m_fclk", "per_abe_nc_fclk", -}; - -DEFINE_CLK_MUX(mcbsp4_sync_mux_ck, mcbsp4_sync_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, - OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL); - -static const struct clksel per_mcbsp4_gfclk_sel[] = { - { .parent = &mcbsp4_sync_mux_ck, .rates = div_1_0_rates }, - { .parent = &pad_clks_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *per_mcbsp4_gfclk_parents[] = { - "mcbsp4_sync_mux_ck", "pad_clks_ck", -}; - -DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents, - func_dmic_abe_gfclk_ops); - -static const struct clksel hsmmc1_fclk_sel[] = { - { .parent = &func_64m_fclk, .rates = div_1_0_rates }, - { .parent = &func_96m_fclk, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *hsmmc1_fclk_parents[] = { - "func_64m_fclk", "func_96m_fclk", -}; - -DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, - OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_0, "abe_24m_fclk", &abe_24m_fclk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK0_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_fclk_2, "pad_clks_ck", &pad_clks_ck, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_FCLK2_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_fclk_0, "func_24mc_fclk", &func_24mc_fclk, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck", - &pad_slimbus_core_clks_ck, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_iva_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(smartreflex_mpu_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, - 0x0, OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -static const struct clksel dmt1_clk_mux_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &sys_32k_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -static const struct clksel timer5_sync_mux_sel[] = { - { .parent = &syc_clk_div_ck, .rates = div_1_0_rates }, - { .parent = &sys_32k_ck, .rates = div_1_1_rates }, - { .parent = NULL }, -}; - -static const char *timer5_sync_mux_parents[] = { - "syc_clk_div_ck", "sys_32k_ck", -}; - -DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -static struct clk usb_host_fs_fck; - -static const char *usb_host_fs_fck_parent_names[] = { - "func_48mc_fclk", -}; - -static const struct clk_ops usb_host_fs_fck_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, -}; - -static struct clk_hw_omap usb_host_fs_fck_hw = { - .hw = { - .clk = &usb_host_fs_fck, - }, - .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_SWCTRL_SHIFT, - .clkdm_name = "l3_init_clkdm", -}; - -DEFINE_STRUCT_CLK(usb_host_fs_fck, usb_host_fs_fck_parent_names, - usb_host_fs_fck_ops); - -static const char *utmi_p1_gfclk_parents[] = { - "init_60m_fclk", "xclk60mhsp1_ck", -}; - -DEFINE_CLK_MUX(utmi_p1_gfclk, utmi_p1_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_CLKSEL_UTMI_P1_SHIFT, OMAP4430_CLKSEL_UTMI_P1_WIDTH, - 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p1_clk, "utmi_p1_gfclk", &utmi_p1_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT, 0x0, NULL); - -static const char *utmi_p2_gfclk_parents[] = { - "init_60m_fclk", "xclk60mhsp2_ck", -}; - -DEFINE_CLK_MUX(utmi_p2_gfclk, utmi_p2_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_CLKSEL_UTMI_P2_SHIFT, OMAP4430_CLKSEL_UTMI_P2_WIDTH, - 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p2_clk, "utmi_p2_gfclk", &utmi_p2_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_utmi_p3_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic480m_p1_clk, "dpll_usb_m2_ck", - &dpll_usb_m2_ck, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic60m_p1_clk, "init_60m_fclk", - &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic60m_p2_clk, "init_60m_fclk", - &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_hsic480m_p2_clk, "dpll_usb_m2_ck", - &dpll_usb_m2_ck, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_func48mclk, "func_48mc_fclk", &func_48mc_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_host_hs_fck, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -static const char *otg_60m_gfclk_parents[] = { - "utmi_phy_clkout_ck", "xclk60motg_ck", -}; - -DEFINE_CLK_MUX(otg_60m_gfclk, otg_60m_gfclk_parents, NULL, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, OMAP4430_CLKSEL_60M_SHIFT, - OMAP4430_CLKSEL_60M_WIDTH, 0x0, NULL); - -DEFINE_CLK_GATE(usb_otg_hs_xclk, "otg_60m_gfclk", &otg_60m_gfclk, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, - OMAP4430_OPTFCLKEN_XCLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_otg_hs_ick, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_phy_cm_clk32k, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_ALWON_USBPHY_CLKCTRL, - OMAP4430_OPTFCLKEN_CLK32K_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch2_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch0_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_usb_ch1_clk, "init_60m_fclk", &init_60m_fclk, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(usb_tll_hs_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -static const struct clk_div_table usim_ck_rates[] = { - { .div = 14, .val = 0 }, - { .div = 18, .val = 1 }, - { .div = 0 }, -}; -DEFINE_CLK_DIVIDER_TABLE(usim_ck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, - OMAP4430_CM_WKUP_USIM_CLKCTRL, - OMAP4430_CLKSEL_DIV_SHIFT, OMAP4430_CLKSEL_DIV_WIDTH, - 0x0, usim_ck_rates, NULL); - -DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0, - OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT, - 0x0, NULL); - -/* Remaining optional clocks */ -static const char *pmd_stm_clock_mux_ck_parents[] = { - "sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck", -}; - -DEFINE_CLK_MUX(pmd_stm_clock_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, OMAP4430_PMD_STM_MUX_CTRL_SHIFT, - OMAP4430_PMD_STM_MUX_CTRL_WIDTH, 0x0, NULL); - -DEFINE_CLK_MUX(pmd_trace_clk_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0, - OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT, - OMAP4430_PMD_TRACE_MUX_CTRL_WIDTH, 0x0, NULL); - -DEFINE_CLK_DIVIDER(stm_clk_div_ck, "pmd_stm_clock_mux_ck", - &pmd_stm_clock_mux_ck, 0x0, OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT, - OMAP4430_CLKSEL_PMD_STM_CLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, - NULL); - -static const char *trace_clk_div_ck_parents[] = { - "pmd_trace_clk_mux_ck", -}; - -static const struct clksel trace_clk_div_div[] = { - { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates }, - { .parent = NULL }, -}; - -static struct clk trace_clk_div_ck; - -static const struct clk_ops trace_clk_div_ck_ops = { - .recalc_rate = &omap2_clksel_recalc, - .set_rate = &omap2_clksel_set_rate, - .round_rate = &omap2_clksel_round_rate, - .init = &omap2_init_clk_clkdm, - .enable = &omap2_clkops_enable_clkdm, - .disable = &omap2_clkops_disable_clkdm, -}; - -static struct clk_hw_omap trace_clk_div_ck_hw = { - .hw = { - .clk = &trace_clk_div_ck, - }, - .clkdm_name = "emu_sys_clkdm", - .clksel = trace_clk_div_div, - .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, - .clksel_mask = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK, -}; - -DEFINE_STRUCT_CLK(trace_clk_div_ck, trace_clk_div_ck_parents, - trace_clk_div_ck_ops); - -/* SCRM aux clk nodes */ - -static const struct clksel auxclk_src_sel[] = { - { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, - { .parent = &dpll_core_m3x2_ck, .rates = div_1_1_rates }, - { .parent = &dpll_per_m3x2_ck, .rates = div_1_2_rates }, - { .parent = NULL }, -}; - -static const char *auxclk_src_ck_parents[] = { - "sys_clkin_ck", "dpll_core_m3x2_ck", "dpll_per_m3x2_ck", -}; - -static const struct clk_ops auxclk_src_ck_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, -}; - -DEFINE_CLK_OMAP_MUX_GATE(auxclk0_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK0, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK0, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk0_ck, "auxclk0_src_ck", &auxclk0_src_ck, 0x0, - OMAP4_SCRM_AUXCLK0, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk1_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK1, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK1, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk1_ck, "auxclk1_src_ck", &auxclk1_src_ck, 0x0, - OMAP4_SCRM_AUXCLK1, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk2_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK2, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK2, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk2_ck, "auxclk2_src_ck", &auxclk2_src_ck, 0x0, - OMAP4_SCRM_AUXCLK2, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk3_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK3, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK3, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk3_ck, "auxclk3_src_ck", &auxclk3_src_ck, 0x0, - OMAP4_SCRM_AUXCLK3, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk4_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK4, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK4, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk4_ck, "auxclk4_src_ck", &auxclk4_src_ck, 0x0, - OMAP4_SCRM_AUXCLK4, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -DEFINE_CLK_OMAP_MUX_GATE(auxclk5_src_ck, NULL, auxclk_src_sel, - OMAP4_SCRM_AUXCLK5, OMAP4_SRCSELECT_MASK, - OMAP4_SCRM_AUXCLK5, OMAP4_ENABLE_SHIFT, NULL, - auxclk_src_ck_parents, auxclk_src_ck_ops); - -DEFINE_CLK_DIVIDER(auxclk5_ck, "auxclk5_src_ck", &auxclk5_src_ck, 0x0, - OMAP4_SCRM_AUXCLK5, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH, - 0x0, NULL); - -static const char *auxclkreq_ck_parents[] = { - "auxclk0_ck", "auxclk1_ck", "auxclk2_ck", "auxclk3_ck", "auxclk4_ck", - "auxclk5_ck", -}; - -DEFINE_CLK_MUX(auxclkreq0_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ0, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq1_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ1, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq2_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ2, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq3_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ3, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq4_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ4, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -DEFINE_CLK_MUX(auxclkreq5_ck, auxclkreq_ck_parents, NULL, 0x0, - OMAP4_SCRM_AUXCLKREQ5, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH, - 0x0, NULL); - -/* - * clocks specific to omap4460 - */ -static struct omap_clk omap446x_clks[] = { - CLK(NULL, "div_ts_ck", &div_ts_ck), - CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk), -}; - -/* - * clocks specific to omap4430 - */ -static struct omap_clk omap443x_clks[] = { - CLK(NULL, "bandgap_fclk", &bandgap_fclk), -}; - -/* - * clocks common to omap44xx - */ -static struct omap_clk omap44xx_clks[] = { - CLK(NULL, "extalt_clkin_ck", &extalt_clkin_ck), - CLK(NULL, "pad_clks_src_ck", &pad_clks_src_ck), - CLK(NULL, "pad_clks_ck", &pad_clks_ck), - CLK(NULL, "pad_slimbus_core_clks_ck", &pad_slimbus_core_clks_ck), - CLK(NULL, "secure_32k_clk_src_ck", &secure_32k_clk_src_ck), - CLK(NULL, "slimbus_src_clk", &slimbus_src_clk), - CLK(NULL, "slimbus_clk", &slimbus_clk), - CLK(NULL, "sys_32k_ck", &sys_32k_ck), - CLK(NULL, "virt_12000000_ck", &virt_12000000_ck), - CLK(NULL, "virt_13000000_ck", &virt_13000000_ck), - CLK(NULL, "virt_16800000_ck", &virt_16800000_ck), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck), - CLK(NULL, "virt_27000000_ck", &virt_27000000_ck), - CLK(NULL, "virt_38400000_ck", &virt_38400000_ck), - CLK(NULL, "sys_clkin_ck", &sys_clkin_ck), - CLK(NULL, "tie_low_clock_ck", &tie_low_clock_ck), - CLK(NULL, "utmi_phy_clkout_ck", &utmi_phy_clkout_ck), - CLK(NULL, "xclk60mhsp1_ck", &xclk60mhsp1_ck), - CLK(NULL, "xclk60mhsp2_ck", &xclk60mhsp2_ck), - CLK(NULL, "xclk60motg_ck", &xclk60motg_ck), - CLK(NULL, "abe_dpll_bypass_clk_mux_ck", &abe_dpll_bypass_clk_mux_ck), - CLK(NULL, "abe_dpll_refclk_mux_ck", &abe_dpll_refclk_mux_ck), - CLK(NULL, "dpll_abe_ck", &dpll_abe_ck), - CLK(NULL, "dpll_abe_x2_ck", &dpll_abe_x2_ck), - CLK(NULL, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck), - CLK(NULL, "abe_24m_fclk", &abe_24m_fclk), - CLK(NULL, "abe_clk", &abe_clk), - CLK(NULL, "aess_fclk", &aess_fclk), - CLK(NULL, "dpll_abe_m3x2_ck", &dpll_abe_m3x2_ck), - CLK(NULL, "core_hsd_byp_clk_mux_ck", &core_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_core_ck", &dpll_core_ck), - CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck), - CLK(NULL, "dpll_core_m6x2_ck", &dpll_core_m6x2_ck), - CLK(NULL, "dbgclk_mux_ck", &dbgclk_mux_ck), - CLK(NULL, "dpll_core_m2_ck", &dpll_core_m2_ck), - CLK(NULL, "ddrphy_ck", &ddrphy_ck), - CLK(NULL, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck), - CLK(NULL, "div_core_ck", &div_core_ck), - CLK(NULL, "div_iva_hs_clk", &div_iva_hs_clk), - CLK(NULL, "div_mpu_hs_clk", &div_mpu_hs_clk), - CLK(NULL, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck), - CLK(NULL, "dll_clk_div_ck", &dll_clk_div_ck), - CLK(NULL, "dpll_abe_m2_ck", &dpll_abe_m2_ck), - CLK(NULL, "dpll_core_m3x2_ck", &dpll_core_m3x2_ck), - CLK(NULL, "dpll_core_m7x2_ck", &dpll_core_m7x2_ck), - CLK(NULL, "iva_hsd_byp_clk_mux_ck", &iva_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_iva_ck", &dpll_iva_ck), - CLK(NULL, "dpll_iva_x2_ck", &dpll_iva_x2_ck), - CLK(NULL, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck), - CLK(NULL, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck), - CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck), - CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck), - CLK(NULL, "per_hs_clk_div_ck", &per_hs_clk_div_ck), - CLK(NULL, "per_hsd_byp_clk_mux_ck", &per_hsd_byp_clk_mux_ck), - CLK(NULL, "dpll_per_ck", &dpll_per_ck), - CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck), - CLK(NULL, "dpll_per_x2_ck", &dpll_per_x2_ck), - CLK(NULL, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck), - CLK(NULL, "dpll_per_m3x2_ck", &dpll_per_m3x2_ck), - CLK(NULL, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck), - CLK(NULL, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck), - CLK(NULL, "dpll_per_m6x2_ck", &dpll_per_m6x2_ck), - CLK(NULL, "dpll_per_m7x2_ck", &dpll_per_m7x2_ck), - CLK(NULL, "usb_hs_clk_div_ck", &usb_hs_clk_div_ck), - CLK(NULL, "dpll_usb_ck", &dpll_usb_ck), - CLK(NULL, "dpll_usb_clkdcoldo_ck", &dpll_usb_clkdcoldo_ck), - CLK(NULL, "dpll_usb_m2_ck", &dpll_usb_m2_ck), - CLK(NULL, "ducati_clk_mux_ck", &ducati_clk_mux_ck), - CLK(NULL, "func_12m_fclk", &func_12m_fclk), - CLK(NULL, "func_24m_clk", &func_24m_clk), - CLK(NULL, "func_24mc_fclk", &func_24mc_fclk), - CLK(NULL, "func_48m_fclk", &func_48m_fclk), - CLK(NULL, "func_48mc_fclk", &func_48mc_fclk), - CLK(NULL, "func_64m_fclk", &func_64m_fclk), - CLK(NULL, "func_96m_fclk", &func_96m_fclk), - CLK(NULL, "init_60m_fclk", &init_60m_fclk), - CLK(NULL, "l3_div_ck", &l3_div_ck), - CLK(NULL, "l4_div_ck", &l4_div_ck), - CLK(NULL, "lp_clk_div_ck", &lp_clk_div_ck), - CLK(NULL, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck), - CLK("smp_twd", NULL, &mpu_periphclk), - CLK(NULL, "ocp_abe_iclk", &ocp_abe_iclk), - CLK(NULL, "per_abe_24m_fclk", &per_abe_24m_fclk), - CLK(NULL, "per_abe_nc_fclk", &per_abe_nc_fclk), - CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck), - CLK(NULL, "aes1_fck", &aes1_fck), - CLK(NULL, "aes2_fck", &aes2_fck), - CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck), - CLK(NULL, "func_dmic_abe_gfclk", &func_dmic_abe_gfclk), - CLK(NULL, "dss_sys_clk", &dss_sys_clk), - CLK(NULL, "dss_tv_clk", &dss_tv_clk), - CLK(NULL, "dss_dss_clk", &dss_dss_clk), - CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk), - CLK(NULL, "dss_fck", &dss_fck), - CLK("omapdss_dss", "ick", &dss_fck), - CLK(NULL, "fdif_fck", &fdif_fck), - CLK(NULL, "gpio1_dbclk", &gpio1_dbclk), - CLK(NULL, "gpio2_dbclk", &gpio2_dbclk), - CLK(NULL, "gpio3_dbclk", &gpio3_dbclk), - CLK(NULL, "gpio4_dbclk", &gpio4_dbclk), - CLK(NULL, "gpio5_dbclk", &gpio5_dbclk), - CLK(NULL, "gpio6_dbclk", &gpio6_dbclk), - CLK(NULL, "sgx_clk_mux", &sgx_clk_mux), - CLK(NULL, "hsi_fck", &hsi_fck), - CLK(NULL, "iss_ctrlclk", &iss_ctrlclk), - CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck), - CLK(NULL, "func_mcasp_abe_gfclk", &func_mcasp_abe_gfclk), - CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck), - CLK(NULL, "func_mcbsp1_gfclk", &func_mcbsp1_gfclk), - CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck), - CLK(NULL, "func_mcbsp2_gfclk", &func_mcbsp2_gfclk), - CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck), - CLK(NULL, "func_mcbsp3_gfclk", &func_mcbsp3_gfclk), - CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck), - CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk), - CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk), - CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk), - CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m), - CLK(NULL, "sha2md5_fck", &sha2md5_fck), - CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1), - CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0), - CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2), - CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk), - CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1), - CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0), - CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk), - CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck), - CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck), - CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck), - CLK(NULL, "dmt1_clk_mux", &dmt1_clk_mux), - CLK(NULL, "cm2_dm10_mux", &cm2_dm10_mux), - CLK(NULL, "cm2_dm11_mux", &cm2_dm11_mux), - CLK(NULL, "cm2_dm2_mux", &cm2_dm2_mux), - CLK(NULL, "cm2_dm3_mux", &cm2_dm3_mux), - CLK(NULL, "cm2_dm4_mux", &cm2_dm4_mux), - CLK(NULL, "timer5_sync_mux", &timer5_sync_mux), - CLK(NULL, "timer6_sync_mux", &timer6_sync_mux), - CLK(NULL, "timer7_sync_mux", &timer7_sync_mux), - CLK(NULL, "timer8_sync_mux", &timer8_sync_mux), - CLK(NULL, "cm2_dm9_mux", &cm2_dm9_mux), - CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck), - CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck), - CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk), - CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk), - CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk), - CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk), - CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk), - CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk), - CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk), - CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk), - CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk), - CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk), - CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck), - CLK("usbhs_omap", "hs_fck", &usb_host_hs_fck), - CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk), - CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk), - CLK(NULL, "usb_otg_hs_ick", &usb_otg_hs_ick), - CLK("musb-omap2430", "ick", &usb_otg_hs_ick), - CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k), - CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk), - CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk), - CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk), - CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick), - CLK("usbhs_omap", "usbtll_ick", &usb_tll_hs_ick), - CLK("usbhs_tll", "usbtll_ick", &usb_tll_hs_ick), - CLK(NULL, "usim_ck", &usim_ck), - CLK(NULL, "usim_fclk", &usim_fclk), - CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck), - CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck), - CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck), - CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck), - CLK(NULL, "auxclk0_src_ck", &auxclk0_src_ck), - CLK(NULL, "auxclk0_ck", &auxclk0_ck), - CLK(NULL, "auxclkreq0_ck", &auxclkreq0_ck), - CLK(NULL, "auxclk1_src_ck", &auxclk1_src_ck), - CLK(NULL, "auxclk1_ck", &auxclk1_ck), - CLK(NULL, "auxclkreq1_ck", &auxclkreq1_ck), - CLK(NULL, "auxclk2_src_ck", &auxclk2_src_ck), - CLK(NULL, "auxclk2_ck", &auxclk2_ck), - CLK(NULL, "auxclkreq2_ck", &auxclkreq2_ck), - CLK(NULL, "auxclk3_src_ck", &auxclk3_src_ck), - CLK(NULL, "auxclk3_ck", &auxclk3_ck), - CLK(NULL, "auxclkreq3_ck", &auxclkreq3_ck), - CLK(NULL, "auxclk4_src_ck", &auxclk4_src_ck), - CLK(NULL, "auxclk4_ck", &auxclk4_ck), - CLK(NULL, "auxclkreq4_ck", &auxclkreq4_ck), - CLK(NULL, "auxclk5_src_ck", &auxclk5_src_ck), - CLK(NULL, "auxclk5_ck", &auxclk5_ck), - CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck), - CLK("50000000.gpmc", "fck", &dummy_ck), - CLK("omap_i2c.1", "ick", &dummy_ck), - CLK("omap_i2c.2", "ick", &dummy_ck), - CLK("omap_i2c.3", "ick", &dummy_ck), - CLK("omap_i2c.4", "ick", &dummy_ck), - CLK(NULL, "mailboxes_ick", &dummy_ck), - CLK("omap_hsmmc.0", "ick", &dummy_ck), - CLK("omap_hsmmc.1", "ick", &dummy_ck), - CLK("omap_hsmmc.2", "ick", &dummy_ck), - CLK("omap_hsmmc.3", "ick", &dummy_ck), - CLK("omap_hsmmc.4", "ick", &dummy_ck), - CLK("omap-mcbsp.1", "ick", &dummy_ck), - CLK("omap-mcbsp.2", "ick", &dummy_ck), - CLK("omap-mcbsp.3", "ick", &dummy_ck), - CLK("omap-mcbsp.4", "ick", &dummy_ck), - CLK("omap2_mcspi.1", "ick", &dummy_ck), - CLK("omap2_mcspi.2", "ick", &dummy_ck), - CLK("omap2_mcspi.3", "ick", &dummy_ck), - CLK("omap2_mcspi.4", "ick", &dummy_ck), - CLK(NULL, "uart1_ick", &dummy_ck), - CLK(NULL, "uart2_ick", &dummy_ck), - CLK(NULL, "uart3_ick", &dummy_ck), - CLK(NULL, "uart4_ick", &dummy_ck), - CLK("usbhs_omap", "usbhost_ick", &dummy_ck), - CLK("usbhs_omap", "usbtll_fck", &dummy_ck), - CLK("usbhs_tll", "usbtll_fck", &dummy_ck), - CLK("omap_wdt", "ick", &dummy_ck), - CLK(NULL, "timer_32k_ck", &sys_32k_ck), - /* TODO: Remove "omap_timer.X" aliases once DT migration is complete */ - CLK("omap_timer.1", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.2", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.3", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.4", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.9", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.10", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.11", "timer_sys_ck", &sys_clkin_ck), - CLK("omap_timer.5", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.6", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.7", "timer_sys_ck", &syc_clk_div_ck), - CLK("omap_timer.8", "timer_sys_ck", &syc_clk_div_ck), - CLK("4a318000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48032000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48034000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48036000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("4803e000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48086000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("48088000.timer", "timer_sys_ck", &sys_clkin_ck), - CLK("40138000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013a000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013c000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK("4013e000.timer", "timer_sys_ck", &syc_clk_div_ck), - CLK(NULL, "cpufreq_ck", &dpll_mpu_ck), -}; - -int __init omap4xxx_clk_init(void) -{ - int rc; - - if (cpu_is_omap443x()) { - cpu_mask = RATE_IN_4430; - omap_clocks_register(omap443x_clks, ARRAY_SIZE(omap443x_clks)); - } else if (cpu_is_omap446x() || cpu_is_omap447x()) { - cpu_mask = RATE_IN_4460 | RATE_IN_4430; - omap_clocks_register(omap446x_clks, ARRAY_SIZE(omap446x_clks)); - if (cpu_is_omap447x()) - pr_warn("WARNING: OMAP4470 clock data incomplete!\n"); - } else { - return 0; - } - - omap_clocks_register(omap44xx_clks, ARRAY_SIZE(omap44xx_clks)); - - omap2_clk_disable_autoidle_all(); - - /* - * A set rate of ABE DPLL inturn triggers a set rate of USB DPLL - * when its in bypass. So always lock USB before ABE DPLL. - */ - /* - * Lock USB DPLL on OMAP4 devices so that the L3INIT power - * domain can transition to retention state when not in use. - */ - rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ); - if (rc) - pr_err("%s: failed to configure USB DPLL!\n", __func__); - - /* - * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power - * state when turning the ABE clock domain. Workaround this by - * locking the ABE DPLL on boot. - * Lock the ABE DPLL in any case to avoid issues with audio. - */ - rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck); - if (!rc) - rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ); - if (rc) - pr_err("%s: failed to configure ABE DPLL!\n", __func__); - - return 0; -} diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c index 0ec9f6fdf046..7ee26108ac0d 100644 --- a/arch/arm/mach-omap2/clkt_clksel.c +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -97,12 +97,12 @@ static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val) { u32 v; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= ~clk->clksel_mask; v |= field_val << __ffs(clk->clksel_mask); - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); - v = __raw_readl(clk->clksel_reg); /* OCP barrier */ + v = omap2_clk_readl(clk, clk->clksel_reg); /* OCP barrier */ } /** @@ -204,7 +204,7 @@ static u32 _read_divisor(struct clk_hw_omap *clk) if (!clk->clksel || !clk->clksel_mask) return 0; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= clk->clksel_mask; v >>= __ffs(clk->clksel_mask); @@ -320,7 +320,7 @@ u8 omap2_clksel_find_parent_index(struct clk_hw *hw) WARN((!clk->clksel || !clk->clksel_mask), "clock: %s: attempt to call on a non-clksel clock", clk_name); - r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + r = omap2_clk_readl(clk, clk->clksel_reg) & clk->clksel_mask; r >>= __ffs(clk->clksel_mask); for (clks = clk->clksel; clks->parent && !found; clks++) { diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index 924c230f8948..47f9562ca7aa 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -196,7 +196,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw) if (!dd) return -EINVAL; - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); @@ -243,7 +243,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) return 0; /* Return bypass rate if DPLL is bypassed */ - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); @@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) return __clk_get_rate(dd->clk_bypass); } - v = __raw_readl(dd->mult_div1_reg); + v = omap2_clk_readl(clk, dd->mult_div1_reg); dpll_mult = v & dd->mult_mask; dpll_mult >>= __ffs(dd->mult_mask); dpll_div = v & dd->div1_mask; diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c index f10eb03ce3e2..333f0a666171 100644 --- a/arch/arm/mach-omap2/clkt_iclk.c +++ b/arch/arm/mach-omap2/clkt_iclk.c @@ -25,25 +25,29 @@ /* XXX */ void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) { - u32 v, r; + u32 v; + void __iomem *r; - r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - v = __raw_readl((__force void __iomem *)r); + v = omap2_clk_readl(clk, r); v |= (1 << clk->enable_bit); - __raw_writel(v, (__force void __iomem *)r); + omap2_clk_writel(v, clk, r); } /* XXX */ void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) { - u32 v, r; + u32 v; + void __iomem *r; - r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - v = __raw_readl((__force void __iomem *)r); + v = omap2_clk_readl(clk, r); v &= ~(1 << clk->enable_bit); - __raw_writel(v, (__force void __iomem *)r); + omap2_clk_writel(v, clk, r); } /* Public data */ diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index c7c5d31e9082..591581a66532 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -26,7 +26,6 @@ #include <linux/clk-private.h> #include <asm/cpu.h> - #include <trace/events/power.h> #include "soc.h" @@ -56,6 +55,31 @@ u16 cpu_mask; static bool clkdm_control = true; static LIST_HEAD(clk_hw_omap_clocks); +void __iomem *clk_memmaps[CLK_MAX_MEMMAPS]; + +void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg) +{ + if (clk->flags & MEMMAP_ADDRESSING) { + struct clk_omap_reg *r = (struct clk_omap_reg *)® + writel_relaxed(val, clk_memmaps[r->index] + r->offset); + } else { + writel_relaxed(val, reg); + } +} + +u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg) +{ + u32 val; + + if (clk->flags & MEMMAP_ADDRESSING) { + struct clk_omap_reg *r = (struct clk_omap_reg *)® + val = readl_relaxed(clk_memmaps[r->index] + r->offset); + } else { + val = readl_relaxed(reg); + } + + return val; +} /* * Used for clocks that have the same value as the parent clock, @@ -87,6 +111,7 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, /** * _wait_idlest_generic - wait for a module to leave the idle state + * @clk: module clock to wait for (needed for register offsets) * @reg: virtual address of module IDLEST register * @mask: value to mask against to determine if the module is active * @idlest: idle state indicator (0 or 1) for the clock @@ -98,14 +123,14 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, * elapsed. XXX Deprecated - should be moved into drivers for the * individual IP block that the IDLEST register exists in. */ -static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest, - const char *name) +static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, + u32 mask, u8 idlest, const char *name) { int i = 0, ena = 0; ena = (idlest) ? 0 : mask; - omap_test_timeout(((__raw_readl(reg) & mask) == ena), + omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena), MAX_MODULE_ENABLE_WAIT, i); if (i < MAX_MODULE_ENABLE_WAIT) @@ -138,7 +163,7 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) /* Not all modules have multiple clocks that their IDLEST depends on */ if (clk->ops->find_companion) { clk->ops->find_companion(clk, &companion_reg, &other_bit); - if (!(__raw_readl(companion_reg) & (1 << other_bit))) + if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit))) return; } @@ -146,8 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id); if (r) { /* IDLEST register not in the CM module */ - _wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val, - __clk_get_name(clk->hw.clk)); + _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), + idlest_val, __clk_get_name(clk->hw.clk)); } else { cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit); }; @@ -309,13 +334,13 @@ int omap2_dflt_clk_enable(struct clk_hw *hw) } /* FIXME should not have INVERT_ENABLE bit here */ - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v &= ~(1 << clk->enable_bit); else v |= (1 << clk->enable_bit); - __raw_writel(v, clk->enable_reg); - v = __raw_readl(clk->enable_reg); /* OCP barrier */ + omap2_clk_writel(v, clk, clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */ if (clk->ops && clk->ops->find_idlest) _omap2_module_wait_ready(clk); @@ -353,12 +378,12 @@ void omap2_dflt_clk_disable(struct clk_hw *hw) return; } - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v |= (1 << clk->enable_bit); else v &= ~(1 << clk->enable_bit); - __raw_writel(v, clk->enable_reg); + omap2_clk_writel(v, clk, clk->enable_reg); /* No OCP barrier needed here since it is a disable operation */ if (clkdm_control && clk->clkdm) @@ -454,7 +479,7 @@ int omap2_dflt_clk_is_enabled(struct clk_hw *hw) struct clk_hw_omap *clk = to_clk_hw_omap(hw); u32 v; - v = __raw_readl(clk->enable_reg); + v = omap2_clk_readl(clk, clk->enable_reg); if (clk->flags & INVERT_ENABLE) v ^= BIT(clk->enable_bit); @@ -520,6 +545,9 @@ int omap2_clk_enable_autoidle_all(void) list_for_each_entry(c, &clk_hw_omap_clocks, node) if (c->ops && c->ops->allow_idle) c->ops->allow_idle(c); + + of_ti_clk_allow_autoidle_all(); + return 0; } @@ -539,6 +567,9 @@ int omap2_clk_disable_autoidle_all(void) list_for_each_entry(c, &clk_hw_omap_clocks, node) if (c->ops && c->ops->deny_idle) c->ops->deny_idle(c); + + of_ti_clk_deny_autoidle_all(); + return 0; } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 82916cc82c92..bda767a9dea8 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -21,6 +21,7 @@ #include <linux/clkdev.h> #include <linux/clk-provider.h> +#include <linux/clk/ti.h> struct omap_clk { u16 cpu; @@ -37,7 +38,6 @@ struct omap_clk { } struct clockdomain; -#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \ static struct clk _name = { \ @@ -178,141 +178,6 @@ struct clksel { const struct clksel_rate *rates; }; -/** - * struct dpll_data - DPLL registers and integration data - * @mult_div1_reg: register containing the DPLL M and N bitfields - * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg - * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg - * @clk_bypass: struct clk pointer to the clock's bypass clock input - * @clk_ref: struct clk pointer to the clock's reference clock input - * @control_reg: register containing the DPLL mode bitfield - * @enable_mask: mask of the DPLL mode bitfield in @control_reg - * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() - * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() - * @last_rounded_m4xen: cache of the last M4X result of - * omap4_dpll_regm4xen_round_rate() - * @last_rounded_lpmode: cache of the last lpmode result of - * omap4_dpll_lpmode_recalc() - * @max_multiplier: maximum valid non-bypass multiplier value (actual) - * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() - * @min_divider: minimum valid non-bypass divider value (actual) - * @max_divider: maximum valid non-bypass divider value (actual) - * @modes: possible values of @enable_mask - * @autoidle_reg: register containing the DPLL autoidle mode bitfield - * @idlest_reg: register containing the DPLL idle status bitfield - * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg - * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg - * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg - * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg - * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg - * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg - * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs - * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs - * @flags: DPLL type/features (see below) - * - * Possible values for @flags: - * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) - * - * @freqsel_mask is only used on the OMAP34xx family and AM35xx. - * - * XXX Some DPLLs have multiple bypass inputs, so it's not technically - * correct to only have one @clk_bypass pointer. - * - * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m, - * @last_rounded_n) should be separated from the runtime-fixed fields - * and placed into a different structure, so that the runtime-fixed data - * can be placed into read-only space. - */ -struct dpll_data { - void __iomem *mult_div1_reg; - u32 mult_mask; - u32 div1_mask; - struct clk *clk_bypass; - struct clk *clk_ref; - void __iomem *control_reg; - u32 enable_mask; - unsigned long last_rounded_rate; - u16 last_rounded_m; - u8 last_rounded_m4xen; - u8 last_rounded_lpmode; - u16 max_multiplier; - u8 last_rounded_n; - u8 min_divider; - u16 max_divider; - u8 modes; - void __iomem *autoidle_reg; - void __iomem *idlest_reg; - u32 autoidle_mask; - u32 freqsel_mask; - u32 idlest_mask; - u32 dco_mask; - u32 sddiv_mask; - u32 lpmode_mask; - u32 m4xen_mask; - u8 auto_recal_bit; - u8 recal_en_bit; - u8 recal_st_bit; - u8 flags; -}; - -/* - * struct clk.flags possibilities - * - * XXX document the rest of the clock flags here - * - * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL - * bits share the same register. This flag allows the - * omap4_dpllmx*() code to determine which GATE_CTRL bit field - * should be used. This is a temporary solution - a better approach - * would be to associate clock type-specific data with the clock, - * similar to the struct dpll_data approach. - */ -#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ -#define CLOCK_IDLE_CONTROL (1 << 1) -#define CLOCK_NO_IDLE_PARENT (1 << 2) -#define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ -#define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ -#define CLOCK_CLKOUTX2 (1 << 5) - -/** - * struct clk_hw_omap - OMAP struct clk - * @node: list_head connecting this clock into the full clock list - * @enable_reg: register to write to enable the clock (see @enable_bit) - * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) - * @flags: see "struct clk.flags possibilities" above - * @clksel_reg: for clksel clks, register va containing src/divisor select - * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector - * @clksel: for clksel clks, pointer to struct clksel for this clock - * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock - * @clkdm_name: clockdomain name that this clock is contained in - * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime - * @rate_offset: bitshift for rate selection bitfield (OMAP1 only) - * @src_offset: bitshift for source selection bitfield (OMAP1 only) - * - * XXX @rate_offset, @src_offset should probably be removed and OMAP1 - * clock code converted to use clksel. - * - */ - -struct clk_hw_omap_ops; - -struct clk_hw_omap { - struct clk_hw hw; - struct list_head node; - unsigned long fixed_rate; - u8 fixed_div; - void __iomem *enable_reg; - u8 enable_bit; - u8 flags; - void __iomem *clksel_reg; - u32 clksel_mask; - const struct clksel *clksel; - struct dpll_data *dpll_data; - const char *clkdm_name; - struct clockdomain *clkdm; - const struct clk_hw_omap_ops *ops; -}; - struct clk_hw_omap_ops { void (*find_idlest)(struct clk_hw_omap *oclk, void __iomem **idlest_reg, @@ -348,36 +213,13 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 #define OMAP4XXX_EN_DPLL_LOCKED 0x7 -/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ -#define DPLL_LOW_POWER_STOP 0x1 -#define DPLL_LOW_POWER_BYPASS 0x5 -#define DPLL_LOCKED 0x7 - -/* DPLL Type and DCO Selection Flags */ -#define DPLL_J_TYPE 0x1 - -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); -unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); -int omap3_noncore_dpll_enable(struct clk_hw *hw); -void omap3_noncore_dpll_disable(struct clk_hw *hw); -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); void omap3_dpll_allow_idle(struct clk_hw_omap *clk); void omap3_dpll_deny_idle(struct clk_hw_omap *clk); -unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, - unsigned long parent_rate); int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk); void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); -unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate); -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate); -void omap2_init_clk_clkdm(struct clk_hw *clk); void __init omap2_clk_disable_clkdm_control(void); /* clkt_clksel.c public functions */ @@ -396,29 +238,25 @@ int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); -u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); -int omap2_dflt_clk_enable(struct clk_hw *hw); -void omap2_dflt_clk_disable(struct clk_hw *hw); -int omap2_dflt_clk_is_enabled(struct clk_hw *hw); void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, void __iomem **other_reg, u8 *other_bit); void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val); -void omap2_init_clk_hw_omap_clocks(struct clk *clk); int omap2_clk_enable_autoidle_all(void); -int omap2_clk_disable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, const char *core_ck_name, const char *mpu_ck_name); +u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg); +void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg); + extern u16 cpu_mask; extern const struct clkops clkops_omap2_dflt_wait; @@ -433,19 +271,12 @@ extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; extern struct clk dummy_ck; -extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_wait; -extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; -extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; extern const struct clk_hw_omap_ops clkhwops_apll54; extern const struct clk_hw_omap_ops clkhwops_apll96; extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; @@ -460,6 +291,8 @@ extern const struct clksel_rate div_1_3_rates[]; extern const struct clksel_rate div_1_4_rates[]; extern const struct clksel_rate div31_1to31_rates[]; +extern void __iomem *clk_memmaps[]; + extern int am33xx_clk_init(void); extern int omap2_clkops_enable_clkdm(struct clk_hw *hw); diff --git a/arch/arm/mach-omap2/clock36xx.c b/arch/arm/mach-omap2/clock36xx.c index bbd6a3f717e6..91ccb962e09e 100644 --- a/arch/arm/mach-omap2/clock36xx.c +++ b/arch/arm/mach-omap2/clock36xx.c @@ -43,6 +43,7 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) struct clk_divider *parent; struct clk_hw *parent_hw; u32 dummy_v, orig_v; + struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk); int ret; /* Clear PWRDN bit of HSDIVIDER */ @@ -53,15 +54,15 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) /* Restore the dividers */ if (!ret) { - orig_v = __raw_readl(parent->reg); + orig_v = omap2_clk_readl(omap_clk, parent->reg); dummy_v = orig_v; /* Write any other value different from the Read value */ dummy_v ^= (1 << parent->shift); - __raw_writel(dummy_v, parent->reg); + omap2_clk_writel(dummy_v, omap_clk, parent->reg); /* Write the original divider */ - __raw_writel(orig_v, parent->reg); + omap2_clk_writel(orig_v, omap_clk, parent->reg); } return ret; diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h index 8cd4b0a882ae..78d9f562e3ce 100644 --- a/arch/arm/mach-omap2/clock3xxx.h +++ b/arch/arm/mach-omap2/clock3xxx.h @@ -9,11 +9,8 @@ #define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H int omap3xxx_clk_init(void); -int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, - unsigned long parent_rate); int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); -void omap3_clk_lock_dpll5(void); extern struct clk *sdrc_ick_p; extern struct clk *arm_fck_p; diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 240db38f232c..e51527835160 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -306,7 +306,7 @@ struct omap_hwmod; extern int omap_dss_reset(struct omap_hwmod *); /* SoC specific clock initializer */ -extern int (*omap_clk_init)(void); +int omap_clk_init(void); #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 3a0296cfcace..3185ced807c9 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -50,10 +50,10 @@ static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) dd = clk->dpll_data; - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->enable_mask; v |= clken_bits << __ffs(dd->enable_mask); - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ @@ -69,8 +69,8 @@ static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) state <<= __ffs(dd->idlest_mask); - while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) && - i < MAX_DPLL_WAIT_TRIES) { + while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) + != state) && i < MAX_DPLL_WAIT_TRIES) { i++; udelay(1); } @@ -147,7 +147,7 @@ static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) state <<= __ffs(dd->idlest_mask); /* Check if already locked */ - if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state) + if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state) goto done; ai = omap3_dpll_autoidle_read(clk); @@ -311,14 +311,14 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) * only since freqsel field is no longer present on other devices. */ if (cpu_is_omap343x()) { - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* Set DPLL multiplier, divider */ - v = __raw_readl(dd->mult_div1_reg); + v = omap2_clk_readl(clk, dd->mult_div1_reg); v &= ~(dd->mult_mask | dd->div1_mask); v |= dd->last_rounded_m << __ffs(dd->mult_mask); v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); @@ -336,11 +336,11 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v |= sd_div << __ffs(dd->sddiv_mask); } - __raw_writel(v, dd->mult_div1_reg); + omap2_clk_writel(v, clk, dd->mult_div1_reg); /* Set 4X multiplier and low-power mode */ if (dd->m4xen_mask || dd->lpmode_mask) { - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); if (dd->m4xen_mask) { if (dd->last_rounded_m4xen) @@ -356,7 +356,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v &= ~dd->lpmode_mask; } - __raw_writel(v, dd->control_reg); + omap2_clk_writel(v, clk, dd->control_reg); } /* We let the clock framework set the other output dividers later */ @@ -554,7 +554,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return -EINVAL; - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= dd->autoidle_mask; v >>= __ffs(dd->autoidle_mask); @@ -588,10 +588,10 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk) * by writing 0x5 instead of 0x1. Add some mechanism to * optionally enter this mode. */ - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); - __raw_writel(v, dd->autoidle_reg); + omap2_clk_writel(v, clk, dd->autoidle_reg); } @@ -614,10 +614,10 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return; - v = __raw_readl(dd->autoidle_reg); + v = omap2_clk_readl(clk, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); - __raw_writel(v, dd->autoidle_reg); + omap2_clk_writel(v, clk, dd->autoidle_reg); } @@ -639,6 +639,9 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, struct clk_hw_omap *pclk = NULL; struct clk *parent; + if (!parent_rate) + return 0; + /* Walk up the parents of clk, looking for a DPLL */ do { do { @@ -660,7 +663,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, WARN_ON(!dd->enable_mask); - v = __raw_readl(dd->control_reg) & dd->enable_mask; + v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; v >>= __ffs(dd->enable_mask); if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) rate = parent_rate; diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index d28b0f726715..52f9438b92f2 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -42,7 +42,7 @@ int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); v &= mask; v >>= __ffs(mask); @@ -61,10 +61,10 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); /* Clear the bit to allow gatectrl */ v &= ~mask; - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); } void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) @@ -79,10 +79,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = __raw_readl(clk->clksel_reg); + v = omap2_clk_readl(clk, clk->clksel_reg); /* Set the bit to deny gatectrl */ v |= mask; - __raw_writel(v, clk->clksel_reg); + omap2_clk_writel(v, clk, clk->clksel_reg); } const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { @@ -140,7 +140,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, rate = omap2_get_dpll_rate(clk); /* regm4xen adds a multiplier of 4 to DPLL calculations */ - v = __raw_readl(dd->control_reg); + v = omap2_clk_readl(clk, dd->control_reg); if (v & OMAP4430_DPLL_REGM4XEN_MASK) rate *= OMAP4430_REGM4XEN_MULT; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 07b68d5a7940..47381fd8746f 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -55,10 +55,10 @@ #include "prm44xx.h" /* - * omap_clk_init: points to a function that does the SoC-specific + * omap_clk_soc_init: points to a function that does the SoC-specific * clock initializations */ -int (*omap_clk_init)(void); +static int (*omap_clk_soc_init)(void); /* * The machine specific code may provide the extra mapping besides the @@ -419,7 +419,7 @@ void __init omap2420_init_early(void) omap242x_clockdomains_init(); omap2420_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap2420_clk_init; + omap_clk_soc_init = omap2420_clk_init; } void __init omap2420_init_late(void) @@ -448,7 +448,7 @@ void __init omap2430_init_early(void) omap243x_clockdomains_init(); omap2430_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap2430_clk_init; + omap_clk_soc_init = omap2430_clk_init; } void __init omap2430_init_late(void) @@ -482,27 +482,35 @@ void __init omap3_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap3xxx_clk_init; + omap_clk_soc_init = omap3xxx_clk_init; } void __init omap3430_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3430_dt_clk_init; } void __init omap35xx_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3430_dt_clk_init; } void __init omap3630_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = omap3630_dt_clk_init; } void __init am35xx_init_early(void) { omap3_init_early(); + if (of_have_populated_dt()) + omap_clk_soc_init = am35xx_dt_clk_init; } void __init ti81xx_init_early(void) @@ -520,7 +528,10 @@ void __init ti81xx_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap3xxx_clk_init; + if (of_have_populated_dt()) + omap_clk_soc_init = ti81xx_dt_clk_init; + else + omap_clk_soc_init = omap3xxx_clk_init; } void __init omap3_init_late(void) @@ -581,7 +592,7 @@ void __init am33xx_init_early(void) am33xx_clockdomains_init(); am33xx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = am33xx_clk_init; + omap_clk_soc_init = am33xx_dt_clk_init; } void __init am33xx_init_late(void) @@ -606,6 +617,7 @@ void __init am43xx_init_early(void) am43xx_clockdomains_init(); am43xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = am43xx_dt_clk_init; } void __init am43xx_init_late(void) @@ -635,7 +647,7 @@ void __init omap4430_init_early(void) omap44xx_clockdomains_init(); omap44xx_hwmod_init(); omap_hwmod_init_postsetup(); - omap_clk_init = omap4xxx_clk_init; + omap_clk_soc_init = omap4xxx_dt_clk_init; } void __init omap4430_init_late(void) @@ -666,6 +678,7 @@ void __init omap5_init_early(void) omap54xx_clockdomains_init(); omap54xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = omap5xxx_dt_clk_init; } void __init omap5_init_late(void) @@ -691,6 +704,7 @@ void __init dra7xx_init_early(void) dra7xx_clockdomains_init(); dra7xx_hwmod_init(); omap_hwmod_init_postsetup(); + omap_clk_soc_init = dra7xx_dt_clk_init; } void __init dra7xx_init_late(void) @@ -710,3 +724,17 @@ void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, _omap2_init_reprogram_sdrc(); } } + +int __init omap_clk_init(void) +{ + int ret = 0; + + if (!omap_clk_soc_init) + return 0; + + ret = of_prcm_init(); + if (!ret) + ret = omap_clk_soc_init(); + + return ret; +} diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f7a6fd35b1e4..42d81885c700 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -686,6 +686,8 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh) if (oh->clkdm) { return oh->clkdm; } else if (oh->_clk) { + if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC) + return NULL; clk = to_clk_hw_omap(__clk_get_hw(oh->_clk)); return clk->clkdm; } @@ -1576,7 +1578,7 @@ static int _init_clkdm(struct omap_hwmod *oh) if (!oh->clkdm) { pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n", oh->name, oh->clkdm_name); - return -EINVAL; + return 0; } pr_debug("omap_hwmod: %s: associated to clkdm %s\n", @@ -4231,6 +4233,7 @@ void __init omap_hwmod_init(void) soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; + soc_ops.init_clkdm = _init_clkdm; } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) { soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index ac25ae6667cf..623db40fdbbd 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -18,6 +18,7 @@ # ifndef __ASSEMBLER__ extern void __iomem *prm_base; extern void omap2_set_globals_prm(void __iomem *prm); +int of_prcm_init(void); # endif diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index a2e1174ad1b6..b4c4ab9c8044 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -23,6 +23,10 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> #include "soc.h" #include "prm2xxx_3xxx.h" @@ -30,6 +34,7 @@ #include "prm3xxx.h" #include "prm44xx.h" #include "common.h" +#include "clock.h" /* * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs @@ -464,3 +469,64 @@ int prm_unregister(struct prm_ll_data *pld) return 0; } + +static struct of_device_id omap_prcm_dt_match_table[] = { + { .compatible = "ti,am3-prcm" }, + { .compatible = "ti,am3-scrm" }, + { .compatible = "ti,am4-prcm" }, + { .compatible = "ti,am4-scrm" }, + { .compatible = "ti,omap3-prm" }, + { .compatible = "ti,omap3-cm" }, + { .compatible = "ti,omap3-scrm" }, + { .compatible = "ti,omap4-cm1" }, + { .compatible = "ti,omap4-prm" }, + { .compatible = "ti,omap4-cm2" }, + { .compatible = "ti,omap4-scrm" }, + { .compatible = "ti,omap5-prm" }, + { .compatible = "ti,omap5-cm-core-aon" }, + { .compatible = "ti,omap5-scrm" }, + { .compatible = "ti,omap5-cm-core" }, + { .compatible = "ti,dra7-prm" }, + { .compatible = "ti,dra7-cm-core-aon" }, + { .compatible = "ti,dra7-cm-core" }, + { } +}; + +static struct clk_hw_omap memmap_dummy_ck = { + .flags = MEMMAP_ADDRESSING, +}; + +static u32 prm_clk_readl(void __iomem *reg) +{ + return omap2_clk_readl(&memmap_dummy_ck, reg); +} + +static void prm_clk_writel(u32 val, void __iomem *reg) +{ + omap2_clk_writel(val, &memmap_dummy_ck, reg); +} + +static struct ti_clk_ll_ops omap_clk_ll_ops = { + .clk_readl = prm_clk_readl, + .clk_writel = prm_clk_writel, +}; + +int __init of_prcm_init(void) +{ + struct device_node *np; + void __iomem *mem; + int memmap_index = 0; + + ti_clk_ll_ops = &omap_clk_ll_ops; + + for_each_matching_node(np, omap_prcm_dt_match_table) { + mem = of_iomap(np, 0); + clk_memmaps[memmap_index] = mem; + ti_dt_clk_init_provider(np, memmap_index); + memmap_index++; + } + + ti_dt_clockdomains_setup(); + + return 0; +} diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index ec084d158f64..74044aaf438b 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -570,8 +570,7 @@ static inline void __init realtime_counter_init(void) clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_gptimer_timer_init(void) \ { \ - if (omap_clk_init) \ - omap_clk_init(); \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ @@ -582,8 +581,7 @@ void __init omap##name##_gptimer_timer_init(void) \ clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_sync32k_timer_init(void) \ { \ - if (omap_clk_init) \ - omap_clk_init(); \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ /* Enable the use of clocksource="gp_timer" kernel parameter */ \ diff --git a/arch/arm/plat-samsung/include/plat/regs-nand.h b/arch/arm/plat-samsung/include/plat/regs-nand.h deleted file mode 100644 index 238efea7b9e4..000000000000 --- a/arch/arm/plat-samsung/include/plat/regs-nand.h +++ /dev/null @@ -1,123 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-nand.h - * - * Copyright (c) 2004-2005 Simtec Electronics <linux@simtec.co.uk> - * http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2410 NAND register definitions -*/ - -#ifndef __ASM_ARM_REGS_NAND -#define __ASM_ARM_REGS_NAND - - -#define S3C2410_NFREG(x) (x) - -#define S3C2410_NFCONF S3C2410_NFREG(0x00) -#define S3C2410_NFCMD S3C2410_NFREG(0x04) -#define S3C2410_NFADDR S3C2410_NFREG(0x08) -#define S3C2410_NFDATA S3C2410_NFREG(0x0C) -#define S3C2410_NFSTAT S3C2410_NFREG(0x10) -#define S3C2410_NFECC S3C2410_NFREG(0x14) - -#define S3C2440_NFCONT S3C2410_NFREG(0x04) -#define S3C2440_NFCMD S3C2410_NFREG(0x08) -#define S3C2440_NFADDR S3C2410_NFREG(0x0C) -#define S3C2440_NFDATA S3C2410_NFREG(0x10) -#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) -#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) -#define S3C2440_NFECCD S3C2410_NFREG(0x1C) -#define S3C2440_NFSTAT S3C2410_NFREG(0x20) -#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) -#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) -#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) -#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) -#define S3C2440_NFSECC S3C2410_NFREG(0x34) -#define S3C2440_NFSBLK S3C2410_NFREG(0x38) -#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) - -#define S3C2412_NFSBLK S3C2410_NFREG(0x20) -#define S3C2412_NFEBLK S3C2410_NFREG(0x24) -#define S3C2412_NFSTAT S3C2410_NFREG(0x28) -#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) -#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) -#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) -#define S3C2412_NFMECC1 S3C2410_NFREG(0x38) -#define S3C2412_NFSECC S3C2410_NFREG(0x3C) - -#define S3C2410_NFCONF_EN (1<<15) -#define S3C2410_NFCONF_512BYTE (1<<14) -#define S3C2410_NFCONF_4STEP (1<<13) -#define S3C2410_NFCONF_INITECC (1<<12) -#define S3C2410_NFCONF_nFCE (1<<11) -#define S3C2410_NFCONF_TACLS(x) ((x)<<8) -#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) -#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) - -#define S3C2410_NFSTAT_BUSY (1<<0) - -#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0) -#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0) -#define S3C2440_NFCONF_ADVFLASH (1<<3) -#define S3C2440_NFCONF_TACLS(x) ((x)<<12) -#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) -#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) - -#define S3C2440_NFCONT_LOCKTIGHT (1<<13) -#define S3C2440_NFCONT_SOFTLOCK (1<<12) -#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10) -#define S3C2440_NFCONT_RNBINT_EN (1<<9) -#define S3C2440_NFCONT_RN_FALLING (1<<8) -#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6) -#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5) -#define S3C2440_NFCONT_INITECC (1<<4) -#define S3C2440_NFCONT_nFCE (1<<1) -#define S3C2440_NFCONT_ENABLE (1<<0) - -#define S3C2440_NFSTAT_READY (1<<0) -#define S3C2440_NFSTAT_nCE (1<<1) -#define S3C2440_NFSTAT_RnB_CHANGE (1<<2) -#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3) - -#define S3C2412_NFCONF_NANDBOOT (1<<31) -#define S3C2412_NFCONF_ECCCLKCON (1<<30) -#define S3C2412_NFCONF_ECC_MLC (1<<24) -#define S3C2412_NFCONF_TACLS_MASK (7<<12) /* 1 extra bit of Tacls */ - -#define S3C2412_NFCONT_ECC4_DIRWR (1<<18) -#define S3C2412_NFCONT_LOCKTIGHT (1<<17) -#define S3C2412_NFCONT_SOFTLOCK (1<<16) -#define S3C2412_NFCONT_ECC4_ENCINT (1<<13) -#define S3C2412_NFCONT_ECC4_DECINT (1<<12) -#define S3C2412_NFCONT_MAIN_ECC_LOCK (1<<7) -#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) -#define S3C2412_NFCONT_nFCE1 (1<<2) -#define S3C2412_NFCONT_nFCE0 (1<<1) - -#define S3C2412_NFSTAT_ECC_ENCDONE (1<<7) -#define S3C2412_NFSTAT_ECC_DECDONE (1<<6) -#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1<<5) -#define S3C2412_NFSTAT_RnB_CHANGE (1<<4) -#define S3C2412_NFSTAT_nFCE1 (1<<3) -#define S3C2412_NFSTAT_nFCE0 (1<<2) -#define S3C2412_NFSTAT_Res1 (1<<1) -#define S3C2412_NFSTAT_READY (1<<0) - -#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) -#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) -#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) -#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) -#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_NONE (0) -#define S3C2412_NFECCERR_1BIT (1) -#define S3C2412_NFECCERR_MULTIBIT (2) -#define S3C2412_NFECCERR_ECCAREA (3) - - - -#endif /* __ASM_ARM_REGS_NAND */ - diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 396193042127..4f424ae3b36d 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -17,7 +17,7 @@ #ifdef CONFIG_MTD_UCLINUX #include <linux/mtd/map.h> #include <linux/ext2_fs.h> -#include <linux/cramfs_fs.h> +#include <uapi/linux/cramfs_fs.h> #include <linux/romfs_fs.h> #endif diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 9c957c81c688..ed0fcdf7e990 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -122,12 +122,6 @@ config ETRAX100LX_V2 help Support version 2 of the ETRAX 100LX. -config SVINTO_SIM - bool "ETRAX-100LX-for-xsim-simulator" - select ARCH_USES_GETTIMEOFFSET - help - Support the xsim ETRAX Simulator. - config ETRAXFS bool "ETRAX-FS-V32" help diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index 609d5510410e..f4374bae4fb4 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -838,13 +838,13 @@ static int __init gpio_init(void) * in some tests. */ res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name); + IRQF_SHARED, "gpio poll", gpio_name); if (res) { printk(KERN_CRIT "err: timer0 irq for gpio\n"); return res; } res = request_irq(PA_IRQ_NBR, gpio_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name); + IRQF_SHARED, "gpio PA", gpio_name); if (res) printk(KERN_CRIT "err: PA irq for gpio\n"); diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c index a1c498d18d31..29eb02ab3f25 100644 --- a/arch/cris/arch-v10/drivers/sync_serial.c +++ b/arch/cris/arch-v10/drivers/sync_serial.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/timer.h> +#include <linux/wait.h> #include <asm/irq.h> #include <asm/dma.h> #include <asm/io.h> @@ -580,7 +581,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) if (port == &ports[0]) { if (request_irq(8, manual_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "synchronous serial manual irq", &ports[0])) { printk(KERN_CRIT "Can't alloc " @@ -590,7 +591,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) } else if (port == &ports[1]) { if (request_irq(8, manual_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "synchronous serial manual irq", &ports[1])) { printk(KERN_CRIT "Can't alloc " @@ -1136,7 +1137,8 @@ static ssize_t sync_serial_read(struct file *file, char *buf, if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); if (signal_pending(current)) return -EINTR; diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile index dcfec41d3533..4841e822cdd1 100644 --- a/arch/cris/arch-v10/kernel/Makefile +++ b/arch/cris/arch-v10/kernel/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $ # # Makefile for the linux kernel. # diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index f932c85fbde4..7d307cce8bd8 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/tty.h> #include <arch/svinto.h> -#include <asm/io.h> /* Get SIMCOUT. */ extern void reset_watchdog(void); @@ -318,12 +317,6 @@ console_write(struct console *co, const char *buf, unsigned int len) if (!port) return; -#ifdef CONFIG_SVINTO_SIM - /* no use to simulate the serial debug output */ - SIMCOUT(buf, len); - return; -#endif - console_write_direct(co, buf, len); } diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 897bba67bf7a..81570fcd0412 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -13,8 +13,8 @@ * after a timer-interrupt and after each system call. * * Stack layout in 'ret_from_system_call': - * ptrace needs to have all regs on the stack. - * if the order here is changed, it needs to be + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be * updated in fork.c:copy_process, signal.c:do_signal, * ptrace.c and ptrace.h * @@ -31,7 +31,7 @@ #include <asm/pgtable.h> ;; functions exported from this file - + .globl system_call .globl ret_from_intr .globl ret_from_fork @@ -46,10 +46,10 @@ .globl do_sigtrap .globl gdb_handle_breakpoint .globl sys_call_table - + ;; below are various parts of system_call which are not in the fast-path - -#ifdef CONFIG_PREEMPT + +#ifdef CONFIG_PREEMPT ; Check if preemptive kernel scheduling should be done _resume_kernel: di @@ -74,7 +74,7 @@ _need_resched: nop #else #define _resume_kernel _Rexit -#endif +#endif ; Called at exit from fork. schedule_tail must be called to drop ; spinlock if CONFIG_PREEMPT @@ -91,16 +91,16 @@ ret_from_kernel_thread: ba ret_from_sys_call ret_from_intr: - ;; check for resched if preemptive kernel or if we're going back to user-mode + ;; check for resched if preemptive kernel or if we're going back to user-mode ;; this test matches the user_regs(regs) macro ;; we cannot simply test $dccr, because that does not necessarily ;; reflect what mode we'll return into. - + move.d [$sp + PT_dccr], $r0; regs->dccr btstq 8, $r0 ; U-flag bpl _resume_kernel - ; Note that di below is in delay slot - + ; Note that di below is in delay slot + _resume_userspace: di ; so need_resched and sigpending don't change @@ -113,7 +113,7 @@ _resume_userspace: nop ba _Rexit nop - + ;; The system_call is called by a BREAK instruction, which works like ;; an interrupt call but it stores the return PC in BRP instead of IRP. ;; Since we dont really want to have two epilogues (one for system calls @@ -123,7 +123,7 @@ _resume_userspace: ;; ;; Since we can't have system calls inside interrupts, it should not matter ;; that we don't stack IRP. - ;; + ;; ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp ;; ;; This function looks on the _surface_ like spaghetti programming, but it's @@ -140,7 +140,7 @@ system_call: movem $r13, [$sp] ; push r0-r13 push $r10 ; push orig_r10 clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe - + movs.w -ENOSYS, $r0 move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame @@ -148,17 +148,17 @@ system_call: movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 - + move.d [$r0+TI_flags], $r0 btstq TIF_SYSCALL_TRACE, $r0 bmi _syscall_trace_entry - nop + nop -_syscall_traced: +_syscall_traced: ;; check for sanity in the requested syscall number - - cmpu.w NR_syscalls, $r9 + + cmpu.w NR_syscalls, $r9 bcc ret_from_sys_call lslq 2, $r9 ; multiply by 4, in the delay slot @@ -166,28 +166,28 @@ _syscall_traced: ;; of the register structure itself. some syscalls need this. push $sp - + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. - ;; the fifth and sixth parameters (if any) was in mof and srp + ;; the fifth and sixth parameters (if any) was in mof and srp ;; respectively, and we need to put them on the stack. push $srp push $mof - + jsr [$r9+sys_call_table] ; actually do the system call addq 3*4, $sp ; pop the mof, srp and regs parameters move.d $r10, [$sp+PT_r10] ; save the return value moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call - + ;; fall through into ret_from_sys_call to return - + ret_from_sys_call: ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq - + ;; get the current task-struct pointer (see top for defs) - movs.w -8192, $r0 ; THREAD_SIZE == 8192 + movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 di ; make sure need_resched and sigpending don't change @@ -202,7 +202,7 @@ _Rexit: bne _RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise addq 4, $sp ; skip orig_r10, in delayslot movem [$sp+], $r13 ; registers r0-r13 - pop $mof ; multiply overflow register + pop $mof ; multiply overflow register pop $dccr ; condition codes pop $srp ; subroutine return pointer ;; now we have a 4-word SBFS frame which we do not want to restore @@ -216,14 +216,14 @@ _Rexit: _RBFexit: movem [$sp+], $r13 ; registers r0-r13, in delay slot - pop $mof ; multiply overflow register + pop $mof ; multiply overflow register pop $dccr ; condition codes pop $srp ; subroutine return pointer rbf [$sp+] ; return by popping the CPU status ;; We get here after doing a syscall if extra work might need to be done ;; perform syscall exit tracing if needed - + _syscall_exit_work: ;; $r0 contains current at this point and irq's are disabled @@ -231,22 +231,22 @@ _syscall_exit_work: btstq TIF_SYSCALL_TRACE, $r1 bpl _work_pending nop - + ei move.d $r9, $r1 ; preserve r9 jsr do_syscall_trace move.d $r1, $r9 - + ba _resume_userspace nop - + _work_pending: move.d [$r0+TI_flags], $r1 btstq TIF_NEED_RESCHED, $r1 bpl _work_notifysig ; was neither trace nor sched, must be signal/notify nop - + _work_resched: move.d $r9, $r1 ; preserve r9 jsr schedule @@ -268,17 +268,17 @@ _work_notifysig: move.d $sp, $r11 ; the regs param move.d $r1, $r12 ; the thread_info_flags parameter jsr do_notify_resume - + ba _Rexit nop ;; We get here as a sidetrack when we've entered a syscall with the ;; trace-bit set. We need to call do_syscall_trace and then continue ;; with the call. - + _syscall_trace_entry: ;; PT_r10 in the frame contains -ENOSYS as required, at this point - + jsr do_syscall_trace ;; now re-enter the syscall code to do the syscall itself @@ -292,10 +292,10 @@ _syscall_trace_entry: move.d [$sp+PT_r13], $r13 move [$sp+PT_mof], $mof move [$sp+PT_srp], $srp - + ba _syscall_traced nop - + ;; resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct ;; returns old current in r10 @@ -303,29 +303,29 @@ _syscall_trace_entry: ;; TODO: see the i386 version. The switch_to which calls resume in our version ;; could really be an inline asm of this. -resume: - push $srp ; we keep the old/new PC on the stack +resume: + push $srp ; we keep the old/new PC on the stack add.d $r12, $r10 ; r10 = current tasks tss move $dccr, [$r10+THREAD_dccr]; save irq enable state di move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer - + ;; See copy_thread for the reason why register R9 is saved. subq 10*4, $sp movem $r9, [$sp] ; save non-scratch registers and R9. - + move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task move.d $sp, $r10 ; return last running task in r10 and.d -8192, $r10 ; get thread_info from stackpointer - move.d [$r10+TI_task], $r10 ; get task + move.d [$r10+TI_task], $r10 ; get task add.d $r12, $r11 ; find the new tasks tss move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp movem [$sp+], $r9 ; restore non-scratch registers and R9. move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer - + move [$r11+THREAD_dccr], $dccr ; restore irq enable status jump [$sp+] ; restore PC @@ -401,7 +401,7 @@ mmu_bus_fault: push $r10 ; frametype == 1, BUSFAULT frame type move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault - + jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c ;; now we need to return through the normal path, we cannot just @@ -410,10 +410,10 @@ mmu_bus_fault: ;; whatever. moveq 0, $r9 ; busfault is equivalent to an irq - + ba ret_from_intr nop - + ;; special handlers for breakpoint and NMI hwbreakpoint: push $dccr @@ -429,7 +429,7 @@ hwbreakpoint: pop $dccr retb nop - + IRQ1_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame @@ -457,7 +457,7 @@ IRQ1_interrupt: ba _Rexit ; Return the standard way nop wdog: -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) ;; Check if we're waiting for reset to happen, as signalled by ;; hard_reset_now setting cause_of_death to a magic value. If so, just ;; get stuck until reset happens. @@ -500,7 +500,7 @@ Watchdog_bite: move.d $r10, [$r11] #endif - + ;; Note that we don't do "setf m" here (or after two necessary NOPs), ;; since *not* doing that saves us from re-entrancy checks. We don't want ;; to get here again due to possible subsequent NMIs; we want the watchdog @@ -523,16 +523,16 @@ _watchdogmsg: .ascii "Oops: bitten by watchdog\n\0" .previous -#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */ +#endif /* CONFIG_ETRAX_WATCHDOG */ -spurious_interrupt: +spurious_interrupt: di jump hard_reset_now ;; this handles the case when multiple interrupts arrive at the same time ;; we jump to the first set interrupt bit in a priority fashion ;; the hardware will call the unserved interrupts after the handler finishes - + multiple_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame @@ -551,7 +551,7 @@ multiple_interrupt: jump ret_from_intr do_sigtrap: - ;; + ;; ;; SIGTRAP the process that executed the break instruction. ;; Make a frame that Rexit in entry.S expects. ;; @@ -568,30 +568,30 @@ do_sigtrap: movs.w -8192,$r9 ; THREAD_SIZE == 8192 and.d $sp, $r9 move.d [$r9+TI_task], $r10 - move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. + move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. moveq 5, $r11 ; SIGTRAP as arg2. - jsr sys_kill + jsr sys_kill jump ret_from_intr ; Use the return routine for interrupts. -gdb_handle_breakpoint: +gdb_handle_breakpoint: push $dccr push $r0 #ifdef CONFIG_ETRAX_KGDB - move $dccr, $r0 ; U-flag not affected by previous insns. + move $dccr, $r0 ; U-flag not affected by previous insns. btstq 8, $r0 ; Test the U-flag. - bmi _ugdb_handle_breakpoint ; Go to user mode debugging. - nop ; Empty delay slot (cannot pop r0 here). + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Empty delay slot (cannot pop r0 here). pop $r0 ; Restore r0. - ba kgdb_handle_breakpoint ; Go to kernel debugging. + ba kgdb_handle_breakpoint ; Go to kernel debugging. pop $dccr ; Restore dccr in delay slot. #endif - -_ugdb_handle_breakpoint: + +_ugdb_handle_breakpoint: move $brp, $r0 ; Use r0 temporarily for calculation. subq 2, $r0 ; Set to address of previous instruction. move $r0, $brp - pop $r0 ; Restore r0. - ba do_sigtrap ; SIGTRAP the offending process. + pop $r0 ; Restore r0. + ba do_sigtrap ; SIGTRAP the offending process. pop $dccr ; Restore dccr in delay slot. .data @@ -602,7 +602,7 @@ hw_bp_trig_ptr: .dword hw_bp_trigs .section .rodata,"a" -sys_call_table: +sys_call_table: .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork @@ -713,7 +713,7 @@ sys_call_table: .long sys_newlstat .long sys_newfstat .long sys_ni_syscall /* old sys_uname holder */ - .long sys_ni_syscall /* sys_iopl in i386 */ + .long sys_ni_syscall /* 110 */ /* sys_iopl in i386 */ .long sys_vhangup .long sys_ni_syscall /* old "idle" system call */ .long sys_ni_syscall /* vm86old in i386 */ @@ -730,7 +730,7 @@ sys_call_table: .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module .long sys_ni_syscall /* 130: old "get_kernel_syms" */ @@ -795,7 +795,7 @@ sys_call_table: .long sys_ni_syscall /* streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap2 + .long sys_mmap2 /* mmap_pgoff */ .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ @@ -861,21 +861,21 @@ sys_call_table: .long sys_epoll_ctl /* 255 */ .long sys_epoll_wait .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 260 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 265 */ - .long sys_clock_getres - .long sys_clock_nanosleep + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 270 */ + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ .long sys_utimes - .long sys_fadvise64_64 + .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ .long sys_ni_syscall /* sys_mbind */ .long sys_ni_syscall /* 275 sys_get_mempolicy */ @@ -886,7 +886,7 @@ sys_call_table: .long sys_mq_timedreceive /* 280 */ .long sys_mq_notify .long sys_mq_getsetattr - .long sys_ni_syscall /* reserved for kexec */ + .long sys_ni_syscall .long sys_waitid .long sys_ni_syscall /* 285 */ /* available */ .long sys_add_key @@ -939,6 +939,22 @@ sys_call_table: .long sys_preadv .long sys_pwritev .long sys_setns /* 335 */ + .long sys_name_to_handle_at + .long sys_open_by_handle_at + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_recvmmsg /* 340 */ + .long sys_accept4 + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 + .long sys_clock_adjtime /* 345 */ + .long sys_syncfs + .long sys_sendmmsg + .long sys_process_vm_readv + .long sys_process_vm_writev + .long sys_kcmp /* 350 */ + .long sys_finit_module /* * NOTE!! This doesn't have to be exact - we just have @@ -950,4 +966,4 @@ sys_call_table: .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr - + diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index a1f2014b4e3b..4a146e1749c9 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,12 +1,10 @@ /* * Head of the kernel - alter with care * - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000, 2001, 2010 Axis Communications AB * - * Authors: Bjorn Wesen (bjornw@axis.com) - * */ - + #define ASSEMBLER_MACROS_ONLY /* The IO_* macros use the ## token concatenation operator, so -traditional must not be used when assembling this file. */ @@ -18,15 +16,15 @@ #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) - + ;; exported symbols - + .globl etrax_irv .globl romfs_start .globl romfs_length .globl romfs_in_flash .globl swapper_pg_dir - + .text ;; This is the entry point of the kernel. We are in supervisor mode. @@ -35,10 +33,10 @@ ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; ;; NOTICE! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). + ;; information from the decompressor (if the kernel was compressed). ;; They should not be used in the code below until read. - - nop + + nop di ;; First setup the kseg_c mapping from where the kernel is linked @@ -58,19 +56,19 @@ #ifdef CONFIG_CRIS_LOW_MAP ; kseg mappings, temporary map of 0xc0->0x40 - move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ + move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \ | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \ | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0 move.d $r0, [R_MMU_KBASE_HI] - ; temporary map of 0x40->0x40 and 0x60->0x40 - move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ + ; temporary map of 0x40->0x40 and 0x60->0x40 + move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 move.d $r0, [R_MMU_KBASE_LO] ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped - move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ @@ -93,17 +91,17 @@ move.d $r0, [R_MMU_CONFIG] #else ; kseg mappings - move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ + move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0 move.d $r0, [R_MMU_KBASE_HI] - ; temporary map of 0x40->0x40 and 0x00->0x00 + ; temporary map of 0x40->0x40 and 0x00->0x00 move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 move.d $r0, [R_MMU_KBASE_LO] ; mmu enable, segs f,e,c,b,4,0 segment mapped - move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ @@ -141,12 +139,12 @@ ;; ;; In both cases, we start in un-cached mode, and need to jump into a ;; cached PC after we're done fiddling around with the segments. - ;; + ;; ;; arch/etrax100/etrax100.ld sets some symbols that define the start ;; and end of each segment. ;; Check if we start from DRAM or FLASH by testing PC - + move.d $pc,$r0 and.d 0x7fffffff,$r0 ; get rid of the non-cache bit cmp.d 0x10000,$r0 ; arbitrary... just something above this code @@ -163,30 +161,28 @@ _inflash0: ;; after init. .section ".init.text", "ax" _inflash: -#ifdef CONFIG_ETRAX_ETHERNET +#ifdef CONFIG_ETRAX_ETHERNET ;; Start MII clock to make sure it is running when tranceiver is reset move.d START_ETHERNET_CLOCK, $r0 move.d $r0, [R_NETWORK_GEN_CONFIG] #endif ;; Set up waitstates etc according to kernel configuration. -#ifndef CONFIG_SVINTO_SIM move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 move.d $r0, [R_WAITSTATES] move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 move.d $r0, [R_BUS_CONFIG] -#endif ;; We need to initialze DRAM registers before we start using the DRAM cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? beq _dram_init_finished nop - + #include "../lib/dram_init.S" -_dram_init_finished: +_dram_init_finished: ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -198,7 +194,7 @@ _dram_init_finished: ;; between the physical start of the flash and the flash-image start, ;; and when run with compression, the kernel is actually unpacked to ;; DRAM and we never get here in the first place :)) - + moveq 0, $r0 ; source move.d text_start, $r1 ; destination move.d __vmlinux_end, $r2 ; end destination @@ -229,10 +225,10 @@ _dram_init_finished: add.d 0xf0000000, $r4 ; add flash start in virtual memory (cached) #endif move.d $r4, [romfs_start] -1: +1: moveq 1, $r0 move.d $r0, [romfs_in_flash] - + jump _start_it ; enter code, cached this time _inram: @@ -241,7 +237,7 @@ _inram: moveq 0, $r0 move.d $r0, [romfs_length] ; default if there is no cramfs - + ;; The kernel could have been unpacked to DRAM by the loader, but ;; the cramfs image could still be in the Flash directly after the ;; compressed kernel image. The loader passes the address of the @@ -251,7 +247,7 @@ _inram: ;; (Notice that if this is not booted from the loader, r9 will be ;; garbage but we do sanity checks on it, the chance that it points ;; to a cramfs magic is small.. ) - + cmp.d 0x0ffffff8, $r9 bhs _no_romfs_in_flash ; r9 points outside the flash area nop @@ -274,7 +270,7 @@ _inram: jump _start_it ; enter code, cached this time _no_romfs_in_flash: - + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does @@ -286,8 +282,8 @@ _no_romfs_in_flash: bne 2f nop - ;; Ok. What is its size ? - + ;; Ok. What is its size ? + move.d [$r0 + 4], $r2 ; cramfs_super.size (again, no need to swapwb) ;; We want to copy it to the end of the BSS @@ -303,7 +299,7 @@ _no_romfs_in_flash: add.d $r2, $r0 add.d $r2, $r1 - + ;; Go ahead. Make my loop. lsrq 1, $r2 ; size is in bytes, we copy words @@ -314,14 +310,14 @@ _no_romfs_in_flash: bne 1b nop -2: +2: ;; Dont worry that the BSS is tainted. It will be cleared later. moveq 0, $r0 move.d $r0, [romfs_in_flash] jump _start_it ; better skip the additional cramfs check below - + _start_it: ;; Check if kernel command line is supplied @@ -348,7 +344,7 @@ no_command_line: move.d ibr_start,$r0 ; this symbol is set by the linker script move $r0,$ibr move.d $r0,[etrax_irv] ; set the interrupt base register and pointer - + ;; Clear BSS region, from _bss_start to _end move.d __bss_start, $r0 @@ -357,7 +353,7 @@ no_command_line: cmp.d $r1, $r0 blo 1b nop - + #ifdef CONFIG_BLK_DEV_ETRAXIDE ;; disable ATA before enabling it in genconfig below moveq 0,$r0 @@ -380,7 +376,7 @@ no_command_line: #ifdef CONFIG_JULIETTE ;; configure external DMA channel 0 before enabling it in genconfig - + moveq 0,$r0 move.d $r0,[R_EXT_DMA_0_ADDR] ; cnt enable, word size, output, stop, size 0 @@ -395,7 +391,7 @@ no_command_line: move.d $r0,[R_EXT_DMA_0_CMD] ;; reset dma4 and wait for completion - + moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH4_CMD] 1: move.b [R_DMA_CH4_CMD],$r0 @@ -405,7 +401,7 @@ no_command_line: nop ;; reset dma5 and wait for completion - + moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH5_CMD] 1: move.b [R_DMA_CH5_CMD],$r0 @@ -413,8 +409,8 @@ no_command_line: cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 beq 1b nop -#endif - +#endif + ;; Etrax product HW genconfig setup moveq 0,$r0 @@ -468,7 +464,6 @@ no_command_line: move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG -#ifndef CONFIG_SVINTO_SIM move.d $r0,[R_GEN_CONFIG] #if 0 @@ -486,7 +481,7 @@ no_command_line: beq 1b nop #endif - + moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 move.b $r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) move.b $r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) @@ -503,7 +498,7 @@ no_command_line: ;; setup port PA and PB default initial directions and data ;; including their shadow registers - + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0 #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0 @@ -520,7 +515,7 @@ no_command_line: #endif move.b $r0,[port_pa_data_shadow] move.b $r0,[R_PORT_PA_DATA] - + move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0 move.b $r0,[port_pb_config_shadow] move.b $r0,[R_PORT_PB_CONFIG] @@ -562,13 +557,13 @@ no_command_line: #endif move.d $r0,[port_g_data_shadow] move.d $r0,[R_PORT_G_DATA] - + ;; setup the serial port 0 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL0_XOFF] + move.d $r0,[R_SERIAL0_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \ @@ -584,8 +579,8 @@ no_command_line: | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL0_REC_CTRL] - + move.b $r0,[R_SERIAL0_REC_CTRL] + ; Set up and enable the serial0 transmitter. move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \ @@ -598,11 +593,11 @@ no_command_line: move.b $r0,[R_SERIAL0_TR_CTRL] ;; setup the serial port 1 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL1_XOFF] + move.d $r0,[R_SERIAL1_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \ @@ -618,8 +613,8 @@ no_command_line: | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL1_REC_CTRL] - + move.b $r0,[R_SERIAL1_REC_CTRL] + ; Set up and enable the serial1 transmitter. move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \ @@ -666,14 +661,14 @@ no_command_line: | IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0 move.b $r0,[R_SERIAL2_TR_CTRL] #endif - -#ifdef CONFIG_ETRAX_SERIAL_PORT3 + +#ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes - + moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \ | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \ | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0 - move.d $r0,[R_SERIAL3_XOFF] + move.d $r0,[R_SERIAL3_XOFF] ; 115.2kbaud for both transmit and receive move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \ @@ -689,8 +684,8 @@ no_command_line: | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \ | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \ | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0 - move.b $r0,[R_SERIAL3_REC_CTRL] - + move.b $r0,[R_SERIAL3_REC_CTRL] + ; Set up and enable the serial3 transmitter. move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \ | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \ @@ -702,13 +697,11 @@ no_command_line: | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0 move.b $r0,[R_SERIAL3_TR_CTRL] #endif - -#endif /* CONFIG_SVINTO_SIM */ jump start_kernel ; jump into the C-function start_kernel in init/main.c - + .data -etrax_irv: +etrax_irv: .dword 0 romfs_start: .dword 0 @@ -716,13 +709,13 @@ romfs_length: .dword 0 romfs_in_flash: .dword 0 - + ;; put some special pages at the beginning of the kernel aligned ;; to page boundaries - the kernel cannot start until after this #ifdef CONFIG_CRIS_LOW_MAP swapper_pg_dir = 0x60002000 -#else +#else swapper_pg_dir = 0xc0002000 #endif diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index ba0e5965d6e3..09cae80a834a 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -5,7 +5,7 @@ * * Authors: Bjorn Wesen (bjornw@axis.com) * - * This file contains the interrupt vectors and some + * This file contains the interrupt vectors and some * helper functions * */ @@ -182,19 +182,14 @@ void do_multiple_IRQ(struct pt_regs* regs) setting the irq vector table. */ -void __init -init_IRQ(void) +void __init init_IRQ(void) { int i; /* clear all interrupt masks */ - -#ifndef CONFIG_SVINTO_SIM *R_IRQ_MASK0_CLR = 0xffffffff; *R_IRQ_MASK1_CLR = 0xffffffff; *R_IRQ_MASK2_CLR = 0xffffffff; -#endif - *R_VECT_MASK_CLR = 0xffffffff; for (i = 0; i < 256; i++) @@ -211,25 +206,20 @@ init_IRQ(void) executed by the associated break handler, rather than just a jump address. therefore we need to setup a default breakpoint handler for all breakpoints */ - for (i = 0; i < 16; i++) set_break_vector(i, do_sigtrap); - - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt); - - /* 0 and 1 which are special breakpoint/NMI traps */ + /* 0 and 1 which are special breakpoint/NMI traps */ set_int_vector(0, hwbreakpoint); set_int_vector(1, IRQ1_interrupt); /* and irq 14 which is the mmu bus fault handler */ - set_int_vector(14, mmu_bus_fault); /* setup the system-call trap, which is reached by BREAK 13 */ - set_break_vector(13, system_call); /* setup a breakpoint handler for debugging used for both user and diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 753e9a03cf87..02b783457be0 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -56,14 +56,14 @@ void hard_reset_now (void) * code to know about it than the watchdog handler in entry.S and * this code, implementing hard reset through the watchdog. */ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) extern int cause_of_death; #endif printk("*** HARD RESET ***\n"); local_irq_disable(); -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) cause_of_death = 0xbedead; #else /* Since we dont plan to keep on resetting the watchdog, diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c index fce7c541d70d..b5eb5cd2f60b 100644 --- a/arch/cris/arch-v10/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -14,7 +14,6 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/mm.h> -#include <arch/svinto.h> #include <asm/types.h> #include <asm/signal.h> #include <asm/io.h> @@ -34,7 +33,7 @@ unsigned long get_ns_in_jiffie(void) local_irq_save(flags); timer_count = *R_TIMER0_DATA; - presc_count = *R_TIM_PRESC_STATUS; + presc_count = *R_TIM_PRESC_STATUS; /* presc_count might be wrapped */ t1 = *R_TIMER0_DATA; @@ -50,7 +49,7 @@ unsigned long get_ns_in_jiffie(void) presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; } - ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + + ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + ( (presc_count) * (1000000000/PRESCALE_FREQ)); return ns; } @@ -80,7 +79,7 @@ static u32 cris_v10_gettimeoffset(void) * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is * described in the table below: - * + * * Watchdog Value written: * state: To enable: To key: Operation: * -------- ---------- ------- ---------- @@ -89,15 +88,15 @@ static u32 cris_v10_gettimeoffset(void) * started 0 ~key Stop watchdog * started 1 ~key Restart watchdog with key = ~key. * started X new_key_val Change key to new_key_val. - * + * * Note: '~' is the bitwise NOT operator. - * + * */ /* right now, starting the watchdog is the same as resetting it */ #define start_watchdog reset_watchdog -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#ifdef CONFIG_ETRAX_WATCHDOG static int watchdog_key = 0; /* arbitrary number */ #endif @@ -107,10 +106,9 @@ static int watchdog_key = 0; /* arbitrary number */ #define WATCHDOG_MIN_FREE_PAGES 8 -void -reset_watchdog(void) +void reset_watchdog(void) { -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) /* only keep watchdog happy as long as we have memory left! */ if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { /* reset the watchdog with the inverse of the old key */ @@ -123,28 +121,23 @@ reset_watchdog(void) /* stop the watchdog - we still need the correct key */ -void -stop_watchdog(void) +void stop_watchdog(void) { -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#ifdef CONFIG_ETRAX_WATCHDOG watchdog_key ^= 0x7; /* invert key, which is 3 bits */ *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | IO_STATE(R_WATCHDOG, enable, stop); -#endif +#endif } +extern void cris_do_profile(struct pt_regs *regs); + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "xtime_update()" routine every clocktick */ - -//static unsigned short myjiff; /* used by our debug routine print_timestamp */ - -extern void cris_do_profile(struct pt_regs *regs); - -static inline irqreturn_t -timer_interrupt(int irq, void *dev_id) +static inline irqreturn_t timer_interrupt(int irq, void *dev_id) { struct pt_regs *regs = get_irq_regs(); /* acknowledge the timer irq */ @@ -160,44 +153,39 @@ timer_interrupt(int irq, void *dev_id) IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); #else - *R_TIMER_CTRL = r_timer_ctrl_shadow | - IO_STATE(R_TIMER_CTRL, i0, clr); + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr); #endif /* reset watchdog otherwise it resets us! */ reset_watchdog(); - + /* Update statistics. */ update_process_times(user_mode(regs)); /* call the real timer interrupt handler */ - xtime_update(1); - + cris_do_profile(regs); /* Save profiling information */ return IRQ_HANDLED; } -/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain - * it needs to be IRQF_DISABLED to make the jiffies update work properly - */ +/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain */ static struct irqaction irq2 = { .handler = timer_interrupt, - .flags = IRQF_SHARED | IRQF_DISABLED, + .flags = IRQF_SHARED, .name = "timer", }; -void __init -time_init(void) -{ +void __init time_init(void) +{ arch_gettimeoffset = cris_v10_gettimeoffset; - /* probe for the RTC and read it if it exists - * Before the RTC can be probed the loops_per_usec variable needs - * to be initialized to make usleep work. A better value for - * loops_per_usec is calculated by the kernel later once the - * clock has started. + /* probe for the RTC and read it if it exists + * Before the RTC can be probed the loops_per_usec variable needs + * to be initialized to make usleep work. A better value for + * loops_per_usec is calculated by the kernel later once the + * clock has started. */ loops_per_usec = 50; @@ -208,7 +196,7 @@ time_init(void) * Remember that linux/timex.h contains #defines that rely on the * timer settings below (hz and divide factor) !!! */ - + #ifdef USE_CASCADE_TIMERS *R_TIMER_CTRL = IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | @@ -219,8 +207,8 @@ time_init(void) IO_STATE( R_TIMER_CTRL, i0, nop) | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = + + *R_TIMER_CTRL = r_timer_ctrl_shadow = IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | IO_STATE( R_TIMER_CTRL, i1, nop) | @@ -230,18 +218,18 @@ time_init(void) IO_STATE( R_TIMER_CTRL, tm0, run) | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); #else - *R_TIMER_CTRL = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + *R_TIMER_CTRL = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | - IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | IO_STATE(R_TIMER_CTRL, i0, nop) | IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | IO_STATE(R_TIMER_CTRL, clksel0, flexible); - + *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, run) | @@ -253,16 +241,14 @@ time_init(void) *R_TIMER_PRESCALE = PRESCALE_VALUE; #endif - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ - - /* now actually register the timer irq handler that calls timer_interrupt() */ - + /* unmask the timer irq */ + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); + + /* now actually register the irq handler that calls timer_interrupt() */ setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ /* enable watchdog if we should use one */ - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_WATCHDOG) printk("Enabling watchdog...\n"); start_watchdog(); @@ -275,9 +261,7 @@ time_init(void) driver or infrastructure support yet. */ asm ("setf m"); - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); - *R_VECT_MASK_SET = - IO_STATE(R_VECT_MASK_SET, nmi, set); + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); + *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, nmi, set); #endif } diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S index b9190ff7d0a4..e541d3d8f922 100644 --- a/arch/cris/arch-v10/lib/dram_init.S +++ b/arch/cris/arch-v10/lib/dram_init.S @@ -5,9 +5,7 @@ * Note: This file may not modify r9 because r9 is used to carry * information from the decompresser to the kernel * - * Copyright (C) 2000, 2001 Axis Communications AB - * - * Authors: Mikael Starvik (starvik@axis.com) + * Copyright (C) 2000-2012 Axis Communications AB * */ @@ -18,16 +16,15 @@ ;; WARNING! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). + ;; information from the decompressor (if the kernel was compressed). ;; They should not be used in the code below. -#ifndef CONFIG_SVINTO_SIM move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 move.d $r0, [R_WAITSTATES] move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 move.d $r0, [R_BUS_CONFIG] - + #ifndef CONFIG_ETRAX_SDRAM move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, $r0 move.d $r0, [R_DRAM_CONFIG] @@ -38,14 +35,14 @@ ;; Samsung SDRAMs seem to require to be initialized twice to work properly. moveq 2, $r6 _sdram_init: - + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization - + ; Bank configuration move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r0 move.d $r0, [R_SDRAM_CONFIG] - ; Calculate value of mrs_data + ; Calculate value of mrs_data ; CAS latency = 2 && bus_width = 32 => 0x40 ; CAS latency = 3 && bus_width = 32 => 0x60 ; CAS latency = 2 && bus_width = 16 => 0x20 @@ -56,22 +53,22 @@ _sdram_init: and.d 0x00ff0000, $r2 bne _set_timing lsrq 16, $r2 - + move.d 0x40, $r2 ; Assume 32 bits and CAS latency = 2 move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 move.d $r1, $r3 - and.d 0x03, $r1 ; Get CAS latency + and.d 0x03, $r1 ; Get CAS latency and.d 0x1000, $r3 ; 50 or 100 MHz? beq _speed_50 nop -_speed_100: +_speed_100: cmp.d 0x00, $r1 ; CAS latency = 2? beq _bw_check nop - or.d 0x20, $r2 ; CAS latency = 3 + or.d 0x20, $r2 ; CAS latency = 3 ba _bw_check nop -_speed_50: +_speed_50: cmp.d 0x01, $r1 ; CAS latency = 2? beq _bw_check nop @@ -86,19 +83,19 @@ _bw_check: ; Set timing parameters. Starts master clock _set_timing: move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 - and.d 0x8000f9ff, $r1 ; Make sure mrs data and command is 0 + and.d 0x8000f9ff, $r1 ; Make sure mrs data and command is 0 or.d 0x80000000, $r1 ; Make sure sdram enable bit is set move.d $r1, $r5 or.d 0x0000c000, $r1 ; ref = disable lslq 16, $r2 ; mrs data starts at bit 16 - or.d $r2, $r1 - move.d $r1, [R_SDRAM_TIMING] - + or.d $r2, $r1 + move.d $r1, [R_SDRAM_TIMING] + ; Wait 200us move.d 10000, $r2 1: bne 1b subq 1, $r2 - + ; Issue initialization command sequence move.d _sdram_commands_start, $r2 and.d 0x000fffff, $r2 ; Make sure commands are read from flash @@ -144,7 +141,6 @@ _sdram_commands_start: .byte 2 ; refresh .byte 0 ; nop .byte 1 ; mrs - .byte 0 ; nop -_sdram_commands_end: -#endif + .byte 0 ; nop +_sdram_commands_end: #endif diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 1b6ad6247204..28dd77144e8f 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c @@ -24,8 +24,6 @@ #include <linux/mtd/mtdram.h> #include <linux/mtd/partitions.h> -#include <linux/cramfs_fs.h> - #include <asm/axisflashmap.h> #include <asm/mmu.h> diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c index 0b86deedacb9..74f9fe80940c 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c @@ -978,7 +978,7 @@ static int __init gpio_init(void) CRIS_LED_DISK_WRITE(0); int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist); + IRQF_SHARED, "gpio", &alarmlist); if (res2) { printk(KERN_ERR "err: irq for gpio\n"); return res2; diff --git a/arch/cris/arch-v32/drivers/mach-fs/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c index a2ac0917f1a6..9e54273af0ca 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c @@ -964,11 +964,11 @@ gpio_init(void) * in some tests. */ if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist)) + IRQF_SHARED, "gpio poll", &alarmlist)) printk(KERN_ERR "timer0 irq for gpio\n"); if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt, - IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist)) + IRQF_SHARED, "gpio PA", &alarmlist)) printk(KERN_ERR "PA irq for gpio\n"); #ifdef CONFIG_ETRAX_VIRTUAL_GPIO diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 219f704e3221..bbb806b68838 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/timer.h> #include <linux/spinlock.h> +#include <linux/wait.h> #include <asm/io.h> #include <dma.h> @@ -1144,7 +1145,8 @@ static ssize_t sync_serial_read(struct file * file, char * buf, if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); if (signal_pending(current)) return -EINTR; diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index faa644111feb..2f19ac6217aa 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -424,7 +424,7 @@ nmi_interrupt: bpl 1f nop jsr handle_watchdog_bite ; In time.c. - move.d $sp, $r10 ; Pointer to registers + move.d $sp, $r10 ; Pointer to registers 1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 bpl 1f nop @@ -452,7 +452,7 @@ spurious_interrupt: nop ;; This handles the case when multiple interrupts arrive at the same - ;; time. Jump to the first set interrupt bit in a priotiry fashion. The + ;; time. Jump to the first set interrupt bit in a priority fashion. The ;; hardware will call the unserved interrupts after the handler ;; finishes. .type multiple_interrupt, @function @@ -885,13 +885,29 @@ sys_call_table: .long sys_preadv .long sys_pwritev .long sys_setns /* 335 */ - - /* - * NOTE!! This doesn't have to be exact - we just have - * to make sure we have _enough_ of the "sys_ni_syscall" - * entries. Don't panic if you notice that this hasn't - * been shrunk every time we add a new system call. - */ + .long sys_name_to_handle_at + .long sys_open_by_handle_at + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_recvmmsg /* 340 */ + .long sys_accept4 + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 + .long sys_clock_adjtime /* 345 */ + .long sys_syncfs + .long sys_sendmmsg + .long sys_process_vm_readv + .long sys_process_vm_writev + .long sys_kcmp /* 350 */ + .long sys_finit_module + + /* + * NOTE!! This doesn't have to be exact - we just have + * to make sure we have _enough_ of the "sys_ni_syscall" + * entries. Don't panic if you notice that this hasn't + * been shrunk every time we add a new system call. + */ .rept NR_syscalls - (.-sys_call_table) / 4 .long sys_ni_syscall diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c index f6644535b17e..b130c2c5fdd8 100644 --- a/arch/cris/arch-v32/kernel/fasttimer.c +++ b/arch/cris/arch-v32/kernel/fasttimer.c @@ -786,7 +786,7 @@ int fast_timer_init(void) proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops); #endif /* PROC_FS */ if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "fast timer int", &fast_timer_list)) printk(KERN_ERR "err: fasttimer irq\n"); fast_timer_is_init = 1; diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index 5ebe6e841820..25437ae28128 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -331,11 +331,11 @@ extern void do_IRQ(int irq, struct pt_regs * regs); void crisv32_do_IRQ(int irq, int block, struct pt_regs* regs) { - /* Interrupts that may not be moved to another CPU and - * are IRQF_DISABLED may skip blocking. This is currently - * only valid for the timer IRQ and the IPI and is used - * for the timer interrupt to avoid watchdog starvation. - */ + /* Interrupts that may not be moved to another CPU may + * skip blocking. This is currently only valid for the + * timer IRQ and the IPI and is used for the timer + * interrupt to avoid watchdog starvation. + */ if (!block) { do_IRQ(irq, regs); return; diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index fe8e6039db2a..0698582467ca 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -64,7 +64,7 @@ static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id); static int send_ipi(int vector, int wait, cpumask_t cpu_mask); static struct irqaction irq_ipi = { .handler = crisv32_ipi_interrupt, - .flags = IRQF_DISABLED, + .flags = 0, .name = "ipi", }; diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 8c4b45efd7b6..ee66866538f8 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -216,12 +216,10 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. - * It needs to be IRQF_DISABLED to make the jiffies update work properly. - */ +/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ static struct irqaction irq_timer = { .handler = timer_interrupt, - .flags = IRQF_SHARED | IRQF_DISABLED, + .flags = IRQF_SHARED, .name = "timer" }; diff --git a/arch/cris/arch-v32/mach-a3/arbiter.c b/arch/cris/arch-v32/mach-a3/arbiter.c index 15f5c9de2639..ab5c421a4de8 100644 --- a/arch/cris/arch-v32/mach-a3/arbiter.c +++ b/arch/cris/arch-v32/mach-a3/arbiter.c @@ -256,11 +256,11 @@ static void crisv32_arbiter_init(void) crisv32_arbiter_config(1, EXT_REGION, 0); if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq, - IRQF_DISABLED, "arbiter", NULL)) + 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq, - IRQF_DISABLED, "arbiter", NULL)) + 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); #ifndef CONFIG_ETRAX_KGDB diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c index 3f8ebb5c1477..c97f4d8120f9 100644 --- a/arch/cris/arch-v32/mach-fs/arbiter.c +++ b/arch/cris/arch-v32/mach-fs/arbiter.c @@ -184,7 +184,7 @@ static void crisv32_arbiter_init(void) crisv32_arbiter_config(EXT_REGION, 0); crisv32_arbiter_config(INT_REGION, 0); - if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, + if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, 0, "arbiter", NULL)) printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); diff --git a/arch/cris/boot/rescue/kimagerescue.S b/arch/cris/boot/rescue/kimagerescue.S index 6f7b3e61260b..655b511fecf3 100644 --- a/arch/cris/boot/rescue/kimagerescue.S +++ b/arch/cris/boot/rescue/kimagerescue.S @@ -50,7 +50,6 @@ nop di -#ifndef CONFIG_SVINTO_SIM ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) @@ -67,7 +66,6 @@ ;; We need to setup the bus registers before we start using the DRAM #include "../../lib/dram_init.S" -#endif ;; Setup the stack to a suitably high address. ;; We assume 8 MB is the minimum DRAM in an eLinux ;; product and put the sp at the top for now. diff --git a/arch/cris/include/arch-v10/arch/io.h b/arch/cris/include/arch-v10/arch/io.h index f627ad0b8a3d..4a724172877f 100644 --- a/arch/cris/include/arch-v10/arch/io.h +++ b/arch/cris/include/arch-v10/arch/io.h @@ -1,8 +1,6 @@ #ifndef _ASM_ARCH_CRIS_IO_H #define _ASM_ARCH_CRIS_IO_H -#include <arch/svinto.h> - /* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ extern unsigned long gen_config_ii_shadow; @@ -34,7 +32,7 @@ extern volatile unsigned long *port_csp4_addr; /* The LED's on various Etrax-based products are set differently. */ -#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) +#if defined(CONFIG_ETRAX_NO_LEDS) #undef CONFIG_ETRAX_PA_LEDS #undef CONFIG_ETRAX_PB_LEDS #undef CONFIG_ETRAX_CSP0_LEDS @@ -171,29 +169,4 @@ extern volatile unsigned long *port_csp4_addr; #define SOFT_SHUTDOWN() #endif -/* Console I/O for simulated etrax100. Use #ifdef so erroneous - use will be evident. */ -#ifdef CONFIG_SVINTO_SIM - /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) \ - asm ("moveq 4,$r9 \n\t" \ - "moveq 2,$r10 \n\t" \ - "move.d %0,$r11 \n\t" \ - "move.d %1,$r12 \n\t" \ - "push $irp \n\t" \ - "move 0f,$irp \n\t" \ - "jump -6809 \n" \ - "0: \n\t" \ - "pop $irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") -#define TRACE_ON() __extension__ \ - ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ - (255)); _Foofoo; }) - -#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) -#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) -#define CRIS_CYCLES() __extension__ \ - ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) -#endif /* ! defined CONFIG_SVINTO_SIM */ - #endif diff --git a/arch/cris/include/arch-v10/arch/irq.h b/arch/cris/include/arch-v10/arch/irq.h index ca2675ae08ed..6aecb835037d 100644 --- a/arch/cris/include/arch-v10/arch/irq.h +++ b/arch/cris/include/arch-v10/arch/irq.h @@ -141,9 +141,9 @@ __asm__ ( \ * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed * it here, we would not get the multiple_irq at all. * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. + * The non-blocking here is based on the knowledge that the timer interrupt runs + * with interrupts disabled, and therefore there will not be an sti() before the + * timer irq handler is run to acknowledge the interrupt. */ #define BUILD_TIMER_IRQ(nr,mask) \ diff --git a/arch/cris/include/arch-v32/arch/irq.h b/arch/cris/include/arch-v32/arch/irq.h index fe3cdd22bed4..0c1b4d3a34e7 100644 --- a/arch/cris/include/arch-v32/arch/irq.h +++ b/arch/cris/include/arch-v32/arch/irq.h @@ -102,9 +102,9 @@ __asm__ ( \ * multiple_irq handler is run and it prioritizes the timer interrupt. However * if we had BLOCK'edit here, we would not get the multiple_irq at all. * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. + * The non-blocking here is based on the knowledge that the timer interrupt runs + * with interrupts disabled, and therefore there will not be an sti() before the + * timer irq handler is run to acknowledge the interrupt. */ #define BUILD_TIMER_IRQ(nr, mask) \ void IRQ_NAME(nr); \ diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h index 0ff3f6889842..5cc7d1991e48 100644 --- a/arch/cris/include/asm/unistd.h +++ b/arch/cris/include/asm/unistd.h @@ -4,7 +4,7 @@ #include <uapi/asm/unistd.h> -#define NR_syscalls 336 +#define NR_syscalls 360 #include <arch/unistd.h> diff --git a/arch/cris/include/uapi/asm/unistd.h b/arch/cris/include/uapi/asm/unistd.h index 48842896f6c2..f3287face443 100644 --- a/arch/cris/include/uapi/asm/unistd.h +++ b/arch/cris/include/uapi/asm/unistd.h @@ -340,5 +340,21 @@ #define __NR_preadv 333 #define __NR_pwritev 334 #define __NR_setns 335 +#define __NR_name_to_handle_at 336 +#define __NR_open_by_handle_at 337 +#define __NR_rt_tgsigqueueinfo 338 +#define __NR_perf_event_open 339 +#define __NR_recvmmsg 340 +#define __NR_accept4 341 +#define __NR_fanotify_init 342 +#define __NR_fanotify_mark 343 +#define __NR_prlimit64 344 +#define __NR_clock_adjtime 345 +#define __NR_syncfs 346 +#define __NR_sendmmsg 347 +#define __NR_process_vm_readv 348 +#define __NR_process_vm_writev 349 +#define __NR_kcmp 350 +#define __NR_finit_module 351 #endif /* _UAPI_ASM_CRIS_UNISTD_H_ */ diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index d36836dbbc07..dd0be5de55d5 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -40,9 +40,6 @@ /* called by the assembler IRQ entry functions defined in irq.h * to dispatch the interrupts to registered handlers - * interrupts are disabled upon entry - depending on if the - * interrupt was registered with IRQF_DISABLED or not, interrupts - * are re-enabled or not. */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 8d581ab06c5d..79b9bcdfe498 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -26,6 +26,8 @@ config MICROBLAZE select GENERIC_CPU_DEVICES select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS + select COMMON_CLK + select GENERIC_SCHED_CLOCK select GENERIC_IDLE_POLL_SETUP select MODULES_USE_ELF_RELA select CLONE_BACKWARDS3 diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 40350a3c24e9..a69eaf2ab130 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -1,3 +1,5 @@ +KBUILD_DEFCONFIG := mmu_defconfig + ifeq ($(CONFIG_MMU),y) UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\" else diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h index 7d6831ac8a46..3337417fcdca 100644 --- a/arch/microblaze/include/asm/cpuinfo.h +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -91,15 +91,18 @@ extern struct cpuinfo cpuinfo; /* fwd declarations of the various CPUinfo populators */ void setup_cpuinfo(void); +void setup_cpuinfo_clk(void); void set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu); void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu); static inline unsigned int fcpu(struct device_node *cpu, char *n) { - const __be32 *val; - return (val = of_get_property(cpu, n, NULL)) ? - be32_to_cpup(val) : 0; + u32 val = 0; + + of_property_read_u32(cpu, n, &val); + + return val; } #endif /* _ASM_MICROBLAZE_CPUINFO_H */ diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h index 2565cb94f32f..a2cea7206077 100644 --- a/arch/microblaze/include/asm/io.h +++ b/arch/microblaze/include/asm/io.h @@ -342,4 +342,12 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) #define iowrite32_rep(p, src, count) \ outsl((unsigned long) (p), (src), (count)) +#define readb_relaxed readb +#define readw_relaxed readw +#define readl_relaxed readl + +#define writeb_relaxed writeb +#define writew_relaxed writew +#define writel_relaxed writel + #endif /* _ASM_MICROBLAZE_IO_H */ diff --git a/arch/microblaze/include/asm/sections.h b/arch/microblaze/include/asm/sections.h index c07ed5d2a820..1b281d3ea734 100644 --- a/arch/microblaze/include/asm/sections.h +++ b/arch/microblaze/include/asm/sections.h @@ -16,7 +16,6 @@ # ifndef __ASSEMBLY__ extern char _ssbss[], _esbss[]; extern unsigned long __ivt_start[], __ivt_end[]; -extern char _etext[], _stext[]; extern u32 _fdt_start[], _fdt_end[]; diff --git a/arch/microblaze/include/uapi/asm/Kbuild b/arch/microblaze/include/uapi/asm/Kbuild index 6d7d7f4aaae8..1aac99f87df1 100644 --- a/arch/microblaze/include/uapi/asm/Kbuild +++ b/arch/microblaze/include/uapi/asm/Kbuild @@ -1,6 +1,8 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +generic-y += types.h + header-y += auxvec.h header-y += bitsperlong.h header-y += byteorder.h @@ -31,5 +33,4 @@ header-y += statfs.h header-y += swab.h header-y += termbits.h header-y += termios.h -header-y += types.h header-y += unistd.h diff --git a/arch/microblaze/include/uapi/asm/types.h b/arch/microblaze/include/uapi/asm/types.h deleted file mode 100644 index b9e79bc580dd..000000000000 --- a/arch/microblaze/include/uapi/asm/types.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/types.h> diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index ee4689415410..93c26cf50de5 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -112,7 +112,4 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK); CI(fpga_family_code, TARGET_FAMILY); - - /* take timebase-frequency from DTS */ - ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency"); } diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index 592bb2e838c4..4854285b26e7 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -113,8 +113,6 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk"); ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk"); - ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency"); - ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1"); ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2"); diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index c9203b1007aa..234acad79b9e 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -8,6 +8,7 @@ * for more details. */ +#include <linux/clk.h> #include <linux/init.h> #include <asm/cpuinfo.h> #include <asm/pvr.h> @@ -39,6 +40,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"8.30.a", 0x17}, {"8.40.a", 0x18}, {"8.40.b", 0x19}, + {"8.50.a", 0x1a}, {"9.0", 0x1b}, {"9.1", 0x1d}, {NULL, 0}, @@ -68,11 +70,10 @@ const struct family_string_key family_string_lookup[] = { }; struct cpuinfo cpuinfo; +static struct device_node *cpu; void __init setup_cpuinfo(void) { - struct device_node *cpu = NULL; - cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu"); if (!cpu) pr_err("You don't have cpu!!!\n"); @@ -102,3 +103,22 @@ void __init setup_cpuinfo(void) pr_warn("%s: Stream instructions enabled" " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); } + +void __init setup_cpuinfo_clk(void) +{ + struct clk *clk; + + clk = of_clk_get(cpu, 0); + if (IS_ERR(clk)) { + pr_err("ERROR: CPU CCF input clock not found\n"); + /* take timebase-frequency from DTS */ + cpuinfo.cpu_clock_freq = fcpu(cpu, "timebase-frequency"); + } else { + cpuinfo.cpu_clock_freq = clk_get_rate(clk); + } + + if (!cpuinfo.cpu_clock_freq) { + pr_err("ERROR: CPU clock frequency not setup\n"); + BUG(); + } +} diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 817b7eec95b6..b7fb0438458c 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -64,6 +64,10 @@ real_start: #endif mts rmsr, r0 +/* Disable stack protection from bootloader */ + mts rslr, r0 + addi r8, r0, 0xFFFFFFF + mts rshr, r8 /* * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc' * if the msrclr instruction is not enabled. We use this to detect diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index fc6b89f4dd31..0b11a4469deb 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -147,15 +147,14 @@ or r3, r0, NUM_TO_REG (regnum); /* Shift right instruction depending on available configuration */ - #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0 - #define BSRLI(rD, rA, imm) \ - bsrli rD, rA, imm - #else - #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA) + #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0 /* Only the used shift constants defined here - add more if needed */ #define BSRLI2(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ + #define BSRLI4(rD, rA) \ + BSRLI2(rD, rA); \ + BSRLI2(rD, rD) #define BSRLI10(rD, rA) \ srl rD, rA; /* << 1 */ \ srl rD, rD; /* << 2 */ \ @@ -170,7 +169,33 @@ #define BSRLI20(rD, rA) \ BSRLI10(rD, rA); \ BSRLI10(rD, rD) + + .macro bsrli, rD, rA, IMM + .if (\IMM) == 2 + BSRLI2(\rD, \rA) + .elseif (\IMM) == 10 + BSRLI10(\rD, \rA) + .elseif (\IMM) == 12 + BSRLI2(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 14 + BSRLI4(\rD, \rA) + BSRLI10(\rD, \rD) + .elseif (\IMM) == 20 + BSRLI20(\rD, \rA) + .elseif (\IMM) == 24 + BSRLI4(\rD, \rA) + BSRLI20(\rD, \rD) + .elseif (\IMM) == 28 + BSRLI4(\rD, \rA) + BSRLI4(\rD, \rD) + BSRLI20(\rD, \rD) + .else + .error "BSRLI shift macros \IMM" + .endif + .endm #endif + #endif /* CONFIG_MMU */ .extern other_exception_handler /* Defined in exception.c */ @@ -604,7 +629,7 @@ ex_handler_done: ex4: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -613,7 +638,7 @@ ex_handler_done: beqi r5, ex2 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -705,7 +730,7 @@ ex_handler_done: ex6: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -714,7 +739,7 @@ ex_handler_done: beqi r5, ex7 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -776,7 +801,7 @@ ex_handler_done: ex9: tophys(r4,r4) /* Create L1 (pgdir/pmd) address */ - BSRLI(r5,r3, PGDIR_SHIFT - 2) + bsrli r5, r3, PGDIR_SHIFT - 2 andi r5, r5, PAGE_SIZE - 4 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */ or r4, r4, r5 @@ -785,7 +810,7 @@ ex_handler_done: beqi r5, ex10 /* Bail if no table */ tophys(r5,r5) - BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */ + bsrli r6, r3, PTE_SHIFT /* Compute PTE address */ andi r6, r6, PAGE_SIZE - 4 or r5, r5, r6 lwi r4, r5, 0 /* Get Linux PTE */ @@ -922,7 +947,7 @@ ex_handler_done: .ent _unaligned_data_exception _unaligned_data_exception: andi r8, r3, 0x3E0; /* Mask and extract the register operand */ - BSRLI(r8,r8,2); /* r8 >> 2 = register operand * 8 */ + bsrli r8, r8, 2; /* r8 >> 2 = register operand * 8 */ andi r6, r3, 0x400; /* Extract ESR[S] */ bneid r6, ex_sw_vm; andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */ diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 8de8ebc309f1..67cc4b282cc1 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -9,6 +9,7 @@ */ #include <linux/init.h> +#include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/string.h> #include <linux/seq_file.h> @@ -136,7 +137,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, lockdep_init(); /* initialize device tree for usage in early_printk */ - early_init_devtree((void *)_fdt_start); + early_init_devtree(_fdt_start); #ifdef CONFIG_EARLY_PRINTK setup_early_printk(NULL); @@ -152,8 +153,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, if (fdt) pr_info("FDT at 0x%08x\n", fdt); else - pr_info("Compiled-in FDT at 0x%08x\n", - (unsigned int)_fdt_start); + pr_info("Compiled-in FDT at %p\n", _fdt_start); #ifdef CONFIG_MTD_UCLINUX pr_info("Found romfs @ 0x%08x (0x%08x)\n", @@ -175,7 +175,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, #else if (!msr) { pr_info("!!!Your kernel not setup MSR instruction but "); - pr_cont"CPU have it %x\n", msr); + pr_cont("CPU have it %x\n", msr); } #endif @@ -196,6 +196,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, void __init time_init(void) { + of_clk_init(NULL); + setup_cpuinfo_clk(); clocksource_of_init(); } diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 3e39b1082fdf..fb0c61443f19 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -12,12 +12,12 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/sched_clock.h> #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <asm/cpuinfo.h> -#include <linux/cnt32_to_63.h> static void __iomem *timer_baseaddr; @@ -167,10 +167,15 @@ static __init void xilinx_clockevent_init(void) clockevents_register_device(&clockevent_xilinx_timer); } +static u64 xilinx_clock_read(void) +{ + return in_be32(timer_baseaddr + TCR1); +} + static cycle_t xilinx_read(struct clocksource *cs) { /* reading actual value of timer 1 */ - return (cycle_t) (in_be32(timer_baseaddr + TCR1)); + return (cycle_t)xilinx_clock_read(); } static struct timecounter xilinx_tc = { @@ -222,17 +227,17 @@ static int __init xilinx_clocksource_init(void) return 0; } -/* - * We have to protect accesses before timer initialization - * and return 0 for sched_clock function below. - */ -static int timer_initialized; - static void __init xilinx_timer_init(struct device_node *timer) { + struct clk *clk; + static int initialized; u32 irq; u32 timer_num = 1; - int ret; + + if (initialized) + return; + + initialized = 1; timer_baseaddr = of_iomap(timer, 0); if (!timer_baseaddr) { @@ -250,10 +255,20 @@ static void __init xilinx_timer_init(struct device_node *timer) pr_info("%s: irq=%d\n", timer->full_name, irq); - /* If there is clock-frequency property than use it */ - ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq); - if (ret < 0) + clk = of_clk_get(timer, 0); + if (IS_ERR(clk)) { + pr_err("ERROR: timer CCF input clock not found\n"); + /* If there is clock-frequency property than use it */ + of_property_read_u32(timer, "clock-frequency", + &timer_clock_freq); + } else { + timer_clock_freq = clk_get_rate(clk); + } + + if (!timer_clock_freq) { + pr_err("ERROR: Using CPU clock frequency\n"); timer_clock_freq = cpuinfo.cpu_clock_freq; + } freq_div_hz = timer_clock_freq / HZ; @@ -263,18 +278,8 @@ static void __init xilinx_timer_init(struct device_node *timer) #endif xilinx_clocksource_init(); xilinx_clockevent_init(); - timer_initialized = 1; -} -unsigned long long notrace sched_clock(void) -{ - if (timer_initialized) { - struct clocksource *cs = &clocksource_microblaze; - - cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX; - return clocksource_cyc2ns(cyc, cs->mult, cs->shift); - } - return 0; + sched_clock_register(xilinx_clock_read, 32, timer_clock_freq); } CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index 936d01a689d7..be9488d69734 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -51,6 +51,7 @@ SECTIONS { . = ALIGN(16); RODATA EXCEPTION_TABLE(16) + NOTES /* * sdata2 section can go anywhere, but must be word aligned diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1695b6ab503d..25493a0b174c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -140,6 +140,7 @@ config PPC select OLD_SIGACTION if PPC32 select HAVE_DEBUG_STACKOVERFLOW select HAVE_IRQ_EXIT_ON_IRQ_STACK + select ARCH_USE_CMPXCHG_LOCKREF if PPC64 config GENERIC_CSUM def_bool CPU_LITTLE_ENDIAN @@ -214,9 +215,6 @@ config DEFAULT_UIMAGE Used to allow a board to specify it wants a uImage built by default default n -config REDBOOT - bool - config ARCH_HIBERNATION_POSSIBLE bool default y @@ -384,6 +382,12 @@ config ARCH_HAS_WALK_MEMORY config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y +config PPC64_SUPPORTS_MEMORY_FAILURE + bool "Add support for memory hwpoison" + depends on PPC_BOOK3S_64 + default "y" if PPC_POWERNV + select ARCH_SUPPORTS_MEMORY_FAILURE + config KEXEC bool "kexec system call" depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) @@ -404,8 +408,7 @@ config KEXEC config CRASH_DUMP bool "Build a kdump crash kernel" depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP) - select RELOCATABLE if PPC64 || 44x - select DYNAMIC_MEMSTART if FSL_BOOKE + select RELOCATABLE if PPC64 || 44x || FSL_BOOKE help Build a kernel suitable for use as a kdump capture kernel. The same kernel binary can be used as production kernel and dump @@ -886,7 +889,7 @@ config DYNAMIC_MEMSTART config RELOCATABLE bool "Build a relocatable kernel" - depends on ADVANCED_OPTIONS && FLATMEM && 44x + depends on ADVANCED_OPTIONS && FLATMEM && (44x || FSL_BOOKE) select NONSTATIC_KERNEL help This builds a kernel image that is capable of running at the diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index 554734ff302e..d61c03525777 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -16,6 +16,7 @@ mktree uImage cuImage.* dtbImage.* +*.dtb treeImage.* zImage zImage.initrd diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index ca7f08cc4afd..90e9d9548660 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -71,9 +71,9 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \ uartlite.c mpc52xx-psc.c src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c -src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c +src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c -src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c +src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c fsl-soc.c src-plat-y := of.c epapr.c src-plat-$(CONFIG_40x) += fixed-head.S ep405.c cuboot-hotfoot.c \ @@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \ cuboot-c2k.c gamecube-head.S \ gamecube.c wii-head.S wii.c holly.c \ - prpmc2800.c + prpmc2800.c fixed-head.S mvme5100.c src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c @@ -286,6 +286,7 @@ image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2 image-$(CONFIG_PPC_C2K) += cuImage.c2k image-$(CONFIG_GAMECUBE) += dtbImage.gamecube image-$(CONFIG_WII) += dtbImage.wii +image-$(CONFIG_MVME5100) += dtbImage.mvme5100 # Board port in arch/powerpc/platform/amigaone/Kconfig image-$(CONFIG_AMIGAONE) += cuImage.amigaone diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi new file mode 100644 index 000000000000..d3cc8d0f7c25 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi @@ -0,0 +1,82 @@ +/* + * QorIQ Elo3 DMA device tree stub [ controller @ offset 0x102300 ] + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +dma2: dma@102300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elo3-dma"; + reg = <0x102300 0x4>, + <0x102600 0x4>; + ranges = <0x0 0x102100 0x500>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + interrupts = <464 2 0 0>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + interrupts = <465 2 0 0>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + interrupts = <466 2 0 0>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + interrupts = <467 2 0 0>; + }; + dma-channel@300 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x300 0x80>; + interrupts = <468 2 0 0>; + }; + dma-channel@380 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x380 0x80>; + interrupts = <469 2 0 0>; + }; + dma-channel@400 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x400 0x80>; + interrupts = <470 2 0 0>; + }; + dma-channel@480 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x480 0x80>; + interrupts = <471 2 0 0>; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 68cc5e7f6477..642dc3a83d0e 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index adb82fd9057f..407cb5fd0f5b 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1021-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index e179803a81ef..ebf202234549 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi @@ -40,7 +40,8 @@ * pin muxing when the DIU is enabled. */ compatible = "fsl,p1022-elbc", "fsl,elbc"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0x9000 */ diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index f1105bffa915..81437fdf1db4 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi @@ -36,7 +36,8 @@ #address-cells = <2>; #size-cells = <1>; compatible = "fsl,p1023-elbc", "fsl,elbc", "simple-bus"; - interrupts = <19 2 0 0>; + interrupts = <19 2 0 0>, + <16 2 0 0>; }; /* controller at 0xa000 */ diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts index 1613d6e4049e..5ba7f01e2a29 100644 --- a/arch/powerpc/boot/dts/kilauea.dts +++ b/arch/powerpc/boot/dts/kilauea.dts @@ -406,7 +406,7 @@ MSI: ppc4xx-msi@C10000000 { compatible = "amcc,ppc4xx-msi", "ppc4xx-msi"; - reg = < 0x0 0xEF620000 0x100>; + reg = <0xEF620000 0x100>; sdr-base = <0x4B0>; msi-data = <0x00000000>; msi-mask = <0x44440000>; diff --git a/arch/powerpc/boot/dts/mvme5100.dts b/arch/powerpc/boot/dts/mvme5100.dts new file mode 100644 index 000000000000..1ecb341a232a --- /dev/null +++ b/arch/powerpc/boot/dts/mvme5100.dts @@ -0,0 +1,185 @@ +/* + * Device Tree Source for Motorola/Emerson MVME5100. + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * 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. + */ + +/dts-v1/; + +/ { + model = "MVME5100"; + compatible = "MVME5100"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &serial0; + pci0 = &pci0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,7410 { + device_type = "cpu"; + reg = <0x0>; + /* Following required by dtc but not used */ + d-cache-line-size = <32>; + i-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + timebase-frequency = <25000000>; + clock-frequency = <500000000>; + bus-frequency = <100000000>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x20000000>; + }; + + hawk@fef80000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "hawk-bridge", "simple-bus"; + ranges = <0x0 0xfef80000 0x10000>; + reg = <0xfef80000 0x10000>; + + serial0: serial@8000 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x8000 0x80>; + reg-shift = <4>; + clock-frequency = <1843200>; + current-speed = <9600>; + interrupts = <1 1>; // IRQ1 Level Active Low. + interrupt-parent = <&mpic>; + }; + + serial1: serial@8200 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x8200 0x80>; + reg-shift = <4>; + clock-frequency = <1843200>; + current-speed = <9600>; + interrupts = <1 1>; // IRQ1 Level Active Low. + interrupt-parent = <&mpic>; + }; + + mpic: interrupt-controller@f3f80000 { + #interrupt-cells = <2>; + #address-cells = <0>; + device_type = "open-pic"; + compatible = "chrp,open-pic"; + interrupt-controller; + reg = <0xf3f80000 0x40000>; + }; + }; + + pci0: pci@feff0000 { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + compatible = "hawk-pci"; + reg = <0xfec00000 0x400000>; + 8259-interrupt-acknowledge = <0xfeff0030>; + ranges = <0x1000000 0x0 0x0 0xfe000000 0x0 0x800000 + 0x2000000 0x0 0x80000000 0x80000000 0x0 0x74000000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* + * This definition (IDSEL 11) duplicates the + * interrupts definition in the i8259 + * interrupt controller below. + * + * Do not change the interrupt sense/polarity from + * 0x2 to anything else, doing so will cause endless + * "spurious" i8259 interrupts to be fielded. + */ + // IDSEL 11 - iPMC712 PCI/ISA Bridge + 0x5800 0x0 0x0 0x1 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x2 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x3 &mpic 0x0 0x2 + 0x5800 0x0 0x0 0x4 &mpic 0x0 0x2 + + /* IDSEL 12 - Not Used */ + + /* IDSEL 13 - Universe VME Bridge */ + 0x6800 0x0 0x0 0x1 &mpic 0x5 0x1 + 0x6800 0x0 0x0 0x2 &mpic 0x6 0x1 + 0x6800 0x0 0x0 0x3 &mpic 0x7 0x1 + 0x6800 0x0 0x0 0x4 &mpic 0x8 0x1 + + /* IDSEL 14 - ENET 1 */ + 0x7000 0x0 0x0 0x1 &mpic 0x2 0x1 + + /* IDSEL 15 - Not Used */ + + /* IDSEL 16 - PMC Slot 1 */ + 0x8000 0x0 0x0 0x1 &mpic 0x9 0x1 + 0x8000 0x0 0x0 0x2 &mpic 0xa 0x1 + 0x8000 0x0 0x0 0x3 &mpic 0xb 0x1 + 0x8000 0x0 0x0 0x4 &mpic 0xc 0x1 + + /* IDSEL 17 - PMC Slot 2 */ + 0x8800 0x0 0x0 0x1 &mpic 0xc 0x1 + 0x8800 0x0 0x0 0x2 &mpic 0x9 0x1 + 0x8800 0x0 0x0 0x3 &mpic 0xa 0x1 + 0x8800 0x0 0x0 0x4 &mpic 0xb 0x1 + + /* IDSEL 18 - Not Used */ + + /* IDSEL 19 - ENET 2 */ + 0x9800 0x0 0x0 0x1 &mpic 0xd 0x1 + + /* IDSEL 20 - PMCSPAN (PCI-X) */ + 0xa000 0x0 0x0 0x1 &mpic 0x9 0x1 + 0xa000 0x0 0x0 0x2 &mpic 0xa 0x1 + 0xa000 0x0 0x0 0x3 &mpic 0xb 0x1 + 0xa000 0x0 0x0 0x4 &mpic 0xc 0x1 + + >; + + isa { + #address-cells = <2>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "isa"; + compatible = "isa"; + ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + #interrupt-cells = <2>; + #address-cells = <0>; + interrupts = <0 2>; + device_type = "interrupt-controller"; + compatible = "chrp,iic"; + interrupt-controller; + reg = <1 0x00000020 0x00000002 + 1 0x000000a0 0x00000002 + 1 0x000004d0 0x00000002>; + interrupt-parent = <&mpic>; + }; + + }; + + }; + + chosen { + linux,stdout-path = &serial0; + }; + +}; diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dts b/arch/powerpc/boot/dts/p1010rdb-pa.dts new file mode 100644 index 000000000000..767d4c032857 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pa.dts @@ -0,0 +1,23 @@ +/* + * P1010 RDB Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * 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/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB"; + compatible = "fsl,P1010RDB"; + + /include/ "p1010rdb_32b.dtsi" +}; + +/include/ "p1010rdb.dtsi" +/include/ "p1010rdb-pa.dtsi" +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dtsi b/arch/powerpc/boot/dts/p1010rdb-pa.dtsi new file mode 100644 index 000000000000..434fb2d58575 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pa.dtsi @@ -0,0 +1,85 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&ifc_nand { + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 15MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00f00000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1900000 { + /* 7MB for User Area */ + reg = <0x01900000 0x00700000>; + label = "NAND User area"; + }; +}; + +&phy0 { + interrupts = <1 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <4 1 0 0>; +}; diff --git a/arch/powerpc/boot/dts/p1010rdb_36b.dts b/arch/powerpc/boot/dts/p1010rdb-pa_36b.dts index 64776f4a4651..3033371bc007 100644 --- a/arch/powerpc/boot/dts/p1010rdb_36b.dts +++ b/arch/powerpc/boot/dts/p1010rdb-pa_36b.dts @@ -38,52 +38,9 @@ model = "fsl,P1010RDB"; compatible = "fsl,P1010RDB"; - memory { - device_type = "memory"; - }; - - board_ifc: ifc: ifc@fffe1e000 { - /* NOR, NAND Flashes and CPLD on board */ - ranges = <0x0 0x0 0xf 0xee000000 0x02000000 - 0x1 0x0 0xf 0xff800000 0x00010000 - 0x3 0x0 0xf 0xffb00000 0x00000020>; - reg = <0xf 0xffe1e000 0 0x2000>; - }; - - board_soc: soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; + /include/ "p1010rdb_36b.dtsi" }; /include/ "p1010rdb.dtsi" +/include/ "p1010rdb-pa.dtsi" /include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pb.dts b/arch/powerpc/boot/dts/p1010rdb-pb.dts new file mode 100644 index 000000000000..6eeb7d3185be --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pb.dts @@ -0,0 +1,35 @@ +/* + * P1010 RDB Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * 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/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB-PB"; + compatible = "fsl,P1010RDB-PB"; + + /include/ "p1010rdb_32b.dtsi" +}; + +/include/ "p1010rdb.dtsi" + +&phy0 { + interrupts = <0 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <1 1 0 0>; +}; + +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts b/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts new file mode 100644 index 000000000000..7ab3c907b326 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts @@ -0,0 +1,58 @@ +/* + * P1010 RDB Device Tree Source (36-bit address map) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1010si-pre.dtsi" + +/ { + model = "fsl,P1010RDB-PB"; + compatible = "fsl,P1010RDB-PB"; + + /include/ "p1010rdb_36b.dtsi" +}; + +/include/ "p1010rdb.dtsi" + +&phy0 { + interrupts = <0 1 0 0>; +}; + +&phy1 { + interrupts = <2 1 0 0>; +}; + +&phy2 { + interrupts = <1 1 0 0>; +}; + +/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb.dts b/arch/powerpc/boot/dts/p1010rdb.dts deleted file mode 100644 index b868d22984e9..000000000000 --- a/arch/powerpc/boot/dts/p1010rdb.dts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * P1010 RDB Device Tree Source - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * 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/ "fsl/p1010si-pre.dtsi" - -/ { - model = "fsl,P1010RDB"; - compatible = "fsl,P1010RDB"; - - memory { - device_type = "memory"; - }; - - board_ifc: ifc: ifc@ffe1e000 { - /* NOR, NAND Flashes and CPLD on board */ - ranges = <0x0 0x0 0x0 0xee000000 0x02000000 - 0x1 0x0 0x0 0xff800000 0x00010000 - 0x3 0x0 0x0 0xffb00000 0x00000020>; - reg = <0x0 0xffe1e000 0 0x2000>; - }; - - board_soc: soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - reg = <0 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p1010rdb.dtsi" -/include/ "fsl/p1010si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi index ec7c27a64671..ea534efa790d 100644 --- a/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/arch/powerpc/boot/dts/p1010rdb.dtsi @@ -69,49 +69,11 @@ }; }; - nand@1,0 { + ifc_nand: nand@1,0 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,ifc-nand"; reg = <0x1 0x0 0x10000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 15MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00f00000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1900000 { - /* 7MB for User Area */ - reg = <0x01900000 0x00700000>; - label = "NAND User area"; - }; }; cpld@3,0 { @@ -193,17 +155,14 @@ mdio@24000 { phy0: ethernet-phy@0 { - interrupts = <3 1 0 0>; reg = <0x1>; }; phy1: ethernet-phy@1 { - interrupts = <2 1 0 0>; reg = <0x0>; }; phy2: ethernet-phy@2 { - interrupts = <2 1 0 0>; reg = <0x2>; }; diff --git a/arch/powerpc/boot/dts/p1010rdb_32b.dtsi b/arch/powerpc/boot/dts/p1010rdb_32b.dtsi new file mode 100644 index 000000000000..fdc19aab2f70 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb_32b.dtsi @@ -0,0 +1,79 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +memory { + device_type = "memory"; +}; + +board_ifc: ifc: ifc@ffe1e000 { + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0x0 0xee000000 0x02000000 + 0x1 0x0 0x0 0xff800000 0x00010000 + 0x3 0x0 0x0 0xffb00000 0x00000020>; + reg = <0x0 0xffe1e000 0 0x2000>; +}; + +board_soc: soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; +}; + +pci0: pcie@ffe09000 { + reg = <0 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; + +pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; diff --git a/arch/powerpc/boot/dts/p1010rdb_36b.dtsi b/arch/powerpc/boot/dts/p1010rdb_36b.dtsi new file mode 100644 index 000000000000..de2fceed4f79 --- /dev/null +++ b/arch/powerpc/boot/dts/p1010rdb_36b.dtsi @@ -0,0 +1,79 @@ +/* + * P1010 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +memory { + device_type = "memory"; +}; + +board_ifc: ifc: ifc@fffe1e000 { + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0xf 0xee000000 0x02000000 + 0x1 0x0 0xf 0xff800000 0x00010000 + 0x3 0x0 0xf 0xffb00000 0x00000020>; + reg = <0xf 0xffe1e000 0 0x2000>; +}; + +board_soc: soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; +}; + +pci0: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; + +pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; +}; diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi index 873da350d01b..957e0dc1dc0f 100644 --- a/arch/powerpc/boot/dts/p1022ds.dtsi +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -146,8 +146,9 @@ */ }; rtc@68 { - compatible = "dallas,ds1339"; + compatible = "dallas,ds3232"; reg = <0x68>; + interrupts = <0x1 0x1 0 0>; }; adt7461@4c { compatible = "adi,adt7461"; diff --git a/arch/powerpc/boot/dts/p1025twr.dts b/arch/powerpc/boot/dts/p1025twr.dts new file mode 100644 index 000000000000..9036a4987905 --- /dev/null +++ b/arch/powerpc/boot/dts/p1025twr.dts @@ -0,0 +1,95 @@ +/* + * P1025 TWR Device Tree Source (32-bit address map) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1025"; + compatible = "fsl,TWR-P1025"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR Flash and SSD1289 */ + ranges = <0x0 0x0 0x0 0xec000000 0x04000000 + 0x2 0x0 0x0 0xe0000000 0x00020000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe: qe@ffe80000 { + ranges = <0x0 0x0 0xffe80000 0x40000>; + reg = <0 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + }; +}; + +/include/ "p1025twr.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1025twr.dtsi b/arch/powerpc/boot/dts/p1025twr.dtsi new file mode 100644 index 000000000000..8453501c256e --- /dev/null +++ b/arch/powerpc/boot/dts/p1025twr.dtsi @@ -0,0 +1,280 @@ +/* + * P1025 TWR Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/{ + aliases { + ethernet3 = &enet3; + ethernet4 = &enet4; + }; +}; + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x4000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 5.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00580000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 56.75MB for Root file System */ + reg = <0x00600000 0x038c0000>; + label = "NOR Root File System"; + }; + + partition@ec0000 { + /* This location must not be altered */ + /* 256KB for QE ucode firmware*/ + reg = <0x03ec0000 0x00040000>; + label = "NOR QE microcode firmware"; + read-only; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x03f00000 0x00100000>; + label = "NOR U-Boot Image"; + read-only; + }; + }; + + /* CS2 for Display */ + display@2,0 { + compatible = "solomon,ssd1289fb"; + reg = <0x2 0x0000 0x0004>; + }; + +}; + +&soc { + usb@22000 { + phy_type = "ulpi"; + }; + + mdio@24000 { + phy0: ethernet-phy@2 { + interrupt-parent = <&mpic>; + interrupts = <1 1 0 0>; + reg = <0x2>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1 0 0>; + reg = <0x1>; + }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25000 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26000 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + status = "disabled"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + par_io@e0100 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe0100 0x60>; + ranges = <0x0 0xe0100 0x60>; + device_type = "par_io"; + num-ports = <3>; + pio1: ucc_pin@01 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ + 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 */ + 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ + 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ + 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ + 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ + 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ + 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ + 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ + 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ + 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ + 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ + 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ + 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ + 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ + 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ + }; + + pio2: ucc_pin@02 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ + 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ + 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ + 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ + 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ + 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ + 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ + 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ + }; + + pio3: ucc_pin@03 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x0 0x16 0x2 0x0 0x2 0x0 /* SER7_CD_B*/ + 0x0 0x12 0x2 0x0 0x2 0x0 /* SER7_CTS_B*/ + 0x0 0x13 0x1 0x0 0x2 0x0 /* SER7_RTS_B*/ + 0x0 0x14 0x2 0x0 0x2 0x0 /* SER7_RXD0*/ + 0x0 0x15 0x1 0x0 0x2 0x0>; /* SER7_TXD0*/ + }; + + pio4: ucc_pin@04 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x0 0x2 0x0 0x2 0x0 /* SER3_CD_B*/ + 0x0 0x1c 0x2 0x0 0x2 0x0 /* SER3_CTS_B*/ + 0x0 0x1d 0x1 0x0 0x2 0x0 /* SER3_RTS_B*/ + 0x0 0x1e 0x2 0x0 0x2 0x0 /* SER3_RXD0*/ + 0x0 0x1f 0x1 0x0 0x2 0x0>; /* SER3_TXD0*/ + }; + }; +}; + +&qe { + enet3: ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "clk12"; + tx-clock-name = "clk9"; + pio-handle = <&pio1>; + phy-handle = <&qe_phy0>; + phy-connection-type = "mii"; + }; + + mdio@2120 { + qe_phy0: ethernet-phy@18 { + interrupt-parent = <&mpic>; + interrupts = <4 1 0 0>; + reg = <0x18>; + device_type = "ethernet-phy"; + }; + qe_phy1: ethernet-phy@19 { + interrupt-parent = <&mpic>; + interrupts = <5 1 0 0>; + reg = <0x19>; + device_type = "ethernet-phy"; + }; + tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet4: ucc@2400 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "none"; + tx-clock-name = "clk13"; + pio-handle = <&pio2>; + phy-handle = <&qe_phy1>; + phy-connection-type = "rmii"; + }; + + serial2: ucc@2600 { + device_type = "serial"; + compatible = "ucc_uart"; + port-number = <0>; + rx-clock-name = "brg6"; + tx-clock-name = "brg6"; + pio-handle = <&pio3>; + }; + + serial3: ucc@2200 { + device_type = "serial"; + compatible = "ucc_uart"; + port-number = <1>; + rx-clock-name = "brg2"; + tx-clock-name = "brg2"; + pio-handle = <&pio4>; + }; +}; diff --git a/arch/powerpc/boot/dts/virtex440-ml507.dts b/arch/powerpc/boot/dts/virtex440-ml507.dts index fc7073bc547e..391a4e299783 100644 --- a/arch/powerpc/boot/dts/virtex440-ml507.dts +++ b/arch/powerpc/boot/dts/virtex440-ml507.dts @@ -257,6 +257,8 @@ #size-cells = <1>; compatible = "xlnx,compound"; ethernet@81c00000 { + #address-cells = <1>; + #size-cells = <0>; compatible = "xlnx,xps-ll-temac-1.01.b"; device_type = "network"; interrupt-parent = <&xps_intc_0>; diff --git a/arch/powerpc/boot/mvme5100.c b/arch/powerpc/boot/mvme5100.c new file mode 100644 index 000000000000..cb865f83c60b --- /dev/null +++ b/arch/powerpc/boot/mvme5100.c @@ -0,0 +1,27 @@ +/* + * Motorola/Emerson MVME5100 with PPCBug firmware. + * + * Author: Stephen Chivers <schivers@csc.com> + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + */ +#include "types.h" +#include "ops.h" +#include "io.h" + +BSS_STACK(4096); + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5) +{ + u32 heapsize; + + heapsize = 0x8000000 - (u32)_end; /* 128M */ + simple_alloc_init(_end, heapsize, 32, 64); + fdt_init(_dtb_start); + serial_console_init(); +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 2e1af74a64be..d27a25518b01 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -265,6 +265,10 @@ epapr) link_address='0x20000000' pie=-pie ;; +mvme5100) + platformo="$object/fixed-head.o $object/mvme5100.o" + binary=y + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" diff --git a/arch/powerpc/configs/85xx/p1023_defconfig b/arch/powerpc/configs/85xx/p1023_defconfig deleted file mode 100644 index b06d37da44f4..000000000000 --- a/arch/powerpc/configs/85xx/p1023_defconfig +++ /dev/null @@ -1,188 +0,0 @@ -CONFIG_PPC_85xx=y -CONFIG_SMP=y -CONFIG_NR_CPUS=2 -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_RCU_FANOUT=32 -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y -CONFIG_EMBEDDED=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -CONFIG_PHYSICAL_START=0x00000000 -CONFIG_P1023_RDB=y -CONFIG_P1023_RDS=y -CONFIG_QUICC_ENGINE=y -CONFIG_QE_GPIO=y -CONFIG_CPM2=y -CONFIG_HIGHMEM=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_BINFMT_MISC=m -CONFIG_MATH_EMULATION=y -CONFIG_SWIOTLB=y -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -# CONFIG_PCIEAER is not set -# CONFIG_PCIEASPM is not set -CONFIG_PCI_MSI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NET_IPIP=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y -CONFIG_INET_ESP=y -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -CONFIG_IPV6=y -CONFIG_IP_SCTP=m -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_EEPROM_AT24=y -CONFIG_EEPROM_LEGACY=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_LOGGING=y -CONFIG_ATA=y -CONFIG_SATA_FSL=y -CONFIG_SATA_SIL24=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_FS_ENET=y -CONFIG_FSL_PQ_MDIO=y -CONFIG_E1000E=y -CONFIG_PHYLIB=y -CONFIG_AT803X_PHY=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_FIXED_PHY=y -CONFIG_INPUT_FF_MEMLESS=m -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_8250_DETECT_IRQ=y -CONFIG_SERIAL_8250_RSA=y -CONFIG_HW_RANDOM=y -CONFIG_NVRAM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_CPM=m -CONFIG_I2C_MPC=y -CONFIG_GPIO_MPC8XXX=y -# CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -# CONFIG_SND_SUPPORT_OLD_API is not set -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_FSL=y -CONFIG_USB_STORAGE=y -CONFIG_EDAC=y -CONFIG_EDAC_MM_EDAC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_CMOS=y -CONFIG_DMADEVICES=y -CONFIG_FSL_DMA=y -# CONFIG_NET_DMA is not set -CONFIG_STAGING=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=y -CONFIG_NTFS_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_ADFS_FS=m -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_CRAMFS=y -CONFIG_VXFS_FS=m -CONFIG_HPFS_FS=m -CONFIG_QNX4FS_FS=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y -CONFIG_CRC_T10DIF=y -CONFIG_FRAME_WARN=8092 -CONFIG_DEBUG_FS=y -CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -CONFIG_STRICT_DEVMEM=y -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_FSL_CAAM=y diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig index 69128740c14d..15b1ff5d96e7 100644 --- a/arch/powerpc/configs/adder875_defconfig +++ b/arch/powerpc/configs/adder875_defconfig @@ -70,3 +70,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig index 219fd470ed22..b8a79d7ee89f 100644 --- a/arch/powerpc/configs/ep88xc_defconfig +++ b/arch/powerpc/configs/ep88xc_defconfig @@ -72,3 +72,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index d2e0fab5ee5b..83d3550fdb54 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -31,6 +31,7 @@ CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y +CONFIG_P1023_RDB=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y @@ -113,6 +114,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_EEPROM_AT24=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -211,6 +213,7 @@ CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1307=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y # CONFIG_NET_DMA is not set diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 4cb7b59e98bd..4b686294feb4 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -34,6 +34,7 @@ CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y +CONFIG_P1023_RDB=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y @@ -116,6 +117,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_EEPROM_AT24=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -212,6 +214,7 @@ CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1307=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y # CONFIG_NET_DMA is not set diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig index 5c258823e694..d954e80c286a 100644 --- a/arch/powerpc/configs/mpc866_ads_defconfig +++ b/arch/powerpc/configs/mpc866_ads_defconfig @@ -55,3 +55,4 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_CCITT=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig index 9e146cdf63de..3f47d00a10c0 100644 --- a/arch/powerpc/configs/mpc885_ads_defconfig +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -78,3 +78,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig new file mode 100644 index 000000000000..93c7752e2dbb --- /dev/null +++ b/arch/powerpc/configs/mvme5100_defconfig @@ -0,0 +1,144 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_PPC_CHRP is not set +# CONFIG_PPC_PMAC is not set +CONFIG_EMBEDDED6xx=y +CONFIG_MVME5100=y +CONFIG_KVM_GUEST=y +CONFIG_HZ_100=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,9600 ip=dhcp root=/dev/nfs" +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_LAPB=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_EEPROM_LEGACY=m +CONFIG_NETDEVICES=y +CONFIG_TUN=m +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_E100=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=10 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MPC=y +# CONFIG_HWMON is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_VGA_CONSOLE is not set +# CONFIG_HID is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_VME_BUS=m +CONFIG_VME_CA91CX42=m +CONFIG_EXT2_FS=m +CONFIG_EXT3_FS=m +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_XFS_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_CIFS=m +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_UTF8=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20 +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_DEFLATE=m +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 581a3bcae728..e015896b7e5c 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -186,6 +186,7 @@ CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y CONFIG_SATA_SIL24=y +CONFIG_SATA_MV=y CONFIG_SATA_SVW=y CONFIG_MD=y CONFIG_BLK_DEV_MD=y diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig index 8616fde0896f..4b6f8bf104e0 100644 --- a/arch/powerpc/configs/tqm8xx_defconfig +++ b/arch/powerpc/configs/tqm8xx_defconfig @@ -84,3 +84,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_CRC32_SLICEBY4=y diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index 910194e9a1e2..a5e9a7d494d8 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -46,6 +46,11 @@ #include <asm/asm-compat.h> #include <asm/synch.h> +/* PPC bit number conversion */ +#define PPC_BITLSHIFT(be) (BITS_PER_LONG - 1 - (be)) +#define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit)) +#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) + /* * clear_bit doesn't imply a memory barrier */ diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 9e495c9a6a88..ed0afc1e44a4 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -41,8 +41,20 @@ struct ppc64_caches { extern struct ppc64_caches ppc64_caches; #endif /* __powerpc64__ && ! __ASSEMBLY__ */ -#if !defined(__ASSEMBLY__) +#if defined(__ASSEMBLY__) +/* + * For a snooping icache, we still need a dummy icbi to purge all the + * prefetched instructions from the ifetch buffers. We also need a sync + * before the icbi to order the the actual stores to memory that might + * have modified instructions with the icbi. + */ +#define PURGE_PREFETCHED_INS \ + sync; \ + icbi 0,r3; \ + sync; \ + isync +#else #define __read_mostly __attribute__((__section__(".data..read_mostly"))) #ifdef CONFIG_6xx diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h index e245aab7f191..d463c68fe7f0 100644 --- a/arch/powerpc/include/asm/cmpxchg.h +++ b/arch/powerpc/include/asm/cmpxchg.h @@ -300,6 +300,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new, BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \ }) +#define cmpxchg64_relaxed cmpxchg64_local #else #include <asm-generic/cmpxchg-local.h> #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h index a6f8c7a5cbb7..97e02f985df8 100644 --- a/arch/powerpc/include/asm/code-patching.h +++ b/arch/powerpc/include/asm/code-patching.h @@ -34,6 +34,13 @@ int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); unsigned long branch_target(const unsigned int *instr); unsigned int translate_branch(const unsigned int *dest, const unsigned int *src); +#ifdef CONFIG_PPC_BOOK3E_64 +void __patch_exception(int exc, unsigned long addr); +#define patch_exception(exc, name) do { \ + extern unsigned int name; \ + __patch_exception((exc), (unsigned long)&name); \ +} while (0) +#endif static inline unsigned long ppc_function_entry(void *func) { diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 0d4939ba48e7..617cc767c076 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -90,6 +90,18 @@ struct cpu_spec { * if the error is fatal, 1 if it was fully recovered and 0 to * pass up (not CPU originated) */ int (*machine_check)(struct pt_regs *regs); + + /* + * Processor specific early machine check handler which is + * called in real mode to handle SLB and TLB errors. + */ + long (*machine_check_early)(struct pt_regs *regs); + + /* + * Processor specific routine to flush tlbs. + */ + void (*flush_tlb)(unsigned long inval_selector); + }; extern struct cpu_spec *cur_cpu_spec; diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index d3e5e9bc8f94..9e39ceb1d19f 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -90,7 +90,8 @@ struct eeh_pe { #define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */ #define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */ -#define EEH_DEV_SYSFS (1 << 8) /* Sysfs created */ +#define EEH_DEV_NO_HANDLER (1 << 8) /* No error handler */ +#define EEH_DEV_SYSFS (1 << 9) /* Sysfs created */ struct eeh_dev { int mode; /* EEH mode */ @@ -117,6 +118,16 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) return edev ? edev->pdev : NULL; } +/* Return values from eeh_ops::next_error */ +enum { + EEH_NEXT_ERR_NONE = 0, + EEH_NEXT_ERR_INF, + EEH_NEXT_ERR_FROZEN_PE, + EEH_NEXT_ERR_FENCED_PHB, + EEH_NEXT_ERR_DEAD_PHB, + EEH_NEXT_ERR_DEAD_IOC +}; + /* * The struct is used to trace the registered EEH operation * callback functions. Actually, those operation callback @@ -157,6 +168,7 @@ struct eeh_ops { int (*read_config)(struct device_node *dn, int where, int size, u32 *val); int (*write_config)(struct device_node *dn, int where, int size, u32 val); int (*next_error)(struct eeh_pe **pe); + int (*restore_config)(struct device_node *dn); }; extern struct eeh_ops *eeh_ops; diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 243ce69ad685..66830618cc19 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -301,9 +301,12 @@ do_kvm_##n: \ beq 4f; /* if from kernel mode */ \ ACCOUNT_CPU_USER_ENTRY(r9, r10); \ SAVE_PPR(area, r9, r10); \ -4: std r2,GPR2(r1); /* save r2 in stackframe */ \ - SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ - SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ +4: EXCEPTION_PROLOG_COMMON_2(area) \ + EXCEPTION_PROLOG_COMMON_3(n) \ + ACCOUNT_STOLEN_TIME + +/* Save original regs values from save area to stack frame. */ +#define EXCEPTION_PROLOG_COMMON_2(area) \ ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ ld r10,area+EX_R10(r13); \ std r9,GPR9(r1); \ @@ -318,11 +321,16 @@ do_kvm_##n: \ ld r10,area+EX_CFAR(r13); \ std r10,ORIG_GPR3(r1); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + GET_CTR(r10, area); \ + std r10,_CTR(r1); + +#define EXCEPTION_PROLOG_COMMON_3(n) \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ + SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ + SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ mflr r9; /* Get LR, later save to stack */ \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ std r9,_LINK(r1); \ - GET_CTR(r10, area); \ - std r10,_CTR(r1); \ lbz r10,PACASOFTIRQEN(r13); \ mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r10,SOFTE(r1); \ @@ -332,8 +340,7 @@ do_kvm_##n: \ li r10,0; \ ld r11,exception_marker@toc(r2); \ std r10,RESULT(r1); /* clear regs->result */ \ - std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \ - ACCOUNT_STOLEN_TIME + std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ /* * Exception vectors. diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 420b45368fcf..067fb0dca549 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h @@ -285,7 +285,7 @@ struct fsl_lbc_ctrl { /* device info */ struct device *dev; struct fsl_lbc_regs __iomem *regs; - int irq; + int irq[2]; wait_queue_head_t irq_wait; spinlock_t lock; void *nand; diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h index 3bdcfce2c42a..418fb654370d 100644 --- a/arch/powerpc/include/asm/hardirq.h +++ b/arch/powerpc/include/asm/hardirq.h @@ -6,7 +6,8 @@ typedef struct { unsigned int __softirq_pending; - unsigned int timer_irqs; + unsigned int timer_irqs_event; + unsigned int timer_irqs_others; unsigned int pmu_irqs; unsigned int mce_exceptions; unsigned int spurious_irqs; diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 575fbf81fad0..97d3869991ca 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -191,8 +191,24 @@ DEF_MMIO_OUT_D(out_le32, 32, stw); #endif /* __BIG_ENDIAN */ +/* + * Cache inhibitied accessors for use in real mode, you don't want to use these + * unless you know what you're doing. + * + * NB. These use the cpu byte ordering. + */ +DEF_MMIO_OUT_X(out_rm8, 8, stbcix); +DEF_MMIO_OUT_X(out_rm16, 16, sthcix); +DEF_MMIO_OUT_X(out_rm32, 32, stwcix); +DEF_MMIO_IN_X(in_rm8, 8, lbzcix); +DEF_MMIO_IN_X(in_rm16, 16, lhzcix); +DEF_MMIO_IN_X(in_rm32, 32, lwzcix); + #ifdef __powerpc64__ +DEF_MMIO_OUT_X(out_rm64, 64, stdcix); +DEF_MMIO_IN_X(in_rm64, 64, ldcix); + #ifdef __BIG_ENDIAN__ DEF_MMIO_OUT_D(out_be64, 64, std); DEF_MMIO_IN_D(in_be64, 64, ld); diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index c34656a8925e..f7a8036579b5 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -30,22 +30,19 @@ #include <asm/machdep.h> #include <asm/types.h> -#define IOMMU_PAGE_SHIFT 12 -#define IOMMU_PAGE_SIZE (ASM_CONST(1) << IOMMU_PAGE_SHIFT) -#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1)) -#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE) +#define IOMMU_PAGE_SHIFT_4K 12 +#define IOMMU_PAGE_SIZE_4K (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K) +#define IOMMU_PAGE_MASK_4K (~((1 << IOMMU_PAGE_SHIFT_4K) - 1)) +#define IOMMU_PAGE_ALIGN_4K(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE_4K) + +#define IOMMU_PAGE_SIZE(tblptr) (ASM_CONST(1) << (tblptr)->it_page_shift) +#define IOMMU_PAGE_MASK(tblptr) (~((1 << (tblptr)->it_page_shift) - 1)) +#define IOMMU_PAGE_ALIGN(addr, tblptr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE(tblptr)) /* Boot time flags */ extern int iommu_is_off; extern int iommu_force_on; -/* Pure 2^n version of get_order */ -static __inline__ __attribute_const__ int get_iommu_order(unsigned long size) -{ - return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1; -} - - /* * IOMAP_MAX_ORDER defines the largest contiguous block * of dma space we can get. IOMAP_MAX_ORDER = 13 @@ -76,11 +73,20 @@ struct iommu_table { struct iommu_pool large_pool; struct iommu_pool pools[IOMMU_NR_POOLS]; unsigned long *it_map; /* A simple allocation bitmap for now */ + unsigned long it_page_shift;/* table iommu page size */ #ifdef CONFIG_IOMMU_API struct iommu_group *it_group; #endif }; +/* Pure 2^n version of get_order */ +static inline __attribute_const__ +int get_iommu_order(unsigned long size, struct iommu_table *tbl) +{ + return __ilog2((size - 1) >> tbl->it_page_shift) + 1; +} + + struct scatterlist; static inline void set_iommu_table_base(struct device *dev, void *base) @@ -101,8 +107,34 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name); */ extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, int nid); +#ifdef CONFIG_IOMMU_API extern void iommu_register_group(struct iommu_table *tbl, int pci_domain_number, unsigned long pe_num); +extern int iommu_add_device(struct device *dev); +extern void iommu_del_device(struct device *dev); +#else +static inline void iommu_register_group(struct iommu_table *tbl, + int pci_domain_number, + unsigned long pe_num) +{ +} + +static inline int iommu_add_device(struct device *dev) +{ + return 0; +} + +static inline void iommu_del_device(struct device *dev) +{ +} +#endif /* !CONFIG_IOMMU_API */ + +static inline void set_iommu_table_base_and_group(struct device *dev, + void *base) +{ + set_iommu_table_base(dev, base); + iommu_add_device(dev); +} extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 1bd92fd43cfb..1503d8c7c41b 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h @@ -74,6 +74,7 @@ #define BOOKE_INTERRUPT_GUEST_DBELL_CRIT 39 #define BOOKE_INTERRUPT_HV_SYSCALL 40 #define BOOKE_INTERRUPT_HV_PRIV 41 +#define BOOKE_INTERRUPT_LRAT_ERROR 42 /* book3s */ diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index 844c28de7ec0..d0a2a2f99564 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -132,8 +132,6 @@ struct slb_shadow { } save_area[SLB_NUM_BOLTED]; } ____cacheline_aligned; -extern struct slb_shadow slb_shadow[]; - /* * Layout of entries in the hypervisor's dispatch trace log buffer. */ diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h new file mode 100644 index 000000000000..8e99edf6d966 --- /dev/null +++ b/arch/powerpc/include/asm/mce.h @@ -0,0 +1,197 @@ +/* + * Machine check exception header file. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#ifndef __ASM_PPC64_MCE_H__ +#define __ASM_PPC64_MCE_H__ + +#include <linux/bitops.h> + +/* + * Machine Check bits on power7 and power8 + */ +#define P7_SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42)) /* P8 too */ + +/* SRR1 bits for machine check (On Power7 and Power8) */ +#define P7_SRR1_MC_IFETCH(srr1) ((srr1) & PPC_BITMASK(43, 45)) /* P8 too */ + +#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45)) +#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45)) + +/* SRR1 bits for machine check (On Power8) */ +#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45)) + +/* DSISR bits for machine check (On Power7 and Power8) */ +#define P7_DSISR_MC_UE (PPC_BIT(48)) /* P8 too */ +#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) /* P8 too */ +#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) /* P8 too */ +#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) /* P8 too */ +#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57)) /* P8 too */ + +/* + * DSISR bits for machine check (Power8) in addition to above. + * Secondary DERAT Multihit + */ +#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54)) + +/* SLB error bits */ +#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \ + P7_DSISR_MC_SLB_PARITY_MFSLB | \ + P7_DSISR_MC_SLB_MULTIHIT | \ + P7_DSISR_MC_SLB_MULTIHIT_PARITY) + +#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ + P8_DSISR_MC_ERAT_MULTIHIT_SEC) +enum MCE_Version { + MCE_V1 = 1, +}; + +enum MCE_Severity { + MCE_SEV_NO_ERROR = 0, + MCE_SEV_WARNING = 1, + MCE_SEV_ERROR_SYNC = 2, + MCE_SEV_FATAL = 3, +}; + +enum MCE_Disposition { + MCE_DISPOSITION_RECOVERED = 0, + MCE_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum MCE_Initiator { + MCE_INITIATOR_UNKNOWN = 0, + MCE_INITIATOR_CPU = 1, +}; + +enum MCE_ErrorType { + MCE_ERROR_TYPE_UNKNOWN = 0, + MCE_ERROR_TYPE_UE = 1, + MCE_ERROR_TYPE_SLB = 2, + MCE_ERROR_TYPE_ERAT = 3, + MCE_ERROR_TYPE_TLB = 4, +}; + +enum MCE_UeErrorType { + MCE_UE_ERROR_INDETERMINATE = 0, + MCE_UE_ERROR_IFETCH = 1, + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2, + MCE_UE_ERROR_LOAD_STORE = 3, + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4, +}; + +enum MCE_SlbErrorType { + MCE_SLB_ERROR_INDETERMINATE = 0, + MCE_SLB_ERROR_PARITY = 1, + MCE_SLB_ERROR_MULTIHIT = 2, +}; + +enum MCE_EratErrorType { + MCE_ERAT_ERROR_INDETERMINATE = 0, + MCE_ERAT_ERROR_PARITY = 1, + MCE_ERAT_ERROR_MULTIHIT = 2, +}; + +enum MCE_TlbErrorType { + MCE_TLB_ERROR_INDETERMINATE = 0, + MCE_TLB_ERROR_PARITY = 1, + MCE_TLB_ERROR_MULTIHIT = 2, +}; + +struct machine_check_event { + enum MCE_Version version:8; /* 0x00 */ + uint8_t in_use; /* 0x01 */ + enum MCE_Severity severity:8; /* 0x02 */ + enum MCE_Initiator initiator:8; /* 0x03 */ + enum MCE_ErrorType error_type:8; /* 0x04 */ + enum MCE_Disposition disposition:8; /* 0x05 */ + uint8_t reserved_1[2]; /* 0x06 */ + uint64_t gpr3; /* 0x08 */ + uint64_t srr0; /* 0x10 */ + uint64_t srr1; /* 0x18 */ + union { /* 0x20 */ + struct { + enum MCE_UeErrorType ue_error_type:8; + uint8_t effective_address_provided; + uint8_t physical_address_provided; + uint8_t reserved_1[5]; + uint64_t effective_address; + uint64_t physical_address; + uint8_t reserved_2[8]; + } ue_error; + + struct { + enum MCE_SlbErrorType slb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } slb_error; + + struct { + enum MCE_EratErrorType erat_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } erat_error; + + struct { + enum MCE_TlbErrorType tlb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } tlb_error; + } u; +}; + +struct mce_error_info { + enum MCE_ErrorType error_type:8; + union { + enum MCE_UeErrorType ue_error_type:8; + enum MCE_SlbErrorType slb_error_type:8; + enum MCE_EratErrorType erat_error_type:8; + enum MCE_TlbErrorType tlb_error_type:8; + } u; + uint8_t reserved[2]; +}; + +#define MAX_MC_EVT 100 + +/* Release flags for get_mce_event() */ +#define MCE_EVENT_RELEASE true +#define MCE_EVENT_DONTRELEASE false + +extern void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, uint64_t addr); +extern int get_mce_event(struct machine_check_event *mce, bool release); +extern void release_mce_event(void); +extern void machine_check_queue_event(void); +extern void machine_check_print_event_info(struct machine_check_event *evt); +extern uint64_t get_mce_fault_addr(struct machine_check_event *evt); + +#endif /* __ASM_PPC64_MCE_H__ */ diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 936db360790a..89b785d16846 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -286,8 +286,21 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize) extern int mmu_linear_psize; extern int mmu_vmemmap_psize; +struct tlb_core_data { + /* For software way selection, as on Freescale TLB1 */ + u8 esel_next, esel_max, esel_first; + + /* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */ + u8 lock; +}; + #ifdef CONFIG_PPC64 extern unsigned long linear_map_top; +extern int book3e_htw_mode; + +#define PPC_HTW_NONE 0 +#define PPC_HTW_IBM 1 +#define PPC_HTW_E6500 2 /* * 64-bit booke platforms don't load the tlb in the tlb miss handler code. diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 691fd8aca939..f8d1d6dcf7db 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -180,16 +180,17 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) #define MMU_PAGE_64K_AP 3 /* "Admixed pages" (hash64 only) */ #define MMU_PAGE_256K 4 #define MMU_PAGE_1M 5 -#define MMU_PAGE_4M 6 -#define MMU_PAGE_8M 7 -#define MMU_PAGE_16M 8 -#define MMU_PAGE_64M 9 -#define MMU_PAGE_256M 10 -#define MMU_PAGE_1G 11 -#define MMU_PAGE_16G 12 -#define MMU_PAGE_64G 13 - -#define MMU_PAGE_COUNT 14 +#define MMU_PAGE_2M 6 +#define MMU_PAGE_4M 7 +#define MMU_PAGE_8M 8 +#define MMU_PAGE_16M 9 +#define MMU_PAGE_64M 10 +#define MMU_PAGE_256M 11 +#define MMU_PAGE_1G 12 +#define MMU_PAGE_16G 13 +#define MMU_PAGE_64G 14 + +#define MMU_PAGE_COUNT 15 #if defined(CONFIG_PPC_STD_MMU_64) /* 64-bit classic hash table MMU */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 7bdcf340016c..40157e2ca691 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -33,6 +33,28 @@ struct opal_takeover_args { u64 rd_loc; /* r11 */ }; +/* + * SG entry + * + * WARNING: The current implementation requires each entry + * to represent a block that is 4k aligned *and* each block + * size except the last one in the list to be as well. + */ +struct opal_sg_entry { + void *data; + long length; +}; + +/* sg list */ +struct opal_sg_list { + unsigned long num_entries; + struct opal_sg_list *next; + struct opal_sg_entry entry[]; +}; + +/* We calculate number of sg entries based on PAGE_SIZE */ +#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) + extern long opal_query_takeover(u64 *hal_size, u64 *hal_align); extern long opal_do_takeover(struct opal_takeover_args *args); @@ -132,6 +154,9 @@ extern int opal_enter_rtas(struct rtas_args *args, #define OPAL_FLASH_VALIDATE 76 #define OPAL_FLASH_MANAGE 77 #define OPAL_FLASH_UPDATE 78 +#define OPAL_GET_MSG 85 +#define OPAL_CHECK_ASYNC_COMPLETION 86 +#define OPAL_SYNC_HOST_REBOOT 87 #ifndef __ASSEMBLY__ @@ -211,7 +236,16 @@ enum OpalPendingState { OPAL_EVENT_ERROR_LOG = 0x40, OPAL_EVENT_EPOW = 0x80, OPAL_EVENT_LED_STATUS = 0x100, - OPAL_EVENT_PCI_ERROR = 0x200 + OPAL_EVENT_PCI_ERROR = 0x200, + OPAL_EVENT_MSG_PENDING = 0x800, +}; + +enum OpalMessageType { + OPAL_MSG_ASYNC_COMP = 0, + OPAL_MSG_MEM_ERR, + OPAL_MSG_EPOW, + OPAL_MSG_SHUTDOWN, + OPAL_MSG_TYPE_MAX, }; /* Machine check related definitions */ @@ -311,12 +345,16 @@ enum OpalMveEnableAction { OPAL_ENABLE_MVE = 1 }; -enum OpalPciResetAndReinitScope { +enum OpalPciResetScope { OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3, OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5, OPAL_PCI_IODA_TABLE_RESET = 6, }; +enum OpalPciReinitScope { + OPAL_REINIT_PCI_DEV = 1000 +}; + enum OpalPciResetState { OPAL_DEASSERT_RESET = 0, OPAL_ASSERT_RESET = 1 @@ -356,6 +394,12 @@ enum OpalLPCAddressType { OPAL_LPC_FW = 2, }; +struct opal_msg { + uint32_t msg_type; + uint32_t reserved; + uint64_t params[8]; +}; + struct opal_machine_check_event { enum OpalMCE_Version version:8; /* 0x00 */ uint8_t in_use; /* 0x01 */ @@ -404,6 +448,58 @@ struct opal_machine_check_event { } u; }; +/* FSP memory errors handling */ +enum OpalMemErr_Version { + OpalMemErr_V1 = 1, +}; + +enum OpalMemErrType { + OPAL_MEM_ERR_TYPE_RESILIENCE = 0, + OPAL_MEM_ERR_TYPE_DYN_DALLOC, + OPAL_MEM_ERR_TYPE_SCRUB, +}; + +/* Memory Reilience error type */ +enum OpalMemErr_ResilErrType { + OPAL_MEM_RESILIENCE_CE = 0, + OPAL_MEM_RESILIENCE_UE, + OPAL_MEM_RESILIENCE_UE_SCRUB, +}; + +/* Dynamic Memory Deallocation type */ +enum OpalMemErr_DynErrType { + OPAL_MEM_DYNAMIC_DEALLOC = 0, +}; + +/* OpalMemoryErrorData->flags */ +#define OPAL_MEM_CORRECTED_ERROR 0x0001 +#define OPAL_MEM_THRESHOLD_EXCEEDED 0x0002 +#define OPAL_MEM_ACK_REQUIRED 0x8000 + +struct OpalMemoryErrorData { + enum OpalMemErr_Version version:8; /* 0x00 */ + enum OpalMemErrType type:8; /* 0x01 */ + uint16_t flags; /* 0x02 */ + uint8_t reserved_1[4]; /* 0x04 */ + + union { + /* Memory Resilience corrected/uncorrected error info */ + struct { + enum OpalMemErr_ResilErrType resil_err_type:8; + uint8_t reserved_1[7]; + uint64_t physical_address_start; + uint64_t physical_address_end; + } resilience; + /* Dynamic memory deallocation error info */ + struct { + enum OpalMemErr_DynErrType dyn_err_type:8; + uint8_t reserved_1[7]; + uint64_t physical_address_start; + uint64_t physical_address_end; + } dyn_dealloc; + } u; +}; + enum { OPAL_P7IOC_DIAG_TYPE_NONE = 0, OPAL_P7IOC_DIAG_TYPE_RGC = 1, @@ -710,7 +806,7 @@ int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer, int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer, uint64_t diag_buffer_len); int64_t opal_pci_fence_phb(uint64_t phb_id); -int64_t opal_pci_reinit(uint64_t phb_id, uint8_t reinit_scope); +int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data); int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action); int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action); int64_t opal_get_epow_status(__be64 *status); @@ -731,6 +827,10 @@ int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result); int64_t opal_manage_flash(uint8_t op); int64_t opal_update_flash(uint64_t blk_list); +int64_t opal_get_msg(uint64_t buffer, size_t size); +int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token); +int64_t opal_sync_host_reboot(void); + /* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); @@ -744,6 +844,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); extern int opal_notifier_register(struct notifier_block *nb); +extern int opal_message_notifier_register(enum OpalMessageType msg_type, + struct notifier_block *nb); extern void opal_notifier_enable(void); extern void opal_notifier_disable(void); extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val); diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index b6ea9e068c13..9c5dbc3833fb 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -16,7 +16,6 @@ #ifdef CONFIG_PPC64 -#include <linux/init.h> #include <asm/types.h> #include <asm/lppaca.h> #include <asm/mmu.h> @@ -113,6 +112,10 @@ struct paca_struct { /* Keep pgd in the same cacheline as the start of extlb */ pgd_t *pgd __attribute__((aligned(0x80))); /* Current PGD */ pgd_t *kernel_pgd; /* Kernel PGD */ + + /* Shared by all threads of a core -- points to tcd of first thread */ + struct tlb_core_data *tcd_ptr; + /* We can have up to 3 levels of reentrancy in the TLB miss handler */ u64 extlb[3][EX_TLB_SIZE / sizeof(u64)]; u64 exmc[8]; /* used for machine checks */ @@ -123,6 +126,8 @@ struct paca_struct { void *mc_kstack; void *crit_kstack; void *dbg_kstack; + + struct tlb_core_data tcd; #endif /* CONFIG_PPC_BOOK3E */ mm_context_t context; @@ -152,6 +157,15 @@ struct paca_struct { */ struct opal_machine_check_event *opal_mc_evt; #endif +#ifdef CONFIG_PPC_BOOK3S_64 + /* Exclusive emergency stack pointer for machine check exception. */ + void *mc_emergency_sp; + /* + * Flag to check whether we are in machine check early handler + * and already using emergency stack. + */ + u16 in_mce; +#endif /* Stuff for accurate time accounting */ u64 user_time; /* accumulated usermode TB ticks */ diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 4a191c472867..d27960c89a71 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -558,5 +558,19 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #define __HAVE_ARCH_PMDP_INVALIDATE extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); + +#define pmd_move_must_withdraw pmd_move_must_withdraw +typedef struct spinlock spinlock_t; +static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl, + spinlock_t *old_pmd_ptl) +{ + /* + * Archs like ppc64 use pgtable to store per pmd + * specific information. So when we switch the pmd, + * we should also withdraw and deposit the pgtable + */ + return true; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 7d6eacf249cf..b999ca318985 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -3,6 +3,7 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +#include <linux/mmdebug.h> #include <asm/processor.h> /* For TASK_SIZE */ #include <asm/mmu.h> #include <asm/page.h> @@ -33,10 +34,73 @@ static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } -static inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; } static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } +#ifdef CONFIG_NUMA_BALANCING + +static inline int pte_present(pte_t pte) +{ + return pte_val(pte) & (_PAGE_PRESENT | _PAGE_NUMA); +} + +#define pte_numa pte_numa +static inline int pte_numa(pte_t pte) +{ + return (pte_val(pte) & + (_PAGE_NUMA|_PAGE_PRESENT)) == _PAGE_NUMA; +} + +#define pte_mknonnuma pte_mknonnuma +static inline pte_t pte_mknonnuma(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_NUMA; + pte_val(pte) |= _PAGE_PRESENT | _PAGE_ACCESSED; + return pte; +} + +#define pte_mknuma pte_mknuma +static inline pte_t pte_mknuma(pte_t pte) +{ + /* + * We should not set _PAGE_NUMA on non present ptes. Also clear the + * present bit so that hash_page will return 1 and we collect this + * as numa fault. + */ + if (pte_present(pte)) { + pte_val(pte) |= _PAGE_NUMA; + pte_val(pte) &= ~_PAGE_PRESENT; + } else + VM_BUG_ON(1); + return pte; +} + +#define pmd_numa pmd_numa +static inline int pmd_numa(pmd_t pmd) +{ + return pte_numa(pmd_pte(pmd)); +} + +#define pmd_mknonnuma pmd_mknonnuma +static inline pmd_t pmd_mknonnuma(pmd_t pmd) +{ + return pte_pmd(pte_mknonnuma(pmd_pte(pmd))); +} + +#define pmd_mknuma pmd_mknuma +static inline pmd_t pmd_mknuma(pmd_t pmd) +{ + return pte_pmd(pte_mknuma(pmd_pte(pmd))); +} + +# else + +static inline int pte_present(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} +#endif /* CONFIG_NUMA_BALANCING */ + /* Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. * diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index f595b98079ee..6586a40a46ce 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -4,7 +4,6 @@ #ifndef _ASM_POWERPC_PPC_ASM_H #define _ASM_POWERPC_PPC_ASM_H -#include <linux/init.h> #include <linux/stringify.h> #include <asm/asm-compat.h> #include <asm/processor.h> @@ -295,6 +294,11 @@ n: * you want to access various offsets within it). On ppc32 this is * identical to LOAD_REG_IMMEDIATE. * + * LOAD_REG_ADDR_PIC(rn, name) + * Loads the address of label 'name' into register 'run'. Use this when + * the kernel doesn't run at the linked or relocated address. Please + * note that this macro will clobber the lr register. + * * LOAD_REG_ADDRBASE(rn, name) * ADDROFF(name) * LOAD_REG_ADDRBASE loads part of the address of label 'name' into @@ -305,6 +309,14 @@ n: * LOAD_REG_ADDRBASE(rX, name) * ld rY,ADDROFF(name)(rX) */ + +/* Be careful, this will clobber the lr register. */ +#define LOAD_REG_ADDR_PIC(reg, name) \ + bl 0f; \ +0: mflr reg; \ + addis reg,reg,(name - 0b)@ha; \ + addi reg,reg,(name - 0b)@l; + #ifdef __powerpc64__ #define LOAD_REG_IMMEDIATE(reg,expr) \ lis reg,(expr)@highest; \ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index fc14a38c7ccf..8ca20ac28dc2 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -256,6 +256,8 @@ struct thread_struct { unsigned long evr[32]; /* upper 32-bits of SPE regs */ u64 acc; /* Accumulator */ unsigned long spefscr; /* SPE & eFP status */ + unsigned long spefscr_last; /* SPEFSCR value on last prctl + call or trap return */ int used_spe; /* set if process has used spe */ #endif /* CONFIG_SPE */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -317,7 +319,9 @@ struct thread_struct { (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack) #ifdef CONFIG_SPE -#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, +#define SPEFSCR_INIT \ + .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, \ + .spefscr_last = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, #else #define SPEFSCR_INIT #endif @@ -373,6 +377,8 @@ extern int set_endian(struct task_struct *tsk, unsigned int val); extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); +extern void fp_enable(void); +extern void vec_enable(void); extern void load_fp_state(struct thread_fp_state *fp); extern void store_fp_state(struct thread_fp_state *fp); extern void load_vr_state(struct thread_vr_state *vr); diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index 678a7c1d9cb8..a1bc7e758422 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -21,7 +21,6 @@ #if !defined(_ASM_POWERPC_PS3_H) #define _ASM_POWERPC_PS3_H -#include <linux/init.h> #include <linux/types.h> #include <linux/device.h> #include <asm/cell-pmu.h> diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h index 0419eeb53274..2505d8eab15c 100644 --- a/arch/powerpc/include/asm/pte-hash64.h +++ b/arch/powerpc/include/asm/pte-hash64.h @@ -19,7 +19,7 @@ #define _PAGE_FILE 0x0002 /* (!present only) software: pte holds file offset */ #define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */ #define _PAGE_GUARDED 0x0008 -#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */ +/* We can derive Memory coherence from _PAGE_NO_CACHE */ #define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */ #define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */ #define _PAGE_DIRTY 0x0080 /* C: page changed */ @@ -27,6 +27,12 @@ #define _PAGE_RW 0x0200 /* software: user write access allowed */ #define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */ +/* + * Used for tracking numa faults + */ +#define _PAGE_NUMA 0x00000010 /* Gather numa placement stats */ + + /* No separate kernel read-only */ #define _PAGE_KERNEL_RW (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */ #define _PAGE_KERNEL_RO _PAGE_KERNEL_RW diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fa8388ed94c5..62b114e079cf 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1075,6 +1075,8 @@ #define PVR_8560 0x80200000 #define PVR_VER_E500V1 0x8020 #define PVR_VER_E500V2 0x8021 +#define PVR_VER_E6500 0x8040 + /* * For the 8xx processors, all of them report the same PVR family for * the PowerPC core. The various versions of these processors must be diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 2e31aacd8acc..163c3b05a76e 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -101,6 +101,7 @@ #define SPRN_IVOR39 0x1B1 /* Interrupt Vector Offset Register 39 */ #define SPRN_IVOR40 0x1B2 /* Interrupt Vector Offset Register 40 */ #define SPRN_IVOR41 0x1B3 /* Interrupt Vector Offset Register 41 */ +#define SPRN_IVOR42 0x1B4 /* Interrupt Vector Offset Register 42 */ #define SPRN_GIVOR2 0x1B8 /* Guest IVOR2 */ #define SPRN_GIVOR3 0x1B9 /* Guest IVOR3 */ #define SPRN_GIVOR4 0x1BA /* Guest IVOR4 */ @@ -170,6 +171,7 @@ #define SPRN_L2CSR1 0x3FA /* L2 Data Cache Control and Status Register 1 */ #define SPRN_DCCR 0x3FA /* Data Cache Cacheability Register */ #define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */ +#define SPRN_PWRMGTCR0 0x3FB /* Power management control register 0 */ #define SPRN_SVR 0x3FF /* System Version Register */ /* @@ -216,6 +218,14 @@ #define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */ #define CCR1_TCS 0x00000080 /* Timer Clock Select */ +/* Bit definitions for PWRMGTCR0. */ +#define PWRMGTCR0_PW20_WAIT (1 << 14) /* PW20 state enable bit */ +#define PWRMGTCR0_PW20_ENT_SHIFT 8 +#define PWRMGTCR0_PW20_ENT 0x3F00 +#define PWRMGTCR0_AV_IDLE_PD_EN (1 << 22) /* Altivec idle enable */ +#define PWRMGTCR0_AV_IDLE_CNT_SHIFT 16 +#define PWRMGTCR0_AV_IDLE_CNT 0x3F0000 + /* Bit definitions for the MCSR. */ #define MCSR_MCS 0x80000000 /* Machine Check Summary */ #define MCSR_IB 0x40000000 /* Instruction PLB Error */ diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f6e78d63fb6a..35aa339410bd 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -30,8 +30,6 @@ #define smp_mb__after_unlock_lock() smp_mb() /* Full ordering for lock. */ -#define arch_spin_is_locked(x) ((x)->slock != 0) - #ifdef CONFIG_PPC64 /* use 0x800000yy when locked, where yy == CPU number */ #ifdef __BIG_ENDIAN__ @@ -56,6 +54,16 @@ #define SYNC_IO #endif +static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ + return lock.slock == 0; +} + +static inline int arch_spin_is_locked(arch_spinlock_t *lock) +{ + return !arch_spin_value_unlocked(*lock); +} + /* * This returns the old value in the lock, so we succeeded * in getting the lock if the return value is 0. diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 9854c564ac52..b034ecdb7c74 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -91,8 +91,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_32BIT 4 /* 32 bit binary */ -#define TIF_PERFMON_WORK 5 /* work for pfm_handle_work() */ -#define TIF_PERFMON_CTXSW 6 /* perfmon needs ctxsw calls */ +#define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SINGLESTEP 8 /* singlestepping active */ #define TIF_NOHZ 9 /* in adaptive nohz mode */ @@ -115,8 +114,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_32BIT (1<<TIF_32BIT) -#define _TIF_PERFMON_WORK (1<<TIF_PERFMON_WORK) -#define _TIF_PERFMON_CTXSW (1<<TIF_PERFMON_CTXSW) +#define _TIF_RESTORE_TM (1<<TIF_RESTORE_TM) #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) #define _TIF_SECCOMP (1<<TIF_SECCOMP) @@ -132,7 +130,8 @@ static inline struct thread_info *current_thread_info(void) _TIF_NOHZ) #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_NOTIFY_RESUME | _TIF_UPROBE) + _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ + _TIF_RESTORE_TM) #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) /* Bits in local_flags */ diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h index 9dfbc34bdbf5..0c9f8b74dd97 100644 --- a/arch/powerpc/include/asm/tm.h +++ b/arch/powerpc/include/asm/tm.h @@ -15,6 +15,7 @@ extern void do_load_up_transact_altivec(struct thread_struct *thread); extern void tm_enable(void); extern void tm_reclaim(struct thread_struct *thread, unsigned long orig_msr, uint8_t cause); +extern void tm_reclaim_current(uint8_t cause); extern void tm_recheckpoint(struct thread_struct *thread, unsigned long orig_msr); extern void tm_abort(uint8_t cause); diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 89e3ef2496ac..d0b5fca6b077 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -22,7 +22,15 @@ struct device_node; static inline int cpu_to_node(int cpu) { - return numa_cpu_lookup_table[cpu]; + int nid; + + nid = numa_cpu_lookup_table[cpu]; + + /* + * During early boot, the numa-cpu lookup table might not have been + * setup for all CPUs yet. In such cases, default to node 0. + */ + return (nid < 0) ? 0 : nid; } #define parent_node(node) (node) diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h index 68d0cc998b1b..4f9b7ca0710f 100644 --- a/arch/powerpc/include/asm/vio.h +++ b/arch/powerpc/include/asm/vio.h @@ -15,7 +15,6 @@ #define _ASM_POWERPC_VIO_H #ifdef __KERNEL__ -#include <linux/init.h> #include <linux/errno.h> #include <linux/device.h> #include <linux/dma-mapping.h> diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 445cb6e39d5b..904d713366ff 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index d3de01066f7d..8d1d94d9c649 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -203,6 +203,15 @@ int main(void) DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack)); DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack)); DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack)); + DEFINE(PACA_TCD_PTR, offsetof(struct paca_struct, tcd_ptr)); + + DEFINE(TCD_ESEL_NEXT, + offsetof(struct tlb_core_data, esel_next)); + DEFINE(TCD_ESEL_MAX, + offsetof(struct tlb_core_data, esel_max)); + DEFINE(TCD_ESEL_FIRST, + offsetof(struct tlb_core_data, esel_first)); + DEFINE(TCD_LOCK, offsetof(struct tlb_core_data, lock)); #endif /* CONFIG_PPC_BOOK3E */ #ifdef CONFIG_PPC_STD_MMU_64 @@ -232,6 +241,10 @@ int main(void) DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx)); #endif /* CONFIG_PPC_STD_MMU_64 */ DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); +#ifdef CONFIG_PPC_BOOK3S_64 + DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp)); + DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce)); +#endif DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime)); diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index 654932727873..abfa011344d9 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -12,7 +12,6 @@ #include <linux/cpu.h> #include <linux/cpumask.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/kobject.h> #include <linux/list.h> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index bfb18c7290b7..cc2d8962e090 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -53,11 +53,57 @@ _GLOBAL(__e500_dcache_setup) isync blr +/* + * FIXME - we haven't yet done testing to determine a reasonable default + * value for PW20_WAIT_IDLE_BIT. + */ +#define PW20_WAIT_IDLE_BIT 50 /* 1ms, TB frequency is 41.66MHZ */ +_GLOBAL(setup_pw20_idle) + mfspr r3, SPRN_PWRMGTCR0 + + /* Set PW20_WAIT bit, enable pw20 state*/ + ori r3, r3, PWRMGTCR0_PW20_WAIT + li r11, PW20_WAIT_IDLE_BIT + + /* Set Automatic PW20 Core Idle Count */ + rlwimi r3, r11, PWRMGTCR0_PW20_ENT_SHIFT, PWRMGTCR0_PW20_ENT + + mtspr SPRN_PWRMGTCR0, r3 + + blr + +/* + * FIXME - we haven't yet done testing to determine a reasonable default + * value for AV_WAIT_IDLE_BIT. + */ +#define AV_WAIT_IDLE_BIT 50 /* 1ms, TB frequency is 41.66MHZ */ +_GLOBAL(setup_altivec_idle) + mfspr r3, SPRN_PWRMGTCR0 + + /* Enable Altivec Idle */ + oris r3, r3, PWRMGTCR0_AV_IDLE_PD_EN@h + li r11, AV_WAIT_IDLE_BIT + + /* Set Automatic AltiVec Idle Count */ + rlwimi r3, r11, PWRMGTCR0_AV_IDLE_CNT_SHIFT, PWRMGTCR0_AV_IDLE_CNT + + mtspr SPRN_PWRMGTCR0, r3 + + blr + _GLOBAL(__setup_cpu_e6500) mflr r6 #ifdef CONFIG_PPC64 bl .setup_altivec_ivors + /* Touch IVOR42 only if the CPU supports E.HV category */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f + bl .setup_lrat_ivor +1: #endif + bl setup_pw20_idle + bl setup_altivec_idle bl __setup_cpu_e5500 mtlr r6 blr @@ -119,6 +165,14 @@ _GLOBAL(__setup_cpu_e5500) _GLOBAL(__restore_cpu_e6500) mflr r5 bl .setup_altivec_ivors + /* Touch IVOR42 only if the CPU supports E.HV category */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f + bl .setup_lrat_ivor +1: + bl .setup_pw20_idle + bl .setup_altivec_idle bl __restore_cpu_e5500 mtlr r5 blr diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 18b5b9cf8e37..37d1bb002aa9 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -29,7 +29,7 @@ _GLOBAL(__setup_cpu_power7) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -42,7 +42,7 @@ _GLOBAL(__restore_cpu_power7) mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -59,7 +59,7 @@ _GLOBAL(__setup_cpu_power8) oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -78,7 +78,7 @@ _GLOBAL(__restore_cpu_power8) oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -134,15 +134,31 @@ __init_HFSCR: mtspr SPRN_HFSCR,r3 blr -__init_TLB: - /* - * Clear the TLB using the "IS 3" form of tlbiel instruction - * (invalidate by congruence class). P7 has 128 CCs, P8 has 512 - * so we just always do 512 - */ +/* + * Clear the TLB using the specified IS form of tlbiel instruction + * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. + * + * r3 = IS field + */ +__init_tlb_power7: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power7) + li r6,128 + mtctr r6 + mr r7,r3 /* IS field */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr + +__init_tlb_power8: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power8) li r6,512 mtctr r6 - li r7,0xc00 /* IS field = 0b11 */ + mr r7,r3 /* IS field */ ptesync 2: tlbiel r7 addi r7,r7,0x1000 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 597d954e5860..6c8dd5da4de5 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -71,6 +71,10 @@ extern void __restore_cpu_power7(void); extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power8(void); extern void __restore_cpu_a2(void); +extern void __flush_tlb_power7(unsigned long inval_selector); +extern void __flush_tlb_power8(unsigned long inval_selector); +extern long __machine_check_early_realmode_p7(struct pt_regs *regs); +extern long __machine_check_early_realmode_p8(struct pt_regs *regs); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); @@ -440,6 +444,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* 2.07-compliant processor, i.e. Power8 "architected" mode */ @@ -456,6 +462,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power7 */ @@ -474,6 +482,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* Power7+ */ @@ -492,6 +502,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7+", }, { /* Power8E */ @@ -510,6 +522,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power8 */ @@ -528,6 +542,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Cell Broadband Engine */ diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index fdcd8f551aff..18d7c80ddeb9 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -17,7 +17,6 @@ #include <linux/export.h> #include <linux/crash_dump.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/irq.h> #include <linux/types.h> diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index e4897523de41..54d0116256f7 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -83,10 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) return 0; } - if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT)) { + if (tbl->it_offset > (mask >> tbl->it_page_shift)) { dev_info(dev, "Warning: IOMMU offset too big for device mask\n"); dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n", - mask, tbl->it_offset << IOMMU_PAGE_SHIFT); + mask, tbl->it_offset << tbl->it_page_shift); return 0; } else return 1; diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 4bd687d5e7aa..148db72a8c43 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -84,7 +84,7 @@ #define EEH_MAX_FAILS 2100000 /* Time to wait for a PCI slot to report status, in milliseconds */ -#define PCI_BUS_RESET_WAIT_MSEC (60*1000) +#define PCI_BUS_RESET_WAIT_MSEC (5*60*1000) /* Platform dependent EEH operations */ struct eeh_ops *eeh_ops = NULL; @@ -921,6 +921,13 @@ void eeh_add_device_late(struct pci_dev *dev) eeh_sysfs_remove_device(edev->pdev); edev->mode &= ~EEH_DEV_SYSFS; + /* + * We definitely should have the PCI device removed + * though it wasn't correctly. So we needn't call + * into error handler afterwards. + */ + edev->mode |= EEH_DEV_NO_HANDLER; + edev->pdev = NULL; dev->dev.archdata.edev = NULL; } @@ -1023,6 +1030,14 @@ void eeh_remove_device(struct pci_dev *dev) else edev->mode |= EEH_DEV_DISCONNECTED; + /* + * We're removing from the PCI subsystem, that means + * the PCI device driver can't support EEH or not + * well. So we rely on hotplug completely to do recovery + * for the specific PCI device. + */ + edev->mode |= EEH_DEV_NO_HANDLER; + eeh_addr_cache_rmv_dev(dev); eeh_sysfs_remove_device(dev); edev->mode &= ~EEH_DEV_SYSFS; diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index c17f90d0f73c..7bb30dca4e19 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -217,7 +217,8 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (!driver) return NULL; if (!driver->err_handler || - !driver->err_handler->mmio_enabled) { + !driver->err_handler->mmio_enabled || + (edev->mode & EEH_DEV_NO_HANDLER)) { eeh_pcid_put(dev); return NULL; } @@ -258,7 +259,8 @@ static void *eeh_report_reset(void *data, void *userdata) eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->slot_reset) { + !driver->err_handler->slot_reset || + (edev->mode & EEH_DEV_NO_HANDLER)) { eeh_pcid_put(dev); return NULL; } @@ -297,7 +299,9 @@ static void *eeh_report_resume(void *data, void *userdata) eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->resume) { + !driver->err_handler->resume || + (edev->mode & EEH_DEV_NO_HANDLER)) { + edev->mode &= ~EEH_DEV_NO_HANDLER; eeh_pcid_put(dev); return NULL; } @@ -476,7 +480,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) /* The longest amount of time to wait for a pci device * to come back on line, in seconds. */ -#define MAX_WAIT_FOR_RECOVERY 150 +#define MAX_WAIT_FOR_RECOVERY 300 static void eeh_handle_normal_event(struct eeh_pe *pe) { @@ -637,86 +641,92 @@ static void eeh_handle_special_event(void) { struct eeh_pe *pe, *phb_pe; struct pci_bus *bus; - struct pci_controller *hose, *tmp; + struct pci_controller *hose; unsigned long flags; - int rc = 0; + int rc; - /* - * The return value from next_error() has been classified as follows. - * It might be good to enumerate them. However, next_error() is only - * supported by PowerNV platform for now. So it would be fine to use - * integer directly: - * - * 4 - Dead IOC 3 - Dead PHB - * 2 - Fenced PHB 1 - Frozen PE - * 0 - No error found - * - */ - rc = eeh_ops->next_error(&pe); - if (rc <= 0) - return; - switch (rc) { - case 4: - /* Mark all PHBs in dead state */ - eeh_serialize_lock(&flags); - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe) continue; - - eeh_pe_state_mark(phb_pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + do { + rc = eeh_ops->next_error(&pe); + + switch (rc) { + case EEH_NEXT_ERR_DEAD_IOC: + /* Mark all PHBs in dead state */ + eeh_serialize_lock(&flags); + + /* Purge all events */ + eeh_remove_event(NULL); + + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe) continue; + + eeh_pe_state_mark(phb_pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + } + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_FROZEN_PE: + case EEH_NEXT_ERR_FENCED_PHB: + case EEH_NEXT_ERR_DEAD_PHB: + /* Mark the PE in fenced state */ + eeh_serialize_lock(&flags); + + /* Purge all events of the PHB */ + eeh_remove_event(pe); + + if (rc == EEH_NEXT_ERR_DEAD_PHB) + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + else + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_RECOVERING); + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_NONE: + return; + default: + pr_warn("%s: Invalid value %d from next_error()\n", + __func__, rc); + return; } - eeh_serialize_unlock(flags); - - /* Purge all events */ - eeh_remove_event(NULL); - break; - case 3: - case 2: - case 1: - /* Mark the PE in fenced state */ - eeh_serialize_lock(&flags); - if (rc == 3) - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); - else - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_RECOVERING); - eeh_serialize_unlock(flags); - - /* Purge all events of the PHB */ - eeh_remove_event(pe); - break; - default: - pr_err("%s: Invalid value %d from next_error()\n", - __func__, rc); - return; - } - /* - * For fenced PHB and frozen PE, it's handled as normal - * event. We have to remove the affected PHBs for dead - * PHB and IOC - */ - if (rc == 2 || rc == 1) - eeh_handle_normal_event(pe); - else { - pci_lock_rescan_remove(); - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe || !(phb_pe->state & EEH_PE_PHB_DEAD)) - continue; - - bus = eeh_pe_bus_get(phb_pe); - /* Notify all devices that they're about to go down. */ - eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); - pcibios_remove_pci_devices(bus); + /* + * For fenced PHB and frozen PE, it's handled as normal + * event. We have to remove the affected PHBs for dead + * PHB and IOC + */ + if (rc == EEH_NEXT_ERR_FROZEN_PE || + rc == EEH_NEXT_ERR_FENCED_PHB) { + eeh_handle_normal_event(pe); + } else { + pci_lock_rescan_remove(); + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe || + !(phb_pe->state & EEH_PE_PHB_DEAD)) + continue; + + /* Notify all devices to be down */ + bus = eeh_pe_bus_get(phb_pe); + eeh_pe_dev_traverse(pe, + eeh_report_failure, NULL); + pcibios_remove_pci_devices(bus); + } + pci_unlock_rescan_remove(); } - pci_unlock_rescan_remove(); - } + + /* + * If we have detected dead IOC, we needn't proceed + * any more since all PHBs would have been removed + */ + if (rc == EEH_NEXT_ERR_DEAD_IOC) + break; + } while (rc != EEH_NEXT_ERR_NONE); } /** diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index f9450537e335..f0c353fa655a 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -25,7 +25,6 @@ #include <linux/delay.h> #include <linux/export.h> #include <linux/gfp.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/string.h> @@ -737,6 +736,9 @@ static void *eeh_restore_one_device_bars(void *data, void *flag) else eeh_restore_device_bars(edev, dn); + if (eeh_ops->restore_config) + eeh_ops->restore_config(dn); + return NULL; } diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bbfb0294b354..662c6dd98072 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -664,8 +664,16 @@ _GLOBAL(ret_from_except_lite) bl .restore_interrupts SCHEDULE_USER b .ret_from_except_lite - -2: bl .save_nvgprs +2: +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM + bne 3f /* only restore TM if nothing else to do */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .restore_tm_state + b restore +3: +#endif + bl .save_nvgprs bl .restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index e7751561fd1d..063b65dd4f27 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -308,6 +308,7 @@ interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x2e0, guest_doorbell_crit) EXCEPTION_STUB(0x300, hypercall) EXCEPTION_STUB(0x320, ehpriv) + EXCEPTION_STUB(0x340, lrat_error) .globl interrupt_end_book3e interrupt_end_book3e: @@ -677,6 +678,17 @@ kernel_dbg_exc: bl .unknown_exception b .ret_from_except +/* LRAT Error interrupt */ + START_EXCEPTION(lrat_error); + NORMAL_EXCEPTION_PROLOG(0x340, BOOKE_INTERRUPT_LRAT_ERROR, + PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x340, PACA_EXGEN, INTS_KEEP) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD + bl .unknown_exception + b .ret_from_except + /* * An interrupt came in while soft-disabled; We mark paca->irq_happened * accordingly and if the interrupt is level sensitive, we hard disable @@ -859,6 +871,7 @@ BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) BAD_STACK_TRAMPOLINE(0x310) BAD_STACK_TRAMPOLINE(0x320) +BAD_STACK_TRAMPOLINE(0x340) BAD_STACK_TRAMPOLINE(0x400) BAD_STACK_TRAMPOLINE(0x500) BAD_STACK_TRAMPOLINE(0x600) @@ -1055,12 +1068,9 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS0,r3 tlbre mfspr r6,SPRN_MAS1 - rlwinm r6,r6,0,2,0 /* clear IPROT */ + rlwinm r6,r6,0,2,31 /* clear IPROT and VALID */ mtspr SPRN_MAS1,r6 tlbwe - - /* Invalidate TLB1 */ - PPC_TLBILX_ALL(0,R0) sync isync @@ -1114,12 +1124,9 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS0,r4 tlbre mfspr r5,SPRN_MAS1 - rlwinm r5,r5,0,2,0 /* clear IPROT */ + rlwinm r5,r5,0,2,31 /* clear IPROT and VALID */ mtspr SPRN_MAS1,r5 tlbwe - - /* Invalidate TLB1 */ - PPC_TLBILX_ALL(0,R0) sync isync @@ -1414,3 +1421,7 @@ _GLOBAL(setup_ehv_ivors) SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ blr + +_GLOBAL(setup_lrat_ivor) + SET_IVOR(42, 0x340) /* LRAT Error */ + blr diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 9f905e40922e..38d507306a11 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -155,8 +155,30 @@ machine_check_pSeries_1: */ HMT_MEDIUM_PPR_DISCARD SET_SCRATCH0(r13) /* save r13 */ +#ifdef CONFIG_PPC_P7_NAP +BEGIN_FTR_SECTION + /* Running native on arch 2.06 or later, check if we are + * waking up from nap. We only handle no state loss and + * supervisor state loss. We do -not- handle hypervisor + * state loss at this time. + */ + mfspr r13,SPRN_SRR1 + rlwinm. r13,r13,47-31,30,31 + beq 9f + + /* waking up from powersave (nap) state */ + cmpwi cr1,r13,2 + /* Total loss of HV state is fatal. let's just stay stuck here */ + bgt cr1,. +9: +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +#endif /* CONFIG_PPC_P7_NAP */ EXCEPTION_PROLOG_0(PACA_EXMC) +BEGIN_FTR_SECTION + b machine_check_pSeries_early +FTR_SECTION_ELSE b machine_check_pSeries_0 +ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) . = 0x300 .globl data_access_pSeries @@ -405,6 +427,64 @@ denorm_exception_hv: .align 7 /* moved from 0x200 */ +machine_check_pSeries_early: +BEGIN_FTR_SECTION + EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) + /* + * Register contents: + * R13 = PACA + * R9 = CR + * Original R9 to R13 is saved on PACA_EXMC + * + * Switch to mc_emergency stack and handle re-entrancy (though we + * currently don't test for overflow). Save MCE registers srr1, + * srr0, dar and dsisr and then set ME=1 + * + * We use paca->in_mce to check whether this is the first entry or + * nested machine check. We increment paca->in_mce to track nested + * machine checks. + * + * If this is the first entry then set stack pointer to + * paca->mc_emergency_sp, otherwise r1 is already pointing to + * stack frame on mc_emergency stack. + * + * NOTE: We are here with MSR_ME=0 (off), which means we risk a + * checkstop if we get another machine check exception before we do + * rfid with MSR_ME=1. + */ + mr r11,r1 /* Save r1 */ + lhz r10,PACA_IN_MCE(r13) + cmpwi r10,0 /* Are we in nested machine check */ + bne 0f /* Yes, we are. */ + /* First machine check entry */ + ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */ +0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ + addi r10,r10,1 /* increment paca->in_mce */ + sth r10,PACA_IN_MCE(r13) + std r11,GPR1(r1) /* Save r1 on the stack. */ + std r11,0(r1) /* make stack chain pointer */ + mfspr r11,SPRN_SRR0 /* Save SRR0 */ + std r11,_NIP(r1) + mfspr r11,SPRN_SRR1 /* Save SRR1 */ + std r11,_MSR(r1) + mfspr r11,SPRN_DAR /* Save DAR */ + std r11,_DAR(r1) + mfspr r11,SPRN_DSISR /* Save DSISR */ + std r11,_DSISR(r1) + std r9,_CCR(r1) /* Save CR in stackframe */ + /* Save r9 through r13 from EXMC save area to stack frame. */ + EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) + mfmsr r11 /* get MSR value */ + ori r11,r11,MSR_ME /* turn on ME bit */ + ori r11,r11,MSR_RI /* turn on RI bit */ + ld r12,PACAKBASE(r13) /* get high part of &label */ + LOAD_HANDLER(r12, machine_check_handle_early) + mtspr SPRN_SRR0,r12 + mtspr SPRN_SRR1,r11 + rfid + b . /* prevent speculative execution */ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) + machine_check_pSeries: .globl machine_check_fwnmi machine_check_fwnmi: @@ -688,30 +768,6 @@ kvmppc_skip_Hinterrupt: STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) - /* - * Machine check is different because we use a different - * save area: PACA_EXMC instead of PACA_EXGEN. - */ - .align 7 - .globl machine_check_common -machine_check_common: - - mfspr r10,SPRN_DAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,SPRN_DSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) - FINISH_NAP - DISABLE_INTS - ld r3,PACA_EXGEN+EX_DAR(r13) - lwz r4,PACA_EXGEN+EX_DSISR(r13) - std r3,_DAR(r1) - std r4,_DSISR(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception - b .ret_from_except - STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) @@ -1080,6 +1136,30 @@ unrecov_user_slb: #endif /* __DISABLED__ */ + /* + * Machine check is different because we use a different + * save area: PACA_EXMC instead of PACA_EXGEN. + */ + .align 7 + .globl machine_check_common +machine_check_common: + + mfspr r10,SPRN_DAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_DSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) + FINISH_NAP + DISABLE_INTS + ld r3,PACA_EXGEN+EX_DAR(r13) + lwz r4,PACA_EXGEN+EX_DSISR(r13) + std r3,_DAR(r1) + std r4,_DSISR(r1) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_exception + b .ret_from_except + .align 7 .globl alignment_common alignment_common: @@ -1263,6 +1343,120 @@ _GLOBAL(opal_mc_secondary_handler) #endif /* CONFIG_PPC_POWERNV */ +#define MACHINE_CHECK_HANDLER_WINDUP \ + /* Clear MSR_RI before setting SRR0 and SRR1. */\ + li r0,MSR_RI; \ + mfmsr r9; /* get MSR value */ \ + andc r9,r9,r0; \ + mtmsrd r9,1; /* Clear MSR_RI */ \ + /* Move original SRR0 and SRR1 into the respective regs */ \ + ld r9,_MSR(r1); \ + mtspr SPRN_SRR1,r9; \ + ld r3,_NIP(r1); \ + mtspr SPRN_SRR0,r3; \ + ld r9,_CTR(r1); \ + mtctr r9; \ + ld r9,_XER(r1); \ + mtxer r9; \ + ld r9,_LINK(r1); \ + mtlr r9; \ + REST_GPR(0, r1); \ + REST_8GPRS(2, r1); \ + REST_GPR(10, r1); \ + ld r11,_CCR(r1); \ + mtcr r11; \ + /* Decrement paca->in_mce. */ \ + lhz r12,PACA_IN_MCE(r13); \ + subi r12,r12,1; \ + sth r12,PACA_IN_MCE(r13); \ + REST_GPR(11, r1); \ + REST_2GPRS(12, r1); \ + /* restore original r1. */ \ + ld r1,GPR1(r1) + + /* + * Handle machine check early in real mode. We come here with + * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack. + */ + .align 7 + .globl machine_check_handle_early +machine_check_handle_early: + std r0,GPR0(r1) /* Save r0 */ + EXCEPTION_PROLOG_COMMON_3(0x200) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_early + ld r12,_MSR(r1) +#ifdef CONFIG_PPC_P7_NAP + /* + * Check if thread was in power saving mode. We come here when any + * of the following is true: + * a. thread wasn't in power saving mode + * b. thread was in power saving mode with no state loss or + * supervisor state loss + * + * Go back to nap again if (b) is true. + */ + rlwinm. r11,r12,47-31,30,31 /* Was it in power saving mode? */ + beq 4f /* No, it wasn;t */ + /* Thread was in power saving mode. Go back to nap again. */ + cmpwi r11,2 + bne 3f + /* Supervisor state loss */ + li r0,1 + stb r0,PACA_NAPSTATELOST(r13) +3: bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + GET_PACA(r13) + ld r1,PACAR1(r13) + b .power7_enter_nap_mode +4: +#endif + /* + * Check if we are coming from hypervisor userspace. If yes then we + * continue in host kernel in V mode to deliver the MC event. + */ + rldicl. r11,r12,4,63 /* See if MC hit while in HV mode. */ + beq 5f + andi. r11,r12,MSR_PR /* See if coming from user. */ + bne 9f /* continue in V mode if we are. */ + +5: +#ifdef CONFIG_KVM_BOOK3S_64_HV + /* + * We are coming from kernel context. Check if we are coming from + * guest. if yes, then we can continue. We will fall through + * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest. + */ + lbz r11,HSTATE_IN_GUEST(r13) + cmpwi r11,0 /* Check if coming from guest */ + bne 9f /* continue if we are. */ +#endif + /* + * At this point we are not sure about what context we come from. + * Queue up the MCE event and return from the interrupt. + * But before that, check if this is an un-recoverable exception. + * If yes, then stay on emergency stack and panic. + */ + andi. r11,r12,MSR_RI + bne 2f +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b +2: + /* + * Return from MC interrupt. + * Queue up the MCE event so that we can log it later, while + * returning from kernel or opal call. + */ + bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + rfid +9: + /* Deliver the machine check to host kernel in V mode. */ + MACHINE_CHECK_HANDLER_WINDUP + b machine_check_pSeries + /* * r13 points to the PACA, r9 contains the saved CR, * r12 contain the saved SRR1, SRR0 is still ready for return diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index f7f5b8bed68f..9ad236e5d2c9 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -81,6 +81,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ /* + * Enable use of the FPU, and VSX if possible, for the caller. + */ +_GLOBAL(fp_enable) + mfmsr r3 + ori r3,r3,MSR_FP +#ifdef CONFIG_VSX +BEGIN_FTR_SECTION + oris r3,r3,MSR_VSX@h +END_FTR_SECTION_IFSET(CPU_FTR_VSX) +#endif + SYNC + MTMSRD(r3) + isync /* (not necessary for arch 2.02 and later) */ + blr + +/* * Load state from memory into FP registers including FPSCR. * Assumes the caller has enabled FP in the MSR. */ diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index a92c79be2728..f22e7e44fbf3 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -176,6 +176,8 @@ skpinv: addi r6,r6,1 /* Increment */ /* 7. Jump to KERNELBASE mapping */ lis r6,(KERNELBASE & ~0xfff)@h ori r6,r6,(KERNELBASE & ~0xfff)@l + rlwinm r7,r25,0,0x03ffffff + add r6,r7,r6 #elif defined(ENTRY_MAPPING_KEXEC_SETUP) /* diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 4f0946de2d5c..b7363bd42452 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -23,6 +23,7 @@ */ #include <linux/threads.h> +#include <linux/init.h> #include <asm/reg.h> #include <asm/page.h> #include <asm/mmu.h> diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index f45726a1d963..b497188a94a1 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -65,29 +65,78 @@ _ENTRY(_start); nop /* Translate device tree address to physical, save in r30/r31 */ - mfmsr r16 - mfspr r17,SPRN_PID - rlwinm r17,r17,16,0x3fff0000 /* turn PID into MAS6[SPID] */ - rlwimi r17,r16,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ - mtspr SPRN_MAS6,r17 - - tlbsx 0,r3 /* must succeed */ - - mfspr r16,SPRN_MAS1 - mfspr r20,SPRN_MAS3 - rlwinm r17,r16,25,0x1f /* r17 = log2(page size) */ - li r18,1024 - slw r18,r18,r17 /* r18 = page size */ - addi r18,r18,-1 - and r19,r3,r18 /* r19 = page offset */ - andc r31,r20,r18 /* r31 = page base */ - or r31,r31,r19 /* r31 = devtree phys addr */ - mfspr r30,SPRN_MAS7 + bl get_phys_addr + mr r30,r3 + mr r31,r4 li r25,0 /* phys kernel start (low) */ li r24,0 /* CPU number */ li r23,0 /* phys kernel start (high) */ +#ifdef CONFIG_RELOCATABLE + LOAD_REG_ADDR_PIC(r3, _stext) /* Get our current runtime base */ + + /* Translate _stext address to physical, save in r23/r25 */ + bl get_phys_addr + mr r23,r3 + mr r25,r4 + + bl 0f +0: mflr r8 + addis r3,r8,(is_second_reloc - 0b)@ha + lwz r19,(is_second_reloc - 0b)@l(r3) + + /* Check if this is the second relocation. */ + cmpwi r19,1 + bne 1f + + /* + * For the second relocation, we already get the real memstart_addr + * from device tree. So we will map PAGE_OFFSET to memstart_addr, + * then the virtual address of start kernel should be: + * PAGE_OFFSET + (kernstart_addr - memstart_addr) + * Since the offset between kernstart_addr and memstart_addr should + * never be beyond 1G, so we can just use the lower 32bit of them + * for the calculation. + */ + lis r3,PAGE_OFFSET@h + + addis r4,r8,(kernstart_addr - 0b)@ha + addi r4,r4,(kernstart_addr - 0b)@l + lwz r5,4(r4) + + addis r6,r8,(memstart_addr - 0b)@ha + addi r6,r6,(memstart_addr - 0b)@l + lwz r7,4(r6) + + subf r5,r7,r5 + add r3,r3,r5 + b 2f + +1: + /* + * We have the runtime (virutal) address of our base. + * We calculate our shift of offset from a 64M page. + * We could map the 64M page we belong to at PAGE_OFFSET and + * get going from there. + */ + lis r4,KERNELBASE@h + ori r4,r4,KERNELBASE@l + rlwinm r6,r25,0,0x3ffffff /* r6 = PHYS_START % 64M */ + rlwinm r5,r4,0,0x3ffffff /* r5 = KERNELBASE % 64M */ + subf r3,r5,r6 /* r3 = r6 - r5 */ + add r3,r4,r3 /* Required Virtual Address */ + +2: bl relocate + + /* + * For the second relocation, we already set the right tlb entries + * for the kernel space, so skip the code in fsl_booke_entry_mapping.S + */ + cmpwi r19,1 + beq set_ivor +#endif + /* We try to not make any assumptions about how the boot loader * setup or used the TLBs. We invalidate all mappings from the * boot loader and load a single entry in TLB1[0] to map the @@ -113,6 +162,7 @@ _ENTRY(__early_start) #include "fsl_booke_entry_mapping.S" #undef ENTRY_MAPPING_BOOT_SETUP +set_ivor: /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); SET_IVOR(1, MachineCheck); @@ -166,8 +216,7 @@ _ENTRY(__early_start) /* Check to see if we're the second processor, and jump * to the secondary_start code if so */ - lis r24, boot_cpuid@h - ori r24, r24, boot_cpuid@l + LOAD_REG_ADDR_PIC(r24, boot_cpuid) lwz r24, 0(r24) cmpwi r24, -1 mfspr r24,SPRN_PIR @@ -197,6 +246,18 @@ _ENTRY(__early_start) bl early_init +#ifdef CONFIG_RELOCATABLE + mr r3,r30 + mr r4,r31 +#ifdef CONFIG_PHYS_64BIT + mr r5,r23 + mr r6,r25 +#else + mr r5,r25 +#endif + bl relocate_init +#endif + #ifdef CONFIG_DYNAMIC_MEMSTART lis r3,kernstart_addr@ha la r3,kernstart_addr@l(r3) @@ -856,6 +917,33 @@ KernelSPE: #endif /* CONFIG_SPE */ /* + * Translate the effec addr in r3 to phys addr. The phys addr will be put + * into r3(higher 32bit) and r4(lower 32bit) + */ +get_phys_addr: + mfmsr r8 + mfspr r9,SPRN_PID + rlwinm r9,r9,16,0x3fff0000 /* turn PID into MAS6[SPID] */ + rlwimi r9,r8,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ + mtspr SPRN_MAS6,r9 + + tlbsx 0,r3 /* must succeed */ + + mfspr r8,SPRN_MAS1 + mfspr r12,SPRN_MAS3 + rlwinm r9,r8,25,0x1f /* r9 = log2(page size) */ + li r10,1024 + slw r10,r10,r9 /* r10 = page size */ + addi r10,r10,-1 + and r11,r3,r10 /* r11 = page offset */ + andc r4,r12,r10 /* r4 = page base */ + or r4,r4,r11 /* r4 = devtree phys addr */ +#ifdef CONFIG_PHYS_64BIT + mfspr r3,SPRN_MAS7 +#endif + blr + +/* * Global functions */ @@ -1057,24 +1145,36 @@ _GLOBAL(__flush_disable_L1) /* When we get here, r24 needs to hold the CPU # */ .globl __secondary_start __secondary_start: - lis r3,__secondary_hold_acknowledge@h - ori r3,r3,__secondary_hold_acknowledge@l - stw r24,0(r3) - - li r3,0 - mr r4,r24 /* Why? */ - bl call_setup_cpu - - lis r3,tlbcam_index@ha - lwz r3,tlbcam_index@l(r3) + LOAD_REG_ADDR_PIC(r3, tlbcam_index) + lwz r3,0(r3) mtctr r3 li r26,0 /* r26 safe? */ + bl switch_to_as1 + mr r27,r3 /* tlb entry */ /* Load each CAM entry */ 1: mr r3,r26 bl loadcam_entry addi r26,r26,1 bdnz 1b + mr r3,r27 /* tlb entry */ + LOAD_REG_ADDR_PIC(r4, memstart_addr) + lwz r4,0(r4) + mr r5,r25 /* phys kernel start */ + rlwinm r5,r5,0,~0x3ffffff /* aligned 64M */ + subf r4,r5,r4 /* memstart_addr - phys kernel start */ + li r5,0 /* no device tree */ + li r6,0 /* not boot cpu */ + bl restore_to_as0 + + + lis r3,__secondary_hold_acknowledge@h + ori r3,r3,__secondary_hold_acknowledge@l + stw r24,0(r3) + + li r3,0 + mr r4,r24 /* Why? */ + bl call_setup_cpu /* get current_thread_info and current */ lis r1,secondary_ti@ha @@ -1111,6 +1211,112 @@ __secondary_hold_acknowledge: #endif /* + * Create a tlb entry with the same effective and physical address as + * the tlb entry used by the current running code. But set the TS to 1. + * Then switch to the address space 1. It will return with the r3 set to + * the ESEL of the new created tlb. + */ +_GLOBAL(switch_to_as1) + mflr r5 + + /* Find a entry not used */ + mfspr r3,SPRN_TLB1CFG + andi. r3,r3,0xfff + mfspr r4,SPRN_PID + rlwinm r4,r4,16,0x3fff0000 /* turn PID into MAS6[SPID] */ + mtspr SPRN_MAS6,r4 +1: lis r4,0x1000 /* Set MAS0(TLBSEL) = 1 */ + addi r3,r3,-1 + rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r4 + tlbre + mfspr r4,SPRN_MAS1 + andis. r4,r4,MAS1_VALID@h + bne 1b + + /* Get the tlb entry used by the current running code */ + bl 0f +0: mflr r4 + tlbsx 0,r4 + + mfspr r4,SPRN_MAS1 + ori r4,r4,MAS1_TS /* Set the TS = 1 */ + mtspr SPRN_MAS1,r4 + + mfspr r4,SPRN_MAS0 + rlwinm r4,r4,0,~MAS0_ESEL_MASK + rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r4 + tlbwe + isync + sync + + mfmsr r4 + ori r4,r4,MSR_IS | MSR_DS + mtspr SPRN_SRR0,r5 + mtspr SPRN_SRR1,r4 + sync + rfi + +/* + * Restore to the address space 0 and also invalidate the tlb entry created + * by switch_to_as1. + * r3 - the tlb entry which should be invalidated + * r4 - __pa(PAGE_OFFSET in AS1) - __pa(PAGE_OFFSET in AS0) + * r5 - device tree virtual address. If r4 is 0, r5 is ignored. + * r6 - boot cpu +*/ +_GLOBAL(restore_to_as0) + mflr r0 + + bl 0f +0: mflr r9 + addi r9,r9,1f - 0b + + /* + * We may map the PAGE_OFFSET in AS0 to a different physical address, + * so we need calculate the right jump and device tree address based + * on the offset passed by r4. + */ + add r9,r9,r4 + add r5,r5,r4 + add r0,r0,r4 + +2: mfmsr r7 + li r8,(MSR_IS | MSR_DS) + andc r7,r7,r8 + + mtspr SPRN_SRR0,r9 + mtspr SPRN_SRR1,r7 + sync + rfi + + /* Invalidate the temporary tlb entry for AS1 */ +1: lis r9,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r9,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r9 + tlbre + mfspr r9,SPRN_MAS1 + rlwinm r9,r9,0,2,31 /* Clear MAS1 Valid and IPPROT */ + mtspr SPRN_MAS1,r9 + tlbwe + isync + + cmpwi r4,0 + cmpwi cr1,r6,0 + cror eq,4*cr1+eq,eq + bne 3f /* offset != 0 && is_boot_cpu */ + mtlr r0 + blr + + /* + * The PAGE_OFFSET will map to a different physical address, + * jump to _start to do another relocation again. + */ +3: mr r3,r5 + bl _start + +/* * We put a few things here that have to be page-aligned. This stuff * goes at the beginning of the data segment, which is page-aligned. */ diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index f0b47d1a6b0e..b0a1792279bb 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -28,7 +28,6 @@ #include <linux/percpu.h> #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/init.h> #include <linux/smp.h> #include <asm/hw_breakpoint.h> diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index 847e40e62fce..3fdef0f0c67f 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -84,6 +84,7 @@ _GLOBAL(power7_nap) std r9,_MSR(r1) std r1,PACAR1(r13) +_GLOBAL(power7_enter_nap_mode) #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE /* Tell KVM we're napping */ li r4,KVM_HWTHREAD_IN_NAP diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index 97a3715ac8bd..b82227e7e21b 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c @@ -3,7 +3,6 @@ * * (C) Copyright 2004 Linus Torvalds */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/mm.h> #include <linux/export.h> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 572bb5b95f35..d773dd440a45 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -251,14 +251,13 @@ again: if (dev) boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, - 1 << IOMMU_PAGE_SHIFT); + 1 << tbl->it_page_shift); else - boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT); + boundary_size = ALIGN(1UL << 32, 1 << tbl->it_page_shift); /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */ - n = iommu_area_alloc(tbl->it_map, limit, start, npages, - tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT, - align_mask); + n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset, + boundary_size >> tbl->it_page_shift, align_mask); if (n == -1) { if (likely(pass == 0)) { /* First try the pool from the start */ @@ -320,12 +319,12 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, return DMA_ERROR_CODE; entry += tbl->it_offset; /* Offset into real TCE table */ - ret = entry << IOMMU_PAGE_SHIFT; /* Set the return dma address */ + ret = entry << tbl->it_page_shift; /* Set the return dma address */ /* Put the TCEs in the HW table */ build_fail = ppc_md.tce_build(tbl, entry, npages, - (unsigned long)page & IOMMU_PAGE_MASK, - direction, attrs); + (unsigned long)page & + IOMMU_PAGE_MASK(tbl), direction, attrs); /* ppc_md.tce_build() only returns non-zero for transient errors. * Clean up the table bitmap in this case and return @@ -352,7 +351,7 @@ static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr, { unsigned long entry, free_entry; - entry = dma_addr >> IOMMU_PAGE_SHIFT; + entry = dma_addr >> tbl->it_page_shift; free_entry = entry - tbl->it_offset; if (((free_entry + npages) > tbl->it_size) || @@ -401,7 +400,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned long flags; struct iommu_pool *pool; - entry = dma_addr >> IOMMU_PAGE_SHIFT; + entry = dma_addr >> tbl->it_page_shift; free_entry = entry - tbl->it_offset; pool = get_pool(tbl, free_entry); @@ -468,13 +467,13 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, } /* Allocate iommu entries for that segment */ vaddr = (unsigned long) sg_virt(s); - npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE(tbl)); align = 0; - if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE && + if (tbl->it_page_shift < PAGE_SHIFT && slen >= PAGE_SIZE && (vaddr & ~PAGE_MASK) == 0) - align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; + align = PAGE_SHIFT - tbl->it_page_shift; entry = iommu_range_alloc(dev, tbl, npages, &handle, - mask >> IOMMU_PAGE_SHIFT, align); + mask >> tbl->it_page_shift, align); DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); @@ -489,16 +488,16 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, /* Convert entry to a dma_addr_t */ entry += tbl->it_offset; - dma_addr = entry << IOMMU_PAGE_SHIFT; - dma_addr |= (s->offset & ~IOMMU_PAGE_MASK); + dma_addr = entry << tbl->it_page_shift; + dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl)); DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n", npages, entry, dma_addr); /* Insert into HW table */ build_fail = ppc_md.tce_build(tbl, entry, npages, - vaddr & IOMMU_PAGE_MASK, - direction, attrs); + vaddr & IOMMU_PAGE_MASK(tbl), + direction, attrs); if(unlikely(build_fail)) goto failure; @@ -559,9 +558,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, if (s->dma_length != 0) { unsigned long vaddr, npages; - vaddr = s->dma_address & IOMMU_PAGE_MASK; + vaddr = s->dma_address & IOMMU_PAGE_MASK(tbl); npages = iommu_num_pages(s->dma_address, s->dma_length, - IOMMU_PAGE_SIZE); + IOMMU_PAGE_SIZE(tbl)); __iommu_free(tbl, vaddr, npages); s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; @@ -592,7 +591,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, if (sg->dma_length == 0) break; npages = iommu_num_pages(dma_handle, sg->dma_length, - IOMMU_PAGE_SIZE); + IOMMU_PAGE_SIZE(tbl)); __iommu_free(tbl, dma_handle, npages); sg = sg_next(sg); } @@ -676,7 +675,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) set_bit(0, tbl->it_map); /* We only split the IOMMU table if we have 1GB or more of space */ - if ((tbl->it_size << IOMMU_PAGE_SHIFT) >= (1UL * 1024 * 1024 * 1024)) + if ((tbl->it_size << tbl->it_page_shift) >= (1UL * 1024 * 1024 * 1024)) tbl->nr_pools = IOMMU_NR_POOLS; else tbl->nr_pools = 1; @@ -768,16 +767,16 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, vaddr = page_address(page) + offset; uaddr = (unsigned long)vaddr; - npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl)); if (tbl) { align = 0; - if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && size >= PAGE_SIZE && + if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE && ((unsigned long)vaddr & ~PAGE_MASK) == 0) - align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; + align = PAGE_SHIFT - tbl->it_page_shift; dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction, - mask >> IOMMU_PAGE_SHIFT, align, + mask >> tbl->it_page_shift, align, attrs); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { @@ -786,7 +785,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, npages); } } else - dma_handle |= (uaddr & ~IOMMU_PAGE_MASK); + dma_handle |= (uaddr & ~IOMMU_PAGE_MASK(tbl)); } return dma_handle; @@ -801,7 +800,8 @@ void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle, BUG_ON(direction == DMA_NONE); if (tbl) { - npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE); + npages = iommu_num_pages(dma_handle, size, + IOMMU_PAGE_SIZE(tbl)); iommu_free(tbl, dma_handle, npages); } } @@ -845,10 +845,10 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, memset(ret, 0, size); /* Set up tces to cover the allocated range */ - nio_pages = size >> IOMMU_PAGE_SHIFT; - io_order = get_iommu_order(size); + nio_pages = size >> tbl->it_page_shift; + io_order = get_iommu_order(size, tbl); mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, - mask >> IOMMU_PAGE_SHIFT, io_order, NULL); + mask >> tbl->it_page_shift, io_order, NULL); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); return NULL; @@ -864,7 +864,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size, unsigned int nio_pages; size = PAGE_ALIGN(size); - nio_pages = size >> IOMMU_PAGE_SHIFT; + nio_pages = size >> tbl->it_page_shift; iommu_free(tbl, dma_handle, nio_pages); size = PAGE_ALIGN(size); free_pages((unsigned long)vaddr, get_order(size)); @@ -935,10 +935,10 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl, if (tce_value) return -EINVAL; - if (ioba & ~IOMMU_PAGE_MASK) + if (ioba & ~IOMMU_PAGE_MASK(tbl)) return -EINVAL; - ioba >>= IOMMU_PAGE_SHIFT; + ioba >>= tbl->it_page_shift; if (ioba < tbl->it_offset) return -EINVAL; @@ -955,13 +955,13 @@ int iommu_tce_put_param_check(struct iommu_table *tbl, if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ))) return -EINVAL; - if (tce & ~(IOMMU_PAGE_MASK | TCE_PCI_WRITE | TCE_PCI_READ)) + if (tce & ~(IOMMU_PAGE_MASK(tbl) | TCE_PCI_WRITE | TCE_PCI_READ)) return -EINVAL; - if (ioba & ~IOMMU_PAGE_MASK) + if (ioba & ~IOMMU_PAGE_MASK(tbl)) return -EINVAL; - ioba >>= IOMMU_PAGE_SHIFT; + ioba >>= tbl->it_page_shift; if (ioba < tbl->it_offset) return -EINVAL; @@ -1037,7 +1037,7 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry, /* if (unlikely(ret)) pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n", - __func__, hwaddr, entry << IOMMU_PAGE_SHIFT, + __func__, hwaddr, entry << IOMMU_PAGE_SHIFT(tbl), hwaddr, ret); */ return ret; @@ -1049,14 +1049,14 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry, { int ret; struct page *page = NULL; - unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK & ~PAGE_MASK; + unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK; enum dma_data_direction direction = iommu_tce_direction(tce); ret = get_user_pages_fast(tce & PAGE_MASK, 1, direction != DMA_TO_DEVICE, &page); if (unlikely(ret != 1)) { /* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n", - tce, entry << IOMMU_PAGE_SHIFT, ret); */ + tce, entry << IOMMU_PAGE_SHIFT(tbl), ret); */ return -EFAULT; } hwaddr = (unsigned long) page_address(page) + offset; @@ -1067,7 +1067,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry, if (ret < 0) pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n", - __func__, entry << IOMMU_PAGE_SHIFT, tce, ret); + __func__, entry << tbl->it_page_shift, tce, ret); return ret; } @@ -1105,7 +1105,7 @@ void iommu_release_ownership(struct iommu_table *tbl) } EXPORT_SYMBOL_GPL(iommu_release_ownership); -static int iommu_add_device(struct device *dev) +int iommu_add_device(struct device *dev) { struct iommu_table *tbl; int ret = 0; @@ -1127,6 +1127,12 @@ static int iommu_add_device(struct device *dev) pr_debug("iommu_tce: adding %s to iommu group %d\n", dev_name(dev), iommu_group_id(tbl->it_group)); + if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) { + pr_err("iommu_tce: unsupported iommu page size."); + pr_err("%s has not been added\n", dev_name(dev)); + return -EINVAL; + } + ret = iommu_group_add_device(tbl->it_group, dev); if (ret < 0) pr_err("iommu_tce: %s has not been added, ret=%d\n", @@ -1134,52 +1140,23 @@ static int iommu_add_device(struct device *dev) return ret; } +EXPORT_SYMBOL_GPL(iommu_add_device); -static void iommu_del_device(struct device *dev) -{ - iommu_group_remove_device(dev); -} - -static int iommu_bus_notifier(struct notifier_block *nb, - unsigned long action, void *data) +void iommu_del_device(struct device *dev) { - struct device *dev = data; - - switch (action) { - case BUS_NOTIFY_ADD_DEVICE: - return iommu_add_device(dev); - case BUS_NOTIFY_DEL_DEVICE: - iommu_del_device(dev); - return 0; - default: - return 0; + /* + * Some devices might not have IOMMU table and group + * and we needn't detach them from the associated + * IOMMU groups + */ + if (!dev->iommu_group) { + pr_debug("iommu_tce: skipping device %s with no tbl\n", + dev_name(dev)); + return; } -} -static struct notifier_block tce_iommu_bus_nb = { - .notifier_call = iommu_bus_notifier, -}; - -static int __init tce_iommu_init(void) -{ - struct pci_dev *pdev = NULL; - - BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE); - - for_each_pci_dev(pdev) - iommu_add_device(&pdev->dev); - - bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); - return 0; -} - -subsys_initcall_sync(tce_iommu_init); - -#else - -void iommu_register_group(struct iommu_table *tbl, - int pci_domain_number, unsigned long pe_num) -{ + iommu_group_remove_device(dev); } +EXPORT_SYMBOL_GPL(iommu_del_device); #endif /* CONFIG_IOMMU_API */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index ba0165615215..9729b23bfb0a 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -354,8 +354,13 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%*s: ", prec, "LOC"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs); - seq_printf(p, " Local timer interrupts\n"); + seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_event); + seq_printf(p, " Local timer interrupts for timer event device\n"); + + seq_printf(p, "%*s: ", prec, "LOC"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_others); + seq_printf(p, " Local timer interrupts for others\n"); seq_printf(p, "%*s: ", prec, "SPU"); for_each_online_cpu(j) @@ -389,11 +394,12 @@ int arch_show_interrupts(struct seq_file *p, int prec) */ u64 arch_irq_stat_cpu(unsigned int cpu) { - u64 sum = per_cpu(irq_stat, cpu).timer_irqs; + u64 sum = per_cpu(irq_stat, cpu).timer_irqs_event; sum += per_cpu(irq_stat, cpu).pmu_irqs; sum += per_cpu(irq_stat, cpu).mce_exceptions; sum += per_cpu(irq_stat, cpu).spurious_irqs; + sum += per_cpu(irq_stat, cpu).timer_irqs_others; #ifdef CONFIG_PPC_DOORBELL sum += per_cpu(irq_stat, cpu).doorbell_irqs; #endif diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 83e89d310734..8504657379f1 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -15,7 +15,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/kgdb.h> #include <linux/smp.h> #include <linux/signal.h> diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c new file mode 100644 index 000000000000..cadef7e64e42 --- /dev/null +++ b/arch/powerpc/kernel/mce.c @@ -0,0 +1,352 @@ +/* + * Machine check exception handling. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce: " fmt + +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/percpu.h> +#include <linux/export.h> +#include <linux/irq_work.h> +#include <asm/mce.h> + +static DEFINE_PER_CPU(int, mce_nest_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event); + +/* Queue for delayed MCE events. */ +static DEFINE_PER_CPU(int, mce_queue_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue); + +static void machine_check_process_queued_event(struct irq_work *work); +struct irq_work mce_event_process_work = { + .func = machine_check_process_queued_event, +}; + +static void mce_set_error_info(struct machine_check_event *mce, + struct mce_error_info *mce_err) +{ + mce->error_type = mce_err->error_type; + switch (mce_err->error_type) { + case MCE_ERROR_TYPE_UE: + mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type; + break; + case MCE_ERROR_TYPE_SLB: + mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type; + break; + case MCE_ERROR_TYPE_ERAT: + mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type; + break; + case MCE_ERROR_TYPE_TLB: + mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type; + break; + case MCE_ERROR_TYPE_UNKNOWN: + default: + break; + } +} + +/* + * Decode and save high level MCE information into per cpu buffer which + * is an array of machine_check_event structure. + */ +void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, + uint64_t addr) +{ + uint64_t srr1; + int index = __get_cpu_var(mce_nest_count)++; + struct machine_check_event *mce = &__get_cpu_var(mce_event[index]); + + /* + * Return if we don't have enough space to log mce event. + * mce_nest_count may go beyond MAX_MC_EVT but that's ok, + * the check below will stop buffer overrun. + */ + if (index >= MAX_MC_EVT) + return; + + /* Populate generic machine check info */ + mce->version = MCE_V1; + mce->srr0 = regs->nip; + mce->srr1 = regs->msr; + mce->gpr3 = regs->gpr[3]; + mce->in_use = 1; + + mce->initiator = MCE_INITIATOR_CPU; + if (handled) + mce->disposition = MCE_DISPOSITION_RECOVERED; + else + mce->disposition = MCE_DISPOSITION_NOT_RECOVERED; + mce->severity = MCE_SEV_ERROR_SYNC; + + srr1 = regs->msr; + + /* + * Populate the mce error_type and type-specific error_type. + */ + mce_set_error_info(mce, mce_err); + + if (!addr) + return; + + if (mce->error_type == MCE_ERROR_TYPE_TLB) { + mce->u.tlb_error.effective_address_provided = true; + mce->u.tlb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_SLB) { + mce->u.slb_error.effective_address_provided = true; + mce->u.slb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_ERAT) { + mce->u.erat_error.effective_address_provided = true; + mce->u.erat_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_UE) { + mce->u.ue_error.effective_address_provided = true; + mce->u.ue_error.effective_address = addr; + } + return; +} + +/* + * get_mce_event: + * mce Pointer to machine_check_event structure to be filled. + * release Flag to indicate whether to free the event slot or not. + * 0 <= do not release the mce event. Caller will invoke + * release_mce_event() once event has been consumed. + * 1 <= release the slot. + * + * return 1 = success + * 0 = failure + * + * get_mce_event() will be called by platform specific machine check + * handle routine and in KVM. + * When we call get_mce_event(), we are still in interrupt context and + * preemption will not be scheduled until ret_from_expect() routine + * is called. + */ +int get_mce_event(struct machine_check_event *mce, bool release) +{ + int index = __get_cpu_var(mce_nest_count) - 1; + struct machine_check_event *mc_evt; + int ret = 0; + + /* Sanity check */ + if (index < 0) + return ret; + + /* Check if we have MCE info to process. */ + if (index < MAX_MC_EVT) { + mc_evt = &__get_cpu_var(mce_event[index]); + /* Copy the event structure and release the original */ + if (mce) + *mce = *mc_evt; + if (release) + mc_evt->in_use = 0; + ret = 1; + } + /* Decrement the count to free the slot. */ + if (release) + __get_cpu_var(mce_nest_count)--; + + return ret; +} + +void release_mce_event(void) +{ + get_mce_event(NULL, true); +} + +/* + * Queue up the MCE event which then can be handled later. + */ +void machine_check_queue_event(void) +{ + int index; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return; + + index = __get_cpu_var(mce_queue_count)++; + /* If queue is full, just return for now. */ + if (index >= MAX_MC_EVT) { + __get_cpu_var(mce_queue_count)--; + return; + } + __get_cpu_var(mce_event_queue[index]) = evt; + + /* Queue irq work to process this event later. */ + irq_work_queue(&mce_event_process_work); +} + +/* + * process pending MCE event from the mce event queue. This function will be + * called during syscall exit. + */ +static void machine_check_process_queued_event(struct irq_work *work) +{ + int index; + + /* + * For now just print it to console. + * TODO: log this error event to FSP or nvram. + */ + while (__get_cpu_var(mce_queue_count) > 0) { + index = __get_cpu_var(mce_queue_count) - 1; + machine_check_print_event_info( + &__get_cpu_var(mce_event_queue[index])); + __get_cpu_var(mce_queue_count)--; + } +} + +void machine_check_print_event_info(struct machine_check_event *evt) +{ + const char *level, *sevstr, *subtype; + static const char *mc_ue_types[] = { + "Indeterminate", + "Instruction fetch", + "Page table walk ifetch", + "Load/Store", + "Page table walk Load/Store", + }; + static const char *mc_slb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_erat_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_tlb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + + /* Print things out */ + if (evt->version != MCE_V1) { + pr_err("Machine Check Exception, Unknown event version %d !\n", + evt->version); + return; + } + switch (evt->severity) { + case MCE_SEV_NO_ERROR: + level = KERN_INFO; + sevstr = "Harmless"; + break; + case MCE_SEV_WARNING: + level = KERN_WARNING; + sevstr = ""; + break; + case MCE_SEV_ERROR_SYNC: + level = KERN_ERR; + sevstr = "Severe"; + break; + case MCE_SEV_FATAL: + default: + level = KERN_ERR; + sevstr = "Fatal"; + break; + } + + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, + evt->disposition == MCE_DISPOSITION_RECOVERED ? + "Recovered" : "[Not recovered"); + printk("%s Initiator: %s\n", level, + evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown"); + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + subtype = evt->u.ue_error.ue_error_type < + ARRAY_SIZE(mc_ue_types) ? + mc_ue_types[evt->u.ue_error.ue_error_type] + : "Unknown"; + printk("%s Error type: UE [%s]\n", level, subtype); + if (evt->u.ue_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.ue_error.effective_address); + if (evt->u.ue_error.physical_address_provided) + printk("%s Physial address: %016llx\n", + level, evt->u.ue_error.physical_address); + break; + case MCE_ERROR_TYPE_SLB: + subtype = evt->u.slb_error.slb_error_type < + ARRAY_SIZE(mc_slb_types) ? + mc_slb_types[evt->u.slb_error.slb_error_type] + : "Unknown"; + printk("%s Error type: SLB [%s]\n", level, subtype); + if (evt->u.slb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.slb_error.effective_address); + break; + case MCE_ERROR_TYPE_ERAT: + subtype = evt->u.erat_error.erat_error_type < + ARRAY_SIZE(mc_erat_types) ? + mc_erat_types[evt->u.erat_error.erat_error_type] + : "Unknown"; + printk("%s Error type: ERAT [%s]\n", level, subtype); + if (evt->u.erat_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.erat_error.effective_address); + break; + case MCE_ERROR_TYPE_TLB: + subtype = evt->u.tlb_error.tlb_error_type < + ARRAY_SIZE(mc_tlb_types) ? + mc_tlb_types[evt->u.tlb_error.tlb_error_type] + : "Unknown"; + printk("%s Error type: TLB [%s]\n", level, subtype); + if (evt->u.tlb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.tlb_error.effective_address); + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + printk("%s Error type: Unknown\n", level); + break; + } +} + +uint64_t get_mce_fault_addr(struct machine_check_event *evt) +{ + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + if (evt->u.ue_error.effective_address_provided) + return evt->u.ue_error.effective_address; + break; + case MCE_ERROR_TYPE_SLB: + if (evt->u.slb_error.effective_address_provided) + return evt->u.slb_error.effective_address; + break; + case MCE_ERROR_TYPE_ERAT: + if (evt->u.erat_error.effective_address_provided) + return evt->u.erat_error.effective_address; + break; + case MCE_ERROR_TYPE_TLB: + if (evt->u.tlb_error.effective_address_provided) + return evt->u.tlb_error.effective_address; + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + break; + } + return 0; +} +EXPORT_SYMBOL(get_mce_fault_addr); diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c new file mode 100644 index 000000000000..27c93f41166f --- /dev/null +++ b/arch/powerpc/kernel/mce_power.c @@ -0,0 +1,284 @@ +/* + * Machine check exception handling CPU-side for power7 and power8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce_power: " fmt + +#include <linux/types.h> +#include <linux/ptrace.h> +#include <asm/mmu.h> +#include <asm/mce.h> + +/* flush SLBs and reload */ +static void flush_and_reload_slb(void) +{ + struct slb_shadow *slb; + unsigned long i, n; + + /* Invalidate all SLBs */ + asm volatile("slbmte %0,%0; slbia" : : "r" (0)); + +#ifdef CONFIG_KVM_BOOK3S_HANDLER + /* + * If machine check is hit when in guest or in transition, we will + * only flush the SLBs and continue. + */ + if (get_paca()->kvm_hstate.in_guest) + return; +#endif + + /* For host kernel, reload the SLBs from shadow SLB buffer. */ + slb = get_slb_shadow(); + if (!slb) + return; + + n = min_t(u32, be32_to_cpu(slb->persistent), SLB_MIN_SIZE); + + /* Load up the SLB entries from shadow SLB */ + for (i = 0; i < n; i++) { + unsigned long rb = be64_to_cpu(slb->save_area[i].esid); + unsigned long rs = be64_to_cpu(slb->save_area[i].vsid); + + rb = (rb & ~0xFFFul) | i; + asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb)); + } +} + +static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) +{ + long handled = 1; + + /* + * flush and reload SLBs for SLB errors and flush TLBs for TLB errors. + * reset the error bits whenever we handle them so that at the end + * we can check whether we handled all of them or not. + * */ + if (dsisr & slb_error_bits) { + flush_and_reload_slb(); + /* reset error bits */ + dsisr &= ~(slb_error_bits); + } + if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + /* reset error bits */ + dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; + } + /* Any other errors we don't understand? */ + if (dsisr & 0xffffffffUL) + handled = 0; + + return handled; +} + +static long mce_handle_derror_p7(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS); +} + +static long mce_handle_common_ierror(uint64_t srr1) +{ + long handled = 0; + + switch (P7_SRR1_MC_IFETCH(srr1)) { + case 0: + break; + case P7_SRR1_MC_IFETCH_SLB_PARITY: + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + /* flush and reload SLBs for SLB errors. */ + flush_and_reload_slb(); + handled = 1; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + handled = 1; + } + break; + default: + break; + } + + return handled; +} + +static long mce_handle_ierror_p7(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1) +{ + switch (P7_SRR1_MC_IFETCH(srr1)) { + case P7_SRR1_MC_IFETCH_SLB_PARITY: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + break; + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_UE: + case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH; + break; + case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH; + break; + } +} + +static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr) +{ + if (dsisr & P7_DSISR_MC_UE) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + } else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +long __machine_check_early_realmode_p7(struct pt_regs *regs) +{ + uint64_t srr1, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + + /* + * Handle memory errors depending whether this was a load/store or + * ifetch exception. Also, populate the mce error_type and + * type-specific error_type from either SRR1 or DSISR, depending + * whether this was a load/store or ifetch exception + */ + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p7(regs->dsisr); + mce_get_derror_p7(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p7(srr1); + mce_get_ierror_p7(&mce_error_info, srr1); + addr = regs->nip; + } + + save_mce_event(regs, handled, &mce_error_info, addr); + return handled; +} + +static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr) +{ + mce_get_derror_p7(mce_err, dsisr); + if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static long mce_handle_ierror_p8(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static long mce_handle_derror_p8(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS); +} + +long __machine_check_early_realmode_p8(struct pt_regs *regs) +{ + uint64_t srr1, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p8(regs->dsisr); + mce_get_derror_p8(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p8(srr1); + mce_get_ierror_p8(&mce_error_info, srr1); + addr = regs->nip; + } + + save_mce_event(regs, handled, &mce_error_info, addr); + return handled; +} diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index e47d268727a4..879f09620f83 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -344,7 +344,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) */ _KPROBE(flush_icache_range) BEGIN_FTR_SECTION - isync + PURGE_PREFETCHED_INS blr /* for 601, do nothing */ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) li r5,L1_CACHE_BYTES-1 @@ -448,6 +448,7 @@ _GLOBAL(invalidate_dcache_range) */ _GLOBAL(__flush_dcache_icache) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */ @@ -489,6 +490,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x) */ _GLOBAL(__flush_dcache_icache_phys) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr /* for 601, do nothing */ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) mfmsr r10 diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 64bf8db12b15..3d0249599d52 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -67,6 +67,7 @@ PPC64_CACHES: _KPROBE(flush_icache_range) BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS blr END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) /* @@ -211,6 +212,11 @@ _GLOBAL(__flush_dcache_icache) * Different systems have different cache line sizes */ +BEGIN_FTR_SECTION + PURGE_PREFETCHED_INS + blr +END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) + /* Flush the dcache */ ld r7,PPC64_CACHES@toc(r2) clrrdi r3,r3,PAGE_SHIFT /* Page align */ diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0620eaaaad45..bf0aada02fe4 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -99,12 +99,28 @@ static inline void free_lppacas(void) { } * 3 persistent SLBs are registered here. The buffer will be zero * initially, hence will all be invaild until we actually write them. */ -struct slb_shadow slb_shadow[] __cacheline_aligned = { - [0 ... (NR_CPUS-1)] = { - .persistent = cpu_to_be32(SLB_NUM_BOLTED), - .buffer_length = cpu_to_be32(sizeof(struct slb_shadow)), - }, -}; +static struct slb_shadow *slb_shadow; + +static void __init allocate_slb_shadows(int nr_cpus, int limit) +{ + int size = PAGE_ALIGN(sizeof(struct slb_shadow) * nr_cpus); + slb_shadow = __va(memblock_alloc_base(size, PAGE_SIZE, limit)); + memset(slb_shadow, 0, size); +} + +static struct slb_shadow * __init init_slb_shadow(int cpu) +{ + struct slb_shadow *s = &slb_shadow[cpu]; + + s->persistent = cpu_to_be32(SLB_NUM_BOLTED); + s->buffer_length = cpu_to_be32(sizeof(*s)); + + return s; +} + +#else /* CONFIG_PPC_STD_MMU_64 */ + +static void __init allocate_slb_shadows(int nr_cpus, int limit) { } #endif /* CONFIG_PPC_STD_MMU_64 */ @@ -142,8 +158,13 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) new_paca->__current = &init_task; new_paca->data_offset = 0xfeeeeeeeeeeeeeeeULL; #ifdef CONFIG_PPC_STD_MMU_64 - new_paca->slb_shadow_ptr = &slb_shadow[cpu]; + new_paca->slb_shadow_ptr = init_slb_shadow(cpu); #endif /* CONFIG_PPC_STD_MMU_64 */ + +#ifdef CONFIG_PPC_BOOK3E + /* For now -- if we have threads this will be adjusted later */ + new_paca->tcd_ptr = &new_paca->tcd; +#endif } /* Put the paca pointer into r13 and SPRG_PACA */ @@ -190,6 +211,8 @@ void __init allocate_pacas(void) allocate_lppacas(nr_cpu_ids, limit); + allocate_slb_shadows(nr_cpu_ids, limit); + /* Can't use for_each_*_cpu, as they aren't functional yet */ for (cpu = 0; cpu < nr_cpu_ids; cpu++) initialise_paca(&paca[cpu], cpu); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 4a96556fd2d4..64b7a6e61dd1 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -25,7 +25,6 @@ #include <linux/slab.h> #include <linux/user.h> #include <linux/elf.h> -#include <linux/init.h> #include <linux/prctl.h> #include <linux/init_task.h> #include <linux/export.h> @@ -74,6 +73,48 @@ struct task_struct *last_task_used_vsx = NULL; struct task_struct *last_task_used_spe = NULL; #endif +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +void giveup_fpu_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_fpu(tsk); +} + +void giveup_altivec_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_altivec(tsk); +} + +#else +#define giveup_fpu_maybe_transactional(tsk) giveup_fpu(tsk) +#define giveup_altivec_maybe_transactional(tsk) giveup_altivec(tsk) +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ + #ifdef CONFIG_PPC_FPU /* * Make sure the floating-point register state in the @@ -102,13 +143,13 @@ void flush_fp_to_thread(struct task_struct *tsk) */ BUG_ON(tsk != current); #endif - giveup_fpu(tsk); + giveup_fpu_maybe_transactional(tsk); } preempt_enable(); } } EXPORT_SYMBOL_GPL(flush_fp_to_thread); -#endif +#endif /* CONFIG_PPC_FPU */ void enable_kernel_fp(void) { @@ -116,11 +157,11 @@ void enable_kernel_fp(void) #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); + giveup_fpu_maybe_transactional(current); else giveup_fpu(NULL); /* just enables FP for kernel */ #else - giveup_fpu(last_task_used_math); + giveup_fpu_maybe_transactional(last_task_used_math); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_fp); @@ -132,11 +173,11 @@ void enable_kernel_altivec(void) #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); + giveup_altivec_maybe_transactional(current); else giveup_altivec_notask(); #else - giveup_altivec(last_task_used_altivec); + giveup_altivec_maybe_transactional(last_task_used_altivec); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_altivec); @@ -153,7 +194,7 @@ void flush_altivec_to_thread(struct task_struct *tsk) #ifdef CONFIG_SMP BUG_ON(tsk != current); #endif - giveup_altivec(tsk); + giveup_altivec_maybe_transactional(tsk); } preempt_enable(); } @@ -182,8 +223,8 @@ EXPORT_SYMBOL(enable_kernel_vsx); void giveup_vsx(struct task_struct *tsk) { - giveup_fpu(tsk); - giveup_altivec(tsk); + giveup_fpu_maybe_transactional(tsk); + giveup_altivec_maybe_transactional(tsk); __giveup_vsx(tsk); } @@ -479,7 +520,48 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a, return false; return true; } + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM +static void tm_reclaim_thread(struct thread_struct *thr, + struct thread_info *ti, uint8_t cause) +{ + unsigned long msr_diff = 0; + + /* + * If FP/VSX registers have been already saved to the + * thread_struct, move them to the transact_fp array. + * We clear the TIF_RESTORE_TM bit since after the reclaim + * the thread will no longer be transactional. + */ + if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { + msr_diff = thr->tm_orig_msr & ~thr->regs->msr; + if (msr_diff & MSR_FP) + memcpy(&thr->transact_fp, &thr->fp_state, + sizeof(struct thread_fp_state)); + if (msr_diff & MSR_VEC) + memcpy(&thr->transact_vr, &thr->vr_state, + sizeof(struct thread_vr_state)); + clear_ti_thread_flag(ti, TIF_RESTORE_TM); + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; + } + + tm_reclaim(thr, thr->regs->msr, cause); + + /* Having done the reclaim, we now have the checkpointed + * FP/VSX values in the registers. These might be valid + * even if we have previously called enable_kernel_fp() or + * flush_fp_to_thread(), so update thr->regs->msr to + * indicate their current validity. + */ + thr->regs->msr |= msr_diff; +} + +void tm_reclaim_current(uint8_t cause) +{ + tm_enable(); + tm_reclaim_thread(¤t->thread, current_thread_info(), cause); +} + static inline void tm_reclaim_task(struct task_struct *tsk) { /* We have to work out if we're switching from/to a task that's in the @@ -502,9 +584,11 @@ static inline void tm_reclaim_task(struct task_struct *tsk) /* Stash the original thread MSR, as giveup_fpu et al will * modify it. We hold onto it to see whether the task used - * FP & vector regs. + * FP & vector regs. If the TIF_RESTORE_TM flag is set, + * tm_orig_msr is already set. */ - thr->tm_orig_msr = thr->regs->msr; + if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) + thr->tm_orig_msr = thr->regs->msr; TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " "ccr=%lx, msr=%lx, trap=%lx)\n", @@ -512,7 +596,7 @@ static inline void tm_reclaim_task(struct task_struct *tsk) thr->regs->ccr, thr->regs->msr, thr->regs->trap); - tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED); + tm_reclaim_thread(thr, task_thread_info(tsk), TM_CAUSE_RESCHED); TM_DEBUG("--- tm_reclaim on pid %d complete\n", tsk->pid); @@ -588,6 +672,43 @@ static inline void __switch_to_tm(struct task_struct *prev) tm_reclaim_task(prev); } } + +/* + * This is called if we are on the way out to userspace and the + * TIF_RESTORE_TM flag is set. It checks if we need to reload + * FP and/or vector state and does so if necessary. + * If userspace is inside a transaction (whether active or + * suspended) and FP/VMX/VSX instructions have ever been enabled + * inside that transaction, then we have to keep them enabled + * and keep the FP/VMX/VSX state loaded while ever the transaction + * continues. The reason is that if we didn't, and subsequently + * got a FP/VMX/VSX unavailable interrupt inside a transaction, + * we don't know whether it's the same transaction, and thus we + * don't know which of the checkpointed state and the transactional + * state to use. + */ +void restore_tm_state(struct pt_regs *regs) +{ + unsigned long msr_diff; + + clear_thread_flag(TIF_RESTORE_TM); + if (!MSR_TM_ACTIVE(regs->msr)) + return; + + msr_diff = current->thread.tm_orig_msr & ~regs->msr; + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX; + if (msr_diff & MSR_FP) { + fp_enable(); + load_fp_state(¤t->thread.fp_state); + regs->msr |= current->thread.fpexc_mode; + } + if (msr_diff & MSR_VEC) { + vec_enable(); + load_vr_state(¤t->thread.vr_state); + } + regs->msr |= msr_diff; +} + #else #define tm_recheckpoint_new_task(new) #define __switch_to_tm(prev) @@ -1175,6 +1296,19 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) if (val & PR_FP_EXC_SW_ENABLE) { #ifdef CONFIG_SPE if (cpu_has_feature(CPU_FTR_SPE)) { + /* + * When the sticky exception bits are set + * directly by userspace, it must call prctl + * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE + * in the existing prctl settings) or + * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in + * the bits being set). <fenv.h> functions + * saving and restoring the whole + * floating-point environment need to do so + * anyway to restore the prctl settings from + * the saved environment. + */ + tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); tsk->thread.fpexc_mode = val & (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); return 0; @@ -1206,9 +1340,22 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) #ifdef CONFIG_SPE - if (cpu_has_feature(CPU_FTR_SPE)) + if (cpu_has_feature(CPU_FTR_SPE)) { + /* + * When the sticky exception bits are set + * directly by userspace, it must call prctl + * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE + * in the existing prctl settings) or + * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in + * the bits being set). <fenv.h> functions + * saving and restoring the whole + * floating-point environment need to do so + * anyway to restore the prctl settings from + * the saved environment. + */ + tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); val = tsk->thread.fpexc_mode; - else + } else return -EINVAL; #else return -EINVAL; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fa0ad8aafbcc..f58c0d3aaeb4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -523,6 +523,20 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node, return early_init_dt_scan_memory(node, uname, depth, data); } +/* + * For a relocatable kernel, we need to get the memstart_addr first, + * then use it to calculate the virtual kernel start address. This has + * to happen at a very early stage (before machine_init). In this case, + * we just want to get the memstart_address and would not like to mess the + * memblock at this stage. So introduce a variable to skip the memblock_add() + * for this reason. + */ +#ifdef CONFIG_RELOCATABLE +static int add_mem_to_memblock = 1; +#else +#define add_mem_to_memblock 1 +#endif + void __init early_init_dt_add_memory_arch(u64 base, u64 size) { #ifdef CONFIG_PPC64 @@ -543,7 +557,8 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) } /* Add the chunk to the MEMBLOCK list */ - memblock_add(base, size); + if (add_mem_to_memblock) + memblock_add(base, size); } static void __init early_reserve_mem_dt(void) @@ -740,6 +755,30 @@ void __init early_init_devtree(void *params) DBG(" <- early_init_devtree()\n"); } +#ifdef CONFIG_RELOCATABLE +/* + * This function run before early_init_devtree, so we have to init + * initial_boot_params. + */ +void __init early_get_first_memblock_info(void *params, phys_addr_t *size) +{ + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* + * Scan the memory nodes and set add_mem_to_memblock to 0 to avoid + * mess the memblock. + */ + add_mem_to_memblock = 0; + of_scan_flat_dt(early_init_dt_scan_root, NULL); + of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); + add_mem_to_memblock = 1; + + if (size) + *size = first_memblock_size; +} +#endif + /******* * * New implementation of the OF "find" APIs, return a refcounted diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 856dd4e99bfe..f5f11a7d30e5 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -97,6 +97,36 @@ int dcache_bsize; int icache_bsize; int ucache_bsize; +#if defined(CONFIG_PPC_BOOK3E) && defined(CONFIG_SMP) +static void setup_tlb_core_data(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + int first = cpu_first_thread_sibling(cpu); + + paca[cpu].tcd_ptr = &paca[first].tcd; + + /* + * If we have threads, we need either tlbsrx. + * or e6500 tablewalk mode, or else TLB handlers + * will be racy and could produce duplicate entries. + */ + if (smt_enabled_at_boot >= 2 && + !mmu_has_feature(MMU_FTR_USE_TLBRSRV) && + book3e_htw_mode != PPC_HTW_E6500) { + /* Should we panic instead? */ + WARN_ONCE("%s: unsupported MMU configuration -- expect problems\n", + __func__); + } + } +} +#else +static void setup_tlb_core_data(void) +{ +} +#endif + #ifdef CONFIG_SMP static char *smt_enabled_cmdline; @@ -445,6 +475,7 @@ void __init setup_system(void) smp_setup_cpu_maps(); check_smt_enabled(); + setup_tlb_core_data(); #ifdef CONFIG_SMP /* Release secondary cpus out of their spinloops at 0x60 now that @@ -520,9 +551,6 @@ static void __init irqstack_early_init(void) #ifdef CONFIG_PPC_BOOK3E static void __init exc_lvl_early_init(void) { - extern unsigned int interrupt_base_book3e; - extern unsigned int exc_debug_debug_book3e; - unsigned int i; for_each_possible_cpu(i) { @@ -535,8 +563,7 @@ static void __init exc_lvl_early_init(void) } if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) - patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, - (unsigned long)&exc_debug_debug_book3e, 0); + patch_exception(0x040, exc_debug_debug_book3e); } #else #define exc_lvl_early_init() @@ -544,7 +571,8 @@ static void __init exc_lvl_early_init(void) /* * Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. + * early in SMP boots before relocation is enabled. Exclusive emergency + * stack for machine checks. */ static void __init emergency_stack_init(void) { @@ -567,6 +595,13 @@ static void __init emergency_stack_init(void) sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); sp += THREAD_SIZE; paca[i].emergency_sp = __va(sp); + +#ifdef CONFIG_PPC_BOOK3S_64 + /* emergency stack for machine check exception handling. */ + sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); + sp += THREAD_SIZE; + paca[i].mc_emergency_sp = __va(sp); +#endif } } diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 457e97aa2945..8fc4177ed65a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -203,8 +203,7 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs) #ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (MSR_TM_ACTIVE(regs->msr)) { - tm_enable(); - tm_reclaim(¤t->thread, regs->msr, TM_CAUSE_SIGNAL); + tm_reclaim_current(TM_CAUSE_SIGNAL); if (MSR_TM_TRANSACTIONAL(regs->msr)) return current->thread.ckpt_regs.gpr[1]; } diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 68027bfa5f8e..6ce69e6f1fcb 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -519,6 +519,13 @@ static int save_tm_user_regs(struct pt_regs *regs, { unsigned long msr = regs->msr; + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + /* Make sure floating point registers are stored in regs */ flush_fp_to_thread(current); @@ -1056,13 +1063,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* enter the signal handler in native-endian mode */ regs->msr &= ~MSR_LE; regs->msr |= (MSR_KERNEL & MSR_LE); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: @@ -1484,13 +1484,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, regs->nip = (unsigned long) ka->sa.sa_handler; /* enter the signal handler in big-endian mode */ regs->msr &= ~MSR_LE; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 42991045349f..e35bf773df7a 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -192,6 +192,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, BUG_ON(!MSR_TM_ACTIVE(regs->msr)); + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + flush_fp_to_thread(current); #ifdef CONFIG_ALTIVEC @@ -749,13 +756,6 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, /* Make sure signal handler doesn't get spurious FP exceptions */ current->thread.fp_state.fpscr = 0; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif /* Set up to return from userspace. */ if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c index e68fd1ae727a..7a37ecd3afa3 100644 --- a/arch/powerpc/kernel/smp-tbsync.c +++ b/arch/powerpc/kernel/smp-tbsync.c @@ -9,7 +9,6 @@ #include <linux/sched.h> #include <linux/smp.h> #include <linux/unistd.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/atomic.h> #include <asm/smp.h> diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index c1cf4a1522d9..ac2621af3154 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -369,13 +369,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid)); cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); - if (smp_ops) - if (smp_ops->probe) - max_cpus = smp_ops->probe(); - else - max_cpus = NR_CPUS; - else - max_cpus = 1; + if (smp_ops && smp_ops->probe) + smp_ops->probe(); } void smp_prepare_boot_cpu(void) diff --git a/arch/powerpc/kernel/swsusp_booke.S b/arch/powerpc/kernel/swsusp_booke.S index 0f204053e5b5..553c1405ee05 100644 --- a/arch/powerpc/kernel/swsusp_booke.S +++ b/arch/powerpc/kernel/swsusp_booke.S @@ -74,21 +74,21 @@ _GLOBAL(swsusp_arch_suspend) bne 1b /* Save SPRGs */ - mfsprg r4,0 + mfspr r4,SPRN_SPRG0 stw r4,SL_SPRG0(r11) - mfsprg r4,1 + mfspr r4,SPRN_SPRG1 stw r4,SL_SPRG1(r11) - mfsprg r4,2 + mfspr r4,SPRN_SPRG2 stw r4,SL_SPRG2(r11) - mfsprg r4,3 + mfspr r4,SPRN_SPRG3 stw r4,SL_SPRG3(r11) - mfsprg r4,4 + mfspr r4,SPRN_SPRG4 stw r4,SL_SPRG4(r11) - mfsprg r4,5 + mfspr r4,SPRN_SPRG5 stw r4,SL_SPRG5(r11) - mfsprg r4,6 + mfspr r4,SPRN_SPRG6 stw r4,SL_SPRG6(r11) - mfsprg r4,7 + mfspr r4,SPRN_SPRG7 stw r4,SL_SPRG7(r11) /* Call the low level suspend stuff (we should probably have made @@ -150,21 +150,21 @@ _GLOBAL(swsusp_arch_resume) bl _tlbil_all lwz r4,SL_SPRG0(r11) - mtsprg 0,r4 + mtspr SPRN_SPRG0,r4 lwz r4,SL_SPRG1(r11) - mtsprg 1,r4 + mtspr SPRN_SPRG1,r4 lwz r4,SL_SPRG2(r11) - mtsprg 2,r4 + mtspr SPRN_SPRG2,r4 lwz r4,SL_SPRG3(r11) - mtsprg 3,r4 + mtspr SPRN_SPRG3,r4 lwz r4,SL_SPRG4(r11) - mtsprg 4,r4 + mtspr SPRN_SPRG4,r4 lwz r4,SL_SPRG5(r11) - mtsprg 5,r4 + mtspr SPRN_SPRG5,r4 lwz r4,SL_SPRG6(r11) - mtsprg 6,r4 + mtspr SPRN_SPRG6,r4 lwz r4,SL_SPRG7(r11) - mtsprg 7,r4 + mtspr SPRN_SPRG7,r4 /* restore the MSR */ lwz r3,SL_MSR(r11) diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 4e3cc47f26b9..cd9be9aa016d 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -34,7 +34,6 @@ #include <linux/ipc.h> #include <linux/utsname.h> #include <linux/file.h> -#include <linux/init.h> #include <linux/personality.h> #include <asm/uaccess.h> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index b4e667663d9b..d4a43e64a6a9 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -86,6 +86,304 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E +#define MAX_BIT 63 + +static u64 pw20_wt; +static u64 altivec_idle_wt; + +static unsigned int get_idle_ticks_bit(u64 ns) +{ + u64 cycle; + + if (ns >= 10000) + cycle = div_u64(ns + 500, 1000) * tb_ticks_per_usec; + else + cycle = div_u64(ns * tb_ticks_per_usec, 1000); + + if (!cycle) + return 0; + + return ilog2(cycle); +} + +static void do_show_pwrmgtcr0(void *val) +{ + u32 *value = val; + + *value = mfspr(SPRN_PWRMGTCR0); +} + +static ssize_t show_pw20_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + unsigned int cpu = dev->id; + + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + + value &= PWRMGTCR0_PW20_WAIT; + + return sprintf(buf, "%u\n", value ? 1 : 0); +} + +static void do_store_pw20_state(void *val) +{ + u32 *value = val; + u32 pw20_state; + + pw20_state = mfspr(SPRN_PWRMGTCR0); + + if (*value) + pw20_state |= PWRMGTCR0_PW20_WAIT; + else + pw20_state &= ~PWRMGTCR0_PW20_WAIT; + + mtspr(SPRN_PWRMGTCR0, pw20_state); +} + +static ssize_t store_pw20_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 value; + unsigned int cpu = dev->id; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + smp_call_function_single(cpu, do_store_pw20_state, &value, 1); + + return count; +} + +static ssize_t show_pw20_wait_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + u64 tb_cycle = 1; + u64 time; + + unsigned int cpu = dev->id; + + if (!pw20_wt) { + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + value = (value & PWRMGTCR0_PW20_ENT) >> + PWRMGTCR0_PW20_ENT_SHIFT; + + tb_cycle = (tb_cycle << (MAX_BIT - value + 1)); + /* convert ms to ns */ + if (tb_ticks_per_usec > 1000) { + time = div_u64(tb_cycle, tb_ticks_per_usec / 1000); + } else { + u32 rem_us; + + time = div_u64_rem(tb_cycle, tb_ticks_per_usec, + &rem_us); + time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec; + } + } else { + time = pw20_wt; + } + + return sprintf(buf, "%llu\n", time > 0 ? time : 0); +} + +static void set_pw20_wait_entry_bit(void *val) +{ + u32 *value = val; + u32 pw20_idle; + + pw20_idle = mfspr(SPRN_PWRMGTCR0); + + /* Set Automatic PW20 Core Idle Count */ + /* clear count */ + pw20_idle &= ~PWRMGTCR0_PW20_ENT; + + /* set count */ + pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT); + + mtspr(SPRN_PWRMGTCR0, pw20_idle); +} + +static ssize_t store_pw20_wait_time(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 entry_bit; + u64 value; + + unsigned int cpu = dev->id; + + if (kstrtou64(buf, 0, &value)) + return -EINVAL; + + if (!value) + return -EINVAL; + + entry_bit = get_idle_ticks_bit(value); + if (entry_bit > MAX_BIT) + return -EINVAL; + + pw20_wt = value; + + smp_call_function_single(cpu, set_pw20_wait_entry_bit, + &entry_bit, 1); + + return count; +} + +static ssize_t show_altivec_idle(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + unsigned int cpu = dev->id; + + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + + value &= PWRMGTCR0_AV_IDLE_PD_EN; + + return sprintf(buf, "%u\n", value ? 1 : 0); +} + +static void do_store_altivec_idle(void *val) +{ + u32 *value = val; + u32 altivec_idle; + + altivec_idle = mfspr(SPRN_PWRMGTCR0); + + if (*value) + altivec_idle |= PWRMGTCR0_AV_IDLE_PD_EN; + else + altivec_idle &= ~PWRMGTCR0_AV_IDLE_PD_EN; + + mtspr(SPRN_PWRMGTCR0, altivec_idle); +} + +static ssize_t store_altivec_idle(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 value; + unsigned int cpu = dev->id; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + smp_call_function_single(cpu, do_store_altivec_idle, &value, 1); + + return count; +} + +static ssize_t show_altivec_idle_wait_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + u64 tb_cycle = 1; + u64 time; + + unsigned int cpu = dev->id; + + if (!altivec_idle_wt) { + smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1); + value = (value & PWRMGTCR0_AV_IDLE_CNT) >> + PWRMGTCR0_AV_IDLE_CNT_SHIFT; + + tb_cycle = (tb_cycle << (MAX_BIT - value + 1)); + /* convert ms to ns */ + if (tb_ticks_per_usec > 1000) { + time = div_u64(tb_cycle, tb_ticks_per_usec / 1000); + } else { + u32 rem_us; + + time = div_u64_rem(tb_cycle, tb_ticks_per_usec, + &rem_us); + time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec; + } + } else { + time = altivec_idle_wt; + } + + return sprintf(buf, "%llu\n", time > 0 ? time : 0); +} + +static void set_altivec_idle_wait_entry_bit(void *val) +{ + u32 *value = val; + u32 altivec_idle; + + altivec_idle = mfspr(SPRN_PWRMGTCR0); + + /* Set Automatic AltiVec Idle Count */ + /* clear count */ + altivec_idle &= ~PWRMGTCR0_AV_IDLE_CNT; + + /* set count */ + altivec_idle |= ((MAX_BIT - *value) << PWRMGTCR0_AV_IDLE_CNT_SHIFT); + + mtspr(SPRN_PWRMGTCR0, altivec_idle); +} + +static ssize_t store_altivec_idle_wait_time(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 entry_bit; + u64 value; + + unsigned int cpu = dev->id; + + if (kstrtou64(buf, 0, &value)) + return -EINVAL; + + if (!value) + return -EINVAL; + + entry_bit = get_idle_ticks_bit(value); + if (entry_bit > MAX_BIT) + return -EINVAL; + + altivec_idle_wt = value; + + smp_call_function_single(cpu, set_altivec_idle_wait_entry_bit, + &entry_bit, 1); + + return count; +} + +/* + * Enable/Disable interface: + * 0, disable. 1, enable. + */ +static DEVICE_ATTR(pw20_state, 0600, show_pw20_state, store_pw20_state); +static DEVICE_ATTR(altivec_idle, 0600, show_altivec_idle, store_altivec_idle); + +/* + * Set wait time interface:(Nanosecond) + * Example: Base on TBfreq is 41MHZ. + * 1~48(ns): TB[63] + * 49~97(ns): TB[62] + * 98~195(ns): TB[61] + * 196~390(ns): TB[60] + * 391~780(ns): TB[59] + * 781~1560(ns): TB[58] + * ... + */ +static DEVICE_ATTR(pw20_wait_time, 0600, + show_pw20_wait_time, + store_pw20_wait_time); +static DEVICE_ATTR(altivec_idle_wait_time, 0600, + show_altivec_idle_wait_time, + store_altivec_idle_wait_time); +#endif + /* * Enabling PMCs will slow partition context switch times so we only do * it the first time we write to the PMCs. @@ -108,14 +406,14 @@ void ppc_enable_pmcs(void) } EXPORT_SYMBOL(ppc_enable_pmcs); -#define SYSFS_PMCSETUP(NAME, ADDRESS) \ +#define __SYSFS_SPRSETUP(NAME, ADDRESS, EXTRA) \ static void read_##NAME(void *val) \ { \ *(unsigned long *)val = mfspr(ADDRESS); \ } \ static void write_##NAME(void *val) \ { \ - ppc_enable_pmcs(); \ + EXTRA; \ mtspr(ADDRESS, *(unsigned long *)val); \ } \ static ssize_t show_##NAME(struct device *dev, \ @@ -140,6 +438,10 @@ static ssize_t __used \ return count; \ } +#define SYSFS_PMCSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs()) +#define SYSFS_SPRSETUP(NAME, ADDRESS) \ + __SYSFS_SPRSETUP(NAME, ADDRESS, ) /* Let's define all possible registers, we'll only hook up the ones * that are implemented on the current processor @@ -175,10 +477,10 @@ SYSFS_PMCSETUP(pmc7, SPRN_PMC7); SYSFS_PMCSETUP(pmc8, SPRN_PMC8); SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); -SYSFS_PMCSETUP(purr, SPRN_PURR); -SYSFS_PMCSETUP(spurr, SPRN_SPURR); -SYSFS_PMCSETUP(dscr, SPRN_DSCR); -SYSFS_PMCSETUP(pir, SPRN_PIR); +SYSFS_SPRSETUP(purr, SPRN_PURR); +SYSFS_SPRSETUP(spurr, SPRN_SPURR); +SYSFS_SPRSETUP(dscr, SPRN_DSCR); +SYSFS_SPRSETUP(pir, SPRN_PIR); /* Lets only enable read for phyp resources and @@ -249,34 +551,34 @@ SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); #ifdef CONFIG_DEBUG_KERNEL -SYSFS_PMCSETUP(hid0, SPRN_HID0); -SYSFS_PMCSETUP(hid1, SPRN_HID1); -SYSFS_PMCSETUP(hid4, SPRN_HID4); -SYSFS_PMCSETUP(hid5, SPRN_HID5); -SYSFS_PMCSETUP(ima0, SPRN_PA6T_IMA0); -SYSFS_PMCSETUP(ima1, SPRN_PA6T_IMA1); -SYSFS_PMCSETUP(ima2, SPRN_PA6T_IMA2); -SYSFS_PMCSETUP(ima3, SPRN_PA6T_IMA3); -SYSFS_PMCSETUP(ima4, SPRN_PA6T_IMA4); -SYSFS_PMCSETUP(ima5, SPRN_PA6T_IMA5); -SYSFS_PMCSETUP(ima6, SPRN_PA6T_IMA6); -SYSFS_PMCSETUP(ima7, SPRN_PA6T_IMA7); -SYSFS_PMCSETUP(ima8, SPRN_PA6T_IMA8); -SYSFS_PMCSETUP(ima9, SPRN_PA6T_IMA9); -SYSFS_PMCSETUP(imaat, SPRN_PA6T_IMAAT); -SYSFS_PMCSETUP(btcr, SPRN_PA6T_BTCR); -SYSFS_PMCSETUP(pccr, SPRN_PA6T_PCCR); -SYSFS_PMCSETUP(rpccr, SPRN_PA6T_RPCCR); -SYSFS_PMCSETUP(der, SPRN_PA6T_DER); -SYSFS_PMCSETUP(mer, SPRN_PA6T_MER); -SYSFS_PMCSETUP(ber, SPRN_PA6T_BER); -SYSFS_PMCSETUP(ier, SPRN_PA6T_IER); -SYSFS_PMCSETUP(sier, SPRN_PA6T_SIER); -SYSFS_PMCSETUP(siar, SPRN_PA6T_SIAR); -SYSFS_PMCSETUP(tsr0, SPRN_PA6T_TSR0); -SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1); -SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2); -SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3); +SYSFS_SPRSETUP(hid0, SPRN_HID0); +SYSFS_SPRSETUP(hid1, SPRN_HID1); +SYSFS_SPRSETUP(hid4, SPRN_HID4); +SYSFS_SPRSETUP(hid5, SPRN_HID5); +SYSFS_SPRSETUP(ima0, SPRN_PA6T_IMA0); +SYSFS_SPRSETUP(ima1, SPRN_PA6T_IMA1); +SYSFS_SPRSETUP(ima2, SPRN_PA6T_IMA2); +SYSFS_SPRSETUP(ima3, SPRN_PA6T_IMA3); +SYSFS_SPRSETUP(ima4, SPRN_PA6T_IMA4); +SYSFS_SPRSETUP(ima5, SPRN_PA6T_IMA5); +SYSFS_SPRSETUP(ima6, SPRN_PA6T_IMA6); +SYSFS_SPRSETUP(ima7, SPRN_PA6T_IMA7); +SYSFS_SPRSETUP(ima8, SPRN_PA6T_IMA8); +SYSFS_SPRSETUP(ima9, SPRN_PA6T_IMA9); +SYSFS_SPRSETUP(imaat, SPRN_PA6T_IMAAT); +SYSFS_SPRSETUP(btcr, SPRN_PA6T_BTCR); +SYSFS_SPRSETUP(pccr, SPRN_PA6T_PCCR); +SYSFS_SPRSETUP(rpccr, SPRN_PA6T_RPCCR); +SYSFS_SPRSETUP(der, SPRN_PA6T_DER); +SYSFS_SPRSETUP(mer, SPRN_PA6T_MER); +SYSFS_SPRSETUP(ber, SPRN_PA6T_BER); +SYSFS_SPRSETUP(ier, SPRN_PA6T_IER); +SYSFS_SPRSETUP(sier, SPRN_PA6T_SIER); +SYSFS_SPRSETUP(siar, SPRN_PA6T_SIAR); +SYSFS_SPRSETUP(tsr0, SPRN_PA6T_TSR0); +SYSFS_SPRSETUP(tsr1, SPRN_PA6T_TSR1); +SYSFS_SPRSETUP(tsr2, SPRN_PA6T_TSR2); +SYSFS_SPRSETUP(tsr3, SPRN_PA6T_TSR3); #endif /* CONFIG_DEBUG_KERNEL */ #endif /* HAS_PPC_PMC_PA6T */ @@ -421,6 +723,15 @@ static void register_cpu_online(unsigned int cpu) device_create_file(s, &dev_attr_pir); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E + if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) { + device_create_file(s, &dev_attr_pw20_state); + device_create_file(s, &dev_attr_pw20_wait_time); + + device_create_file(s, &dev_attr_altivec_idle); + device_create_file(s, &dev_attr_altivec_idle_wait_time); + } +#endif cacheinfo_cpu_online(cpu); } @@ -493,6 +804,15 @@ static void unregister_cpu_online(unsigned int cpu) device_remove_file(s, &dev_attr_pir); #endif /* CONFIG_PPC64 */ +#ifdef CONFIG_PPC_FSL_BOOK3E + if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) { + device_remove_file(s, &dev_attr_pw20_state); + device_remove_file(s, &dev_attr_pw20_wait_time); + + device_remove_file(s, &dev_attr_altivec_idle); + device_remove_file(s, &dev_attr_altivec_idle_wait_time); + } +#endif cacheinfo_cpu_offline(cpu); } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index b3b144121cc9..b3dab20acf34 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -510,7 +510,6 @@ void timer_interrupt(struct pt_regs * regs) */ may_hard_irq_enable(); - __get_cpu_var(irq_stat).timer_irqs++; #if defined(CONFIG_PPC32) && defined(CONFIG_PMAC) if (atomic_read(&ppc_n_lost_interrupts) != 0) @@ -532,10 +531,15 @@ void timer_interrupt(struct pt_regs * regs) *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); + __get_cpu_var(irq_stat).timer_irqs_event++; } else { now = *next_tb - now; if (now <= DECREMENTER_MAX) set_dec((int)now); + /* We may have raced with new irq work */ + if (test_irq_work_pending()) + set_dec(1); + __get_cpu_var(irq_stat).timer_irqs_others++; } #ifdef CONFIG_PPC64 @@ -801,8 +805,16 @@ static void __init clocksource_init(void) static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { + /* Don't adjust the decrementer if some irq work is pending */ + if (test_irq_work_pending()) + return 0; __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt; set_dec(evt); + + /* We may have raced with new irq work */ + if (test_irq_work_pending()) + set_dec(1); + return 0; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 907a472f9a9e..33cd7a0b8e73 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -285,6 +285,21 @@ void system_reset_exception(struct pt_regs *regs) /* What should we do here? We could issue a shutdown or hard reset. */ } + +/* + * This function is called in real mode. Strictly no printk's please. + * + * regs->nip and regs->msr contains srr0 and ssr1. + */ +long machine_check_early(struct pt_regs *regs) +{ + long handled = 0; + + if (cur_cpu_spec && cur_cpu_spec->machine_check_early) + handled = cur_cpu_spec->machine_check_early(regs); + return handled; +} + #endif /* @@ -1384,7 +1399,6 @@ void fp_unavailable_tm(struct pt_regs *regs) TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); /* We can only have got here if the task started using FP after * beginning the transaction. So, the transactional regs are just a @@ -1393,8 +1407,7 @@ void fp_unavailable_tm(struct pt_regs *regs) * transaction, and probably retry but now with FP enabled. So the * checkpointed FP registers need to be loaded. */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); /* Reclaim didn't save out any FPRs to transact_fprs. */ /* Enable FP for the task: */ @@ -1403,11 +1416,19 @@ void fp_unavailable_tm(struct pt_regs *regs) /* This loads and recheckpoints the FP registers from * thread.fpr[]. They will remain in registers after the * checkpoint so we don't need to reload them after. + * If VMX is in use, the VRs now hold checkpointed values, + * so we don't want to load the VRs from the thread_struct. */ - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_FP); + + /* If VMX is in use, get the transactional values back */ + if (regs->msr & MSR_VEC) { + do_load_up_transact_altivec(¤t->thread); + /* At this point all the VSX state is loaded, so enable it */ + regs->msr |= MSR_VSX; + } } -#ifdef CONFIG_ALTIVEC void altivec_unavailable_tm(struct pt_regs *regs) { /* See the comments in fp_unavailable_tm(). This function operates @@ -1417,18 +1438,21 @@ void altivec_unavailable_tm(struct pt_regs *regs) TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx," "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC; - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_VEC); current->thread.used_vr = 1; + + if (regs->msr & MSR_FP) { + do_load_up_transact_fpu(¤t->thread); + regs->msr |= MSR_VSX; + } } -#endif -#ifdef CONFIG_VSX void vsx_unavailable_tm(struct pt_regs *regs) { + unsigned long orig_msr = regs->msr; + /* See the comments in fp_unavailable_tm(). This works similarly, * though we're loading both FP and VEC registers in here. * @@ -1440,18 +1464,30 @@ void vsx_unavailable_tm(struct pt_regs *regs) "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); + current->thread.used_vsr = 1; + + /* If FP and VMX are already loaded, we have all the state we need */ + if ((orig_msr & (MSR_FP | MSR_VEC)) == (MSR_FP | MSR_VEC)) { + regs->msr |= MSR_VSX; + return; + } + /* This reclaims FP and/or VR regs if they're already enabled */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode | MSR_VSX; - /* This loads & recheckpoints FP and VRs. */ - tm_recheckpoint(¤t->thread, regs->msr); - current->thread.used_vsr = 1; + + /* This loads & recheckpoints FP and VRs; but we have + * to be sure not to overwrite previously-valid state. + */ + tm_recheckpoint(¤t->thread, regs->msr & ~orig_msr); + + if (orig_msr & MSR_FP) + do_load_up_transact_fpu(¤t->thread); + if (orig_msr & MSR_VEC) + do_load_up_transact_altivec(¤t->thread); } -#endif #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ void performance_monitor_exception(struct pt_regs *regs) diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S index 6e8f507ed32b..79683d0393f5 100644 --- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S +++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S @@ -1,4 +1,3 @@ -#include <linux/init.h> #include <linux/linkage.h> #include <asm/page.h> diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S index b8553d62b792..8df9e2463007 100644 --- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S +++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S @@ -1,4 +1,3 @@ -#include <linux/init.h> #include <linux/linkage.h> #include <asm/page.h> diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 0458a9aaba9d..74f8050518d6 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -37,6 +37,16 @@ _GLOBAL(do_load_up_transact_altivec) #endif /* + * Enable use of VMX/Altivec for the caller. + */ +_GLOBAL(vec_enable) + mfmsr r3 + oris r3,r3,MSR_VEC@h + MTMSRD(r3) + isync + blr + +/* * Load state from memory into VMX registers including VSCR. * Assumes the caller has enabled VMX in the MSR. */ diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 76a64821f4a2..826d8bd9e522 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -518,16 +518,18 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; dma_addr_t ret = DMA_ERROR_CODE; - if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE))) { + tbl = get_iommu_table_base(dev); + if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) { atomic_inc(&viodev->cmo.allocs_failed); return ret; } ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs); if (unlikely(dma_mapping_error(dev, ret))) { - vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); + vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); atomic_inc(&viodev->cmo.allocs_failed); } @@ -540,10 +542,12 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; + tbl = get_iommu_table_base(dev); dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs); - vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); + vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); } static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, @@ -551,12 +555,14 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; struct scatterlist *sgl; int ret, count = 0; size_t alloc_size = 0; + tbl = get_iommu_table_base(dev); for (sgl = sglist; count < nelems; count++, sgl++) - alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE); + alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl)); if (vio_cmo_alloc(viodev, alloc_size)) { atomic_inc(&viodev->cmo.allocs_failed); @@ -572,7 +578,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, } for (sgl = sglist, count = 0; count < ret; count++, sgl++) - alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE); + alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); if (alloc_size) vio_cmo_dealloc(viodev, alloc_size); @@ -585,12 +591,14 @@ static void vio_dma_iommu_unmap_sg(struct device *dev, struct dma_attrs *attrs) { struct vio_dev *viodev = to_vio_dev(dev); + struct iommu_table *tbl; struct scatterlist *sgl; size_t alloc_size = 0; int count = 0; + tbl = get_iommu_table_base(dev); for (sgl = sglist; count < nelems; count++, sgl++) - alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE); + alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs); @@ -706,11 +714,14 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev) { struct vio_cmo_dev_entry *dev_ent; struct device *dev = &viodev->dev; + struct iommu_table *tbl; struct vio_driver *viodrv = to_vio_driver(dev->driver); unsigned long flags; size_t size; bool dma_capable = false; + tbl = get_iommu_table_base(dev); + /* A device requires entitlement if it has a DMA window property */ switch (viodev->family) { case VDEVICE: @@ -736,7 +747,8 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev) return -EINVAL; } - viodev->cmo.desired = IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev)); + viodev->cmo.desired = + IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev), tbl); if (viodev->cmo.desired < VIO_CMO_MIN_ENT) viodev->cmo.desired = VIO_CMO_MIN_ENT; size = VIO_CMO_MIN_ENT; @@ -1176,9 +1188,10 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) &tbl->it_index, &offset, &size); /* TCE table size - measured in tce entries */ - tbl->it_size = size >> IOMMU_PAGE_SHIFT; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->it_size = size >> tbl->it_page_shift; /* offset for VIO should always be 0 */ - tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; + tbl->it_offset = offset >> tbl->it_page_shift; tbl->it_busno = 0; tbl->it_type = TCE_VB; tbl->it_blocksize = 16; diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index a353c485808c..768a9f977c00 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -12,6 +12,7 @@ #include <linux/kvm_host.h> #include <linux/kernel.h> #include <asm/opal.h> +#include <asm/mce.h> /* SRR1 bits for machine check on POWER7 */ #define SRR1_MC_LDSTERR (1ul << (63-42)) @@ -58,18 +59,6 @@ static void reload_slb(struct kvm_vcpu *vcpu) } } -/* POWER7 TLB flush */ -static void flush_tlb_power7(struct kvm_vcpu *vcpu) -{ - unsigned long i, rb; - - rb = TLBIEL_INVAL_SET_LPID; - for (i = 0; i < POWER7_TLB_SETS; ++i) { - asm volatile("tlbiel %0" : : "r" (rb)); - rb += 1 << TLBIEL_INVAL_SET_SHIFT; - } -} - /* * On POWER7, see if we can handle a machine check that occurred inside * the guest in real mode, without switching to the host partition. @@ -79,9 +68,7 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu) static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) { unsigned long srr1 = vcpu->arch.shregs.msr; -#ifdef CONFIG_PPC_POWERNV - struct opal_machine_check_event *opal_evt; -#endif + struct machine_check_event mce_evt; long handled = 1; if (srr1 & SRR1_MC_LDSTERR) { @@ -96,7 +83,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI); } if (dsisr & DSISR_MC_TLB_MULTI) { - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); dsisr &= ~DSISR_MC_TLB_MULTI; } /* Any other errors we don't understand? */ @@ -113,28 +101,38 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) reload_slb(vcpu); break; case SRR1_MC_IFETCH_TLBMULTI: - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); break; default: handled = 0; } -#ifdef CONFIG_PPC_POWERNV /* - * See if OPAL has already handled the condition. - * We assume that if the condition is recovered then OPAL + * See if we have already handled the condition in the linux host. + * We assume that if the condition is recovered then linux host * will have generated an error log event that we will pick * up and log later. + * Don't release mce event now. In case if condition is not + * recovered we do guest exit and go back to linux host machine + * check handler. Hence we need make sure that current mce event + * is available for linux host to consume. */ - opal_evt = local_paca->opal_mc_evt; - if (opal_evt->version == OpalMCE_V1 && - (opal_evt->severity == OpalMCE_SEV_NO_ERROR || - opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED)) + if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE)) + goto out; + + if (mce_evt.version == MCE_V1 && + (mce_evt.severity == MCE_SEV_NO_ERROR || + mce_evt.disposition == MCE_DISPOSITION_RECOVERED)) handled = 1; +out: + /* + * If we have handled the error, then release the mce event because + * we will be delivering machine check to guest. + */ if (handled) - opal_evt->in_use = 0; -#endif + release_mce_event(); return handled; } diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index e8ed7d659c55..a0d6929d8678 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -319,6 +319,8 @@ kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \ SPRN_DSRR0, SPRN_DSRR1, 0 kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \ SPRN_CSRR0, SPRN_CSRR1, 0 +kvm_handler BOOKE_INTERRUPT_LRAT_ERROR, EX_PARAMS(GEN), \ + SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) #else /* * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index 17e5b2364312..d5edbeb8eb82 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -159,6 +159,21 @@ unsigned int translate_branch(const unsigned int *dest, const unsigned int *src) return 0; } +#ifdef CONFIG_PPC_BOOK3E_64 +void __patch_exception(int exc, unsigned long addr) +{ + extern unsigned int interrupt_base_book3e; + unsigned int *ibase = &interrupt_base_book3e; + + /* Our exceptions vectors start with a NOP and -then- a branch + * to deal with single stepping from userspace which stops on + * the second instruction. Thus we need to patch the second + * instruction of the exception, not the first one + */ + + patch_branch(ibase + (exc / 4) + 1, addr, 0); +} +#endif #ifdef CONFIG_CODE_PATCHING_SELFTEST diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S index b2c68ce139ae..a5b30c71a8d3 100644 --- a/arch/powerpc/lib/crtsavres.S +++ b/arch/powerpc/lib/crtsavres.S @@ -231,6 +231,87 @@ _GLOBAL(_rest32gpr_31_x) mr 1,11 blr +#ifdef CONFIG_ALTIVEC +/* Called with r0 pointing just beyond the end of the vector save area. */ + +_GLOBAL(_savevr_20) + li r11,-192 + stvx vr20,r11,r0 +_GLOBAL(_savevr_21) + li r11,-176 + stvx vr21,r11,r0 +_GLOBAL(_savevr_22) + li r11,-160 + stvx vr22,r11,r0 +_GLOBAL(_savevr_23) + li r11,-144 + stvx vr23,r11,r0 +_GLOBAL(_savevr_24) + li r11,-128 + stvx vr24,r11,r0 +_GLOBAL(_savevr_25) + li r11,-112 + stvx vr25,r11,r0 +_GLOBAL(_savevr_26) + li r11,-96 + stvx vr26,r11,r0 +_GLOBAL(_savevr_27) + li r11,-80 + stvx vr27,r11,r0 +_GLOBAL(_savevr_28) + li r11,-64 + stvx vr28,r11,r0 +_GLOBAL(_savevr_29) + li r11,-48 + stvx vr29,r11,r0 +_GLOBAL(_savevr_30) + li r11,-32 + stvx vr30,r11,r0 +_GLOBAL(_savevr_31) + li r11,-16 + stvx vr31,r11,r0 + blr + +_GLOBAL(_restvr_20) + li r11,-192 + lvx vr20,r11,r0 +_GLOBAL(_restvr_21) + li r11,-176 + lvx vr21,r11,r0 +_GLOBAL(_restvr_22) + li r11,-160 + lvx vr22,r11,r0 +_GLOBAL(_restvr_23) + li r11,-144 + lvx vr23,r11,r0 +_GLOBAL(_restvr_24) + li r11,-128 + lvx vr24,r11,r0 +_GLOBAL(_restvr_25) + li r11,-112 + lvx vr25,r11,r0 +_GLOBAL(_restvr_26) + li r11,-96 + lvx vr26,r11,r0 +_GLOBAL(_restvr_27) + li r11,-80 + lvx vr27,r11,r0 +_GLOBAL(_restvr_28) + li r11,-64 + lvx vr28,r11,r0 +_GLOBAL(_restvr_29) + li r11,-48 + lvx vr29,r11,r0 +_GLOBAL(_restvr_30) + li r11,-32 + lvx vr30,r11,r0 +_GLOBAL(_restvr_31) + li r11,-16 + lvx vr31,r11,r0 + blr + +#endif /* CONFIG_ALTIVEC */ + #else /* CONFIG_PPC64 */ .section ".text.save.restore","ax",@progbits @@ -356,6 +437,111 @@ _restgpr0_31: mtlr r0 blr +#ifdef CONFIG_ALTIVEC +/* Called with r0 pointing just beyond the end of the vector save area. */ + +.globl _savevr_20 +_savevr_20: + li r12,-192 + stvx vr20,r12,r0 +.globl _savevr_21 +_savevr_21: + li r12,-176 + stvx vr21,r12,r0 +.globl _savevr_22 +_savevr_22: + li r12,-160 + stvx vr22,r12,r0 +.globl _savevr_23 +_savevr_23: + li r12,-144 + stvx vr23,r12,r0 +.globl _savevr_24 +_savevr_24: + li r12,-128 + stvx vr24,r12,r0 +.globl _savevr_25 +_savevr_25: + li r12,-112 + stvx vr25,r12,r0 +.globl _savevr_26 +_savevr_26: + li r12,-96 + stvx vr26,r12,r0 +.globl _savevr_27 +_savevr_27: + li r12,-80 + stvx vr27,r12,r0 +.globl _savevr_28 +_savevr_28: + li r12,-64 + stvx vr28,r12,r0 +.globl _savevr_29 +_savevr_29: + li r12,-48 + stvx vr29,r12,r0 +.globl _savevr_30 +_savevr_30: + li r12,-32 + stvx vr30,r12,r0 +.globl _savevr_31 +_savevr_31: + li r12,-16 + stvx vr31,r12,r0 + blr + +.globl _restvr_20 +_restvr_20: + li r12,-192 + lvx vr20,r12,r0 +.globl _restvr_21 +_restvr_21: + li r12,-176 + lvx vr21,r12,r0 +.globl _restvr_22 +_restvr_22: + li r12,-160 + lvx vr22,r12,r0 +.globl _restvr_23 +_restvr_23: + li r12,-144 + lvx vr23,r12,r0 +.globl _restvr_24 +_restvr_24: + li r12,-128 + lvx vr24,r12,r0 +.globl _restvr_25 +_restvr_25: + li r12,-112 + lvx vr25,r12,r0 +.globl _restvr_26 +_restvr_26: + li r12,-96 + lvx vr26,r12,r0 +.globl _restvr_27 +_restvr_27: + li r12,-80 + lvx vr27,r12,r0 +.globl _restvr_28 +_restvr_28: + li r12,-64 + lvx vr28,r12,r0 +.globl _restvr_29 +_restvr_29: + li r12,-48 + lvx vr29,r12,r0 +.globl _restvr_30 +_restvr_30: + li r12,-32 + lvx vr30,r12,r0 +.globl _restvr_31 +_restvr_31: + li r12,-16 + lvx vr31,r12,r0 + blr + +#endif /* CONFIG_ALTIVEC */ + #endif /* CONFIG_PPC64 */ #endif diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index a73f0884d358..28337c9709ae 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c @@ -20,6 +20,7 @@ */ #include <linux/types.h> +#include <linux/prctl.h> #include <asm/uaccess.h> #include <asm/reg.h> @@ -275,21 +276,13 @@ int do_spe_mathemu(struct pt_regs *regs) case EFSCTSF: case EFSCTUF: - if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) { - /* NaN */ - if (((vb.wp[1] >> 23) & 0xff) == 0) { - /* denorm */ - vc.wp[1] = 0x0; - } else if ((vb.wp[1] >> 31) == 0) { - /* positive normal */ - vc.wp[1] = (func == EFSCTSF) ? - 0x7fffffff : 0xffffffff; - } else { /* negative normal */ - vc.wp[1] = (func == EFSCTSF) ? - 0x80000000 : 0x0; - } - } else { /* rB is NaN */ - vc.wp[1] = 0x0; + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB_e += (func == EFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, + (func == EFSCTSF)); } goto update_regs; @@ -306,16 +299,25 @@ int do_spe_mathemu(struct pt_regs *regs) } case EFSCTSI: - case EFSCTSIZ: case EFSCTUI: + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + + case EFSCTSIZ: case EFSCTUIZ: - if (func & 0x4) { - _FP_ROUND(1, SB); + if (SB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(1, SB); + FP_TO_INT_S(vc.wp[1], SB, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_S(vc.wp[1], SB, 32, - (((func & 0x3) != 0) || SB_s)); goto update_regs; default: @@ -404,22 +406,13 @@ cmp_s: case EFDCTSF: case EFDCTUF: - if (!((vb.wp[0] >> 20) == 0x7ff && - ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) { - /* not a NaN */ - if (((vb.wp[0] >> 20) & 0x7ff) == 0) { - /* denorm */ - vc.wp[1] = 0x0; - } else if ((vb.wp[0] >> 31) == 0) { - /* positive normal */ - vc.wp[1] = (func == EFDCTSF) ? - 0x7fffffff : 0xffffffff; - } else { /* negative normal */ - vc.wp[1] = (func == EFDCTSF) ? - 0x80000000 : 0x0; - } - } else { /* NaN */ - vc.wp[1] = 0x0; + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + DB_e += (func == EFDCTSF ? 31 : 32); + FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, + (func == EFDCTSF)); } goto update_regs; @@ -437,21 +430,35 @@ cmp_s: case EFDCTUIDZ: case EFDCTSIDZ: - _FP_ROUND_ZERO(2, DB); - FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0)); + if (DB_c == FP_CLS_NAN) { + vc.dp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_D(vc.dp[0], DB, 64, + ((func & 0x1) == 0)); + } goto update_regs; case EFDCTUI: case EFDCTSI: + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + case EFDCTUIZ: case EFDCTSIZ: - if (func & 0x4) { - _FP_ROUND(2, DB); + if (DB_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(2, DB); + FP_TO_INT_D(vc.wp[1], DB, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_D(vc.wp[1], DB, 32, - (((func & 0x3) != 0) || DB_s)); goto update_regs; default: @@ -556,37 +563,60 @@ cmp_d: cmp = -1; goto cmp_vs; - case EVFSCTSF: - __asm__ __volatile__ ("mtspr 512, %4\n" - "efsctsf %0, %2\n" - "efsctsf %1, %3\n" - : "=r" (vc.wp[0]), "=r" (vc.wp[1]) - : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); - goto update_regs; - case EVFSCTUF: - __asm__ __volatile__ ("mtspr 512, %4\n" - "efsctuf %0, %2\n" - "efsctuf %1, %3\n" - : "=r" (vc.wp[0]), "=r" (vc.wp[1]) - : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0)); + case EVFSCTSF: + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB0_e += (func == EVFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, + (func == EVFSCTSF)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + SB1_e += (func == EVFSCTSF ? 31 : 32); + FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, + (func == EVFSCTSF)); + } goto update_regs; case EVFSCTUI: case EVFSCTSI: + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, + ((func & 0x3) != 0)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, + ((func & 0x3) != 0)); + } + goto update_regs; + case EVFSCTUIZ: case EVFSCTSIZ: - if (func & 0x4) { - _FP_ROUND(1, SB0); - _FP_ROUND(1, SB1); + if (SB0_c == FP_CLS_NAN) { + vc.wp[0] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); } else { - _FP_ROUND_ZERO(1, SB0); - _FP_ROUND_ZERO(1, SB1); + FP_TO_INT_S(vc.wp[0], SB0, 32, + ((func & 0x3) != 0)); + } + if (SB1_c == FP_CLS_NAN) { + vc.wp[1] = 0; + FP_SET_EXCEPTION(FP_EX_INVALID); + } else { + FP_TO_INT_S(vc.wp[1], SB1, 32, + ((func & 0x3) != 0)); } - FP_TO_INT_S(vc.wp[0], SB0, 32, - (((func & 0x3) != 0) || SB0_s)); - FP_TO_INT_S(vc.wp[1], SB1, 32, - (((func & 0x3) != 0) || SB1_s)); goto update_regs; default: @@ -630,9 +660,27 @@ update_ccr: regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); update_regs: - __FPU_FPSCR &= ~FP_EX_MASK; + /* + * If the "invalid" exception sticky bit was set by the + * processor for non-finite input, but was not set before the + * instruction being emulated, clear it. Likewise for the + * "underflow" bit, which may have been set by the processor + * for exact underflow, not just inexact underflow when the + * flag should be set for IEEE 754 semantics. Other sticky + * exceptions will only be set by the processor when they are + * correct according to IEEE 754 semantics, and we must not + * clear sticky bits that were already set before the emulated + * instruction as they represent the user-visible sticky + * exception status. "inexact" traps to kernel are not + * required for IEEE semantics and are not enabled by default, + * so the "inexact" sticky bit may have been set by a previous + * instruction without the kernel being aware of it. + */ + __FPU_FPSCR + &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last; __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); mtspr(SPRN_SPEFSCR, __FPU_FPSCR); + current->thread.spefscr_last = __FPU_FPSCR; current->thread.evr[fc] = vc.wp[0]; regs->gpr[fc] = vc.wp[1]; @@ -644,6 +692,23 @@ update_regs: pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]); pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); + if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) { + if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO) + && (current->thread.fpexc_mode & PR_FP_EXC_DIV)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW) + && (current->thread.fpexc_mode & PR_FP_EXC_OVF)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW) + && (current->thread.fpexc_mode & PR_FP_EXC_UND)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) + && (current->thread.fpexc_mode & PR_FP_EXC_RES)) + return 1; + if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID) + && (current->thread.fpexc_mode & PR_FP_EXC_INV)) + return 1; + } return 0; illegal: @@ -662,21 +727,28 @@ int speround_handler(struct pt_regs *regs) { union dw_union fgpr; int s_lo, s_hi; - unsigned long speinsn, type, fc; + int lo_inexact, hi_inexact; + int fp_result; + unsigned long speinsn, type, fb, fc, fptype, func; if (get_user(speinsn, (unsigned int __user *) regs->nip)) return -EFAULT; if ((speinsn >> 26) != 4) return -EINVAL; /* not an spe instruction */ - type = insn_type(speinsn & 0x7ff); + func = speinsn & 0x7ff; + type = insn_type(func); if (type == XCR) return -ENOSYS; __FPU_FPSCR = mfspr(SPRN_SPEFSCR); pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); + fptype = (speinsn >> 5) & 0x7; + /* No need to round if the result is exact */ - if (!(__FPU_FPSCR & FP_EX_INEXACT)) + lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX); + hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH); + if (!(lo_inexact || (hi_inexact && fptype == VCT))) return 0; fc = (speinsn >> 21) & 0x1f; @@ -685,9 +757,68 @@ int speround_handler(struct pt_regs *regs) fgpr.wp[0] = current->thread.evr[fc]; fgpr.wp[1] = regs->gpr[fc]; + fb = (speinsn >> 11) & 0x1f; + switch (func) { + case EFSCTUIZ: + case EFSCTSIZ: + case EVFSCTUIZ: + case EVFSCTSIZ: + case EFDCTUIDZ: + case EFDCTSIDZ: + case EFDCTUIZ: + case EFDCTSIZ: + /* + * These instructions always round to zero, + * independent of the rounding mode. + */ + return 0; + + case EFSCTUI: + case EFSCTUF: + case EVFSCTUI: + case EVFSCTUF: + case EFDCTUI: + case EFDCTUF: + fp_result = 0; + s_lo = 0; + s_hi = 0; + break; + + case EFSCTSI: + case EFSCTSF: + fp_result = 0; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_lo = regs->gpr[fb] & SIGN_BIT_S; + break; + + case EVFSCTSI: + case EVFSCTSF: + fp_result = 0; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_lo = regs->gpr[fb] & SIGN_BIT_S; + if (fgpr.wp[0] == 0) + s_hi = current->thread.evr[fb] & SIGN_BIT_S; + break; + + case EFDCTSI: + case EFDCTSF: + fp_result = 0; + s_hi = s_lo; + /* Recover the sign of a zero result if possible. */ + if (fgpr.wp[1] == 0) + s_hi = current->thread.evr[fb] & SIGN_BIT_S; + break; + + default: + fp_result = 1; + break; + } + pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); - switch ((speinsn >> 5) & 0x7) { + switch (fptype) { /* Since SPE instructions on E500 core can handle round to nearest * and round toward zero with IEEE-754 complied, we just need * to handle round toward +Inf and round toward -Inf by software. @@ -696,25 +827,52 @@ int speround_handler(struct pt_regs *regs) if ((FP_ROUNDMODE) == FP_RND_PINF) { if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */ } else { /* round to -Inf */ - if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */ + if (s_lo) { + if (fp_result) + fgpr.wp[1]++; /* Z < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z < 0, choose Z2 */ + } } break; case DPFP: if (FP_ROUNDMODE == FP_RND_PINF) { - if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */ + if (!s_hi) { + if (fp_result) + fgpr.dp[0]++; /* Z > 0, choose Z1 */ + else + fgpr.wp[1]++; /* Z > 0, choose Z1 */ + } } else { /* round to -Inf */ - if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */ + if (s_hi) { + if (fp_result) + fgpr.dp[0]++; /* Z < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z < 0, choose Z2 */ + } } break; case VCT: if (FP_ROUNDMODE == FP_RND_PINF) { - if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ - if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ + if (lo_inexact && !s_lo) + fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ + if (hi_inexact && !s_hi) + fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ } else { /* round to -Inf */ - if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ - if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ + if (lo_inexact && s_lo) { + if (fp_result) + fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ + else + fgpr.wp[1]--; /* Z_low < 0, choose Z2 */ + } + if (hi_inexact && s_hi) { + if (fp_result) + fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ + else + fgpr.wp[0]--; /* Z_high < 0, choose Z2 */ + } } break; @@ -727,6 +885,8 @@ int speround_handler(struct pt_regs *regs) pr_debug(" to fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); + if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) + return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0; return 0; } diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 07ba45b0f07c..94cd728166d3 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -52,6 +52,7 @@ #include <asm/smp.h> #include <asm/machdep.h> #include <asm/setup.h> +#include <asm/paca.h> #include "mmu_decl.h" @@ -171,11 +172,10 @@ unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, return 1UL << camsize; } -unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) +static unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt, + unsigned long ram, int max_cam_idx) { int i; - unsigned long virt = PAGE_OFFSET; - phys_addr_t phys = memstart_addr; unsigned long amount_mapped = 0; /* Calculate CAM values */ @@ -192,9 +192,23 @@ unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) } tlbcam_index = i; +#ifdef CONFIG_PPC64 + get_paca()->tcd.esel_next = i; + get_paca()->tcd.esel_max = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; + get_paca()->tcd.esel_first = i; +#endif + return amount_mapped; } +unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) +{ + unsigned long virt = PAGE_OFFSET; + phys_addr_t phys = memstart_addr; + + return map_mem_in_cams_addr(phys, virt, ram, max_cam_idx); +} + #ifdef CONFIG_PPC32 #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) @@ -222,7 +236,9 @@ void __init adjust_total_lowmem(void) /* adjust lowmem size to __max_low_memory */ ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); + i = switch_to_as1(); __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM); + restore_to_as0(i, 0, 0, 1); pr_info("Memory CAM mapping: "); for (i = 0; i < tlbcam_index - 1; i++) @@ -241,4 +257,62 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, /* 64M mapped initially according to head_fsl_booke.S */ memblock_set_current_limit(min_t(u64, limit, 0x04000000)); } + +#ifdef CONFIG_RELOCATABLE +int __initdata is_second_reloc; +notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start) +{ + unsigned long base = KERNELBASE; + + kernstart_addr = start; + if (is_second_reloc) { + virt_phys_offset = PAGE_OFFSET - memstart_addr; + return; + } + + /* + * Relocatable kernel support based on processing of dynamic + * relocation entries. Before we get the real memstart_addr, + * We will compute the virt_phys_offset like this: + * virt_phys_offset = stext.run - kernstart_addr + * + * stext.run = (KERNELBASE & ~0x3ffffff) + + * (kernstart_addr & 0x3ffffff) + * When we relocate, we have : + * + * (kernstart_addr & 0x3ffffff) = (stext.run & 0x3ffffff) + * + * hence: + * virt_phys_offset = (KERNELBASE & ~0x3ffffff) - + * (kernstart_addr & ~0x3ffffff) + * + */ + start &= ~0x3ffffff; + base &= ~0x3ffffff; + virt_phys_offset = base - start; + early_get_first_memblock_info(__va(dt_ptr), NULL); + /* + * We now get the memstart_addr, then we should check if this + * address is the same as what the PAGE_OFFSET map to now. If + * not we have to change the map of PAGE_OFFSET to memstart_addr + * and do a second relocation. + */ + if (start != memstart_addr) { + int n; + long offset = start - memstart_addr; + + is_second_reloc = 1; + n = switch_to_as1(); + /* map a 64M area for the second relocation */ + if (memstart_addr > start) + map_mem_in_cams(0x4000000, CONFIG_LOWMEM_CAM_NUM); + else + map_mem_in_cams_addr(start, PAGE_OFFSET + offset, + 0x4000000, CONFIG_LOWMEM_CAM_NUM); + restore_to_as0(n, offset, __va(dt_ptr), 1); + /* We should never reach here */ + panic("Relocation error"); + } +} +#endif #endif diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index d3cbda62857b..1136d26a95ae 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -148,7 +148,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -457,7 +460,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r3,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -795,7 +801,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ - ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + ori r3,r3,HPTE_R_C | HPTE_R_M /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 6176b3cdf579..de6881259aef 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -169,9 +169,10 @@ static unsigned long htab_convert_pte_flags(unsigned long pteflags) if ((pteflags & _PAGE_USER) && !((pteflags & _PAGE_RW) && (pteflags & _PAGE_DIRTY))) rflags |= 1; - - /* Always add C */ - return rflags | HPTE_R_C; + /* + * Always add "C" bit for perf. Memory coherence is always enabled + */ + return rflags | HPTE_R_C | HPTE_R_M; } int htab_bolt_mapping(unsigned long vstart, unsigned long vend, diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c index 34de9e0cdc34..826893fcb3a7 100644 --- a/arch/powerpc/mm/hugepage-hash64.c +++ b/arch/powerpc/mm/hugepage-hash64.c @@ -127,7 +127,11 @@ repeat: /* Add in WIMG bits */ rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | - _PAGE_COHERENT | _PAGE_GUARDED)); + _PAGE_GUARDED)); + /* + * enable the memory coherence always + */ + rflags |= HPTE_R_M; /* Insert into the hash table, primary slot */ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0, diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 74551b5e41e5..5e4ee2573903 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -8,6 +8,44 @@ #include <linux/mm.h> #include <linux/hugetlb.h> +#ifdef CONFIG_PPC_FSL_BOOK3E +#ifdef CONFIG_PPC64 +static inline int tlb1_next(void) +{ + struct paca_struct *paca = get_paca(); + struct tlb_core_data *tcd; + int this, next; + + tcd = paca->tcd_ptr; + this = tcd->esel_next; + + next = this + 1; + if (next >= tcd->esel_max) + next = tcd->esel_first; + + tcd->esel_next = next; + return this; +} +#else +static inline int tlb1_next(void) +{ + int index, ncams; + + ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; + + index = __get_cpu_var(next_tlbcam_idx); + + /* Just round-robin the entries and wrap when we hit the end */ + if (unlikely(index == ncams - 1)) + __get_cpu_var(next_tlbcam_idx) = tlbcam_index; + else + __get_cpu_var(next_tlbcam_idx)++; + + return index; +} +#endif /* !PPC64 */ +#endif /* FSL */ + static inline int mmu_get_tsize(int psize) { return mmu_psize_defs[psize].enc; @@ -47,7 +85,7 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, struct mm_struct *mm; #ifdef CONFIG_PPC_FSL_BOOK3E - int index, ncams; + int index; #endif if (unlikely(is_kernel_addr(ea))) @@ -77,18 +115,11 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, } #ifdef CONFIG_PPC_FSL_BOOK3E - ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; - /* We have to use the CAM(TLB1) on FSL parts for hugepages */ - index = __get_cpu_var(next_tlbcam_idx); + index = tlb1_next(); mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1)); - - /* Just round-robin the entries and wrap when we hit the end */ - if (unlikely(index == ncams - 1)) - __get_cpu_var(next_tlbcam_idx) = tlbcam_index; - else - __get_cpu_var(next_tlbcam_idx)++; #endif + mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize); mas2 = ea & ~((1UL << shift) - 1); mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK; @@ -103,7 +134,8 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) { mtspr(SPRN_MAS7_MAS3, mas7_3); } else { - mtspr(SPRN_MAS7, upper_32_bits(mas7_3)); + if (mmu_has_feature(MMU_FTR_BIG_PHYS)) + mtspr(SPRN_MAS7, upper_32_bits(mas7_3)); mtspr(SPRN_MAS3, lower_32_bits(mas7_3)); } diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index 0b7fb6761015..a5bcf9301196 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c @@ -99,6 +99,10 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, /* Add in WIMG bits */ rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT | _PAGE_GUARDED)); + /* + * enable the memory coherence always + */ + rflags |= HPTE_R_M; slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0, mmu_psize, ssize); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 8c1dd23652a1..4b5cd5c2594d 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -307,6 +307,12 @@ static void __init register_page_bootmem_info(void) void __init mem_init(void) { + /* + * book3s is limited to 16 page sizes due to encoding this in + * a 4-bit field for slices. + */ + BUILD_BUG_ON(MMU_PAGE_COUNT > 16); + #ifdef CONFIG_SWIOTLB swiotlb_init(0); #endif @@ -507,7 +513,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, * System memory should not be in /proc/iomem but various tools expect it * (eg kdump). */ -static int add_system_ram_resources(void) +static int __init add_system_ram_resources(void) { struct memblock_region *reg; diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 83eb5d5f53d5..9615d82919b8 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -148,6 +148,8 @@ extern unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(unsigned long top); extern void adjust_total_lowmem(void); +extern int switch_to_as1(void); +extern void restore_to_as0(int esel, int offset, void *dt_ptr, int bootcpu); #endif extern void loadcam_entry(unsigned int index); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5a944f25e94f..86a63de072c6 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -31,6 +31,8 @@ #include <asm/sparsemem.h> #include <asm/prom.h> #include <asm/smp.h> +#include <asm/cputhreads.h> +#include <asm/topology.h> #include <asm/firmware.h> #include <asm/paca.h> #include <asm/hvcall.h> @@ -152,9 +154,22 @@ static void __init get_node_active_region(unsigned long pfn, } } -static void map_cpu_to_node(int cpu, int node) +static void reset_numa_cpu_lookup_table(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) + numa_cpu_lookup_table[cpu] = -1; +} + +static void update_numa_cpu_lookup_table(unsigned int cpu, int node) { numa_cpu_lookup_table[cpu] = node; +} + +static void map_cpu_to_node(int cpu, int node) +{ + update_numa_cpu_lookup_table(cpu, node); dbg("adding cpu %d to node %d\n", cpu, node); @@ -522,11 +537,24 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem, */ static int numa_setup_cpu(unsigned long lcpu) { - int nid = 0; - struct device_node *cpu = of_get_cpu_node(lcpu, NULL); + int nid; + struct device_node *cpu; + + /* + * If a valid cpu-to-node mapping is already available, use it + * directly instead of querying the firmware, since it represents + * the most recent mapping notified to us by the platform (eg: VPHN). + */ + if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) { + map_cpu_to_node(lcpu, nid); + return nid; + } + + cpu = of_get_cpu_node(lcpu, NULL); if (!cpu) { WARN_ON(1); + nid = 0; goto out; } @@ -542,16 +570,38 @@ out: return nid; } +static void verify_cpu_node_mapping(int cpu, int node) +{ + int base, sibling, i; + + /* Verify that all the threads in the core belong to the same node */ + base = cpu_first_thread_sibling(cpu); + + for (i = 0; i < threads_per_core; i++) { + sibling = base + i; + + if (sibling == cpu || cpu_is_offline(sibling)) + continue; + + if (cpu_to_node(sibling) != node) { + WARN(1, "CPU thread siblings %d and %d don't belong" + " to the same node!\n", cpu, sibling); + break; + } + } +} + static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned long lcpu = (unsigned long)hcpu; - int ret = NOTIFY_DONE; + int ret = NOTIFY_DONE, nid; switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - numa_setup_cpu(lcpu); + nid = numa_setup_cpu(lcpu); + verify_cpu_node_mapping((int)lcpu, nid); ret = NOTIFY_OK; break; #ifdef CONFIG_HOTPLUG_CPU @@ -1069,6 +1119,7 @@ void __init do_init_bootmem(void) */ setup_node_to_cpumask_map(); + reset_numa_cpu_lookup_table(); register_cpu_notifier(&ppc64_numa_nb); cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, (void *)(unsigned long)boot_cpuid); @@ -1447,6 +1498,33 @@ static int update_cpu_topology(void *data) return 0; } +static int update_lookup_table(void *data) +{ + struct topology_update_data *update; + + if (!data) + return -EINVAL; + + /* + * Upon topology update, the numa-cpu lookup table needs to be updated + * for all threads in the core, including offline CPUs, to ensure that + * future hotplug operations respect the cpu-to-node associativity + * properly. + */ + for (update = data; update; update = update->next) { + int nid, base, j; + + nid = update->new_nid; + base = cpu_first_thread_sibling(update->cpu); + + for (j = 0; j < threads_per_core; j++) { + update_numa_cpu_lookup_table(base + j, nid); + } + } + + return 0; +} + /* * Update the node maps and sysfs entries for each cpu whose home node * has changed. Returns 1 when the topology has changed, and 0 otherwise. @@ -1515,6 +1593,14 @@ int arch_update_cpu_topology(void) stop_machine(update_cpu_topology, &updates[0], &updated_cpus); + /* + * Update the numa-cpu lookup table with the new mappings, even for + * offline CPUs. It is best to perform this update from the stop- + * machine context. + */ + stop_machine(update_lookup_table, &updates[0], + cpumask_of(raw_smp_processor_id())); + for (ud = &updates[0]; ud; ud = ud->next) { unregister_cpu_under_node(ud->cpu, ud->old_nid); register_cpu_under_node(ud->cpu, ud->new_nid); diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 841e0d00863c..c695943a513c 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -24,7 +24,6 @@ #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/mm.h> -#include <linux/init.h> #include <linux/percpu.h> #include <linux/hardirq.h> #include <linux/hugetlb.h> @@ -174,7 +173,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { #ifdef CONFIG_DEBUG_VM - WARN_ON(pte_present(*ptep)); + WARN_ON(pte_val(*ptep) & _PAGE_PRESENT); #endif /* Note: mm->context.id might not yet have been assigned as * this context might not have been activated yet when this diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 5b9601715289..343a87fa78b5 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -299,6 +299,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); } + smp_wmb(); return err; } diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 9d95786aa80f..65b7b65e8708 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -33,7 +33,6 @@ #include <linux/swap.h> #include <linux/stddef.h> #include <linux/vmalloc.h> -#include <linux/init.h> #include <linux/bootmem.h> #include <linux/memblock.h> #include <linux/slab.h> @@ -153,6 +152,18 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags) } #endif /* !CONFIG_PPC_MMU_NOHASH */ } + +#ifdef CONFIG_PPC_BOOK3E_64 + /* + * With hardware tablewalk, a sync is needed to ensure that + * subsequent accesses see the PTE we just wrote. Unlike userspace + * mappings, we can't tolerate spurious faults, so make sure + * the new PTE will be seen the first time. + */ + mb(); +#else + smp_wmb(); +#endif return 0; } @@ -687,7 +698,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) { #ifdef CONFIG_DEBUG_VM - WARN_ON(!pmd_none(*pmdp)); + WARN_ON(pmd_val(*pmdp) & _PAGE_PRESENT); assert_spin_locked(&mm->page_table_lock); WARN_ON(!pmd_trans_huge(pmd)); #endif diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c index 36e44b4260eb..c99f6510a0b2 100644 --- a/arch/powerpc/mm/tlb_hash64.c +++ b/arch/powerpc/mm/tlb_hash64.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> #include <linux/mm.h> -#include <linux/init.h> #include <linux/percpu.h> #include <linux/hardirq.h> #include <asm/pgalloc.h> diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index b4113bf86353..16250b162375 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -136,7 +136,7 @@ BEGIN_MMU_FTR_SECTION */ PPC_TLBSRX_DOT(0,R16) ldx r14,r14,r15 /* grab pgd entry */ - beq normal_tlb_miss_done /* tlb exists already, bail */ + beq tlb_miss_done_bolted /* tlb exists already, bail */ MMU_FTR_SECTION_ELSE ldx r14,r14,r15 /* grab pgd entry */ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV) @@ -192,6 +192,7 @@ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV) mtspr SPRN_MAS7_MAS3,r15 tlbwe +tlb_miss_done_bolted: TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK) tlb_epilog_bolted rfi @@ -239,6 +240,177 @@ itlb_miss_fault_bolted: beq tlb_miss_common_bolted b itlb_miss_kernel_bolted +/* + * TLB miss handling for e6500 and derivatives, using hardware tablewalk. + * + * Linear mapping is bolted: no virtual page table or nested TLB misses + * Indirect entries in TLB1, hardware loads resulting direct entries + * into TLB0 + * No HES or NV hint on TLB1, so we need to do software round-robin + * No tlbsrx. so we need a spinlock, and we have to deal + * with MAS-damage caused by tlbsx + * 4K pages only + */ + + START_EXCEPTION(instruction_tlb_miss_e6500) + tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0 + + ld r11,PACA_TCD_PTR(r13) + srdi. r15,r16,60 /* get region */ + ori r16,r16,1 + + TLB_MISS_STATS_SAVE_INFO_BOLTED + bne tlb_miss_kernel_e6500 /* user/kernel test */ + + b tlb_miss_common_e6500 + + START_EXCEPTION(data_tlb_miss_e6500) + tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR + + ld r11,PACA_TCD_PTR(r13) + srdi. r15,r16,60 /* get region */ + rldicr r16,r16,0,62 + + TLB_MISS_STATS_SAVE_INFO_BOLTED + bne tlb_miss_kernel_e6500 /* user vs kernel check */ + +/* + * This is the guts of the TLB miss handler for e6500 and derivatives. + * We are entered with: + * + * r16 = page of faulting address (low bit 0 if data, 1 if instruction) + * r15 = crap (free to use) + * r14 = page table base + * r13 = PACA + * r11 = tlb_per_core ptr + * r10 = crap (free to use) + */ +tlb_miss_common_e6500: + /* + * Search if we already have an indirect entry for that virtual + * address, and if we do, bail out. + * + * MAS6:IND should be already set based on MAS4 + */ + addi r10,r11,TCD_LOCK +1: lbarx r15,0,r10 + cmpdi r15,0 + bne 2f + li r15,1 + stbcx. r15,0,r10 + bne 1b + .subsection 1 +2: lbz r15,0(r10) + cmpdi r15,0 + bne 2b + b 1b + .previous + + mfspr r15,SPRN_MAS2 + + tlbsx 0,r16 + mfspr r10,SPRN_MAS1 + andis. r10,r10,MAS1_VALID@h + bne tlb_miss_done_e6500 + + /* Undo MAS-damage from the tlbsx */ + mfspr r10,SPRN_MAS1 + oris r10,r10,MAS1_VALID@h + mtspr SPRN_MAS1,r10 + mtspr SPRN_MAS2,r15 + + /* Now, we need to walk the page tables. First check if we are in + * range. + */ + rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 + bne- tlb_miss_fault_e6500 + + rldicl r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3 + cmpldi cr0,r14,0 + clrrdi r15,r15,3 + beq- tlb_miss_fault_e6500 /* No PGDIR, bail */ + ldx r14,r14,r15 /* grab pgd entry */ + + rldicl r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3 + clrrdi r15,r15,3 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 /* Bad pgd entry or hugepage; bail */ + ldx r14,r14,r15 /* grab pud entry */ + + rldicl r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3 + clrrdi r15,r15,3 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 + ldx r14,r14,r15 /* Grab pmd entry */ + + mfspr r10,SPRN_MAS0 + cmpdi cr0,r14,0 + bge tlb_miss_fault_e6500 + + /* Now we build the MAS for a 2M indirect page: + * + * MAS 0 : ESEL needs to be filled by software round-robin + * MAS 1 : Fully set up + * - PID already updated by caller if necessary + * - TSIZE for now is base ind page size always + * - TID already cleared if necessary + * MAS 2 : Default not 2M-aligned, need to be redone + * MAS 3+7 : Needs to be done + */ + + ori r14,r14,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT) + mtspr SPRN_MAS7_MAS3,r14 + + clrrdi r15,r16,21 /* make EA 2M-aligned */ + mtspr SPRN_MAS2,r15 + + lbz r15,TCD_ESEL_NEXT(r11) + lbz r16,TCD_ESEL_MAX(r11) + lbz r14,TCD_ESEL_FIRST(r11) + rlwimi r10,r15,16,0x00ff0000 /* insert esel_next into MAS0 */ + addi r15,r15,1 /* increment esel_next */ + mtspr SPRN_MAS0,r10 + cmpw r15,r16 + iseleq r15,r14,r15 /* if next == last use first */ + stb r15,TCD_ESEL_NEXT(r11) + + tlbwe + +tlb_miss_done_e6500: + .macro tlb_unlock_e6500 + li r15,0 + isync + stb r15,TCD_LOCK(r11) + .endm + + tlb_unlock_e6500 + TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK) + tlb_epilog_bolted + rfi + +tlb_miss_kernel_e6500: + mfspr r10,SPRN_MAS1 + ld r14,PACA_KERNELPGD(r13) + cmpldi cr0,r15,8 /* Check for vmalloc region */ + rlwinm r10,r10,0,16,1 /* Clear TID */ + mtspr SPRN_MAS1,r10 + beq+ tlb_miss_common_e6500 + +tlb_miss_fault_e6500: + tlb_unlock_e6500 + /* We need to check if it was an instruction miss */ + andi. r16,r16,1 + bne itlb_miss_fault_e6500 +dtlb_miss_fault_e6500: + TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT) + tlb_epilog_bolted + b exc_data_storage_book3e +itlb_miss_fault_e6500: + TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT) + tlb_epilog_bolted + b exc_instruction_storage_book3e + + /********************************************************************** * * * TLB miss handling for Book3E with TLB reservation and HES support * diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 358d74303138..735839b74dc5 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -43,6 +43,7 @@ #include <asm/tlb.h> #include <asm/code-patching.h> #include <asm/hugetlb.h> +#include <asm/paca.h> #include "mmu_decl.h" @@ -58,6 +59,10 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { .shift = 12, .enc = BOOK3E_PAGESZ_4K, }, + [MMU_PAGE_2M] = { + .shift = 21, + .enc = BOOK3E_PAGESZ_2M, + }, [MMU_PAGE_4M] = { .shift = 22, .enc = BOOK3E_PAGESZ_4M, @@ -136,7 +141,7 @@ static inline int mmu_get_tsize(int psize) int mmu_linear_psize; /* Page size used for the linear mapping */ int mmu_pte_psize; /* Page size used for PTE pages */ int mmu_vmemmap_psize; /* Page size used for the virtual mem map */ -int book3e_htw_enabled; /* Is HW tablewalk enabled ? */ +int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */ unsigned long linear_map_top; /* Top of linear mapping */ #endif /* CONFIG_PPC64 */ @@ -377,7 +382,7 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address) { int tsize = mmu_psize_defs[mmu_pte_psize].enc; - if (book3e_htw_enabled) { + if (book3e_htw_mode != PPC_HTW_NONE) { unsigned long start = address & PMD_MASK; unsigned long end = address + PMD_SIZE; unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift; @@ -430,7 +435,7 @@ static void setup_page_sizes(void) def = &mmu_psize_defs[psize]; shift = def->shift; - if (shift == 0) + if (shift == 0 || shift & 1) continue; /* adjust to be in terms of 4^shift Kb */ @@ -440,21 +445,40 @@ static void setup_page_sizes(void) def->flags |= MMU_PAGE_SIZE_DIRECT; } - goto no_indirect; + goto out; } if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { - u32 tlb1ps = mfspr(SPRN_TLB1PS); + u32 tlb1cfg, tlb1ps; + + tlb0cfg = mfspr(SPRN_TLB0CFG); + tlb1cfg = mfspr(SPRN_TLB1CFG); + tlb1ps = mfspr(SPRN_TLB1PS); + eptcfg = mfspr(SPRN_EPTCFG); + + if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT)) + book3e_htw_mode = PPC_HTW_E6500; + + /* + * We expect 4K subpage size and unrestricted indirect size. + * The lack of a restriction on indirect size is a Freescale + * extension, indicated by PSn = 0 but SPSn != 0. + */ + if (eptcfg != 2) + book3e_htw_mode = PPC_HTW_NONE; for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { struct mmu_psize_def *def = &mmu_psize_defs[psize]; if (tlb1ps & (1U << (def->shift - 10))) { def->flags |= MMU_PAGE_SIZE_DIRECT; + + if (book3e_htw_mode && psize == MMU_PAGE_2M) + def->flags |= MMU_PAGE_SIZE_INDIRECT; } } - goto no_indirect; + goto out; } #endif @@ -471,8 +495,11 @@ static void setup_page_sizes(void) } /* Indirect page sizes supported ? */ - if ((tlb0cfg & TLBnCFG_IND) == 0) - goto no_indirect; + if ((tlb0cfg & TLBnCFG_IND) == 0 || + (tlb0cfg & TLBnCFG_PT) == 0) + goto out; + + book3e_htw_mode = PPC_HTW_IBM; /* Now, we only deal with one IND page size for each * direct size. Hopefully all implementations today are @@ -497,8 +524,8 @@ static void setup_page_sizes(void) def->ind = ps + 10; } } - no_indirect: +out: /* Cleanup array and print summary */ pr_info("MMU: Supported page sizes\n"); for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { @@ -518,44 +545,25 @@ static void setup_page_sizes(void) } } -static void __patch_exception(int exc, unsigned long addr) -{ - extern unsigned int interrupt_base_book3e; - unsigned int *ibase = &interrupt_base_book3e; - - /* Our exceptions vectors start with a NOP and -then- a branch - * to deal with single stepping from userspace which stops on - * the second instruction. Thus we need to patch the second - * instruction of the exception, not the first one - */ - - patch_branch(ibase + (exc / 4) + 1, addr, 0); -} - -#define patch_exception(exc, name) do { \ - extern unsigned int name; \ - __patch_exception((exc), (unsigned long)&name); \ -} while (0) - static void setup_mmu_htw(void) { - /* Check if HW tablewalk is present, and if yes, enable it by: - * - * - patching the TLB miss handlers to branch to the - * one dedicates to it - * - * - setting the global book3e_htw_enabled - */ - unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); + /* + * If we want to use HW tablewalk, enable it by patching the TLB miss + * handlers to branch to the one dedicated to it. + */ - if ((tlb0cfg & TLBnCFG_IND) && - (tlb0cfg & TLBnCFG_PT)) { + switch (book3e_htw_mode) { + case PPC_HTW_IBM: patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e); patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e); - book3e_htw_enabled = 1; + break; + case PPC_HTW_E6500: + patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e); + patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e); + break; } pr_info("MMU: Book3E HW tablewalk %s\n", - book3e_htw_enabled ? "enabled" : "not supported"); + book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported"); } /* @@ -595,8 +603,16 @@ static void __early_init_mmu(int boot_cpu) /* Set MAS4 based on page table setting */ mas4 = 0x4 << MAS4_WIMGED_SHIFT; - if (book3e_htw_enabled) { - mas4 |= mas4 | MAS4_INDD; + switch (book3e_htw_mode) { + case PPC_HTW_E6500: + mas4 |= MAS4_INDD; + mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT; + mas4 |= MAS4_TLBSELD(1); + mmu_pte_psize = MMU_PAGE_2M; + break; + + case PPC_HTW_IBM: + mas4 |= MAS4_INDD; #ifdef CONFIG_PPC_64K_PAGES mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT; mmu_pte_psize = MMU_PAGE_256M; @@ -604,13 +620,16 @@ static void __early_init_mmu(int boot_cpu) mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT; mmu_pte_psize = MMU_PAGE_1M; #endif - } else { + break; + + case PPC_HTW_NONE: #ifdef CONFIG_PPC_64K_PAGES mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT; #else mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT; #endif mmu_pte_psize = mmu_virtual_psize; + break; } mtspr(SPRN_MAS4, mas4); @@ -630,8 +649,11 @@ static void __early_init_mmu(int boot_cpu) /* limit memory so we dont have linear faults */ memblock_enforce_memory_limit(linear_map_top); - patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); - patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e); + if (book3e_htw_mode == PPC_HTW_NONE) { + patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); + patch_exception(0x1e0, + exc_instruction_tlb_miss_bolted_book3e); + } } #endif diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index 626ad081639f..43ff3c797fbf 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -402,7 +402,9 @@ _GLOBAL(set_context) * Load TLBCAM[index] entry in to the L2 CAM MMU */ _GLOBAL(loadcam_entry) - LOAD_REG_ADDR(r4, TLBCAM) + mflr r5 + LOAD_REG_ADDR_PIC(r4, TLBCAM) + mtlr r5 mulli r5,r3,TLBCAM_SIZE add r3,r5,r4 lwz r4,TLBCAM_MAS0(r3) diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c index ff617246d128..d29b6e4e5e72 100644 --- a/arch/powerpc/oprofile/op_model_7450.c +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -16,7 +16,6 @@ */ #include <linux/oprofile.h> -#include <linux/init.h> #include <linux/smp.h> #include <asm/ptrace.h> #include <asm/processor.h> diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index b9589c19ccda..1f0ebdeea5f7 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -16,7 +16,6 @@ #include <linux/cpufreq.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/oprofile.h> diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c index 2a82d3ed464d..14cf86fdddab 100644 --- a/arch/powerpc/oprofile/op_model_fsl_emb.c +++ b/arch/powerpc/oprofile/op_model_fsl_emb.c @@ -14,7 +14,6 @@ */ #include <linux/oprofile.h> -#include <linux/init.h> #include <linux/smp.h> #include <asm/ptrace.h> #include <asm/processor.h> diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c index 42f778dff919..a114a7c22d40 100644 --- a/arch/powerpc/oprofile/op_model_pa6t.c +++ b/arch/powerpc/oprofile/op_model_pa6t.c @@ -22,7 +22,6 @@ */ #include <linux/oprofile.h> -#include <linux/init.h> #include <linux/smp.h> #include <linux/percpu.h> #include <asm/processor.h> diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index f444b94935f5..962fe7b3e3fb 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -10,7 +10,6 @@ */ #include <linux/oprofile.h> -#include <linux/init.h> #include <linux/smp.h> #include <asm/firmware.h> #include <asm/ptrace.h> diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c index 9b801b8c8c5a..7e5b8ed3a1b7 100644 --- a/arch/powerpc/oprofile/op_model_rs64.c +++ b/arch/powerpc/oprofile/op_model_rs64.c @@ -8,7 +8,6 @@ */ #include <linux/oprofile.h> -#include <linux/init.h> #include <linux/smp.h> #include <asm/ptrace.h> #include <asm/processor.h> diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 670a033264c0..2bdc8c862c46 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -99,7 +99,6 @@ config SBC834x config ASP834x bool "Analogue & Micro ASP 834x" select PPC_MPC834x - select REDBOOT help This enables support for the Analogue & Micro ASP 83xx board. diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index fd71cfdf2380..e238b6a55b15 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -11,7 +11,6 @@ * (at your option) any later version. */ -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 3d9716ccd327..4b4c081df94d 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -10,7 +10,6 @@ * by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pm.h> #include <linux/types.h> #include <linux/ioport.h> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 4d4634958cfb..c17aae80e7ff 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -123,6 +123,12 @@ config P1023_RDS help This option enables support for the P1023 RDS and RDB boards +config TWR_P102x + bool "Freescale TWR-P102x" + select DEFAULT_UIMAGE + help + This option enables support for the TWR-P1025 board. + config SOCRATES bool "Socrates" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index dd4c0b59577b..25cebe74ac46 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_P1010_RDB) += p1010rdb.o obj-$(CONFIG_P1022_DS) += p1022_ds.o obj-$(CONFIG_P1022_RDK) += p1022_rdk.o obj-$(CONFIG_P1023_RDS) += p1023_rds.o +obj-$(CONFIG_TWR_P102x) += twr_p102x.o obj-$(CONFIG_CORENET_GENERIC) += corenet_generic.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index eba78c85303f..3b085c7ee539 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -9,6 +9,7 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <asm/qe.h> #include <sysdev/cpm2_pic.h> #include "mpc85xx.h" @@ -82,3 +83,40 @@ void __init mpc85xx_cpm2_pic_init(void) irq_set_chained_handler(irq, cpm2_cascade); } #endif + +#ifdef CONFIG_QUICC_ENGINE +void __init mpc85xx_qe_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) { + np = of_find_node_by_name(NULL, "qe"); + if (!np) { + pr_err("%s: Could not find Quicc Engine node\n", + __func__); + return; + } + } + + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + + qe_reset(); + of_node_put(np); + + np = of_find_node_by_name(NULL, "par_io"); + if (np) { + struct device_node *ucc; + + par_io_init(np); + of_node_put(np); + + for_each_node_by_name(ucc, "ucc") + par_io_of_config(ucc); + + } +} +#endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index 2aa7c5dc2c7f..fc51dd4092e5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -8,4 +8,10 @@ extern void mpc85xx_cpm2_pic_init(void); static inline void __init mpc85xx_cpm2_pic_init(void) {} #endif /* CONFIG_CPM2 */ +#ifdef CONFIG_QUICC_ENGINE +extern void mpc85xx_qe_init(void); +#else +static inline void __init mpc85xx_qe_init(void) {} +#endif + #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index a7b3621a8df5..34f3c5eb3bee 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2006-2010, 2012-2013 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Andy Fleming <afleming@freescale.com> @@ -238,32 +238,7 @@ static void __init mpc85xx_mds_qe_init(void) { struct device_node *np; - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - np = of_find_node_by_name(NULL, "qe"); - if (!np) - return; - } - - if (!of_device_is_available(np)) { - of_node_put(np); - return; - } - - qe_reset(); - of_node_put(np); - - np = of_find_node_by_name(NULL, "par_io"); - if (np) { - struct device_node *ucc; - - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(ucc, "ucc") - par_io_of_config(ucc); - } - + mpc85xx_qe_init(); mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index 53b6fb0a3d56..e15bdd18fdb2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@ /* * MPC85xx RDB Board Setup * - * Copyright 2009,2012 Freescale Semiconductor Inc. + * Copyright 2009,2012-2013 Freescale Semiconductor Inc. * * 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 @@ -98,26 +98,7 @@ static void __init mpc85xx_rdb_setup_arch(void) fsl_pci_assign_primary(); #ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - pr_err("%s: Could not find Quicc Engine node\n", __func__); - goto qe_fail; - } - - qe_reset(); - of_node_put(np); - - np = of_find_node_by_name(NULL, "par_io"); - if (np) { - struct device_node *ucc; - - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(ucc, "ucc") - par_io_of_config(ucc); - - } + mpc85xx_qe_init(); #if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) if (machine_is(p1025_rdb)) { @@ -148,8 +129,6 @@ static void __init mpc85xx_rdb_setup_arch(void) } #endif - -qe_fail: #endif /* CONFIG_QUICC_ENGINE */ printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c index b9197cea1854..bb75add67084 100644 --- a/arch/powerpc/platforms/85xx/sgy_cts1000.c +++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c @@ -14,7 +14,6 @@ #include <linux/platform_device.h> #include <linux/device.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/workqueue.h> diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 393f975ab397..6382098d6f8d 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -389,15 +389,18 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) } #endif /* CONFIG_KEXEC */ -static void smp_85xx_setup_cpu(int cpu_nr) +static void smp_85xx_basic_setup(int cpu_nr) { - if (smp_85xx_ops.probe == smp_mpic_probe) - mpic_setup_this_cpu(); - if (cpu_has_feature(CPU_FTR_DBELL)) doorbell_setup_this_cpu(); } +static void smp_85xx_setup_cpu(int cpu_nr) +{ + mpic_setup_this_cpu(); + smp_85xx_basic_setup(cpu_nr); +} + static const struct of_device_id mpc85xx_smp_guts_ids[] = { { .compatible = "fsl,mpc8572-guts", }, { .compatible = "fsl,p1020-guts", }, @@ -412,13 +415,14 @@ void __init mpc85xx_smp_init(void) { struct device_node *np; - smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; np = of_find_node_by_type(NULL, "open-pic"); if (np) { smp_85xx_ops.probe = smp_mpic_probe; + smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; smp_85xx_ops.message_pass = smp_mpic_message_pass; - } + } else + smp_85xx_ops.setup_cpu = smp_85xx_basic_setup; if (cpu_has_feature(CPU_FTR_DBELL)) { /* @@ -427,6 +431,7 @@ void __init mpc85xx_smp_init(void) */ smp_85xx_ops.message_pass = NULL; smp_85xx_ops.cause_ipi = doorbell_cause_ipi; + smp_85xx_ops.probe = NULL; } np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c new file mode 100644 index 000000000000..c25ff10f05ee --- /dev/null +++ b/arch/powerpc/platforms/85xx/twr_p102x.c @@ -0,0 +1,147 @@ +/* + * Copyright 2010-2011, 2013 Freescale Semiconductor, Inc. + * + * Author: Michael Johnston <michael.johnston@freescale.com> + * + * Description: + * TWR-P102x Board Setup + * + * 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/errno.h> +#include <linux/pci.h> +#include <linux/of_platform.h> + +#include <asm/pci-bridge.h> +#include <asm/udbg.h> +#include <asm/mpic.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <asm/fsl_guts.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" + +static void __init twr_p1025_pic_init(void) +{ + struct mpic *mpic; + +#ifdef CONFIG_QUICC_ENGINE + struct device_node *np; +#endif + + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + + BUG_ON(mpic == NULL); + mpic_init(mpic); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (np) { + qe_ic_init(np, 0, qe_ic_cascade_low_mpic, + qe_ic_cascade_high_mpic); + of_node_put(np); + } else + pr_err("Could not find qe-ic node\n"); +#endif +} + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init twr_p1025_setup_arch(void) +{ +#ifdef CONFIG_QUICC_ENGINE + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("twr_p1025_setup_arch()", 0); + + mpc85xx_smp_init(); + + fsl_pci_assign_primary(); + +#ifdef CONFIG_QUICC_ENGINE + mpc85xx_qe_init(); + +#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) + if (machine_is(twr_p1025)) { + struct ccsr_guts __iomem *guts; + + np = of_find_compatible_node(NULL, NULL, "fsl,p1021-guts"); + if (np) { + guts = of_iomap(np, 0); + if (!guts) + pr_err("twr_p1025: could not map global utilities register\n"); + else { + /* P1025 has pins muxed for QE and other functions. To + * enable QE UEC mode, we need to set bit QE0 for UCC1 + * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 + * and QE12 for QE MII management signals in PMUXCR + * register. + * Set QE mux bits in PMUXCR */ + setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | + MPC85xx_PMUXCR_QE(3) | + MPC85xx_PMUXCR_QE(9) | + MPC85xx_PMUXCR_QE(12)); + iounmap(guts); + +#if defined(CONFIG_SERIAL_QE) + /* On P1025TWR board, the UCC7 acted as UART port. + * However, The UCC7's CTS pin is low level in default, + * it will impact the transmission in full duplex + * communication. So disable the Flow control pin PA18. + * The UCC7 UART just can use RXD and TXD pins. + */ + par_io_config_pin(0, 18, 0, 0, 0, 0); +#endif + /* Drive PB29 to CPLD low - CPLD will then change + * muxing from LBC to QE */ + par_io_config_pin(1, 29, 1, 0, 0, 0); + par_io_data_set(1, 29, 0); + } + of_node_put(np); + } + } +#endif +#endif /* CONFIG_QUICC_ENGINE */ + + pr_info("TWR-P1025 board from Freescale Semiconductor\n"); +} + +machine_arch_initcall(twr_p1025, mpc85xx_common_publish_devices); + +static int __init twr_p1025_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,TWR-P1025"); +} + +define_machine(twr_p1025) { + .name = "TWR-P1025", + .probe = twr_p1025_probe, + .setup_arch = twr_p1025_setup_arch, + .init_IRQ = twr_p1025_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 8dec3c0911ad..bd6f1a1cf922 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -45,7 +45,6 @@ config PPC_EP88XC config PPC_ADDER875 bool "Analogue & Micro Adder 875" select CPM1 - select REDBOOT help This enables support for the Analogue & Micro Adder 875 board. diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index bca2465a9c34..434fda39bf8b 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -72,6 +72,7 @@ config PPC_BOOK3S_64 select PPC_HAVE_PMU_SUPPORT select SYS_SUPPORTS_HUGETLBFS select HAVE_ARCH_TRANSPARENT_HUGEPAGE if PPC_64K_PAGES + select ARCH_SUPPORTS_NUMA_BALANCING config PPC_BOOK3E_64 bool "Embedded processors" diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index c34ee4e60873..d4d245c0d787 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -111,7 +111,7 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); if (rflags & _PAGE_NO_CACHE) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; raw_spin_lock(&beat_htab_lock); lpar_rc = beat_read_mask(hpte_group); @@ -337,7 +337,7 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); if (rflags & _PAGE_NO_CACHE) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; /* insert into not-volted entry */ lpar_rc = beat_insert_htab_entry3(0, hpte_group, hpte_v, hpte_r, diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index b53560660b72..2b90ff8a93be 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -197,7 +197,7 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages, io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); - for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE) + for (i = 0; i < npages; i++, uaddr += tbl->it_page_shift) io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask); mb(); @@ -430,7 +430,7 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, { cell_iommu_setup_stab(iommu, base, size, 0, 0); iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size, 0, 0, - IOMMU_PAGE_SHIFT); + IOMMU_PAGE_SHIFT_4K); cell_iommu_enable_hardware(iommu); } @@ -487,8 +487,10 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, window->table.it_blocksize = 16; window->table.it_base = (unsigned long)iommu->ptab; window->table.it_index = iommu->nid; - window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset; - window->table.it_size = size >> IOMMU_PAGE_SHIFT; + window->table.it_page_shift = IOMMU_PAGE_SHIFT_4K; + window->table.it_offset = + (offset >> window->table.it_page_shift) + pte_offset; + window->table.it_size = size >> window->table.it_page_shift; iommu_init_table(&window->table, iommu->nid); @@ -773,7 +775,7 @@ static void __init cell_iommu_init_one(struct device_node *np, /* Setup the iommu_table */ cell_iommu_setup_window(iommu, np, base, size, - offset >> IOMMU_PAGE_SHIFT); + offset >> IOMMU_PAGE_SHIFT_4K); } static void __init cell_disable_iommus(void) @@ -1122,7 +1124,7 @@ static int __init cell_iommu_fixed_mapping_init(void) cell_iommu_setup_stab(iommu, dbase, dsize, fbase, fsize); iommu->ptab = cell_iommu_alloc_ptab(iommu, dbase, dsize, 0, 0, - IOMMU_PAGE_SHIFT); + IOMMU_PAGE_SHIFT_4K); cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize, fbase, fsize); cell_iommu_enable_hardware(iommu); diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index dead91b177b9..b6c9a0dcc924 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/spinlock.h> #include <asm/ptrace.h> diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 302ba43d73a1..6d3c7a9fd047 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -67,6 +67,18 @@ config PPC_C2K This option enables support for the GE Fanuc C2K board (formerly an SBS board). +config MVME5100 + bool "Motorola/Emerson MVME5100" + depends on EMBEDDED6xx + select MPIC + select PCI + select PPC_INDIRECT_PCI + select PPC_I8259 + select PPC_NATIVE + help + This option enables support for the Motorola (now Emerson) MVME5100 + board. + config TSI108_BRIDGE bool select PCI @@ -113,4 +125,3 @@ config WII help Select WII if configuring for the Nintendo Wii. More information at: <http://gc-linux.sourceforge.net/> - diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index 66c23e423f40..cdd48d402b93 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o obj-$(CONFIG_GAMECUBE) += gamecube.o obj-$(CONFIG_WII) += wii.o hlwd-pic.o +obj-$(CONFIG_MVME5100) += mvme5100.o diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 6c03034dbbd3..c269caee58f9 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -15,7 +15,6 @@ #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt #include <linux/kernel.h> -#include <linux/init.h> #include <linux/irq.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c new file mode 100644 index 000000000000..25e3bfb64efb --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -0,0 +1,221 @@ +/* + * Board setup routines for the Motorola/Emerson MVME5100. + * + * Copyright 2013 CSC Australia Pty. Ltd. + * + * Based on earlier code by: + * + * Matt Porter, MontaVista Software Inc. + * Copyright 2001 MontaVista Software Inc. + * + * 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. + * + * Author: Stephen Chivers <schivers@csc.com> + * + */ + +#include <linux/of_platform.h> + +#include <asm/i8259.h> +#include <asm/pci-bridge.h> +#include <asm/mpic.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#define HAWK_MPIC_SIZE 0x00040000U +#define MVME5100_PCI_MEM_OFFSET 0x00000000 + +/* Board register addresses. */ +#define BOARD_STATUS_REG 0xfef88080 +#define BOARD_MODFAIL_REG 0xfef88090 +#define BOARD_MODRST_REG 0xfef880a0 +#define BOARD_TBEN_REG 0xfef880c0 +#define BOARD_SW_READ_REG 0xfef880e0 +#define BOARD_GEO_ADDR_REG 0xfef880e8 +#define BOARD_EXT_FEATURE1_REG 0xfef880f0 +#define BOARD_EXT_FEATURE2_REG 0xfef88100 + +static phys_addr_t pci_membase; +static u_char *restart; + +static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq = i8259_irq(); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + +static void __init mvme5100_pic_init(void) +{ + struct mpic *mpic; + struct device_node *np; + struct device_node *cp = NULL; + unsigned int cirq; + unsigned long intack = 0; + const u32 *prop = NULL; + + np = of_find_node_by_type(NULL, "open-pic"); + if (!np) { + pr_err("Could not find open-pic node\n"); + return; + } + + mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC "); + + BUG_ON(mpic == NULL); + of_node_put(np); + + mpic_assign_isu(mpic, 0, pci_membase + 0x10000); + + mpic_init(mpic); + + cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); + if (cp == NULL) { + pr_warn("mvme5100_pic_init: couldn't find i8259\n"); + return; + } + + cirq = irq_of_parse_and_map(cp, 0); + if (cirq == NO_IRQ) { + pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); + return; + } + + np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); + if (np) { + prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); + + if (prop) + intack = prop[0]; + + of_node_put(np); + } + + if (intack) + pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", + intack); + + i8259_init(cp, intack); + of_node_put(cp); + irq_set_chained_handler(cirq, mvme5100_8259_cascade); +} + +static int __init mvme5100_add_bridge(struct device_node *dev) +{ + const int *bus_range; + int len; + struct pci_controller *hose; + unsigned short devid; + + pr_info("Adding PCI host bridge %s\n", dev->full_name); + + bus_range = of_get_property(dev, "bus-range", &len); + + hose = pcibios_alloc_controller(dev); + if (hose == NULL) + return -ENOMEM; + + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); + + pci_process_bridge_OF_ranges(hose, dev, 1); + + early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); + + if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { + pr_err("HAWK PHB not present?\n"); + return 0; + } + + early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); + + if (pci_membase == 0) { + pr_err("HAWK PHB mibar not correctly set?\n"); + return 0; + } + + pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); + + return 0; +} + +static struct of_device_id mvme5100_of_bus_ids[] __initdata = { + { .compatible = "hawk-bridge", }, + {}, +}; + +/* + * Setup the architecture + */ +static void __init mvme5100_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mvme5100_setup_arch()", 0); + + for_each_compatible_node(np, "pci", "hawk-pci") + mvme5100_add_bridge(np); + + restart = ioremap(BOARD_MODRST_REG, 4); +} + + +static void mvme5100_show_cpuinfo(struct seq_file *m) +{ + seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); + seq_puts(m, "Machine\t\t: MVME5100\n"); +} + +static void mvme5100_restart(char *cmd) +{ + + local_irq_disable(); + mtmsr(mfmsr() | MSR_IP); + + out_8((u_char *) restart, 0x01); + + while (1) + ; +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mvme5100_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MVME5100"); +} + +static int __init probe_of_platform_devices(void) +{ + + of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); + return 0; +} + +machine_device_initcall(mvme5100, probe_of_platform_devices); + +define_machine(mvme5100) { + .name = "MVME5100", + .probe = mvme5100_probe, + .setup_arch = mvme5100_setup_arch, + .init_IRQ = mvme5100_pic_init, + .show_cpuinfo = mvme5100_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = mvme5100_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index f3defd8a2806..aafa01ba062f 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -18,7 +18,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/export.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 7d2d036754b5..2e576f2ae442 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -138,8 +138,11 @@ static void iommu_table_iobmap_setup(void) pr_debug(" -> %s\n", __func__); iommu_table_iobmap.it_busno = 0; iommu_table_iobmap.it_offset = 0; + iommu_table_iobmap.it_page_shift = IOBMAP_PAGE_SHIFT; + /* it_size is in number of entries */ - iommu_table_iobmap.it_size = 0x80000000 >> IOBMAP_PAGE_SHIFT; + iommu_table_iobmap.it_size = + 0x80000000 >> iommu_table_iobmap.it_page_shift; /* Initialize the common IOMMU code */ iommu_table_iobmap.it_base = (unsigned long)iob_l2_base; diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index d588e48dff74..43075081721f 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -5,7 +5,6 @@ * FIXME: LOCKING !!! */ -#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/spinlock.h> diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index 9fced3f6d2dc..895e8a20a3fc 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -13,11 +13,6 @@ config PPC_POWERNV select ARCH_RANDOM default y -config POWERNV_MSI - bool "Support PCI MSI on PowerNV platform" - depends on PCI_MSI - default y - config PPC_POWERNV_RTAS depends on PPC_POWERNV bool "Support for RTAS based PowerNV platforms such as BML" diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 873fa1370dc4..8d767fde5a6a 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o obj-$(CONFIG_PPC_SCOM) += opal-xscom.o +obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index d7ddcee7feb8..e1e71618b70c 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -14,7 +14,6 @@ #include <linux/bootmem.h> #include <linux/debugfs.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> @@ -578,11 +577,8 @@ static int ioda_eeh_get_log(struct eeh_pe *pe, int severity, return -EIO; } - /* - * FIXME: We probably need log the error in somewhere. - * Lets make it up in future. - */ - /* pr_info("%s", phb->diag.blob); */ + /* The PHB diag-data is always indicative */ + pnv_pci_dump_phb_diag_data(hose, phb->diag.blob); spin_unlock_irqrestore(&phb->lock, flags); @@ -670,143 +666,9 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose) } } -static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoP7IOCPhbErrorData *data; - int i; - - data = (struct OpalIoP7IOCPhbErrorData *)common; - - pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - -static void ioda_eeh_phb3_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoPhb3ErrorData *data; - int i; - - data = (struct OpalIoPhb3ErrorData*)common; - pr_info("PHB3 PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" nFir: %016llx\n", data->nFir); - pr_info(" nFirMask: %016llx\n", data->nFirMask); - pr_info(" nFirWOF: %016llx\n", data->nFirWOF); - pr_info(" PhbPlssr: %016llx\n", data->phbPlssr); - pr_info(" PhbCsr: %016llx\n", data->phbCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - static void ioda_eeh_phb_diag(struct pci_controller *hose) { struct pnv_phb *phb = hose->private_data; - struct OpalIoPhbErrorCommon *common; long rc; rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, @@ -817,18 +679,7 @@ static void ioda_eeh_phb_diag(struct pci_controller *hose) return; } - common = (struct OpalIoPhbErrorCommon *)phb->diag.blob; - switch (common->ioType) { - case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: - ioda_eeh_p7ioc_phb_diag(hose, common); - break; - case OPAL_PHB_ERROR_DATA_TYPE_PHB3: - ioda_eeh_phb3_phb_diag(hose, common); - break; - default: - pr_warning("%s: Unrecognized I/O chip %d\n", - __func__, common->ioType); - } + pnv_pci_dump_phb_diag_data(hose, phb->diag.blob); } static int ioda_eeh_get_phb_pe(struct pci_controller *hose, @@ -862,11 +713,7 @@ static int ioda_eeh_get_pe(struct pci_controller *hose, dev.phb = hose; dev.pe_config_addr = pe_no; dev_pe = eeh_pe_get(&dev); - if (!dev_pe) { - pr_warning("%s: Can't find PE for PHB#%x - PE#%x\n", - __func__, hose->global_number, pe_no); - return -EEXIST; - } + if (!dev_pe) return -EEXIST; *pe = dev_pe; return 0; @@ -884,12 +731,12 @@ static int ioda_eeh_get_pe(struct pci_controller *hose, */ static int ioda_eeh_next_error(struct eeh_pe **pe) { - struct pci_controller *hose, *tmp; + struct pci_controller *hose; struct pnv_phb *phb; u64 frozen_pe_no; u16 err_type, severity; long rc; - int ret = 1; + int ret = EEH_NEXT_ERR_NONE; /* * While running here, it's safe to purge the event queue. @@ -899,7 +746,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) eeh_remove_event(NULL); opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, list_node) { /* * If the subordinate PCI buses of the PHB has been * removed, we needn't take care of it any more. @@ -938,19 +785,19 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) switch (err_type) { case OPAL_EEH_IOC_ERROR: if (severity == OPAL_EEH_SEV_IOC_DEAD) { - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, + list_node) { phb = hose->private_data; phb->eeh_state |= PNV_EEH_STATE_REMOVED; } pr_err("EEH: dead IOC detected\n"); - ret = 4; - goto out; + ret = EEH_NEXT_ERR_DEAD_IOC; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: IOC informative error " "detected\n"); ioda_eeh_hub_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; @@ -962,37 +809,61 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) pr_err("EEH: dead PHB#%x detected\n", hose->global_number); phb->eeh_state |= PNV_EEH_STATE_REMOVED; - ret = 3; - goto out; + ret = EEH_NEXT_ERR_DEAD_PHB; } else if (severity == OPAL_EEH_SEV_PHB_FENCED) { if (ioda_eeh_get_phb_pe(hose, pe)) break; pr_err("EEH: fenced PHB#%x detected\n", hose->global_number); - ret = 2; - goto out; + ret = EEH_NEXT_ERR_FENCED_PHB; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: PHB#%x informative error " "detected\n", hose->global_number); ioda_eeh_phb_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; case OPAL_EEH_PE_ERROR: - if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) - break; + /* + * If we can't find the corresponding PE, the + * PEEV / PEST would be messy. So we force an + * fenced PHB so that it can be recovered. + */ + if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) { + if (!ioda_eeh_get_phb_pe(hose, pe)) { + pr_err("EEH: Escalated fenced PHB#%x " + "detected for PE#%llx\n", + hose->global_number, + frozen_pe_no); + ret = EEH_NEXT_ERR_FENCED_PHB; + } else { + ret = EEH_NEXT_ERR_NONE; + } + } else { + pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", + (*pe)->addr, (*pe)->phb->global_number); + ret = EEH_NEXT_ERR_FROZEN_PE; + } - pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", - (*pe)->addr, (*pe)->phb->global_number); - ret = 1; - goto out; + break; + default: + pr_warn("%s: Unexpected error type %d\n", + __func__, err_type); } + + /* + * If we have no errors on the specific PHB or only + * informative error there, we continue poking it. + * Otherwise, we need actions to be taken by upper + * layer. + */ + if (ret > EEH_NEXT_ERR_INF) + break; } - ret = 0; -out: return ret; } diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 73b981438cc5..a79fddc5e74e 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -344,6 +344,27 @@ static int powernv_eeh_next_error(struct eeh_pe **pe) return -EEXIST; } +static int powernv_eeh_restore_config(struct device_node *dn) +{ + struct eeh_dev *edev = of_node_to_eeh_dev(dn); + struct pnv_phb *phb; + s64 ret; + + if (!edev) + return -EEXIST; + + phb = edev->phb->private_data; + ret = opal_pci_reinit(phb->opal_id, + OPAL_REINIT_PCI_DEV, edev->config_addr); + if (ret) { + pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", + __func__, edev->config_addr, ret); + return -EIO; + } + + return 0; +} + static struct eeh_ops powernv_eeh_ops = { .name = "powernv", .init = powernv_eeh_init, @@ -359,7 +380,8 @@ static struct eeh_ops powernv_eeh_ops = { .configure_bridge = powernv_eeh_configure_bridge, .read_config = pnv_pci_cfg_read, .write_config = pnv_pci_cfg_write, - .next_error = powernv_eeh_next_error + .next_error = powernv_eeh_next_error, + .restore_config = powernv_eeh_restore_config }; /** diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index d8773079ce19..714ef972406b 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c @@ -76,8 +76,8 @@ /* Validate buffer size */ #define VALIDATE_BUF_SIZE 4096 -/* XXX: Assume candidate image size is <= 256MB */ -#define MAX_IMAGE_SIZE 0x10000000 +/* XXX: Assume candidate image size is <= 1GB */ +#define MAX_IMAGE_SIZE 0x40000000 /* Flash sg list version */ #define SG_LIST_VERSION (1UL) @@ -103,27 +103,6 @@ struct image_header_t { uint32_t size; }; -/* Scatter/gather entry */ -struct opal_sg_entry { - void *data; - long length; -}; - -/* We calculate number of entries based on PAGE_SIZE */ -#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) - -/* - * This struct is very similar but not identical to that - * needed by the opal flash update. All we need to do for - * opal is rewrite num_entries into a version/length and - * translate the pointers to absolute. - */ -struct opal_sg_list { - unsigned long num_entries; - struct opal_sg_list *next; - struct opal_sg_entry entry[SG_ENTRIES_PER_NODE]; -}; - struct validate_flash_t { int status; /* Return status */ void *buf; /* Candidate image buffer */ @@ -333,7 +312,7 @@ static struct opal_sg_list *image_data_to_sglist(void) addr = image_data.data; size = image_data.size; - sg1 = kzalloc((sizeof(struct opal_sg_list)), GFP_KERNEL); + sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!sg1) return NULL; @@ -351,8 +330,7 @@ static struct opal_sg_list *image_data_to_sglist(void) sg1->num_entries++; if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { - sg1->next = kzalloc((sizeof(struct opal_sg_list)), - GFP_KERNEL); + sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!sg1->next) { pr_err("%s : Failed to allocate memory\n", __func__); @@ -402,7 +380,10 @@ static int opal_flash_update(int op) else sg->next = NULL; - /* Make num_entries into the version/length field */ + /* + * Convert num_entries to version/length format + * to satisfy OPAL. + */ sg->num_entries = (SG_LIST_VERSION << 56) | (sg->num_entries * sizeof(struct opal_sg_entry) + 16); } diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c new file mode 100644 index 000000000000..ec4132239cdf --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-memory-errors.c @@ -0,0 +1,146 @@ +/* + * OPAL asynchronus Memory error handling support in PowreNV. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/mm.h> +#include <linux/slab.h> + +#include <asm/opal.h> +#include <asm/cputable.h> + +static int opal_mem_err_nb_init; +static LIST_HEAD(opal_memory_err_list); +static DEFINE_SPINLOCK(opal_mem_err_lock); + +struct OpalMsgNode { + struct list_head list; + struct opal_msg msg; +}; + +static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt) +{ + uint64_t paddr_start, paddr_end; + + pr_debug("%s: Retrived memory error event, type: 0x%x\n", + __func__, merr_evt->type); + switch (merr_evt->type) { + case OPAL_MEM_ERR_TYPE_RESILIENCE: + paddr_start = merr_evt->u.resilience.physical_address_start; + paddr_end = merr_evt->u.resilience.physical_address_end; + break; + case OPAL_MEM_ERR_TYPE_DYN_DALLOC: + paddr_start = merr_evt->u.dyn_dealloc.physical_address_start; + paddr_end = merr_evt->u.dyn_dealloc.physical_address_end; + break; + default: + return; + } + + for (; paddr_start < paddr_end; paddr_start += PAGE_SIZE) { + memory_failure(paddr_start >> PAGE_SHIFT, 0, 0); + } +} + +static void handle_memory_error(void) +{ + unsigned long flags; + struct OpalMemoryErrorData *merr_evt; + struct OpalMsgNode *msg_node; + + spin_lock_irqsave(&opal_mem_err_lock, flags); + while (!list_empty(&opal_memory_err_list)) { + msg_node = list_entry(opal_memory_err_list.next, + struct OpalMsgNode, list); + list_del(&msg_node->list); + spin_unlock_irqrestore(&opal_mem_err_lock, flags); + + merr_evt = (struct OpalMemoryErrorData *) + &msg_node->msg.params[0]; + handle_memory_error_event(merr_evt); + kfree(msg_node); + spin_lock_irqsave(&opal_mem_err_lock, flags); + } + spin_unlock_irqrestore(&opal_mem_err_lock, flags); +} + +static void mem_error_handler(struct work_struct *work) +{ + handle_memory_error(); +} + +static DECLARE_WORK(mem_error_work, mem_error_handler); + +/* + * opal_memory_err_event - notifier handler that queues up the opal message + * to be preocessed later. + */ +static int opal_memory_err_event(struct notifier_block *nb, + unsigned long msg_type, void *msg) +{ + unsigned long flags; + struct OpalMsgNode *msg_node; + + if (msg_type != OPAL_MSG_MEM_ERR) + return 0; + + msg_node = kzalloc(sizeof(*msg_node), GFP_ATOMIC); + if (!msg_node) { + pr_err("MEMORY_ERROR: out of memory, Opal message event not" + "handled\n"); + return -ENOMEM; + } + memcpy(&msg_node->msg, msg, sizeof(struct opal_msg)); + + spin_lock_irqsave(&opal_mem_err_lock, flags); + list_add(&msg_node->list, &opal_memory_err_list); + spin_unlock_irqrestore(&opal_mem_err_lock, flags); + + schedule_work(&mem_error_work); + return 0; +} + +static struct notifier_block opal_mem_err_nb = { + .notifier_call = opal_memory_err_event, + .next = NULL, + .priority = 0, +}; + +static int __init opal_mem_err_init(void) +{ + int ret; + + if (!opal_mem_err_nb_init) { + ret = opal_message_notifier_register( + OPAL_MSG_MEM_ERR, &opal_mem_err_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + opal_mem_err_nb_init = 1; + } + return 0; +} +subsys_initcall(opal_mem_err_init); diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index 7d07c7e80ec0..b1885db8fdf3 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -18,6 +18,7 @@ #include <asm/opal.h> #include <asm/firmware.h> +#include <asm/machdep.h> static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) { @@ -48,8 +49,11 @@ unsigned long __init opal_get_boot_time(void) else mdelay(10); } - if (rc != OPAL_SUCCESS) + if (rc != OPAL_SUCCESS) { + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; return 0; + } y_m_d = be32_to_cpu(__y_m_d); h_m_s_ms = be64_to_cpu(__h_m_s_ms); opal_to_tm(y_m_d, h_m_s_ms, &tm); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index e7806504e976..3e8829c40fbb 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -126,3 +126,6 @@ OPAL_CALL(opal_return_cpu, OPAL_RETURN_CPU); OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); +OPAL_CALL(opal_get_msg, OPAL_GET_MSG); +OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION); +OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 1c798cd55372..65499adaecff 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -18,9 +18,12 @@ #include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/slab.h> +#include <linux/sched.h> #include <linux/kobject.h> +#include <linux/delay.h> #include <asm/opal.h> #include <asm/firmware.h> +#include <asm/mce.h> #include "powernv.h" @@ -38,6 +41,7 @@ extern u64 opal_mc_secondary_handler[]; static unsigned int *opal_irqs; static unsigned int opal_irq_count; static ATOMIC_NOTIFIER_HEAD(opal_notifier_head); +static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX]; static DEFINE_SPINLOCK(opal_notifier_lock); static uint64_t last_notified_mask = 0x0ul; static atomic_t opal_notifier_hold = ATOMIC_INIT(0); @@ -88,14 +92,10 @@ static int __init opal_register_exception_handlers(void) if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) return -ENODEV; - /* Hookup some exception handlers. We use the fwnmi area at 0x7000 - * to provide the glue space to OPAL + /* Hookup some exception handlers except machine check. We use the + * fwnmi area at 0x7000 to provide the glue space to OPAL */ glue = 0x7000; - opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER, - __pa(opal_mc_secondary_handler[0]), - glue); - glue += 128; opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 0, glue); glue += 128; @@ -169,6 +169,95 @@ void opal_notifier_disable(void) atomic_set(&opal_notifier_hold, 1); } +/* + * Opal message notifier based on message type. Allow subscribers to get + * notified for specific messgae type. + */ +int opal_message_notifier_register(enum OpalMessageType msg_type, + struct notifier_block *nb) +{ + if (!nb) { + pr_warning("%s: Invalid argument (%p)\n", + __func__, nb); + return -EINVAL; + } + if (msg_type > OPAL_MSG_TYPE_MAX) { + pr_warning("%s: Invalid message type argument (%d)\n", + __func__, msg_type); + return -EINVAL; + } + return atomic_notifier_chain_register( + &opal_msg_notifier_head[msg_type], nb); +} + +static void opal_message_do_notify(uint32_t msg_type, void *msg) +{ + /* notify subscribers */ + atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type], + msg_type, msg); +} + +static void opal_handle_message(void) +{ + s64 ret; + /* + * TODO: pre-allocate a message buffer depending on opal-msg-size + * value in /proc/device-tree. + */ + static struct opal_msg msg; + + ret = opal_get_msg(__pa(&msg), sizeof(msg)); + /* No opal message pending. */ + if (ret == OPAL_RESOURCE) + return; + + /* check for errors. */ + if (ret) { + pr_warning("%s: Failed to retrive opal message, err=%lld\n", + __func__, ret); + return; + } + + /* Sanity check */ + if (msg.msg_type > OPAL_MSG_TYPE_MAX) { + pr_warning("%s: Unknown message type: %u\n", + __func__, msg.msg_type); + return; + } + opal_message_do_notify(msg.msg_type, (void *)&msg); +} + +static int opal_message_notify(struct notifier_block *nb, + unsigned long events, void *change) +{ + if (events & OPAL_EVENT_MSG_PENDING) + opal_handle_message(); + return 0; +} + +static struct notifier_block opal_message_nb = { + .notifier_call = opal_message_notify, + .next = NULL, + .priority = 0, +}; + +static int __init opal_message_init(void) +{ + int ret, i; + + for (i = 0; i < OPAL_MSG_TYPE_MAX; i++) + ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]); + + ret = opal_notifier_register(&opal_message_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + return 0; +} +early_initcall(opal_message_init); + int opal_get_chars(uint32_t vtermno, char *buf, int count) { s64 rc; @@ -254,119 +343,62 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) return written; } +static int opal_recover_mce(struct pt_regs *regs, + struct machine_check_event *evt) +{ + int recovered = 0; + uint64_t ea = get_mce_fault_addr(evt); + + if (!(regs->msr & MSR_RI)) { + /* If MSR_RI isn't set, we cannot recover */ + recovered = 0; + } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) { + /* Platform corrected itself */ + recovered = 1; + } else if (ea && !is_kernel_addr(ea)) { + /* + * Faulting address is not in kernel text. We should be fine. + * We need to find which process uses this address. + * For now, kill the task if we have received exception when + * in userspace. + * + * TODO: Queue up this address for hwpoisioning later. + */ + if (user_mode(regs) && !is_global_init(current)) { + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } else + recovered = 0; + } else if (user_mode(regs) && !is_global_init(current) && + evt->severity == MCE_SEV_ERROR_SYNC) { + /* + * If we have received a synchronous error when in userspace + * kill the task. + */ + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } + return recovered; +} + int opal_machine_check(struct pt_regs *regs) { - struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; - struct opal_machine_check_event evt; - const char *level, *sevstr, *subtype; - static const char *opal_mc_ue_types[] = { - "Indeterminate", - "Instruction fetch", - "Page table walk ifetch", - "Load/Store", - "Page table walk Load/Store", - }; - static const char *opal_mc_slb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_erat_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_tlb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - - /* Copy the event structure and release the original */ - evt = *opal_evt; - opal_evt->in_use = 0; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return 0; /* Print things out */ - if (evt.version != OpalMCE_V1) { + if (evt.version != MCE_V1) { pr_err("Machine Check Exception, Unknown event version %d !\n", evt.version); return 0; } - switch(evt.severity) { - case OpalMCE_SEV_NO_ERROR: - level = KERN_INFO; - sevstr = "Harmless"; - break; - case OpalMCE_SEV_WARNING: - level = KERN_WARNING; - sevstr = ""; - break; - case OpalMCE_SEV_ERROR_SYNC: - level = KERN_ERR; - sevstr = "Severe"; - break; - case OpalMCE_SEV_FATAL: - default: - level = KERN_ERR; - sevstr = "Fatal"; - break; - } + machine_check_print_event_info(&evt); - printk("%s%s Machine check interrupt [%s]\n", level, sevstr, - evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? - "Recovered" : "[Not recovered"); - printk("%s Initiator: %s\n", level, - evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown"); - switch(evt.error_type) { - case OpalMCE_ERROR_TYPE_UE: - subtype = evt.u.ue_error.ue_error_type < - ARRAY_SIZE(opal_mc_ue_types) ? - opal_mc_ue_types[evt.u.ue_error.ue_error_type] - : "Unknown"; - printk("%s Error type: UE [%s]\n", level, subtype); - if (evt.u.ue_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.ue_error.effective_address); - if (evt.u.ue_error.physical_address_provided) - printk("%s Physial address: %016llx\n", - level, evt.u.ue_error.physical_address); - break; - case OpalMCE_ERROR_TYPE_SLB: - subtype = evt.u.slb_error.slb_error_type < - ARRAY_SIZE(opal_mc_slb_types) ? - opal_mc_slb_types[evt.u.slb_error.slb_error_type] - : "Unknown"; - printk("%s Error type: SLB [%s]\n", level, subtype); - if (evt.u.slb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.slb_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_ERAT: - subtype = evt.u.erat_error.erat_error_type < - ARRAY_SIZE(opal_mc_erat_types) ? - opal_mc_erat_types[evt.u.erat_error.erat_error_type] - : "Unknown"; - printk("%s Error type: ERAT [%s]\n", level, subtype); - if (evt.u.erat_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.erat_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_TLB: - subtype = evt.u.tlb_error.tlb_error_type < - ARRAY_SIZE(opal_mc_tlb_types) ? - opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type] - : "Unknown"; - printk("%s Error type: TLB [%s]\n", level, subtype); - if (evt.u.tlb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.tlb_error.effective_address); - break; - default: - case OpalMCE_ERROR_TYPE_UNKNOWN: - printk("%s Error type: Unknown\n", level); - break; - } - return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1; + if (opal_recover_mce(regs, &evt)) + return 1; + return 0; } static irqreturn_t opal_interrupt(int irq, void *data) @@ -451,10 +483,25 @@ subsys_initcall(opal_init); void opal_shutdown(void) { unsigned int i; + long rc = OPAL_BUSY; + /* First free interrupts, which will also mask them */ for (i = 0; i < opal_irq_count; i++) { if (opal_irqs[i]) free_irq(opal_irqs[i], NULL); opal_irqs[i] = 0; } + + /* + * Then sync with OPAL which ensure anything that can + * potentially write to our memory has completed such + * as an ongoing dump retrieval + */ + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_sync_host_reboot(); + if (rc == OPAL_BUSY) + opal_poll_events(NULL); + else + mdelay(10); + } } diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 2c6d173842b2..7d6dcc6d5fa9 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -460,7 +460,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev return; pe = &phb->ioda.pe_array[pdn->pe_number]; - set_iommu_table_base(&pdev->dev, &pe->tce32_table); + set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table); } static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) @@ -468,7 +468,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { - set_iommu_table_base(&dev->dev, &pe->tce32_table); + set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table); if (dev->subordinate) pnv_ioda_setup_bus_dma(pe, dev->subordinate); } @@ -644,7 +644,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); if (pe->pdev) - set_iommu_table_base(&pe->pdev->dev, tbl); + set_iommu_table_base_and_group(&pe->pdev->dev, tbl); else pnv_ioda_setup_bus_dma(pe, pe->pbus); @@ -723,7 +723,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); if (pe->pdev) - set_iommu_table_base(&pe->pdev->dev, tbl); + set_iommu_table_base_and_group(&pe->pdev->dev, tbl); else pnv_ioda_setup_bus_dma(pe, pe->pbus); @@ -1144,7 +1144,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, { struct pci_controller *hose; struct pnv_phb *phb; - unsigned long size, m32map_off, iomap_off, pemap_off; + unsigned long size, m32map_off, pemap_off, iomap_off = 0; const __be64 *prop64; const __be32 *prop32; int len; @@ -1231,7 +1231,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); m32map_off = size; size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]); - iomap_off = size; if (phb->type == PNV_PHB_IODA1) { iomap_off = size; size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]); diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index f8b4bd8afb2e..e3807d69393e 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -92,7 +92,7 @@ static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, pci_domain_nr(phb->hose->bus), phb->opal_id); } - set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); + set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table); } static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id, diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 4eb33a9ed532..b555ebc57ef5 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -124,77 +124,157 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) } #endif /* CONFIG_PCI_MSI */ -static void pnv_pci_dump_p7ioc_diag_data(struct pnv_phb *phb) +static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) { - struct OpalIoP7IOCPhbErrorData *data = &phb->diag.p7ioc; + struct OpalIoP7IOCPhbErrorData *data; int i; - pr_info("PHB %d diagnostic data:\n", phb->hose->global_number); - - pr_info(" brdgCtl = 0x%08x\n", data->brdgCtl); - - pr_info(" portStatusReg = 0x%08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus = 0x%08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus = 0x%08x\n", data->busAgentStatus); - - pr_info(" deviceStatus = 0x%08x\n", data->deviceStatus); - pr_info(" slotStatus = 0x%08x\n", data->slotStatus); - pr_info(" linkStatus = 0x%08x\n", data->linkStatus); - pr_info(" devCmdStatus = 0x%08x\n", data->devCmdStatus); - pr_info(" devSecStatus = 0x%08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus = 0x%08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus = 0x%08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus = 0x%08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1 = 0x%08x\n", data->tlpHdr1); - pr_info(" tlpHdr2 = 0x%08x\n", data->tlpHdr2); - pr_info(" tlpHdr3 = 0x%08x\n", data->tlpHdr3); - pr_info(" tlpHdr4 = 0x%08x\n", data->tlpHdr4); - pr_info(" sourceId = 0x%08x\n", data->sourceId); - - pr_info(" errorClass = 0x%016llx\n", data->errorClass); - pr_info(" correlator = 0x%016llx\n", data->correlator); - - pr_info(" p7iocPlssr = 0x%016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr = 0x%016llx\n", data->p7iocCsr); - pr_info(" lemFir = 0x%016llx\n", data->lemFir); - pr_info(" lemErrorMask = 0x%016llx\n", data->lemErrorMask); - pr_info(" lemWOF = 0x%016llx\n", data->lemWOF); - pr_info(" phbErrorStatus = 0x%016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus = 0x%016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0 = 0x%016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1 = 0x%016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus = 0x%016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus = 0x%016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0 = 0x%016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1 = 0x%016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus = 0x%016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus = 0x%016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0 = 0x%016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1 = 0x%016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus = 0x%016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus = 0x%016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0 = 0x%016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1 = 0x%016llx\n", data->dma1ErrorLog1); + data = (struct OpalIoP7IOCPhbErrorData *)common; + pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + + pr_info(" brdgCtl: %08x\n", data->brdgCtl); + + pr_info(" portStatusReg: %08x\n", data->portStatusReg); + pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); + pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); + + pr_info(" deviceStatus: %08x\n", data->deviceStatus); + pr_info(" slotStatus: %08x\n", data->slotStatus); + pr_info(" linkStatus: %08x\n", data->linkStatus); + pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); + pr_info(" devSecStatus: %08x\n", data->devSecStatus); + + pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); + pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); + pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); + pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); + pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); + pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); + pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); + pr_info(" sourceId: %08x\n", data->sourceId); + pr_info(" errorClass: %016llx\n", data->errorClass); + pr_info(" correlator: %016llx\n", data->correlator); + pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); + pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); + pr_info(" lemFir: %016llx\n", data->lemFir); + pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); + pr_info(" lemWOF: %016llx\n", data->lemWOF); + pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); + pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); + pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); + pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); + pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); + pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); + pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); + pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); + pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); + pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); + pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); + pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); + pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); + pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); + pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); + pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { if ((data->pestA[i] >> 63) == 0 && (data->pestB[i] >> 63) == 0) continue; - pr_info(" PE[%3d] PESTA = 0x%016llx\n", i, data->pestA[i]); - pr_info(" PESTB = 0x%016llx\n", data->pestB[i]); + + pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); + pr_info(" PESTB: %016llx\n", data->pestB[i]); + } +} + +static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) +{ + struct OpalIoPhb3ErrorData *data; + int i; + + data = (struct OpalIoPhb3ErrorData*)common; + pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + + pr_info(" brdgCtl: %08x\n", data->brdgCtl); + + pr_info(" portStatusReg: %08x\n", data->portStatusReg); + pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); + pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); + + pr_info(" deviceStatus: %08x\n", data->deviceStatus); + pr_info(" slotStatus: %08x\n", data->slotStatus); + pr_info(" linkStatus: %08x\n", data->linkStatus); + pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); + pr_info(" devSecStatus: %08x\n", data->devSecStatus); + + pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); + pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); + pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); + pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); + pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); + pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); + pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); + pr_info(" sourceId: %08x\n", data->sourceId); + pr_info(" errorClass: %016llx\n", data->errorClass); + pr_info(" correlator: %016llx\n", data->correlator); + + pr_info(" nFir: %016llx\n", data->nFir); + pr_info(" nFirMask: %016llx\n", data->nFirMask); + pr_info(" nFirWOF: %016llx\n", data->nFirWOF); + pr_info(" PhbPlssr: %016llx\n", data->phbPlssr); + pr_info(" PhbCsr: %016llx\n", data->phbCsr); + pr_info(" lemFir: %016llx\n", data->lemFir); + pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); + pr_info(" lemWOF: %016llx\n", data->lemWOF); + pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); + pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); + pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); + pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); + pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); + pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); + pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); + pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); + pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); + pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); + pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); + pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); + pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); + pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); + pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); + pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); + + for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { + if ((data->pestA[i] >> 63) == 0 && + (data->pestB[i] >> 63) == 0) + continue; + + pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); + pr_info(" PESTB: %016llx\n", data->pestB[i]); } } -static void pnv_pci_dump_phb_diag_data(struct pnv_phb *phb) +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff) { - switch(phb->model) { - case PNV_PHB_MODEL_P7IOC: - pnv_pci_dump_p7ioc_diag_data(phb); + struct OpalIoPhbErrorCommon *common; + + if (!hose || !log_buff) + return; + + common = (struct OpalIoPhbErrorCommon *)log_buff; + switch (common->ioType) { + case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: + pnv_pci_dump_p7ioc_diag_data(hose, common); + break; + case OPAL_PHB_ERROR_DATA_TYPE_PHB3: + pnv_pci_dump_phb3_diag_data(hose, common); break; default: - pr_warning("PCI %d: Can't decode this PHB diag data\n", - phb->hose->global_number); + pr_warn("%s: Unrecognized ioType %d\n", + __func__, common->ioType); } } @@ -222,7 +302,7 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) * with the normal errors generated when probing empty slots */ if (has_diag) - pnv_pci_dump_phb_diag_data(phb); + pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob); else pr_warning("PCI %d: No diag data available\n", phb->hose->global_number); @@ -484,7 +564,8 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl, { tbl->it_blocksize = 16; tbl->it_base = (unsigned long)tce_mem; - tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->it_offset = dma_offset >> tbl->it_page_shift; tbl->it_index = 0; tbl->it_size = tce_size >> 3; tbl->it_busno = 0; @@ -536,7 +617,7 @@ static void pnv_pci_dma_fallback_setup(struct pci_controller *hose, pdn->iommu_table = pnv_pci_setup_bml_iommu(hose); if (!pdn->iommu_table) return; - set_iommu_table_base(&pdev->dev, pdn->iommu_table); + set_iommu_table_base_and_group(&pdev->dev, pdn->iommu_table); } static void pnv_pci_dma_dev_setup(struct pci_dev *pdev) @@ -657,3 +738,32 @@ void __init pnv_pci_init(void) ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; #endif } + +static int tce_iommu_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + return iommu_add_device(dev); + case BUS_NOTIFY_DEL_DEVICE: + if (dev->iommu_group) + iommu_del_device(dev); + return 0; + default: + return 0; + } +} + +static struct notifier_block tce_iommu_bus_nb = { + .notifier_call = tce_iommu_bus_notifier, +}; + +static int __init tce_iommu_bus_notifier_init(void) +{ + bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); + return 0; +} + +subsys_initcall_sync(tce_iommu_bus_notifier_init); diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 1ed8d5f40f5a..13f1942a9a5f 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -176,6 +176,7 @@ struct pnv_phb { union { unsigned char blob[PNV_PCI_DIAG_BUF_SIZE]; struct OpalIoP7IOCPhbErrorData p7ioc; + struct OpalIoPhb3ErrorData phb3; struct OpalIoP7IOCErrorData hub_diag; } diag; @@ -186,6 +187,8 @@ extern struct pci_ops pnv_pci_ops; extern struct pnv_eeh_ops ioda_eeh_ops; #endif +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff); int pnv_pci_cfg_read(struct device_node *dn, int where, int size, u32 *val); int pnv_pci_cfg_write(struct device_node *dn, diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 19884b2a51b4..a932feb2901c 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -145,8 +145,10 @@ static void pnv_shutdown(void) /* Let the PCI code clear up IODA tables */ pnv_pci_shutdown(); - /* And unregister all OPAL interrupts so they don't fire - * up while we kexec + /* + * Stop OPAL activity: Unregister all OPAL interrupts so they + * don't fire up while we kexec and make sure all potentially + * DMA'ing ops are complete (such as dump retrieval). */ opal_shutdown(); } diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index e17fa1432d80..a0bca05e26b0 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -143,7 +143,7 @@ static void _dump_areas(unsigned int spe_id, unsigned long priv2, pr_debug("%s:%d: shadow: %lxh\n", func, line, shadow); } -inline u64 ps3_get_spe_id(void *arg) +u64 ps3_get_spe_id(void *arg) { return spu_pdata(arg)->spe_id; } diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 62b4f8025de0..e66643250fee 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,7 +34,7 @@ config PPC_SPLPAR config PSERIES_MSI bool - depends on PCI_MSI && EEH + depends on PCI_MSI && PPC_PSERIES && EEH default y config PSERIES_ENERGY diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 1e561bef459b..2d8bf15879fd 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -25,7 +25,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/gfp.h> -#include <linux/init.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/oom.h> diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 5db66f1fbc26..7d61498e45c0 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -20,7 +20,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/debugfs.h> #include <linux/spinlock.h> diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index ccb633e077b1..9ef3cc8ebc11 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -689,7 +689,9 @@ static struct eeh_ops pseries_eeh_ops = { .get_log = pseries_eeh_get_log, .configure_bridge = pseries_eeh_configure_bridge, .read_config = pseries_eeh_read_config, - .write_config = pseries_eeh_write_config + .write_config = pseries_eeh_write_config, + .next_error = NULL, + .restore_config = NULL }; /** diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index f253361552ae..33b552ffbe57 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -486,9 +486,10 @@ static void iommu_table_setparms(struct pci_controller *phb, memset((void *)tbl->it_base, 0, *sizep); tbl->it_busno = phb->bus->number; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; /* Units of tce entries */ - tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT; + tbl->it_offset = phb->dma_window_base_cur >> tbl->it_page_shift; /* Test if we are going over 2GB of DMA space */ if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { @@ -499,7 +500,7 @@ static void iommu_table_setparms(struct pci_controller *phb, phb->dma_window_base_cur += phb->dma_window_size; /* Set the tce table size - measured in entries */ - tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT; + tbl->it_size = phb->dma_window_size >> tbl->it_page_shift; tbl->it_index = 0; tbl->it_blocksize = 16; @@ -537,11 +538,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); tbl->it_busno = phb->bus->number; + tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; tbl->it_base = 0; tbl->it_blocksize = 16; tbl->it_type = TCE_PCI; - tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; - tbl->it_size = size >> IOMMU_PAGE_SHIFT; + tbl->it_offset = offset >> tbl->it_page_shift; + tbl->it_size = size >> tbl->it_page_shift; } static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) @@ -687,7 +689,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) iommu_table_setparms(phb, dn, tbl); PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); iommu_register_group(tbl, pci_domain_nr(phb->bus), 0); - set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); + set_iommu_table_base_and_group(&dev->dev, + PCI_DN(dn)->iommu_table); return; } @@ -699,7 +702,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) dn = dn->parent; if (dn && PCI_DN(dn)) - set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table); + set_iommu_table_base_and_group(&dev->dev, + PCI_DN(dn)->iommu_table); else printk(KERN_WARNING "iommu: Device %s has no iommu table\n", pci_name(dev)); @@ -717,21 +721,6 @@ static int __init disable_ddw_setup(char *str) early_param("disable_ddw", disable_ddw_setup); -static inline void __remove_ddw(struct device_node *np, const u32 *ddw_avail, u64 liobn) -{ - int ret; - - ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); - if (ret) - pr_warning("%s: failed to remove DMA window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); - else - pr_debug("%s: successfully removed DMA window: rtas returned " - "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddw_avail[2], liobn); -} - static void remove_ddw(struct device_node *np) { struct dynamic_dma_window_prop *dwp; @@ -761,7 +750,15 @@ static void remove_ddw(struct device_node *np) pr_debug("%s successfully cleared tces in window.\n", np->full_name); - __remove_ddw(np, ddw_avail, liobn); + ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); + if (ret) + pr_warning("%s: failed to remove direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); + else + pr_debug("%s: successfully removed direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddw_avail[2], liobn); delprop: ret = of_remove_property(np, win64); @@ -790,68 +787,33 @@ static u64 find_existing_ddw(struct device_node *pdn) return dma_addr; } -static void __restore_default_window(struct eeh_dev *edev, - u32 ddw_restore_token) -{ - u32 cfg_addr; - u64 buid; - int ret; - - /* - * Get the config address and phb buid of the PE window. - * Rely on eeh to retrieve this for us. - * Retrieve them from the pci device, not the node with the - * dma-window property - */ - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; - - do { - ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr, - BUID_HI(buid), BUID_LO(buid)); - } while (rtas_busy_delay(ret)); - pr_info("ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n", - ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); -} - static int find_existing_ddw_windows(void) { + int len; struct device_node *pdn; + struct direct_window *window; const struct dynamic_dma_window_prop *direct64; - const u32 *ddw_extensions; if (!firmware_has_feature(FW_FEATURE_LPAR)) return 0; for_each_node_with_property(pdn, DIRECT64_PROPNAME) { - direct64 = of_get_property(pdn, DIRECT64_PROPNAME, NULL); + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); if (!direct64) continue; - /* - * We need to ensure the IOMMU table is active when we - * return from the IOMMU setup so that the common code - * can clear the table or find the holes. To that end, - * first, remove any existing DDW configuration. - */ - remove_ddw(pdn); + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window || len < sizeof(struct dynamic_dma_window_prop)) { + kfree(window); + remove_ddw(pdn); + continue; + } - /* - * Second, if we are running on a new enough level of - * firmware where the restore API is present, use it to - * restore the 32-bit window, which was removed in - * create_ddw. - * If the API is not present, then create_ddw couldn't - * have removed the 32-bit window in the first place, so - * removing the DDW configuration should be sufficient. - */ - ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", - NULL); - if (ddw_extensions && ddw_extensions[0] > 0) - __restore_default_window(of_node_to_eeh_dev(pdn), - ddw_extensions[1]); + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); } return 0; @@ -921,12 +883,6 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, return ret; } -static void restore_default_window(struct pci_dev *dev, - u32 ddw_restore_token) -{ - __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token); -} - struct failed_ddw_pdn { struct device_node *pdn; struct list_head list; @@ -954,13 +910,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) u64 dma_addr, max_addr; struct device_node *dn; const u32 *uninitialized_var(ddw_avail); - const u32 *uninitialized_var(ddw_extensions); - u32 ddw_restore_token = 0; struct direct_window *window; struct property *win64; struct dynamic_dma_window_prop *ddwprop; - const void *dma_window = NULL; - unsigned long liobn, offset, size; struct failed_ddw_pdn *fpdn; mutex_lock(&direct_window_init_mutex); @@ -991,42 +943,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) */ ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); if (!ddw_avail || len < 3 * sizeof(u32)) - goto out_unlock; - - /* - * the extensions property is only required to exist in certain - * levels of firmware and later - * the ibm,ddw-extensions property is a list with the first - * element containing the number of extensions and each - * subsequent entry is a value corresponding to that extension - */ - ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", &len); - if (ddw_extensions) { - /* - * each new defined extension length should be added to - * the top of the switch so the "earlier" entries also - * get picked up - */ - switch (ddw_extensions[0]) { - /* ibm,reset-pe-dma-windows */ - case 1: - ddw_restore_token = ddw_extensions[1]; - break; - } - } - - /* - * Only remove the existing DMA window if we can restore back to - * the default state. Removing the existing window maximizes the - * resources available to firmware for dynamic window creation. - */ - if (ddw_restore_token) { - dma_window = of_get_property(pdn, "ibm,dma-window", NULL); - of_parse_dma_window(pdn, dma_window, &liobn, &offset, &size); - __remove_ddw(pdn, ddw_avail, liobn); - } + goto out_failed; - /* + /* * Query if there is a second window of size to map the * whole partition. Query returns number of windows, largest * block assigned to PE (partition endpoint), and two bitmasks @@ -1035,7 +954,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dn = pci_device_to_OF_node(dev); ret = query_ddw(dev, ddw_avail, &query); if (ret != 0) - goto out_restore_window; + goto out_failed; if (query.windows_available == 0) { /* @@ -1044,7 +963,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * trading in for a larger page size. */ dev_dbg(&dev->dev, "no free dynamic windows"); - goto out_restore_window; + goto out_failed; } if (be32_to_cpu(query.page_size) & 4) { page_shift = 24; /* 16MB */ @@ -1055,7 +974,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) } else { dev_dbg(&dev->dev, "no supported direct page size in mask %x", query.page_size); - goto out_restore_window; + goto out_failed; } /* verify the window * number of ptes will map the partition */ /* check largest block * page size > max memory hotplug addr */ @@ -1064,14 +983,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u " "%llu-sized pages\n", max_addr, query.largest_available_block, 1ULL << page_shift); - goto out_restore_window; + goto out_failed; } len = order_base_2(max_addr); win64 = kzalloc(sizeof(struct property), GFP_KERNEL); if (!win64) { dev_info(&dev->dev, "couldn't allocate property for 64bit dma window\n"); - goto out_restore_window; + goto out_failed; } win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); @@ -1133,9 +1052,7 @@ out_free_prop: kfree(win64->value); kfree(win64); -out_restore_window: - if (ddw_restore_token) - restore_default_window(dev, ddw_restore_token); +out_failed: fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); if (!fpdn) @@ -1193,7 +1110,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pr_debug(" found DMA window, table: %p\n", pci->iommu_table); } - set_iommu_table_base(&dev->dev, pci->iommu_table); + set_iommu_table_base_and_group(&dev->dev, pci->iommu_table); } static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 4fca3def9db9..b02af9ef3ff6 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -92,7 +92,7 @@ void vpa_init(int cpu) * PAPR says this feature is SLB-Buffer but firmware never * reports that. All SPLPAR support SLB shadow buffer. */ - addr = __pa(&slb_shadow[cpu]); + addr = __pa(paca[cpu].slb_shadow_ptr); if (firmware_has_feature(FW_FEATURE_SPLPAR)) { ret = register_slb_shadow(hwcpu, addr); if (ret) @@ -153,7 +153,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, /* Make pHyp happy */ if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU)) - hpte_r &= ~_PAGE_COHERENT; + hpte_r &= ~HPTE_R_M; + if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N)) flags |= H_COALESCE_CAND; diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 94134a5aecaa..002d5b4112f2 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -17,7 +17,6 @@ #include <asm/reg.h> #include <asm/machdep.h> #include <asm/firmware.h> -#include <asm/runlatch.h> #include <asm/plpar_wrappers.h> struct cpuidle_driver pseries_idle_driver = { @@ -62,7 +61,6 @@ static int snooze_loop(struct cpuidle_device *dev, set_thread_flag(TIF_POLLING_NRFLAG); while ((!need_resched()) && cpu_online(cpu)) { - ppc64_runlatch_off(); HMT_low(); HMT_very_low(); } @@ -102,7 +100,6 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, idle_loop_prolog(&in_purr); get_lppaca()->donate_dedicated_cpu = 1; - ppc64_runlatch_off(); HMT_medium(); check_and_cede_processor(); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 6f76ae417f47..8e639d7cbda7 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -72,7 +72,7 @@ int CMO_PrPSP = -1; int CMO_SecPSP = -1; -unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT); +unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K); EXPORT_SYMBOL(CMO_PageSize); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -569,7 +569,7 @@ void pSeries_cmo_feature_init(void) { char *ptr, *key, *value, *end; int call_status; - int page_order = IOMMU_PAGE_SHIFT; + int page_order = IOMMU_PAGE_SHIFT_4K; pr_debug(" -> fw_cmo_feature_init()\n"); spin_lock(&rtas_data_buf_lock); diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c index 62cb527493e7..9a15e5b39bb8 100644 --- a/arch/powerpc/platforms/wsp/wsp_pci.c +++ b/arch/powerpc/platforms/wsp/wsp_pci.c @@ -260,7 +260,7 @@ static int tce_build_wsp(struct iommu_table *tbl, long index, long npages, *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; dma_debug("[DMA] TCE %p set to 0x%016llx (dma addr: 0x%lx)\n", - tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT); + tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT_4K); uaddr += TCE_PAGE_SIZE; index++; @@ -381,8 +381,9 @@ static struct wsp_dma_table *wsp_pci_create_dma32_table(struct wsp_phb *phb, /* Init bits and pieces */ tbl->table.it_blocksize = 16; - tbl->table.it_offset = addr >> IOMMU_PAGE_SHIFT; - tbl->table.it_size = size >> IOMMU_PAGE_SHIFT; + tbl->table.it_page_shift = IOMMU_PAGE_SHIFT_4K; + tbl->table.it_offset = addr >> tbl->table.it_page_shift; + tbl->table.it_size = size >> tbl->table.it_page_shift; /* * It's already blank but we clear it anyway. @@ -449,8 +450,8 @@ static void wsp_pci_dma_dev_setup(struct pci_dev *pdev) if (table) { pr_info("%s: Setup iommu: 32-bit DMA region 0x%08lx..0x%08lx\n", pci_name(pdev), - table->table.it_offset << IOMMU_PAGE_SHIFT, - (table->table.it_offset << IOMMU_PAGE_SHIFT) + table->table.it_offset << IOMMU_PAGE_SHIFT_4K, + (table->table.it_offset << IOMMU_PAGE_SHIFT_4K) + phb->dma32_region_size - 1); archdata->dma_data.iommu_table_base = &table->table; return; diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 13ec968be4c7..7baa70d6dc01 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -19,7 +19,7 @@ config PPC_MSI_BITMAP default y if MPIC default y if FSL_PCI default y if PPC4xx_MSI - default y if POWERNV_MSI + default y if PPC_POWERNV source "arch/powerpc/sysdev/xics/Kconfig" diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 10386b676d87..a11bd1d433ad 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -27,7 +27,6 @@ */ #include <linux/stddef.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> #include <linux/irq.h> diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c index d7fc72239144..fbc885b31946 100644 --- a/arch/powerpc/sysdev/fsl_ifc.c +++ b/arch/powerpc/sysdev/fsl_ifc.c @@ -19,7 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/compiler.h> diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 6bc5a546d49f..d631022ffb4b 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c @@ -214,10 +214,14 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) struct fsl_lbc_ctrl *ctrl = data; struct fsl_lbc_regs __iomem *lbc = ctrl->regs; u32 status; + unsigned long flags; + spin_lock_irqsave(&fsl_lbc_lock, flags); status = in_be32(&lbc->ltesr); - if (!status) + if (!status) { + spin_unlock_irqrestore(&fsl_lbc_lock, flags); return IRQ_NONE; + } out_be32(&lbc->ltesr, LTESR_CLEAR); out_be32(&lbc->lteatr, 0); @@ -260,6 +264,7 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) if (status & ~LTESR_MASK) dev_err(ctrl->dev, "Unknown error: " "LTESR 0x%08X\n", status); + spin_unlock_irqrestore(&fsl_lbc_lock, flags); return IRQ_HANDLED; } @@ -298,8 +303,8 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev) goto err; } - fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); - if (fsl_lbc_ctrl_dev->irq == NO_IRQ) { + fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0); + if (!fsl_lbc_ctrl_dev->irq[0]) { dev_err(&dev->dev, "failed to get irq resource\n"); ret = -ENODEV; goto err; @@ -311,20 +316,34 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev) if (ret < 0) goto err; - ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, + ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0, "fsl-lbc", fsl_lbc_ctrl_dev); if (ret != 0) { dev_err(&dev->dev, "failed to install irq (%d)\n", - fsl_lbc_ctrl_dev->irq); - ret = fsl_lbc_ctrl_dev->irq; + fsl_lbc_ctrl_dev->irq[0]); + ret = fsl_lbc_ctrl_dev->irq[0]; goto err; } + fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1); + if (fsl_lbc_ctrl_dev->irq[1]) { + ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq, + IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev); + if (ret) { + dev_err(&dev->dev, "failed to install irq (%d)\n", + fsl_lbc_ctrl_dev->irq[1]); + ret = fsl_lbc_ctrl_dev->irq[1]; + goto err1; + } + } + /* Enable interrupts for any detected events */ out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE); return 0; +err1: + free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev); err: iounmap(fsl_lbc_ctrl_dev->regs); kfree(fsl_lbc_ctrl_dev); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 4dfd61df8aba..a625dcf26b2b 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -122,7 +122,7 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask) * address width of the SoC such that we can address any internal * SoC address from across PCI if needed */ - if ((dev->bus == &pci_bus_type) && + if ((dev_is_pci(dev)) && dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) { set_dma_ops(dev, &dma_direct_ops); set_dma_offset(dev, pci64_dma_offset); @@ -454,7 +454,7 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus) } } -int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) +int fsl_add_bridge(struct platform_device *pdev, int is_primary) { int len; struct pci_controller *hose; @@ -1035,6 +1035,7 @@ static const struct of_device_id pci_ids[] = { { .compatible = "fsl,mpc8548-pcie", }, { .compatible = "fsl,mpc8610-pci", }, { .compatible = "fsl,mpc8641-pcie", }, + { .compatible = "fsl,qoriq-pcie", }, { .compatible = "fsl,qoriq-pcie-v2.1", }, { .compatible = "fsl,qoriq-pcie-v2.2", }, { .compatible = "fsl,qoriq-pcie-v2.3", }, diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h index 6149916da3f4..908dbd9826b6 100644 --- a/arch/powerpc/sysdev/ge/ge_pic.h +++ b/arch/powerpc/sysdev/ge/ge_pic.h @@ -1,7 +1,6 @@ #ifndef __GEF_PIC_H__ #define __GEF_PIC_H__ -#include <linux/init.h> void gef_pic_cascade(unsigned int, struct irq_desc *); unsigned int gef_pic_get_irq(void); diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 997df6a7ab5d..45598da0b321 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -8,7 +8,6 @@ */ #undef DEBUG -#include <linux/init.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/kernel.h> diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index c6c8b526a4f6..1f6c570d66d4 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -152,10 +152,8 @@ static struct pci_ops indirect_pci_ops = .write = indirect_write_config, }; -void __init -setup_indirect_pci(struct pci_controller* hose, - resource_size_t cfg_addr, - resource_size_t cfg_data, u32 flags) +void setup_indirect_pci(struct pci_controller *hose, resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags) { resource_size_t base = cfg_addr & PAGE_MASK; void __iomem *mbase; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index b724622c3a0b..c4828c0be5bd 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -1,6 +1,5 @@ #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> #include <linux/irq.h> diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c index 22d7d57eead9..9d9b06217f8b 100644 --- a/arch/powerpc/sysdev/mpic_timer.c +++ b/arch/powerpc/sysdev/mpic_timer.c @@ -41,6 +41,7 @@ #define MPIC_TIMER_TCR_ROVR_OFFSET 24 #define TIMER_STOP 0x80000000 +#define GTCCR_TOG 0x80000000 #define TIMERS_PER_GROUP 4 #define MAX_TICKS (~0U >> 1) #define MAX_TICKS_CASCADE (~0U) @@ -96,8 +97,11 @@ static void convert_ticks_to_time(struct timer_group_priv *priv, time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq); tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq; - time->tv_usec = (__kernel_suseconds_t) - div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq); + time->tv_usec = 0; + + if (tmp_sec <= ticks) + time->tv_usec = (__kernel_suseconds_t) + div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq); return; } @@ -327,11 +331,13 @@ void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time) casc_priv = priv->timer[handle->num].cascade_handle; if (casc_priv) { tmp_ticks = in_be32(&priv->regs[handle->num].gtccr); + tmp_ticks &= ~GTCCR_TOG; ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE; tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr); ticks += tmp_ticks; } else { ticks = in_be32(&priv->regs[handle->num].gtccr); + ticks &= ~GTCCR_TOG; } convert_ticks_to_time(priv, ticks, time); diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index a88807b3dd57..d09994164daf 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -16,7 +16,6 @@ #include <linux/stddef.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/ioport.h> diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 134b07d29435..621575b7e84a 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -14,7 +14,6 @@ * option) any later version. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/stddef.h> #include <linux/spinlock.h> diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index cceb2e366738..65aaf15032ae 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -13,7 +13,6 @@ * option) any later version. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/stddef.h> diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 1c062f48f1ac..befaf1123f7f 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -13,7 +13,6 @@ * option) any later version. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/stddef.h> diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c index ce5a7b489e4b..9998c0de12d0 100644 --- a/arch/powerpc/sysdev/udbg_memcons.c +++ b/arch/powerpc/sysdev/udbg_memcons.c @@ -18,7 +18,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/init.h> #include <linux/kernel.h> #include <asm/barrier.h> #include <asm/page.h> diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index df0fc5821469..c1917cf67c3d 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -12,7 +12,6 @@ #include <linux/irq.h> #include <linux/smp.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/cpu.h> #include <linux/of.h> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index af9d3469fb99..a90731b3d44a 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2051,6 +2051,10 @@ static void dump_one_paca(int cpu) DUMP(p, stab_addr, "lx"); #endif DUMP(p, emergency_sp, "p"); +#ifdef CONFIG_PPC_BOOK3S_64 + DUMP(p, mc_emergency_sp, "p"); + DUMP(p, in_mce, "x"); +#endif DUMP(p, data_offset, "lx"); DUMP(p, hw_cpu_id, "x"); DUMP(p, cpu_start, "x"); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4f858f77d870..65a07750f4f9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -596,7 +596,7 @@ config CRASH_DUMP config ZFCPDUMP def_bool n prompt "zfcpdump support" - depends on SMP + depends on 64BIT && SMP help Select this option if you want to build an zfcpdump enabled kernel. Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index 2e671d5004ca..06f8d95a16cd 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index 79f2ac55253f..b34b5ab90a31 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -13,6 +13,7 @@ #include <linux/debugfs.h> #include <linux/workqueue.h> #include <linux/kref.h> +#include <asm/hypfs.h> #define REG_FILE_MODE 0440 #define UPDATE_FILE_MODE 0220 @@ -36,6 +37,10 @@ extern int hypfs_vm_init(void); extern void hypfs_vm_exit(void); extern int hypfs_vm_create_files(struct dentry *root); +/* Set Partition-Resource Parameter */ +int hypfs_sprp_init(void); +void hypfs_sprp_exit(void); + /* debugfs interface */ struct hypfs_dbfs_file; @@ -52,6 +57,8 @@ struct hypfs_dbfs_file { int (*data_create)(void **data, void **data_free_ptr, size_t *size); void (*data_free)(const void *buf_free_ptr); + long (*unlocked_ioctl) (struct file *, unsigned int, + unsigned long); /* Private data for hypfs_dbfs.c */ struct hypfs_dbfs_data *data; diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index 17ab8b7b53cc..2badf2bf9cd7 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf, return rc; } +static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct hypfs_dbfs_file *df; + long rc; + + df = file->f_path.dentry->d_inode->i_private; + mutex_lock(&df->lock); + if (df->unlocked_ioctl) + rc = df->unlocked_ioctl(file, cmd, arg); + else + rc = -ENOTTY; + mutex_unlock(&df->lock); + return rc; +} + static const struct file_operations dbfs_ops = { .read = dbfs_read, .llseek = no_llseek, + .unlocked_ioctl = dbfs_ioctl, }; int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c new file mode 100644 index 000000000000..f043c3c7e73c --- /dev/null +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -0,0 +1,141 @@ +/* + * Hypervisor filesystem for Linux on s390. + * Set Partition-Resource Parameter interface. + * + * Copyright IBM Corp. 2013 + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#include <linux/compat.h> +#include <linux/errno.h> +#include <linux/gfp.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <asm/compat.h> +#include <asm/sclp.h> +#include "hypfs.h" + +#define DIAG304_SET_WEIGHTS 0 +#define DIAG304_QUERY_PRP 1 +#define DIAG304_SET_CAPPING 2 + +#define DIAG304_CMD_MAX 2 + +static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd) +{ + register unsigned long _data asm("2") = (unsigned long) data; + register unsigned long _rc asm("3"); + register unsigned long _cmd asm("4") = cmd; + + asm volatile("diag %1,%2,0x304\n" + : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory"); + + return _rc; +} + +static void hypfs_sprp_free(const void *data) +{ + free_page((unsigned long) data); +} + +static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size) +{ + unsigned long rc; + void *data; + + data = (void *) get_zeroed_page(GFP_KERNEL); + if (!data) + return -ENOMEM; + rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP); + if (rc != 1) { + *data_ptr = *free_ptr = NULL; + *size = 0; + free_page((unsigned long) data); + return -EIO; + } + *data_ptr = *free_ptr = data; + *size = PAGE_SIZE; + return 0; +} + +static int __hypfs_sprp_ioctl(void __user *user_area) +{ + struct hypfs_diag304 diag304; + unsigned long cmd; + void __user *udata; + void *data; + int rc; + + if (copy_from_user(&diag304, user_area, sizeof(diag304))) + return -EFAULT; + if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX) + return -EINVAL; + + data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + udata = (void __user *)(unsigned long) diag304.data; + if (diag304.args[1] == DIAG304_SET_WEIGHTS || + diag304.args[1] == DIAG304_SET_CAPPING) + if (copy_from_user(data, udata, PAGE_SIZE)) { + rc = -EFAULT; + goto out; + } + + cmd = *(unsigned long *) &diag304.args[0]; + diag304.rc = hypfs_sprp_diag304(data, cmd); + + if (diag304.args[1] == DIAG304_QUERY_PRP) + if (copy_to_user(udata, data, PAGE_SIZE)) { + rc = -EFAULT; + goto out; + } + + rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0; +out: + free_page((unsigned long) data); + return rc; +} + +static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (is_compat_task()) + argp = compat_ptr(arg); + else + argp = (void __user *) arg; + switch (cmd) { + case HYPFS_DIAG304: + return __hypfs_sprp_ioctl(argp); + default: /* unknown ioctl number */ + return -ENOTTY; + } + return 0; +} + +static struct hypfs_dbfs_file hypfs_sprp_file = { + .name = "diag_304", + .data_create = hypfs_sprp_create, + .data_free = hypfs_sprp_free, + .unlocked_ioctl = hypfs_sprp_ioctl, +}; + +int hypfs_sprp_init(void) +{ + if (!sclp_has_sprp()) + return 0; + return hypfs_dbfs_create_file(&hypfs_sprp_file); +} + +void hypfs_sprp_exit(void) +{ + if (!sclp_has_sprp()) + return; + hypfs_dbfs_remove_file(&hypfs_sprp_file); +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ddfe09b45134..c952b981e4f2 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -478,10 +478,14 @@ static int __init hypfs_init(void) rc = -ENODATA; goto fail_hypfs_diag_exit; } + if (hypfs_sprp_init()) { + rc = -ENODATA; + goto fail_hypfs_vm_exit; + } s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); if (!s390_kobj) { rc = -ENOMEM; - goto fail_hypfs_vm_exit; + goto fail_hypfs_sprp_exit; } rc = register_filesystem(&hypfs_type); if (rc) @@ -490,6 +494,8 @@ static int __init hypfs_init(void) fail_filesystem: kobject_put(s390_kobj); +fail_hypfs_sprp_exit: + hypfs_sprp_exit(); fail_hypfs_vm_exit: hypfs_vm_exit(); fail_hypfs_diag_exit: @@ -502,11 +508,12 @@ fail_dbfs_exit: static void __exit hypfs_exit(void) { - hypfs_diag_exit(); - hypfs_vm_exit(); - hypfs_dbfs_exit(); unregister_filesystem(&hypfs_type); kobject_put(s390_kobj); + hypfs_sprp_exit(); + hypfs_vm_exit(); + hypfs_diag_exit(); + hypfs_dbfs_exit(); } module_init(hypfs_init) diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 0f636cbdf342..4236408070e5 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -185,11 +185,12 @@ static inline unsigned long long __cmpxchg64(void *ptr, { register_pair rp_old = {.pair = old}; register_pair rp_new = {.pair = new}; + unsigned long long *ullptr = ptr; asm volatile( " cds %0,%2,%1" - : "+&d" (rp_old), "=Q" (ptr) - : "d" (rp_new), "Q" (ptr) + : "+d" (rp_old), "+Q" (*ullptr) + : "d" (rp_new) : "memory", "cc"); return rp_old.pair; } diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 220e171413f8..abaca2275c7a 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -54,6 +54,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info); void sclp_get_ipl_info(struct sclp_ipl_info *info); bool __init sclp_has_linemode(void); bool __init sclp_has_vt220(void); +bool sclp_has_sprp(void); int sclp_pci_configure(u32 fid); int sclp_pci_deconfigure(u32 fid); int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h new file mode 100644 index 000000000000..37998b449531 --- /dev/null +++ b/arch/s390/include/uapi/asm/hypfs.h @@ -0,0 +1,25 @@ +/* + * IOCTL interface for hypfs + * + * Copyright IBM Corp. 2013 + * + * Author: Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#ifndef _ASM_HYPFS_CTL_H +#define _ASM_HYPFS_CTL_H + +#include <linux/types.h> + +struct hypfs_diag304 { + __u32 args[2]; + __u64 data; + __u64 rc; +} __attribute__((packed)); + +#define HYPFS_IOCTL_MAGIC 0x10 + +#define HYPFS_DIAG304 \ + _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304) + +#endif diff --git a/arch/s390/include/uapi/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h index a61d538756f2..471eb09184d4 100644 --- a/arch/s390/include/uapi/asm/statfs.h +++ b/arch/s390/include/uapi/asm/statfs.h @@ -35,11 +35,11 @@ struct statfs { struct statfs64 { unsigned int f_type; unsigned int f_bsize; - unsigned long f_blocks; - unsigned long f_bfree; - unsigned long f_bavail; - unsigned long f_files; - unsigned long f_ffree; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; __kernel_fsid_t f_fsid; unsigned int f_namelen; unsigned int f_frsize; diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 864f693c237f..5eb5c9ddb120 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h @@ -280,6 +280,8 @@ #define __NR_s390_runtime_instr 342 #define __NR_kcmp 343 #define __NR_finit_module 344 +#define __NR_sched_setattr 345 +#define __NR_sched_getattr 346 #define NR_syscalls 345 /* diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index e030d2bdec1b..db02052bd137 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -286,8 +286,8 @@ asmlinkage long sys32_getegid16(void) } #ifdef CONFIG_SYSVIPC -COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, - unsigned long, third, compat_uptr_t, ptr) +COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second, + compat_ulong_t, third, compat_uptr_t, ptr) { if (call >> 16) /* hack for backward compatibility */ return -EINVAL; diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 9cb1b975b353..59c8efce1b99 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1412,3 +1412,14 @@ ENTRY(sys_finit_module_wrapper) llgtr %r3,%r3 # const char __user * lgfr %r4,%r4 # int jg sys_finit_module + +ENTRY(sys_sched_setattr_wrapper) + lgfr %r2,%r2 # pid_t + llgtr %r3,%r3 # struct sched_attr __user * + jg sys_sched_setattr + +ENTRY(sys_sched_getattr_wrapper) + lgfr %r2,%r2 # pid_t + llgtr %r3,%r3 # const char __user * + llgfr %r3,%r3 # unsigned int + jg sys_sched_getattr diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 913410bd74a3..143992152ec9 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -353,3 +353,5 @@ SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper) SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper) SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper) +SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */ +SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper) diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h index 315dbe09983e..b1a22173d027 100644 --- a/arch/s390/lib/uaccess.h +++ b/arch/s390/lib/uaccess.h @@ -6,15 +6,6 @@ #ifndef __ARCH_S390_LIB_UACCESS_H #define __ARCH_S390_LIB_UACCESS_H -extern size_t copy_from_user_std(size_t, const void __user *, void *); -extern size_t copy_to_user_std(size_t, void __user *, const void *); -extern size_t strnlen_user_std(size_t, const char __user *); -extern size_t strncpy_from_user_std(size_t, const char __user *, char *); -extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32); -extern int futex_atomic_op_std(int, u32 __user *, int, int *); - -extern size_t copy_from_user_pt(size_t, const void __user *, void *); -extern size_t copy_to_user_pt(size_t, void __user *, const void *); extern int futex_atomic_op_pt(int, u32 __user *, int, int *); extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32); diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 0632dc50da78..61ebcc9ccb34 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -153,6 +153,8 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, unsigned long offset, done, size, kaddr; void *from, *to; + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -209,7 +211,7 @@ fault: return 0; } -size_t copy_from_user_pt(size_t n, const void __user *from, void *to) +static size_t copy_from_user_pt(size_t n, const void __user *from, void *to) { size_t rc; @@ -221,7 +223,7 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to) return rc; } -size_t copy_to_user_pt(size_t n, void __user *to, const void *from) +static size_t copy_to_user_pt(size_t n, void __user *to, const void *from) { if (segment_eq(get_fs(), KERNEL_DS)) return copy_in_kernel(n, to, (void __user *) from); @@ -262,6 +264,8 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) return 0; if (segment_eq(get_fs(), KERNEL_DS)) return strnlen_kernel(count, src); + if (!mm) + return 0; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -323,6 +327,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to, if (segment_eq(get_fs(), KERNEL_DS)) return copy_in_kernel(n, to, from); + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -411,6 +417,8 @@ int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old) if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_op_pt(op, uaddr, oparg, old); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1); @@ -448,6 +456,8 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr, if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1); diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h index 62ced589bcf7..b73274fb961a 100644 --- a/arch/sparc/include/uapi/asm/unistd.h +++ b/arch/sparc/include/uapi/asm/unistd.h @@ -408,8 +408,10 @@ #define __NR_kern_features 340 #define __NR_kcmp 341 #define __NR_finit_module 342 +#define __NR_sched_setattr 343 +#define __NR_sched_getattr 344 -#define NR_syscalls 343 +#define NR_syscalls 345 /* Bitmask values returned from kern_features system call. */ #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c index cb5d272d658a..de1c844dfabc 100644 --- a/arch/sparc/kernel/cpumap.c +++ b/arch/sparc/kernel/cpumap.c @@ -6,7 +6,6 @@ #include <linux/export.h> #include <linux/slab.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/cpumask.h> #include <linux/spinlock.h> #include <asm/cpudata.h> diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index e306fb08ee5e..acf8314cec48 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -7,7 +7,6 @@ #include <linux/export.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S index 4eb1a5a1d544..b7ddcdd1dea9 100644 --- a/arch/sparc/kernel/hvtramp.S +++ b/arch/sparc/kernel/hvtramp.S @@ -3,7 +3,6 @@ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> */ -#include <linux/init.h> #include <asm/thread_info.h> #include <asm/hypervisor.h> diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index de199bf0cb05..3241f56331c2 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -1,7 +1,6 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/of.h> -#include <linux/init.h> #include <linux/export.h> #include <linux/mod_devicetable.h> #include <linux/errno.h> diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 7de8d1f590b7..1555bbcae1ee 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -1005,6 +1005,5 @@ static int __init of_pci_slot_init(void) return 0; } - -module_init(of_pci_slot_init); +device_initcall(of_pci_slot_init); #endif diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c index a6895987fb70..944a06536ecc 100644 --- a/arch/sparc/kernel/pci_common.c +++ b/arch/sparc/kernel/pci_common.c @@ -5,7 +5,6 @@ #include <linux/string.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/device.h> #include <linux/of_device.h> diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index fdd819dfdacf..510baec1b69b 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -22,7 +22,6 @@ #include <linux/reboot.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/init.h> #include <linux/slab.h> #include <asm/auxio.h> diff --git a/arch/sparc/kernel/sparc_ksyms_32.c b/arch/sparc/kernel/sparc_ksyms_32.c index e521c54560f9..bf4ccb10a78c 100644 --- a/arch/sparc/kernel/sparc_ksyms_32.c +++ b/arch/sparc/kernel/sparc_ksyms_32.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <asm/pgtable.h> #include <asm/uaccess.h> diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c index 9f5e24ddcc70..a92d5d2c46a3 100644 --- a/arch/sparc/kernel/sparc_ksyms_64.c +++ b/arch/sparc/kernel/sparc_ksyms_64.c @@ -7,7 +7,6 @@ #include <linux/export.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/bitops.h> #include <asm/cpudata.h> diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 7b87171ecf1e..151ace8766cc 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -85,4 +85,4 @@ sys_call_table: /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev -/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module +/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 6d81597064b6..4bd4e2bb26cf 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -86,7 +86,7 @@ sys_call_table32: .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init /*330*/ .word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev -/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module +/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr #endif /* CONFIG_COMPAT */ @@ -164,4 +164,4 @@ sys_call_table: .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev -/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module +/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S index 76dcbd3c988a..3eed99fc6989 100644 --- a/arch/sparc/kernel/trampoline_32.S +++ b/arch/sparc/kernel/trampoline_32.S @@ -5,7 +5,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include <linux/init.h> #include <asm/head.h> #include <asm/psr.h> #include <asm/page.h> diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S index ad4bde3bb61e..737f8cbc7d56 100644 --- a/arch/sparc/kernel/trampoline_64.S +++ b/arch/sparc/kernel/trampoline_64.S @@ -4,7 +4,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/init.h> #include <asm/head.h> #include <asm/asi.h> diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 30963178d7e9..9bd9ce80bf77 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -4,7 +4,6 @@ * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net) */ -#include <linux/init.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/hugetlb.h> diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index ad3bf4b4324d..b12cb5e72812 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -4,7 +4,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/percpu.h> #include <linux/mm.h> #include <linux/swap.h> diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c index 04a4540509dd..e58b81726319 100644 --- a/arch/sparc/prom/p1275.c +++ b/arch/sparc/prom/p1275.c @@ -5,7 +5,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/smp.h> #include <linux/string.h> diff --git a/arch/unicore32/kernel/early_printk.c b/arch/unicore32/kernel/early_printk.c index 9be0d5d02a9a..f2f6323c8d64 100644 --- a/arch/unicore32/kernel/early_printk.c +++ b/arch/unicore32/kernel/early_printk.c @@ -35,17 +35,11 @@ static struct console early_ocd_console = { static int __init setup_early_printk(char *buf) { - int keep_early; - if (!buf || early_console) return 0; - if (strstr(buf, "keep")) - keep_early = 1; - early_console = &early_ocd_console; - - if (keep_early) + if (strstr(buf, "keep")) early_console->flags &= ~CON_BOOT; else early_console->flags |= CON_BOOT; diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 2f59cce3b38a..f97fbe3abb67 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -51,9 +51,9 @@ extern int devmem_is_allowed(unsigned long pagenr); extern unsigned long max_low_pfn_mapped; extern unsigned long max_pfn_mapped; -static inline phys_addr_t get_max_low_mapped(void) +static inline phys_addr_t get_max_mapped(void) { - return (phys_addr_t)max_low_pfn_mapped << PAGE_SHIFT; + return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT; } bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c9675594d7ca..06853e670354 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1119,7 +1119,7 @@ void __init setup_arch(char **cmdline_p) setup_real_mode(); - memblock_set_current_limit(get_max_low_mapped()); + memblock_set_current_limit(get_max_mapped()); dma_contiguous_reserve(0); /* diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cb1db2979d3d..16cab6635163 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -41,6 +41,7 @@ #include <linux/fs.h> #include <linux/blkdev.h> #include <linux/slab.h> +#include <linux/idr.h> #include "rbd_types.h" @@ -89,9 +90,9 @@ static int atomic_dec_return_safe(atomic_t *v) } #define RBD_DRV_NAME "rbd" -#define RBD_DRV_NAME_LONG "rbd (rados block device)" -#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ +#define RBD_MINORS_PER_MAJOR 256 +#define RBD_SINGLE_MAJOR_PART_SHIFT 4 #define RBD_SNAP_DEV_NAME_PREFIX "snap_" #define RBD_MAX_SNAP_NAME_LEN \ @@ -323,6 +324,7 @@ struct rbd_device { int dev_id; /* blkdev unique id */ int major; /* blkdev assigned major */ + int minor; struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ @@ -386,6 +388,17 @@ static struct kmem_cache *rbd_img_request_cache; static struct kmem_cache *rbd_obj_request_cache; static struct kmem_cache *rbd_segment_name_cache; +static int rbd_major; +static DEFINE_IDA(rbd_dev_id_ida); + +/* + * Default to false for now, as single-major requires >= 0.75 version of + * userspace rbd utility. + */ +static bool single_major = false; +module_param(single_major, bool, S_IRUGO); +MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: false)"); + static int rbd_img_request_submit(struct rbd_img_request *img_request); static void rbd_dev_device_release(struct device *dev); @@ -394,18 +407,52 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count); static ssize_t rbd_remove(struct bus_type *bus, const char *buf, size_t count); +static ssize_t rbd_add_single_major(struct bus_type *bus, const char *buf, + size_t count); +static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf, + size_t count); static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); static void rbd_spec_put(struct rbd_spec *spec); +static int rbd_dev_id_to_minor(int dev_id) +{ + return dev_id << RBD_SINGLE_MAJOR_PART_SHIFT; +} + +static int minor_to_rbd_dev_id(int minor) +{ + return minor >> RBD_SINGLE_MAJOR_PART_SHIFT; +} + static BUS_ATTR(add, S_IWUSR, NULL, rbd_add); static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove); +static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major); +static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major); static struct attribute *rbd_bus_attrs[] = { &bus_attr_add.attr, &bus_attr_remove.attr, + &bus_attr_add_single_major.attr, + &bus_attr_remove_single_major.attr, NULL, }; -ATTRIBUTE_GROUPS(rbd_bus); + +static umode_t rbd_bus_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + if (!single_major && + (attr == &bus_attr_add_single_major.attr || + attr == &bus_attr_remove_single_major.attr)) + return 0; + + return attr->mode; +} + +static const struct attribute_group rbd_bus_group = { + .attrs = rbd_bus_attrs, + .is_visible = rbd_bus_is_visible, +}; +__ATTRIBUTE_GROUPS(rbd_bus); static struct bus_type rbd_bus_type = { .name = "rbd", @@ -1041,9 +1088,9 @@ static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset) name_format = "%s.%012llx"; if (rbd_dev->image_format == 2) name_format = "%s.%016llx"; - ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, name_format, + ret = snprintf(name, CEPH_MAX_OID_NAME_LEN + 1, name_format, rbd_dev->header.object_prefix, segment); - if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) { + if (ret < 0 || ret > CEPH_MAX_OID_NAME_LEN) { pr_err("error formatting segment name for #%llu (%d)\n", segment, ret); kfree(name); @@ -1761,11 +1808,8 @@ static struct ceph_osd_request *rbd_osd_req_create( osd_req->r_callback = rbd_osd_req_callback; osd_req->r_priv = obj_request; - osd_req->r_oid_len = strlen(obj_request->object_name); - rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid)); - memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len); - - osd_req->r_file_layout = rbd_dev->layout; /* struct */ + osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout); + ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name); return osd_req; } @@ -1802,11 +1846,8 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request) osd_req->r_callback = rbd_osd_req_callback; osd_req->r_priv = obj_request; - osd_req->r_oid_len = strlen(obj_request->object_name); - rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid)); - memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len); - - osd_req->r_file_layout = rbd_dev->layout; /* struct */ + osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout); + ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name); return osd_req; } @@ -2866,7 +2907,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) * Request sync osd watch/unwatch. The value of "start" determines * whether a watch request is being initiated or torn down. */ -static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) +static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; struct rbd_obj_request *obj_request; @@ -2941,6 +2982,22 @@ out_cancel: return ret; } +static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev) +{ + return __rbd_dev_header_watch_sync(rbd_dev, true); +} + +static void rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev) +{ + int ret; + + ret = __rbd_dev_header_watch_sync(rbd_dev, false); + if (ret) { + rbd_warn(rbd_dev, "unable to tear down watch request: %d\n", + ret); + } +} + /* * Synchronous osd object method call. Returns the number of bytes * returned in the outbound buffer, or a negative error code. @@ -3388,14 +3445,18 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) u64 segment_size; /* create gendisk info */ - disk = alloc_disk(RBD_MINORS_PER_MAJOR); + disk = alloc_disk(single_major ? + (1 << RBD_SINGLE_MAJOR_PART_SHIFT) : + RBD_MINORS_PER_MAJOR); if (!disk) return -ENOMEM; snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d", rbd_dev->dev_id); disk->major = rbd_dev->major; - disk->first_minor = 0; + disk->first_minor = rbd_dev->minor; + if (single_major) + disk->flags |= GENHD_FL_EXT_DEVT; disk->fops = &rbd_bd_ops; disk->private_data = rbd_dev; @@ -3467,7 +3528,14 @@ static ssize_t rbd_major_show(struct device *dev, return sprintf(buf, "%d\n", rbd_dev->major); return sprintf(buf, "(none)\n"); +} +static ssize_t rbd_minor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + + return sprintf(buf, "%d\n", rbd_dev->minor); } static ssize_t rbd_client_id_show(struct device *dev, @@ -3589,6 +3657,7 @@ static ssize_t rbd_image_refresh(struct device *dev, static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL); static DEVICE_ATTR(features, S_IRUGO, rbd_features_show, NULL); static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL); +static DEVICE_ATTR(minor, S_IRUGO, rbd_minor_show, NULL); static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL); static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL); @@ -3602,6 +3671,7 @@ static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, &dev_attr_features.attr, &dev_attr_major.attr, + &dev_attr_minor.attr, &dev_attr_client_id.attr, &dev_attr_pool.attr, &dev_attr_pool_id.attr, @@ -4372,21 +4442,29 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev) device_unregister(&rbd_dev->dev); } -static atomic64_t rbd_dev_id_max = ATOMIC64_INIT(0); - /* * Get a unique rbd identifier for the given new rbd_dev, and add - * the rbd_dev to the global list. The minimum rbd id is 1. + * the rbd_dev to the global list. */ -static void rbd_dev_id_get(struct rbd_device *rbd_dev) +static int rbd_dev_id_get(struct rbd_device *rbd_dev) { - rbd_dev->dev_id = atomic64_inc_return(&rbd_dev_id_max); + int new_dev_id; + + new_dev_id = ida_simple_get(&rbd_dev_id_ida, + 0, minor_to_rbd_dev_id(1 << MINORBITS), + GFP_KERNEL); + if (new_dev_id < 0) + return new_dev_id; + + rbd_dev->dev_id = new_dev_id; spin_lock(&rbd_dev_list_lock); list_add_tail(&rbd_dev->node, &rbd_dev_list); spin_unlock(&rbd_dev_list_lock); - dout("rbd_dev %p given dev id %llu\n", rbd_dev, - (unsigned long long) rbd_dev->dev_id); + + dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id); + + return 0; } /* @@ -4395,49 +4473,13 @@ static void rbd_dev_id_get(struct rbd_device *rbd_dev) */ static void rbd_dev_id_put(struct rbd_device *rbd_dev) { - struct list_head *tmp; - int rbd_id = rbd_dev->dev_id; - int max_id; - - rbd_assert(rbd_id > 0); - - dout("rbd_dev %p released dev id %llu\n", rbd_dev, - (unsigned long long) rbd_dev->dev_id); spin_lock(&rbd_dev_list_lock); list_del_init(&rbd_dev->node); - - /* - * If the id being "put" is not the current maximum, there - * is nothing special we need to do. - */ - if (rbd_id != atomic64_read(&rbd_dev_id_max)) { - spin_unlock(&rbd_dev_list_lock); - return; - } - - /* - * We need to update the current maximum id. Search the - * list to find out what it is. We're more likely to find - * the maximum at the end, so search the list backward. - */ - max_id = 0; - list_for_each_prev(tmp, &rbd_dev_list) { - struct rbd_device *rbd_dev; - - rbd_dev = list_entry(tmp, struct rbd_device, node); - if (rbd_dev->dev_id > max_id) - max_id = rbd_dev->dev_id; - } spin_unlock(&rbd_dev_list_lock); - /* - * The max id could have been updated by rbd_dev_id_get(), in - * which case it now accurately reflects the new maximum. - * Be careful not to overwrite the maximum value in that - * case. - */ - atomic64_cmpxchg(&rbd_dev_id_max, rbd_id, max_id); - dout(" max dev id has been reset\n"); + ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + + dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id); } /* @@ -4860,20 +4902,29 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) { int ret; - /* generate unique id: find highest unique id, add one */ - rbd_dev_id_get(rbd_dev); + /* Get an id and fill in device name. */ + + ret = rbd_dev_id_get(rbd_dev); + if (ret) + return ret; - /* Fill in the device name, now that we have its id. */ BUILD_BUG_ON(DEV_NAME_LEN < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); - /* Get our block major device number. */ + /* Record our major and minor device numbers. */ - ret = register_blkdev(0, rbd_dev->name); - if (ret < 0) - goto err_out_id; - rbd_dev->major = ret; + if (!single_major) { + ret = register_blkdev(0, rbd_dev->name); + if (ret < 0) + goto err_out_id; + + rbd_dev->major = ret; + rbd_dev->minor = 0; + } else { + rbd_dev->major = rbd_major; + rbd_dev->minor = rbd_dev_id_to_minor(rbd_dev->dev_id); + } /* Set up the blkdev mapping. */ @@ -4905,7 +4956,8 @@ err_out_mapping: err_out_disk: rbd_free_disk(rbd_dev); err_out_blkdev: - unregister_blkdev(rbd_dev->major, rbd_dev->name); + if (!single_major) + unregister_blkdev(rbd_dev->major, rbd_dev->name); err_out_id: rbd_dev_id_put(rbd_dev); rbd_dev_mapping_clear(rbd_dev); @@ -4961,7 +5013,6 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev) static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) { int ret; - int tmp; /* * Get the id from the image id object. Unless there's an @@ -4980,7 +5031,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) goto err_out_format; if (mapping) { - ret = rbd_dev_header_watch_sync(rbd_dev, true); + ret = rbd_dev_header_watch_sync(rbd_dev); if (ret) goto out_header_name; } @@ -5007,12 +5058,8 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) err_out_probe: rbd_dev_unprobe(rbd_dev); err_out_watch: - if (mapping) { - tmp = rbd_dev_header_watch_sync(rbd_dev, false); - if (tmp) - rbd_warn(rbd_dev, "unable to tear down " - "watch request (%d)\n", tmp); - } + if (mapping) + rbd_dev_header_unwatch_sync(rbd_dev); out_header_name: kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; @@ -5026,9 +5073,9 @@ err_out_format: return ret; } -static ssize_t rbd_add(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_add(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; struct ceph_options *ceph_opts = NULL; @@ -5090,6 +5137,12 @@ static ssize_t rbd_add(struct bus_type *bus, rc = rbd_dev_device_setup(rbd_dev); if (rc) { + /* + * rbd_dev_header_unwatch_sync() can't be moved into + * rbd_dev_image_release() without refactoring, see + * commit 1f3ef78861ac. + */ + rbd_dev_header_unwatch_sync(rbd_dev); rbd_dev_image_release(rbd_dev); goto err_out_module; } @@ -5110,6 +5163,23 @@ err_out_module: return (ssize_t)rc; } +static ssize_t rbd_add(struct bus_type *bus, + const char *buf, + size_t count) +{ + if (single_major) + return -EINVAL; + + return do_rbd_add(bus, buf, count); +} + +static ssize_t rbd_add_single_major(struct bus_type *bus, + const char *buf, + size_t count) +{ + return do_rbd_add(bus, buf, count); +} + static void rbd_dev_device_release(struct device *dev) { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); @@ -5117,8 +5187,8 @@ static void rbd_dev_device_release(struct device *dev) rbd_free_disk(rbd_dev); clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); rbd_dev_mapping_clear(rbd_dev); - unregister_blkdev(rbd_dev->major, rbd_dev->name); - rbd_dev->major = 0; + if (!single_major) + unregister_blkdev(rbd_dev->major, rbd_dev->name); rbd_dev_id_put(rbd_dev); rbd_dev_mapping_clear(rbd_dev); } @@ -5149,9 +5219,9 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) } } -static ssize_t rbd_remove(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; struct list_head *tmp; @@ -5191,16 +5261,14 @@ static ssize_t rbd_remove(struct bus_type *bus, if (ret < 0 || already) return ret; - ret = rbd_dev_header_watch_sync(rbd_dev, false); - if (ret) - rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret); - + rbd_dev_header_unwatch_sync(rbd_dev); /* * flush remaining watch callbacks - these must be complete * before the osd_client is shutdown */ dout("%s: flushing notifies", __func__); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); + /* * Don't free anything from rbd_dev->disk until after all * notifies are completely processed. Otherwise @@ -5214,6 +5282,23 @@ static ssize_t rbd_remove(struct bus_type *bus, return count; } +static ssize_t rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) +{ + if (single_major) + return -EINVAL; + + return do_rbd_remove(bus, buf, count); +} + +static ssize_t rbd_remove_single_major(struct bus_type *bus, + const char *buf, + size_t count) +{ + return do_rbd_remove(bus, buf, count); +} + /* * create control files in sysfs * /sys/bus/rbd/... @@ -5259,7 +5344,7 @@ static int rbd_slab_init(void) rbd_assert(!rbd_segment_name_cache); rbd_segment_name_cache = kmem_cache_create("rbd_segment_name", - MAX_OBJ_NAME_SIZE + 1, 1, 0, NULL); + CEPH_MAX_OID_NAME_LEN + 1, 1, 0, NULL); if (rbd_segment_name_cache) return 0; out_err: @@ -5295,24 +5380,45 @@ static int __init rbd_init(void) if (!libceph_compatible(NULL)) { rbd_warn(NULL, "libceph incompatibility (quitting)"); - return -EINVAL; } + rc = rbd_slab_init(); if (rc) return rc; + + if (single_major) { + rbd_major = register_blkdev(0, RBD_DRV_NAME); + if (rbd_major < 0) { + rc = rbd_major; + goto err_out_slab; + } + } + rc = rbd_sysfs_init(); if (rc) - rbd_slab_exit(); + goto err_out_blkdev; + + if (single_major) + pr_info("loaded (major %d)\n", rbd_major); else - pr_info("loaded " RBD_DRV_NAME_LONG "\n"); + pr_info("loaded\n"); + + return 0; +err_out_blkdev: + if (single_major) + unregister_blkdev(rbd_major, RBD_DRV_NAME); +err_out_slab: + rbd_slab_exit(); return rc; } static void __exit rbd_exit(void) { rbd_sysfs_cleanup(); + if (single_major) + unregister_blkdev(rbd_major, RBD_DRV_NAME); rbd_slab_exit(); } @@ -5322,9 +5428,8 @@ module_exit(rbd_exit); MODULE_AUTHOR("Alex Elder <elder@inktank.com>"); MODULE_AUTHOR("Sage Weil <sage@newdream.net>"); MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>"); -MODULE_DESCRIPTION("rados block device"); - /* following authorship retained from original osdblk.c */ MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>"); +MODULE_DESCRIPTION("RADOS Block Device (RBD) driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 0c16e9cdfb87..a367a9831717 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,45 +9,44 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o -# SoCs specific -obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o -obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o -obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o -obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ -obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o -obj-$(CONFIG_ARCH_MXS) += mxs/ -obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ -obj-$(CONFIG_PLAT_SPEAR) += spear/ -obj-$(CONFIG_ARCH_U300) += clk-u300.o -obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ -obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ -obj-$(CONFIG_PLAT_ORION) += mvebu/ +# hardware specific clock types +# please keep this section sorted lexicographically by file/directory path name +obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o +obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o +obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o +obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o +obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o +obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o +obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o +obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o +obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o +obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +obj-$(CONFIG_ARCH_U300) += clk-u300.o +obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o +obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o +obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ +obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ ifeq ($(CONFIG_COMMON_CLK), y) -obj-$(CONFIG_ARCH_MMP) += mmp/ +obj-$(CONFIG_ARCH_MMP) += mmp/ endif -obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o -obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ -obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o -obj-$(CONFIG_ARCH_SIRF) += sirf/ -obj-$(CONFIG_ARCH_ZYNQ) += zynq/ -obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ -obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o -obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ -obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_PLAT_ORION) += mvebu/ +obj-$(CONFIG_ARCH_MXS) += mxs/ +obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ +obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ - -obj-$(CONFIG_X86) += x86/ - -# Chip specific -obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o -obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o -obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o -obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o -obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o -obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o -obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o -obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o +obj-$(CONFIG_ARCH_SIRF) += sirf/ +obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ +obj-$(CONFIG_PLAT_SPEAR) += spear/ +obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/ +obj-$(CONFIG_ARCH_U8500) += ux500/ +obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ +obj-$(CONFIG_X86) += x86/ +obj-$(CONFIG_ARCH_ZYNQ) += zynq/ diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index c50e83744b0a..3b2a66f78755 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1111,11 +1111,11 @@ static const struct of_device_id si5351_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, si5351_dt_ids); -static int si5351_dt_parse(struct i2c_client *client) +static int si5351_dt_parse(struct i2c_client *client, + enum si5351_variant variant) { struct device_node *child, *np = client->dev.of_node; struct si5351_platform_data *pdata; - const struct of_device_id *match; struct property *prop; const __be32 *p; int num = 0; @@ -1124,15 +1124,10 @@ static int si5351_dt_parse(struct i2c_client *client) if (np == NULL) return 0; - match = of_match_node(si5351_dt_ids, np); - if (match == NULL) - return -EINVAL; - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->variant = (enum si5351_variant)match->data; pdata->clk_xtal = of_clk_get(np, 0); if (!IS_ERR(pdata->clk_xtal)) clk_put(pdata->clk_xtal); @@ -1163,7 +1158,7 @@ static int si5351_dt_parse(struct i2c_client *client) pdata->pll_src[num] = SI5351_PLL_SRC_XTAL; break; case 1: - if (pdata->variant != SI5351_VARIANT_C) { + if (variant != SI5351_VARIANT_C) { dev_err(&client->dev, "invalid parent %d for pll %d\n", val, num); @@ -1187,7 +1182,7 @@ static int si5351_dt_parse(struct i2c_client *client) } if (num >= 8 || - (pdata->variant == SI5351_VARIANT_A3 && num >= 3)) { + (variant == SI5351_VARIANT_A3 && num >= 3)) { dev_err(&client->dev, "invalid clkout %d\n", num); return -EINVAL; } @@ -1226,7 +1221,7 @@ static int si5351_dt_parse(struct i2c_client *client) SI5351_CLKOUT_SRC_XTAL; break; case 3: - if (pdata->variant != SI5351_VARIANT_C) { + if (variant != SI5351_VARIANT_C) { dev_err(&client->dev, "invalid parent %d for clkout %d\n", val, num); @@ -1298,7 +1293,7 @@ static int si5351_dt_parse(struct i2c_client *client) return 0; } #else -static int si5351_dt_parse(struct i2c_client *client) +static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant) { return 0; } @@ -1307,6 +1302,7 @@ static int si5351_dt_parse(struct i2c_client *client) static int si5351_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + enum si5351_variant variant = (enum si5351_variant)id->driver_data; struct si5351_platform_data *pdata; struct si5351_driver_data *drvdata; struct clk_init_data init; @@ -1315,7 +1311,7 @@ static int si5351_i2c_probe(struct i2c_client *client, u8 num_parents, num_clocks; int ret, n; - ret = si5351_dt_parse(client); + ret = si5351_dt_parse(client, variant); if (ret) return ret; @@ -1331,7 +1327,7 @@ static int si5351_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, drvdata); drvdata->client = client; - drvdata->variant = pdata->variant; + drvdata->variant = variant; drvdata->pxtal = pdata->clk_xtal; drvdata->pclkin = pdata->clk_clkin; @@ -1568,10 +1564,10 @@ static int si5351_i2c_probe(struct i2c_client *client, } static const struct i2c_device_id si5351_i2c_ids[] = { - { "si5351a", 0 }, - { "si5351a-msop", 0 }, - { "si5351b", 0 }, - { "si5351c", 0 }, + { "si5351a", SI5351_VARIANT_A }, + { "si5351a-msop", SI5351_VARIANT_A3 }, + { "si5351b", SI5351_VARIANT_B }, + { "si5351c", SI5351_VARIANT_C }, { } }; MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids); diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h index c0dbf2676872..4d0746b50c32 100644 --- a/drivers/clk/clk-si5351.h +++ b/drivers/clk/clk-si5351.h @@ -153,4 +153,18 @@ #define SI5351_XTAL_ENABLE (1<<6) #define SI5351_MULTISYNTH_ENABLE (1<<4) +/** + * enum si5351_variant - SiLabs Si5351 chip variant + * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input) + * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input) + * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input) + * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input) + */ +enum si5351_variant { + SI5351_VARIANT_A = 1, + SI5351_VARIANT_A3 = 2, + SI5351_VARIANT_B = 3, + SI5351_VARIANT_C = 4, +}; + #endif diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2b38dc99063f..5517944495d8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -575,16 +575,19 @@ struct clk_hw *__clk_get_hw(struct clk *clk) { return !clk ? NULL : clk->hw; } +EXPORT_SYMBOL_GPL(__clk_get_hw); u8 __clk_get_num_parents(struct clk *clk) { return !clk ? 0 : clk->num_parents; } +EXPORT_SYMBOL_GPL(__clk_get_num_parents); struct clk *__clk_get_parent(struct clk *clk) { return !clk ? NULL : clk->parent; } +EXPORT_SYMBOL_GPL(__clk_get_parent); struct clk *clk_get_parent_by_index(struct clk *clk, u8 index) { @@ -598,6 +601,7 @@ struct clk *clk_get_parent_by_index(struct clk *clk, u8 index) else return clk->parents[index]; } +EXPORT_SYMBOL_GPL(clk_get_parent_by_index); unsigned int __clk_get_enable_count(struct clk *clk) { @@ -629,6 +633,7 @@ unsigned long __clk_get_rate(struct clk *clk) out: return ret; } +EXPORT_SYMBOL_GPL(__clk_get_rate); unsigned long __clk_get_accuracy(struct clk *clk) { @@ -685,6 +690,7 @@ bool __clk_is_enabled(struct clk *clk) out: return !!ret; } +EXPORT_SYMBOL_GPL(__clk_is_enabled); static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) { @@ -776,6 +782,7 @@ out: return best; } +EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); /*** clk api ***/ @@ -2373,8 +2380,6 @@ struct of_clk_provider { void *data; }; -extern struct of_device_id __clk_of_table[]; - static const struct of_device_id __clk_of_table_sentinel __used __section(__clk_of_table_end); @@ -2534,7 +2539,7 @@ void __init of_clk_init(const struct of_device_id *matches) struct device_node *np; if (!matches) - matches = __clk_of_table; + matches = &__clk_of_table; for_each_matching_node_and_match(np, matches, &match) { of_clk_init_cb_t clk_init_cb = match->data; diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 190d38433202..f60db2ef1aee 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -1,11 +1,11 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg2.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-branch.o -clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += reset.o +clk-qcom-y += clk-regmap.o +clk-qcom-y += clk-pll.o +clk-qcom-y += clk-rcg.o +clk-qcom-y += clk-rcg2.o +clk-qcom-y += clk-branch.o +clk-qcom-y += reset.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 529e11dc2c6b..81e6d2f49aa0 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -375,7 +375,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, break; default: break; - }; + } /* Set new configuration. */ __raw_writel(con1, pll->con_reg + 0x4); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 659e4ea31893..abb6c5ac8a10 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -875,7 +875,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, if (!clk_data) return; - clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); + clks = kzalloc((SUNXI_DIVS_MAX_QTY+1) * sizeof(*clks), GFP_KERNEL); if (!clks) goto free_clkdata; diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile new file mode 100644 index 000000000000..4319d4031aa3 --- /dev/null +++ b/drivers/clk/ti/Makefile @@ -0,0 +1,11 @@ +ifneq ($(CONFIG_OF),) +obj-y += clk.o autoidle.o clockdomain.o +clk-common = dpll.o composite.o divider.o gate.o \ + fixed-factor.o mux.o apll.o +obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o +obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +endif diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c new file mode 100644 index 000000000000..b986f61f5a77 --- /dev/null +++ b/drivers/clk/ti/apll.c @@ -0,0 +1,223 @@ +/* + * OMAP APLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * J Keerthy <j-keerthy@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/log2.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> +#include <linux/delay.h> + +#define APLL_FORCE_LOCK 0x1 +#define APLL_AUTO_IDLE 0x2 +#define MAX_APLL_WAIT_TRIES 1000000 + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int dra7_apll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int r = 0, i = 0; + struct dpll_data *ad; + const char *clk_name; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + if (!ad) + return -EINVAL; + + clk_name = __clk_get_name(clk->hw.clk); + + state <<= __ffs(ad->idlest_mask); + + /* Check is already locked */ + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + + if ((v & ad->idlest_mask) == state) + return r; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); + + state <<= __ffs(ad->idlest_mask); + + while (1) { + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + if ((v & ad->idlest_mask) == state) + break; + if (i > MAX_APLL_WAIT_TRIES) + break; + i++; + udelay(1); + } + + if (i == MAX_APLL_WAIT_TRIES) { + pr_warn("clock: %s failed transition to '%s'\n", + clk_name, (state) ? "locked" : "bypassed"); + } else { + pr_debug("clock: %s transition to '%s' in %d loops\n", + clk_name, (state) ? "locked" : "bypassed", i); + + r = 0; + } + + return r; +} + +static void dra7_apll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + + state <<= __ffs(ad->idlest_mask); + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); +} + +static int dra7_apll_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u32 v; + + ad = clk->dpll_data; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ad->enable_mask; + + v >>= __ffs(ad->enable_mask); + + return v == APLL_AUTO_IDLE ? 0 : 1; +} + +static u8 dra7_init_apll_parent(struct clk_hw *hw) +{ + return 0; +} + +static const struct clk_ops apll_ck_ops = { + .enable = &dra7_apll_enable, + .disable = &dra7_apll_disable, + .is_enabled = &dra7_apll_is_enabled, + .get_parent = &dra7_init_apll_parent, +}; + +static void __init omap_clk_register_apll(struct clk_hw *hw, + struct device_node *node) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *ad = clk_hw->dpll_data; + struct clk *clk; + + ad->clk_ref = of_clk_get(node, 0); + ad->clk_bypass = of_clk_get(node, 1); + + if (IS_ERR(ad->clk_ref) || IS_ERR(ad->clk_bypass)) { + pr_debug("clk-ref or clk-bypass for %s not ready, retry\n", + node->name); + if (!ti_clk_retry_init(node, hw, omap_clk_register_apll)) + return; + + goto cleanup; + } + + clk = clk_register(NULL, &clk_hw->hw); + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +static void __init of_dra7_apll_setup(struct device_node *node) +{ + struct dpll_data *ad = NULL; + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + int i; + + ad = kzalloc(sizeof(*ad), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!ad || !clk_hw || !init) + goto cleanup; + + clk_hw->dpll_data = ad; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = &apll_ck_ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("dra7 apll %s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + ad->control_reg = ti_clk_get_reg_addr(node, 0); + ad->idlest_reg = ti_clk_get_reg_addr(node, 1); + + if (!ad->control_reg || !ad->idlest_reg) + goto cleanup; + + ad->idlest_mask = 0x1; + ad->enable_mask = 0x3; + + omap_clk_register_apll(&clk_hw->hw, node); + return; + +cleanup: + kfree(parent_names); + kfree(ad); + kfree(clk_hw); + kfree(init); +} +CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup); diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c new file mode 100644 index 000000000000..8912ff80af34 --- /dev/null +++ b/drivers/clk/ti/autoidle.c @@ -0,0 +1,133 @@ +/* + * TI clock autoidle support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +struct clk_ti_autoidle { + void __iomem *reg; + u8 shift; + u8 flags; + const char *name; + struct list_head node; +}; + +#define AUTOIDLE_LOW 0x1 + +static LIST_HEAD(autoidle_clks); + +static void ti_allow_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val &= ~(1 << clk->shift); + else + val |= (1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +static void ti_deny_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val |= (1 << clk->shift); + else + val &= ~(1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +/** + * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks + * + * Enables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_allow_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_allow_autoidle(c); +} + +/** + * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks + * + * Disables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_deny_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_deny_autoidle(c); +} + +/** + * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock + * @node: pointer to the clock device node + * + * Checks if a clock has hardware autoidle support or not (check + * for presence of 'ti,autoidle-shift' property in the device tree + * node) and sets up the hardware autoidle feature for the clock + * if available. If autoidle is available, the clock is also added + * to the autoidle list for later processing. Returns 0 on success, + * negative error value on failure. + */ +int __init of_ti_clk_autoidle_setup(struct device_node *node) +{ + u32 shift; + struct clk_ti_autoidle *clk; + + /* Check if this clock has autoidle support or not */ + if (of_property_read_u32(node, "ti,autoidle-shift", &shift)) + return 0; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + + if (!clk) + return -ENOMEM; + + clk->shift = shift; + clk->name = node->name; + clk->reg = ti_clk_get_reg_addr(node, 0); + + if (!clk->reg) { + kfree(clk); + return -EINVAL; + } + + if (of_property_read_bool(node, "ti,invert-autoidle-bit")) + clk->flags |= AUTOIDLE_LOW; + + list_add(&clk->node, &autoidle_clks); + + return 0; +} diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c new file mode 100644 index 000000000000..776ee4594bd4 --- /dev/null +++ b/drivers/clk/ti/clk-33xx.c @@ -0,0 +1,161 @@ +/* + * AM33XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + +static struct ti_dt_clk am33xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK("cpu0", NULL, "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_ddr_m2_div2_ck", "dpll_ddr_m2_div2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "cefuse_fck", "cefuse_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK("481cc000.d_can", NULL, "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK("481d0000.d_can", NULL, "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "mmu_fck", "mmu_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + DT_CLK(NULL, "rng_fck", "rng_fck"), + DT_CLK(NULL, "timer1_fck", "timer1_fck"), + DT_CLK(NULL, "timer2_fck", "timer2_fck"), + DT_CLK(NULL, "timer3_fck", "timer3_fck"), + DT_CLK(NULL, "timer4_fck", "timer4_fck"), + DT_CLK(NULL, "timer5_fck", "timer5_fck"), + DT_CLK(NULL, "timer6_fck", "timer6_fck"), + DT_CLK(NULL, "timer7_fck", "timer7_fck"), + DT_CLK(NULL, "usbotg_fck", "usbotg_fck"), + DT_CLK(NULL, "ieee5000_fck", "ieee5000_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l4_rtc_gclk", "l4_rtc_gclk"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4fw_gclk", "l4fw_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "sysclk_div_ck", "sysclk_div_ck"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "lcd_gclk", "lcd_gclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "sysclkout_pre_ck", "sysclkout_pre_ck"), + DT_CLK(NULL, "clkout2_div_ck", "clkout2_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "dbg_sysclk_ck", "dbg_sysclk_ck"), + DT_CLK(NULL, "dbg_clka_ck", "dbg_clka_ck"), + DT_CLK(NULL, "stm_pmd_clock_mux_ck", "stm_pmd_clock_mux_ck"), + DT_CLK(NULL, "trace_pmd_clk_mux_ck", "trace_pmd_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "clkout2_ck", "clkout2_ck"), + DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"), + DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"), + DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "dpll_ddr_m2_ck", + "dpll_mpu_m2_ck", + "l3_gclk", + "l4hs_gclk", + "l4fw_gclk", + "l4ls_gclk", + /* Required for external peripherals like, Audio codecs */ + "clkout2_ck", +}; + +int __init am33xx_dt_clk_init(void) +{ + struct clk *clk1, *clk2; + + ti_dt_clocks_register(am33xx_clks); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always + * physically present, in such a case HWMOD enabling of + * clock would be failure with default parent. And timer + * probe thinks clock is already enabled, this leads to + * crash upon accessing timer 3 & 6 registers in probe. + * Fix by setting parent of both these timers to master + * oscillator clock. + */ + + clk1 = clk_get_sys(NULL, "sys_clkin_ck"); + clk2 = clk_get_sys(NULL, "timer3_fck"); + clk_set_parent(clk2, clk1); + + clk2 = clk_get_sys(NULL, "timer6_fck"); + clk_set_parent(clk2, clk1); + /* + * The On-Chip 32K RC Osc clock is not an accurate clock-source as per + * the design/spec, so as a result, for example, timer which supposed + * to get expired @60Sec, but will expire somewhere ~@40Sec, which is + * not expected by any use-case, so change WDT1 clock source to PRCM + * 32KHz clock. + */ + clk1 = clk_get_sys(NULL, "wdt1_fck"); + clk2 = clk_get_sys(NULL, "clkdiv32k_ick"); + clk_set_parent(clk1, clk2); + + return 0; +} diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c new file mode 100644 index 000000000000..d3230234f07b --- /dev/null +++ b/drivers/clk/ti/clk-3xxx.c @@ -0,0 +1,401 @@ +/* + * OMAP3 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + + +static struct ti_dt_clk omap3xxx_clks[] = { + DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), + DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), + DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"), + DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_38_4m_ck", "virt_38_4m_ck"), + DT_CLK(NULL, "osc_sys_ck", "osc_sys_ck"), + DT_CLK("twl", "fck", "osc_sys_ck"), + DT_CLK(NULL, "sys_ck", "sys_ck"), + DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"), + DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"), + DT_CLK(NULL, "sys_altclk", "sys_altclk"), + DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"), + DT_CLK(NULL, "sys_clkout1", "sys_clkout1"), + DT_CLK(NULL, "dpll1_ck", "dpll1_ck"), + DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"), + DT_CLK(NULL, "dpll1_x2m2_ck", "dpll1_x2m2_ck"), + DT_CLK(NULL, "dpll3_ck", "dpll3_ck"), + DT_CLK(NULL, "core_ck", "core_ck"), + DT_CLK(NULL, "dpll3_x2_ck", "dpll3_x2_ck"), + DT_CLK(NULL, "dpll3_m2_ck", "dpll3_m2_ck"), + DT_CLK(NULL, "dpll3_m2x2_ck", "dpll3_m2x2_ck"), + DT_CLK(NULL, "dpll3_m3_ck", "dpll3_m3_ck"), + DT_CLK(NULL, "dpll3_m3x2_ck", "dpll3_m3x2_ck"), + DT_CLK(NULL, "dpll4_ck", "dpll4_ck"), + DT_CLK(NULL, "dpll4_x2_ck", "dpll4_x2_ck"), + DT_CLK(NULL, "omap_96m_fck", "omap_96m_fck"), + DT_CLK(NULL, "cm_96m_fck", "cm_96m_fck"), + DT_CLK(NULL, "omap_54m_fck", "omap_54m_fck"), + DT_CLK(NULL, "omap_48m_fck", "omap_48m_fck"), + DT_CLK(NULL, "omap_12m_fck", "omap_12m_fck"), + DT_CLK(NULL, "dpll4_m2_ck", "dpll4_m2_ck"), + DT_CLK(NULL, "dpll4_m2x2_ck", "dpll4_m2x2_ck"), + DT_CLK(NULL, "dpll4_m3_ck", "dpll4_m3_ck"), + DT_CLK(NULL, "dpll4_m3x2_ck", "dpll4_m3x2_ck"), + DT_CLK(NULL, "dpll4_m4_ck", "dpll4_m4_ck"), + DT_CLK(NULL, "dpll4_m4x2_ck", "dpll4_m4x2_ck"), + DT_CLK(NULL, "dpll4_m5_ck", "dpll4_m5_ck"), + DT_CLK(NULL, "dpll4_m5x2_ck", "dpll4_m5x2_ck"), + DT_CLK(NULL, "dpll4_m6_ck", "dpll4_m6_ck"), + DT_CLK(NULL, "dpll4_m6x2_ck", "dpll4_m6x2_ck"), + DT_CLK("etb", "emu_per_alwon_ck", "emu_per_alwon_ck"), + DT_CLK(NULL, "clkout2_src_ck", "clkout2_src_ck"), + DT_CLK(NULL, "sys_clkout2", "sys_clkout2"), + DT_CLK(NULL, "corex2_fck", "corex2_fck"), + DT_CLK(NULL, "dpll1_fck", "dpll1_fck"), + DT_CLK(NULL, "mpu_ck", "mpu_ck"), + DT_CLK(NULL, "arm_fck", "arm_fck"), + DT_CLK("etb", "emu_mpu_alwon_ck", "emu_mpu_alwon_ck"), + DT_CLK(NULL, "l3_ick", "l3_ick"), + DT_CLK(NULL, "l4_ick", "l4_ick"), + DT_CLK(NULL, "rm_ick", "rm_ick"), + DT_CLK(NULL, "gpt10_fck", "gpt10_fck"), + DT_CLK(NULL, "gpt11_fck", "gpt11_fck"), + DT_CLK(NULL, "core_96m_fck", "core_96m_fck"), + DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"), + DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"), + DT_CLK(NULL, "i2c3_fck", "i2c3_fck"), + DT_CLK(NULL, "i2c2_fck", "i2c2_fck"), + DT_CLK(NULL, "i2c1_fck", "i2c1_fck"), + DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"), + DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"), + DT_CLK(NULL, "core_48m_fck", "core_48m_fck"), + DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"), + DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"), + DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"), + DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"), + DT_CLK(NULL, "uart2_fck", "uart2_fck"), + DT_CLK(NULL, "uart1_fck", "uart1_fck"), + DT_CLK(NULL, "core_12m_fck", "core_12m_fck"), + DT_CLK("omap_hdq.0", "fck", "hdq_fck"), + DT_CLK(NULL, "hdq_fck", "hdq_fck"), + DT_CLK(NULL, "core_l3_ick", "core_l3_ick"), + DT_CLK(NULL, "sdrc_ick", "sdrc_ick"), + DT_CLK(NULL, "gpmc_fck", "gpmc_fck"), + DT_CLK(NULL, "core_l4_ick", "core_l4_ick"), + DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"), + DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"), + DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"), + DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"), + DT_CLK("omap_hdq.0", "ick", "hdq_ick"), + DT_CLK(NULL, "hdq_ick", "hdq_ick"), + DT_CLK("omap2_mcspi.4", "ick", "mcspi4_ick"), + DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"), + DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"), + DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"), + DT_CLK(NULL, "mcspi4_ick", "mcspi4_ick"), + DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"), + DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"), + DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"), + DT_CLK("omap_i2c.3", "ick", "i2c3_ick"), + DT_CLK("omap_i2c.2", "ick", "i2c2_ick"), + DT_CLK("omap_i2c.1", "ick", "i2c1_ick"), + DT_CLK(NULL, "i2c3_ick", "i2c3_ick"), + DT_CLK(NULL, "i2c2_ick", "i2c2_ick"), + DT_CLK(NULL, "i2c1_ick", "i2c1_ick"), + DT_CLK(NULL, "uart2_ick", "uart2_ick"), + DT_CLK(NULL, "uart1_ick", "uart1_ick"), + DT_CLK(NULL, "gpt11_ick", "gpt11_ick"), + DT_CLK(NULL, "gpt10_ick", "gpt10_ick"), + DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"), + DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"), + DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"), + DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"), + DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"), + DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"), + DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"), + DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"), + DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"), + DT_CLK(NULL, "init_60m_fclk", "dummy_ck"), + DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), + DT_CLK(NULL, "aes2_ick", "aes2_ick"), + DT_CLK(NULL, "wkup_32k_fck", "wkup_32k_fck"), + DT_CLK(NULL, "gpio1_dbck", "gpio1_dbck"), + DT_CLK(NULL, "sha12_ick", "sha12_ick"), + DT_CLK(NULL, "wdt2_fck", "wdt2_fck"), + DT_CLK("omap_wdt", "ick", "wdt2_ick"), + DT_CLK(NULL, "wdt2_ick", "wdt2_ick"), + DT_CLK(NULL, "wdt1_ick", "wdt1_ick"), + DT_CLK(NULL, "gpio1_ick", "gpio1_ick"), + DT_CLK(NULL, "omap_32ksync_ick", "omap_32ksync_ick"), + DT_CLK(NULL, "gpt12_ick", "gpt12_ick"), + DT_CLK(NULL, "gpt1_ick", "gpt1_ick"), + DT_CLK(NULL, "per_96m_fck", "per_96m_fck"), + DT_CLK(NULL, "per_48m_fck", "per_48m_fck"), + DT_CLK(NULL, "uart3_fck", "uart3_fck"), + DT_CLK(NULL, "gpt2_fck", "gpt2_fck"), + DT_CLK(NULL, "gpt3_fck", "gpt3_fck"), + DT_CLK(NULL, "gpt4_fck", "gpt4_fck"), + DT_CLK(NULL, "gpt5_fck", "gpt5_fck"), + DT_CLK(NULL, "gpt6_fck", "gpt6_fck"), + DT_CLK(NULL, "gpt7_fck", "gpt7_fck"), + DT_CLK(NULL, "gpt8_fck", "gpt8_fck"), + DT_CLK(NULL, "gpt9_fck", "gpt9_fck"), + DT_CLK(NULL, "per_32k_alwon_fck", "per_32k_alwon_fck"), + DT_CLK(NULL, "gpio6_dbck", "gpio6_dbck"), + DT_CLK(NULL, "gpio5_dbck", "gpio5_dbck"), + DT_CLK(NULL, "gpio4_dbck", "gpio4_dbck"), + DT_CLK(NULL, "gpio3_dbck", "gpio3_dbck"), + DT_CLK(NULL, "gpio2_dbck", "gpio2_dbck"), + DT_CLK(NULL, "wdt3_fck", "wdt3_fck"), + DT_CLK(NULL, "per_l4_ick", "per_l4_ick"), + DT_CLK(NULL, "gpio6_ick", "gpio6_ick"), + DT_CLK(NULL, "gpio5_ick", "gpio5_ick"), + DT_CLK(NULL, "gpio4_ick", "gpio4_ick"), + DT_CLK(NULL, "gpio3_ick", "gpio3_ick"), + DT_CLK(NULL, "gpio2_ick", "gpio2_ick"), + DT_CLK(NULL, "wdt3_ick", "wdt3_ick"), + DT_CLK(NULL, "uart3_ick", "uart3_ick"), + DT_CLK(NULL, "uart4_ick", "uart4_ick"), + DT_CLK(NULL, "gpt9_ick", "gpt9_ick"), + DT_CLK(NULL, "gpt8_ick", "gpt8_ick"), + DT_CLK(NULL, "gpt7_ick", "gpt7_ick"), + DT_CLK(NULL, "gpt6_ick", "gpt6_ick"), + DT_CLK(NULL, "gpt5_ick", "gpt5_ick"), + DT_CLK(NULL, "gpt4_ick", "gpt4_ick"), + DT_CLK(NULL, "gpt3_ick", "gpt3_ick"), + DT_CLK(NULL, "gpt2_ick", "gpt2_ick"), + DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"), + DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"), + DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp4_ick", "mcbsp2_ick"), + DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"), + DT_CLK(NULL, "mcbsp2_ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"), + DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"), + DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"), + DT_CLK("etb", "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "pclk_fck", "pclk_fck"), + DT_CLK(NULL, "pclkx2_fck", "pclkx2_fck"), + DT_CLK(NULL, "atclk_fck", "atclk_fck"), + DT_CLK(NULL, "traceclk_src_fck", "traceclk_src_fck"), + DT_CLK(NULL, "traceclk_fck", "traceclk_fck"), + DT_CLK(NULL, "secure_32k_fck", "secure_32k_fck"), + DT_CLK(NULL, "gpt12_fck", "gpt12_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"), + DT_CLK(NULL, "timer_sys_ck", "sys_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll1_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap34xx_omap36xx_clks[] = { + DT_CLK(NULL, "aes1_ick", "aes1_ick"), + DT_CLK("omap_rng", "ick", "rng_ick"), + DT_CLK("omap3-rom-rng", "ick", "rng_ick"), + DT_CLK(NULL, "sha11_ick", "sha11_ick"), + DT_CLK(NULL, "des1_ick", "des1_ick"), + DT_CLK(NULL, "cam_mclk", "cam_mclk"), + DT_CLK(NULL, "cam_ick", "cam_ick"), + DT_CLK(NULL, "csi2_96m_fck", "csi2_96m_fck"), + DT_CLK(NULL, "security_l3_ick", "security_l3_ick"), + DT_CLK(NULL, "pka_ick", "pka_ick"), + DT_CLK(NULL, "icr_ick", "icr_ick"), + DT_CLK("omap-aes", "ick", "aes2_ick"), + DT_CLK("omap-sham", "ick", "sha12_ick"), + DT_CLK(NULL, "des2_ick", "des2_ick"), + DT_CLK(NULL, "mspro_ick", "mspro_ick"), + DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"), + DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"), + DT_CLK(NULL, "sr1_fck", "sr1_fck"), + DT_CLK(NULL, "sr2_fck", "sr2_fck"), + DT_CLK(NULL, "sr_l4_ick", "sr_l4_ick"), + DT_CLK(NULL, "security_l4_ick2", "security_l4_ick2"), + DT_CLK(NULL, "wkup_l4_ick", "wkup_l4_ick"), + DT_CLK(NULL, "dpll2_fck", "dpll2_fck"), + DT_CLK(NULL, "iva2_ck", "iva2_ck"), + DT_CLK(NULL, "modem_fck", "modem_fck"), + DT_CLK(NULL, "sad2d_ick", "sad2d_ick"), + DT_CLK(NULL, "mad2d_ick", "mad2d_ick"), + DT_CLK(NULL, "mspro_fck", "mspro_fck"), + DT_CLK(NULL, "dpll2_ck", "dpll2_ck"), + DT_CLK(NULL, "dpll2_m2_ck", "dpll2_m2_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"), + DT_CLK(NULL, "usim_fck", "usim_fck"), + DT_CLK(NULL, "usim_ick", "usim_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap3430es1_clks[] = { + DT_CLK(NULL, "gfx_l3_ck", "gfx_l3_ck"), + DT_CLK(NULL, "gfx_l3_fck", "gfx_l3_fck"), + DT_CLK(NULL, "gfx_l3_ick", "gfx_l3_ick"), + DT_CLK(NULL, "gfx_cg1_ck", "gfx_cg1_ck"), + DT_CLK(NULL, "gfx_cg2_ck", "gfx_cg2_ck"), + DT_CLK(NULL, "d2d_26m_fck", "d2d_26m_fck"), + DT_CLK(NULL, "fshostusb_fck", "fshostusb_fck"), + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "fac_ick", "fac_ick"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"), + DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es1"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "virt_16_8m_ck", "virt_16_8m_ck"), + DT_CLK(NULL, "dpll5_ck", "dpll5_ck"), + DT_CLK(NULL, "dpll5_m2_ck", "dpll5_m2_ck"), + DT_CLK(NULL, "sgx_fck", "sgx_fck"), + DT_CLK(NULL, "sgx_ick", "sgx_ick"), + DT_CLK(NULL, "cpefuse_fck", "cpefuse_fck"), + DT_CLK(NULL, "ts_fck", "ts_fck"), + DT_CLK(NULL, "usbtll_fck", "usbtll_fck"), + DT_CLK(NULL, "usbtll_ick", "usbtll_ick"), + DT_CLK("omap_hsmmc.2", "ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_fck", "mmchs3_fck"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es2"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"), + DT_CLK(NULL, "usbhost_120m_fck", "usbhost_120m_fck"), + DT_CLK(NULL, "usbhost_48m_fck", "usbhost_48m_fck"), + DT_CLK(NULL, "usbhost_ick", "usbhost_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk am35xx_clks[] = { + DT_CLK(NULL, "ipss_ick", "ipss_ick"), + DT_CLK(NULL, "rmii_ck", "rmii_ck"), + DT_CLK(NULL, "pclk_ck", "pclk_ck"), + DT_CLK(NULL, "emac_ick", "emac_ick"), + DT_CLK(NULL, "emac_fck", "emac_fck"), + DT_CLK("davinci_emac.0", NULL, "emac_ick"), + DT_CLK("davinci_mdio.0", NULL, "emac_fck"), + DT_CLK("vpfe-capture", "master", "vpfe_ick"), + DT_CLK("vpfe-capture", "slave", "vpfe_fck"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"), + DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"), + DT_CLK(NULL, "hecc_ck", "hecc_ck"), + DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"), + DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_clks[] = { + DT_CLK(NULL, "omap_192m_alwon_fck", "omap_192m_alwon_fck"), + DT_CLK(NULL, "uart4_fck", "uart4_fck"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "sdrc_ick", + "gpmc_fck", + "omapctrl_ick", +}; + +enum { + OMAP3_SOC_AM35XX, + OMAP3_SOC_OMAP3430_ES1, + OMAP3_SOC_OMAP3430_ES2_PLUS, + OMAP3_SOC_OMAP3630, + OMAP3_SOC_TI81XX, +}; + +static int __init omap3xxx_dt_clk_init(int soc_type) +{ + if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || + soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap3xxx_clks); + + if (soc_type == OMAP3_SOC_AM35XX) + ti_dt_clocks_register(am35xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1) + ti_dt_clocks_register(omap3430es1_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap34xx_omap36xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_clks); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n", + (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 100000) % 10, + (clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000)); + + if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1) + omap3_clk_lock_dpll5(); + + return 0; +} + +int __init omap3430_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS); +} + +int __init omap3630_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630); +} + +int __init am35xx_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX); +} + +int __init ti81xx_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX); +} diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c new file mode 100644 index 000000000000..67c8de572c50 --- /dev/null +++ b/drivers/clk/ti/clk-43xx.c @@ -0,0 +1,118 @@ +/* + * AM43XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + +static struct ti_dt_clk am43xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + DT_CLK(NULL, "timer1_fck", "timer1_fck"), + DT_CLK(NULL, "timer2_fck", "timer2_fck"), + DT_CLK(NULL, "timer3_fck", "timer3_fck"), + DT_CLK(NULL, "timer4_fck", "timer4_fck"), + DT_CLK(NULL, "timer5_fck", "timer5_fck"), + DT_CLK(NULL, "timer6_fck", "timer6_fck"), + DT_CLK(NULL, "timer7_fck", "timer7_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "sysclk_div", "sysclk_div"), + DT_CLK(NULL, "disp_clk", "disp_clk"), + DT_CLK(NULL, "clk_32k_mosc_ck", "clk_32k_mosc_ck"), + DT_CLK(NULL, "clk_32k_tpm_ck", "clk_32k_tpm_ck"), + DT_CLK(NULL, "dpll_extdev_ck", "dpll_extdev_ck"), + DT_CLK(NULL, "dpll_extdev_m2_ck", "dpll_extdev_m2_ck"), + DT_CLK(NULL, "mux_synctimer32k_ck", "mux_synctimer32k_ck"), + DT_CLK(NULL, "synctimer_32kclk", "synctimer_32kclk"), + DT_CLK(NULL, "timer8_fck", "timer8_fck"), + DT_CLK(NULL, "timer9_fck", "timer9_fck"), + DT_CLK(NULL, "timer10_fck", "timer10_fck"), + DT_CLK(NULL, "timer11_fck", "timer11_fck"), + DT_CLK(NULL, "cpsw_50m_clkdiv", "cpsw_50m_clkdiv"), + DT_CLK(NULL, "cpsw_5m_clkdiv", "cpsw_5m_clkdiv"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_m4_ck", "dpll_ddr_m4_ck"), + DT_CLK(NULL, "dpll_per_clkdcoldo", "dpll_per_clkdcoldo"), + DT_CLK(NULL, "dll_aging_clk_div", "dll_aging_clk_div"), + DT_CLK(NULL, "div_core_25m_ck", "div_core_25m_ck"), + DT_CLK(NULL, "func_12m_clk", "func_12m_clk"), + DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"), + DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"), + { .node_name = NULL }, +}; + +int __init am43xx_dt_clk_init(void) +{ + ti_dt_clocks_register(am43xx_clks); + + omap2_clk_disable_autoidle_all(); + + return 0; +} diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c new file mode 100644 index 000000000000..ae00218b5da3 --- /dev/null +++ b/drivers/clk/ti/clk-44xx.c @@ -0,0 +1,316 @@ +/* + * OMAP4 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> + +/* + * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section + * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK + * must be set to 196.608 MHz" and hence, the DPLL locked frequency is + * half of this value. + */ +#define OMAP4_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section + * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred + * locked frequency for the USB DPLL is 960MHz. + */ +#define OMAP4_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap44xx_clks[] = { + DT_CLK(NULL, "extalt_clkin_ck", "extalt_clkin_ck"), + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "pad_slimbus_core_clks_ck", "pad_slimbus_core_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tie_low_clock_ck", "tie_low_clock_ck"), + DT_CLK(NULL, "utmi_phy_clkout_ck", "utmi_phy_clkout_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "xclk60motg_ck", "xclk60motg_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux_ck", "abe_dpll_bypass_clk_mux_ck"), + DT_CLK(NULL, "abe_dpll_refclk_mux_ck", "abe_dpll_refclk_mux_ck"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "core_hsd_byp_clk_mux_ck", "core_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m6x2_ck", "dpll_core_m6x2_ck"), + DT_CLK(NULL, "dbgclk_mux_ck", "dbgclk_mux_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "ddrphy_ck", "ddrphy_ck"), + DT_CLK(NULL, "dpll_core_m5x2_ck", "dpll_core_m5x2_ck"), + DT_CLK(NULL, "div_core_ck", "div_core_ck"), + DT_CLK(NULL, "div_iva_hs_clk", "div_iva_hs_clk"), + DT_CLK(NULL, "div_mpu_hs_clk", "div_mpu_hs_clk"), + DT_CLK(NULL, "dpll_core_m4x2_ck", "dpll_core_m4x2_ck"), + DT_CLK(NULL, "dll_clk_div_ck", "dll_clk_div_ck"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "dpll_core_m7x2_ck", "dpll_core_m7x2_ck"), + DT_CLK(NULL, "iva_hsd_byp_clk_mux_ck", "iva_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_m4x2_ck", "dpll_iva_m4x2_ck"), + DT_CLK(NULL, "dpll_iva_m5x2_ck", "dpll_iva_m5x2_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_hs_clk_div_ck", "per_hs_clk_div_ck"), + DT_CLK(NULL, "per_hsd_byp_clk_mux_ck", "per_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_per_m4x2_ck", "dpll_per_m4x2_ck"), + DT_CLK(NULL, "dpll_per_m5x2_ck", "dpll_per_m5x2_ck"), + DT_CLK(NULL, "dpll_per_m6x2_ck", "dpll_per_m6x2_ck"), + DT_CLK(NULL, "dpll_per_m7x2_ck", "dpll_per_m7x2_ck"), + DT_CLK(NULL, "usb_hs_clk_div_ck", "usb_hs_clk_div_ck"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo_ck", "dpll_usb_clkdcoldo_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "ducati_clk_mux_ck", "ducati_clk_mux_ck"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_24mc_fclk", "func_24mc_fclk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_48mc_fclk", "func_48mc_fclk"), + DT_CLK(NULL, "func_64m_fclk", "func_64m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "init_60m_fclk", "init_60m_fclk"), + DT_CLK(NULL, "l3_div_ck", "l3_div_ck"), + DT_CLK(NULL, "l4_div_ck", "l4_div_ck"), + DT_CLK(NULL, "lp_clk_div_ck", "lp_clk_div_ck"), + DT_CLK(NULL, "l4_wkup_clk_mux_ck", "l4_wkup_clk_mux_ck"), + DT_CLK("smp_twd", NULL, "mpu_periphclk"), + DT_CLK(NULL, "ocp_abe_iclk", "ocp_abe_iclk"), + DT_CLK(NULL, "per_abe_24m_fclk", "per_abe_24m_fclk"), + DT_CLK(NULL, "per_abe_nc_fclk", "per_abe_nc_fclk"), + DT_CLK(NULL, "syc_clk_div_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "aes1_fck", "aes1_fck"), + DT_CLK(NULL, "aes2_fck", "aes2_fck"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "func_dmic_abe_gfclk", "func_dmic_abe_gfclk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "dss_tv_clk", "dss_tv_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_fck", "dss_fck"), + DT_CLK("omapdss_dss", "ick", "dss_fck"), + DT_CLK(NULL, "fdif_fck", "fdif_fck"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "sgx_clk_mux", "sgx_clk_mux"), + DT_CLK(NULL, "hsi_fck", "hsi_fck"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "func_mcasp_abe_gfclk", "func_mcasp_abe_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp1_gfclk", "func_mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp2_gfclk", "func_mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp3_gfclk", "func_mcbsp3_gfclk"), + DT_CLK(NULL, "mcbsp4_sync_mux_ck", "mcbsp4_sync_mux_ck"), + DT_CLK(NULL, "per_mcbsp4_gfclk", "per_mcbsp4_gfclk"), + DT_CLK(NULL, "hsmmc1_fclk", "hsmmc1_fclk"), + DT_CLK(NULL, "hsmmc2_fclk", "hsmmc2_fclk"), + DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "ocp2scp_usb_phy_phy_48m"), + DT_CLK(NULL, "sha2md5_fck", "sha2md5_fck"), + DT_CLK(NULL, "slimbus1_fclk_1", "slimbus1_fclk_1"), + DT_CLK(NULL, "slimbus1_fclk_0", "slimbus1_fclk_0"), + DT_CLK(NULL, "slimbus1_fclk_2", "slimbus1_fclk_2"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "slimbus2_fclk_1", "slimbus2_fclk_1"), + DT_CLK(NULL, "slimbus2_fclk_0", "slimbus2_fclk_0"), + DT_CLK(NULL, "slimbus2_slimbus_clk", "slimbus2_slimbus_clk"), + DT_CLK(NULL, "smartreflex_core_fck", "smartreflex_core_fck"), + DT_CLK(NULL, "smartreflex_iva_fck", "smartreflex_iva_fck"), + DT_CLK(NULL, "smartreflex_mpu_fck", "smartreflex_mpu_fck"), + DT_CLK(NULL, "dmt1_clk_mux", "dmt1_clk_mux"), + DT_CLK(NULL, "cm2_dm10_mux", "cm2_dm10_mux"), + DT_CLK(NULL, "cm2_dm11_mux", "cm2_dm11_mux"), + DT_CLK(NULL, "cm2_dm2_mux", "cm2_dm2_mux"), + DT_CLK(NULL, "cm2_dm3_mux", "cm2_dm3_mux"), + DT_CLK(NULL, "cm2_dm4_mux", "cm2_dm4_mux"), + DT_CLK(NULL, "timer5_sync_mux", "timer5_sync_mux"), + DT_CLK(NULL, "timer6_sync_mux", "timer6_sync_mux"), + DT_CLK(NULL, "timer7_sync_mux", "timer7_sync_mux"), + DT_CLK(NULL, "timer8_sync_mux", "timer8_sync_mux"), + DT_CLK(NULL, "cm2_dm9_mux", "cm2_dm9_mux"), + DT_CLK(NULL, "usb_host_fs_fck", "usb_host_fs_fck"), + DT_CLK("usbhs_omap", "fs_fck", "usb_host_fs_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_func48mclk", "usb_host_hs_func48mclk"), + DT_CLK(NULL, "usb_host_hs_fck", "usb_host_hs_fck"), + DT_CLK("usbhs_omap", "hs_fck", "usb_host_hs_fck"), + DT_CLK(NULL, "otg_60m_gfclk", "otg_60m_gfclk"), + DT_CLK(NULL, "usb_otg_hs_xclk", "usb_otg_hs_xclk"), + DT_CLK(NULL, "usb_otg_hs_ick", "usb_otg_hs_ick"), + DT_CLK("musb-omap2430", "ick", "usb_otg_hs_ick"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_omap", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_tll", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK(NULL, "usim_ck", "usim_ck"), + DT_CLK(NULL, "usim_fclk", "usim_fclk"), + DT_CLK(NULL, "pmd_stm_clock_mux_ck", "pmd_stm_clock_mux_ck"), + DT_CLK(NULL, "pmd_trace_clk_mux_ck", "pmd_trace_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "auxclk4_src_ck", "auxclk4_src_ck"), + DT_CLK(NULL, "auxclk4_ck", "auxclk4_ck"), + DT_CLK(NULL, "auxclkreq4_ck", "auxclkreq4_ck"), + DT_CLK(NULL, "auxclk5_src_ck", "auxclk5_src_ck"), + DT_CLK(NULL, "auxclk5_ck", "auxclk5_ck"), + DT_CLK(NULL, "auxclkreq5_ck", "auxclkreq5_ck"), + DT_CLK("50000000.gpmc", "fck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.2", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.3", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.4", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.9", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.10", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.11", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.5", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.6", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.7", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.8", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("40138000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013a000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013c000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013e000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "bandgap_fclk", "bandgap_fclk"), + DT_CLK(NULL, "div_ts_ck", "div_ts_ck"), + DT_CLK(NULL, "bandgap_ts_fclk", "bandgap_ts_fclk"), + { .node_name = NULL }, +}; + +int __init omap4xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap44xx_clks); + + omap2_clk_disable_autoidle_all(); + + /* + * Lock USB DPLL on OMAP4 devices so that the L3INIT power + * domain can transition to retention state when not in use. + */ + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP4_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + /* + * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power + * state when turning the ABE clock domain. Workaround this by + * locking the ABE DPLL on boot. + * Lock the ABE DPLL in any case to avoid issues with audio. + */ + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_refclk_mux_ck"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP4_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c new file mode 100644 index 000000000000..0ef9f581286b --- /dev/null +++ b/drivers/clk/ti/clk-54xx.c @@ -0,0 +1,255 @@ +/* + * OMAP5 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/clk/ti.h> + +#define OMAP5_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP543x TRM, section "3.6.3.9.5 DPLL_USB Preferred Settings" + * states it must be at 960MHz + */ +#define OMAP5_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap54xx_clks[] = { + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin", "sys_clkin"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "abe_iclk", "abe_iclk"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h21x2_ck", "dpll_core_h21x2_ck"), + DT_CLK(NULL, "c2c_fclk", "c2c_fclk"), + DT_CLK(NULL, "c2c_iclk", "c2c_iclk"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h11x2_ck", "dpll_core_h11x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_h11x2_ck", "dpll_iva_h11x2_ck"), + DT_CLK(NULL, "dpll_iva_h12x2_ck", "dpll_iva_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_unipro1_ck", "dpll_unipro1_ck"), + DT_CLK(NULL, "dpll_unipro1_clkdcoldo", "dpll_unipro1_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro1_m2_ck", "dpll_unipro1_m2_ck"), + DT_CLK(NULL, "dpll_unipro2_ck", "dpll_unipro2_ck"), + DT_CLK(NULL, "dpll_unipro2_clkdcoldo", "dpll_unipro2_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro2_m2_ck", "dpll_unipro2_m2_ck"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "dss_syc_gfclk_div", "dss_syc_gfclk_div"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "gpu_l3_iclk", "gpu_l3_iclk"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "lli_txphy_clk", "lli_txphy_clk"), + DT_CLK(NULL, "lli_txphy_ls_clk", "lli_txphy_ls_clk"), + DT_CLK(NULL, "mmc1_32khz_clk", "mmc1_32khz_clk"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "usb_host_hs_hsic480m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "usb_host_hs_hsic60m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_otg_ss_refclk960m", "usb_otg_ss_refclk960m"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "dmic_gfclk", "dmic_gfclk"), + DT_CLK(NULL, "fdif_fclk", "fdif_fclk"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "hsi_fclk", "hsi_fclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "mcasp_gfclk", "mcasp_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "mcbsp1_gfclk", "mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "mcbsp2_gfclk", "mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "mcbsp3_gfclk", "mcbsp3_gfclk"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk", "mmc1_fclk"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk", "mmc2_fclk"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.2", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.3", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.4", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.9", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.10", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.11", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.5", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.6", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.7", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.8", "sys_ck", "dss_syc_gfclk_div"), + { .node_name = NULL }, +}; + +int __init omap5xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap54xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_m2_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ/2); + if (rc) + pr_err("%s: failed to set USB_DPLL M2 OUT\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c new file mode 100644 index 000000000000..9977653f2d63 --- /dev/null +++ b/drivers/clk/ti/clk-7xx.c @@ -0,0 +1,332 @@ +/* + * DRA7 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> + +#define DRA7_DPLL_ABE_DEFFREQ 361267200 +#define DRA7_DPLL_GMAC_DEFFREQ 1000000000 + + +static struct ti_dt_clk dra7xx_clks[] = { + DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), + DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), + DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"), + DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"), + DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"), + DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"), + DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"), + DT_CLK(NULL, "pciesref_acs_clk_ck", "pciesref_acs_clk_ck"), + DT_CLK(NULL, "ref_clkin0_ck", "ref_clkin0_ck"), + DT_CLK(NULL, "ref_clkin1_ck", "ref_clkin1_ck"), + DT_CLK(NULL, "ref_clkin2_ck", "ref_clkin2_ck"), + DT_CLK(NULL, "ref_clkin3_ck", "ref_clkin3_ck"), + DT_CLK(NULL, "rmii_clk_ck", "rmii_clk_ck"), + DT_CLK(NULL, "sdvenc_clkin_ck", "sdvenc_clkin_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_20000000_ck", "virt_20000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin1", "sys_clkin1"), + DT_CLK(NULL, "sys_clkin2", "sys_clkin2"), + DT_CLK(NULL, "usb_otg_clkin_ck", "usb_otg_clkin_ck"), + DT_CLK(NULL, "video1_clkin_ck", "video1_clkin_ck"), + DT_CLK(NULL, "video1_m2_clkin_ck", "video1_m2_clkin_ck"), + DT_CLK(NULL, "video2_clkin_ck", "video2_clkin_ck"), + DT_CLK(NULL, "video2_m2_clkin_ck", "video2_m2_clkin_ck"), + DT_CLK(NULL, "abe_dpll_sys_clk_mux", "abe_dpll_sys_clk_mux"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "abe_giclk_div", "abe_giclk_div"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "abe_sys_clk_div", "abe_sys_clk_div"), + DT_CLK(NULL, "adc_gfclk_mux", "adc_gfclk_mux"), + DT_CLK(NULL, "dpll_pcie_ref_ck", "dpll_pcie_ref_ck"), + DT_CLK(NULL, "dpll_pcie_ref_m2ldo_ck", "dpll_pcie_ref_m2ldo_ck"), + DT_CLK(NULL, "apll_pcie_ck", "apll_pcie_ck"), + DT_CLK(NULL, "apll_pcie_clkvcoldo", "apll_pcie_clkvcoldo"), + DT_CLK(NULL, "apll_pcie_clkvcoldo_div", "apll_pcie_clkvcoldo_div"), + DT_CLK(NULL, "apll_pcie_m2_ck", "apll_pcie_m2_ck"), + DT_CLK(NULL, "sys_clk1_dclk_div", "sys_clk1_dclk_div"), + DT_CLK(NULL, "sys_clk2_dclk_div", "sys_clk2_dclk_div"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "per_abe_x1_dclk_div", "per_abe_x1_dclk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "mpu_dclk_div", "mpu_dclk_div"), + DT_CLK(NULL, "dsp_dpll_hs_clk_div", "dsp_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_dsp_ck", "dpll_dsp_ck"), + DT_CLK(NULL, "dpll_dsp_m2_ck", "dpll_dsp_m2_ck"), + DT_CLK(NULL, "dsp_gclk_div", "dsp_gclk_div"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_m2_ck", "dpll_iva_m2_ck"), + DT_CLK(NULL, "iva_dclk", "iva_dclk"), + DT_CLK(NULL, "dpll_gpu_ck", "dpll_gpu_ck"), + DT_CLK(NULL, "dpll_gpu_m2_ck", "dpll_gpu_m2_ck"), + DT_CLK(NULL, "gpu_dclk", "gpu_dclk"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "core_dpll_out_dclk_div", "core_dpll_out_dclk_div"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "emif_phy_dclk_div", "emif_phy_dclk_div"), + DT_CLK(NULL, "dpll_gmac_ck", "dpll_gmac_ck"), + DT_CLK(NULL, "dpll_gmac_m2_ck", "dpll_gmac_m2_ck"), + DT_CLK(NULL, "gmac_250m_dclk_div", "gmac_250m_dclk_div"), + DT_CLK(NULL, "video2_dclk_div", "video2_dclk_div"), + DT_CLK(NULL, "video1_dclk_div", "video1_dclk_div"), + DT_CLK(NULL, "hdmi_dclk_div", "hdmi_dclk_div"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "func_96m_aon_dclk_div", "func_96m_aon_dclk_div"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "l3init_480m_dclk_div", "l3init_480m_dclk_div"), + DT_CLK(NULL, "usb_otg_dclk_div", "usb_otg_dclk_div"), + DT_CLK(NULL, "sata_dclk_div", "sata_dclk_div"), + DT_CLK(NULL, "dpll_pcie_ref_m2_ck", "dpll_pcie_ref_m2_ck"), + DT_CLK(NULL, "pcie2_dclk_div", "pcie2_dclk_div"), + DT_CLK(NULL, "pcie_dclk_div", "pcie_dclk_div"), + DT_CLK(NULL, "emu_dclk_div", "emu_dclk_div"), + DT_CLK(NULL, "secure_32k_dclk_div", "secure_32k_dclk_div"), + DT_CLK(NULL, "eve_dpll_hs_clk_div", "eve_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_eve_ck", "dpll_eve_ck"), + DT_CLK(NULL, "dpll_eve_m2_ck", "dpll_eve_m2_ck"), + DT_CLK(NULL, "eve_dclk_div", "eve_dclk_div"), + DT_CLK(NULL, "clkoutmux0_clk_mux", "clkoutmux0_clk_mux"), + DT_CLK(NULL, "clkoutmux1_clk_mux", "clkoutmux1_clk_mux"), + DT_CLK(NULL, "clkoutmux2_clk_mux", "clkoutmux2_clk_mux"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_h11x2_ck", "dpll_ddr_h11x2_ck"), + DT_CLK(NULL, "dpll_dsp_x2_ck", "dpll_dsp_x2_ck"), + DT_CLK(NULL, "dpll_dsp_m3x2_ck", "dpll_dsp_m3x2_ck"), + DT_CLK(NULL, "dpll_gmac_x2_ck", "dpll_gmac_x2_ck"), + DT_CLK(NULL, "dpll_gmac_h11x2_ck", "dpll_gmac_h11x2_ck"), + DT_CLK(NULL, "dpll_gmac_h12x2_ck", "dpll_gmac_h12x2_ck"), + DT_CLK(NULL, "dpll_gmac_h13x2_ck", "dpll_gmac_h13x2_ck"), + DT_CLK(NULL, "dpll_gmac_m3x2_ck", "dpll_gmac_m3x2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h13x2_ck", "dpll_per_h13x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "eve_clk", "eve_clk"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "gmii_m_clk_div", "gmii_m_clk_div"), + DT_CLK(NULL, "hdmi_clk2_div", "hdmi_clk2_div"), + DT_CLK(NULL, "hdmi_div_clk", "hdmi_div_clk"), + DT_CLK(NULL, "hdmi_dpll_clk_mux", "hdmi_dpll_clk_mux"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "mlb_clk", "mlb_clk"), + DT_CLK(NULL, "mlbp_clk", "mlbp_clk"), + DT_CLK(NULL, "per_abe_x1_gfclk2_div", "per_abe_x1_gfclk2_div"), + DT_CLK(NULL, "timer_sys_clk_div", "timer_sys_clk_div"), + DT_CLK(NULL, "video1_clk2_div", "video1_clk2_div"), + DT_CLK(NULL, "video1_div_clk", "video1_div_clk"), + DT_CLK(NULL, "video1_dpll_clk_mux", "video1_dpll_clk_mux"), + DT_CLK(NULL, "video2_clk2_div", "video2_clk2_div"), + DT_CLK(NULL, "video2_div_clk", "video2_div_clk"), + DT_CLK(NULL, "video2_dpll_clk_mux", "video2_dpll_clk_mux"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_hdmi_clk", "dss_hdmi_clk"), + DT_CLK(NULL, "dss_video1_clk", "dss_video1_clk"), + DT_CLK(NULL, "dss_video2_clk", "dss_video2_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "mmc1_clk32k", "mmc1_clk32k"), + DT_CLK(NULL, "mmc2_clk32k", "mmc2_clk32k"), + DT_CLK(NULL, "mmc3_clk32k", "mmc3_clk32k"), + DT_CLK(NULL, "mmc4_clk32k", "mmc4_clk32k"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "usb_otg_ss1_refclk960m", "usb_otg_ss1_refclk960m"), + DT_CLK(NULL, "usb_otg_ss2_refclk960m", "usb_otg_ss2_refclk960m"), + DT_CLK(NULL, "usb_phy1_always_on_clk32k", "usb_phy1_always_on_clk32k"), + DT_CLK(NULL, "usb_phy2_always_on_clk32k", "usb_phy2_always_on_clk32k"), + DT_CLK(NULL, "usb_phy3_always_on_clk32k", "usb_phy3_always_on_clk32k"), + DT_CLK(NULL, "atl_dpll_clk_mux", "atl_dpll_clk_mux"), + DT_CLK(NULL, "atl_gfclk_mux", "atl_gfclk_mux"), + DT_CLK(NULL, "dcan1_sys_clk_mux", "dcan1_sys_clk_mux"), + DT_CLK(NULL, "gmac_gmii_ref_clk_div", "gmac_gmii_ref_clk_div"), + DT_CLK(NULL, "gmac_rft_clk_mux", "gmac_rft_clk_mux"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1_gfclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "mcasp1_ahclkr_mux", "mcasp1_ahclkr_mux"), + DT_CLK(NULL, "mcasp1_ahclkx_mux", "mcasp1_ahclkx_mux"), + DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "mcasp1_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp2_ahclkr_mux", "mcasp2_ahclkr_mux"), + DT_CLK(NULL, "mcasp2_ahclkx_mux", "mcasp2_ahclkx_mux"), + DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "mcasp2_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp3_ahclkx_mux", "mcasp3_ahclkx_mux"), + DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "mcasp3_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp4_ahclkx_mux", "mcasp4_ahclkx_mux"), + DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "mcasp4_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp5_ahclkx_mux", "mcasp5_ahclkx_mux"), + DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "mcasp5_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp6_ahclkx_mux", "mcasp6_ahclkx_mux"), + DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "mcasp6_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp7_ahclkx_mux", "mcasp7_ahclkx_mux"), + DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "mcasp7_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp8_ahclk_mux", "mcasp8_ahclk_mux"), + DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "mcasp8_aux_gfclk_mux"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk_div", "mmc1_fclk_div"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk_div", "mmc2_fclk_div"), + DT_CLK(NULL, "mmc3_gfclk_mux", "mmc3_gfclk_mux"), + DT_CLK(NULL, "mmc3_gfclk_div", "mmc3_gfclk_div"), + DT_CLK(NULL, "mmc4_gfclk_mux", "mmc4_gfclk_mux"), + DT_CLK(NULL, "mmc4_gfclk_div", "mmc4_gfclk_div"), + DT_CLK(NULL, "qspi_gfclk_mux", "qspi_gfclk_mux"), + DT_CLK(NULL, "qspi_gfclk_div", "qspi_gfclk_div"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer13_gfclk_mux", "timer13_gfclk_mux"), + DT_CLK(NULL, "timer14_gfclk_mux", "timer14_gfclk_mux"), + DT_CLK(NULL, "timer15_gfclk_mux", "timer15_gfclk_mux"), + DT_CLK(NULL, "timer16_gfclk_mux", "timer16_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "uart10_gfclk_mux", "uart10_gfclk_mux"), + DT_CLK(NULL, "uart1_gfclk_mux", "uart1_gfclk_mux"), + DT_CLK(NULL, "uart2_gfclk_mux", "uart2_gfclk_mux"), + DT_CLK(NULL, "uart3_gfclk_mux", "uart3_gfclk_mux"), + DT_CLK(NULL, "uart4_gfclk_mux", "uart4_gfclk_mux"), + DT_CLK(NULL, "uart5_gfclk_mux", "uart5_gfclk_mux"), + DT_CLK(NULL, "uart6_gfclk_mux", "uart6_gfclk_mux"), + DT_CLK(NULL, "uart7_gfclk_mux", "uart7_gfclk_mux"), + DT_CLK(NULL, "uart8_gfclk_mux", "uart8_gfclk_mux"), + DT_CLK(NULL, "uart9_gfclk_mux", "uart9_gfclk_mux"), + DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"), + DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"), + DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK(NULL, "sys_clkin", "sys_clkin1"), + { .node_name = NULL }, +}; + +int __init dra7xx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck; + + ti_dt_clocks_register(dra7xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_mux = clk_get_sys(NULL, "abe_dpll_sys_clk_mux"); + sys_clkin2 = clk_get_sys(NULL, "sys_clkin2"); + dpll_ck = clk_get_sys(NULL, "dpll_abe_ck"); + + rc = clk_set_parent(abe_dpll_mux, sys_clkin2); + if (!rc) + rc = clk_set_rate(dpll_ck, DRA7_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + dpll_ck = clk_get_sys(NULL, "dpll_gmac_ck"); + rc = clk_set_rate(dpll_ck, DRA7_DPLL_GMAC_DEFFREQ); + if (rc) + pr_err("%s: failed to configure GMAC DPLL!\n", __func__); + + return rc; +} diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c new file mode 100644 index 000000000000..b1a6f7144f3f --- /dev/null +++ b/drivers/clk/ti/clk.c @@ -0,0 +1,167 @@ +/* + * TI clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/list.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int ti_dt_clk_memmap_index; +struct ti_clk_ll_ops *ti_clk_ll_ops; + +/** + * ti_dt_clocks_register - register DT alias clocks during boot + * @oclks: list of clocks to register + * + * Register alias or non-standard DT clock entries during boot. By + * default, DT clocks are found based on their node name. If any + * additional con-id / dev-id -> clock mapping is required, use this + * function to list these. + */ +void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) +{ + struct ti_dt_clk *c; + struct device_node *node; + struct clk *clk; + struct of_phandle_args clkspec; + + for (c = oclks; c->node_name != NULL; c++) { + node = of_find_node_by_name(NULL, c->node_name); + clkspec.np = node; + clk = of_clk_get_from_provider(&clkspec); + + if (!IS_ERR(clk)) { + c->lk.clk = clk; + clkdev_add(&c->lk); + } else { + pr_warn("failed to lookup clock node %s\n", + c->node_name); + } + } +} + +struct clk_init_item { + struct device_node *node; + struct clk_hw *hw; + ti_of_clk_init_cb_t func; + struct list_head link; +}; + +static LIST_HEAD(retry_list); + +/** + * ti_clk_retry_init - retries a failed clock init at later phase + * @node: device not for the clock + * @hw: partially initialized clk_hw struct for the clock + * @func: init function to be called for the clock + * + * Adds a failed clock init to the retry list. The retry list is parsed + * once all the other clocks have been initialized. + */ +int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func) +{ + struct clk_init_item *retry; + + pr_debug("%s: adding to retry list...\n", node->name); + retry = kzalloc(sizeof(*retry), GFP_KERNEL); + if (!retry) + return -ENOMEM; + + retry->node = node; + retry->func = func; + retry->hw = hw; + list_add(&retry->link, &retry_list); + + return 0; +} + +/** + * ti_clk_get_reg_addr - get register address for a clock register + * @node: device node for the clock + * @index: register index from the clock node + * + * Builds clock register address from device tree information. This + * is a struct of type clk_omap_reg. + */ +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) +{ + struct clk_omap_reg *reg; + u32 val; + u32 tmp; + + reg = (struct clk_omap_reg *)&tmp; + reg->index = ti_dt_clk_memmap_index; + + if (of_property_read_u32_index(node, "reg", index, &val)) { + pr_err("%s must have reg[%d]!\n", node->name, index); + return NULL; + } + + reg->offset = val; + + return (void __iomem *)tmp; +} + +/** + * ti_dt_clk_init_provider - init master clock provider + * @parent: master node + * @index: internal index for clk_reg_ops + * + * Initializes a master clock IP block and its child clock nodes. + * Regmap is provided for accessing the register space for the + * IP block and all the clocks under it. + */ +void ti_dt_clk_init_provider(struct device_node *parent, int index) +{ + const struct of_device_id *match; + struct device_node *np; + struct device_node *clocks; + of_clk_init_cb_t clk_init_cb; + struct clk_init_item *retry; + struct clk_init_item *tmp; + + ti_dt_clk_memmap_index = index; + + /* get clocks for this parent */ + clocks = of_get_child_by_name(parent, "clocks"); + if (!clocks) { + pr_err("%s missing 'clocks' child node.\n", parent->name); + return; + } + + for_each_child_of_node(clocks, np) { + match = of_match_node(&__clk_of_table, np); + if (!match) + continue; + clk_init_cb = (of_clk_init_cb_t)match->data; + pr_debug("%s: initializing: %s\n", __func__, np->name); + clk_init_cb(np); + } + + list_for_each_entry_safe(retry, tmp, &retry_list, link) { + pr_debug("retry-init: %s\n", retry->node->name); + retry->func(retry->hw, retry->node); + list_del(&retry->link); + kfree(retry); + } +} diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c new file mode 100644 index 000000000000..f1e0038d76ac --- /dev/null +++ b/drivers/clk/ti/clockdomain.c @@ -0,0 +1,70 @@ +/* + * OMAP clockdomain support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static void __init of_ti_clockdomain_setup(struct device_node *node) +{ + struct clk *clk; + struct clk_hw *clk_hw; + const char *clkdm_name = node->name; + int i; + int num_clks; + + num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells"); + + for (i = 0; i < num_clks; i++) { + clk = of_clk_get(node, i); + if (__clk_get_flags(clk) & CLK_IS_BASIC) { + pr_warn("can't setup clkdm for basic clk %s\n", + __clk_get_name(clk)); + continue; + } + clk_hw = __clk_get_hw(clk); + to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name; + omap2_init_clk_clkdm(clk_hw); + } +} + +static struct of_device_id ti_clkdm_match_table[] __initdata = { + { .compatible = "ti,clockdomain" }, + { } +}; + +/** + * ti_dt_clockdomains_setup - setup device tree clockdomains + * + * Initializes clockdomain nodes for a SoC. This parses through all the + * nodes with compatible = "ti,clockdomain", and add the clockdomain + * info for all the clocks listed under these. This function shall be + * called after rest of the DT clock init has completed and all + * clock nodes have been registered. + */ +void __init ti_dt_clockdomains_setup(void) +{ + struct device_node *np; + for_each_matching_node(np, ti_clkdm_match_table) { + of_ti_clockdomain_setup(np); + } +} diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c new file mode 100644 index 000000000000..19d8980ba458 --- /dev/null +++ b/drivers/clk/ti/composite.c @@ -0,0 +1,269 @@ +/* + * TI composite clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> +#include <linux/list.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return ti_clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return -EINVAL; +} + +static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return -EINVAL; +} + +static const struct clk_ops ti_composite_divider_ops = { + .recalc_rate = &ti_composite_recalc_rate, + .round_rate = &ti_composite_round_rate, + .set_rate = &ti_composite_set_rate, +}; + +static const struct clk_ops ti_composite_gate_ops = { + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +struct component_clk { + int num_parents; + const char **parent_names; + struct device_node *node; + int type; + struct clk_hw *hw; + struct list_head link; +}; + +static const char * __initconst component_clk_types[] = { + "gate", "divider", "mux" +}; + +static LIST_HEAD(component_clks); + +static struct device_node *_get_component_node(struct device_node *node, int i) +{ + int rc; + struct of_phandle_args clkspec; + + rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i, + &clkspec); + if (rc) + return NULL; + + return clkspec.np; +} + +static struct component_clk *_lookup_component(struct device_node *node) +{ + struct component_clk *comp; + + list_for_each_entry(comp, &component_clks, link) { + if (comp->node == node) + return comp; + } + return NULL; +} + +struct clk_hw_omap_comp { + struct clk_hw hw; + struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX]; + struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX]; +}; + +static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) +{ + if (!clk) + return NULL; + + if (!clk->comp_clks[idx]) + return NULL; + + return clk->comp_clks[idx]->hw; +} + +#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw) + +static void __init ti_clk_register_composite(struct clk_hw *hw, + struct device_node *node) +{ + struct clk *clk; + struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); + struct component_clk *comp; + int num_parents = 0; + const char **parent_names = NULL; + int i; + + /* Check for presence of each component clock */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_nodes[i]) + continue; + + comp = _lookup_component(cclk->comp_nodes[i]); + if (!comp) { + pr_debug("component %s not ready for %s, retry\n", + cclk->comp_nodes[i]->name, node->name); + if (!ti_clk_retry_init(node, hw, + ti_clk_register_composite)) + return; + + goto cleanup; + } + if (cclk->comp_clks[comp->type] != NULL) { + pr_err("duplicate component types for %s (%s)!\n", + node->name, component_clk_types[comp->type]); + goto cleanup; + } + + cclk->comp_clks[comp->type] = comp; + + /* Mark this node as found */ + cclk->comp_nodes[i] = NULL; + } + + /* All components exists, proceed with registration */ + for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) { + comp = cclk->comp_clks[i]; + if (!comp) + continue; + if (comp->num_parents) { + num_parents = comp->num_parents; + parent_names = comp->parent_names; + break; + } + } + + if (!num_parents) { + pr_err("%s: no parents found for %s!\n", __func__, node->name); + goto cleanup; + } + + clk = clk_register_composite(NULL, node->name, + parent_names, num_parents, + _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), + &ti_clk_mux_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), + &ti_composite_divider_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), + &ti_composite_gate_ops, 0); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + +cleanup: + /* Free component clock list entries */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_clks[i]) + continue; + list_del(&cclk->comp_clks[i]->link); + kfree(cclk->comp_clks[i]); + } + + kfree(cclk); +} + +static void __init of_ti_composite_clk_setup(struct device_node *node) +{ + int num_clks; + int i; + struct clk_hw_omap_comp *cclk; + + /* Number of component clocks to be put inside this clock */ + num_clks = of_clk_get_parent_count(node); + + if (num_clks < 1) { + pr_err("composite clk %s must have component(s)\n", node->name); + return; + } + + cclk = kzalloc(sizeof(*cclk), GFP_KERNEL); + if (!cclk) + return; + + /* Get device node pointers for each component clock */ + for (i = 0; i < num_clks; i++) + cclk->comp_nodes[i] = _get_component_node(node, i); + + ti_clk_register_composite(&cclk->hw, node); +} +CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", + of_ti_composite_clk_setup); + +/** + * ti_clk_add_component - add a component clock to the pool + * @node: device node of the component clock + * @hw: hardware clock definition for the component clock + * @type: type of the component clock + * + * Adds a component clock to the list of available components, so that + * it can be registered by a composite clock. + */ +int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, + int type) +{ + int num_parents; + const char **parent_names; + struct component_clk *clk; + int i; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 1) { + pr_err("component-clock %s must have parent(s)\n", node->name); + return -EINVAL; + } + + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + kfree(parent_names); + return -ENOMEM; + } + + clk->num_parents = num_parents; + clk->parent_names = parent_names; + clk->hw = hw; + clk->node = node; + clk->type = type; + list_add(&clk->link, &component_clks); + + return 0; +} diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c new file mode 100644 index 000000000000..a15e445570b2 --- /dev/null +++ b/drivers/clk/ti/divider.c @@ -0,0 +1,487 @@ +/* + * TI Divider Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#define div_mask(d) ((1 << ((d)->width)) - 1) + +static unsigned int _get_table_maxdiv(const struct clk_div_table *table) +{ + unsigned int maxdiv = 0; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; +} + +static unsigned int _get_maxdiv(struct clk_divider *divider) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div_mask(divider); + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << div_mask(divider); + if (divider->table) + return _get_table_maxdiv(divider->table); + return div_mask(divider) + 1; +} + +static unsigned int _get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int _get_div(struct clk_divider *divider, unsigned int val) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return val; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << val; + if (divider->table) + return _get_table_div(divider->table, val); + return val + 1; +} + +static unsigned int _get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned int _get_val(struct clk_divider *divider, u8 div) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return __ffs(div); + if (divider->table) + return _get_table_val(divider->table, div); + return div - 1; +} + +static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, val; + + val = ti_clk_ll_ops->clk_readl(divider->reg) >> divider->shift; + val &= div_mask(divider); + + div = _get_div(divider, val); + if (!div) { + WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), + "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + __clk_get_name(hw->clk)); + return parent_rate; + } + + return parent_rate / div; +} + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +static bool _is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static bool _is_valid_div(struct clk_divider *divider, unsigned int div) +{ + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return is_power_of_2(div); + if (divider->table) + return _is_valid_table_div(divider->table, div); + return true; +} + +static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + unsigned long parent_rate_saved = *best_parent_rate; + + if (!rate) + rate = 1; + + maxdiv = _get_maxdiv(divider); + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + if (!_is_valid_div(divider, i)) + continue; + if (rate * i == parent_rate_saved) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return i; + } + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = _get_maxdiv(divider); + *best_parent_rate = + __clk_round_rate(__clk_get_parent(hw->clk), 1); + } + + return bestdiv; +} + +static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div; + div = ti_clk_divider_bestdiv(hw, rate, prate); + + return *prate / div; +} + +static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, value; + unsigned long flags = 0; + u32 val; + + div = parent_rate / rate; + value = _get_val(divider, div); + + if (value > div_mask(divider)) + value = div_mask(divider); + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = div_mask(divider) << (divider->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + } + val |= value << divider->shift; + ti_clk_ll_ops->clk_writel(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_divider_ops = { + .recalc_rate = ti_clk_divider_recalc_rate, + .round_rate = ti_clk_divider_round_rate, + .set_rate = ti_clk_divider_set_rate, +}; + +static struct clk *_register_divider(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, void __iomem *reg, + u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_divider *div; + struct clk *clk; + struct clk_init_data init; + + if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { + if (width + shift > 16) { + pr_warn("divider value exceeds LOWORD field\n"); + return ERR_PTR(-EINVAL); + } + } + + /* allocate the divider */ + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + pr_err("%s: could not allocate divider clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_divider_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_divider assignments */ + div->reg = reg; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + /* register the clock */ + clk = clk_register(dev, &div->hw); + + if (IS_ERR(clk)) + kfree(div); + + return clk; +} + +static struct clk_div_table +__init *ti_clk_get_div_table(struct device_node *node) +{ + struct clk_div_table *table; + const __be32 *divspec; + u32 val; + u32 num_div; + u32 valid_div; + int i; + + divspec = of_get_property(node, "ti,dividers", &num_div); + + if (!divspec) + return NULL; + + num_div /= 4; + + valid_div = 0; + + /* Determine required size for divider table */ + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) + valid_div++; + } + + if (!valid_div) { + pr_err("no valid dividers for %s table\n", node->name); + return ERR_PTR(-EINVAL); + } + + table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + valid_div = 0; + + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) { + table[valid_div].div = val; + table[valid_div].val = i; + valid_div++; + } + } + + return table; +} + +static int _get_divider_width(struct device_node *node, + const struct clk_div_table *table, + u8 flags) +{ + u32 min_div; + u32 max_div; + u32 val = 0; + u32 div; + + if (!table) { + /* Clk divider table not provided, determine min/max divs */ + if (of_property_read_u32(node, "ti,min-div", &min_div)) + min_div = 1; + + if (of_property_read_u32(node, "ti,max-div", &max_div)) { + pr_err("no max-div for %s!\n", node->name); + return -EINVAL; + } + + /* Determine bit width for the field */ + if (flags & CLK_DIVIDER_ONE_BASED) + val = 1; + + div = min_div; + + while (div < max_div) { + if (flags & CLK_DIVIDER_POWER_OF_TWO) + div <<= 1; + else + div++; + val++; + } + } else { + div = 0; + + while (table[div].div) { + val = table[div].val; + div++; + } + } + + return fls(val); +} + +static int __init ti_clk_divider_populate(struct device_node *node, + void __iomem **reg, const struct clk_div_table **table, + u32 *flags, u8 *div_flags, u8 *width, u8 *shift) +{ + u32 val; + + *reg = ti_clk_get_reg_addr(node, 0); + if (!*reg) + return -EINVAL; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + *shift = val; + else + *shift = 0; + + *flags = 0; + *div_flags = 0; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + *div_flags |= CLK_DIVIDER_ONE_BASED; + + if (of_property_read_bool(node, "ti,index-power-of-two")) + *div_flags |= CLK_DIVIDER_POWER_OF_TWO; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + *flags |= CLK_SET_RATE_PARENT; + + *table = ti_clk_get_div_table(node); + + if (IS_ERR(*table)) + return PTR_ERR(*table); + + *width = _get_divider_width(node, *table, *div_flags); + + return 0; +} + +/** + * of_ti_divider_clk_setup - Setup function for simple div rate clock + * @node: device node for this clock + * + * Sets up a basic divider clock. + */ +static void __init of_ti_divider_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *parent_name; + void __iomem *reg; + u8 clk_divider_flags = 0; + u8 width = 0; + u8 shift = 0; + const struct clk_div_table *table = NULL; + u32 flags = 0; + + parent_name = of_clk_get_parent_name(node, 0); + + if (ti_clk_divider_populate(node, ®, &table, &flags, + &clk_divider_flags, &width, &shift)) + goto cleanup; + + clk = _register_divider(NULL, node->name, parent_name, flags, reg, + shift, width, clk_divider_flags, table, NULL); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + return; + } + +cleanup: + kfree(table); +} +CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup); + +static void __init of_ti_composite_divider_clk_setup(struct device_node *node) +{ + struct clk_divider *div; + u32 val; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return; + + if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, + &div->flags, &div->width, &div->shift) < 0) + goto cleanup; + + if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) + return; + +cleanup: + kfree(div->table); + kfree(div); +} +CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock", + of_ti_composite_divider_clk_setup); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c new file mode 100644 index 000000000000..7e498a44f97d --- /dev/null +++ b/drivers/clk/ti/dpll.c @@ -0,0 +1,558 @@ +/* + * OMAP DPLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define DPLL_HAS_AUTOIDLE 0x1 + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static const struct clk_ops dpll_m4xen_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap4_dpll_regm4xen_recalc, + .round_rate = &omap4_dpll_regm4xen_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; +#endif + +static const struct clk_ops dpll_core_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_core_ck_ops = { + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; + +static const struct clk_ops dpll_no_gate_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_noncore_dpll_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; + +static const struct clk_ops omap3_dpll_per_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_dpll4_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_x2_ck_ops = { + .recalc_rate = &omap3_clkoutx2_recalc, +}; + +/** + * ti_clk_register_dpll - low level registration of a DPLL clock + * @hw: hardware clock definition for the clock + * @node: device node for the clock + * + * Finalizes DPLL registration process. In case a failure (clk-ref or + * clk-bypass is missing), the clock is added to retry list and + * the initialization is retried on later stage. + */ +static void __init ti_clk_register_dpll(struct clk_hw *hw, + struct device_node *node) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *dd = clk_hw->dpll_data; + struct clk *clk; + + dd->clk_ref = of_clk_get(node, 0); + dd->clk_bypass = of_clk_get(node, 1); + + if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { + pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", + node->name); + if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll)) + return; + + goto cleanup; + } + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) +/** + * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock + * @node: device node for this clock + * @ops: clk_ops for this clock + * @hw_ops: clk_hw_ops for this clock + * + * Initializes a DPLL x 2 clock from device tree data. + */ +static void ti_clk_register_dpll_x2(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *name = node->name; + const char *parent_name; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have parent\n", node->name); + return; + } + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->ops = hw_ops; + clk_hw->hw.init = &init; + + init.name = name; + init.ops = ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (IS_ERR(clk)) { + kfree(clk_hw); + } else { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + } +} +#endif + +/** + * of_ti_dpll_setup - Setup function for OMAP DPLL clocks + * @node: device node containing the DPLL info + * @ops: ops for the DPLL + * @ddt: DPLL data template to use + * @init_flags: flags for controlling init types + * + * Initializes a DPLL clock from device tree data. + */ +static void __init of_ti_dpll_setup(struct device_node *node, + const struct clk_ops *ops, + const struct dpll_data *ddt, + u8 init_flags) +{ + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + struct dpll_data *dd = NULL; + int i; + u8 dpll_mode = 0; + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!dd || !clk_hw || !init) + goto cleanup; + + memcpy(dd, ddt, sizeof(*dd)); + + clk_hw->dpll_data = dd; + clk_hw->ops = &clkhwops_omap3_dpll; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("%s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + dd->control_reg = ti_clk_get_reg_addr(node, 0); + dd->idlest_reg = ti_clk_get_reg_addr(node, 1); + dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); + + if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg) + goto cleanup; + + if (init_flags & DPLL_HAS_AUTOIDLE) { + dd->autoidle_reg = ti_clk_get_reg_addr(node, 3); + if (!dd->autoidle_reg) + goto cleanup; + } + + if (of_property_read_bool(node, "ti,low-power-stop")) + dpll_mode |= 1 << DPLL_LOW_POWER_STOP; + + if (of_property_read_bool(node, "ti,low-power-bypass")) + dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS; + + if (of_property_read_bool(node, "ti,lock")) + dpll_mode |= 1 << DPLL_LOCKED; + + if (dpll_mode) + dd->modes = dpll_mode; + + ti_clk_register_dpll(&clk_hw->hw, node); + return; + +cleanup: + kfree(dd); + kfree(parent_names); + kfree(init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) +{ + ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); +} +CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", + of_ti_omap4_dpll_x2_setup); +#endif + +#ifdef CONFIG_SOC_AM33XX +static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) +{ + ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL); +} +CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", + of_ti_am3_dpll_x2_setup); +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_omap3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock", + of_ti_omap3_dpll_setup); + +static void __init of_ti_omap3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 16, + .div1_mask = 0x7f << 8, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + }; + + of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock", + of_ti_omap3_core_dpll_setup); + +static void __init of_ti_omap3_per_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf00000, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock", + of_ti_omap3_per_dpll_setup); + +static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0xfff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 128, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .dco_mask = 0xe << 20, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock", + of_ti_omap3_per_jtype_dpll_setup); +#endif + +static void __init of_ti_omap4_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock", + of_ti_omap4_dpll_setup); + +static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock", + of_ti_omap4_core_dpll_setup); + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .m4xen_mask = 0x800, + .lpmode_mask = 1 << 10, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock", + of_ti_omap4_m4xen_dpll_setup); + +static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0xfff << 8, + .div1_mask = 0xff, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock", + of_ti_omap4_jtype_dpll_setup); +#endif + +static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock", + of_ti_am3_no_gate_dpll_setup); + +static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 2, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock", + of_ti_am3_jtype_dpll_setup); + +static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock, + "ti,am3-dpll-no-gate-j-type-clock", + of_ti_am3_no_gate_jtype_dpll_setup); + +static void __init of_ti_am3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup); + +static void __init of_ti_am3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock", + of_ti_am3_core_dpll_setup); diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c new file mode 100644 index 000000000000..c2c8a287408c --- /dev/null +++ b/drivers/clk/ti/fixed-factor.c @@ -0,0 +1,66 @@ +/* + * TI Fixed Factor Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +/** + * of_ti_fixed_factor_clk_setup - Setup function for TI fixed factor clock + * @node: device node for this clock + * + * Sets up a simple fixed factor clock based on device tree info. + */ +static void __init of_ti_fixed_factor_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *parent_name; + u32 div, mult; + u32 flags = 0; + + if (of_property_read_u32(node, "ti,clock-div", &div)) { + pr_err("%s must have a clock-div property\n", node->name); + return; + } + + if (of_property_read_u32(node, "ti,clock-mult", &mult)) { + pr_err("%s must have a clock-mult property\n", node->name); + return; + } + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + parent_name = of_clk_get_parent_name(node, 0); + + clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, + mult, div); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + } +} +CLK_OF_DECLARE(ti_fixed_factor_clk, "ti,fixed-factor-clock", + of_ti_fixed_factor_clk_setup); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c new file mode 100644 index 000000000000..3e2999d11d15 --- /dev/null +++ b/drivers/clk/ti/gate.c @@ -0,0 +1,249 @@ +/* + * OMAP gate clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk); + +static const struct clk_ops omap_gate_clkdm_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_clkops_enable_clkdm, + .disable = &omap2_clkops_disable_clkdm, +}; + +static const struct clk_ops omap_gate_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap36xx_gate_clk_enable_with_hsdiv_restore, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +/** + * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering + * from HSDivider PWRDN problem Implements Errata ID: i556. + * @clk: DPLL output struct clk + * + * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, + * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset + * valueafter their respective PWRDN bits are set. Any dummy write + * (Any other value different from the Read value) to the + * corresponding CM_CLKSEL register will refresh the dividers. + */ +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk) +{ + struct clk_divider *parent; + struct clk_hw *parent_hw; + u32 dummy_v, orig_v; + int ret; + + /* Clear PWRDN bit of HSDIVIDER */ + ret = omap2_dflt_clk_enable(clk); + + /* Parent is the x2 node, get parent of parent for the m2 div */ + parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk))); + parent = to_clk_divider(parent_hw); + + /* Restore the dividers */ + if (!ret) { + orig_v = ti_clk_ll_ops->clk_readl(parent->reg); + dummy_v = orig_v; + + /* Write any other value different from the Read value */ + dummy_v ^= (1 << parent->shift); + ti_clk_ll_ops->clk_writel(dummy_v, parent->reg); + + /* Write the original divider */ + ti_clk_ll_ops->clk_writel(orig_v, parent->reg); + } + + return ret; +} + +static void __init _of_ti_gate_clk_setup(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *clk_name = node->name; + const char *parent_name; + u32 val; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + + init.name = clk_name; + init.ops = ops; + + if (ops != &omap_gate_clkdm_clk_ops) { + clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!clk_hw->enable_reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + clk_hw->enable_bit = val; + } + + clk_hw->ops = hw_ops; + + clk_hw->flags = MEMMAP_ADDRESSING; + + if (of_clk_get_parent_count(node) != 1) { + pr_err("%s must have 1 parent\n", clk_name); + goto cleanup; + } + + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + init.flags |= CLK_SET_RATE_PARENT; + + if (of_property_read_bool(node, "ti,set-bit-to-disable")) + clk_hw->flags |= INVERT_ENABLE; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init +_of_ti_composite_gate_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk_hw_omap *gate; + u32 val = 0; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return; + + gate->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!gate->enable_reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &val); + + gate->enable_bit = val; + gate->ops = hw_ops; + gate->flags = MEMMAP_ADDRESSING; + + if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE)) + return; + +cleanup: + kfree(gate); +} + +static void __init +of_ti_composite_no_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, NULL); +} +CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock", + of_ti_composite_no_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_composite_interface_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock", + of_ti_composite_interface_clk_setup); +#endif + +static void __init of_ti_composite_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock", + of_ti_composite_gate_clk_setup); + + +static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock", + of_ti_clkdm_gate_clk_setup); + +static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops, + &clkhwops_wait); +} +CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock", + of_ti_hsdiv_gate_clk_setup); + +static void __init of_ti_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup) + +static void __init of_ti_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock", + of_ti_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_am35xx_ipss_module_wait); +} +CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock", + of_ti_am35xx_gate_clk_setup); + +static void __init of_ti_dss_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_omap3430es2_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock", + of_ti_dss_gate_clk_setup); +#endif diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c new file mode 100644 index 000000000000..320a2b168bb2 --- /dev/null +++ b/drivers/clk/ti/interface.c @@ -0,0 +1,125 @@ +/* + * OMAP interface clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static const struct clk_ops ti_interface_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +static void __init _of_ti_interface_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *ops) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *parent_name; + u32 val; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + clk_hw->ops = ops; + clk_hw->flags = MEMMAP_ADDRESSING; + + clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!clk_hw->enable_reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + clk_hw->enable_bit = val; + + init.name = node->name; + init.ops = &ti_interface_clk_ops; + init.flags = 0; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have a parent\n", node->name); + goto cleanup; + } + + init.num_parents = 1; + init.parent_names = &parent_name; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + omap2_init_clk_hw_omap_clocks(clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init of_ti_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_interface_clk, "ti,omap3-interface-clock", + of_ti_interface_clk_setup); + +static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk); +} +CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock", + of_ti_no_wait_interface_clk_setup); + +static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_hsotgusb_wait); +} +CLK_OF_DECLARE(ti_hsotgusb_interface_clk, "ti,omap3-hsotgusb-interface-clock", + of_ti_hsotgusb_interface_clk_setup); + +static void __init of_ti_dss_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_interface_clk, "ti,omap3-dss-interface-clock", + of_ti_dss_interface_clk_setup); + +static void __init of_ti_ssi_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_omap3430es2_iclk_ssi_wait); +} +CLK_OF_DECLARE(ti_ssi_interface_clk, "ti,omap3-ssi-interface-clock", + of_ti_ssi_interface_clk_setup); + +static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_am35xx_ipss_wait); +} +CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock", + of_ti_am35xx_interface_clk_setup); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c new file mode 100644 index 000000000000..0197a478720c --- /dev/null +++ b/drivers/clk/ti/mux.c @@ -0,0 +1,246 @@ +/* + * TI Multiplexer Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static u8 ti_clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + int num_parents = __clk_get_num_parents(hw->clk); + u32 val; + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or + * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges + * from 0x1 to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" + */ + val = ti_clk_ll_ops->clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + if (mux->table) { + int i; + + for (i = 0; i < num_parents; i++) + if (mux->table[i] == val) + return i; + return -EINVAL; + } + + if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + val = ffs(val) - 1; + + if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + val--; + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->table) { + index = mux->table[index]; + } else { + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + } + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + + if (mux->flags & CLK_MUX_HIWORD_MASK) { + val = mux->mask << (mux->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(mux->reg); + val &= ~(mux->mask << mux->shift); + } + val |= index << mux->shift; + ti_clk_ll_ops->clk_writel(val, mux->reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_mux_ops = { + .get_parent = ti_clk_mux_get_parent, + .set_parent = ti_clk_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk *_register_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, + u8 shift, u32 mask, u8 clk_mux_flags, + u32 *table, spinlock_t *lock) +{ + struct clk_mux *mux; + struct clk *clk; + struct clk_init_data init; + + /* allocate the mux */ + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + pr_err("%s: could not allocate mux clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_mux_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + /* struct clk_mux assignments */ + mux->reg = reg; + mux->shift = shift; + mux->mask = mask; + mux->flags = clk_mux_flags; + mux->lock = lock; + mux->table = table; + mux->hw.init = &init; + + clk = clk_register(dev, &mux->hw); + + if (IS_ERR(clk)) + kfree(mux); + + return clk; +} + +/** + * of_mux_clk_setup - Setup function for simple mux rate clock + * @node: DT node for the clock + * + * Sets up a basic clock multiplexer. + */ +static void of_mux_clk_setup(struct device_node *node) +{ + struct clk *clk; + void __iomem *reg; + int num_parents; + const char **parent_names; + int i; + u8 clk_mux_flags = 0; + u32 mask = 0; + u32 shift = 0; + u32 flags = 0; + + num_parents = of_clk_get_parent_count(node); + if (num_parents < 2) { + pr_err("mux-clock %s must have parents\n", node->name); + return; + } + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + reg = ti_clk_get_reg_addr(node, 0); + + if (!reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &shift); + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + clk_mux_flags |= CLK_MUX_INDEX_ONE; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + /* Generate bit-mask based on parent info */ + mask = num_parents; + if (!(clk_mux_flags & CLK_MUX_INDEX_ONE)) + mask--; + + mask = (1 << fls(mask)) - 1; + + clk = _register_mux(NULL, node->name, parent_names, num_parents, flags, + reg, shift, mask, clk_mux_flags, NULL, NULL); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + +cleanup: + kfree(parent_names); +} +CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup); + +static void __init of_ti_composite_mux_clk_setup(struct device_node *node) +{ + struct clk_mux *mux; + int num_parents; + u32 val; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return; + + mux->reg = ti_clk_get_reg_addr(node, 0); + + if (!mux->reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + mux->shift = val; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + mux->flags |= CLK_MUX_INDEX_ONE; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 2) { + pr_err("%s must have parents\n", node->name); + goto cleanup; + } + + mux->mask = num_parents - 1; + mux->mask = (1 << fls(mux->mask)) - 1; + + if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX)) + return; + +cleanup: + kfree(mux); +} +CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock", + of_ti_composite_mux_clk_setup); diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 0e799516a2ab..eb6935c8ad94 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -523,11 +523,11 @@ static DEFINE_SPINLOCK(address_handler_list_lock); static LIST_HEAD(address_handler_list); const struct fw_address_region fw_high_memory_region = - { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; + { .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, }; EXPORT_SYMBOL(fw_high_memory_region); static const struct fw_address_region low_memory_region = - { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; + { .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, }; #if 0 const struct fw_address_region fw_private_region = @@ -1217,7 +1217,7 @@ static void handle_low_memory(struct fw_card *card, struct fw_request *request, } static struct fw_address_handler low_memory = { - .length = 0x000100000000ULL, + .length = FW_MAX_PHYSICAL_RANGE, .address_callback = handle_low_memory, }; diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 515a42c786d0..c98764aeeec6 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -237,6 +237,9 @@ static inline bool is_next_generation(int new_generation, int old_generation) #define LOCAL_BUS 0xffc0 +/* arbitrarily chosen maximum range for physical DMA: 128 TB */ +#define FW_MAX_PHYSICAL_RANGE (128ULL << 40) + void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); int fw_get_response_length(struct fw_request *request); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 6aa8a86cb83b..6f74d8d3f700 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -370,6 +370,10 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); +static bool param_remote_dma; +module_param_named(remote_dma, param_remote_dma, bool, 0444); +MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)"); + static void log_irqs(struct fw_ohci *ohci, u32 evt) { if (likely(!(param_debug & @@ -2050,10 +2054,10 @@ static void bus_reset_work(struct work_struct *work) be32_to_cpu(ohci->next_header)); } -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); - reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); -#endif + if (param_remote_dma) { + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); + } spin_unlock_irq(&ohci->lock); @@ -2363,7 +2367,7 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_FairnessControl, 0); card->priority_budget_implemented = ohci->pri_req_max != 0; - reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); + reg_write(ohci, OHCI1394_PhyUpperBound, FW_MAX_PHYSICAL_RANGE >> 16); reg_write(ohci, OHCI1394_IntEventClear, ~0); reg_write(ohci, OHCI1394_IntMaskClear, ~0); @@ -2587,13 +2591,13 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) static int ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) { -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - return 0; -#else struct fw_ohci *ohci = fw_ohci(card); unsigned long flags; int n, ret = 0; + if (param_remote_dma) + return 0; + /* * FIXME: Make sure this bitmask is cleared when we clear the busReset * interrupt bit. Clear physReqResourceAllBuses on bus reset. @@ -2622,7 +2626,6 @@ static int ohci_enable_phys_dma(struct fw_card *card, spin_unlock_irqrestore(&ohci->lock, flags); return ret; -#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ } static u32 ohci_read_csr(struct fw_card *card, int csr_offset) @@ -3720,9 +3723,11 @@ static int pci_probe(struct pci_dev *dev, version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; ohci_notice(ohci, "added OHCI v%x.%x device as card %d, " - "%d IR + %d IT contexts, quirks 0x%x\n", + "%d IR + %d IT contexts, quirks 0x%x%s\n", version >> 16, version & 0xff, ohci->card.index, - ohci->n_ir, ohci->n_it, ohci->quirks); + ohci->n_ir, ohci->n_it, ohci->quirks, + reg_read(ohci, OHCI1394_PhyUpperBound) ? + ", >4 GB phys DMA" : ""); return 0; diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 2f21b0bfe653..29c8cdda82a1 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -12,8 +12,7 @@ menu "Google Firmware Drivers" config GOOGLE_SMI tristate "SMI interface for Google platforms" - depends on ACPI && DMI - select EFI + depends on ACPI && DMI && EFI select EFI_VARS help Say Y here if you want to enable SMI callbacks for Google diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c index 6490a2dea96b..f079ca2f260b 100644 --- a/drivers/ide/ide-cd_verbose.c +++ b/drivers/ide/ide-cd_verbose.c @@ -9,7 +9,9 @@ #include <linux/kernel.h> #include <linux/blkdev.h> #include <linux/cdrom.h> +#include <linux/ide.h> #include <scsi/scsi.h> +#include "ide-cd.h" #ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS void ide_cd_log_error(const char *name, struct request *failed_command, diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c index a8c2c8f8660a..40e683a84ff9 100644 --- a/drivers/ide/ide-pio-blacklist.c +++ b/drivers/ide/ide-pio-blacklist.c @@ -7,6 +7,7 @@ */ #include <linux/string.h> +#include <linux/ide.h> static struct ide_pio_info { const char *name; diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 3c972b2f9893..e387f41a9cb7 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -242,18 +242,14 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister); void led_trigger_event(struct led_trigger *trig, enum led_brightness brightness) { - struct list_head *entry; + struct led_classdev *led_cdev; if (!trig) return; read_lock(&trig->leddev_list_lock); - list_for_each(entry, &trig->led_cdevs) { - struct led_classdev *led_cdev; - - led_cdev = list_entry(entry, struct led_classdev, trig_list); + list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) led_set_brightness(led_cdev, brightness); - } read_unlock(&trig->leddev_list_lock); } EXPORT_SYMBOL_GPL(led_trigger_event); @@ -264,16 +260,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig, int oneshot, int invert) { - struct list_head *entry; + struct led_classdev *led_cdev; if (!trig) return; read_lock(&trig->leddev_list_lock); - list_for_each(entry, &trig->led_cdevs) { - struct led_classdev *led_cdev; - - led_cdev = list_entry(entry, struct led_classdev, trig_list); + list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { if (oneshot) led_blink_set_oneshot(led_cdev, delay_on, delay_off, invert); diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index a97263e902ff..2ec34cfcedce 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -152,12 +152,26 @@ static void lp5521_load_engine(struct lp55xx_chip *chip) lp5521_wait_opmode_done(); } -static void lp5521_stop_engine(struct lp55xx_chip *chip) +static void lp5521_stop_all_engines(struct lp55xx_chip *chip) { lp55xx_write(chip, LP5521_REG_OP_MODE, 0); lp5521_wait_opmode_done(); } +static void lp5521_stop_engine(struct lp55xx_chip *chip) +{ + enum lp55xx_engine_index idx = chip->engine_idx; + u8 mask[] = { + [LP55XX_ENGINE_1] = LP5521_MODE_R_M, + [LP55XX_ENGINE_2] = LP5521_MODE_G_M, + [LP55XX_ENGINE_3] = LP5521_MODE_B_M, + }; + + lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], 0); + + lp5521_wait_opmode_done(); +} + static void lp5521_run_engine(struct lp55xx_chip *chip, bool start) { int ret; @@ -564,7 +578,7 @@ static int lp5521_remove(struct i2c_client *client) struct lp55xx_led *led = i2c_get_clientdata(client); struct lp55xx_chip *chip = led->chip; - lp5521_stop_engine(chip); + lp5521_stop_all_engines(chip); lp55xx_unregister_sysfs(chip); lp55xx_unregister_leds(led, chip); lp55xx_deinit_device(chip); diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 3a0bc886a87a..4ade66a2d9d4 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -195,12 +195,26 @@ static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip) lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]); } -static void lp5523_stop_engine(struct lp55xx_chip *chip) +static void lp5523_stop_all_engines(struct lp55xx_chip *chip) { lp55xx_write(chip, LP5523_REG_OP_MODE, 0); lp5523_wait_opmode_done(); } +static void lp5523_stop_engine(struct lp55xx_chip *chip) +{ + enum lp55xx_engine_index idx = chip->engine_idx; + u8 mask[] = { + [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M, + [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M, + [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M, + }; + + lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], 0); + + lp5523_wait_opmode_done(); +} + static void lp5523_turn_off_channels(struct lp55xx_chip *chip) { int i; @@ -311,7 +325,7 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip) } out: - lp5523_stop_engine(chip); + lp5523_stop_all_engines(chip); return ret; } @@ -782,7 +796,7 @@ static int lp5523_remove(struct i2c_client *client) struct lp55xx_led *led = i2c_get_clientdata(client); struct lp55xx_chip *chip = led->chip; - lp5523_stop_engine(chip); + lp5523_stop_all_engines(chip); lp55xx_unregister_sysfs(chip); lp55xx_unregister_leds(led, chip); lp55xx_deinit_device(chip); diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 9acc6bb7deef..88317b4f7bf3 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -210,6 +210,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context) { struct lp55xx_chip *chip = context; struct device *dev = &chip->cl->dev; + enum lp55xx_engine_index idx = chip->engine_idx; if (!fw) { dev_err(dev, "firmware request failed\n"); @@ -219,6 +220,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context) /* handling firmware data is chip dependent */ mutex_lock(&chip->lock); + chip->engines[idx - 1].mode = LP55XX_ENGINE_LOAD; chip->fw = fw; if (chip->cfg->firmware_cb) chip->cfg->firmware_cb(chip); diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index fa9b439323bd..ca87a1b4a0db 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -117,9 +117,7 @@ static void mc13xxx_led_work(struct work_struct *work) BUG(); } - mc13xxx_lock(led->master); mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); - mc13xxx_unlock(led->master); } static void mc13xxx_led_set(struct led_classdev *led_cdev, @@ -132,75 +130,6 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev, schedule_work(&led->work); } -static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current) -{ - int shift, mask, reg, ret, bank; - - switch (led->id) { - case MC13783_LED_MD: - reg = MC13XXX_REG_LED_CONTROL(2); - shift = 0; - mask = 0x07; - break; - case MC13783_LED_AD: - reg = MC13XXX_REG_LED_CONTROL(2); - shift = 3; - mask = 0x07; - break; - case MC13783_LED_KP: - reg = MC13XXX_REG_LED_CONTROL(2); - shift = 6; - mask = 0x07; - break; - case MC13783_LED_R1: - case MC13783_LED_G1: - case MC13783_LED_B1: - case MC13783_LED_R2: - case MC13783_LED_G2: - case MC13783_LED_B2: - case MC13783_LED_R3: - case MC13783_LED_G3: - case MC13783_LED_B3: - bank = (led->id - MC13783_LED_R1) / 3; - reg = MC13XXX_REG_LED_CONTROL(3) + bank; - shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2; - mask = 0x03; - break; - case MC13892_LED_MD: - reg = MC13XXX_REG_LED_CONTROL(0); - shift = 9; - mask = 0x07; - break; - case MC13892_LED_AD: - reg = MC13XXX_REG_LED_CONTROL(0); - shift = 21; - mask = 0x07; - break; - case MC13892_LED_KP: - reg = MC13XXX_REG_LED_CONTROL(1); - shift = 9; - mask = 0x07; - break; - case MC13892_LED_R: - case MC13892_LED_G: - case MC13892_LED_B: - bank = (led->id - MC13892_LED_R) / 2; - reg = MC13XXX_REG_LED_CONTROL(2) + bank; - shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9; - mask = 0x07; - break; - default: - BUG(); - } - - mc13xxx_lock(led->master); - ret = mc13xxx_reg_rmw(led->master, reg, mask << shift, - max_current << shift); - mc13xxx_unlock(led->master); - - return ret; -} - static int __init mc13xxx_led_probe(struct platform_device *pdev) { struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -233,31 +162,22 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) leds->num_leds = num_leds; platform_set_drvdata(pdev, leds); - mc13xxx_lock(mcdev); for (i = 0; i < devtype->num_regs; i++) { reg = pdata->led_control[i]; WARN_ON(reg >= (1 << 24)); ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); if (ret) - break; - } - mc13xxx_unlock(mcdev); - - if (ret) { - dev_err(&pdev->dev, "Unable to init LED driver\n"); - return ret; + return ret; } for (i = 0; i < num_leds; i++) { const char *name, *trig; - char max_current; ret = -EINVAL; id = pdata->led[i].id; name = pdata->led[i].name; trig = pdata->led[i].default_trigger; - max_current = pdata->led[i].max_current; if ((id > devtype->led_max) || (id < devtype->led_min)) { dev_err(&pdev->dev, "Invalid ID %i\n", id); @@ -280,11 +200,6 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) INIT_WORK(&leds->led[i].work, mc13xxx_led_work); - ret = mc13xxx_led_setup(&leds->led[i], max_current); - if (ret) { - dev_err(&pdev->dev, "Unable to setup LED %i\n", id); - break; - } ret = led_classdev_register(pdev->dev.parent, &leds->led[i].cdev); if (ret) { @@ -313,10 +228,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev) cancel_work_sync(&leds->led[i].work); } - mc13xxx_lock(mcdev); for (i = 0; i < leds->devtype->num_regs; i++) mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0); - mc13xxx_unlock(mcdev); return 0; } diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index b31d8e99c419..605047428b5a 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -66,9 +66,11 @@ static void led_pwm_set(struct led_classdev *led_cdev, struct led_pwm_data *led_dat = container_of(led_cdev, struct led_pwm_data, cdev); unsigned int max = led_dat->cdev.max_brightness; - unsigned int period = led_dat->period; + unsigned long long duty = led_dat->period; - led_dat->duty = brightness * period / max; + duty *= brightness; + do_div(duty, max); + led_dat->duty = duty; if (led_dat->can_sleep) schedule_work(&led_dat->work); @@ -85,11 +87,10 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds) static int led_pwm_create_of(struct platform_device *pdev, struct led_pwm_priv *priv) { - struct device_node *node = pdev->dev.of_node; struct device_node *child; int ret; - for_each_child_of_node(node, child) { + for_each_child_of_node(pdev->dev.of_node, child) { struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; led_dat->cdev.name = of_get_property(child, "label", diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 87cf215af798..98174e7240ee 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -18,11 +18,10 @@ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/platform_data/leds-s3c24xx.h> -#include <mach/hardware.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> -#include <linux/platform_data/leds-s3c24xx.h> /* our context */ diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 8cc304f36728..3d9e267a56c4 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -4,77 +4,87 @@ * The TCA6507 is a programmable LED controller that can drive 7 * separate lines either by holding them low, or by pulsing them * with modulated width. - * The modulation can be varied in a simple pattern to produce a blink or - * double-blink. + * The modulation can be varied in a simple pattern to produce a + * blink or double-blink. * - * This driver can configure each line either as a 'GPIO' which is out-only - * (no pull-up) or as an LED with variable brightness and hardware-assisted - * blinking. + * This driver can configure each line either as a 'GPIO' which is + * out-only (pull-up resistor required) or as an LED with variable + * brightness and hardware-assisted blinking. * - * Apart from OFF and ON there are three programmable brightness levels which - * can be programmed from 0 to 15 and indicate how many 500usec intervals in - * each 8msec that the led is 'on'. The levels are named MASTER, BANK0 and - * BANK1. + * Apart from OFF and ON there are three programmable brightness + * levels which can be programmed from 0 to 15 and indicate how many + * 500usec intervals in each 8msec that the led is 'on'. The levels + * are named MASTER, BANK0 and BANK1. * - * There are two different blink rates that can be programmed, each with - * separate time for rise, on, fall, off and second-off. Thus if 3 or more - * different non-trivial rates are required, software must be used for the extra - * rates. The two different blink rates must align with the two levels BANK0 and - * BANK1. - * This driver does not support double-blink so 'second-off' always matches - * 'off'. + * There are two different blink rates that can be programmed, each + * with separate time for rise, on, fall, off and second-off. Thus if + * 3 or more different non-trivial rates are required, software must + * be used for the extra rates. The two different blink rates must + * align with the two levels BANK0 and BANK1. This driver does not + * support double-blink so 'second-off' always matches 'off'. * - * Only 16 different times can be programmed in a roughly logarithmic scale from - * 64ms to 16320ms. To be precise the possible times are: + * Only 16 different times can be programmed in a roughly logarithmic + * scale from 64ms to 16320ms. To be precise the possible times are: * 0, 64, 128, 192, 256, 384, 512, 768, * 1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320 * - * Times that cannot be closely matched with these must be - * handled in software. This driver allows 12.5% error in matching. + * Times that cannot be closely matched with these must be handled in + * software. This driver allows 12.5% error in matching. * - * This driver does not allow rise/fall rates to be set explicitly. When trying - * to match a given 'on' or 'off' period, an appropriate pair of 'change' and - * 'hold' times are chosen to get a close match. If the target delay is even, - * the 'change' number will be the smaller; if odd, the 'hold' number will be - * the smaller. - - * Choosing pairs of delays with 12.5% errors allows us to match delays in the - * ranges: 56-72, 112-144, 168-216, 224-27504, 28560-36720. - * 26% of the achievable sums can be matched by multiple pairings. For example - * 1536 == 1536+0, 1024+512, or 768+768. This driver will always choose the - * pairing with the least maximum - 768+768 in this case. Other pairings are - * not available. + * This driver does not allow rise/fall rates to be set explicitly. + * When trying to match a given 'on' or 'off' period, an appropriate + * pair of 'change' and 'hold' times are chosen to get a close match. + * If the target delay is even, the 'change' number will be the + * smaller; if odd, the 'hold' number will be the smaller. + + * Choosing pairs of delays with 12.5% errors allows us to match + * delays in the ranges: 56-72, 112-144, 168-216, 224-27504, + * 28560-36720. + * 26% of the achievable sums can be matched by multiple pairings. + * For example 1536 == 1536+0, 1024+512, or 768+768. + * This driver will always choose the pairing with the least + * maximum - 768+768 in this case. Other pairings are not available. * - * Access to the 3 levels and 2 blinks are on a first-come, first-served basis. - * Access can be shared by multiple leds if they have the same level and - * either same blink rates, or some don't blink. - * When a led changes, it relinquishes access and tries again, so it might - * lose access to hardware blink. - * If a blink engine cannot be allocated, software blink is used. - * If the desired brightness cannot be allocated, the closest available non-zero - * brightness is used. As 'full' is always available, the worst case would be - * to have two different blink rates at '1', with Max at '2', then other leds - * will have to choose between '2' and '16'. Hopefully this is not likely. + * Access to the 3 levels and 2 blinks are on a first-come, + * first-served basis. Access can be shared by multiple leds if they + * have the same level and either same blink rates, or some don't + * blink. When a led changes, it relinquishes access and tries again, + * so it might lose access to hardware blink. * - * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the brightness - * and LEDs using the blink. It can only be reprogrammed when the appropriate - * counter is zero. The MASTER level has a single usage count. + * If a blink engine cannot be allocated, software blink is used. If + * the desired brightness cannot be allocated, the closest available + * non-zero brightness is used. As 'full' is always available, the + * worst case would be to have two different blink rates at '1', with + * Max at '2', then other leds will have to choose between '2' and + * '16'. Hopefully this is not likely. * - * Each Led has programmable 'on' and 'off' time as milliseconds. With each - * there is a flag saying if it was explicitly requested or defaulted. - * Similarly the banks know if each time was explicit or a default. Defaults - * are permitted to be changed freely - they are not recognised when matching. + * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the + * brightness and LEDs using the blink. It can only be reprogrammed + * when the appropriate counter is zero. The MASTER level has a + * single usage count. * + * Each LED has programmable 'on' and 'off' time as milliseconds. + * With each there is a flag saying if it was explicitly requested or + * defaulted. Similarly the banks know if each time was explicit or a + * default. Defaults are permitted to be changed freely - they are + * not recognised when matching. * - * An led-tca6507 device must be provided with platform data. This data - * lists for each output: the name, default trigger, and whether the signal - * is being used as a GPiO rather than an led. 'struct led_plaform_data' - * is used for this. If 'name' is NULL, the output isn't used. If 'flags' - * is TCA6507_MAKE_CPIO, the output is a GPO. - * The "struct led_platform_data" can be embedded in a - * "struct tca6507_platform_data" which adds a 'gpio_base' for the GPiOs, - * and a 'setup' callback which is called once the GPiOs are available. * + * An led-tca6507 device must be provided with platform data or + * configured via devicetree. + * + * The platform-data lists for each output: the name, default trigger, + * and whether the signal is being used as a GPIO rather than an LED. + * 'struct led_plaform_data' is used for this. If 'name' is NULL, the + * output isn't used. If 'flags' is TCA6507_MAKE_GPIO, the output is + * a GPO. The "struct led_platform_data" can be embedded in a "struct + * tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and + * a 'setup' callback which is called once the GPIOs are available. + * + * When configured via devicetree there is one child for each output. + * The "reg" determines the output number and "compatible" determines + * whether it is an LED or a GPIO. "linux,default-trigger" can set a + * default trigger. */ #include <linux/module.h> @@ -192,17 +202,18 @@ MODULE_DEVICE_TABLE(i2c, tca6507_id); static int choose_times(int msec, int *c1p, int *c2p) { /* - * Choose two timecodes which add to 'msec' as near as possible. - * The first returned is the 'on' or 'off' time. The second is to be - * used as a 'fade-on' or 'fade-off' time. If 'msec' is even, - * the first will not be smaller than the second. If 'msec' is odd, - * the first will not be larger than the second. - * If we cannot get a sum within 1/8 of 'msec' fail with -EINVAL, - * otherwise return the sum that was achieved, plus 1 if the first is - * smaller. - * If two possibilities are equally good (e.g. 512+0, 256+256), choose - * the first pair so there is more change-time visible (i.e. it is - * softer). + * Choose two timecodes which add to 'msec' as near as + * possible. The first returned is the 'on' or 'off' time. + * The second is to be used as a 'fade-on' or 'fade-off' time. + * If 'msec' is even, the first will not be smaller than the + * second. If 'msec' is odd, the first will not be larger + * than the second. + * If we cannot get a sum within 1/8 of 'msec' fail with + * -EINVAL, otherwise return the sum that was achieved, plus 1 + * if the first is smaller. + * If two possibilities are equally good (e.g. 512+0, + * 256+256), choose the first pair so there is more + * change-time visible (i.e. it is softer). */ int c1, c2; int tmax = msec * 9 / 8; @@ -255,8 +266,8 @@ static int choose_times(int msec, int *c1p, int *c2p) } /* - * Update the register file with the appropriate 3-bit state for - * the given led. + * Update the register file with the appropriate 3-bit state for the + * given led. */ static void set_select(struct tca6507_chip *tca, int led, int val) { @@ -274,9 +285,9 @@ static void set_select(struct tca6507_chip *tca, int led, int val) } } -/* Update the register file with the appropriate 4-bit code for - * one bank or other. This can be used for timers, for levels, or - * for initialisation. +/* Update the register file with the appropriate 4-bit code for one + * bank or other. This can be used for timers, for levels, or for + * initialization. */ static void set_code(struct tca6507_chip *tca, int reg, int bank, int new) { @@ -309,7 +320,7 @@ static void set_level(struct tca6507_chip *tca, int bank, int level) tca->bank[bank].level = level; } -/* Record all relevant time code for a given bank */ +/* Record all relevant time codes for a given bank */ static void set_times(struct tca6507_chip *tca, int bank) { int c1, c2; @@ -317,7 +328,8 @@ static void set_times(struct tca6507_chip *tca, int bank) result = choose_times(tca->bank[bank].ontime, &c1, &c2); dev_dbg(&tca->client->dev, - "Chose on times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1], + "Chose on times %d(%d) %d(%d) for %dms\n", + c1, time_codes[c1], c2, time_codes[c2], tca->bank[bank].ontime); set_code(tca, TCA6507_FADE_ON, bank, c2); set_code(tca, TCA6507_FULL_ON, bank, c1); @@ -325,7 +337,8 @@ static void set_times(struct tca6507_chip *tca, int bank) result = choose_times(tca->bank[bank].offtime, &c1, &c2); dev_dbg(&tca->client->dev, - "Chose off times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1], + "Chose off times %d(%d) %d(%d) for %dms\n", + c1, time_codes[c1], c2, time_codes[c2], tca->bank[bank].offtime); set_code(tca, TCA6507_FADE_OFF, bank, c2); set_code(tca, TCA6507_FIRST_OFF, bank, c1); @@ -373,7 +386,8 @@ static void led_release(struct tca6507_led *led) static int led_prepare(struct tca6507_led *led) { - /* Assign this led to a bank, configuring that bank if necessary. */ + /* Assign this led to a bank, configuring that bank if + * necessary. */ int level = TO_LEVEL(led->led_cdev.brightness); struct tca6507_chip *tca = led->chip; int c1, c2; @@ -389,10 +403,10 @@ static int led_prepare(struct tca6507_led *led) if (led->ontime == 0 || led->offtime == 0) { /* - * Just set the brightness, choosing first usable bank. - * If none perfect, choose best. - * Count backwards so we check MASTER bank first - * to avoid wasting a timer. + * Just set the brightness, choosing first usable + * bank. If none perfect, choose best. Count + * backwards so we check MASTER bank first to avoid + * wasting a timer. */ int best = -1;/* full-on */ int diff = 15-level; @@ -433,9 +447,9 @@ static int led_prepare(struct tca6507_led *led) } /* - * We have on/off time so we need to try to allocate a timing bank. - * First check if times are compatible with hardware and give up if - * not. + * We have on/off time so we need to try to allocate a timing + * bank. First check if times are compatible with hardware + * and give up if not. */ if (choose_times(led->ontime, &c1, &c2) < 0) return -EINVAL; @@ -523,8 +537,8 @@ static int led_assign(struct tca6507_led *led) err = led_prepare(led); if (err) { /* - * Can only fail on timer setup. In that case we need to - * re-establish as steady level. + * Can only fail on timer setup. In that case we need + * to re-establish as steady level. */ led->ontime = 0; led->offtime = 0; @@ -594,8 +608,8 @@ static void tca6507_gpio_set_value(struct gpio_chip *gc, spin_lock_irqsave(&tca->lock, flags); /* - * 'OFF' is floating high, and 'ON' is pulled down, so it has the - * inverse sense of 'val'. + * 'OFF' is floating high, and 'ON' is pulled down, so it has + * the inverse sense of 'val'. */ set_select(tca, tca->gpio_map[offset], val ? TCA6507_LS_LED_OFF : TCA6507_LS_LED_ON); @@ -638,6 +652,9 @@ static int tca6507_probe_gpios(struct i2c_client *client, tca->gpio.direction_output = tca6507_gpio_direction_output; tca->gpio.set = tca6507_gpio_set_value; tca->gpio.dev = &client->dev; +#ifdef CONFIG_OF_GPIO + tca->gpio.of_node = of_node_get(client->dev.of_node); +#endif err = gpiochip_add(&tca->gpio); if (err) { tca->gpio.ngpio = 0; @@ -682,7 +699,7 @@ tca6507_led_dt_init(struct i2c_client *client) return ERR_PTR(-ENODEV); tca_leds = devm_kzalloc(&client->dev, - sizeof(struct led_info) * count, GFP_KERNEL); + sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL); if (!tca_leds) return ERR_PTR(-ENOMEM); @@ -695,9 +712,11 @@ tca6507_led_dt_init(struct i2c_client *client) of_get_property(child, "label", NULL) ? : child->name; led.default_trigger = of_get_property(child, "linux,default-trigger", NULL); - + led.flags = 0; + if (of_property_match_string(child, "compatible", "gpio") >= 0) + led.flags |= TCA6507_MAKE_GPIO; ret = of_property_read_u32(child, "reg", ®); - if (ret != 0) + if (ret != 0 || reg < 0 || reg >= NUM_LEDS) continue; tca_leds[reg] = led; @@ -708,8 +727,10 @@ tca6507_led_dt_init(struct i2c_client *client) return ERR_PTR(-ENOMEM); pdata->leds.leds = tca_leds; - pdata->leds.num_leds = count; - + pdata->leds.num_leds = NUM_LEDS; +#ifdef CONFIG_GPIOLIB + pdata->gpio_base = -1; +#endif return pdata; } diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 9ef32b3df91f..590214ba736c 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -133,7 +133,7 @@ static int wf_lm75_probe(struct i2c_client *client, lm->inited = 0; lm->ds1775 = ds1775; lm->i2c = client; - lm->sens.name = (char *)name; /* XXX fix constness in structure */ + lm->sens.name = name; lm->sens.ops = &wf_lm75_ops; i2c_set_clientdata(client, lm); diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 945a25b2f31e..87e439b10318 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -95,7 +95,7 @@ static int wf_max6690_probe(struct i2c_client *client, } max->i2c = client; - max->sens.name = (char *)name; /* XXX fix constness in structure */ + max->sens.name = name; max->sens.ops = &wf_max6690_ops; i2c_set_clientdata(client, max); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5fab4e6e8301..5ebcda39f554 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -157,10 +157,11 @@ config MTD_BCM47XX_PARTS comment "User Modules And Translation Layers" +# +# MTD block device support is select'ed if needed +# config MTD_BLKDEVS - tristate "Common interface to block layer for MTD 'translation layers'" - depends on BLOCK - default n + tristate config MTD_BLOCK tristate "Caching block device access to MTD devices" diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 5a3942bf109c..96a33e3f7b00 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = { static int __init afs_parser_init(void) { - return register_mtd_parser(&afs_parser); + register_mtd_parser(&afs_parser); + return 0; } static void __exit afs_parser_exit(void) diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index ddc0a4287a4b..7c9172ad2621 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = { static int __init ar7_parser_init(void) { - return register_mtd_parser(&ar7_parser); + register_mtd_parser(&ar7_parser); + return 0; } static void __exit ar7_parser_exit(void) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 7a6384b0962a..de1eb92e42f5 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -23,10 +23,12 @@ * Amount of bytes we read when analyzing each block of flash memory. * Set it big enough to allow detecting partition and reading important data. */ -#define BCM47XXPART_BYTES_TO_READ 0x404 +#define BCM47XXPART_BYTES_TO_READ 0x4e8 /* Magics */ #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ +#define BOARD_DATA_MAGIC2 0xBD0D0BBD +#define CFE_MAGIC 0x43464531 /* 1EFC */ #define FACTORY_MAGIC 0x59544346 /* FCTY */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ @@ -102,8 +104,9 @@ static int bcm47xxpart_parse(struct mtd_info *master, continue; } - /* CFE has small NVRAM at 0x400 */ - if (buf[0x400 / 4] == NVRAM_HEADER) { + /* Magic or small NVRAM at 0x400 */ + if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) || + (buf[0x400 / 4] == NVRAM_HEADER)) { bcm47xxpart_add_part(&parts[curr_part++], "boot", offset, MTD_WRITEABLE); continue; @@ -190,6 +193,21 @@ static int bcm47xxpart_parse(struct mtd_info *master, offset, 0); continue; } + + /* Read middle of the block */ + if (mtd_read(master, offset + 0x8000, 0x4, + &bytes_read, (uint8_t *)buf) < 0) { + pr_err("mtd_read error while parsing (offset: 0x%X)!\n", + offset); + continue; + } + + /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */ + if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) { + bcm47xxpart_add_part(&parts[curr_part++], "board_data", + offset, MTD_WRITEABLE); + continue; + } } /* Look for NVRAM at the end of the last block. */ @@ -243,7 +261,8 @@ static struct mtd_part_parser bcm47xxpart_mtd_parser = { static int __init bcm47xxpart_init(void) { - return register_mtd_parser(&bcm47xxpart_mtd_parser); + register_mtd_parser(&bcm47xxpart_mtd_parser); + return 0; } static void __exit bcm47xxpart_exit(void) diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 5c813907661c..b2443f7031c9 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = { static int __init bcm63xx_cfe_parser_init(void) { - return register_mtd_parser(&bcm63xx_cfe_parser); + register_mtd_parser(&bcm63xx_cfe_parser); + return 0; } static void __exit bcm63xx_cfe_parser_exit(void) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 721caebbc5cc..3e829b37af8d 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void) { if (mtdparts) mtdpart_setup(mtdparts); - return register_mtd_parser(&cmdline_parser); + register_mtd_parser(&cmdline_parser); + return 0; } static void __exit cmdline_parser_exit(void) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 4f091c1a9981..dd5e1018d37b 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev) ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ress) { dev_err(dev, "No I/O memory resource defined\n"); - goto noress; + return ret; } - base = ioremap(ress->start, DOC_IOSPACE_SIZE); + base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, - GFP_KERNEL); + cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, + GFP_KERNEL); if (!cascade) - goto nomem1; + return ret; cascade->base = base; mutex_init(&cascade->lock); cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, DOC_ECC_BCH_PRIMPOLY); if (!cascade->bch) - goto nomem2; + return ret; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { mtd = doc_probe_device(cascade, floor, dev); @@ -2101,11 +2101,6 @@ err_probe: for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); -nomem2: - kfree(cascade); -nomem1: - iounmap(base); -noress: return ret; } @@ -2119,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev) { struct docg3_cascade *cascade = platform_get_drvdata(pdev); struct docg3 *docg3 = cascade->floors[0]->priv; - void __iomem *base = cascade->base; int floor; doc_unregister_sysfs(pdev, cascade); @@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev) doc_release_device(cascade->floors[floor]); free_bch(docg3->cascade->bch); - kfree(cascade); - iounmap(base); return 0; } diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7eda71dbc183..ad1913909702 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -41,6 +41,7 @@ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ 0x6b /* Read data bytes */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ @@ -48,10 +49,12 @@ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ +#define OPCODE_RDCR 0x35 /* Read configuration register */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ @@ -76,6 +79,11 @@ #define SR_BP2 0x10 /* Block protect 2 */ #define SR_SRWD 0x80 /* SR write protect */ +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ + /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 @@ -84,6 +92,12 @@ /****************************************************************************/ +enum read_type { + M25P80_NORMAL = 0, + M25P80_FAST, + M25P80_QUAD, +}; + struct m25p { struct spi_device *spi; struct mutex lock; @@ -94,7 +108,7 @@ struct m25p { u8 read_opcode; u8 program_opcode; u8 *command; - bool fast_read; + enum read_type flash_read; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -131,6 +145,26 @@ static int read_sr(struct m25p *flash) } /* + * Read configuration register, returning its value in the + * location. Return the configuration register value. + * Returns negative if error occured. + */ +static int read_cr(struct m25p *flash) +{ + u8 code = OPCODE_RDCR; + int ret; + u8 val; + + ret = spi_write_then_read(flash->spi, &code, 1, &val, 1); + if (ret < 0) { + dev_err(&flash->spi->dev, "error %d reading CR\n", ret); + return ret; + } + + return val; +} + +/* * Write status register 1 byte * Returns negative if error occurred. */ @@ -220,6 +254,93 @@ static int wait_till_ready(struct m25p *flash) } /* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occured. + */ +static int write_sr_cr(struct m25p *flash, u16 val) +{ + flash->command[0] = OPCODE_WRSR; + flash->command[1] = val & 0xff; + flash->command[2] = (val >> 8); + + return spi_write(flash->spi, flash->command, 3); +} + +static int macronix_quad_enable(struct m25p *flash) +{ + int ret, val; + u8 cmd[2]; + cmd[0] = OPCODE_WRSR; + + val = read_sr(flash); + cmd[1] = val | SR_QUAD_EN_MX; + write_enable(flash); + + spi_write(flash->spi, &cmd, 2); + + if (wait_till_ready(flash)) + return 1; + + ret = read_sr(flash); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(&flash->spi->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int spansion_quad_enable(struct m25p *flash) +{ + int ret; + int quad_en = CR_QUAD_EN_SPAN << 8; + + write_enable(flash); + + ret = write_sr_cr(flash, quad_en); + if (ret < 0) { + dev_err(&flash->spi->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* read back and check it */ + ret = read_cr(flash); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(&flash->spi->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int set_quad_mode(struct m25p *flash, u32 jedec_id) +{ + int status; + + switch (JEDEC_MFR(jedec_id)) { + case CFI_MFR_MACRONIX: + status = macronix_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Macronix quad-read not enabled\n"); + return -EINVAL; + } + return status; + default: + status = spansion_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Spansion quad-read not enabled\n"); + return -EINVAL; + } + return status; + } +} + +/* * Erase the whole flash memory * * Returns 0 if successful, non-zero otherwise. @@ -350,6 +471,35 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) } /* + * Dummy Cycle calculation for different type of read. + * It can be used to support more commands with + * different dummy cycle requirements. + */ +static inline int m25p80_dummy_cycles_read(struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_FAST: + case M25P80_QUAD: + return 1; + case M25P80_NORMAL: + return 0; + default: + dev_err(&flash->spi->dev, "No valid read type supported\n"); + return -1; + } +} + +static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_QUAD: + return 4; + default: + return 0; + } +} + +/* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. */ @@ -360,6 +510,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; uint8_t opcode; + int dummy; pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, (u32)from, len); @@ -367,11 +518,18 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_message_init(&m); memset(t, 0, (sizeof t)); + dummy = m25p80_dummy_cycles_read(flash); + if (dummy < 0) { + dev_err(&flash->spi->dev, "No valid read command supported\n"); + return -EINVAL; + } + t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); + t[0].len = m25p_cmdsz(flash) + dummy; spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; + t[1].rx_nbits = m25p80_rx_nbits(flash); t[1].len = len; spi_message_add_tail(&t[1], &m); @@ -391,8 +549,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_sync(flash->spi, &m); - *retlen = m.actual_length - m25p_cmdsz(flash) - - (flash->fast_read ? 1 : 0); + *retlen = m.actual_length - m25p_cmdsz(flash) - dummy; mutex_unlock(&flash->lock); @@ -698,6 +855,7 @@ struct flash_info { #define SST_WRITE 0x04 /* use SST byte programming */ #define M25P_NO_FR 0x08 /* Can't do fastread */ #define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ +#define M25P80_QUAD_READ 0x20 /* Flash supports Quad Read */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -775,7 +933,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) }, /* Micron */ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, @@ -795,8 +953,8 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, @@ -851,6 +1009,7 @@ static const struct spi_device_id m25p_ids[] = { { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, @@ -937,6 +1096,7 @@ static int m25p_probe(struct spi_device *spi) unsigned i; struct mtd_part_parser_data ppdata; struct device_node *np = spi->dev.of_node; + int ret; /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -1051,22 +1211,46 @@ static int m25p_probe(struct spi_device *spi) flash->page_size = info->page_size; flash->mtd.writebufsize = flash->page_size; - if (np) + if (np) { /* If we were instantiated by DT, use it */ - flash->fast_read = of_property_read_bool(np, "m25p,fast-read"); - else + if (of_property_read_bool(np, "m25p,fast-read")) + flash->flash_read = M25P80_FAST; + else + flash->flash_read = M25P80_NORMAL; + } else { /* If we weren't instantiated by DT, default to fast-read */ - flash->fast_read = true; + flash->flash_read = M25P80_FAST; + } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & M25P_NO_FR) - flash->fast_read = false; + flash->flash_read = M25P80_NORMAL; + + /* Quad-read mode takes precedence over fast/normal */ + if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) { + ret = set_quad_mode(flash, info->jedec_id); + if (ret) { + dev_err(&flash->spi->dev, "quad mode not supported\n"); + return ret; + } + flash->flash_read = M25P80_QUAD; + } /* Default commands */ - if (flash->fast_read) + switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ; + break; + case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ; - else + break; + case M25P80_NORMAL: flash->read_opcode = OPCODE_NORM_READ; + break; + default: + dev_err(&flash->spi->dev, "No Read opcode defined\n"); + return -EINVAL; + } flash->program_opcode = OPCODE_PP; @@ -1077,9 +1261,17 @@ static int m25p_probe(struct spi_device *spi) flash->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ - flash->read_opcode = flash->fast_read ? - OPCODE_FAST_READ_4B : - OPCODE_NORM_READ_4B; + switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ_4B; + break; + case M25P80_FAST: + flash->read_opcode = OPCODE_FAST_READ_4B; + break; + case M25P80_NORMAL: + flash->read_opcode = OPCODE_NORM_READ_4B; + break; + } flash->program_opcode = OPCODE_PP_4B; /* No small sector erase for 4-byte command set */ flash->erase_opcode = OPCODE_SE_4B; diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 182849d39c61..5c8b322ba904 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr) mtd->type = MTD_RAM; mtd->flags = MTD_CAP_RAM; mtd->size = fixsize; - mtd->name = (char *)ms02nv_name; + mtd->name = ms02nv_name; mtd->owner = THIS_MODULE; mtd->_read = ms02nv_read; mtd->_write = ms02nv_write; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 4a47b0266d4e..624069de4f28 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, if (!err) return 0; - spi_set_drvdata(spi, NULL); kfree(priv); return err; } @@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi) pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); - if (status == 0) { - spi_set_drvdata(spi, NULL); + if (status == 0) kfree(flash); - } return status; } diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index ec59d65897fb..8e285089229c 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void) } int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name) + unsigned long size, const char *name) { memset(mtd, 0, sizeof(*mtd)); diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 2ef19aa0086b..d38b6460d505 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -388,7 +388,7 @@ static void put_chip(struct map_info *map, struct flchip *chip) wake_up(&chip->wq); } -int do_write_buffer(struct map_info *map, struct flchip *chip, +static int do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const struct kvec **pvec, unsigned long *pvec_seek, int len) { @@ -469,7 +469,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip, return ret; } -int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) +static int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) { struct map_info *map = mtd->priv; struct lpddr_private *lpddr = map->fldrv_priv; @@ -748,34 +748,6 @@ static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK); } -int word_program(struct map_info *map, loff_t adr, uint32_t curval) -{ - int ret; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_WRITING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - - send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval); - - ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime)); - if (ret) { - printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n", - map->name, adr, curval); - goto out; - } - -out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>"); MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 10debfea81e7..d6b2451eab1d 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -13,6 +13,7 @@ * */ +#include <linux/err.h> #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> @@ -162,13 +163,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev) mtd_device_unregister(info->mtd); map_destroy(info->mtd); } - if (info->map.virt) - iounmap(info->map.virt); - - if (info->res) { - release_resource(info->res); - kfree(info->res); - } if (plat->exit) plat->exit(); @@ -194,7 +188,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev) return err; } - info = kzalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL); + info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info), + GFP_KERNEL); if(!info) { err = -ENOMEM; goto Error; @@ -220,20 +215,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev) info->map.write = ixp4xx_probe_write16; info->map.copy_from = ixp4xx_copy_from; - info->res = request_mem_region(dev->resource->start, - resource_size(dev->resource), - "IXP4XXFlash"); - if (!info->res) { - printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); - err = -ENOMEM; - goto Error; - } - - info->map.virt = ioremap(dev->resource->start, - resource_size(dev->resource)); - if (!info->map.virt) { - printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); - err = -EIO; + info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource); + if (IS_ERR(info->map.virt)) { + err = PTR_ERR(info->map.virt); goto Error; } diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index d7ac65d1d569..93c507a6f862 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -123,24 +123,28 @@ ltq_mtd_probe(struct platform_device *pdev) return -ENODEV; } - ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); + ltq_mtd = devm_kzalloc(&pdev->dev, sizeof(struct ltq_mtd), GFP_KERNEL); + if (!ltq_mtd) + return -ENOMEM; + platform_set_drvdata(pdev, ltq_mtd); ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ltq_mtd->res) { dev_err(&pdev->dev, "failed to get memory resource\n"); - err = -ENOENT; - goto err_out; + return -ENOENT; } - ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), + GFP_KERNEL); + if (!ltq_mtd->map) + return -ENOMEM; + ltq_mtd->map->phys = ltq_mtd->res->start; ltq_mtd->map->size = resource_size(ltq_mtd->res); ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); - if (IS_ERR(ltq_mtd->map->virt)) { - err = PTR_ERR(ltq_mtd->map->virt); - goto err_out; - } + if (IS_ERR(ltq_mtd->map->virt)) + return PTR_ERR(ltq_mtd->map->virt); ltq_mtd->map->name = ltq_map_name; ltq_mtd->map->bankwidth = 2; @@ -155,8 +159,7 @@ ltq_mtd_probe(struct platform_device *pdev) if (!ltq_mtd->mtd) { dev_err(&pdev->dev, "probing failed\n"); - err = -ENXIO; - goto err_free; + return -ENXIO; } ltq_mtd->mtd->owner = THIS_MODULE; @@ -177,10 +180,6 @@ ltq_mtd_probe(struct platform_device *pdev) err_destroy: map_destroy(ltq_mtd->mtd); -err_free: - kfree(ltq_mtd->map); -err_out: - kfree(ltq_mtd); return err; } @@ -189,13 +188,9 @@ ltq_mtd_remove(struct platform_device *pdev) { struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); - if (ltq_mtd) { - if (ltq_mtd->mtd) { - mtd_device_unregister(ltq_mtd->mtd); - map_destroy(ltq_mtd->mtd); - } - kfree(ltq_mtd->map); - kfree(ltq_mtd); + if (ltq_mtd && ltq_mtd->mtd) { + mtd_device_unregister(ltq_mtd->mtd); + map_destroy(ltq_mtd->mtd); } return 0; } diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 0f55589a56b8..9aad854fe912 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -61,7 +61,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - info->map.name = (char *) flash->name; + info->map.name = flash->name; info->map.bankwidth = flash->width; info->map.phys = res->start; info->map.size = resource_size(res); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index d467f3b11c96..39cc4181f025 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -75,7 +75,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp) up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) - up->map.name = (char *)up->name; + up->map.name = up->name; up->map.phys = op->resource[0].start; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 92311a56939f..34c0b16aed5c 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -313,15 +313,7 @@ static struct attribute *mtd_attrs[] = { &dev_attr_bitflip_threshold.attr, NULL, }; - -static struct attribute_group mtd_group = { - .attrs = mtd_attrs, -}; - -static const struct attribute_group *mtd_groups[] = { - &mtd_group, - NULL, -}; +ATTRIBUTE_GROUPS(mtd); static struct device_type mtd_devtype = { .name = "mtd", diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6e732c3820c1..3c7d6d7623c1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -534,7 +534,7 @@ out_register: return slave; } -int mtd_add_partition(struct mtd_info *master, char *name, +int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length) { struct mtd_partition part; @@ -672,22 +672,19 @@ static struct mtd_part_parser *get_partition_parser(const char *name) #define put_partition_parser(p) do { module_put((p)->owner); } while (0) -int register_mtd_parser(struct mtd_part_parser *p) +void register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); - - return 0; } EXPORT_SYMBOL_GPL(register_mtd_parser); -int deregister_mtd_parser(struct mtd_part_parser *p) +void deregister_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_del(&p->list); spin_unlock(&part_parser_lock); - return 0; } EXPORT_SYMBOL_GPL(deregister_mtd_parser); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 93ae6a6d94f7..90ff447bf043 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -95,7 +95,7 @@ config MTD_NAND_OMAP2 platforms. config MTD_NAND_OMAP_BCH - depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3 + depends on MTD_NAND_OMAP2 tristate "Support hardware based BCH error correction" default n select BCH @@ -326,11 +326,11 @@ config MTD_NAND_ATMEL on Atmel AT91 and AVR32 processors. config MTD_NAND_PXA3xx - tristate "Support for NAND flash devices on PXA3xx" + tristate "NAND support on PXA3xx and Armada 370/XP" depends on PXA3xx || ARCH_MMP || PLAT_ORION help This enables the driver for the NAND flash device found on - PXA3xx processors + PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). config MTD_NAND_SLC_LPC32XX tristate "NXP LPC32xx SLC Controller" @@ -458,17 +458,17 @@ config MTD_NAND_MXC config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help Several Renesas SuperH CPU has FLCTL. This option enables support for NAND Flash using FLCTL. config MTD_NAND_DAVINCI - tristate "Support NAND on DaVinci SoC" - depends on ARCH_DAVINCI + tristate "Support NAND on DaVinci/Keystone SoC" + depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) help Enable the driver for NAND flash chips on Texas Instruments - DaVinci processors. + DaVinci/Keystone processors. config MTD_NAND_TXX9NDFMC tristate "NAND Flash support for TXx9 SoC" diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 59f08c44abdb..c36e9b84487c 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1961,10 +1961,8 @@ static int atmel_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); + if (!host) return -ENOMEM; - } res = platform_driver_register(&atmel_nand_nfc_driver); if (res) @@ -2062,14 +2060,14 @@ static int atmel_nand_probe(struct platform_device *pdev) } if (gpio_get_value(host->board.det_pin)) { - printk(KERN_INFO "No SmartMedia card inserted.\n"); + dev_info(&pdev->dev, "No SmartMedia card inserted.\n"); res = -ENXIO; goto err_no_card; } } if (host->board.on_flash_bbt || on_flash_bbt) { - printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); + dev_info(&pdev->dev, "Use On Flash BBT\n"); nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index ae8dd7c41039..2880d888cfc5 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -418,10 +418,8 @@ static int au1550nd_probe(struct platform_device *pdev) } ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - dev_err(&pdev->dev, "no memory for NAND context\n"); + if (!ctx) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { @@ -480,6 +478,8 @@ static int au1550nd_probe(struct platform_device *pdev) mtd_device_register(&ctx->info, pd->parts, pd->num_parts); + platform_set_drvdata(pdev, ctx); + return 0; out3: diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 2c42e125720f..94f55dbde995 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -745,7 +745,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev) info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto out_err_kzalloc; } diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index c34985a55101..f2f64addb5e8 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -640,10 +640,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, pci_set_master(pdev); mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL); - if (!mtd) { - dev_warn(&pdev->dev, "failed to alloc mtd_info\n"); + if (!mtd) return -ENOMEM; - } cafe = (void *)(&mtd[1]); mtd->dev.parent = &pdev->dev; diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 39b2ef848811..66ec95e6ca6c 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -164,7 +164,6 @@ static int __init cmx270_init(void) sizeof(struct nand_chip), GFP_KERNEL); if (!cmx270_nand_mtd) { - pr_debug("Unable to allocate CM-X270 NAND MTD device structure.\n"); ret = -ENOMEM; goto err_kzalloc; } diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index d469a9a1dea0..88109d375ae7 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -199,7 +199,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Allocate memory for MTD device structure and private data */ new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!new_mtd) { - printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); err = -ENOMEM; goto out; } diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index b77a01efb483..a4989ec6292e 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/of_mtd.h> #include <linux/platform_data/mtd-davinci.h> #include <linux/platform_data/mtd-davinci-aemif.h> @@ -487,7 +488,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd) * ten ECC bytes plus the manufacturer's bad block marker byte, and * and not overlapping the default BBT markers. */ -static struct nand_ecclayout hwecc4_small __initconst = { +static struct nand_ecclayout hwecc4_small = { .eccbytes = 10, .eccpos = { 0, 1, 2, 3, 4, /* offset 5 holds the badblock marker */ @@ -503,7 +504,7 @@ static struct nand_ecclayout hwecc4_small __initconst = { * storing ten ECC bytes plus the manufacturer's bad block marker byte, * and not overlapping the default BBT markers. */ -static struct nand_ecclayout hwecc4_2048 __initconst = { +static struct nand_ecclayout hwecc4_2048 = { .eccbytes = 40, .eccpos = { /* at the end of spare sector */ @@ -534,17 +535,19 @@ static struct davinci_nand_pdata struct davinci_nand_pdata *pdata; const char *mode; u32 prop; - int len; pdata = devm_kzalloc(&pdev->dev, sizeof(struct davinci_nand_pdata), GFP_KERNEL); pdev->dev.platform_data = pdata; if (!pdata) - return NULL; + return ERR_PTR(-ENOMEM); if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-chipselect", &prop)) pdev->id = prop; + else + return ERR_PTR(-EINVAL); + if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-mask-ale", &prop)) pdata->mask_ale = prop; @@ -555,6 +558,8 @@ static struct davinci_nand_pdata "ti,davinci-mask-chipsel", &prop)) pdata->mask_chipsel = prop; if (!of_property_read_string(pdev->dev.of_node, + "nand-ecc-mode", &mode) || + !of_property_read_string(pdev->dev.of_node, "ti,davinci-ecc-mode", &mode)) { if (!strncmp("none", mode, 4)) pdata->ecc_mode = NAND_ECC_NONE; @@ -566,12 +571,16 @@ static struct davinci_nand_pdata if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-ecc-bits", &prop)) pdata->ecc_bits = prop; - if (!of_property_read_u32(pdev->dev.of_node, + + prop = of_get_nand_bus_width(pdev->dev.of_node); + if (0 < prop || !of_property_read_u32(pdev->dev.of_node, "ti,davinci-nand-buswidth", &prop)) if (prop == 16) pdata->options |= NAND_BUSWIDTH_16; - if (of_find_property(pdev->dev.of_node, - "ti,davinci-nand-use-bbt", &len)) + if (of_property_read_bool(pdev->dev.of_node, + "nand-on-flash-bbt") || + of_property_read_bool(pdev->dev.of_node, + "ti,davinci-nand-use-bbt")) pdata->bbt_options = NAND_BBT_USE_FLASH; } @@ -585,7 +594,7 @@ static struct davinci_nand_pdata } #endif -static int __init nand_davinci_probe(struct platform_device *pdev) +static int nand_davinci_probe(struct platform_device *pdev) { struct davinci_nand_pdata *pdata; struct davinci_nand_info *info; @@ -598,6 +607,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) nand_ecc_modes_t ecc_mode; pdata = nand_davinci_get_pdata(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + /* insist on board-specific configuration */ if (!pdata) return -ENODEV; @@ -607,11 +619,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev) return -ENODEV; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) { - dev_err(&pdev->dev, "unable to allocate memory\n"); - ret = -ENOMEM; - goto err_nomem; - } + if (!info) + return -ENOMEM; platform_set_drvdata(pdev, info); @@ -619,19 +628,23 @@ static int __init nand_davinci_probe(struct platform_device *pdev) res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res1 || !res2) { dev_err(&pdev->dev, "resource missing\n"); - ret = -EINVAL; - goto err_nomem; + return -EINVAL; } vaddr = devm_ioremap_resource(&pdev->dev, res1); - if (IS_ERR(vaddr)) { - ret = PTR_ERR(vaddr); - goto err_ioremap; - } - base = devm_ioremap_resource(&pdev->dev, res2); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto err_ioremap; + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + + /* + * This registers range is used to setup NAND settings. In case with + * TI AEMIF driver, the same memory address range is requested already + * by AEMIF, so we cannot request it twice, just ioremap. + * The AEMIF and NAND drivers not use the same registers in this range. + */ + base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2)); + if (!base) { + dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2); + return -EADDRNOTAVAIL; } info->dev = &pdev->dev; @@ -699,7 +712,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) spin_unlock_irq(&davinci_nand_lock); if (ret == -EBUSY) - goto err_ecc; + return ret; info->chip.ecc.calculate = nand_davinci_calculate_4bit; info->chip.ecc.correct = nand_davinci_correct_4bit; @@ -715,8 +728,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.strength = pdata->ecc_bits; break; default: - ret = -EINVAL; - goto err_ecc; + return -EINVAL; } info->chip.ecc.mode = ecc_mode; @@ -724,7 +736,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) if (IS_ERR(info->clk)) { ret = PTR_ERR(info->clk); dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); - goto err_clk; + return ret; } ret = clk_prepare_enable(info->clk); @@ -753,7 +765,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->core_chipsel); if (ret < 0) { dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); - goto err_timing; + goto err; } spin_lock_irq(&davinci_nand_lock); @@ -769,7 +781,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL); if (ret < 0) { dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); - goto err_scan; + goto err; } /* Update ECC layout if needed ... for 1-bit HW ECC, the default @@ -783,7 +795,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) if (!chunks || info->mtd.oobsize < 16) { dev_dbg(&pdev->dev, "too small\n"); ret = -EINVAL; - goto err_scan; + goto err; } /* For small page chips, preserve the manufacturer's @@ -814,7 +826,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "no 4-bit ECC support yet " "for 4KiB-page NAND\n"); ret = -EIO; - goto err_scan; + goto err; syndrome_done: info->chip.ecc.layout = &info->ecclayout; @@ -822,7 +834,7 @@ syndrome_done: ret = nand_scan_tail(&info->mtd); if (ret < 0) - goto err_scan; + goto err; if (pdata->parts) ret = mtd_device_parse_register(&info->mtd, NULL, NULL, @@ -835,7 +847,7 @@ syndrome_done: NULL, 0); } if (ret < 0) - goto err_scan; + goto err; val = davinci_nand_readl(info, NRCSR_OFFSET); dev_info(&pdev->dev, "controller rev. %d.%d\n", @@ -843,8 +855,7 @@ syndrome_done: return 0; -err_scan: -err_timing: +err: clk_disable_unprepare(info->clk); err_clk_enable: @@ -852,15 +863,10 @@ err_clk_enable: if (ecc_mode == NAND_ECC_HW_SYNDROME) ecc4_busy = false; spin_unlock_irq(&davinci_nand_lock); - -err_ecc: -err_clk: -err_ioremap: -err_nomem: return ret; } -static int __exit nand_davinci_remove(struct platform_device *pdev) +static int nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); @@ -877,7 +883,8 @@ static int __exit nand_davinci_remove(struct platform_device *pdev) } static struct platform_driver nand_davinci_driver = { - .remove = __exit_p(nand_davinci_remove), + .probe = nand_davinci_probe, + .remove = nand_davinci_remove, .driver = { .name = "davinci_nand", .owner = THIS_MODULE, @@ -886,7 +893,7 @@ static struct platform_driver nand_davinci_driver = { }; MODULE_ALIAS("platform:davinci_nand"); -module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe); +module_platform_driver(nand_davinci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 370b9dd7a278..c07cd573ad3a 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -125,7 +125,6 @@ static void reset_buf(struct denali_nand_info *denali) static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) { - BUG_ON(denali->buf.tail >= sizeof(denali->buf.buf)); denali->buf.buf[denali->buf.tail++] = byte; } @@ -897,7 +896,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) /* this function examines buffers to see if they contain data that * indicate that the buffer is part of an erased region of flash. */ -bool is_erased(uint8_t *buf, int len) +static bool is_erased(uint8_t *buf, int len) { int i = 0; for (i = 0; i < len; i++) @@ -1429,20 +1428,12 @@ int denali_init(struct denali_nand_info *denali) } } - /* Is 32-bit DMA supported? */ - ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); - if (ret) { - pr_err("Spectra: no usable DMA configuration\n"); - return ret; - } - denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, - DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); + /* allocate a temporary buffer for nand_scan_ident() */ + denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, + GFP_DMA | GFP_KERNEL); + if (!denali->buf.buf) + return -ENOMEM; - if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { - dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); - return -EIO; - } denali->mtd.dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); @@ -1475,12 +1466,29 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* MTD supported page sizes vary by kernel. We validate our - * kernel supports the device here. - */ - if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { - ret = -ENODEV; - pr_err("Spectra: device size not supported by this version of MTD."); + /* allocate the right size buffer now */ + devm_kfree(denali->dev, denali->buf.buf); + denali->buf.buf = devm_kzalloc(denali->dev, + denali->mtd.writesize + denali->mtd.oobsize, + GFP_KERNEL); + if (!denali->buf.buf) { + ret = -ENOMEM; + goto failed_req_irq; + } + + /* Is 32-bit DMA supported? */ + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); + if (ret) { + pr_err("Spectra: no usable DMA configuration\n"); + goto failed_req_irq; + } + + denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); + ret = -EIO; goto failed_req_irq; } @@ -1602,7 +1610,8 @@ EXPORT_SYMBOL(denali_init); void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); - dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, + dma_unmap_single(denali->dev, denali->buf.dma_buf, + denali->mtd.writesize + denali->mtd.oobsize, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index cec5712862c9..966817462421 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -455,12 +455,10 @@ #define ECC_SECTOR_SIZE 512 -#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) - struct nand_buf { int head; int tail; - uint8_t buf[DENALI_BUF_SIZE]; + uint8_t *buf; dma_addr_t dma_buf; }; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 92530244e2cb..babb02c4b220 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -108,7 +108,7 @@ static int denali_dt_probe(struct platform_device *ofdev) denali->dev->dma_mask = NULL; } - dt->clk = clk_get(&ofdev->dev, NULL); + dt->clk = devm_clk_get(&ofdev->dev, NULL); if (IS_ERR(dt->clk)) { dev_err(&ofdev->dev, "no clk available\n"); return PTR_ERR(dt->clk); @@ -124,7 +124,6 @@ static int denali_dt_probe(struct platform_device *ofdev) out_disable_clk: clk_disable_unprepare(dt->clk); - clk_put(dt->clk); return ret; } @@ -135,7 +134,6 @@ static int denali_dt_remove(struct platform_device *ofdev) denali_remove(&dt->denali); clk_disable(dt->clk); - clk_put(dt->clk); return 0; } diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 033f177a6369..6e2f387b823f 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -21,7 +21,7 @@ #define DENALI_NAND_NAME "denali-nand-pci" /* List of platforms this NAND controller has be integrated into */ -static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = { +static const struct pci_device_id denali_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, { /* end: all zeroes */ } @@ -131,7 +131,6 @@ static struct pci_driver denali_pci_driver = { static int denali_init_pci(void) { - pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); return pci_register_driver(&denali_pci_driver); } module_init(denali_init_pci); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b68a4959f700..fec31d71b84e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1058,7 +1058,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1))) @@ -1166,7 +1165,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } @@ -1440,10 +1438,13 @@ static int __init doc_probe(unsigned long physadr) int reg, len, numchips; int ret = 0; + if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL)) + return -EBUSY; virtadr = ioremap(physadr, DOC_IOREMAP_LEN); if (!virtadr) { printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); - return -EIO; + ret = -EIO; + goto error_ioremap; } /* It's not possible to cleanly detect the DiskOnChip - the @@ -1561,7 +1562,6 @@ static int __init doc_probe(unsigned long physadr) sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); mtd = kzalloc(len, GFP_KERNEL); if (!mtd) { - printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); ret = -ENOMEM; goto fail; } @@ -1629,6 +1629,10 @@ static int __init doc_probe(unsigned long physadr) WriteDOC(save_control, virtadr, DOCControl); fail: iounmap(virtadr); + +error_ioremap: + release_mem_region(physadr, DOC_IOREMAP_LEN); + return ret; } @@ -1645,6 +1649,7 @@ static void release_nanddoc(void) nextmtd = doc->nextdoc; nand_release(mtd); iounmap(doc->virtadr); + release_mem_region(doc->physadr, DOC_IOREMAP_LEN); kfree(mtd); } } diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index c966fc7474ce..bcf60800c3ce 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -847,7 +847,6 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) if (!fsl_lbc_ctrl_dev->nand) { elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); if (!elbc_fcm_ctrl) { - dev_err(dev, "failed to allocate memory\n"); mutex_unlock(&fsl_elbc_nand_mutex); ret = -ENOMEM; goto err; @@ -875,7 +874,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) goto err; } - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 43355779cff5..90ca7e75d6f0 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -1060,7 +1060,6 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) if (!fsl_ifc_ctrl_dev->nand) { ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); if (!ifc_nand_ctrl) { - dev_err(&dev->dev, "failed to allocate memory\n"); mutex_unlock(&fsl_ifc_nand_mutex); return -ENOMEM; } @@ -1101,7 +1100,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) IFC_NAND_EVTER_INTR_FTOERIR_EN | IFC_NAND_EVTER_INTR_WPERIR_EN, &ifc->ifc_nand.nand_evter_intr_en); - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 8b2752263db9..1550692973dc 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -889,10 +889,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, pdata->nand_timings = devm_kzalloc(&pdev->dev, sizeof(*pdata->nand_timings), GFP_KERNEL); - if (!pdata->nand_timings) { - dev_err(&pdev->dev, "no memory for nand_timing\n"); + if (!pdata->nand_timings) return -ENOMEM; - } of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, sizeof(*pdata->nand_timings)); @@ -950,10 +948,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure\n"); + if (!host) return -ENOMEM; - } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); host->data_va = devm_ioremap_resource(&pdev->dev, res); @@ -1108,8 +1104,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->ecc_place = &fsmc_ecc4_lp_place; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } else { @@ -1124,8 +1120,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.layout = &fsmc_ecc1_128_layout; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index e826f898241f..8e6148aa4539 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -132,13 +132,17 @@ static int gpio_nand_get_config_of(const struct device *dev, static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) { - struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); + struct resource *r; u64 addr; - if (!r || of_property_read_u64(pdev->dev.of_node, + if (of_property_read_u64(pdev->dev.of_node, "gpio-control-nand,io-sync-reg", &addr)) return NULL; + r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + r->start = addr; r->end = r->start + 0x3; r->flags = IORESOURCE_MEM; @@ -211,10 +215,8 @@ static int gpio_nand_probe(struct platform_device *pdev) return -EINVAL; gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL); - if (!gpiomtd) { - dev_err(&pdev->dev, "failed to create NAND MTD\n"); + if (!gpiomtd) return -ENOMEM; - } chip = &gpiomtd->nand_chip; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index aaced29727fb..dd1df605a1d6 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -20,6 +20,7 @@ */ #include <linux/delay.h> #include <linux/clk.h> +#include <linux/slab.h> #include "gpmi-nand.h" #include "gpmi-regs.h" @@ -207,30 +208,41 @@ void gpmi_dump_info(struct gpmi_nand_data *this) u32 reg; int i; - pr_err("Show GPMI registers :\n"); + dev_err(this->dev, "Show GPMI registers :\n"); for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { reg = readl(r->gpmi_regs + i * 0x10); - pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); } /* start to print out the BCH info */ - pr_err("Show BCH registers :\n"); + dev_err(this->dev, "Show BCH registers :\n"); for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) { reg = readl(r->bch_regs + i * 0x10); - pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); } - pr_err("BCH Geometry :\n"); - pr_err("GF length : %u\n", geo->gf_len); - pr_err("ECC Strength : %u\n", geo->ecc_strength); - pr_err("Page Size in Bytes : %u\n", geo->page_size); - pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); - pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); - pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); - pr_err("Payload Size in Bytes : %u\n", geo->payload_size); - pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); - pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); - pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); - pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); + dev_err(this->dev, "BCH Geometry :\n" + "GF length : %u\n" + "ECC Strength : %u\n" + "Page Size in Bytes : %u\n" + "Metadata Size in Bytes : %u\n" + "ECC Chunk Size in Bytes: %u\n" + "ECC Chunk Count : %u\n" + "Payload Size in Bytes : %u\n" + "Auxiliary Size in Bytes: %u\n" + "Auxiliary Status Offset: %u\n" + "Block Mark Byte Offset : %u\n" + "Block Mark Bit Offset : %u\n", + geo->gf_len, + geo->ecc_strength, + geo->page_size, + geo->metadata_size, + geo->ecc_chunk_size, + geo->ecc_chunk_count, + geo->payload_size, + geo->auxiliary_size, + geo->auxiliary_status_offset, + geo->block_mark_byte_offset, + geo->block_mark_bit_offset); } /* Configures the geometry for BCH. */ @@ -265,8 +277,8 @@ int bch_set_geometry(struct gpmi_nand_data *this) * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. * On the other hand, the MX28 needs the reset, because one case has been * seen where the BCH produced ECC errors constantly after 10000 - * consecutive reboots. The latter case has not been seen on the MX23 yet, - * still we don't know if it could happen there as well. + * consecutive reboots. The latter case has not been seen on the MX23 + * yet, still we don't know if it could happen there as well. */ ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); if (ret) @@ -353,7 +365,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, improved_timing_is_available = (target.tREA_in_ns >= 0) && (target.tRLOH_in_ns >= 0) && - (target.tRHOH_in_ns >= 0) ; + (target.tRHOH_in_ns >= 0); /* Inspect the clock. */ nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]); @@ -911,10 +923,14 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) struct resources *r = &this->resources; struct nand_chip *nand = &this->nand; struct mtd_info *mtd = &this->mtd; - uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; + uint8_t *feature; unsigned long rate; int ret; + feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL); + if (!feature) + return -ENOMEM; + nand->select_chip(mtd, 0); /* [1] send SET FEATURE commond to NAND */ @@ -942,11 +958,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) this->flags |= GPMI_ASYNC_EDO_ENABLED; this->timing_mode = mode; + kfree(feature); dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode); return 0; err_out: nand->select_chip(mtd, -1); + kfree(feature); dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode); return -EINVAL; } @@ -986,7 +1004,7 @@ void gpmi_begin(struct gpmi_nand_data *this) /* Enable the clock. */ ret = gpmi_enable_clk(this); if (ret) { - pr_err("We failed in enable the clk\n"); + dev_err(this->dev, "We failed in enable the clk\n"); goto err_out; } @@ -1003,7 +1021,7 @@ void gpmi_begin(struct gpmi_nand_data *this) /* [1] Set HW_GPMI_TIMING0 */ reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | - BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles); writel(reg, gpmi_regs + HW_GPMI_TIMING0); @@ -1090,7 +1108,7 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); reg = readl(r->gpmi_regs + HW_GPMI_STAT); } else - pr_err("unknow arch.\n"); + dev_err(this->dev, "unknow arch.\n"); return reg & mask; } @@ -1121,10 +1139,8 @@ int gpmi_send_command(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ sgl = &this->cmd_sgl; @@ -1134,11 +1150,8 @@ int gpmi_send_command(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] submit the DMA */ set_dma_type(this, DMA_FOR_COMMAND); @@ -1167,20 +1180,17 @@ int gpmi_send_data(struct gpmi_nand_data *this) pio[1] = 0; desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] send DMA request */ prepare_data_dma(this, DMA_TO_DEVICE); desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; + /* [3] submit the DMA */ set_dma_type(this, DMA_FOR_WRITE_DATA); return start_dma_without_bch_irq(this, desc); @@ -1204,20 +1214,16 @@ int gpmi_read_data(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] : send DMA request */ prepare_data_dma(this, DMA_FROM_DEVICE); desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] : submit the DMA */ set_dma_type(this, DMA_FOR_READ_DATA); @@ -1262,10 +1268,9 @@ int gpmi_send_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; + set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); return start_dma_with_bch_irq(this, desc); } @@ -1297,10 +1302,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, 2, DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] Enable the BCH block and read. */ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; @@ -1327,10 +1330,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] Disable the BCH block */ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; @@ -1348,10 +1349,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, 3, DMA_TRANS_NONE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 3 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [4] submit the DMA */ set_dma_type(this, DMA_FOR_READ_ECC_PAGE); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index dabbc14db563..ca6369fe91ff 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -18,9 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/clk.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -352,6 +349,9 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) int common_nfc_set_geometry(struct gpmi_nand_data *this) { + if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc") + && set_geometry_by_ecc_info(this)) + return 0; return legacy_set_geometry(this); } @@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) struct scatterlist *sgl = &this->data_sgl; int ret; - this->direct_dma_map_ok = true; - /* first try to map the upper buffer directly */ - sg_init_one(sgl, this->upper_buf, this->upper_len); - ret = dma_map_sg(this->dev, sgl, 1, dr); - if (ret == 0) { - /* We have to use our own DMA buffer. */ - sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); - - if (dr == DMA_TO_DEVICE) - memcpy(this->data_buffer_dma, this->upper_buf, - this->upper_len); - + if (virt_addr_valid(this->upper_buf) && + !object_is_on_stack(this->upper_buf)) { + sg_init_one(sgl, this->upper_buf, this->upper_len); ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) - pr_err("DMA mapping failed.\n"); + goto map_fail; - this->direct_dma_map_ok = false; + this->direct_dma_map_ok = true; + return; } + +map_fail: + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, this->upper_len); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len); + + dma_map_sg(this->dev, sgl, 1, dr); + + this->direct_dma_map_ok = false; } /* This will be called after the DMA operation is finished. */ @@ -416,7 +419,7 @@ static void dma_irq_callback(void *param) break; default: - pr_err("in wrong DMA operation.\n"); + dev_err(this->dev, "in wrong DMA operation.\n"); } complete(dma_c); @@ -438,7 +441,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the DMA block. */ err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "DMA timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -467,7 +471,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the BCH block. */ err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "BCH timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -483,70 +488,38 @@ static int acquire_register_block(struct gpmi_nand_data *this, void __iomem *p; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); - if (!r) { - pr_err("Can't get resource for %s\n", res_name); - return -ENODEV; - } - - p = ioremap(r->start, resource_size(r)); - if (!p) { - pr_err("Can't remap %s\n", res_name); - return -ENOMEM; - } + p = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(p)) + return PTR_ERR(p); if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) res->gpmi_regs = p; else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) res->bch_regs = p; else - pr_err("unknown resource name : %s\n", res_name); + dev_err(this->dev, "unknown resource name : %s\n", res_name); return 0; } -static void release_register_block(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - if (res->gpmi_regs) - iounmap(res->gpmi_regs); - if (res->bch_regs) - iounmap(res->bch_regs); - res->gpmi_regs = NULL; - res->bch_regs = NULL; -} - static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) { struct platform_device *pdev = this->pdev; - struct resources *res = &this->resources; const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; struct resource *r; int err; r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); if (!r) { - pr_err("Can't get resource for %s\n", res_name); + dev_err(this->dev, "Can't get resource for %s\n", res_name); return -ENODEV; } - err = request_irq(r->start, irq_h, 0, res_name, this); - if (err) { - pr_err("Can't own %s\n", res_name); - return err; - } - - res->bch_low_interrupt = r->start; - res->bch_high_interrupt = r->end; - return 0; -} - -static void release_bch_irq(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - int i = res->bch_low_interrupt; + err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this); + if (err) + dev_err(this->dev, "error requesting BCH IRQ\n"); - for (; i <= res->bch_high_interrupt; i++) - free_irq(i, this); + return err; } static void release_dma_channels(struct gpmi_nand_data *this) @@ -567,7 +540,7 @@ static int acquire_dma_channels(struct gpmi_nand_data *this) /* request dma channel */ dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx"); if (!dma_chan) { - pr_err("Failed to request DMA channel.\n"); + dev_err(this->dev, "Failed to request DMA channel.\n"); goto acquire_err; } @@ -579,21 +552,6 @@ acquire_err: return -EINVAL; } -static void gpmi_put_clks(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - struct clk *clk; - int i; - - for (i = 0; i < GPMI_CLK_MAX; i++) { - clk = r->clock[i]; - if (clk) { - clk_put(clk); - r->clock[i] = NULL; - } - } -} - static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", }; @@ -606,7 +564,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) int err, i; /* The main clock is stored in the first. */ - r->clock[0] = clk_get(this->dev, "gpmi_io"); + r->clock[0] = devm_clk_get(this->dev, "gpmi_io"); if (IS_ERR(r->clock[0])) { err = PTR_ERR(r->clock[0]); goto err_clock; @@ -622,7 +580,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) if (extra_clks[i - 1] == NULL) break; - clk = clk_get(this->dev, extra_clks[i - 1]); + clk = devm_clk_get(this->dev, extra_clks[i - 1]); if (IS_ERR(clk)) { err = PTR_ERR(clk); goto err_clock; @@ -644,7 +602,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) err_clock: dev_dbg(this->dev, "failed in finding the clocks.\n"); - gpmi_put_clks(this); return err; } @@ -666,7 +623,7 @@ static int acquire_resources(struct gpmi_nand_data *this) ret = acquire_dma_channels(this); if (ret) - goto exit_dma_channels; + goto exit_regs; ret = gpmi_get_clks(this); if (ret) @@ -675,18 +632,12 @@ static int acquire_resources(struct gpmi_nand_data *this) exit_clock: release_dma_channels(this); -exit_dma_channels: - release_bch_irq(this); exit_regs: - release_register_block(this); return ret; } static void release_resources(struct gpmi_nand_data *this) { - gpmi_put_clks(this); - release_register_block(this); - release_bch_irq(this); release_dma_channels(this); } @@ -732,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this, length, DMA_FROM_DEVICE); if (dma_mapping_error(dev, dest_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -783,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this, DMA_TO_DEVICE); if (dma_mapping_error(dev, source_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -837,14 +786,23 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) { struct bch_geometry *geo = &this->bch_geometry; struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); if (this->cmd_buffer == NULL) goto error_alloc; - /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ - this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); + /* + * [2] Allocate a read/write data buffer. + * The gpmi_alloc_dma_buffer can be called twice. + * We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer + * is called before the nand_scan_ident; and we allocate a buffer + * of the real NAND page size when the gpmi_alloc_dma_buffer is + * called after the nand_scan_ident. + */ + this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE, + GFP_DMA | GFP_KERNEL); if (this->data_buffer_dma == NULL) goto error_alloc; @@ -872,7 +830,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) error_alloc: gpmi_free_dma_buffer(this); - pr_err("Error allocating DMA buffers!\n"); return -ENOMEM; } @@ -904,7 +861,8 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) ret = gpmi_send_command(this); if (ret) - pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + dev_err(this->dev, "Chip: %u, Error %d\n", + this->current_chip, ret); this->command_length = 0; } @@ -935,7 +893,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = buf; this->upper_len = len; @@ -947,7 +905,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = (uint8_t *)buf; this->upper_len = len; @@ -1026,13 +984,13 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned int max_bitflips = 0; int ret; - pr_debug("page number is : %d\n", page); + dev_dbg(this->dev, "page number is : %d\n", page); ret = read_page_prepare(this, buf, mtd->writesize, this->payload_virt, this->payload_phys, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate DMA buffer\n"); + dev_err(this->dev, "Inadequate DMA buffer\n"); ret = -ENOMEM; return ret; } @@ -1046,7 +1004,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, payload_virt, payload_phys); if (ret) { - pr_err("Error in ECC-based read: %d\n", ret); + dev_err(this->dev, "Error in ECC-based read: %d\n", ret); return ret; } @@ -1102,7 +1060,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t auxiliary_phys; int ret; - pr_debug("ecc write page.\n"); + dev_dbg(this->dev, "ecc write page.\n"); if (this->swap_block_mark) { /* * If control arrives here, we're doing block mark swapping. @@ -1132,7 +1090,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate payload DMA buffer\n"); + dev_err(this->dev, "Inadequate payload DMA buffer\n"); return 0; } @@ -1142,7 +1100,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->auxiliary_size, &auxiliary_virt, &auxiliary_phys); if (ret) { - pr_err("Inadequate auxiliary DMA buffer\n"); + dev_err(this->dev, "Inadequate auxiliary DMA buffer\n"); goto exit_auxiliary; } } @@ -1150,7 +1108,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* Ask the NFC. */ ret = gpmi_send_page(this, payload_phys, auxiliary_phys); if (ret) - pr_err("Error in ECC-based write: %d\n", ret); + dev_err(this->dev, "Error in ECC-based write: %d\n", ret); if (!this->swap_block_mark) { send_page_end(this, chip->oob_poi, mtd->oobsize, @@ -1240,7 +1198,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, { struct gpmi_nand_data *this = chip->priv; - pr_debug("page number is %d\n", page); + dev_dbg(this->dev, "page number is %d\n", page); /* clear the OOB buffer */ memset(chip->oob_poi, ~0, mtd->oobsize); @@ -1453,7 +1411,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the NCB fingerprint into the page buffer. */ memset(buffer, ~0, mtd->writesize); - memset(chip->oob_poi, ~0, mtd->oobsize); memcpy(buffer + 12, fingerprint, strlen(fingerprint)); /* Loop through the first search area, writing NCB fingerprints. */ @@ -1568,7 +1525,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) /* Set up the NFC geometry which is used by BCH. */ ret = bch_set_geometry(this); if (ret) { - pr_err("Error setting BCH geometry : %d\n", ret); + dev_err(this->dev, "Error setting BCH geometry : %d\n", ret); return ret; } @@ -1576,20 +1533,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) return gpmi_alloc_dma_buffer(this); } -static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) -{ - /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ - if (GPMI_IS_MX23(this)) - this->swap_block_mark = false; - else - this->swap_block_mark = true; - - /* Set up the medium geometry */ - return gpmi_set_geometry(this); - -} - -static void gpmi_nfc_exit(struct gpmi_nand_data *this) +static void gpmi_nand_exit(struct gpmi_nand_data *this) { nand_release(&this->mtd); gpmi_free_dma_buffer(this); @@ -1603,8 +1547,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this) struct bch_geometry *bch_geo = &this->bch_geometry; int ret; - /* Prepare for the BBT scan. */ - ret = gpmi_pre_bbt_scan(this); + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + this->swap_block_mark = !GPMI_IS_MX23(this); + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); if (ret) return ret; @@ -1629,7 +1576,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this) return 0; } -static int gpmi_nfc_init(struct gpmi_nand_data *this) +static int gpmi_nand_init(struct gpmi_nand_data *this) { struct mtd_info *mtd = &this->mtd; struct nand_chip *chip = &this->nand; @@ -1693,7 +1640,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this) return 0; err_out: - gpmi_nfc_exit(this); + gpmi_nand_exit(this); return ret; } @@ -1728,15 +1675,13 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (of_id) { pdev->id_entry = of_id->data; } else { - pr_err("Failed to find the right device id.\n"); + dev_err(&pdev->dev, "Failed to find the right device id.\n"); return -ENODEV; } this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); - if (!this) { - pr_err("Failed to allocate per-device memory\n"); + if (!this) return -ENOMEM; - } platform_set_drvdata(pdev, this); this->pdev = pdev; @@ -1750,7 +1695,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_nfc_init; - ret = gpmi_nfc_init(this); + ret = gpmi_nand_init(this); if (ret) goto exit_nfc_init; @@ -1770,7 +1715,7 @@ static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); - gpmi_nfc_exit(this); + gpmi_nand_exit(this); release_resources(this); return 0; } diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index a7685e3a8748..4c801fa18725 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -26,8 +26,6 @@ struct resources { void __iomem *gpmi_regs; void __iomem *bch_regs; - unsigned int bch_low_interrupt; - unsigned int bch_high_interrupt; unsigned int dma_low_channel; unsigned int dma_high_channel; struct clk *clock[GPMI_CLK_MAX]; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index a264b888c66c..a2c804de156b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -416,10 +416,8 @@ static int jz_nand_probe(struct platform_device *pdev) uint8_t nand_maf_id = 0, nand_dev_id = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) { - dev_err(&pdev->dev, "Failed to allocate device structure.\n"); + if (!nand) return -ENOMEM; - } ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); if (ret) diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 327d96c03505..687478c9f09c 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -539,20 +539,6 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, return 0; } -static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) -{ - int res; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - lpc32xx_waitfunc(mtd, chip); - - return res; -} - static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { @@ -627,10 +613,8 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) struct device_node *np = dev->of_node; ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); - if (!ncfg) { - dev_err(dev, "could not allocate memory for platform data\n"); + if (!ncfg) return NULL; - } of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay); of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay); @@ -666,10 +650,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure.\n"); + if (!host) return -ENOMEM; - } rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->io_base = devm_ioremap_resource(&pdev->dev, rc); @@ -732,9 +714,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) nand_chip->ecc.write_oob = lpc32xx_write_oob; nand_chip->ecc.read_oob = lpc32xx_read_oob; nand_chip->ecc.strength = 4; - nand_chip->write_page = lpc32xx_write_page; nand_chip->waitfunc = lpc32xx_waitfunc; + nand_chip->options = NAND_NO_SUBPAGE_WRITE; nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; nand_chip->bbt_td = &lpc32xx_nand_bbt; nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror; @@ -764,14 +746,12 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); if (!host->dma_buf) { - dev_err(&pdev->dev, "Error allocating dma_buf memory\n"); res = -ENOMEM; goto err_exit3; } host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); if (!host->dummy_buf) { - dev_err(&pdev->dev, "Error allocating dummy_buf memory\n"); res = -ENOMEM; goto err_exit3; } diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 23e6974ccd20..53a6742e3da3 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -725,10 +725,8 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) struct device_node *np = dev->of_node; ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); - if (!ncfg) { - dev_err(dev, "could not allocate memory for NAND config\n"); + if (!ncfg) return NULL; - } of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks); of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth); @@ -772,10 +770,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure\n"); + if (!host) return -ENOMEM; - } host->io_base_dma = rc->start; host->io_base = devm_ioremap_resource(&pdev->dev, rc); @@ -791,8 +787,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) } if (host->ncfg->wp_gpio == -EPROBE_DEFER) return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && - gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev, + host->ncfg->wp_gpio, "NAND WP")) { dev_err(&pdev->dev, "GPIO not available\n"); return -EBUSY; } @@ -808,7 +804,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; /* Get NAND clock */ - host->clk = clk_get(&pdev->dev, NULL); + host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { dev_err(&pdev->dev, "Clock failure\n"); res = -ENOENT; @@ -858,7 +854,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len, GFP_KERNEL); if (host->data_buf == NULL) { - dev_err(&pdev->dev, "Error allocating memory\n"); res = -ENOMEM; goto err_exit2; } @@ -927,10 +922,8 @@ err_exit3: dma_release_channel(host->dma_chan); err_exit2: clk_disable(host->clk); - clk_put(host->clk); err_exit1: lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); return res; } @@ -953,9 +946,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) writel(tmp, SLC_CTRL(host->io_base)); clk_disable(host->clk); - clk_put(host->clk); lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); return 0; } diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 439bc3896418..61e2abc216ad 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -653,10 +653,8 @@ static int mpc5121_nfc_probe(struct platform_device *op) } prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); - if (!prv) { - dev_err(dev, "Memory exhausted!\n"); + if (!prv) return -ENOMEM; - } mtd = &prv->mtd; chip = &prv->chip; @@ -786,7 +784,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) /* Detect NAND chips */ if (nand_scan(mtd, be32_to_cpup(chips_no))) { dev_err(dev, "NAND Flash not found !\n"); - devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; goto error; } @@ -811,7 +808,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) default: dev_err(dev, "Unsupported NAND flash!\n"); - devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; goto error; } @@ -822,7 +818,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (retval) { dev_err(dev, "Error adding MTD device!\n"); - devm_free_irq(dev, prv->irq, mtd); goto error; } @@ -836,11 +831,8 @@ static int mpc5121_nfc_remove(struct platform_device *op) { struct device *dev = &op->dev; struct mtd_info *mtd = dev_get_drvdata(dev); - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; nand_release(mtd); - devm_free_irq(dev, prv->irq, mtd); mpc5121_nfc_free(dev, mtd); return 0; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 9dfdb06c508b..e9a4835c4dd9 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -677,7 +677,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, ecc_stat >>= 4; } while (--no_subpages); - mtd->ecc_stats.corrected += ret; pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); return ret; @@ -1400,12 +1399,15 @@ static int mxcnd_probe(struct platform_device *pdev) int err = 0; /* Allocate memory for MTD device structure and private data */ - host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) + - NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL); + host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host), + GFP_KERNEL); if (!host) return -ENOMEM; - host->data_buf = (uint8_t *)(host + 1); + /* allocate a temporary buffer for the nand_scan_ident() */ + host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!host->data_buf) + return -ENOMEM; host->dev = &pdev->dev; /* structures must be linked */ @@ -1512,7 +1514,9 @@ static int mxcnd_probe(struct platform_device *pdev) if (err) return err; - clk_prepare_enable(host->clk); + err = clk_prepare_enable(host->clk); + if (err) + return err; host->clk_act = 1; /* @@ -1531,6 +1535,15 @@ static int mxcnd_probe(struct platform_device *pdev) goto escan; } + /* allocate the right size buffer now */ + devm_kfree(&pdev->dev, (void *)host->data_buf); + host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!host->data_buf) { + err = -ENOMEM; + goto escan; + } + /* Call preset again, with correct writesize this time */ host->devtype_data->preset(mtd); @@ -1576,6 +1589,8 @@ static int mxcnd_remove(struct platform_device *pdev) struct mxc_nand_host *host = platform_get_drvdata(pdev); nand_release(&host->mtd); + if (host->clk_act) + clk_disable_unprepare(host->clk); return 0; } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bd39f7b67906..59eba5d2c685 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -29,6 +29,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> @@ -202,6 +204,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) } /** + * nand_write_byte - [DEFAULT] write single byte to chip + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + + chip->write_buf(mtd, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_onfi_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->write_buf(mtd, (uint8_t *)&word, 2); +} + +/** * nand_write_buf - [DEFAULT] write buffer to chip * @mtd: MTD device structure * @buf: data buffer @@ -1408,6 +1455,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** + * nand_setup_read_retry - [INTERN] Set the READ RETRY mode + * @mtd: MTD device structure + * @retry_mode: the retry mode to use + * + * Some vendors supply a special command to shift the Vt threshold, to be used + * when there are too many bitflips in a page (i.e., ECC error). After setting + * a new threshold, the host should retry reading the page. + */ +static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + + pr_debug("setting READ RETRY mode %d\n", retry_mode); + + if (retry_mode >= chip->read_retries) + return -EINVAL; + + if (!chip->setup_read_retry) + return -EOPNOTSUPP; + + return chip->setup_read_retry(mtd, retry_mode); +} + +/** * nand_do_read_ops - [INTERN] Read data with ECC * @mtd: MTD device structure * @from: offset to read from @@ -1420,7 +1491,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, { int chipnr, page, realpage, col, bytes, aligned, oob_required; struct nand_chip *chip = mtd->priv; - struct mtd_ecc_stats stats; int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; @@ -1429,8 +1499,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint8_t *bufpoi, *oob, *buf; unsigned int max_bitflips = 0; - - stats = mtd->ecc_stats; + int retry_mode = 0; + bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -1445,6 +1515,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, oob_required = oob ? 1 : 0; while (1) { + unsigned int ecc_failures = mtd->ecc_stats.failed; + bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); @@ -1452,6 +1524,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; +read_retry: chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* @@ -1481,7 +1554,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed) && + !(mtd->ecc_stats.failed - ecc_failures) && (ops->mode != MTD_OPS_RAW)) { chip->pagebuf = realpage; chip->pagebuf_bitflips = ret; @@ -1492,8 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, memcpy(buf, chip->buffers->databuf + col, bytes); } - buf += bytes; - if (unlikely(oob)) { int toread = min(oobreadlen, max_oobsize); @@ -1511,6 +1582,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else nand_wait_ready(mtd); } + + if (mtd->ecc_stats.failed - ecc_failures) { + if (retry_mode + 1 <= chip->read_retries) { + retry_mode++; + ret = nand_setup_read_retry(mtd, + retry_mode); + if (ret < 0) + break; + + /* Reset failures; retry */ + mtd->ecc_stats.failed = ecc_failures; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_fail = true; + } + } + + buf += bytes; } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1520,6 +1610,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, readlen -= bytes; + /* Reset to retry mode 0 */ + if (retry_mode) { + ret = nand_setup_read_retry(mtd, 0); + if (ret < 0) + break; + retry_mode = 0; + } + if (!readlen) break; @@ -1545,7 +1643,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (ret < 0) return ret; - if (mtd->ecc_stats.failed - stats.failed) + if (ecc_fail) return -EBADMSG; return max_bitflips; @@ -2716,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { int status; + int i; if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -2723,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, return -EINVAL; chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->write_byte(mtd, subfeature_param[i]); + status = chip->waitfunc(mtd, chip); if (status & NAND_STATUS_FAIL) return -EIO; @@ -2740,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { + int i; + if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES)) @@ -2749,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + *subfeature_param++ = chip->read_byte(mtd); return 0; } @@ -2812,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf || chip->write_buf == nand_write_buf) chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->write_byte || chip->write_byte == nand_write_byte) + chip->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!chip->read_buf || chip->read_buf == nand_read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->scan_bbt) @@ -2926,6 +3032,30 @@ ext_out: return ret; } +static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; + + return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); +} + +/* + * Configure chip properties from Micron vendor-specific ONFI table + */ +static void nand_onfi_detect_micron(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct nand_onfi_vendor_micron *micron = (void *)p->vendor; + + if (le16_to_cpu(p->vendor_revision) < 1) + return; + + chip->read_retries = micron->read_retry_options; + chip->setup_read_retry = nand_setup_read_retry_micron; +} + /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -2979,7 +3109,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 10; if (!chip->onfi_version) { - pr_info("%s: unsupported ONFI version: %d\n", __func__, val); + pr_info("unsupported ONFI version: %d\n", val); return 0; } @@ -3032,6 +3162,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, pr_warn("Could not retrieve ONFI ECC requirements\n"); } + if (p->jedec_id == NAND_MFR_MICRON) + nand_onfi_detect_micron(chip, p); + return 1; } @@ -3152,9 +3285,12 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, mtd->oobsize = 512; break; case 6: - default: /* Other cases are "reserved" (unknown) */ mtd->oobsize = 640; break; + case 7: + default: /* Other cases are "reserved" (unknown) */ + mtd->oobsize = 1024; + break; } extid >>= 2; /* Calc blocksize */ @@ -3325,6 +3461,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, *busw = type->options & NAND_BUSWIDTH_16; + if (!mtd->name) + mtd->name = type->name; + return true; } return false; @@ -3372,8 +3511,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - pr_info("%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, + pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -3440,10 +3578,10 @@ ident_done: * Check, if buswidth is correct. Hardware drivers should set * chip correct! */ - pr_info("NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - pr_warn("NAND bus width %d instead %d bit\n", + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); return ERR_PTR(-EINVAL); @@ -3472,14 +3610,13 @@ ident_done: if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n", - *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name); - - pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n", + pr_info("%dMiB, %s, page size: %d, OOB size: %d\n", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->writesize, mtd->oobsize); - return type; } @@ -3535,7 +3672,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->select_chip(mtd, -1); } if (i > 1) - pr_info("%d NAND chips detected\n", i); + pr_info("%d chips detected\n", i); /* Store the number of chips and calc total size for mtd */ chip->numchips = i; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a87b0a3afa35..daa2faacd7d0 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -169,6 +169,8 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_AMD, "AMD/Spansion"}, {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, + {NAND_MFR_SANDISK, "SanDisk"}, + {NAND_MFR_INTEL, "Intel"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 52115151e4a7..9ee09a8177c6 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -241,12 +241,10 @@ static int nuc900_nand_probe(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand; struct nand_chip *chip; - int retval; struct resource *res; - retval = 0; - - nuc900_nand = kzalloc(sizeof(struct nuc900_nand), GFP_KERNEL); + nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand), + GFP_KERNEL); if (!nuc900_nand) return -ENOMEM; chip = &(nuc900_nand->chip); @@ -255,11 +253,9 @@ static int nuc900_nand_probe(struct platform_device *pdev) nuc900_nand->mtd.owner = THIS_MODULE; spin_lock_init(&nuc900_nand->lock); - nuc900_nand->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(nuc900_nand->clk)) { - retval = -ENOENT; - goto fail1; - } + nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(nuc900_nand->clk)) + return -ENOENT; clk_enable(nuc900_nand->clk); chip->cmdfunc = nuc900_nand_command_lp; @@ -272,57 +268,29 @@ static int nuc900_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_SOFT; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENXIO; - goto fail1; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - retval = -EBUSY; - goto fail1; - } - - nuc900_nand->reg = ioremap(res->start, resource_size(res)); - if (!nuc900_nand->reg) { - retval = -ENOMEM; - goto fail2; - } + nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nuc900_nand->reg)) + return PTR_ERR(nuc900_nand->reg); nuc900_nand_enable(nuc900_nand); - if (nand_scan(&(nuc900_nand->mtd), 1)) { - retval = -ENXIO; - goto fail3; - } + if (nand_scan(&(nuc900_nand->mtd), 1)) + return -ENXIO; mtd_device_register(&(nuc900_nand->mtd), partitions, ARRAY_SIZE(partitions)); platform_set_drvdata(pdev, nuc900_nand); - return retval; - -fail3: iounmap(nuc900_nand->reg); -fail2: release_mem_region(res->start, resource_size(res)); -fail1: kfree(nuc900_nand); - return retval; + return 0; } static int nuc900_nand_remove(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); - struct resource *res; nand_release(&nuc900_nand->mtd); - iounmap(nuc900_nand->reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - clk_disable(nuc900_nand->clk); - clk_put(nuc900_nand->clk); - - kfree(nuc900_nand); return 0; } diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f77725009907..ef4190a02b7b 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1730,13 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev) break; case NAND_OMAP_POLLED: - if (nand_chip->options & NAND_BUSWIDTH_16) { - nand_chip->read_buf = omap_read_buf16; - nand_chip->write_buf = omap_write_buf16; - } else { - nand_chip->read_buf = omap_read_buf8; - nand_chip->write_buf = omap_write_buf8; - } + /* Use nand_base defaults for {read,write}_buf */ break; case NAND_OMAP_PREFETCH_DMA: diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index a393a5b6ce1e..dd7fe817eafb 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -87,7 +87,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); if (!nc) { - printk(KERN_ERR "orion_nand: failed to allocate device structure.\n"); ret = -ENOMEM; goto no_res; } @@ -101,7 +100,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) io_base = ioremap(res->start, resource_size(res)); if (!io_base) { - printk(KERN_ERR "orion_nand: ioremap failed\n"); + dev_err(&pdev->dev, "ioremap failed\n"); ret = -EIO; goto no_res; } @@ -110,7 +109,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data), GFP_KERNEL); if (!board) { - printk(KERN_ERR "orion_nand: failed to allocate board structure.\n"); ret = -ENOMEM; goto no_res; } diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 4d174366a0f0..90f871acb0ef 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match); static struct platform_driver pasemi_nand_driver = { .driver = { - .name = (char*)driver_name, + .name = driver_name, .owner = THIS_MODULE, .of_match_table = pasemi_nand_match, }, diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index cad4cdc9df39..0b068a5c0bff 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -9,6 +9,7 @@ * */ +#include <linux/err.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -47,30 +48,16 @@ static int plat_nand_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - /* Allocate memory for the device structure (and zero it) */ - data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate device structure.\n"); + data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data), + GFP_KERNEL); + if (!data) return -ENOMEM; - } - - if (!request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto out_free; - } - data->io_base = ioremap(res->start, resource_size(res)); - if (data->io_base == NULL) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -EIO; - goto out_release_io; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->io_base)) + return PTR_ERR(data->io_base); data->chip.priv = &data; data->mtd.priv = &data->chip; @@ -122,11 +109,6 @@ static int plat_nand_probe(struct platform_device *pdev) out: if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); - iounmap(data->io_base); -out_release_io: - release_mem_region(res->start, resource_size(res)); -out_free: - kfree(data); return err; } @@ -137,16 +119,10 @@ static int plat_nand_remove(struct platform_device *pdev) { struct plat_nand_data *data = platform_get_drvdata(pdev); struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_release(&data->mtd); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); - iounmap(data->io_base); - release_mem_region(res->start, resource_size(res)); - kfree(data); return 0; } diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4b3aaa898a8b..2a7a0b27ac38 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -7,6 +7,8 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * See Documentation/mtd/nand/pxa3xx-nand.txt for more details. */ #include <linux/kernel.h> @@ -24,6 +26,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_mtd.h> #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #define ARCH_HAS_DMA @@ -35,6 +38,7 @@ #include <linux/platform_data/mtd-nand-pxa3xx.h> +#define NAND_DEV_READY_TIMEOUT 50 #define CHIP_DELAY_TIMEOUT (2 * HZ/10) #define NAND_STOP_DELAY (2 * HZ/50) #define PAGE_CHUNK_SIZE (2048) @@ -54,6 +58,7 @@ #define NDPCR (0x18) /* Page Count Register */ #define NDBDR0 (0x1C) /* Bad Block Register 0 */ #define NDBDR1 (0x20) /* Bad Block Register 1 */ +#define NDECCCTRL (0x28) /* ECC control */ #define NDDB (0x40) /* Data Buffer */ #define NDCB0 (0x48) /* Command Buffer0 */ #define NDCB1 (0x4C) /* Command Buffer1 */ @@ -80,6 +85,9 @@ #define NDCR_INT_MASK (0xFFF) #define NDSR_MASK (0xfff) +#define NDSR_ERR_CNT_OFF (16) +#define NDSR_ERR_CNT_MASK (0x1f) +#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK) #define NDSR_RDY (0x1 << 12) #define NDSR_FLASH_RDY (0x1 << 11) #define NDSR_CS0_PAGED (0x1 << 10) @@ -88,8 +96,8 @@ #define NDSR_CS1_CMDD (0x1 << 7) #define NDSR_CS0_BBD (0x1 << 6) #define NDSR_CS1_BBD (0x1 << 5) -#define NDSR_DBERR (0x1 << 4) -#define NDSR_SBERR (0x1 << 3) +#define NDSR_UNCORERR (0x1 << 4) +#define NDSR_CORERR (0x1 << 3) #define NDSR_WRDREQ (0x1 << 2) #define NDSR_RDDREQ (0x1 << 1) #define NDSR_WRCMDREQ (0x1) @@ -98,6 +106,8 @@ #define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) +#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29) +#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK) #define NDCB0_CMD_TYPE_MASK (0x7 << 21) #define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) #define NDCB0_NC (0x1 << 20) @@ -108,6 +118,14 @@ #define NDCB0_CMD1_MASK (0xff) #define NDCB0_ADDR_CYC_SHIFT (16) +#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */ +#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */ +#define EXT_CMD_TYPE_READ 4 /* Read */ +#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */ +#define EXT_CMD_TYPE_FINAL 3 /* Final command */ +#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ +#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ + /* macros for registers read/write */ #define nand_writel(info, off, val) \ __raw_writel((val), (info)->mmio_base + (off)) @@ -120,9 +138,9 @@ enum { ERR_NONE = 0, ERR_DMABUSERR = -1, ERR_SENDCMD = -2, - ERR_DBERR = -3, + ERR_UNCORERR = -3, ERR_BBERR = -4, - ERR_SBERR = -5, + ERR_CORERR = -5, }; enum { @@ -149,7 +167,6 @@ struct pxa3xx_nand_host { void *info_data; /* page size of attached chip */ - unsigned int page_size; int use_ecc; int cs; @@ -167,11 +184,13 @@ struct pxa3xx_nand_info { struct clk *clk; void __iomem *mmio_base; unsigned long mmio_phys; - struct completion cmd_complete; + struct completion cmd_complete, dev_ready; unsigned int buf_start; unsigned int buf_count; unsigned int buf_size; + unsigned int data_buff_pos; + unsigned int oob_buff_pos; /* DMA information */ int drcmr_dat; @@ -195,13 +214,18 @@ struct pxa3xx_nand_info { int cs; int use_ecc; /* use HW ECC ? */ + int ecc_bch; /* using BCH ECC? */ int use_dma; /* use DMA ? */ int use_spare; /* use spare ? */ - int is_ready; + int need_wait; - unsigned int page_size; /* page size of attached chip */ - unsigned int data_size; /* data size in FIFO */ + unsigned int data_size; /* data to be read from FIFO */ + unsigned int chunk_size; /* split commands chunk size */ unsigned int oob_size; + unsigned int spare_size; + unsigned int ecc_size; + unsigned int ecc_err_cnt; + unsigned int max_bitflips; int retcode; /* cached register value */ @@ -239,6 +263,64 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, }; +static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; +static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_mirror_pattern +}; + +static struct nand_ecclayout ecc_layout_2KB_bch4bit = { + .eccbytes = 32, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { {2, 30} } +}; + +static struct nand_ecclayout ecc_layout_4KB_bch4bit = { + .eccbytes = 64, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + /* Bootrom looks in bytes 0 & 5 for bad blocks */ + .oobfree = { {6, 26}, { 64, 32} } +}; + +static struct nand_ecclayout ecc_layout_4KB_bch8bit = { + .eccbytes = 128, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { } +}; + /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) @@ -256,6 +338,29 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) +static struct of_device_id pxa3xx_nand_dt_ids[] = { + { + .compatible = "marvell,pxa3xx-nand", + .data = (void *)PXA3XX_NAND_VARIANT_PXA, + }, + { + .compatible = "marvell,armada370-nand", + .data = (void *)PXA3XX_NAND_VARIANT_ARMADA370, + }, + {} +}; +MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); + +static enum pxa3xx_nand_variant +pxa3xx_nand_get_variant(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); + if (!of_id) + return PXA3XX_NAND_VARIANT_PXA; + return (enum pxa3xx_nand_variant)of_id->data; +} + static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, const struct pxa3xx_nand_timing *t) { @@ -280,25 +385,23 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, nand_writel(info, NDTR1CS0, ndtr1); } -static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) +/* + * Set the data and OOB size, depending on the selected + * spare and ECC configuration. + * Only applicable to READ0, READOOB and PAGEPROG commands. + */ +static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info, + struct mtd_info *mtd) { - struct pxa3xx_nand_host *host = info->host[info->cs]; int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - info->data_size = host->page_size; - if (!oob_enable) { - info->oob_size = 0; + info->data_size = mtd->writesize; + if (!oob_enable) return; - } - switch (host->page_size) { - case 2048: - info->oob_size = (info->use_ecc) ? 40 : 64; - break; - case 512: - info->oob_size = (info->use_ecc) ? 8 : 16; - break; - } + info->oob_size = info->spare_size; + if (!info->use_ecc) + info->oob_size += info->ecc_size; } /** @@ -313,10 +416,15 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) ndcr = info->reg_ndcr; - if (info->use_ecc) + if (info->use_ecc) { ndcr |= NDCR_ECC_EN; - else + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x1); + } else { ndcr &= ~NDCR_ECC_EN; + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x0); + } if (info->use_dma) ndcr |= NDCR_DMA_EN; @@ -375,26 +483,39 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) static void handle_data_pio(struct pxa3xx_nand_info *info) { + unsigned int do_bytes = min(info->data_size, info->chunk_size); + switch (info->state) { case STATE_PIO_WRITING: - __raw_writesl(info->mmio_base + NDDB, info->data_buff, - DIV_ROUND_UP(info->data_size, 4)); + __raw_writesl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(do_bytes, 4)); + if (info->oob_size > 0) - __raw_writesl(info->mmio_base + NDDB, info->oob_buff, - DIV_ROUND_UP(info->oob_size, 4)); + __raw_writesl(info->mmio_base + NDDB, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->oob_size, 4)); break; case STATE_PIO_READING: - __raw_readsl(info->mmio_base + NDDB, info->data_buff, - DIV_ROUND_UP(info->data_size, 4)); + __raw_readsl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(do_bytes, 4)); + if (info->oob_size > 0) - __raw_readsl(info->mmio_base + NDDB, info->oob_buff, - DIV_ROUND_UP(info->oob_size, 4)); + __raw_readsl(info->mmio_base + NDDB, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->oob_size, 4)); break; default: dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } + + /* Update buffer pointers for multi-page read/write */ + info->data_buff_pos += do_bytes; + info->oob_buff_pos += info->oob_size; + info->data_size -= do_bytes; } #ifdef ARCH_HAS_DMA @@ -452,7 +573,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; - unsigned int status, is_completed = 0; + unsigned int status, is_completed = 0, is_ready = 0; unsigned int ready, cmd_done; if (info->cs == 0) { @@ -465,10 +586,25 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) status = nand_readl(info, NDSR); - if (status & NDSR_DBERR) - info->retcode = ERR_DBERR; - if (status & NDSR_SBERR) - info->retcode = ERR_SBERR; + if (status & NDSR_UNCORERR) + info->retcode = ERR_UNCORERR; + if (status & NDSR_CORERR) { + info->retcode = ERR_CORERR; + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && + info->ecc_bch) + info->ecc_err_cnt = NDSR_ERR_CNT(status); + else + info->ecc_err_cnt = 1; + + /* + * Each chunk composing a page is corrected independently, + * and we need to store maximum number of corrected bitflips + * to return it to the MTD layer in ecc.read_page(). + */ + info->max_bitflips = max_t(unsigned int, + info->max_bitflips, + info->ecc_err_cnt); + } if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { /* whether use dma to transfer data */ if (info->use_dma) { @@ -488,8 +624,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) is_completed = 1; } if (status & ready) { - info->is_ready = 1; info->state = STATE_READY; + is_ready = 1; } if (status & NDSR_WRCMDREQ) { @@ -518,6 +654,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) nand_writel(info, NDSR, status); if (is_completed) complete(&info->cmd_complete); + if (is_ready) + complete(&info->dev_ready); NORMAL_IRQ_EXIT: return IRQ_HANDLED; } @@ -530,51 +668,94 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) return 1; } -static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, - uint16_t column, int page_addr) +static void set_command_address(struct pxa3xx_nand_info *info, + unsigned int page_size, uint16_t column, int page_addr) { - int addr_cycle, exec_cmd; - struct pxa3xx_nand_host *host; - struct mtd_info *mtd; + /* small page addr setting */ + if (page_size < PAGE_CHUNK_SIZE) { + info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + | (column & 0xFF); - host = info->host[info->cs]; - mtd = host->mtd; - addr_cycle = 0; - exec_cmd = 1; + info->ndcb2 = 0; + } else { + info->ndcb1 = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + + if (page_addr & 0xFF0000) + info->ndcb2 = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2 = 0; + } +} + +static void prepare_start_command(struct pxa3xx_nand_info *info, int command) +{ + struct pxa3xx_nand_host *host = info->host[info->cs]; + struct mtd_info *mtd = host->mtd; /* reset data and oob column point to handle data */ info->buf_start = 0; info->buf_count = 0; info->oob_size = 0; + info->data_buff_pos = 0; + info->oob_buff_pos = 0; info->use_ecc = 0; info->use_spare = 1; - info->is_ready = 0; info->retcode = ERR_NONE; - if (info->cs != 0) - info->ndcb0 = NDCB0_CSEL; - else - info->ndcb0 = 0; + info->ecc_err_cnt = 0; + info->ndcb3 = 0; + info->need_wait = 0; switch (command) { case NAND_CMD_READ0: case NAND_CMD_PAGEPROG: info->use_ecc = 1; case NAND_CMD_READOOB: - pxa3xx_set_datasize(info); + pxa3xx_set_datasize(info, mtd); break; case NAND_CMD_PARAM: info->use_spare = 0; break; - case NAND_CMD_SEQIN: - exec_cmd = 0; - break; default: info->ndcb1 = 0; info->ndcb2 = 0; - info->ndcb3 = 0; break; } + /* + * If we are about to issue a read command, or about to set + * the write address, then clean the data buffer. + */ + if (command == NAND_CMD_READ0 || + command == NAND_CMD_READOOB || + command == NAND_CMD_SEQIN) { + + info->buf_count = mtd->writesize + mtd->oobsize; + memset(info->data_buff, 0xFF, info->buf_count); + } + +} + +static int prepare_set_command(struct pxa3xx_nand_info *info, int command, + int ext_cmd_type, uint16_t column, int page_addr) +{ + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; + + host = info->host[info->cs]; + mtd = host->mtd; + addr_cycle = 0; + exec_cmd = 1; + + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; + + if (command == NAND_CMD_SEQIN) + exec_cmd = 0; + addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + host->col_addr_cycles); @@ -589,30 +770,42 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, if (command == NAND_CMD_READOOB) info->buf_start += mtd->writesize; - /* Second command setting for large pages */ - if (host->page_size >= PAGE_CHUNK_SIZE) + /* + * Multiple page read needs an 'extended command type' field, + * which is either naked-read or last-read according to the + * state. + */ + if (mtd->writesize == PAGE_CHUNK_SIZE) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); + } else if (mtd->writesize > PAGE_CHUNK_SIZE) { + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->chunk_size + + info->oob_size; + } + + set_command_address(info, mtd->writesize, column, page_addr); + break; case NAND_CMD_SEQIN: - /* small page addr setting */ - if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { - info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) - | (column & 0xFF); - info->ndcb2 = 0; - } else { - info->ndcb1 = ((page_addr & 0xFFFF) << 16) - | (column & 0xFFFF); + info->buf_start = column; + set_command_address(info, mtd->writesize, 0, page_addr); - if (page_addr & 0xFF0000) - info->ndcb2 = (page_addr & 0xFF0000) >> 16; - else - info->ndcb2 = 0; + /* + * Multiple page programming needs to execute the initial + * SEQIN command that sets the page address. + */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | addr_cycle + | command; + /* No data transfer in this case */ + info->data_size = 0; + exec_cmd = 1; } - - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); - break; case NAND_CMD_PAGEPROG: @@ -622,13 +815,40 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_AUTO_RS - | NDCB0_ST_ROW_EN - | NDCB0_DBC - | (NAND_CMD_PAGEPROG << 8) - | NAND_CMD_SEQIN - | addr_cycle; + /* Second command setting for large pages */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + /* + * Multiple page write uses the 'extended command' + * field. This can be used to issue a command dispatch + * or a naked-write depending on the current stage. + */ + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->chunk_size + + info->oob_size; + + /* + * This is the command dispatch that completes a chunked + * page program operation. + */ + if (info->data_size == 0) { + info->ndcb0 = NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | command; + info->ndcb1 = 0; + info->ndcb2 = 0; + info->ndcb3 = 0; + } + } else { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | (NAND_CMD_PAGEPROG << 8) + | NAND_CMD_SEQIN + | addr_cycle; + } break; case NAND_CMD_PARAM: @@ -691,8 +911,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, return exec_cmd; } -static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; @@ -717,10 +937,15 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, nand_writel(info, NDTR1CS0, info->ndtr1cs0); } + prepare_start_command(info, command); + info->state = STATE_PREPARED; - exec_cmd = prepare_command_pool(info, command, column, page_addr); + exec_cmd = prepare_set_command(info, command, 0, column, page_addr); + if (exec_cmd) { init_completion(&info->cmd_complete); + init_completion(&info->dev_ready); + info->need_wait = 1; pxa3xx_nand_start(info); ret = wait_for_completion_timeout(&info->cmd_complete, @@ -734,6 +959,117 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->state = STATE_IDLE; } +static void nand_cmdfunc_extended(struct mtd_info *mtd, + const unsigned command, + int column, int page_addr) +{ + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; + int ret, exec_cmd, ext_cmd_type; + + /* + * if this is a x16 device then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); + } + + /* Select the extended command for the first command */ + switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + ext_cmd_type = EXT_CMD_TYPE_MONO; + break; + case NAND_CMD_SEQIN: + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + break; + case NAND_CMD_PAGEPROG: + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + break; + default: + ext_cmd_type = 0; + break; + } + + prepare_start_command(info, command); + + /* + * Prepare the "is ready" completion before starting a command + * transaction sequence. If the command is not executed the + * completion will be completed, see below. + * + * We can do that inside the loop because the command variable + * is invariant and thus so is the exec_cmd. + */ + info->need_wait = 1; + init_completion(&info->dev_ready); + do { + info->state = STATE_PREPARED; + exec_cmd = prepare_set_command(info, command, ext_cmd_type, + column, page_addr); + if (!exec_cmd) { + info->need_wait = 0; + complete(&info->dev_ready); + break; + } + + init_completion(&info->cmd_complete); + pxa3xx_nand_start(info); + + ret = wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT); + if (!ret) { + dev_err(&info->pdev->dev, "Wait time out!!!\n"); + /* Stop State Machine for next command cycle */ + pxa3xx_nand_stop(info); + break; + } + + /* Check if the sequence is complete */ + if (info->data_size == 0 && command != NAND_CMD_PAGEPROG) + break; + + /* + * After a splitted program command sequence has issued + * the command dispatch, the command sequence is complete. + */ + if (info->data_size == 0 && + command == NAND_CMD_PAGEPROG && + ext_cmd_type == EXT_CMD_TYPE_DISPATCH) + break; + + if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { + /* Last read: issue a 'last naked read' */ + if (info->data_size == info->chunk_size) + ext_cmd_type = EXT_CMD_TYPE_LAST_RW; + else + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + + /* + * If a splitted program command has no more data to transfer, + * the command dispatch must be issued to complete. + */ + } else if (command == NAND_CMD_PAGEPROG && + info->data_size == 0) { + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + } + } while (1); + + info->state = STATE_IDLE; +} + static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -753,20 +1089,14 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - if (info->retcode == ERR_SBERR) { - switch (info->use_ecc) { - case 1: - mtd->ecc_stats.corrected++; - break; - case 0: - default: - break; - } - } else if (info->retcode == ERR_DBERR) { + if (info->retcode == ERR_CORERR && info->use_ecc) { + mtd->ecc_stats.corrected += info->ecc_err_cnt; + + } else if (info->retcode == ERR_UNCORERR) { /* * for blank page (all 0xff), HW will calculate its ECC as * 0, which is different from the ECC information within - * OOB, ignore such double bit errors + * OOB, ignore such uncorrectable errors */ if (is_buf_blank(buf, mtd->writesize)) info->retcode = ERR_NONE; @@ -774,7 +1104,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, mtd->ecc_stats.failed++; } - return 0; + return info->max_bitflips; } static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) @@ -833,21 +1163,27 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; + int ret; + + if (info->need_wait) { + ret = wait_for_completion_timeout(&info->dev_ready, + CHIP_DELAY_TIMEOUT); + info->need_wait = 0; + if (!ret) { + dev_err(&info->pdev->dev, "Ready time out!!!\n"); + return NAND_STATUS_FAIL; + } + } /* pxa3xx_nand_send_command has waited for command complete */ if (this->state == FL_WRITING || this->state == FL_ERASING) { if (info->retcode == ERR_NONE) return 0; - else { - /* - * any error make it return 0x01 which will tell - * the caller the erase and write fail - */ - return 0x01; - } + else + return NAND_STATUS_FAIL; } - return 0; + return NAND_STATUS_READY; } static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, @@ -869,7 +1205,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, } /* calculate flash information */ - host->page_size = f->page_size; host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ @@ -906,13 +1241,15 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) uint32_t ndcr = nand_readl(info, NDCR); if (ndcr & NDCR_PAGE_SZ) { - host->page_size = 2048; + /* Controller's FIFO size */ + info->chunk_size = 2048; host->read_id_bytes = 4; } else { - host->page_size = 512; + info->chunk_size = 512; host->read_id_bytes = 2; } + /* Set an initial chunk size */ info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); @@ -988,18 +1325,89 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { struct mtd_info *mtd; + struct nand_chip *chip; int ret; + mtd = info->host[info->cs]->mtd; + chip = mtd->priv; + /* use the common timing to make a try */ ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); if (ret) return ret; - pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); - if (info->is_ready) - return 0; + chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + ret = chip->waitfunc(mtd, chip); + if (ret & NAND_STATUS_FAIL) + return -ENODEV; + + return 0; +} - return -ENODEV; +static int pxa_ecc_init(struct pxa3xx_nand_info *info, + struct nand_ecc_ctrl *ecc, + int strength, int ecc_stepsize, int page_size) +{ + if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) { + info->chunk_size = 2048; + info->spare_size = 40; + info->ecc_size = 24; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + return 1; + + } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) { + info->chunk_size = 512; + info->spare_size = 8; + info->ecc_size = 8; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + return 1; + + /* + * Required ECC: 4-bit correction per 512 bytes + * Select: 16-bit correction per 2048 bytes + */ + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch4bit; + ecc->strength = 16; + return 1; + + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { + info->ecc_bch = 1; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch4bit; + ecc->strength = 16; + return 1; + + /* + * Required ECC: 8-bit correction per 512 bytes + * Select: 16-bit correction per 1024 bytes + */ + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { + info->ecc_bch = 1; + info->chunk_size = 1024; + info->spare_size = 0; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch8bit; + ecc->strength = 16; + return 1; + } + return 0; } static int pxa3xx_nand_scan(struct mtd_info *mtd) @@ -1014,6 +1422,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) uint32_t id = -1; uint64_t chipsize; int i, ret, num; + uint16_t ecc_strength, ecc_step; if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) goto KEEP_CONFIG; @@ -1072,15 +1481,60 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1].name = NULL; def = pxa3xx_flash_ids; KEEP_CONFIG: - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = host->page_size; - chip->ecc.strength = 1; - if (info->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; + /* Device detection must be done with ECC disabled */ + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + nand_writel(info, NDECCCTRL, 0x0); + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; + + if (pdata->flash_bbt) { + /* + * We'll use a bad block table stored in-flash and don't + * allow writing the bad block marker to the flash. + */ + chip->bbt_options |= NAND_BBT_USE_FLASH | + NAND_BBT_NO_OOB_BBM; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + } + + /* + * If the page size is bigger than the FIFO size, let's check + * we are given the right variant and then switch to the extended + * (aka splitted) command handling, + */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { + chip->cmdfunc = nand_cmdfunc_extended; + } else { + dev_err(&info->pdev->dev, + "unsupported page size on this variant\n"); + return -ENODEV; + } + } + + ecc_strength = chip->ecc_strength_ds; + ecc_step = chip->ecc_step_ds; + + /* Set default ECC strength requirements on non-ONFI devices */ + if (ecc_strength < 1 && ecc_step < 1) { + ecc_strength = 1; + ecc_step = 512; + } + + ret = pxa_ecc_init(info, &chip->ecc, ecc_strength, + ecc_step, mtd->writesize); + if (!ret) { + dev_err(&info->pdev->dev, + "ECC strength %d at page size %d is not supported\n", + chip->ecc_strength_ds, mtd->writesize); + return -ENODEV; + } + /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2; @@ -1121,6 +1575,7 @@ static int alloc_nand_resource(struct platform_device *pdev) return -ENOMEM; info->pdev = pdev; + info->variant = pxa3xx_nand_get_variant(pdev); for (cs = 0; cs < pdata->num_cs; cs++) { mtd = (struct mtd_info *)((unsigned int)&info[1] + (sizeof(*mtd) + sizeof(*host)) * cs); @@ -1138,11 +1593,12 @@ static int alloc_nand_resource(struct platform_device *pdev) chip->controller = &info->controller; chip->waitfunc = pxa3xx_nand_waitfunc; chip->select_chip = pxa3xx_nand_select_chip; - chip->cmdfunc = pxa3xx_nand_cmdfunc; chip->read_word = pxa3xx_nand_read_word; chip->read_byte = pxa3xx_nand_read_byte; chip->read_buf = pxa3xx_nand_read_buf; chip->write_buf = pxa3xx_nand_write_buf; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->cmdfunc = nand_cmdfunc; } spin_lock_init(&chip->controller->lock); @@ -1254,25 +1710,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) return 0; } -static struct of_device_id pxa3xx_nand_dt_ids[] = { - { - .compatible = "marvell,pxa3xx-nand", - .data = (void *)PXA3XX_NAND_VARIANT_PXA, - }, - {} -}; -MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); - -static enum pxa3xx_nand_variant -pxa3xx_nand_get_variant(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); - if (!of_id) - return PXA3XX_NAND_VARIANT_PXA; - return (enum pxa3xx_nand_variant)of_id->data; -} - static int pxa3xx_nand_probe_dt(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; @@ -1292,6 +1729,7 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev) if (of_get_property(np, "marvell,nand-keep-config", NULL)) pdata->keep_config = 1; of_property_read_u32(np, "num-cs", &pdata->num_cs); + pdata->flash_bbt = of_get_nand_on_flash_bbt(np); pdev->dev.platform_data = pdata; @@ -1329,7 +1767,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } info = platform_get_drvdata(pdev); - info->variant = pxa3xx_nand_get_variant(pdev); probe_success = 0; for (cs = 0; cs < pdata->num_cs; cs++) { struct mtd_info *mtd = info->host[cs]->mtd; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d65cbe903d40..f0918e7411d9 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -46,9 +46,43 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> -#include <plat/regs-nand.h> #include <linux/platform_data/mtd-nand-s3c2410.h> +#define S3C2410_NFREG(x) (x) + +#define S3C2410_NFCONF S3C2410_NFREG(0x00) +#define S3C2410_NFCMD S3C2410_NFREG(0x04) +#define S3C2410_NFADDR S3C2410_NFREG(0x08) +#define S3C2410_NFDATA S3C2410_NFREG(0x0C) +#define S3C2410_NFSTAT S3C2410_NFREG(0x10) +#define S3C2410_NFECC S3C2410_NFREG(0x14) +#define S3C2440_NFCONT S3C2410_NFREG(0x04) +#define S3C2440_NFCMD S3C2410_NFREG(0x08) +#define S3C2440_NFADDR S3C2410_NFREG(0x0C) +#define S3C2440_NFDATA S3C2410_NFREG(0x10) +#define S3C2440_NFSTAT S3C2410_NFREG(0x20) +#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) +#define S3C2412_NFSTAT S3C2410_NFREG(0x28) +#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) +#define S3C2410_NFCONF_EN (1<<15) +#define S3C2410_NFCONF_INITECC (1<<12) +#define S3C2410_NFCONF_nFCE (1<<11) +#define S3C2410_NFCONF_TACLS(x) ((x)<<8) +#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) +#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) +#define S3C2410_NFSTAT_BUSY (1<<0) +#define S3C2440_NFCONF_TACLS(x) ((x)<<12) +#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) +#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) +#define S3C2440_NFCONT_INITECC (1<<4) +#define S3C2440_NFCONT_nFCE (1<<1) +#define S3C2440_NFCONT_ENABLE (1<<0) +#define S3C2440_NFSTAT_READY (1<<0) +#define S3C2412_NFCONF_NANDBOOT (1<<31) +#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) +#define S3C2412_NFCONT_nFCE0 (1<<1) +#define S3C2412_NFSTAT_READY (1<<0) + /* new oob placement block for use with hardware ecc generation */ @@ -919,7 +953,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { - dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } @@ -974,7 +1007,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) size = nr_sets * sizeof(*info->mtds); info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (info->mtds == NULL) { - dev_err(&pdev->dev, "failed to allocate mtd storage\n"); err = -ENOMEM; goto exit_error; } diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index a3c84ebbe392..d72783dd7b96 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -151,7 +151,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) dma_cap_set(DMA_SLAVE, mask); flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_fifo0_tx); + (void *)(uintptr_t)pdata->slave_id_fifo0_tx); dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__, flctl->chan_fifo0_tx); @@ -168,7 +168,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) goto err; flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_fifo0_rx); + (void *)(uintptr_t)pdata->slave_id_fifo0_rx); dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__, flctl->chan_fifo0_rx); @@ -1021,7 +1021,6 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_OF struct flctl_soc_config { unsigned long flcmncr_val; unsigned has_hwecc:1; @@ -1059,10 +1058,8 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "%s: failed to allocate config data\n", __func__); + if (!pdata) return NULL; - } /* set SoC specific options */ pdata->flcmncr_val = config->flcmncr_val; @@ -1080,12 +1077,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) return pdata; } -#else /* CONFIG_OF */ -static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) -{ - return NULL; -} -#endif /* CONFIG_OF */ static int flctl_probe(struct platform_device *pdev) { @@ -1094,38 +1085,30 @@ static int flctl_probe(struct platform_device *pdev) struct mtd_info *flctl_mtd; struct nand_chip *nand; struct sh_flctl_platform_data *pdata; - int ret = -ENXIO; + int ret; int irq; struct mtd_part_parser_data ppdata = {}; - flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); - if (!flctl) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL); + if (!flctl) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - goto err_iomap; - } - - flctl->reg = ioremap(res->start, resource_size(res)); - if (flctl->reg == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - goto err_iomap; - } + flctl->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(flctl->reg)) + return PTR_ERR(flctl->reg); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get flste irq data\n"); - goto err_flste; + return -ENXIO; } - ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl); + ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED, + "flste", flctl); if (ret) { dev_err(&pdev->dev, "request interrupt failed.\n"); - goto err_flste; + return ret; } if (pdev->dev.of_node) @@ -1135,8 +1118,7 @@ static int flctl_probe(struct platform_device *pdev) if (!pdata) { dev_err(&pdev->dev, "no setup data defined\n"); - ret = -EINVAL; - goto err_pdata; + return -EINVAL; } platform_set_drvdata(pdev, flctl); @@ -1190,12 +1172,6 @@ static int flctl_probe(struct platform_device *pdev) err_chip: flctl_release_dma(flctl); pm_runtime_disable(&pdev->dev); -err_pdata: - free_irq(irq, flctl); -err_flste: - iounmap(flctl->reg); -err_iomap: - kfree(flctl); return ret; } @@ -1206,9 +1182,6 @@ static int flctl_remove(struct platform_device *pdev) flctl_release_dma(flctl); nand_release(&flctl->mtd); pm_runtime_disable(&pdev->dev); - free_irq(platform_get_irq(pdev, 0), flctl); - iounmap(flctl->reg); - kfree(flctl); return 0; } diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 87908d760feb..e81059b58382 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -121,10 +121,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Allocate memory for MTD device structure and private data */ sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); - if (!sharpsl) { - printk("Unable to allocate SharpSL NAND MTD device structure.\n"); + if (!sharpsl) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { @@ -136,7 +134,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* map physical address */ sharpsl->io = ioremap(r->start, resource_size(r)); if (!sharpsl->io) { - printk("ioremap to access Sharp SL NAND chip failed\n"); + dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n"); err = -EIO; goto err_ioremap; } diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index a3747c914d57..fb8fd35fa668 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -371,11 +371,9 @@ static int tmio_probe(struct platform_device *dev) if (data == NULL) dev_warn(&dev->dev, "NULL platform data!\n"); - tmio = kzalloc(sizeof *tmio, GFP_KERNEL); - if (!tmio) { - retval = -ENOMEM; - goto err_kzalloc; - } + tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL); + if (!tmio) + return -ENOMEM; tmio->dev = dev; @@ -385,22 +383,18 @@ static int tmio_probe(struct platform_device *dev) mtd->priv = nand_chip; mtd->name = "tmio-nand"; - tmio->ccr = ioremap(ccr->start, resource_size(ccr)); - if (!tmio->ccr) { - retval = -EIO; - goto err_iomap_ccr; - } + tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr)); + if (!tmio->ccr) + return -EIO; tmio->fcr_base = fcr->start & 0xfffff; - tmio->fcr = ioremap(fcr->start, resource_size(fcr)); - if (!tmio->fcr) { - retval = -EIO; - goto err_iomap_fcr; - } + tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr)); + if (!tmio->fcr) + return -EIO; retval = tmio_hw_init(dev, tmio); if (retval) - goto err_hwinit; + return retval; /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = tmio->fcr; @@ -428,7 +422,8 @@ static int tmio_probe(struct platform_device *dev) /* 15 us command delay time */ nand_chip->chip_delay = 15; - retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio); + retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0, + dev_name(&dev->dev), tmio); if (retval) { dev_err(&dev->dev, "request_irq error %d\n", retval); goto err_irq; @@ -440,7 +435,7 @@ static int tmio_probe(struct platform_device *dev) /* Scan to find existence of the device */ if (nand_scan(mtd, 1)) { retval = -ENODEV; - goto err_scan; + goto err_irq; } /* Register the partitions */ retval = mtd_device_parse_register(mtd, NULL, NULL, @@ -451,18 +446,8 @@ static int tmio_probe(struct platform_device *dev) nand_release(mtd); -err_scan: - if (tmio->irq) - free_irq(tmio->irq, tmio); err_irq: tmio_hw_stop(dev, tmio); -err_hwinit: - iounmap(tmio->fcr); -err_iomap_fcr: - iounmap(tmio->ccr); -err_iomap_ccr: - kfree(tmio); -err_kzalloc: return retval; } @@ -471,12 +456,7 @@ static int tmio_remove(struct platform_device *dev) struct tmio_nand *tmio = platform_get_drvdata(dev); nand_release(&tmio->mtd); - if (tmio->irq) - free_irq(tmio->irq, tmio); tmio_hw_stop(dev, tmio); - iounmap(tmio->fcr); - iounmap(tmio->ccr); - kfree(tmio); return 0; } diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 235714a421dd..c1622a5ba814 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -319,11 +319,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) continue; txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv), GFP_KERNEL); - if (!txx9_priv) { - dev_err(&dev->dev, "Unable to allocate " - "TXx9 NDFMC MTD device structure.\n"); + if (!txx9_priv) continue; - } chip = &txx9_priv->chip; mtd = &txx9_priv->mtd; mtd->owner = THIS_MODULE; diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index d64f8c30945f..aa26c32e1bc2 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -81,7 +81,7 @@ static int parse_ofpart_partitions(struct mtd_info *master, partname = of_get_property(pp, "label", &len); if (!partname) partname = of_get_property(pp, "name", &len); - (*pparts)[i].name = (char *)partname; + (*pparts)[i].name = partname; if (of_get_property(pp, "read-only", &len)) (*pparts)[i].mask_flags |= MTD_WRITEABLE; @@ -152,7 +152,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, if (names && (plen > 0)) { int len = strlen(names) + 1; - (*pparts)[i].name = (char *)names; + (*pparts)[i].name = names; plen -= len; names += len; } else { @@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = { static int __init ofpart_parser_init(void) { - int rc; - rc = register_mtd_parser(&ofpart_parser); - if (rc) - goto out; - - rc = register_mtd_parser(&ofoldpart_parser); - if (!rc) - return 0; - - deregister_mtd_parser(&ofoldpart_parser); -out: - return rc; + register_mtd_parser(&ofpart_parser); + register_mtd_parser(&ofoldpart_parser); + return 0; } static void __exit ofpart_parser_exit(void) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 63699fffc96d..8e1919b6f074 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -58,7 +58,7 @@ static int generic_onenand_probe(struct platform_device *pdev) goto out_release_mem_region; } - info->onenand.mmcontrol = pdata ? pdata->mmcontrol : 0; + info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL; info->onenand.irq = platform_get_irq(pdev, 0); info->mtd.name = dev_name(&pdev->dev); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 580035c803d6..5da911ebdf49 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot"); static int __init redboot_parser_init(void) { - return register_mtd_parser(&redboot_parser); + register_mtd_parser(&redboot_parser); + return 0; } static void __exit redboot_parser_exit(void) diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index 70106607c247..e579f9027c47 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -19,7 +19,7 @@ * or detected. */ -#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE) +#if IS_ENABLED(CONFIG_MTD_NAND) struct nand_ecc_test { const char *name; diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index cde0fd941f0c..4be971590461 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1275,18 +1275,21 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev) { struct net_device *netdev = dev_get_drvdata(&vdev->dev); struct ibmveth_adapter *adapter; + struct iommu_table *tbl; unsigned long ret; int i; int rxqentries = 1; + tbl = get_iommu_table_base(&vdev->dev); + /* netdev inits at probe time along with the structures we need below*/ if (netdev == NULL) - return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT); + return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT, tbl); adapter = netdev_priv(netdev); ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE; - ret += IOMMU_PAGE_ALIGN(netdev->mtu); + ret += IOMMU_PAGE_ALIGN(netdev->mtu, tbl); for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) { /* add the size of the active receive buffers */ @@ -1294,11 +1297,12 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev) ret += adapter->rx_buff_pool[i].size * IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i]. - buff_size); + buff_size, tbl); rxqentries += adapter->rx_buff_pool[i].size; } /* add the size of the receive queue entries */ - ret += IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry)); + ret += IOMMU_PAGE_ALIGN( + rxqentries * sizeof(struct ibmveth_rx_q_entry), tbl); return ret; } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 7acab93d5a47..22f2f2857b82 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -41,6 +41,15 @@ config PWM_AB8500 To compile this driver as a module, choose M here: the module will be called pwm-ab8500. +config PWM_ATMEL + tristate "Atmel PWM support" + depends on ARCH_AT91 + help + Generic PWM framework driver for Atmel SoC. + + To compile this driver as a module, choose M here: the module + will be called pwm-atmel. + config PWM_ATMEL_TCB tristate "Atmel TC Block PWM support" depends on ATMEL_TCLIB && OF @@ -122,7 +131,8 @@ config PWM_MXS config PWM_PCA9685 tristate "NXP PCA9685 PWM driver" - depends on OF && REGMAP_I2C + depends on OF && I2C + select REGMAP_I2C help Generic PWM framework driver for NXP PCA9685 LED controller. @@ -149,7 +159,7 @@ config PWM_PXA config PWM_RENESAS_TPU tristate "Renesas TPU PWM support" - depends on ARCH_SHMOBILE + depends on ARCH_SHMOBILE || COMPILE_TEST help This driver exposes the Timer Pulse Unit (TPU) PWM controller found in Renesas chips through the PWM API. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 4abf337dcd02..d8906ec69976 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o +obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 2ca95042a0b9..a80471399c20 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -808,12 +808,12 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label); if (test_bit(PWMF_REQUESTED, &pwm->flags)) - seq_printf(s, " requested"); + seq_puts(s, " requested"); if (test_bit(PWMF_ENABLED, &pwm->flags)) - seq_printf(s, " enabled"); + seq_puts(s, " enabled"); - seq_printf(s, "\n"); + seq_puts(s, "\n"); } } diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c new file mode 100644 index 000000000000..bf4144a14661 --- /dev/null +++ b/drivers/pwm/pwm-atmel.c @@ -0,0 +1,395 @@ +/* + * Driver for Atmel Pulse Width Modulation Controller + * + * Copyright (C) 2013 Atmel Corporation + * Bo Shen <voice.shen@atmel.com> + * + * Licensed under GPLv2. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +/* The following is global registers for PWM controller */ +#define PWM_ENA 0x04 +#define PWM_DIS 0x08 +#define PWM_SR 0x0C +/* Bit field in SR */ +#define PWM_SR_ALL_CH_ON 0x0F + +/* The following register is PWM channel related registers */ +#define PWM_CH_REG_OFFSET 0x200 +#define PWM_CH_REG_SIZE 0x20 + +#define PWM_CMR 0x0 +/* Bit field in CMR */ +#define PWM_CMR_CPOL (1 << 9) +#define PWM_CMR_UPD_CDTY (1 << 10) + +/* The following registers for PWM v1 */ +#define PWMV1_CDTY 0x04 +#define PWMV1_CPRD 0x08 +#define PWMV1_CUPD 0x10 + +/* The following registers for PWM v2 */ +#define PWMV2_CDTY 0x04 +#define PWMV2_CDTYUPD 0x08 +#define PWMV2_CPRD 0x0C +#define PWMV2_CPRDUPD 0x10 + +/* + * Max value for duty and period + * + * Although the duty and period register is 32 bit, + * however only the LSB 16 bits are significant. + */ +#define PWM_MAX_DTY 0xFFFF +#define PWM_MAX_PRD 0xFFFF +#define PRD_MAX_PRES 10 + +struct atmel_pwm_chip { + struct pwm_chip chip; + struct clk *clk; + void __iomem *base; + + void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, + unsigned long dty, unsigned long prd); +}; + +static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct atmel_pwm_chip, chip); +} + +static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip, + unsigned long offset) +{ + return readl_relaxed(chip->base + offset); +} + +static inline void atmel_pwm_writel(struct atmel_pwm_chip *chip, + unsigned long offset, unsigned long val) +{ + writel_relaxed(val, chip->base + offset); +} + +static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, + unsigned int ch, unsigned long offset) +{ + unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; + + return readl_relaxed(chip->base + base + offset); +} + +static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, + unsigned int ch, unsigned long offset, + unsigned long val) +{ + unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; + + writel_relaxed(val, chip->base + base + offset); +} + +static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + unsigned long clk_rate, prd, dty; + unsigned long long div; + unsigned int pres = 0; + int ret; + + if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { + dev_err(chip->dev, "cannot change PWM period while enabled\n"); + return -EBUSY; + } + + clk_rate = clk_get_rate(atmel_pwm->clk); + div = clk_rate; + + /* Calculate the period cycles */ + while (div > PWM_MAX_PRD) { + div = clk_rate / (1 << pres); + div = div * period_ns; + /* 1/Hz = 100000000 ns */ + do_div(div, 1000000000); + + if (pres++ > PRD_MAX_PRES) { + dev_err(chip->dev, "pres exceeds the maximum value\n"); + return -EINVAL; + } + } + + /* Calculate the duty cycles */ + prd = div; + div *= duty_ns; + do_div(div, period_ns); + dty = div; + + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(chip->dev, "failed to enable PWM clock\n"); + return ret; + } + + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, pres); + atmel_pwm->config(chip, pwm, dty, prd); + + clk_disable(atmel_pwm->clk); + return ret; +} + +static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, + unsigned long dty, unsigned long prd) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + unsigned int val; + + if (test_bit(PWMF_ENABLED, &pwm->flags)) { + /* + * If the PWM channel is enabled, using the update register, + * it needs to set bit 10 of CMR to 0 + */ + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty); + + val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); + val &= ~PWM_CMR_UPD_CDTY; + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); + } else { + /* + * If the PWM channel is disabled, write value to duty and + * period registers directly. + */ + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty); + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd); + } +} + +static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, + unsigned long dty, unsigned long prd) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + + if (test_bit(PWMF_ENABLED, &pwm->flags)) { + /* + * If the PWM channel is enabled, using the duty update register + * to update the value. + */ + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTYUPD, dty); + } else { + /* + * If the PWM channel is disabled, write value to duty and + * period registers directly. + */ + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTY, dty); + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CPRD, prd); + } +} + +static int atmel_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + u32 val; + int ret; + + val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); + + if (polarity == PWM_POLARITY_NORMAL) + val &= ~PWM_CMR_CPOL; + else + val |= PWM_CMR_CPOL; + + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(chip->dev, "failed to enable PWM clock\n"); + return ret; + } + + atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); + + clk_disable(atmel_pwm->clk); + + return 0; +} + +static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + int ret; + + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(chip->dev, "failed to enable PWM clock\n"); + return ret; + } + + atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm); + + return 0; +} + +static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + + atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm); + + clk_disable(atmel_pwm->clk); +} + +static const struct pwm_ops atmel_pwm_ops = { + .config = atmel_pwm_config, + .set_polarity = atmel_pwm_set_polarity, + .enable = atmel_pwm_enable, + .disable = atmel_pwm_disable, + .owner = THIS_MODULE, +}; + +struct atmel_pwm_data { + void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, + unsigned long dty, unsigned long prd); +}; + +static const struct atmel_pwm_data atmel_pwm_data_v1 = { + .config = atmel_pwm_config_v1, +}; + +static const struct atmel_pwm_data atmel_pwm_data_v2 = { + .config = atmel_pwm_config_v2, +}; + +static const struct platform_device_id atmel_pwm_devtypes[] = { + { + .name = "at91sam9rl-pwm", + .driver_data = (kernel_ulong_t)&atmel_pwm_data_v1, + }, { + .name = "sama5d3-pwm", + .driver_data = (kernel_ulong_t)&atmel_pwm_data_v2, + }, { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes); + +static const struct of_device_id atmel_pwm_dt_ids[] = { + { + .compatible = "atmel,at91sam9rl-pwm", + .data = &atmel_pwm_data_v1, + }, { + .compatible = "atmel,sama5d3-pwm", + .data = &atmel_pwm_data_v2, + }, { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); + +static inline const struct atmel_pwm_data * +atmel_pwm_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + + match = of_match_device(atmel_pwm_dt_ids, &pdev->dev); + if (!match) + return NULL; + + return match->data; + } else { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + + return (struct atmel_pwm_data *)id->driver_data; + } +} + +static int atmel_pwm_probe(struct platform_device *pdev) +{ + const struct atmel_pwm_data *data; + struct atmel_pwm_chip *atmel_pwm; + struct resource *res; + int ret; + + data = atmel_pwm_get_driver_data(pdev); + if (!data) + return -ENODEV; + + atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); + if (!atmel_pwm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(atmel_pwm->base)) + return PTR_ERR(atmel_pwm->base); + + atmel_pwm->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(atmel_pwm->clk)) + return PTR_ERR(atmel_pwm->clk); + + ret = clk_prepare(atmel_pwm->clk); + if (ret) { + dev_err(&pdev->dev, "failed to prepare PWM clock\n"); + return ret; + } + + atmel_pwm->chip.dev = &pdev->dev; + atmel_pwm->chip.ops = &atmel_pwm_ops; + + if (pdev->dev.of_node) { + atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags; + atmel_pwm->chip.of_pwm_n_cells = 3; + } + + atmel_pwm->chip.base = -1; + atmel_pwm->chip.npwm = 4; + atmel_pwm->config = data->config; + + ret = pwmchip_add(&atmel_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret); + goto unprepare_clk; + } + + platform_set_drvdata(pdev, atmel_pwm); + + return ret; + +unprepare_clk: + clk_unprepare(atmel_pwm->clk); + return ret; +} + +static int atmel_pwm_remove(struct platform_device *pdev) +{ + struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev); + + clk_unprepare(atmel_pwm->clk); + + return pwmchip_remove(&atmel_pwm->chip); +} + +static struct platform_driver atmel_pwm_driver = { + .driver = { + .name = "atmel-pwm", + .of_match_table = of_match_ptr(atmel_pwm_dt_ids), + }, + .id_table = atmel_pwm_devtypes, + .probe = atmel_pwm_probe, + .remove = atmel_pwm_remove, +}; +module_platform_driver(atmel_pwm_driver); + +MODULE_ALIAS("platform:atmel-pwm"); +MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); +MODULE_DESCRIPTION("Atmel PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index 33aa4461e1ce..e593e9c45c51 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -224,7 +224,7 @@ static struct platform_driver ep93xx_pwm_driver = { module_platform_driver(ep93xx_pwm_driver); MODULE_DESCRIPTION("Cirrus Logic EP93xx PWM driver"); -MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, " - "H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); MODULE_ALIAS("platform:ep93xx-pwm"); MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 0a2ede3c3932..9c46209e1d02 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -165,13 +165,12 @@ static const struct pwm_ops jz4740_pwm_ops = { static int jz4740_pwm_probe(struct platform_device *pdev) { struct jz4740_pwm_chip *jz4740; - int ret; jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL); if (!jz4740) return -ENOMEM; - jz4740->clk = clk_get(NULL, "ext"); + jz4740->clk = devm_clk_get(&pdev->dev, "ext"); if (IS_ERR(jz4740->clk)) return PTR_ERR(jz4740->clk); @@ -180,29 +179,16 @@ static int jz4740_pwm_probe(struct platform_device *pdev) jz4740->chip.npwm = NUM_PWM; jz4740->chip.base = -1; - ret = pwmchip_add(&jz4740->chip); - if (ret < 0) { - clk_put(jz4740->clk); - return ret; - } - platform_set_drvdata(pdev, jz4740); - return 0; + return pwmchip_add(&jz4740->chip); } static int jz4740_pwm_remove(struct platform_device *pdev) { struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev); - int ret; - - ret = pwmchip_remove(&jz4740->chip); - if (ret < 0) - return ret; - clk_put(jz4740->clk); - - return 0; + return pwmchip_remove(&jz4740->chip); } static struct platform_driver jz4740_pwm_driver = { diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index a4d2164aaf55..8d995731cef8 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * 2008-02-13 initial version - * eric miao <eric.miao@marvell.com> + * eric miao <eric.miao@marvell.com> */ #include <linux/module.h> @@ -19,6 +19,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/pwm.h> +#include <linux/of_device.h> #include <asm/div64.h> @@ -124,6 +125,46 @@ static struct pwm_ops pxa_pwm_ops = { .owner = THIS_MODULE, }; +#ifdef CONFIG_OF +/* + * Device tree users must create one device instance for each pwm channel. + * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver + * code that this is a single channel pxa25x-pwm. Currently all devices are + * supported identically. + */ +static struct of_device_id pwm_of_match[] = { + { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]}, + { } +}; +MODULE_DEVICE_TABLE(of, pwm_of_match); +#else +#define pwm_of_match NULL +#endif + +static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) +{ + const struct of_device_id *id = of_match_device(pwm_of_match, dev); + + return id ? id->data : NULL; +} + +static struct pwm_device * +pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +{ + struct pwm_device *pwm; + + pwm = pwm_request_from_chip(pc, 0, NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, args->args[0]); + + return pwm; +} + static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -131,6 +172,12 @@ static int pwm_probe(struct platform_device *pdev) struct resource *r; int ret = 0; + if (IS_ENABLED(CONFIG_OF) && id == NULL) + id = pxa_pwm_get_id_dt(&pdev->dev); + + if (id == NULL) + return -EINVAL; + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); if (pwm == NULL) { dev_err(&pdev->dev, "failed to allocate memory\n"); @@ -146,6 +193,11 @@ static int pwm_probe(struct platform_device *pdev) pwm->chip.base = -1; pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; + if (IS_ENABLED(CONFIG_OF)) { + pwm->chip.of_xlate = pxa_pwm_of_xlate; + pwm->chip.of_pwm_n_cells = 1; + } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(pwm->mmio_base)) @@ -176,6 +228,7 @@ static struct platform_driver pwm_driver = { .driver = { .name = "pxa25x-pwm", .owner = THIS_MODULE, + .of_match_table = pwm_of_match, }, .probe = pwm_probe, .remove = pwm_remove, diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 4e5c3d13d4f8..032092c7a6ae 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -279,7 +279,6 @@ static int ecap_pwm_remove(struct platform_device *pdev) pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ); pm_runtime_put_sync(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return pwmchip_remove(&pc->chip); } diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index a4d8f519d965..aee4471424d1 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -360,8 +360,8 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) /* Enable TBCLK before enabling PWM device */ ret = clk_enable(pc->tbclk); if (ret) { - pr_err("Failed to enable TBCLK for %s\n", - dev_name(pc->chip.dev)); + dev_err(chip->dev, "Failed to enable TBCLK for %s\n", + dev_name(pc->chip.dev)); return ret; } diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 8c20332d4825..4bd0c639e16d 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -169,15 +169,7 @@ static struct attribute *pwm_attrs[] = { &dev_attr_polarity.attr, NULL }; - -static const struct attribute_group pwm_attr_group = { - .attrs = pwm_attrs, -}; - -static const struct attribute_group *pwm_attr_groups[] = { - &pwm_attr_group, - NULL, -}; +ATTRIBUTE_GROUPS(pwm); static void pwm_export_release(struct device *child) { @@ -205,7 +197,7 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) export->child.release = pwm_export_release; export->child.parent = parent; export->child.devt = MKDEV(0, 0); - export->child.groups = pwm_attr_groups; + export->child.groups = pwm_groups; dev_set_name(&export->child, "pwm%u", pwm->hwpwm); ret = device_register(&export->child); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 464dd29d06c0..58141f0651f2 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -257,6 +257,7 @@ static int __init xpram_setup_sizes(unsigned long pages) unsigned long mem_needed; unsigned long mem_auto; unsigned long long size; + char *sizes_end; int mem_auto_no; int i; @@ -275,8 +276,8 @@ static int __init xpram_setup_sizes(unsigned long pages) mem_auto_no = 0; for (i = 0; i < xpram_devs; i++) { if (sizes[i]) { - size = simple_strtoull(sizes[i], &sizes[i], 0); - switch (sizes[i][0]) { + size = simple_strtoull(sizes[i], &sizes_end, 0); + switch (*sizes_end) { case 'g': case 'G': size <<= 20; diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index cb3c4e05a385..49af8eeb90ea 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -700,3 +700,8 @@ out: free_page((unsigned long) sccb); return rc; } + +bool sclp_has_sprp(void) +{ + return !!(sclp_fac84 & 0x2); +} diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 64c467998a90..0efb27f6f199 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -922,8 +922,8 @@ static int ur_set_online(struct ccw_device *cdev) goto fail_free_cdev; } - urd->device = device_create(vmur_class, NULL, urd->char_device->dev, - NULL, "%s", node_id); + urd->device = device_create(vmur_class, &cdev->dev, + urd->char_device->dev, NULL, "%s", node_id); if (IS_ERR(urd->device)) { rc = PTR_ERR(urd->device); TRACE("ur_set_online: device_create rc=%d\n", rc); diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index c1441ed282eb..c7763e482eb2 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -11,7 +11,6 @@ #include <linux/sched.h> #include <linux/wait.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/of_device.h> diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index fc1339cf91ac..7c71e7b4febf 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -9,7 +9,6 @@ #include <linux/fs.h> #include <linux/errno.h> #include <linux/major.h> -#include <linux/init.h> #include <linux/miscdevice.h> #include <linux/ioport.h> /* request_region */ #include <linux/slab.h> diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index ddbe5a9e713d..af15a2fdab5e 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -19,7 +19,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/kthread.h> #include <linux/delay.h> #include <linux/ioport.h> diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index d9f268f23774..25c738e9ef19 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -9,7 +9,6 @@ #include <linux/miscdevice.h> #include <linux/fcntl.h> #include <linux/poll.h> -#include <linux/init.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/mm.h> diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index b0aae0536d58..b7acafc85099 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -11,7 +11,6 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/ioport.h> -#include <linux/init.h> #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/of.h> diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 978db344bda0..b24aa010f68c 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -366,7 +366,7 @@ config TRACE_SINK "Trace data router for MIPI P1149.7 cJTAG standard". config PPC_EPAPR_HV_BYTECHAN - tristate "ePAPR hypervisor byte channel driver" + bool "ePAPR hypervisor byte channel driver" depends on PPC select EPAPR_PARAVIRT help diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index db19a38c8c69..ea74460f3638 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -77,6 +77,7 @@ struct hvc_iucv_private { struct list_head tty_outqueue; /* outgoing IUCV messages */ struct list_head tty_inqueue; /* incoming IUCV messages */ struct device *dev; /* device structure */ + u8 info_path[16]; /* IUCV path info (dev attr) */ }; struct iucv_tty_buffer { @@ -126,7 +127,7 @@ static struct iucv_handler hvc_iucv_handler = { * This function returns the struct hvc_iucv_private instance that corresponds * to the HVC virtual terminal number specified as parameter @num. */ -struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) +static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) { if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) return NULL; @@ -772,18 +773,37 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8]) static int hvc_iucv_path_pending(struct iucv_path *path, u8 ipvmid[8], u8 ipuser[16]) { - struct hvc_iucv_private *priv; + struct hvc_iucv_private *priv, *tmp; + u8 wildcard[9] = "lnxhvc "; + int i, rc, find_unused; u8 nuser_data[16]; u8 vm_user_id[9]; - int i, rc; + ASCEBC(wildcard, sizeof(wildcard)); + find_unused = !memcmp(wildcard, ipuser, 8); + + /* First, check if the pending path request is managed by this + * IUCV handler: + * - find a disconnected device if ipuser contains the wildcard + * - find the device that matches the terminal ID in ipuser + */ priv = NULL; - for (i = 0; i < hvc_iucv_devices; i++) - if (hvc_iucv_table[i] && - (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { - priv = hvc_iucv_table[i]; + for (i = 0; i < hvc_iucv_devices; i++) { + tmp = hvc_iucv_table[i]; + if (!tmp) + continue; + + if (find_unused) { + spin_lock(&tmp->lock); + if (tmp->iucv_state == IUCV_DISCONN) + priv = tmp; + spin_unlock(&tmp->lock); + + } else if (!memcmp(tmp->srv_name, ipuser, 8)) + priv = tmp; + if (priv) break; - } + } if (!priv) return -ENODEV; @@ -826,6 +846,10 @@ static int hvc_iucv_path_pending(struct iucv_path *path, priv->path = path; priv->iucv_state = IUCV_CONNECTED; + /* store path information */ + memcpy(priv->info_path, ipvmid, 8); + memcpy(priv->info_path + 8, ipuser + 8, 8); + /* flush buffered output data... */ schedule_delayed_work(&priv->sndbuf_work, 5); @@ -960,6 +984,49 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev) return 0; } +static ssize_t hvc_iucv_dev_termid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + size_t len; + + len = sizeof(priv->srv_name); + memcpy(buf, priv->srv_name, len); + EBCASC(buf, len); + buf[len++] = '\n'; + return len; +} + +static ssize_t hvc_iucv_dev_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + return sprintf(buf, "%u:%u\n", priv->iucv_state, priv->tty_state); +} + +static ssize_t hvc_iucv_dev_peer_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + char vmid[9], ipuser[9]; + + memset(vmid, 0, sizeof(vmid)); + memset(ipuser, 0, sizeof(ipuser)); + + spin_lock_bh(&priv->lock); + if (priv->iucv_state == IUCV_CONNECTED) { + memcpy(vmid, priv->info_path, 8); + memcpy(ipuser, priv->info_path + 8, 8); + } + spin_unlock_bh(&priv->lock); + EBCASC(ipuser, 8); + + return sprintf(buf, "%s:%s\n", vmid, ipuser); +} + /* HVC operations */ static const struct hv_ops hvc_iucv_ops = { @@ -985,6 +1052,25 @@ static struct device_driver hvc_iucv_driver = { .pm = &hvc_iucv_pm_ops, }; +/* IUCV HVC device attributes */ +static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL); +static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL); +static DEVICE_ATTR(peer, 0640, hvc_iucv_dev_peer_show, NULL); +static struct attribute *hvc_iucv_dev_attrs[] = { + &dev_attr_termid.attr, + &dev_attr_state.attr, + &dev_attr_peer.attr, + NULL, +}; +static struct attribute_group hvc_iucv_dev_attr_group = { + .attrs = hvc_iucv_dev_attrs, +}; +static const struct attribute_group *hvc_iucv_dev_attr_groups[] = { + &hvc_iucv_dev_attr_group, + NULL, +}; + + /** * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance * @id: hvc_iucv_table index @@ -1046,6 +1132,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) priv->dev->bus = &iucv_bus; priv->dev->parent = iucv_root; priv->dev->driver = &hvc_iucv_driver; + priv->dev->groups = hvc_iucv_dev_attr_groups; priv->dev->release = (void (*)(struct device *)) kfree; rc = device_register(priv->dev); if (rc) { diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index d98e43348970..67423805e6d9 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -455,11 +455,11 @@ static void load_code(struct icom_port *icom_port) for (index = 0; index < fw->size; index++) new_page[index] = fw->data[index]; - release_firmware(fw); - writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); writel(temp_pci, &icom_port->dram->mac_load_addr); + release_firmware(fw); + /*Setting the syncReg to 0x80 causes adapter to start downloading the personality code into adapter instruction RAM. Once code is loaded, it will begin executing and, based on diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 9cbd3acaf37f..8fa1134e0051 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1508,10 +1508,14 @@ static int pch_uart_verify_port(struct uart_port *port, __func__); return -EOPNOTSUPP; #endif - dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); - if (!priv->use_dma) + if (!priv->use_dma) { pch_request_dma(port); - priv->use_dma = 1; + if (priv->chan_rx) + priv->use_dma = 1; + } + dev_info(priv->port.dev, "PCH UART: %s\n", + priv->use_dma ? + "Use DMA Mode" : "No DMA"); } return 0; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c1af04d46682..9cd706df3b33 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1209,7 +1209,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); - clk_disable_unprepare(ourport->clk); return 0; } @@ -1287,6 +1286,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(pdev, &ourport->port); + /* + * Deactivate the clock enabled in s3c24xx_serial_init_port here, + * so that a potential re-enablement through the pm-callback overlaps + * and keeps the clock enabled in this case. + */ + clk_disable_unprepare(ourport->clk); + #ifdef CONFIG_SAMSUNG_CLOCK ret = device_create_file(&pdev->dev, &dev_attr_clock_source); if (ret < 0) diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index bdae7a04af75..a84788ba662c 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -81,7 +81,7 @@ static int tce_iommu_enable(struct tce_container *container) * enforcing the limit based on the max that the guest can map. */ down_write(¤t->mm->mmap_sem); - npages = (tbl->it_size << IOMMU_PAGE_SHIFT) >> PAGE_SHIFT; + npages = (tbl->it_size << IOMMU_PAGE_SHIFT_4K) >> PAGE_SHIFT; locked = current->mm->locked_vm + npages; lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) { @@ -110,7 +110,7 @@ static void tce_iommu_disable(struct tce_container *container) down_write(¤t->mm->mmap_sem); current->mm->locked_vm -= (container->tbl->it_size << - IOMMU_PAGE_SHIFT) >> PAGE_SHIFT; + IOMMU_PAGE_SHIFT_4K) >> PAGE_SHIFT; up_write(¤t->mm->mmap_sem); } @@ -174,8 +174,8 @@ static long tce_iommu_ioctl(void *iommu_data, if (info.argsz < minsz) return -EINVAL; - info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT; - info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT; + info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT_4K; + info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT_4K; info.flags = 0; if (copy_to_user((void __user *)arg, &info, minsz)) @@ -205,8 +205,8 @@ static long tce_iommu_ioctl(void *iommu_data, VFIO_DMA_MAP_FLAG_WRITE)) return -EINVAL; - if ((param.size & ~IOMMU_PAGE_MASK) || - (param.vaddr & ~IOMMU_PAGE_MASK)) + if ((param.size & ~IOMMU_PAGE_MASK_4K) || + (param.vaddr & ~IOMMU_PAGE_MASK_4K)) return -EINVAL; /* iova is checked by the IOMMU API */ @@ -220,17 +220,17 @@ static long tce_iommu_ioctl(void *iommu_data, if (ret) return ret; - for (i = 0; i < (param.size >> IOMMU_PAGE_SHIFT); ++i) { + for (i = 0; i < (param.size >> IOMMU_PAGE_SHIFT_4K); ++i) { ret = iommu_put_tce_user_mode(tbl, - (param.iova >> IOMMU_PAGE_SHIFT) + i, + (param.iova >> IOMMU_PAGE_SHIFT_4K) + i, tce); if (ret) break; - tce += IOMMU_PAGE_SIZE; + tce += IOMMU_PAGE_SIZE_4K; } if (ret) iommu_clear_tces_and_put_pages(tbl, - param.iova >> IOMMU_PAGE_SHIFT, i); + param.iova >> IOMMU_PAGE_SHIFT_4K, i); iommu_flush_tce(tbl); @@ -256,17 +256,17 @@ static long tce_iommu_ioctl(void *iommu_data, if (param.flags) return -EINVAL; - if (param.size & ~IOMMU_PAGE_MASK) + if (param.size & ~IOMMU_PAGE_MASK_4K) return -EINVAL; ret = iommu_tce_clear_param_check(tbl, param.iova, 0, - param.size >> IOMMU_PAGE_SHIFT); + param.size >> IOMMU_PAGE_SHIFT_4K); if (ret) return ret; ret = iommu_clear_tces_and_put_pages(tbl, - param.iova >> IOMMU_PAGE_SHIFT, - param.size >> IOMMU_PAGE_SHIFT); + param.iova >> IOMMU_PAGE_SHIFT_4K, + param.size >> IOMMU_PAGE_SHIFT_4K); iommu_flush_tce(tbl); return ret; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index fb80d68f4d33..b75201ff46f6 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -241,7 +241,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL); if (!pb) { - dev_err(&pdev->dev, "no memory for state\n"); ret = -ENOMEM; goto err_alloc; } diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 7af425f53bee..8482f2d11606 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -156,7 +156,7 @@ int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid) return -EOPNOTSUPP; acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { - retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + retval = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (retval) return retval; set_cached_acl(inode, ACL_TYPE_ACCESS, acl); @@ -200,7 +200,7 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep, if (acl) { if (S_ISDIR(mode)) *dpacl = posix_acl_dup(acl); - retval = posix_acl_create(&acl, GFP_NOFS, &mode); + retval = __posix_acl_create(&acl, GFP_NOFS, &mode); if (retval < 0) return retval; if (retval > 0) diff --git a/fs/Kconfig b/fs/Kconfig index c229f828eb01..7385e54be4b9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -68,10 +68,6 @@ source "fs/quota/Kconfig" source "fs/autofs4/Kconfig" source "fs/fuse/Kconfig" -config GENERIC_ACL - bool - select FS_POSIX_ACL - menu "Caches" source "fs/fscache/Kconfig" @@ -119,7 +115,7 @@ config TMPFS_POSIX_ACL bool "Tmpfs POSIX Access Control Lists" depends on TMPFS select TMPFS_XATTR - select GENERIC_ACL + select FS_POSIX_ACL help POSIX Access Control Lists (ACLs) support additional access rights for users and groups beyond the standard owner/group/world scheme, diff --git a/fs/Makefile b/fs/Makefile index 39a824f44e7c..47ac07bb4acc 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -42,9 +42,8 @@ obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o -obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o +obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ -obj-$(CONFIG_GENERIC_ACL) += generic_acl.o obj-$(CONFIG_COREDUMP) += coredump.o obj-$(CONFIG_SYSCTL) += drop_caches.o diff --git a/fs/affs/super.c b/fs/affs/super.c index 45161a832bbc..d098731b82ff 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -49,11 +49,6 @@ affs_put_super(struct super_block *sb) pr_debug("AFFS: put_super()\n"); cancel_delayed_work_sync(&sbi->sb_work); - kfree(sbi->s_prefix); - affs_free_bitmap(sb); - affs_brelse(sbi->s_root_bh); - kfree(sbi); - sb->s_fs_info = NULL; } static int @@ -316,7 +311,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) unsigned long mount_flags; int tmp_flags; /* fix remount prototype... */ u8 sig[4]; - int ret = -EINVAL; + int ret; save_mount_options(sb, data); @@ -412,17 +407,19 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk(KERN_ERR "AFFS: No valid root block on device %s\n", sb->s_id); - goto out_error; + return -EINVAL; /* N.B. after this point bh must be released */ got_root: + /* Keep super block in cache */ + sbi->s_root_bh = root_bh; root_block = sbi->s_root_block; /* Find out which kind of FS we have */ boot_bh = sb_bread(sb, 0); if (!boot_bh) { printk(KERN_ERR "AFFS: Cannot read boot block\n"); - goto out_error; + return -EINVAL; } memcpy(sig, boot_bh->b_data, 4); brelse(boot_bh); @@ -471,7 +468,7 @@ got_root: default: printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", sb->s_id, chksum); - goto out_error; + return -EINVAL; } if (mount_flags & SF_VERBOSE) { @@ -488,22 +485,17 @@ got_root: if (sbi->s_flags & SF_OFS) sbi->s_data_blksize -= 24; - /* Keep super block in cache */ - sbi->s_root_bh = root_bh; - /* N.B. after this point s_root_bh must be released */ - tmp_flags = sb->s_flags; - if (affs_init_bitmap(sb, &tmp_flags)) - goto out_error; + ret = affs_init_bitmap(sb, &tmp_flags); + if (ret) + return ret; sb->s_flags = tmp_flags; /* set up enough so that it can read an inode */ root_inode = affs_iget(sb, root_block); - if (IS_ERR(root_inode)) { - ret = PTR_ERR(root_inode); - goto out_error; - } + if (IS_ERR(root_inode)) + return PTR_ERR(root_inode); if (AFFS_SB(sb)->s_flags & SF_INTL) sb->s_d_op = &affs_intl_dentry_operations; @@ -513,22 +505,11 @@ got_root: sb->s_root = d_make_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); - goto out_error; + return -ENOMEM; } pr_debug("AFFS: s_flags=%lX\n",sb->s_flags); return 0; - - /* - * Begin the cascaded cleanup ... - */ -out_error: - kfree(sbi->s_bitmap); - affs_brelse(root_bh); - kfree(sbi->s_prefix); - kfree(sbi); - sb->s_fs_info = NULL; - return ret; } static int @@ -615,11 +596,23 @@ static struct dentry *affs_mount(struct file_system_type *fs_type, return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super); } +static void affs_kill_sb(struct super_block *sb) +{ + struct affs_sb_info *sbi = AFFS_SB(sb); + kill_block_super(sb); + if (sbi) { + affs_free_bitmap(sb); + affs_brelse(sbi->s_root_bh); + kfree(sbi->s_prefix); + kfree(sbi); + } +} + static struct file_system_type affs_fs_type = { .owner = THIS_MODULE, .name = "affs", .mount = affs_mount, - .kill_sb = kill_block_super, + .kill_sb = affs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("affs"); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a306bb6d88d9..6621f8008122 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -195,7 +195,6 @@ struct afs_cell { struct list_head link; /* main cell list link */ struct key *anonymous_key; /* anonymous user key for this cell */ struct list_head proc_link; /* /proc cell list link */ - struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ #ifdef CONFIG_AFS_FSCACHE struct fscache_cookie *cache; /* caching cookie */ #endif diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 526e4bbbde59..bddc5120ed40 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -41,11 +41,8 @@ static const struct file_operations afs_proc_cells_fops = { .write = afs_proc_cells_write, .llseek = seq_lseek, .release = seq_release, - .owner = THIS_MODULE, }; -static int afs_proc_rootcell_open(struct inode *inode, struct file *file); -static int afs_proc_rootcell_release(struct inode *inode, struct file *file); static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, size_t size, loff_t *_pos); static ssize_t afs_proc_rootcell_write(struct file *file, @@ -53,17 +50,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file, size_t size, loff_t *_pos); static const struct file_operations afs_proc_rootcell_fops = { - .open = afs_proc_rootcell_open, .read = afs_proc_rootcell_read, .write = afs_proc_rootcell_write, .llseek = no_llseek, - .release = afs_proc_rootcell_release, - .owner = THIS_MODULE, }; static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); -static int afs_proc_cell_volumes_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *pos); @@ -81,14 +73,11 @@ static const struct file_operations afs_proc_cell_volumes_fops = { .open = afs_proc_cell_volumes_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_volumes_release, - .owner = THIS_MODULE, + .release = seq_release, }; static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file); -static int afs_proc_cell_vlservers_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *pos); @@ -106,13 +95,10 @@ static const struct file_operations afs_proc_cell_vlservers_fops = { .open = afs_proc_cell_vlservers_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_vlservers_release, - .owner = THIS_MODULE, + .release = seq_release, }; static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); -static int afs_proc_cell_servers_release(struct inode *inode, - struct file *file); static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *pos); @@ -130,8 +116,7 @@ static const struct file_operations afs_proc_cell_servers_fops = { .open = afs_proc_cell_servers_open, .read = seq_read, .llseek = seq_lseek, - .release = afs_proc_cell_servers_release, - .owner = THIS_MODULE, + .release = seq_release, }; /* @@ -139,29 +124,21 @@ static const struct file_operations afs_proc_cell_servers_fops = { */ int afs_proc_init(void) { - struct proc_dir_entry *p; - _enter(""); proc_afs = proc_mkdir("fs/afs", NULL); if (!proc_afs) goto error_dir; - p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops); - if (!p) - goto error_cells; - - p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops); - if (!p) - goto error_rootcell; + if (!proc_create("cells", 0, proc_afs, &afs_proc_cells_fops) || + !proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops)) + goto error_tree; _leave(" = 0"); return 0; -error_rootcell: - remove_proc_entry("cells", proc_afs); -error_cells: - remove_proc_entry("fs/afs", NULL); +error_tree: + remove_proc_subtree("fs/afs", NULL); error_dir: _leave(" = -ENOMEM"); return -ENOMEM; @@ -172,9 +149,7 @@ error_dir: */ void afs_proc_cleanup(void) { - remove_proc_entry("rootcell", proc_afs); - remove_proc_entry("cells", proc_afs); - remove_proc_entry("fs/afs", NULL); + remove_proc_subtree("fs/afs", NULL); } /* @@ -319,19 +294,6 @@ inval: goto done; } -/* - * Stubs for /proc/fs/afs/rootcell - */ -static int afs_proc_rootcell_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int afs_proc_rootcell_release(struct inode *inode, struct file *file) -{ - return 0; -} - static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, size_t size, loff_t *_pos) { @@ -387,38 +349,27 @@ nomem: */ int afs_proc_cell_setup(struct afs_cell *cell) { - struct proc_dir_entry *p; + struct proc_dir_entry *dir; _enter("%p{%s}", cell, cell->name); - cell->proc_dir = proc_mkdir(cell->name, proc_afs); - if (!cell->proc_dir) + dir = proc_mkdir(cell->name, proc_afs); + if (!dir) goto error_dir; - p = proc_create_data("servers", 0, cell->proc_dir, - &afs_proc_cell_servers_fops, cell); - if (!p) - goto error_servers; - - p = proc_create_data("vlservers", 0, cell->proc_dir, - &afs_proc_cell_vlservers_fops, cell); - if (!p) - goto error_vlservers; - - p = proc_create_data("volumes", 0, cell->proc_dir, - &afs_proc_cell_volumes_fops, cell); - if (!p) - goto error_volumes; + if (!proc_create_data("servers", 0, dir, + &afs_proc_cell_servers_fops, cell) || + !proc_create_data("vlservers", 0, dir, + &afs_proc_cell_vlservers_fops, cell) || + !proc_create_data("volumes", 0, dir, + &afs_proc_cell_volumes_fops, cell)) + goto error_tree; _leave(" = 0"); return 0; -error_volumes: - remove_proc_entry("vlservers", cell->proc_dir); -error_vlservers: - remove_proc_entry("servers", cell->proc_dir); -error_servers: - remove_proc_entry(cell->name, proc_afs); +error_tree: + remove_proc_subtree(cell->name, proc_afs); error_dir: _leave(" = -ENOMEM"); return -ENOMEM; @@ -431,10 +382,7 @@ void afs_proc_cell_remove(struct afs_cell *cell) { _enter(""); - remove_proc_entry("volumes", cell->proc_dir); - remove_proc_entry("vlservers", cell->proc_dir); - remove_proc_entry("servers", cell->proc_dir); - remove_proc_entry(cell->name, proc_afs); + remove_proc_subtree(cell->name, proc_afs); _leave(""); } @@ -463,14 +411,6 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ @@ -569,15 +509,6 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_vlservers_release(struct inode *inode, - struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ @@ -673,15 +604,6 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) } /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_servers_release(struct inode *inode, - struct file *file) -{ - return seq_release(inode, file); -} - -/* * set up the iterator to start reading from the cells list and return the * first item */ diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index daa15d6ba450..845d2d690ce2 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -324,8 +324,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino); inode = iget_locked(sb, ino); - if (IS_ERR(inode)) - return inode; + if (!inode) + return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 0890c83643e9..ff9b3995d453 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -35,13 +35,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) char *value = NULL; struct posix_acl *acl; - if (!IS_POSIXACL(inode)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -76,31 +69,10 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) return acl; } -static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name, - void *value, size_t size, int type) -{ - struct posix_acl *acl; - int ret = 0; - - if (!IS_POSIXACL(dentry->d_inode)) - return -EOPNOTSUPP; - - acl = btrfs_get_acl(dentry->d_inode, type); - - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); - posix_acl_release(acl); - - return ret; -} - /* * Needs to be called with fs_mutex held */ -static int btrfs_set_acl(struct btrfs_trans_handle *trans, +static int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct posix_acl *acl, int type) { int ret, size = 0; @@ -158,35 +130,9 @@ out: return ret; } -static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) +int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - int ret; - struct posix_acl *acl = NULL; - - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (!IS_POSIXACL(dentry->d_inode)) - return -EOPNOTSUPP; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (acl) { - ret = posix_acl_valid(acl); - if (ret) - goto out; - } - } - - ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type); -out: - posix_acl_release(acl); - - return ret; + return __btrfs_set_acl(NULL, inode, acl, type); } /* @@ -197,83 +143,31 @@ out: int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; int ret = 0; /* this happens with subvols */ if (!dir) return 0; - if (!S_ISLNK(inode->i_mode)) { - if (IS_POSIXACL(dir)) { - acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } + ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (ret) + return ret; - if (!acl) - inode->i_mode &= ~current_umask(); + if (default_acl) { + ret = __btrfs_set_acl(trans, inode, default_acl, + ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); } - if (IS_POSIXACL(dir) && acl) { - if (S_ISDIR(inode->i_mode)) { - ret = btrfs_set_acl(trans, inode, acl, - ACL_TYPE_DEFAULT); - if (ret) - goto failed; - } - ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (ret < 0) - return ret; - - if (ret > 0) { - /* we need an acl */ - ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); - } else if (ret < 0) { - cache_no_acl(inode); - } - } else { - cache_no_acl(inode); + if (acl) { + if (!ret) + ret = __btrfs_set_acl(trans, inode, acl, + ACL_TYPE_ACCESS); + posix_acl_release(acl); } -failed: - posix_acl_release(acl); - - return ret; -} -int btrfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int ret = 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!IS_POSIXACL(inode)) - return 0; - - acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR_OR_NULL(acl)) - return PTR_ERR(acl); - - ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (ret) - return ret; - ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS); - posix_acl_release(acl); + if (!default_acl && !acl) + cache_no_acl(inode); return ret; } - -const struct xattr_handler btrfs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = btrfs_xattr_acl_get, - .set = btrfs_xattr_acl_set, -}; - -const struct xattr_handler btrfs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = btrfs_xattr_acl_get, - .set = btrfs_xattr_acl_set, -}; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 54ab86127f7a..7506825211a2 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3899,20 +3899,17 @@ do { \ /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL struct posix_acl *btrfs_get_acl(struct inode *inode, int type); +int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir); -int btrfs_acl_chmod(struct inode *inode); #else #define btrfs_get_acl NULL +#define btrfs_set_acl NULL static inline int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { return 0; } -static inline int btrfs_acl_chmod(struct inode *inode) -{ - return 0; -} #endif /* relocation.c */ diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 471a4f7f4044..514b291b1354 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4468,7 +4468,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) err = btrfs_dirty_inode(inode); if (!err && attr->ia_valid & ATTR_MODE) - err = btrfs_acl_chmod(inode); + err = posix_acl_chmod(inode, inode->i_mode); } return err; @@ -8653,12 +8653,14 @@ static const struct inode_operations btrfs_dir_inode_operations = { .removexattr = btrfs_removexattr, .permission = btrfs_permission, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_dir_ro_inode_operations = { .lookup = btrfs_lookup, .permission = btrfs_permission, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; @@ -8728,6 +8730,7 @@ static const struct inode_operations btrfs_file_inode_operations = { .permission = btrfs_permission, .fiemap = btrfs_fiemap, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_special_inode_operations = { @@ -8739,6 +8742,7 @@ static const struct inode_operations btrfs_special_inode_operations = { .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, .get_acl = btrfs_get_acl, + .set_acl = btrfs_set_acl, .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_symlink_inode_operations = { @@ -8752,7 +8756,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .get_acl = btrfs_get_acl, .update_time = btrfs_update_time, }; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 21da5762b0b1..ad27dcea319c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2686,14 +2686,11 @@ out_unlock: #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) static long btrfs_ioctl_file_extent_same(struct file *file, - void __user *argp) + struct btrfs_ioctl_same_args __user *argp) { - struct btrfs_ioctl_same_args tmp; struct btrfs_ioctl_same_args *same; struct btrfs_ioctl_same_extent_info *info; - struct inode *src = file->f_dentry->d_inode; - struct file *dst_file = NULL; - struct inode *dst; + struct inode *src = file_inode(file); u64 off; u64 len; int i; @@ -2701,6 +2698,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, unsigned long size; u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; bool is_admin = capable(CAP_SYS_ADMIN); + u16 count; if (!(file->f_mode & FMODE_READ)) return -EINVAL; @@ -2709,17 +2707,14 @@ static long btrfs_ioctl_file_extent_same(struct file *file, if (ret) return ret; - if (copy_from_user(&tmp, - (struct btrfs_ioctl_same_args __user *)argp, - sizeof(tmp))) { + if (get_user(count, &argp->dest_count)) { ret = -EFAULT; goto out; } - size = sizeof(tmp) + - tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info); + size = offsetof(struct btrfs_ioctl_same_args __user, info[count]); - same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size); + same = memdup_user(argp, size); if (IS_ERR(same)) { ret = PTR_ERR(same); @@ -2756,52 +2751,35 @@ static long btrfs_ioctl_file_extent_same(struct file *file, goto out; /* pre-format output fields to sane values */ - for (i = 0; i < same->dest_count; i++) { + for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; same->info[i].status = 0; } - ret = 0; - for (i = 0; i < same->dest_count; i++) { - info = &same->info[i]; - - dst_file = fget(info->fd); - if (!dst_file) { + for (i = 0, info = same->info; i < count; i++, info++) { + struct inode *dst; + struct fd dst_file = fdget(info->fd); + if (!dst_file.file) { info->status = -EBADF; - goto next; + continue; } + dst = file_inode(dst_file.file); - if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { + if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) { info->status = -EINVAL; - goto next; - } - - info->status = -EXDEV; - if (file->f_path.mnt != dst_file->f_path.mnt) - goto next; - - dst = dst_file->f_dentry->d_inode; - if (src->i_sb != dst->i_sb) - goto next; - - if (S_ISDIR(dst->i_mode)) { + } else if (file->f_path.mnt != dst_file.file->f_path.mnt) { + info->status = -EXDEV; + } else if (S_ISDIR(dst->i_mode)) { info->status = -EISDIR; - goto next; - } - - if (!S_ISREG(dst->i_mode)) { + } else if (!S_ISREG(dst->i_mode)) { info->status = -EACCES; - goto next; + } else { + info->status = btrfs_extent_same(src, off, len, dst, + info->logical_offset); + if (info->status == 0) + info->bytes_deduped += len; } - - info->status = btrfs_extent_same(src, off, len, dst, - info->logical_offset); - if (info->status == 0) - info->bytes_deduped += len; - -next: - if (dst_file) - fput(dst_file); + fdput(dst_file); } ret = copy_to_user(argp, same, size); diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 05740b9789e4..3d1c301c9260 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -22,6 +22,7 @@ #include <linux/rwsem.h> #include <linux/xattr.h> #include <linux/security.h> +#include <linux/posix_acl_xattr.h> #include "ctree.h" #include "btrfs_inode.h" #include "transaction.h" @@ -313,8 +314,8 @@ err: */ const struct xattr_handler *btrfs_xattr_handlers[] = { #ifdef CONFIG_BTRFS_FS_POSIX_ACL - &btrfs_xattr_acl_access_handler, - &btrfs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL, }; diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h index b3cc8039134b..5049608d1388 100644 --- a/fs/btrfs/xattr.h +++ b/fs/btrfs/xattr.h @@ -21,8 +21,6 @@ #include <linux/xattr.h> -extern const struct xattr_handler btrfs_xattr_acl_access_handler; -extern const struct xattr_handler btrfs_xattr_acl_default_handler; extern const struct xattr_handler *btrfs_xattr_handlers[]; extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name, diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig index ac9a2ef5bb9b..264e9bf83ff3 100644 --- a/fs/ceph/Kconfig +++ b/fs/ceph/Kconfig @@ -25,3 +25,16 @@ config CEPH_FSCACHE caching support for Ceph clients using FS-Cache endif + +config CEPH_FS_POSIX_ACL + bool "Ceph POSIX Access Control Lists" + depends on CEPH_FS + select FS_POSIX_ACL + help + POSIX Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the POSIX ACLs for + Linux website <http://acl.bestbits.at/>. + + If you don't know what Access Control Lists are, say N diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile index 32e30106a2f0..85a4230b9bff 100644 --- a/fs/ceph/Makefile +++ b/fs/ceph/Makefile @@ -10,3 +10,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \ debugfs.o ceph-$(CONFIG_CEPH_FSCACHE) += cache.o +ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c new file mode 100644 index 000000000000..66d377a12f7c --- /dev/null +++ b/fs/ceph/acl.c @@ -0,0 +1,230 @@ +/* + * linux/fs/ceph/acl.c + * + * Copyright (C) 2013 Guangliang Zhao, <lucienchao@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <linux/ceph/ceph_debug.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/xattr.h> +#include <linux/posix_acl_xattr.h> +#include <linux/posix_acl.h> +#include <linux/sched.h> +#include <linux/slab.h> + +#include "super.h" + +static inline void ceph_set_cached_acl(struct inode *inode, + int type, struct posix_acl *acl) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + + spin_lock(&ci->i_ceph_lock); + if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) + set_cached_acl(inode, type, acl); + spin_unlock(&ci->i_ceph_lock); +} + +static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, + int type) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct posix_acl *acl = ACL_NOT_CACHED; + + spin_lock(&ci->i_ceph_lock); + if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) + acl = get_cached_acl(inode, type); + spin_unlock(&ci->i_ceph_lock); + + return acl; +} + +void ceph_forget_all_cached_acls(struct inode *inode) +{ + forget_all_cached_acls(inode); +} + +struct posix_acl *ceph_get_acl(struct inode *inode, int type) +{ + int size; + const char *name; + char *value = NULL; + struct posix_acl *acl; + + if (!IS_POSIXACL(inode)) + return NULL; + + acl = ceph_get_cached_acl(inode, type); + if (acl != ACL_NOT_CACHED) + return acl; + + switch (type) { + case ACL_TYPE_ACCESS: + name = POSIX_ACL_XATTR_ACCESS; + break; + case ACL_TYPE_DEFAULT: + name = POSIX_ACL_XATTR_DEFAULT; + break; + default: + BUG(); + } + + size = __ceph_getxattr(inode, name, "", 0); + if (size > 0) { + value = kzalloc(size, GFP_NOFS); + if (!value) + return ERR_PTR(-ENOMEM); + size = __ceph_getxattr(inode, name, value, size); + } + + if (size > 0) + acl = posix_acl_from_xattr(&init_user_ns, value, size); + else if (size == -ERANGE || size == -ENODATA || size == 0) + acl = NULL; + else + acl = ERR_PTR(-EIO); + + kfree(value); + + if (!IS_ERR(acl)) + ceph_set_cached_acl(inode, type, acl); + + return acl; +} + +int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int ret = 0, size = 0; + const char *name = NULL; + char *value = NULL; + struct iattr newattrs; + umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; + struct dentry *dentry = d_find_alias(inode); + + if (acl) { + ret = posix_acl_valid(acl); + if (ret < 0) + goto out; + } + + switch (type) { + case ACL_TYPE_ACCESS: + name = POSIX_ACL_XATTR_ACCESS; + if (acl) { + ret = posix_acl_equiv_mode(acl, &new_mode); + if (ret < 0) + goto out; + if (ret == 0) + acl = NULL; + } + break; + case ACL_TYPE_DEFAULT: + if (!S_ISDIR(inode->i_mode)) { + ret = acl ? -EINVAL : 0; + goto out; + } + name = POSIX_ACL_XATTR_DEFAULT; + break; + default: + ret = -EINVAL; + goto out; + } + + if (acl) { + size = posix_acl_xattr_size(acl->a_count); + value = kmalloc(size, GFP_NOFS); + if (!value) { + ret = -ENOMEM; + goto out; + } + + ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); + if (ret < 0) + goto out_free; + } + + if (new_mode != old_mode) { + newattrs.ia_mode = new_mode; + newattrs.ia_valid = ATTR_MODE; + ret = ceph_setattr(dentry, &newattrs); + if (ret) + goto out_free; + } + + if (value) + ret = __ceph_setxattr(dentry, name, value, size, 0); + else + ret = __ceph_removexattr(dentry, name); + + if (ret) { + if (new_mode != old_mode) { + newattrs.ia_mode = old_mode; + newattrs.ia_valid = ATTR_MODE; + ceph_setattr(dentry, &newattrs); + } + goto out_free; + } + + ceph_set_cached_acl(inode, type, acl); + +out_free: + kfree(value); +out: + return ret; +} + +int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir) +{ + struct posix_acl *acl = NULL; + int ret = 0; + + if (!S_ISLNK(inode->i_mode)) { + if (IS_POSIXACL(dir)) { + acl = ceph_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) { + ret = PTR_ERR(acl); + goto out; + } + } + + if (!acl) + inode->i_mode &= ~current_umask(); + } + + if (IS_POSIXACL(dir) && acl) { + if (S_ISDIR(inode->i_mode)) { + ret = ceph_set_acl(inode, acl, ACL_TYPE_DEFAULT); + if (ret) + goto out_release; + } + ret = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); + if (ret < 0) + goto out; + else if (ret > 0) + ret = ceph_set_acl(inode, acl, ACL_TYPE_ACCESS); + else + cache_no_acl(inode); + } else { + cache_no_acl(inode); + } + +out_release: + posix_acl_release(acl); +out: + return ret; +} diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index ec3ba43b9faa..b53278c9fd97 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -209,6 +209,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) err = 0; if (err < 0) { SetPageError(page); + ceph_fscache_readpage_cancel(inode, page); goto out; } else { if (err < PAGE_CACHE_SIZE) { @@ -256,6 +257,8 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) for (i = 0; i < num_pages; i++) { struct page *page = osd_data->pages[i]; + if (rc < 0) + goto unlock; if (bytes < (int)PAGE_CACHE_SIZE) { /* zero (remainder of) page */ int s = bytes < 0 ? 0 : bytes; @@ -266,6 +269,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) flush_dcache_page(page); SetPageUptodate(page); ceph_readpage_to_fscache(inode, page); +unlock: unlock_page(page); page_cache_release(page); bytes -= PAGE_CACHE_SIZE; @@ -1207,6 +1211,41 @@ const struct address_space_operations ceph_aops = { /* * vm ops */ +static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct inode *inode = file_inode(vma->vm_file); + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_file_info *fi = vma->vm_file->private_data; + loff_t off = vmf->pgoff << PAGE_CACHE_SHIFT; + int want, got, ret; + + dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n", + inode, ceph_vinop(inode), off, (size_t)PAGE_CACHE_SIZE); + if (fi->fmode & CEPH_FILE_MODE_LAZY) + want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; + else + want = CEPH_CAP_FILE_CACHE; + while (1) { + got = 0; + ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1); + if (ret == 0) + break; + if (ret != -ERESTARTSYS) { + WARN_ON(1); + return VM_FAULT_SIGBUS; + } + } + dout("filemap_fault %p %llu~%zd got cap refs on %s\n", + inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got)); + + ret = filemap_fault(vma, vmf); + + dout("filemap_fault %p %llu~%zd dropping cap refs on %s ret %d\n", + inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got), ret); + ceph_put_cap_refs(ci, got); + + return ret; +} /* * Reuse write_begin here for simplicity. @@ -1214,23 +1253,41 @@ const struct address_space_operations ceph_aops = { static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct inode *inode = file_inode(vma->vm_file); - struct page *page = vmf->page; + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_file_info *fi = vma->vm_file->private_data; struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + struct page *page = vmf->page; loff_t off = page_offset(page); - loff_t size, len; - int ret; - - /* Update time before taking page lock */ - file_update_time(vma->vm_file); + loff_t size = i_size_read(inode); + size_t len; + int want, got, ret; - size = i_size_read(inode); if (off + PAGE_CACHE_SIZE <= size) len = PAGE_CACHE_SIZE; else len = size & ~PAGE_CACHE_MASK; - dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode, - off, len, page, page->index); + dout("page_mkwrite %p %llx.%llx %llu~%zd getting caps i_size %llu\n", + inode, ceph_vinop(inode), off, len, size); + if (fi->fmode & CEPH_FILE_MODE_LAZY) + want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; + else + want = CEPH_CAP_FILE_BUFFER; + while (1) { + got = 0; + ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, off + len); + if (ret == 0) + break; + if (ret != -ERESTARTSYS) { + WARN_ON(1); + return VM_FAULT_SIGBUS; + } + } + dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", + inode, off, len, ceph_cap_string(got)); + + /* Update time before taking page lock */ + file_update_time(vma->vm_file); lock_page(page); @@ -1252,14 +1309,26 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ret = VM_FAULT_SIGBUS; } out: - dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret); - if (ret != VM_FAULT_LOCKED) + if (ret != VM_FAULT_LOCKED) { unlock_page(page); + } else { + int dirty; + spin_lock(&ci->i_ceph_lock); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + spin_unlock(&ci->i_ceph_lock); + if (dirty) + __mark_inode_dirty(inode, dirty); + } + + dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n", + inode, off, len, ceph_cap_string(got), ret); + ceph_put_cap_refs(ci, got); + return ret; } static struct vm_operations_struct ceph_vmops = { - .fault = filemap_fault, + .fault = ceph_filemap_fault, .page_mkwrite = ceph_page_mkwrite, .remap_pages = generic_file_remap_pages, }; diff --git a/fs/ceph/cache.h b/fs/ceph/cache.h index ba949408a336..da95f61b7a09 100644 --- a/fs/ceph/cache.h +++ b/fs/ceph/cache.h @@ -67,6 +67,14 @@ static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp) return fscache_maybe_release_page(ci->fscache, page, gfp); } +static inline void ceph_fscache_readpage_cancel(struct inode *inode, + struct page *page) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + if (fscache_cookie_valid(ci->fscache) && PageFsCache(page)) + __fscache_uncache_page(ci->fscache, page); +} + static inline void ceph_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) { @@ -145,6 +153,11 @@ static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp) return 1; } +static inline void ceph_fscache_readpage_cancel(struct inode *inode, + struct page *page) +{ +} + static inline void ceph_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) { diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 3c0a4bd74996..17543383545c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -555,21 +555,34 @@ retry: cap->ci = ci; __insert_cap_node(ci, cap); - /* clear out old exporting info? (i.e. on cap import) */ - if (ci->i_cap_exporting_mds == mds) { - ci->i_cap_exporting_issued = 0; - ci->i_cap_exporting_mseq = 0; - ci->i_cap_exporting_mds = -1; - } - /* add to session cap list */ cap->session = session; spin_lock(&session->s_cap_lock); list_add_tail(&cap->session_caps, &session->s_caps); session->s_nr_caps++; spin_unlock(&session->s_cap_lock); - } else if (new_cap) - ceph_put_cap(mdsc, new_cap); + } else { + if (new_cap) + ceph_put_cap(mdsc, new_cap); + + /* + * auth mds of the inode changed. we received the cap export + * message, but still haven't received the cap import message. + * handle_cap_export() updated the new auth MDS' cap. + * + * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing + * a message that was send before the cap import message. So + * don't remove caps. + */ + if (ceph_seq_cmp(seq, cap->seq) <= 0) { + WARN_ON(cap != ci->i_auth_cap); + WARN_ON(cap->cap_id != cap_id); + seq = cap->seq; + mseq = cap->mseq; + issued |= cap->issued; + flags |= CEPH_CAP_FLAG_AUTH; + } + } if (!ci->i_snap_realm) { /* @@ -611,15 +624,9 @@ retry: if (ci->i_auth_cap == NULL || ceph_seq_cmp(ci->i_auth_cap->mseq, mseq) < 0) ci->i_auth_cap = cap; - } else if (ci->i_auth_cap == cap) { - ci->i_auth_cap = NULL; - spin_lock(&mdsc->cap_dirty_lock); - if (!list_empty(&ci->i_dirty_item)) { - dout(" moving %p to cap_dirty_migrating\n", inode); - list_move(&ci->i_dirty_item, - &mdsc->cap_dirty_migrating); - } - spin_unlock(&mdsc->cap_dirty_lock); + ci->i_cap_exporting_issued = 0; + } else { + WARN_ON(ci->i_auth_cap == cap); } dout("add_cap inode %p (%llx.%llx) cap %p %s now %s seq %d mds%d\n", @@ -628,7 +635,7 @@ retry: cap->cap_id = cap_id; cap->issued = issued; cap->implemented |= issued; - if (mseq > cap->mseq) + if (ceph_seq_cmp(mseq, cap->mseq) > 0) cap->mds_wanted = wanted; else cap->mds_wanted |= wanted; @@ -816,7 +823,7 @@ int __ceph_caps_revoking_other(struct ceph_inode_info *ci, for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { cap = rb_entry(p, struct ceph_cap, ci_node); - if (cap != ocap && __cap_is_valid(cap) && + if (cap != ocap && (cap->implemented & ~cap->issued & mask)) return 1; } @@ -888,7 +895,19 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci) */ static int __ceph_is_any_caps(struct ceph_inode_info *ci) { - return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0; + return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_issued; +} + +int ceph_is_any_caps(struct inode *inode) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + int ret; + + spin_lock(&ci->i_ceph_lock); + ret = __ceph_is_any_caps(ci); + spin_unlock(&ci->i_ceph_lock); + + return ret; } /* @@ -1383,13 +1402,10 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ci->i_snap_realm->cached_context); dout(" inode %p now dirty snapc %p auth cap %p\n", &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); + WARN_ON(!ci->i_auth_cap); BUG_ON(!list_empty(&ci->i_dirty_item)); spin_lock(&mdsc->cap_dirty_lock); - if (ci->i_auth_cap) - list_add(&ci->i_dirty_item, &mdsc->cap_dirty); - else - list_add(&ci->i_dirty_item, - &mdsc->cap_dirty_migrating); + list_add(&ci->i_dirty_item, &mdsc->cap_dirty); spin_unlock(&mdsc->cap_dirty_lock); if (ci->i_flushing_caps == 0) { ihold(inode); @@ -1735,13 +1751,12 @@ ack: /* * Try to flush dirty caps back to the auth mds. */ -static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session, - unsigned *flush_tid) +static int try_flush_caps(struct inode *inode, unsigned *flush_tid) { struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); - int unlock_session = session ? 0 : 1; int flushing = 0; + struct ceph_mds_session *session = NULL; retry: spin_lock(&ci->i_ceph_lock); @@ -1755,13 +1770,14 @@ retry: int want = __ceph_caps_wanted(ci); int delayed; - if (!session) { + if (!session || session != cap->session) { spin_unlock(&ci->i_ceph_lock); + if (session) + mutex_unlock(&session->s_mutex); session = cap->session; mutex_lock(&session->s_mutex); goto retry; } - BUG_ON(session != cap->session); if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) goto out; @@ -1780,7 +1796,7 @@ retry: out: spin_unlock(&ci->i_ceph_lock); out_unlocked: - if (session && unlock_session) + if (session) mutex_unlock(&session->s_mutex); return flushing; } @@ -1865,7 +1881,7 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) return ret; mutex_lock(&inode->i_mutex); - dirty = try_flush_caps(inode, NULL, &flush_tid); + dirty = try_flush_caps(inode, &flush_tid); dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); /* @@ -1900,7 +1916,7 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc) dout("write_inode %p wait=%d\n", inode, wait); if (wait) { - dirty = try_flush_caps(inode, NULL, &flush_tid); + dirty = try_flush_caps(inode, &flush_tid); if (dirty) err = wait_event_interruptible(ci->i_cap_wq, caps_are_flushed(inode, flush_tid)); @@ -2350,11 +2366,11 @@ static void invalidate_aliases(struct inode *inode) d_prune_aliases(inode); /* * For non-directory inode, d_find_alias() only returns - * connected dentry. After calling d_invalidate(), the - * dentry become disconnected. + * hashed dentry. After calling d_invalidate(), the + * dentry becomes unhashed. * * For directory inode, d_find_alias() can return - * disconnected dentry. But directory inode should have + * unhashed dentry. But directory inode should have * one alias at most. */ while ((dn = d_find_alias(inode))) { @@ -2408,6 +2424,22 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, dout(" size %llu max_size %llu, i_size %llu\n", size, max_size, inode->i_size); + + /* + * auth mds of the inode changed. we received the cap export message, + * but still haven't received the cap import message. handle_cap_export + * updated the new auth MDS' cap. + * + * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing a message + * that was sent before the cap import message. So don't remove caps. + */ + if (ceph_seq_cmp(seq, cap->seq) <= 0) { + WARN_ON(cap != ci->i_auth_cap); + WARN_ON(cap->cap_id != le64_to_cpu(grant->cap_id)); + seq = cap->seq; + newcaps |= cap->issued; + } + /* * If CACHE is being revoked, and we have no dirty buffers, * try to invalidate (once). (If there are dirty buffers, we @@ -2434,6 +2466,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, issued |= implemented | __ceph_caps_dirty(ci); cap->cap_gen = session->s_cap_gen; + cap->seq = seq; __check_cap_issue(ci, cap, newcaps); @@ -2464,6 +2497,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, ceph_buffer_put(ci->i_xattrs.blob); ci->i_xattrs.blob = ceph_buffer_get(xattr_buf); ci->i_xattrs.version = version; + ceph_forget_all_cached_acls(inode); } } @@ -2483,6 +2517,10 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, le32_to_cpu(grant->time_warp_seq), &ctime, &mtime, &atime); + + /* file layout may have changed */ + ci->i_layout = grant->layout; + /* max size increase? */ if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { dout("max_size %lld -> %llu\n", ci->i_max_size, max_size); @@ -2511,11 +2549,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, check_caps = 1; } - cap->seq = seq; - - /* file layout may have changed */ - ci->i_layout = grant->layout; - /* revocation, grant, or no-op? */ if (cap->issued & ~newcaps) { int revoking = cap->issued & ~newcaps; @@ -2741,65 +2774,114 @@ static void handle_cap_trunc(struct inode *inode, * caller holds s_mutex */ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, - struct ceph_mds_session *session, - int *open_target_sessions) + struct ceph_mds_cap_peer *ph, + struct ceph_mds_session *session) { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + struct ceph_mds_session *tsession = NULL; + struct ceph_cap *cap, *tcap; struct ceph_inode_info *ci = ceph_inode(inode); - int mds = session->s_mds; + u64 t_cap_id; unsigned mseq = le32_to_cpu(ex->migrate_seq); - struct ceph_cap *cap = NULL, *t; - struct rb_node *p; - int remember = 1; + unsigned t_seq, t_mseq; + int target, issued; + int mds = session->s_mds; - dout("handle_cap_export inode %p ci %p mds%d mseq %d\n", - inode, ci, mds, mseq); + if (ph) { + t_cap_id = le64_to_cpu(ph->cap_id); + t_seq = le32_to_cpu(ph->seq); + t_mseq = le32_to_cpu(ph->mseq); + target = le32_to_cpu(ph->mds); + } else { + t_cap_id = t_seq = t_mseq = 0; + target = -1; + } + dout("handle_cap_export inode %p ci %p mds%d mseq %d target %d\n", + inode, ci, mds, mseq, target); +retry: spin_lock(&ci->i_ceph_lock); + cap = __get_cap_for_mds(ci, mds); + if (!cap) + goto out_unlock; - /* make sure we haven't seen a higher mseq */ - for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { - t = rb_entry(p, struct ceph_cap, ci_node); - if (ceph_seq_cmp(t->mseq, mseq) > 0) { - dout(" higher mseq on cap from mds%d\n", - t->session->s_mds); - remember = 0; - } - if (t->session->s_mds == mds) - cap = t; + if (target < 0) { + __ceph_remove_cap(cap, false); + goto out_unlock; } - if (cap) { - if (remember) { - /* make note */ - ci->i_cap_exporting_mds = mds; - ci->i_cap_exporting_mseq = mseq; - ci->i_cap_exporting_issued = cap->issued; - - /* - * make sure we have open sessions with all possible - * export targets, so that we get the matching IMPORT - */ - *open_target_sessions = 1; + /* + * now we know we haven't received the cap import message yet + * because the exported cap still exist. + */ - /* - * we can't flush dirty caps that we've seen the - * EXPORT but no IMPORT for - */ - spin_lock(&mdsc->cap_dirty_lock); - if (!list_empty(&ci->i_dirty_item)) { - dout(" moving %p to cap_dirty_migrating\n", - inode); - list_move(&ci->i_dirty_item, - &mdsc->cap_dirty_migrating); + issued = cap->issued; + WARN_ON(issued != cap->implemented); + + tcap = __get_cap_for_mds(ci, target); + if (tcap) { + /* already have caps from the target */ + if (tcap->cap_id != t_cap_id || + ceph_seq_cmp(tcap->seq, t_seq) < 0) { + dout(" updating import cap %p mds%d\n", tcap, target); + tcap->cap_id = t_cap_id; + tcap->seq = t_seq - 1; + tcap->issue_seq = t_seq - 1; + tcap->mseq = t_mseq; + tcap->issued |= issued; + tcap->implemented |= issued; + if (cap == ci->i_auth_cap) + ci->i_auth_cap = tcap; + if (ci->i_flushing_caps && ci->i_auth_cap == tcap) { + spin_lock(&mdsc->cap_dirty_lock); + list_move_tail(&ci->i_flushing_item, + &tcap->session->s_cap_flushing); + spin_unlock(&mdsc->cap_dirty_lock); } - spin_unlock(&mdsc->cap_dirty_lock); } __ceph_remove_cap(cap, false); + goto out_unlock; } - /* else, we already released it */ + if (tsession) { + int flag = (cap == ci->i_auth_cap) ? CEPH_CAP_FLAG_AUTH : 0; + spin_unlock(&ci->i_ceph_lock); + /* add placeholder for the export tagert */ + ceph_add_cap(inode, tsession, t_cap_id, -1, issued, 0, + t_seq - 1, t_mseq, (u64)-1, flag, NULL); + goto retry; + } + + spin_unlock(&ci->i_ceph_lock); + mutex_unlock(&session->s_mutex); + + /* open target session */ + tsession = ceph_mdsc_open_export_target_session(mdsc, target); + if (!IS_ERR(tsession)) { + if (mds > target) { + mutex_lock(&session->s_mutex); + mutex_lock_nested(&tsession->s_mutex, + SINGLE_DEPTH_NESTING); + } else { + mutex_lock(&tsession->s_mutex); + mutex_lock_nested(&session->s_mutex, + SINGLE_DEPTH_NESTING); + } + ceph_add_cap_releases(mdsc, tsession); + } else { + WARN_ON(1); + tsession = NULL; + target = -1; + } + goto retry; + +out_unlock: spin_unlock(&ci->i_ceph_lock); + mutex_unlock(&session->s_mutex); + if (tsession) { + mutex_unlock(&tsession->s_mutex); + ceph_put_mds_session(tsession); + } } /* @@ -2810,10 +2892,12 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, */ static void handle_cap_import(struct ceph_mds_client *mdsc, struct inode *inode, struct ceph_mds_caps *im, + struct ceph_mds_cap_peer *ph, struct ceph_mds_session *session, void *snaptrace, int snaptrace_len) { struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_cap *cap; int mds = session->s_mds; unsigned issued = le32_to_cpu(im->caps); unsigned wanted = le32_to_cpu(im->wanted); @@ -2821,28 +2905,44 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, unsigned mseq = le32_to_cpu(im->migrate_seq); u64 realmino = le64_to_cpu(im->realm); u64 cap_id = le64_to_cpu(im->cap_id); + u64 p_cap_id; + int peer; - if (ci->i_cap_exporting_mds >= 0 && - ceph_seq_cmp(ci->i_cap_exporting_mseq, mseq) < 0) { - dout("handle_cap_import inode %p ci %p mds%d mseq %d" - " - cleared exporting from mds%d\n", - inode, ci, mds, mseq, - ci->i_cap_exporting_mds); - ci->i_cap_exporting_issued = 0; - ci->i_cap_exporting_mseq = 0; - ci->i_cap_exporting_mds = -1; + if (ph) { + p_cap_id = le64_to_cpu(ph->cap_id); + peer = le32_to_cpu(ph->mds); + } else { + p_cap_id = 0; + peer = -1; + } - spin_lock(&mdsc->cap_dirty_lock); - if (!list_empty(&ci->i_dirty_item)) { - dout(" moving %p back to cap_dirty\n", inode); - list_move(&ci->i_dirty_item, &mdsc->cap_dirty); + dout("handle_cap_import inode %p ci %p mds%d mseq %d peer %d\n", + inode, ci, mds, mseq, peer); + + spin_lock(&ci->i_ceph_lock); + cap = peer >= 0 ? __get_cap_for_mds(ci, peer) : NULL; + if (cap && cap->cap_id == p_cap_id) { + dout(" remove export cap %p mds%d flags %d\n", + cap, peer, ph->flags); + if ((ph->flags & CEPH_CAP_FLAG_AUTH) && + (cap->seq != le32_to_cpu(ph->seq) || + cap->mseq != le32_to_cpu(ph->mseq))) { + pr_err("handle_cap_import: mismatched seq/mseq: " + "ino (%llx.%llx) mds%d seq %d mseq %d " + "importer mds%d has peer seq %d mseq %d\n", + ceph_vinop(inode), peer, cap->seq, + cap->mseq, mds, le32_to_cpu(ph->seq), + le32_to_cpu(ph->mseq)); } - spin_unlock(&mdsc->cap_dirty_lock); - } else { - dout("handle_cap_import inode %p ci %p mds%d mseq %d\n", - inode, ci, mds, mseq); + ci->i_cap_exporting_issued = cap->issued; + __ceph_remove_cap(cap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); } + /* make sure we re-request max_size, if necessary */ + ci->i_wanted_max_size = 0; + ci->i_requested_max_size = 0; + spin_unlock(&ci->i_ceph_lock); + down_write(&mdsc->snap_rwsem); ceph_update_snap_trace(mdsc, snaptrace, snaptrace+snaptrace_len, false); @@ -2853,11 +2953,6 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, kick_flushing_inode_caps(mdsc, session, inode); up_read(&mdsc->snap_rwsem); - /* make sure we re-request max_size, if necessary */ - spin_lock(&ci->i_ceph_lock); - ci->i_wanted_max_size = 0; /* reset */ - ci->i_requested_max_size = 0; - spin_unlock(&ci->i_ceph_lock); } /* @@ -2875,6 +2970,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, struct ceph_inode_info *ci; struct ceph_cap *cap; struct ceph_mds_caps *h; + struct ceph_mds_cap_peer *peer = NULL; int mds = session->s_mds; int op; u32 seq, mseq; @@ -2885,12 +2981,13 @@ void ceph_handle_caps(struct ceph_mds_session *session, void *snaptrace; size_t snaptrace_len; void *flock; + void *end; u32 flock_len; - int open_target_sessions = 0; dout("handle_caps from mds%d\n", mds); /* decode */ + end = msg->front.iov_base + msg->front.iov_len; tid = le64_to_cpu(msg->hdr.tid); if (msg->front.iov_len < sizeof(*h)) goto bad; @@ -2908,17 +3005,28 @@ void ceph_handle_caps(struct ceph_mds_session *session, snaptrace_len = le32_to_cpu(h->snap_trace_len); if (le16_to_cpu(msg->hdr.version) >= 2) { - void *p, *end; - - p = snaptrace + snaptrace_len; - end = msg->front.iov_base + msg->front.iov_len; + void *p = snaptrace + snaptrace_len; ceph_decode_32_safe(&p, end, flock_len, bad); + if (p + flock_len > end) + goto bad; flock = p; } else { flock = NULL; flock_len = 0; } + if (le16_to_cpu(msg->hdr.version) >= 3) { + if (op == CEPH_CAP_OP_IMPORT) { + void *p = flock + flock_len; + if (p + sizeof(*peer) > end) + goto bad; + peer = p; + } else if (op == CEPH_CAP_OP_EXPORT) { + /* recorded in unused fields */ + peer = (void *)&h->size; + } + } + mutex_lock(&session->s_mutex); session->s_seq++; dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq, @@ -2951,11 +3059,11 @@ void ceph_handle_caps(struct ceph_mds_session *session, goto done; case CEPH_CAP_OP_EXPORT: - handle_cap_export(inode, h, session, &open_target_sessions); - goto done; + handle_cap_export(inode, h, peer, session); + goto done_unlocked; case CEPH_CAP_OP_IMPORT: - handle_cap_import(mdsc, inode, h, session, + handle_cap_import(mdsc, inode, h, peer, session, snaptrace, snaptrace_len); } @@ -3007,8 +3115,6 @@ done: done_unlocked: if (inode) iput(inode); - if (open_target_sessions) - ceph_mdsc_open_export_target_sessions(mdsc, session); return; bad: diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 2a0bcaeb189a..6da4df84ba30 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -693,6 +693,10 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, if (!err && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); ceph_mdsc_put_request(req); + + if (!err) + err = ceph_init_acl(dentry, dentry->d_inode, dir); + if (err) d_drop(dentry); return err; @@ -1037,14 +1041,19 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) valid = 1; } else if (dentry_lease_is_valid(dentry) || dir_lease_is_valid(dir, dentry)) { - valid = 1; + if (dentry->d_inode) + valid = ceph_is_any_caps(dentry->d_inode); + else + valid = 1; } dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid"); - if (valid) + if (valid) { ceph_dentry_lru_touch(dentry); - else + } else { + ceph_dir_clear_complete(dir); d_drop(dentry); + } iput(dir); return valid; } @@ -1293,6 +1302,8 @@ const struct inode_operations ceph_dir_iops = { .getxattr = ceph_getxattr, .listxattr = ceph_listxattr, .removexattr = ceph_removexattr, + .get_acl = ceph_get_acl, + .set_acl = ceph_set_acl, .mknod = ceph_mknod, .symlink = ceph_symlink, .mkdir = ceph_mkdir, diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3de89829e2a1..dfd2ce3419f8 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -408,51 +408,92 @@ more: * * If the read spans object boundary, just do multiple reads. */ -static ssize_t ceph_sync_read(struct file *file, char __user *data, - unsigned len, loff_t *poff, int *checkeof) +static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, + int *checkeof) { + struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct page **pages; - u64 off = *poff; + u64 off = iocb->ki_pos; int num_pages, ret; + size_t len = i->count; - dout("sync_read on file %p %llu~%u %s\n", file, off, len, + dout("sync_read on file %p %llu~%u %s\n", file, off, + (unsigned)len, (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); - - if (file->f_flags & O_DIRECT) { - num_pages = calc_pages_for((unsigned long)data, len); - pages = ceph_get_direct_page_vector(data, num_pages, true); - } else { - num_pages = calc_pages_for(off, len); - pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); - } - if (IS_ERR(pages)) - return PTR_ERR(pages); - /* * flush any page cache pages in this range. this * will make concurrent normal and sync io slow, * but it will at least behave sensibly when they are * in sequence. */ - ret = filemap_write_and_wait(inode->i_mapping); + ret = filemap_write_and_wait_range(inode->i_mapping, off, + off + len); if (ret < 0) - goto done; + return ret; - ret = striped_read(inode, off, len, pages, num_pages, checkeof, - file->f_flags & O_DIRECT, - (unsigned long)data & ~PAGE_MASK); + if (file->f_flags & O_DIRECT) { + while (iov_iter_count(i)) { + void __user *data = i->iov[0].iov_base + i->iov_offset; + size_t len = i->iov[0].iov_len - i->iov_offset; + + num_pages = calc_pages_for((unsigned long)data, len); + pages = ceph_get_direct_page_vector(data, + num_pages, true); + if (IS_ERR(pages)) + return PTR_ERR(pages); + + ret = striped_read(inode, off, len, + pages, num_pages, checkeof, + 1, (unsigned long)data & ~PAGE_MASK); + ceph_put_page_vector(pages, num_pages, true); + + if (ret <= 0) + break; + off += ret; + iov_iter_advance(i, ret); + if (ret < len) + break; + } + } else { + num_pages = calc_pages_for(off, len); + pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); + if (IS_ERR(pages)) + return PTR_ERR(pages); + ret = striped_read(inode, off, len, pages, + num_pages, checkeof, 0, 0); + if (ret > 0) { + int l, k = 0; + size_t left = len = ret; + + while (left) { + void __user *data = i->iov[0].iov_base + + i->iov_offset; + l = min(i->iov[0].iov_len - i->iov_offset, + left); + + ret = ceph_copy_page_vector_to_user(&pages[k], + data, off, + l); + if (ret > 0) { + iov_iter_advance(i, ret); + left -= ret; + off += ret; + k = calc_pages_for(iocb->ki_pos, + len - left + 1) - 1; + BUG_ON(k >= num_pages && left); + } else + break; + } + } + ceph_release_page_vector(pages, num_pages); + } - if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) - ret = ceph_copy_page_vector_to_user(pages, data, off, ret); - if (ret >= 0) - *poff = off + ret; + if (off > iocb->ki_pos) { + ret = off - iocb->ki_pos; + iocb->ki_pos = off; + } -done: - if (file->f_flags & O_DIRECT) - ceph_put_page_vector(pages, num_pages, true); - else - ceph_release_page_vector(pages, num_pages); dout("sync_read result %d\n", ret); return ret; } @@ -489,83 +530,79 @@ static void ceph_sync_write_unsafe(struct ceph_osd_request *req, bool unsafe) } } + /* - * Synchronous write, straight from __user pointer or user pages (if - * O_DIRECT). + * Synchronous write, straight from __user pointer or user pages. * * If write spans object boundary, just do multiple writes. (For a * correct atomic write, we should e.g. take write locks on all * objects, rollback on failure, etc.) */ -static ssize_t ceph_sync_write(struct file *file, const char __user *data, - size_t left, loff_t pos, loff_t *ppos) +static ssize_t +ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, size_t count) { + struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_snap_context *snapc; struct ceph_vino vino; struct ceph_osd_request *req; - int num_ops = 1; struct page **pages; int num_pages; - u64 len; int written = 0; int flags; int check_caps = 0; - int page_align, io_align; - unsigned long buf_align; + int page_align; int ret; struct timespec mtime = CURRENT_TIME; - bool own_pages = false; + loff_t pos = iocb->ki_pos; + struct iov_iter i; if (ceph_snap(file_inode(file)) != CEPH_NOSNAP) return -EROFS; - dout("sync_write on file %p %lld~%u %s\n", file, pos, - (unsigned)left, (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); + dout("sync_direct_write on file %p %lld~%u\n", file, pos, + (unsigned)count); - ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); + ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + count); if (ret < 0) return ret; ret = invalidate_inode_pages2_range(inode->i_mapping, pos >> PAGE_CACHE_SHIFT, - (pos + left) >> PAGE_CACHE_SHIFT); + (pos + count) >> PAGE_CACHE_SHIFT); if (ret < 0) dout("invalidate_inode_pages2_range returned %d\n", ret); flags = CEPH_OSD_FLAG_ORDERSNAP | CEPH_OSD_FLAG_ONDISK | CEPH_OSD_FLAG_WRITE; - if ((file->f_flags & (O_SYNC|O_DIRECT)) == 0) - flags |= CEPH_OSD_FLAG_ACK; - else - num_ops++; /* Also include a 'startsync' command. */ - /* - * we may need to do multiple writes here if we span an object - * boundary. this isn't atomic, unfortunately. :( - */ -more: - io_align = pos & ~PAGE_MASK; - buf_align = (unsigned long)data & ~PAGE_MASK; - len = left; - - snapc = ci->i_snap_realm->cached_context; - vino = ceph_vino(inode); - req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, - vino, pos, &len, num_ops, - CEPH_OSD_OP_WRITE, flags, snapc, - ci->i_truncate_seq, ci->i_truncate_size, - false); - if (IS_ERR(req)) - return PTR_ERR(req); + iov_iter_init(&i, iov, nr_segs, count, 0); + + while (iov_iter_count(&i) > 0) { + void __user *data = i.iov->iov_base + i.iov_offset; + u64 len = i.iov->iov_len - i.iov_offset; + + page_align = (unsigned long)data & ~PAGE_MASK; + + snapc = ci->i_snap_realm->cached_context; + vino = ceph_vino(inode); + req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, + vino, pos, &len, + 2,/*include a 'startsync' command*/ + CEPH_OSD_OP_WRITE, flags, snapc, + ci->i_truncate_seq, + ci->i_truncate_size, + false); + if (IS_ERR(req)) { + ret = PTR_ERR(req); + goto out; + } - /* write from beginning of first page, regardless of io alignment */ - page_align = file->f_flags & O_DIRECT ? buf_align : io_align; - num_pages = calc_pages_for(page_align, len); - if (file->f_flags & O_DIRECT) { + num_pages = calc_pages_for(page_align, len); pages = ceph_get_direct_page_vector(data, num_pages, false); if (IS_ERR(pages)) { ret = PTR_ERR(pages); @@ -577,60 +614,175 @@ more: * may block. */ truncate_inode_pages_range(inode->i_mapping, pos, - (pos+len) | (PAGE_CACHE_SIZE-1)); - } else { + (pos+len) | (PAGE_CACHE_SIZE-1)); + osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align, + false, false); + + /* BUG_ON(vino.snap != CEPH_NOSNAP); */ + ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime); + + ret = ceph_osdc_start_request(&fsc->client->osdc, req, false); + if (!ret) + ret = ceph_osdc_wait_request(&fsc->client->osdc, req); + + ceph_put_page_vector(pages, num_pages, false); + +out: + ceph_osdc_put_request(req); + if (ret == 0) { + pos += len; + written += len; + iov_iter_advance(&i, (size_t)len); + + if (pos > i_size_read(inode)) { + check_caps = ceph_inode_set_size(inode, pos); + if (check_caps) + ceph_check_caps(ceph_inode(inode), + CHECK_CAPS_AUTHONLY, + NULL); + } + } else + break; + } + + if (ret != -EOLDSNAPC && written > 0) { + iocb->ki_pos = pos; + ret = written; + } + return ret; +} + + +/* + * Synchronous write, straight from __user pointer or user pages. + * + * If write spans object boundary, just do multiple writes. (For a + * correct atomic write, we should e.g. take write locks on all + * objects, rollback on failure, etc.) + */ +static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, size_t count) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_fs_client *fsc = ceph_inode_to_client(inode); + struct ceph_snap_context *snapc; + struct ceph_vino vino; + struct ceph_osd_request *req; + struct page **pages; + u64 len; + int num_pages; + int written = 0; + int flags; + int check_caps = 0; + int ret; + struct timespec mtime = CURRENT_TIME; + loff_t pos = iocb->ki_pos; + struct iov_iter i; + + if (ceph_snap(file_inode(file)) != CEPH_NOSNAP) + return -EROFS; + + dout("sync_write on file %p %lld~%u\n", file, pos, (unsigned)count); + + ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + count); + if (ret < 0) + return ret; + + ret = invalidate_inode_pages2_range(inode->i_mapping, + pos >> PAGE_CACHE_SHIFT, + (pos + count) >> PAGE_CACHE_SHIFT); + if (ret < 0) + dout("invalidate_inode_pages2_range returned %d\n", ret); + + flags = CEPH_OSD_FLAG_ORDERSNAP | + CEPH_OSD_FLAG_ONDISK | + CEPH_OSD_FLAG_WRITE | + CEPH_OSD_FLAG_ACK; + + iov_iter_init(&i, iov, nr_segs, count, 0); + + while ((len = iov_iter_count(&i)) > 0) { + size_t left; + int n; + + snapc = ci->i_snap_realm->cached_context; + vino = ceph_vino(inode); + req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, + vino, pos, &len, 1, + CEPH_OSD_OP_WRITE, flags, snapc, + ci->i_truncate_seq, + ci->i_truncate_size, + false); + if (IS_ERR(req)) { + ret = PTR_ERR(req); + goto out; + } + + /* + * write from beginning of first page, + * regardless of io alignment + */ + num_pages = (len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); if (IS_ERR(pages)) { ret = PTR_ERR(pages); goto out; } - ret = ceph_copy_user_to_page_vector(pages, data, pos, len); + + left = len; + for (n = 0; n < num_pages; n++) { + size_t plen = min_t(size_t, left, PAGE_SIZE); + ret = iov_iter_copy_from_user(pages[n], &i, 0, plen); + if (ret != plen) { + ret = -EFAULT; + break; + } + left -= ret; + iov_iter_advance(&i, ret); + } + if (ret < 0) { ceph_release_page_vector(pages, num_pages); goto out; } - if ((file->f_flags & O_SYNC) == 0) { - /* get a second commit callback */ - req->r_unsafe_callback = ceph_sync_write_unsafe; - req->r_inode = inode; - own_pages = true; - } - } - osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align, - false, own_pages); + /* get a second commit callback */ + req->r_unsafe_callback = ceph_sync_write_unsafe; + req->r_inode = inode; - /* BUG_ON(vino.snap != CEPH_NOSNAP); */ - ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime); + osd_req_op_extent_osd_data_pages(req, 0, pages, len, 0, + false, true); - ret = ceph_osdc_start_request(&fsc->client->osdc, req, false); - if (!ret) - ret = ceph_osdc_wait_request(&fsc->client->osdc, req); + /* BUG_ON(vino.snap != CEPH_NOSNAP); */ + ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime); - if (file->f_flags & O_DIRECT) - ceph_put_page_vector(pages, num_pages, false); - else if (file->f_flags & O_SYNC) - ceph_release_page_vector(pages, num_pages); + ret = ceph_osdc_start_request(&fsc->client->osdc, req, false); + if (!ret) + ret = ceph_osdc_wait_request(&fsc->client->osdc, req); out: - ceph_osdc_put_request(req); - if (ret == 0) { - pos += len; - written += len; - left -= len; - data += len; - if (left) - goto more; + ceph_osdc_put_request(req); + if (ret == 0) { + pos += len; + written += len; + + if (pos > i_size_read(inode)) { + check_caps = ceph_inode_set_size(inode, pos); + if (check_caps) + ceph_check_caps(ceph_inode(inode), + CHECK_CAPS_AUTHONLY, + NULL); + } + } else + break; + } + if (ret != -EOLDSNAPC && written > 0) { ret = written; - *ppos = pos; - if (pos > i_size_read(inode)) - check_caps = ceph_inode_set_size(inode, pos); - if (check_caps) - ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, - NULL); - } else if (ret != -EOLDSNAPC && written > 0) { - ret = written; + iocb->ki_pos = pos; } return ret; } @@ -647,55 +799,84 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, { struct file *filp = iocb->ki_filp; struct ceph_file_info *fi = filp->private_data; - loff_t *ppos = &iocb->ki_pos; - size_t len = iov->iov_len; + size_t len = iocb->ki_nbytes; struct inode *inode = file_inode(filp); struct ceph_inode_info *ci = ceph_inode(inode); - void __user *base = iov->iov_base; ssize_t ret; int want, got = 0; int checkeof = 0, read = 0; - dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n", - inode, ceph_vinop(inode), pos, (unsigned)len, inode); again: + dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n", + inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, inode); + if (fi->fmode & CEPH_FILE_MODE_LAZY) want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; else want = CEPH_CAP_FILE_CACHE; ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1); if (ret < 0) - goto out; - dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", - inode, ceph_vinop(inode), pos, (unsigned)len, - ceph_cap_string(got)); + return ret; if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || (iocb->ki_filp->f_flags & O_DIRECT) || - (fi->flags & CEPH_F_SYNC)) + (fi->flags & CEPH_F_SYNC)) { + struct iov_iter i; + + dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n", + inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, + ceph_cap_string(got)); + + if (!read) { + ret = generic_segment_checks(iov, &nr_segs, + &len, VERIFY_WRITE); + if (ret) + goto out; + } + + iov_iter_init(&i, iov, nr_segs, len, read); + /* hmm, this isn't really async... */ - ret = ceph_sync_read(filp, base, len, ppos, &checkeof); - else - ret = generic_file_aio_read(iocb, iov, nr_segs, pos); + ret = ceph_sync_read(iocb, &i, &checkeof); + } else { + /* + * We can't modify the content of iov, + * so we only read from beginning. + */ + if (read) { + iocb->ki_pos = pos; + len = iocb->ki_nbytes; + read = 0; + } + dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", + inode, ceph_vinop(inode), pos, (unsigned)len, + ceph_cap_string(got)); + ret = generic_file_aio_read(iocb, iov, nr_segs, pos); + } out: dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n", inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); ceph_put_cap_refs(ci, got); if (checkeof && ret >= 0) { - int statret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); + int statret = ceph_do_getattr(inode, + CEPH_STAT_CAP_SIZE); /* hit EOF or hole? */ - if (statret == 0 && *ppos < inode->i_size) { - dout("aio_read sync_read hit hole, ppos %lld < size %lld, reading more\n", *ppos, inode->i_size); + if (statret == 0 && iocb->ki_pos < inode->i_size && + ret < len) { + dout("sync_read hit hole, ppos %lld < size %lld" + ", reading more\n", iocb->ki_pos, + inode->i_size); + read += ret; - base += ret; len -= ret; checkeof = 0; goto again; } } + if (ret >= 0) ret += read; @@ -772,11 +953,13 @@ retry_snap: inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || - (iocb->ki_filp->f_flags & O_DIRECT) || - (fi->flags & CEPH_F_SYNC)) { + (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) { mutex_unlock(&inode->i_mutex); - written = ceph_sync_write(file, iov->iov_base, count, - pos, &iocb->ki_pos); + if (file->f_flags & O_DIRECT) + written = ceph_sync_direct_write(iocb, iov, + nr_segs, count); + else + written = ceph_sync_write(iocb, iov, nr_segs, count); if (written == -EOLDSNAPC) { dout("aio_write %p %llx.%llx %llu~%u" "got EOLDSNAPC, retrying\n", @@ -1018,7 +1201,7 @@ static long ceph_fallocate(struct file *file, int mode, loff_t offset, loff_t length) { struct ceph_file_info *fi = file->private_data; - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file_inode(file); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->client->osdc; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 278fd2891288..32d519d8a2e2 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -9,6 +9,7 @@ #include <linux/namei.h> #include <linux/writeback.h> #include <linux/vmalloc.h> +#include <linux/posix_acl.h> #include "super.h" #include "mds_client.h" @@ -95,6 +96,8 @@ const struct inode_operations ceph_file_iops = { .getxattr = ceph_getxattr, .listxattr = ceph_listxattr, .removexattr = ceph_removexattr, + .get_acl = ceph_get_acl, + .set_acl = ceph_set_acl, }; @@ -335,12 +338,10 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ci->i_hold_caps_min = 0; ci->i_hold_caps_max = 0; INIT_LIST_HEAD(&ci->i_cap_delay_list); - ci->i_cap_exporting_mds = 0; - ci->i_cap_exporting_mseq = 0; - ci->i_cap_exporting_issued = 0; INIT_LIST_HEAD(&ci->i_cap_snaps); ci->i_head_snapc = NULL; ci->i_snap_caps = 0; + ci->i_cap_exporting_issued = 0; for (i = 0; i < CEPH_FILE_MODE_NUM; i++) ci->i_nr_by_mode[i] = 0; @@ -436,6 +437,16 @@ void ceph_destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, ceph_i_callback); } +int ceph_drop_inode(struct inode *inode) +{ + /* + * Positve dentry and corresponding inode are always accompanied + * in MDS reply. So no need to keep inode in the cache after + * dropping all its aliases. + */ + return 1; +} + /* * Helpers to fill in size, ctime, mtime, and atime. We have to be * careful because either the client or MDS may have more up to date @@ -670,6 +681,7 @@ static int fill_inode(struct inode *inode, memcpy(ci->i_xattrs.blob->vec.iov_base, iinfo->xattr_data, iinfo->xattr_len); ci->i_xattrs.version = le64_to_cpu(info->xattr_version); + ceph_forget_all_cached_acls(inode); xattr_blob = NULL; } @@ -1454,7 +1466,8 @@ static void ceph_invalidate_work(struct work_struct *work) dout("invalidate_pages %p gen %d revoking %d\n", inode, ci->i_rdcache_gen, ci->i_rdcache_revoking); if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { - /* nevermind! */ + if (__ceph_caps_revoking_other(ci, NULL, CEPH_CAP_FILE_CACHE)) + check = 1; spin_unlock(&ci->i_ceph_lock); mutex_unlock(&ci->i_truncate_mutex); goto out; @@ -1475,13 +1488,14 @@ static void ceph_invalidate_work(struct work_struct *work) dout("invalidate_pages %p gen %d raced, now %d revoking %d\n", inode, orig_gen, ci->i_rdcache_gen, ci->i_rdcache_revoking); + if (__ceph_caps_revoking_other(ci, NULL, CEPH_CAP_FILE_CACHE)) + check = 1; } spin_unlock(&ci->i_ceph_lock); mutex_unlock(&ci->i_truncate_mutex); - +out: if (check) ceph_check_caps(ci, 0, NULL); -out: iput(inode); } @@ -1602,6 +1616,8 @@ static const struct inode_operations ceph_symlink_iops = { .getxattr = ceph_getxattr, .listxattr = ceph_listxattr, .removexattr = ceph_removexattr, + .get_acl = ceph_get_acl, + .set_acl = ceph_set_acl, }; /* @@ -1675,6 +1691,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) dirtied |= CEPH_CAP_AUTH_EXCL; } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || attr->ia_mode != inode->i_mode) { + inode->i_mode = attr->ia_mode; req->r_args.setattr.mode = cpu_to_le32(attr->ia_mode); mask |= CEPH_SETATTR_MODE; release |= CEPH_CAP_AUTH_SHARED; @@ -1790,6 +1807,12 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) if (inode_dirty_flags) __mark_inode_dirty(inode, inode_dirty_flags); + if (ia_valid & ATTR_MODE) { + err = posix_acl_chmod(inode, attr->ia_mode); + if (err) + goto out_put; + } + if (mask) { req->r_inode = inode; ihold(inode); @@ -1809,6 +1832,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) return err; out: spin_unlock(&ci->i_ceph_lock); +out_put: ceph_mdsc_put_request(req); return err; } diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c index 669622fd1ae3..dc66c9e023e4 100644 --- a/fs/ceph/ioctl.c +++ b/fs/ceph/ioctl.c @@ -183,6 +183,8 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; + struct ceph_object_locator oloc; + struct ceph_object_id oid; u64 len = 1, olen; u64 tmp; struct ceph_pg pgid; @@ -211,8 +213,10 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx", ceph_ino(inode), dl.object_no); - r = ceph_calc_ceph_pg(&pgid, dl.object_name, osdc->osdmap, - ceph_file_layout_pg_pool(ci->i_layout)); + oloc.pool = ceph_file_layout_pg_pool(ci->i_layout); + ceph_oid_set_name(&oid, dl.object_name); + + r = ceph_oloc_oid_to_pg(osdc->osdmap, &oloc, &oid, &pgid); if (r < 0) { up_read(&osdc->map_sem); return r; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d90861f45210..f4f050a69a48 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -63,7 +63,7 @@ static const struct ceph_connection_operations mds_con_ops; */ static int parse_reply_info_in(void **p, void *end, struct ceph_mds_reply_info_in *info, - int features) + u64 features) { int err = -EIO; @@ -98,7 +98,7 @@ bad: */ static int parse_reply_info_trace(void **p, void *end, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { int err; @@ -145,7 +145,7 @@ out_bad: */ static int parse_reply_info_dir(void **p, void *end, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { u32 num, i = 0; int err; @@ -217,7 +217,7 @@ out_bad: */ static int parse_reply_info_filelock(void **p, void *end, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { if (*p + sizeof(*info->filelock_reply) > end) goto bad; @@ -238,7 +238,7 @@ bad: */ static int parse_reply_info_create(void **p, void *end, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { if (features & CEPH_FEATURE_REPLY_CREATE_INODE) { if (*p == end) { @@ -262,7 +262,7 @@ bad: */ static int parse_reply_info_extra(void **p, void *end, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { if (info->head->op == CEPH_MDS_OP_GETFILELOCK) return parse_reply_info_filelock(p, end, info, features); @@ -280,7 +280,7 @@ static int parse_reply_info_extra(void **p, void *end, */ static int parse_reply_info(struct ceph_msg *msg, struct ceph_mds_reply_info_parsed *info, - int features) + u64 features) { void *p, *end; u32 len; @@ -713,14 +713,15 @@ static int __choose_mds(struct ceph_mds_client *mdsc, struct dentry *dn = get_nonsnap_parent(parent); inode = dn->d_inode; dout("__choose_mds using nonsnap parent %p\n", inode); - } else if (req->r_dentry->d_inode) { + } else { /* dentry target */ inode = req->r_dentry->d_inode; - } else { - /* dir + name */ - inode = dir; - hash = ceph_dentry_hash(dir, req->r_dentry); - is_hash = true; + if (!inode || mode == USE_AUTH_MDS) { + /* dir + name */ + inode = dir; + hash = ceph_dentry_hash(dir, req->r_dentry); + is_hash = true; + } } } @@ -846,35 +847,56 @@ static int __open_session(struct ceph_mds_client *mdsc, * * called under mdsc->mutex */ +static struct ceph_mds_session * +__open_export_target_session(struct ceph_mds_client *mdsc, int target) +{ + struct ceph_mds_session *session; + + session = __ceph_lookup_mds_session(mdsc, target); + if (!session) { + session = register_session(mdsc, target); + if (IS_ERR(session)) + return session; + } + if (session->s_state == CEPH_MDS_SESSION_NEW || + session->s_state == CEPH_MDS_SESSION_CLOSING) + __open_session(mdsc, session); + + return session; +} + +struct ceph_mds_session * +ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target) +{ + struct ceph_mds_session *session; + + dout("open_export_target_session to mds%d\n", target); + + mutex_lock(&mdsc->mutex); + session = __open_export_target_session(mdsc, target); + mutex_unlock(&mdsc->mutex); + + return session; +} + static void __open_export_target_sessions(struct ceph_mds_client *mdsc, struct ceph_mds_session *session) { struct ceph_mds_info *mi; struct ceph_mds_session *ts; int i, mds = session->s_mds; - int target; if (mds >= mdsc->mdsmap->m_max_mds) return; + mi = &mdsc->mdsmap->m_info[mds]; dout("open_export_target_sessions for mds%d (%d targets)\n", session->s_mds, mi->num_export_targets); for (i = 0; i < mi->num_export_targets; i++) { - target = mi->export_targets[i]; - ts = __ceph_lookup_mds_session(mdsc, target); - if (!ts) { - ts = register_session(mdsc, target); - if (IS_ERR(ts)) - return; - } - if (session->s_state == CEPH_MDS_SESSION_NEW || - session->s_state == CEPH_MDS_SESSION_CLOSING) - __open_session(mdsc, session); - else - dout(" mds%d target mds%d %p is %s\n", session->s_mds, - i, ts, session_state_name(ts->s_state)); - ceph_put_mds_session(ts); + ts = __open_export_target_session(mdsc, mi->export_targets[i]); + if (!IS_ERR(ts)) + ceph_put_mds_session(ts); } } @@ -1136,6 +1158,21 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, return 0; } +static int send_flushmsg_ack(struct ceph_mds_client *mdsc, + struct ceph_mds_session *session, u64 seq) +{ + struct ceph_msg *msg; + + dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n", + session->s_mds, session_state_name(session->s_state), seq); + msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq); + if (!msg) + return -ENOMEM; + ceph_con_send(&session->s_con, msg); + return 0; +} + + /* * Note new cap ttl, and any transition from stale -> not stale (fresh?). * @@ -1214,7 +1251,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) { struct ceph_mds_session *session = arg; struct ceph_inode_info *ci = ceph_inode(inode); - int used, oissued, mine; + int used, wanted, oissued, mine; if (session->s_trim_caps <= 0) return -1; @@ -1222,14 +1259,19 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) spin_lock(&ci->i_ceph_lock); mine = cap->issued | cap->implemented; used = __ceph_caps_used(ci); + wanted = __ceph_caps_file_wanted(ci); oissued = __ceph_caps_issued_other(ci, cap); - dout("trim_caps_cb %p cap %p mine %s oissued %s used %s\n", + dout("trim_caps_cb %p cap %p mine %s oissued %s used %s wanted %s\n", inode, cap, ceph_cap_string(mine), ceph_cap_string(oissued), - ceph_cap_string(used)); - if (ci->i_dirty_caps) - goto out; /* dirty caps */ - if ((used & ~oissued) & mine) + ceph_cap_string(used), ceph_cap_string(wanted)); + if (cap == ci->i_auth_cap) { + if (ci->i_dirty_caps | ci->i_flushing_caps) + goto out; + if ((used | wanted) & CEPH_CAP_ANY_WR) + goto out; + } + if ((used | wanted) & ~oissued & mine) goto out; /* we need these caps */ session->s_trim_caps--; @@ -2156,26 +2198,16 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) */ if (result == -ESTALE) { dout("got ESTALE on request %llu", req->r_tid); - if (!req->r_inode) { - /* do nothing; not an authority problem */ - } else if (req->r_direct_mode != USE_AUTH_MDS) { + if (req->r_direct_mode != USE_AUTH_MDS) { dout("not using auth, setting for that now"); req->r_direct_mode = USE_AUTH_MDS; __do_request(mdsc, req); mutex_unlock(&mdsc->mutex); goto out; } else { - struct ceph_inode_info *ci = ceph_inode(req->r_inode); - struct ceph_cap *cap = NULL; - - if (req->r_session) - cap = ceph_get_cap_for_mds(ci, - req->r_session->s_mds); - - dout("already using auth"); - if ((!cap || cap != ci->i_auth_cap) || - (cap->mseq != req->r_sent_on_mseq)) { - dout("but cap changed, so resending"); + int mds = __choose_mds(mdsc, req); + if (mds >= 0 && mds != req->r_session->s_mds) { + dout("but auth changed, so resending"); __do_request(mdsc, req); mutex_unlock(&mdsc->mutex); goto out; @@ -2400,6 +2432,10 @@ static void handle_session(struct ceph_mds_session *session, trim_caps(mdsc, session, le32_to_cpu(h->max_caps)); break; + case CEPH_SESSION_FLUSHMSG: + send_flushmsg_ack(mdsc, session, seq); + break; + default: pr_err("mdsc_handle_session bad op %d mds%d\n", op, mds); WARN_ON(1); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 4c053d099ae4..68288917c737 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -383,6 +383,8 @@ extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session, extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg); +extern struct ceph_mds_session * +ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target); extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc, struct ceph_mds_session *session); diff --git a/fs/ceph/strings.c b/fs/ceph/strings.c index 89fa4a940a0f..4440f447fd3f 100644 --- a/fs/ceph/strings.c +++ b/fs/ceph/strings.c @@ -41,6 +41,8 @@ const char *ceph_session_op_name(int op) case CEPH_SESSION_RENEWCAPS: return "renewcaps"; case CEPH_SESSION_STALE: return "stale"; case CEPH_SESSION_RECALL_STATE: return "recall_state"; + case CEPH_SESSION_FLUSHMSG: return "flushmsg"; + case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack"; } return "???"; } diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 6a0951e43044..2df963f1cf5a 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -490,10 +490,10 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, struct ceph_options *opt) { struct ceph_fs_client *fsc; - const unsigned supported_features = + const u64 supported_features = CEPH_FEATURE_FLOCK | CEPH_FEATURE_DIRLAYOUTHASH; - const unsigned required_features = 0; + const u64 required_features = 0; int page_count; size_t size; int err = -ENOMEM; @@ -686,6 +686,7 @@ static const struct super_operations ceph_super_ops = { .alloc_inode = ceph_alloc_inode, .destroy_inode = ceph_destroy_inode, .write_inode = ceph_write_inode, + .drop_inode = ceph_drop_inode, .sync_fs = ceph_sync_fs, .put_super = ceph_put_super, .show_options = ceph_show_options, @@ -818,7 +819,11 @@ static int ceph_set_super(struct super_block *s, void *data) s->s_flags = fsc->mount_options->sb_flags; s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ +#ifdef CONFIG_CEPH_FS_POSIX_ACL + s->s_flags |= MS_POSIXACL; +#endif + s->s_xattr = ceph_xattr_handlers; s->s_fs_info = fsc; fsc->sb = s; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index ef4ac38bb614..aa260590f615 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -287,14 +287,12 @@ struct ceph_inode_info { unsigned long i_hold_caps_min; /* jiffies */ unsigned long i_hold_caps_max; /* jiffies */ struct list_head i_cap_delay_list; /* for delayed cap release to mds */ - int i_cap_exporting_mds; /* to handle cap migration between */ - unsigned i_cap_exporting_mseq; /* mds's. */ - unsigned i_cap_exporting_issued; struct ceph_cap_reservation i_cap_migration_resv; struct list_head i_cap_snaps; /* snapped state pending flush to mds */ struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 or dirty|flushing caps */ unsigned i_snap_caps; /* cap bits for snapped files */ + unsigned i_cap_exporting_issued; int i_nr_by_mode[CEPH_FILE_MODE_NUM]; /* open file counts */ @@ -335,7 +333,6 @@ struct ceph_inode_info { u32 i_fscache_gen; /* sequence, for delayed fscache validate */ struct work_struct i_revalidate_work; #endif - struct inode vfs_inode; /* at end */ }; @@ -529,6 +526,8 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) } extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); +extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci, + struct ceph_cap *ocap, int mask); extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); extern int __ceph_caps_used(struct ceph_inode_info *ci); @@ -691,6 +690,7 @@ extern const struct inode_operations ceph_file_iops; extern struct inode *ceph_alloc_inode(struct super_block *sb); extern void ceph_destroy_inode(struct inode *inode); +extern int ceph_drop_inode(struct inode *inode); extern struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino); @@ -718,12 +718,16 @@ extern void ceph_queue_writeback(struct inode *inode); extern int ceph_do_getattr(struct inode *inode, int mask); extern int ceph_permission(struct inode *inode, int mask); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); +extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); /* xattr.c */ extern int ceph_setxattr(struct dentry *, const char *, const void *, size_t, int); +int __ceph_setxattr(struct dentry *, const char *, const void *, size_t, int); +ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t); +int __ceph_removexattr(struct dentry *, const char *); extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t ceph_listxattr(struct dentry *, char *, size_t); extern int ceph_removexattr(struct dentry *, const char *); @@ -732,6 +736,38 @@ extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci); extern void __init ceph_xattr_init(void); extern void ceph_xattr_exit(void); +/* acl.c */ +extern const struct xattr_handler *ceph_xattr_handlers[]; + +#ifdef CONFIG_CEPH_FS_POSIX_ACL + +struct posix_acl *ceph_get_acl(struct inode *, int); +int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type); +int ceph_init_acl(struct dentry *, struct inode *, struct inode *); +void ceph_forget_all_cached_acls(struct inode *inode); + +#else + +#define ceph_get_acl NULL +#define ceph_set_acl NULL + +static inline int ceph_init_acl(struct dentry *dentry, struct inode *inode, + struct inode *dir) +{ + return 0; +} + +static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode) +{ + return 0; +} + +static inline void ceph_forget_all_cached_acls(struct inode *inode) +{ +} + +#endif + /* caps.c */ extern const char *ceph_cap_string(int c); extern void ceph_handle_caps(struct ceph_mds_session *session, @@ -744,6 +780,7 @@ extern int ceph_add_cap(struct inode *inode, extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); extern void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap); +extern int ceph_is_any_caps(struct inode *inode); extern void __queue_cap_release(struct ceph_mds_session *session, u64 ino, u64 cap_id, u32 migrate_seq, u32 issue_seq); diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index be661d8f532a..898b6565ad3e 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -6,16 +6,30 @@ #include <linux/ceph/decode.h> #include <linux/xattr.h> +#include <linux/posix_acl_xattr.h> #include <linux/slab.h> #define XATTR_CEPH_PREFIX "ceph." #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) +/* + * List of handlers for synthetic system.* attributes. Other + * attributes are handled directly. + */ +const struct xattr_handler *ceph_xattr_handlers[] = { +#ifdef CONFIG_CEPH_FS_POSIX_ACL + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, +#endif + NULL, +}; + static bool ceph_is_valid_xattr(const char *name) { return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || + !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) || !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } @@ -663,10 +677,9 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) } } -ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, +ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, size_t size) { - struct inode *inode = dentry->d_inode; struct ceph_inode_info *ci = ceph_inode(inode); int err; struct ceph_inode_xattr *xattr; @@ -675,7 +688,6 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, if (!ceph_is_valid_xattr(name)) return -ENODATA; - /* let's see if a virtual xattr was requested */ vxattr = ceph_match_vxattr(inode, name); if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) { @@ -725,6 +737,15 @@ out: return err; } +ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, + size_t size) +{ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_getxattr(dentry, name, value, size); + + return __ceph_getxattr(dentry->d_inode, name, value, size); +} + ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) { struct inode *inode = dentry->d_inode; @@ -863,8 +884,8 @@ out: return err; } -int ceph_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +int __ceph_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; struct ceph_vxattr *vxattr; @@ -879,9 +900,6 @@ int ceph_setxattr(struct dentry *dentry, const char *name, struct ceph_inode_xattr *xattr = NULL; int required_blob_size; - if (ceph_snap(inode) != CEPH_NOSNAP) - return -EROFS; - if (!ceph_is_valid_xattr(name)) return -EOPNOTSUPP; @@ -958,6 +976,18 @@ out: return err; } +int ceph_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + return -EROFS; + + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_setxattr(dentry, name, value, size, flags); + + return __ceph_setxattr(dentry, name, value, size, flags); +} + static int ceph_send_removexattr(struct dentry *dentry, const char *name) { struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); @@ -984,7 +1014,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name) return err; } -int ceph_removexattr(struct dentry *dentry, const char *name) +int __ceph_removexattr(struct dentry *dentry, const char *name) { struct inode *inode = dentry->d_inode; struct ceph_vxattr *vxattr; @@ -994,9 +1024,6 @@ int ceph_removexattr(struct dentry *dentry, const char *name) int required_blob_size; int dirty; - if (ceph_snap(inode) != CEPH_NOSNAP) - return -EROFS; - if (!ceph_is_valid_xattr(name)) return -EOPNOTSUPP; @@ -1053,3 +1080,13 @@ out: return err; } +int ceph_removexattr(struct dentry *dentry, const char *name) +{ + if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + return -EROFS; + + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_removexattr(dentry, name); + + return __ceph_removexattr(dentry, name); +} diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index e501ac3a49ff..06610cf94d57 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -17,14 +17,30 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/blkdev.h> -#include <linux/cramfs_fs.h> #include <linux/slab.h> -#include <linux/cramfs_fs_sb.h> #include <linux/vfs.h> #include <linux/mutex.h> - +#include <uapi/linux/cramfs_fs.h> #include <asm/uaccess.h> +#include "internal.h" + +/* + * cramfs super-block data in memory + */ +struct cramfs_sb_info { + unsigned long magic; + unsigned long size; + unsigned long blocks; + unsigned long files; + unsigned long flags; +}; + +static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + static const struct super_operations cramfs_ops; static const struct inode_operations cramfs_dir_inode_operations; static const struct file_operations cramfs_directory_operations; @@ -219,10 +235,11 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i return read_buffers[buffer] + offset; } -static void cramfs_put_super(struct super_block *sb) +static void cramfs_kill_sb(struct super_block *sb) { - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + kill_block_super(sb); + kfree(sbi); } static int cramfs_remount(struct super_block *sb, int *flags, char *data) @@ -261,7 +278,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) if (super.magic == CRAMFS_MAGIC_WEND) { if (!silent) printk(KERN_ERR "cramfs: wrong endianness\n"); - goto out; + return -EINVAL; } /* check at 512 byte offset */ @@ -273,20 +290,20 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) printk(KERN_ERR "cramfs: wrong endianness\n"); else if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); - goto out; + return -EINVAL; } } /* get feature flags first */ if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { printk(KERN_ERR "cramfs: unsupported filesystem features\n"); - goto out; + return -EINVAL; } /* Check that the root inode is in a sane state */ if (!S_ISDIR(super.root.mode)) { printk(KERN_ERR "cramfs: root is not a directory\n"); - goto out; + return -EINVAL; } /* correct strange, hard-coded permissions of mkcramfs */ super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); @@ -310,22 +327,18 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) (root_offset != 512 + sizeof(struct cramfs_super)))) { printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset); - goto out; + return -EINVAL; } /* Set it all up.. */ sb->s_op = &cramfs_ops; root = get_cramfs_inode(sb, &super.root, 0); if (IS_ERR(root)) - goto out; + return PTR_ERR(root); sb->s_root = d_make_root(root); if (!sb->s_root) - goto out; + return -ENOMEM; return 0; -out: - kfree(sbi); - sb->s_fs_info = NULL; - return -EINVAL; } static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -550,7 +563,6 @@ static const struct inode_operations cramfs_dir_inode_operations = { }; static const struct super_operations cramfs_ops = { - .put_super = cramfs_put_super, .remount_fs = cramfs_remount, .statfs = cramfs_statfs, }; @@ -565,7 +577,7 @@ static struct file_system_type cramfs_fs_type = { .owner = THIS_MODULE, .name = "cramfs", .mount = cramfs_mount, - .kill_sb = kill_block_super, + .kill_sb = cramfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("cramfs"); diff --git a/include/linux/cramfs_fs.h b/fs/cramfs/internal.h index 133789609f23..349d71272157 100644 --- a/include/linux/cramfs_fs.h +++ b/fs/cramfs/internal.h @@ -1,10 +1,4 @@ -#ifndef __CRAMFS_H -#define __CRAMFS_H - -#include <uapi/linux/cramfs_fs.h> - /* Uncompression interfaces to the underlying zlib */ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); int cramfs_uncompress_init(void); void cramfs_uncompress_exit(void); -#endif diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index 023329800d2e..1760c1b84d97 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -19,7 +19,7 @@ #include <linux/errno.h> #include <linux/vmalloc.h> #include <linux/zlib.h> -#include <linux/cramfs_fs.h> +#include "internal.h" static z_stream stream; static int initialized; diff --git a/fs/dcache.c b/fs/dcache.c index cb4a10690868..265e0ce9769c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3116,26 +3116,28 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) /* * Write full pathname from the root of the filesystem into the buffer. */ -static char *__dentry_path(struct dentry *dentry, char *buf, int buflen) +static char *__dentry_path(struct dentry *d, char *buf, int buflen) { + struct dentry *dentry; char *end, *retval; int len, seq = 0; int error = 0; + if (buflen < 2) + goto Elong; + rcu_read_lock(); restart: + dentry = d; end = buf + buflen; len = buflen; prepend(&end, &len, "\0", 1); - if (buflen < 1) - goto Elong; /* Get '/' right */ retval = end-1; *retval = '/'; read_seqbegin_or_lock(&rename_lock, &seq); while (!IS_ROOT(dentry)) { struct dentry *parent = dentry->d_parent; - int error; prefetch(parent); error = prepend_name(&end, &len, &dentry->d_name); diff --git a/fs/dcookies.c b/fs/dcookies.c index ab5954b50267..ac44a69fbea9 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -204,7 +204,7 @@ out: } #ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, size_t, len) +COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len) { #ifdef __BIG_ENDIAN return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index c36c44824471..b167ca48b8ee 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -659,19 +659,17 @@ out_lock: return rc; } -static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, - size_t *bufsiz) +static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); char *lower_buf; + char *buf; mm_segment_t old_fs; int rc; lower_buf = kmalloc(PATH_MAX, GFP_KERNEL); - if (!lower_buf) { - rc = -ENOMEM; - goto out; - } + if (!lower_buf) + return ERR_PTR(-ENOMEM); old_fs = get_fs(); set_fs(get_ds()); rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, @@ -680,21 +678,18 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, set_fs(old_fs); if (rc < 0) goto out; - rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb, + rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb, lower_buf, rc); out: kfree(lower_buf); - return rc; + return rc ? ERR_PTR(rc) : buf; } static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *buf; - size_t len = PATH_MAX; - int rc; - - rc = ecryptfs_readlink_lower(dentry, &buf, &len); - if (rc) + size_t len; + char *buf = ecryptfs_readlink_lower(dentry, &len); + if (IS_ERR(buf)) goto out; fsstack_copy_attr_atime(dentry->d_inode, ecryptfs_dentry_to_lower(dentry)->d_inode); @@ -1003,10 +998,12 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, char *target; size_t targetsiz; - rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz); - if (!rc) { + target = ecryptfs_readlink_lower(dentry, &targetsiz); + if (!IS_ERR(target)) { kfree(target); stat->size = targetsiz; + } else { + rc = PTR_ERR(target); } } return rc; diff --git a/fs/efs/super.c b/fs/efs/super.c index c6f57a74a559..50215bbd6463 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -26,11 +26,18 @@ static struct dentry *efs_mount(struct file_system_type *fs_type, return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super); } +static void efs_kill_sb(struct super_block *s) +{ + struct efs_sb_info *sbi = SUPER_INFO(s); + kill_block_super(s); + kfree(sbi); +} + static struct file_system_type efs_fs_type = { .owner = THIS_MODULE, .name = "efs", .mount = efs_mount, - .kill_sb = kill_block_super, + .kill_sb = efs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("efs"); @@ -105,12 +112,6 @@ static void destroy_inodecache(void) kmem_cache_destroy(efs_inode_cachep); } -static void efs_put_super(struct super_block *s) -{ - kfree(s->s_fs_info); - s->s_fs_info = NULL; -} - static int efs_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_RDONLY; @@ -120,7 +121,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data) static const struct super_operations efs_superblock_operations = { .alloc_inode = efs_alloc_inode, .destroy_inode = efs_destroy_inode, - .put_super = efs_put_super, .statfs = efs_statfs, .remount_fs = efs_remount, }; @@ -259,7 +259,6 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) struct efs_sb_info *sb; struct buffer_head *bh; struct inode *root; - int ret = -EINVAL; sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL); if (!sb) @@ -270,7 +269,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) { printk(KERN_ERR "EFS: device does not support %d byte blocks\n", EFS_BLOCKSIZE); - goto out_no_fs_ul; + return -EINVAL; } /* read the vh (volume header) block */ @@ -278,7 +277,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) if (!bh) { printk(KERN_ERR "EFS: cannot read volume header\n"); - goto out_no_fs_ul; + return -EINVAL; } /* @@ -290,13 +289,13 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) brelse(bh); if (sb->fs_start == -1) { - goto out_no_fs_ul; + return -EINVAL; } bh = sb_bread(s, sb->fs_start + EFS_SUPER); if (!bh) { printk(KERN_ERR "EFS: cannot read superblock\n"); - goto out_no_fs_ul; + return -EINVAL; } if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) { @@ -304,7 +303,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) printk(KERN_WARNING "EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER); #endif brelse(bh); - goto out_no_fs_ul; + return -EINVAL; } brelse(bh); @@ -319,24 +318,16 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) root = efs_iget(s, EFS_ROOTINODE); if (IS_ERR(root)) { printk(KERN_ERR "EFS: get root inode failed\n"); - ret = PTR_ERR(root); - goto out_no_fs; + return PTR_ERR(root); } s->s_root = d_make_root(root); if (!(s->s_root)) { printk(KERN_ERR "EFS: get root dentry failed\n"); - ret = -ENOMEM; - goto out_no_fs; + return -ENOMEM; } return 0; - -out_no_fs_ul: -out_no_fs: - s->s_fs_info = NULL; - kfree(sb); - return ret; } static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) { diff --git a/fs/eventfd.c b/fs/eventfd.c index 35470d9b96e6..d6a88e7812f3 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -349,15 +349,12 @@ EXPORT_SYMBOL_GPL(eventfd_fget); */ struct eventfd_ctx *eventfd_ctx_fdget(int fd) { - struct file *file; struct eventfd_ctx *ctx; - - file = eventfd_fget(fd); - if (IS_ERR(file)) - return (struct eventfd_ctx *) file; - ctx = eventfd_ctx_get(file->private_data); - fput(file); - + struct fd f = fdget(fd); + if (!f.file) + return ERR_PTR(-EBADF); + ctx = eventfd_ctx_fileget(f.file); + fdput(f); return ctx; } EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index a52a5d23c30b..ee4317faccb1 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -577,7 +577,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) if (offset >= i_size) { *uptodate = true; - EXOFS_DBGMSG("offset >= i_size index=0x%lx\n", index); + EXOFS_DBGMSG2("offset >= i_size index=0x%lx\n", index); return ZERO_PAGE(0); } @@ -596,10 +596,10 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) *uptodate = true; else *uptodate = PageUptodate(page); - EXOFS_DBGMSG("index=0x%lx uptodate=%d\n", index, *uptodate); + EXOFS_DBGMSG2("index=0x%lx uptodate=%d\n", index, *uptodate); return page; } else { - EXOFS_DBGMSG("YES that_locked_page index=0x%lx\n", + EXOFS_DBGMSG2("YES that_locked_page index=0x%lx\n", pcol->that_locked_page->index); *uptodate = true; return pcol->that_locked_page; @@ -611,11 +611,11 @@ static void __r4w_put_page(void *priv, struct page *page) struct page_collect *pcol = priv; if ((pcol->that_locked_page != page) && (ZERO_PAGE(0) != page)) { - EXOFS_DBGMSG("index=0x%lx\n", page->index); + EXOFS_DBGMSG2("index=0x%lx\n", page->index); page_cache_release(page); return; } - EXOFS_DBGMSG("that_locked_page index=0x%lx\n", + EXOFS_DBGMSG2("that_locked_page index=0x%lx\n", ZERO_PAGE(0) == page ? -1 : page->index); } @@ -961,6 +961,14 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset, WARN_ON(1); } + + /* TODO: Should be easy enough to do proprly */ +static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, unsigned long nr_segs) +{ + return 0; +} + const struct address_space_operations exofs_aops = { .readpage = exofs_readpage, .readpages = exofs_readpages, @@ -974,7 +982,7 @@ const struct address_space_operations exofs_aops = { /* Not implemented Yet */ .bmap = NULL, /* TODO: use osd's OSD_ACT_READ_MAP */ - .direct_IO = NULL, /* TODO: Should be trivial to do */ + .direct_IO = exofs_direct_IO, /* With these NULL has special meaning or default is not exported */ .get_xip_mem = NULL, @@ -1010,7 +1018,7 @@ static int _do_truncate(struct inode *inode, loff_t newsize) if (likely(!ret)) truncate_setsize(inode, newsize); - EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n", + EXOFS_DBGMSG2("(0x%lx) size=0x%llx ret=>%d\n", inode->i_ino, newsize, ret); return ret; } @@ -1094,14 +1102,13 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, /* If object is lost on target we might as well enable it's * delete. */ - if ((ret == -ENOENT) || (ret == -EINVAL)) - ret = 0; + ret = 0; goto out; } ret = extract_attr_from_ios(ios, &attrs[0]); if (ret) { - EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__); + EXOFS_ERR("%s: extract_attr 0 of inode failed\n", __func__); goto out; } WARN_ON(attrs[0].len != EXOFS_INO_ATTR_SIZE); @@ -1109,7 +1116,7 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, ret = extract_attr_from_ios(ios, &attrs[1]); if (ret) { - EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__); + EXOFS_ERR("%s: extract_attr 1 of inode failed\n", __func__); goto out; } if (attrs[1].len) { @@ -1124,7 +1131,7 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, ret = extract_attr_from_ios(ios, &attrs[2]); if (ret) { - EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__); + EXOFS_ERR("%s: extract_attr 2 of inode failed\n", __func__); goto out; } if (attrs[2].len) { diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c index b74422888604..dae884694bd9 100644 --- a/fs/exofs/ore.c +++ b/fs/exofs/ore.c @@ -103,7 +103,7 @@ int ore_verify_layout(unsigned total_comps, struct ore_layout *layout) layout->max_io_length = (BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) * - layout->group_width; + (layout->group_width - layout->parity); if (layout->parity) { unsigned stripe_length = (layout->group_width - layout->parity) * @@ -286,7 +286,8 @@ int ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc, if (length) { ore_calc_stripe_info(layout, offset, length, &ios->si); ios->length = ios->si.length; - ios->nr_pages = (ios->length + PAGE_SIZE - 1) / PAGE_SIZE; + ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) + + ios->length + PAGE_SIZE - 1) / PAGE_SIZE; if (layout->parity) _ore_post_alloc_raid_stuff(ios); } @@ -430,8 +431,12 @@ int ore_check_io(struct ore_io_state *ios, ore_on_dev_error on_dev_error) if (likely(!ret)) continue; - if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) { - /* start read offset passed endof file */ + if ((OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) && + per_dev->bio) { + /* start read offset passed endof file. + * Note: if we do not have bio it means read-attributes + * In this case we should return error to caller. + */ _clear_bio(per_dev->bio); ORE_DBGMSG("start read offset passed end of file " "offset=0x%llx, length=0x%llx\n", @@ -536,6 +541,7 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset, u64 H = LmodS - G * T; u32 N = div_u64(H, U); + u32 Nlast; /* "H - (N * U)" is just "H % U" so it's bound to u32 */ u32 C = (u32)(H - (N * U)) / stripe_unit + G * group_width; @@ -568,6 +574,10 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset, si->length = T - H; if (si->length > length) si->length = length; + + Nlast = div_u64(H + si->length + U - 1, U); + si->maxdevUnits = Nlast - N; + si->M = M; } EXPORT_SYMBOL(ore_calc_stripe_info); @@ -583,13 +593,16 @@ int _ore_add_stripe_unit(struct ore_io_state *ios, unsigned *cur_pg, int ret; if (per_dev->bio == NULL) { - unsigned pages_in_stripe = ios->layout->group_width * - (ios->layout->stripe_unit / PAGE_SIZE); - unsigned nr_pages = ios->nr_pages * ios->layout->group_width / - (ios->layout->group_width - - ios->layout->parity); - unsigned bio_size = (nr_pages + pages_in_stripe) / - ios->layout->group_width; + unsigned bio_size; + + if (!ios->reading) { + bio_size = ios->si.maxdevUnits; + } else { + bio_size = (ios->si.maxdevUnits + 1) * + (ios->layout->group_width - ios->layout->parity) / + ios->layout->group_width; + } + bio_size *= (ios->layout->stripe_unit / PAGE_SIZE); per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size); if (unlikely(!per_dev->bio)) { @@ -609,8 +622,12 @@ int _ore_add_stripe_unit(struct ore_io_state *ios, unsigned *cur_pg, added_len = bio_add_pc_page(q, per_dev->bio, pages[pg], pglen, pgbase); if (unlikely(pglen != added_len)) { - ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=%u\n", - per_dev->bio->bi_vcnt); + /* If bi_vcnt == bi_max then this is a SW BUG */ + ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x " + "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n", + per_dev->bio->bi_vcnt, + per_dev->bio->bi_max_vecs, + BIO_MAX_PAGES_KMALLOC, cur_len); ret = -ENOMEM; goto out; } @@ -1098,7 +1115,7 @@ int ore_truncate(struct ore_layout *layout, struct ore_components *oc, size_attr->attr = g_attr_logical_length; size_attr->attr.val_ptr = &size_attr->newsize; - ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n", + ORE_DBGMSG2("trunc(0x%llx) obj_offset=0x%llx dev=%d\n", _LLU(oc->comps->obj.id), _LLU(obj_size), i); ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1, &size_attr->attr); diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 110b6b371a4e..1b8001bbe947 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -148,13 +148,6 @@ ext2_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -189,19 +182,14 @@ ext2_get_acl(struct inode *inode, int type) /* * inode->i_mutex: down */ -static int -ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +int +ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int name_index; void *value = NULL; size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - switch(type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -250,169 +238,21 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) int ext2_init_acl(struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) { - /* This is an extended ACL */ - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - posix_acl_release(acl); - return error; -} - -/* - * Does chmod for an inode that may have an Access Control List. The - * inode->i_mode field must be updated to the desired value by the caller - * before calling this function. - * Returns 0 on success, or a negative error number. - * - * We change the ACL rather than storing some ACL entries in the file - * mode permission bits (which would be more efficient), because that - * would break once additional permissions (like ACL_APPEND, ACL_DELETE - * for directories) are added. There are no more bits available in the - * file mode. - * - * inode->i_mutex: down - */ -int -ext2_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error; + struct posix_acl *default_acl, *acl; + int error; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return error; -} -/* - * Extended attribut handlers - */ -static size_t -ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext2_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ext2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else - acl = NULL; - - error = ext2_set_acl(dentry->d_inode, type, acl); - -release_and_out: - posix_acl_release(acl); + if (default_acl) { + error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + } return error; } - -const struct xattr_handler ext2_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext2_xattr_list_acl_access, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; - -const struct xattr_handler ext2_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext2_xattr_list_acl_default, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index 503bfb0ed79b..44937f9fcf32 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h @@ -55,7 +55,7 @@ static inline int ext2_acl_count(size_t size) /* acl.c */ extern struct posix_acl *ext2_get_acl(struct inode *inode, int type); -extern int ext2_acl_chmod (struct inode *); +extern int ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext2_init_acl (struct inode *, struct inode *); #else @@ -63,12 +63,6 @@ extern int ext2_init_acl (struct inode *, struct inode *); #define ext2_get_acl NULL #define ext2_set_acl NULL -static inline int -ext2_acl_chmod (struct inode *inode) -{ - return 0; -} - static inline int ext2_init_acl (struct inode *inode, struct inode *dir) { return 0; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index a5b3a5db3120..44c36e590765 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -103,5 +103,6 @@ const struct inode_operations ext2_file_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, .fiemap = ext2_fiemap, }; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 8a337640a46a..94ed36849b71 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1566,7 +1566,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) } setattr_copy(inode, iattr); if (iattr->ia_valid & ATTR_MODE) - error = ext2_acl_chmod(inode); + error = posix_acl_chmod(inode, inode->i_mode); mark_inode_dirty(inode); return error; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 256dd5f4c1c4..c268d0af1db9 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -421,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, .tmpfile = ext2_tmpfile, }; @@ -433,4 +434,5 @@ const struct inode_operations ext2_special_inode_operations = { #endif .setattr = ext2_setattr, .get_acl = ext2_get_acl, + .set_acl = ext2_set_acl, }; diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 2d7557db3ae8..91426141c33a 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -103,8 +103,8 @@ static struct mb_cache *ext2_xattr_cache; static const struct xattr_handler *ext2_xattr_handler_map[] = { [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, #ifdef CONFIG_EXT2_FS_POSIX_ACL - [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext2_xattr_acl_access_handler, - [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler, + [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler, #ifdef CONFIG_EXT2_FS_SECURITY @@ -116,8 +116,8 @@ const struct xattr_handler *ext2_xattr_handlers[] = { &ext2_xattr_user_handler, &ext2_xattr_trusted_handler, #ifdef CONFIG_EXT2_FS_POSIX_ACL - &ext2_xattr_acl_access_handler, - &ext2_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT2_FS_SECURITY &ext2_xattr_security_handler, diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index 5e41cccff762..60edf298644e 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -57,8 +57,6 @@ struct ext2_xattr_entry { extern const struct xattr_handler ext2_xattr_user_handler; extern const struct xattr_handler ext2_xattr_trusted_handler; -extern const struct xattr_handler ext2_xattr_acl_access_handler; -extern const struct xattr_handler ext2_xattr_acl_default_handler; extern const struct xattr_handler ext2_xattr_security_handler; extern ssize_t ext2_listxattr(struct dentry *, char *, size_t); diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index dbb5ad59a7fc..8bbaf5bcf982 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -145,13 +145,6 @@ ext3_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -190,7 +183,7 @@ ext3_get_acl(struct inode *inode, int type) * inode->i_mutex: down unless called from ext3_new_inode */ static int -ext3_set_acl(handle_t *handle, struct inode *inode, int type, +__ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { int name_index; @@ -198,9 +191,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -243,204 +233,49 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -/* - * Initialize the ACLs of a new inode. Called from ext3_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext3_set_acl(handle, inode, - ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (error < 0) - return error; - - if (error > 0) { - /* This is an extended ACL */ - error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - posix_acl_release(acl); - return error; -} - -/* - * Does chmod for an inode that may have an Access Control List. The - * inode->i_mode field must be updated to the desired value by the caller - * before calling this function. - * Returns 0 on success, or a negative error number. - * - * We change the ACL rather than storing some ACL entries in the file - * mode permission bits (which would be more efficient), because that - * would break once additional permissions (like ACL_APPEND, ACL_DELETE - * for directories) are added. There are no more bits available in the - * file mode. - * - * inode->i_mutex: down - */ -int -ext3_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; handle_t *handle; - int retries = 0; - int error; + int error, retries = 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; retry: - handle = ext3_journal_start(inode, - EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - ext3_std_error(inode->i_sb, error); - goto out; - } - error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + error = __ext3_set_acl(handle, inode, type, acl); ext3_journal_stop(handle); - if (error == -ENOSPC && - ext3_should_retry_alloc(inode->i_sb, &retries)) + if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; -out: - posix_acl_release(acl); return error; } /* - * Extended attribute handlers + * Initialize the ACLs of a new inode. Called from ext3_new_inode. + * + * dir->i_mutex: down + * inode->i_mutex: up (access to inode is still exclusive) */ -static size_t -ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) +int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int error; - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ext3_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - handle_t *handle; - struct posix_acl *acl; - int error, retries = 0; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else - acl = NULL; - -retry: - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - error = ext3_set_acl(handle, inode, type, acl); - ext3_journal_stop(handle); - if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; -release_and_out: - posix_acl_release(acl); + if (default_acl) { + error = __ext3_set_acl(handle, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = __ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, + acl); + posix_acl_release(acl); + } return error; } - -const struct xattr_handler ext3_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext3_xattr_list_acl_access, - .get = ext3_xattr_get_acl, - .set = ext3_xattr_set_acl, -}; - -const struct xattr_handler ext3_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext3_xattr_list_acl_default, - .get = ext3_xattr_get_acl, - .set = ext3_xattr_set_acl, -}; diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index dbc921e458c5..ea1c69edab9e 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h @@ -55,18 +55,13 @@ static inline int ext3_acl_count(size_t size) /* acl.c */ extern struct posix_acl *ext3_get_acl(struct inode *inode, int type); -extern int ext3_acl_chmod (struct inode *); +extern int ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT3_FS_POSIX_ACL */ #include <linux/sched.h> #define ext3_get_acl NULL - -static inline int -ext3_acl_chmod(struct inode *inode) -{ - return 0; -} +#define ext3_set_acl NULL static inline int ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 25cb413277e9..aad05311392a 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -75,6 +75,7 @@ const struct inode_operations ext3_file_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, .fiemap = ext3_fiemap, }; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 2bd85486b879..384b6ebb655f 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3365,7 +3365,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) mark_inode_dirty(inode); if (ia_valid & ATTR_MODE) - rc = ext3_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); err_out: ext3_std_error(inode->i_sb, error); diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index f8cde46de9cd..f197736dccfa 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2569,6 +2569,7 @@ const struct inode_operations ext3_dir_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, }; const struct inode_operations ext3_special_inode_operations = { @@ -2580,4 +2581,5 @@ const struct inode_operations ext3_special_inode_operations = { .removexattr = generic_removexattr, #endif .get_acl = ext3_get_acl, + .set_acl = ext3_set_acl, }; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index b1fc96383e08..c6874be6d58b 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -102,8 +102,8 @@ static struct mb_cache *ext3_xattr_cache; static const struct xattr_handler *ext3_xattr_handler_map[] = { [EXT3_XATTR_INDEX_USER] = &ext3_xattr_user_handler, #ifdef CONFIG_EXT3_FS_POSIX_ACL - [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext3_xattr_acl_access_handler, - [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler, + [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT3_XATTR_INDEX_TRUSTED] = &ext3_xattr_trusted_handler, #ifdef CONFIG_EXT3_FS_SECURITY @@ -115,8 +115,8 @@ const struct xattr_handler *ext3_xattr_handlers[] = { &ext3_xattr_user_handler, &ext3_xattr_trusted_handler, #ifdef CONFIG_EXT3_FS_POSIX_ACL - &ext3_xattr_acl_access_handler, - &ext3_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT3_FS_SECURITY &ext3_xattr_security_handler, diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index 2be4f69bfa64..32e93ebf8031 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -60,8 +60,6 @@ struct ext3_xattr_entry { extern const struct xattr_handler ext3_xattr_user_handler; extern const struct xattr_handler ext3_xattr_trusted_handler; -extern const struct xattr_handler ext3_xattr_acl_access_handler; -extern const struct xattr_handler ext3_xattr_acl_default_handler; extern const struct xattr_handler ext3_xattr_security_handler; extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 39a54a0e9fe4..d40c8dbbb0d6 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -152,13 +152,6 @@ ext4_get_acl(struct inode *inode, int type) struct posix_acl *acl; int retval; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -196,7 +189,7 @@ ext4_get_acl(struct inode *inode, int type) * inode->i_mutex: down unless called from ext4_new_inode */ static int -ext4_set_acl(handle_t *handle, struct inode *inode, int type, +__ext4_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { int name_index; @@ -204,9 +197,6 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -248,208 +238,51 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -/* - * Initialize the ACLs of a new inode. Called from ext4_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ int -ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext4_set_acl(handle, inode, - ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (error < 0) - return error; - - if (error > 0) { - /* This is an extended ACL */ - error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - posix_acl_release(acl); - return error; -} - -/* - * Does chmod for an inode that may have an Access Control List. The - * inode->i_mode field must be updated to the desired value by the caller - * before calling this function. - * Returns 0 on success, or a negative error number. - * - * We change the ACL rather than storing some ACL entries in the file - * mode permission bits (which would be more efficient), because that - * would break once additional permissions (like ACL_APPEND, ACL_DELETE - * for directories) are added. There are no more bits available in the - * file mode. - * - * inode->i_mutex: down - */ -int -ext4_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; handle_t *handle; - int retries = 0; - int error; - + int error, retries = 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; retry: handle = ext4_journal_start(inode, EXT4_HT_XATTR, ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - ext4_std_error(inode->i_sb, error); - goto out; - } - error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + error = __ext4_set_acl(handle, inode, type, acl); ext4_journal_stop(handle); - if (error == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) + if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; -out: - posix_acl_release(acl); return error; } /* - * Extended attribute handlers + * Initialize the ACLs of a new inode. Called from ext4_new_inode. + * + * dir->i_mutex: down + * inode->i_mutex: up (access to inode is still exclusive) */ -static size_t -ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) +int +ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int error; - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ext4_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - handle_t *handle; - struct posix_acl *acl; - int error, retries = 0; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else - acl = NULL; + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; -retry: - handle = ext4_journal_start(inode, EXT4_HT_XATTR, - ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto release_and_out; + if (default_acl) { + error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, + acl); + posix_acl_release(acl); } - error = ext4_set_acl(handle, inode, type, acl); - ext4_journal_stop(handle); - if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - -release_and_out: - posix_acl_release(acl); return error; } - -const struct xattr_handler ext4_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext4_xattr_list_acl_access, - .get = ext4_xattr_get_acl, - .set = ext4_xattr_set_acl, -}; - -const struct xattr_handler ext4_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext4_xattr_list_acl_default, - .get = ext4_xattr_get_acl, - .set = ext4_xattr_set_acl, -}; diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 18cb39ed7c7b..da2c79577d72 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h @@ -55,18 +55,13 @@ static inline int ext4_acl_count(size_t size) /* acl.c */ struct posix_acl *ext4_get_acl(struct inode *inode, int type); -extern int ext4_acl_chmod(struct inode *); +int ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT4_FS_POSIX_ACL */ #include <linux/sched.h> #define ext4_get_acl NULL - -static inline int -ext4_acl_chmod(struct inode *inode) -{ - return 0; -} +#define ext4_set_acl NULL static inline int ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 3384dc4bed40..10cff4736b11 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3477,7 +3477,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, WARN_ON(map->m_lblk < ee_block); /* * It is safe to convert extent to initialized via explicit - * zeroout only if extent is fully insde i_size or new_size. + * zeroout only if extent is fully inside i_size or new_size. */ split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3da21945ff1f..43e64f6022eb 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -617,6 +617,7 @@ const struct inode_operations ext4_file_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, }; diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index bae987549dc3..82edf5b93352 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -849,15 +849,16 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, handle_t *handle; struct page *page; struct ext4_iloc iloc; + int retries; ret = ext4_get_inode_loc(inode, &iloc); if (ret) return ret; +retry_journal: handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - handle = NULL; goto out; } @@ -867,7 +868,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, if (inline_size >= pos + len) { ret = ext4_prepare_inline_data(handle, inode, pos + len); if (ret && ret != -ENOSPC) - goto out; + goto out_journal; } if (ret == -ENOSPC) { @@ -875,6 +876,10 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, inode, flags, fsdata); + ext4_journal_stop(handle); + if (ret == -ENOSPC && + ext4_should_retry_alloc(inode->i_sb, &retries)) + goto retry_journal; goto out; } @@ -887,7 +892,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, page = grab_cache_page_write_begin(mapping, 0, flags); if (!page) { ret = -ENOMEM; - goto out; + goto out_journal; } down_read(&EXT4_I(inode)->xattr_sem); @@ -904,16 +909,15 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, up_read(&EXT4_I(inode)->xattr_sem); *pagep = page; - handle = NULL; brelse(iloc.bh); return 1; out_release_page: up_read(&EXT4_I(inode)->xattr_sem); unlock_page(page); page_cache_release(page); +out_journal: + ext4_journal_stop(handle); out: - if (handle) - ext4_journal_stop(handle); brelse(iloc.bh); return ret; } @@ -1837,7 +1841,6 @@ int ext4_try_to_evict_inline_data(handle_t *handle, { int error; struct ext4_xattr_entry *entry; - struct ext4_xattr_ibody_header *header; struct ext4_inode *raw_inode; struct ext4_iloc iloc; @@ -1846,7 +1849,6 @@ int ext4_try_to_evict_inline_data(handle_t *handle, return error; raw_inode = ext4_raw_inode(&iloc); - header = IHDR(inode, raw_inode); entry = (struct ext4_xattr_entry *)((void *)raw_inode + EXT4_I(inode)->i_inline_off); if (EXT4_XATTR_LEN(entry->e_name_len) + @@ -1924,9 +1926,11 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline) } /* Clear the content within i_blocks. */ - if (i_size < EXT4_MIN_INLINE_DATA_SIZE) - memset(ext4_raw_inode(&is.iloc)->i_block + i_size, 0, - EXT4_MIN_INLINE_DATA_SIZE - i_size); + if (i_size < EXT4_MIN_INLINE_DATA_SIZE) { + void *p = (void *) ext4_raw_inode(&is.iloc)->i_block; + memset(p + i_size, 0, + EXT4_MIN_INLINE_DATA_SIZE - i_size); + } EXT4_I(inode)->i_inline_size = i_size < EXT4_MIN_INLINE_DATA_SIZE ? diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 31fa964742bc..6e39895a91b8 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -144,8 +144,8 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, */ static int ext4_inode_is_fast_symlink(struct inode *inode) { - int ea_blocks = EXT4_I(inode)->i_file_acl ? - (inode->i_sb->s_blocksize >> 9) : 0; + int ea_blocks = EXT4_I(inode)->i_file_acl ? + EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); } @@ -1772,7 +1772,7 @@ static int __ext4_journalled_writepage(struct page *page, ret = err; if (!ext4_has_inline_data(inode)) - ext4_walk_page_buffers(handle, page_bufs, 0, len, + ext4_walk_page_buffers(NULL, page_bufs, 0, len, NULL, bput_one); ext4_set_inode_state(inode, EXT4_STATE_JDATA); out: @@ -3501,11 +3501,6 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) if (!S_ISREG(inode->i_mode)) return -EOPNOTSUPP; - if (EXT4_SB(sb)->s_cluster_ratio > 1) { - /* TODO: Add support for bigalloc file systems */ - return -EOPNOTSUPP; - } - trace_ext4_punch_hole(inode, offset, length); /* @@ -4667,7 +4662,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) ext4_orphan_del(NULL, inode); if (!rc && (ia_valid & ATTR_MODE)) - rc = ext4_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); err_out: ext4_std_error(inode->i_sb, error); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 60589b60e9b0..6bea80614d77 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -101,9 +101,8 @@ static long swap_inode_boot_loader(struct super_block *sb, handle_t *handle; int err; struct inode *inode_bl; - struct ext4_inode_info *ei; struct ext4_inode_info *ei_bl; - struct ext4_sb_info *sbi; + struct ext4_sb_info *sbi = EXT4_SB(sb); if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) { err = -EINVAL; @@ -115,9 +114,6 @@ static long swap_inode_boot_loader(struct super_block *sb, goto swap_boot_out; } - sbi = EXT4_SB(sb); - ei = EXT4_I(inode); - inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); if (IS_ERR(inode_bl)) { err = PTR_ERR(inode_bl); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 5a0408d7b114..d050e043e884 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1425,9 +1425,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi return ERR_PTR(-EIO); } if (unlikely(ino == dir->i_ino)) { - EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir", - dentry->d_name.len, - dentry->d_name.name); + EXT4_ERROR_INODE(dir, "'%pd' linked to parent dir", + dentry); return ERR_PTR(-EIO); } inode = ext4_iget(dir->i_sb, ino); @@ -3225,6 +3224,7 @@ const struct inode_operations ext4_dir_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, .fiemap = ext4_fiemap, }; @@ -3235,4 +3235,5 @@ const struct inode_operations ext4_special_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, .get_acl = ext4_get_acl, + .set_acl = ext4_set_acl, }; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 1423c4816a47..e175e94116ac 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -95,8 +95,8 @@ static struct mb_cache *ext4_xattr_cache; static const struct xattr_handler *ext4_xattr_handler_map[] = { [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, #ifdef CONFIG_EXT4_FS_POSIX_ACL - [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler, - [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, #ifdef CONFIG_EXT4_FS_SECURITY @@ -108,8 +108,8 @@ const struct xattr_handler *ext4_xattr_handlers[] = { &ext4_xattr_user_handler, &ext4_xattr_trusted_handler, #ifdef CONFIG_EXT4_FS_POSIX_ACL - &ext4_xattr_acl_access_handler, - &ext4_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif #ifdef CONFIG_EXT4_FS_SECURITY &ext4_xattr_security_handler, diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index c767dbdd7fc4..819d6398833f 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -96,8 +96,6 @@ struct ext4_xattr_ibody_find { extern const struct xattr_handler ext4_xattr_user_handler; extern const struct xattr_handler ext4_xattr_trusted_handler; -extern const struct xattr_handler ext4_xattr_acl_access_handler; -extern const struct xattr_handler ext4_xattr_acl_default_handler; extern const struct xattr_handler ext4_xattr_security_handler; extern ssize_t ext4_listxattr(struct dentry *, char *, size_t); diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index d0fc287efeff..fa8da4cb8c4b 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -17,9 +17,6 @@ #include "xattr.h" #include "acl.h" -#define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ - (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) - static inline size_t f2fs_acl_size(int count) { if (count <= 4) { @@ -167,19 +164,11 @@ fail: struct posix_acl *f2fs_get_acl(struct inode *inode, int type) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; void *value = NULL; struct posix_acl *acl; int retval; - if (!test_opt(sbi, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - if (type == ACL_TYPE_ACCESS) name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -205,21 +194,15 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type) return acl; } -static int f2fs_set_acl(struct inode *inode, int type, +static int __f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl, struct page *ipage) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); int name_index; void *value = NULL; size_t size = 0; int error; - if (!test_opt(sbi, POSIX_ACL)) - return 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; @@ -261,154 +244,31 @@ static int f2fs_set_acl(struct inode *inode, int type, return error; } -int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) +int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(sbi, POSIX_ACL)) { - acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - - if (!test_opt(sbi, POSIX_ACL) || !acl) - goto cleanup; - - if (S_ISDIR(inode->i_mode)) { - error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); -cleanup: - posix_acl_release(acl); - return error; + return __f2fs_set_acl(inode, type, acl, NULL); } -int f2fs_acl_chmod(struct inode *inode) +int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) { - struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct posix_acl *acl; - int error; - umode_t mode = get_inode_mode(inode); - - if (!test_opt(sbi, POSIX_ACL)) - return 0; - if (S_ISLNK(mode)) - return -EOPNOTSUPP; - - acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); + struct posix_acl *default_acl, *acl; + int error = 0; - error = posix_acl_chmod(&acl, GFP_KERNEL, mode); + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; - error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL); - posix_acl_release(acl); - return error; -} - -static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - const char *xname = POSIX_ACL_XATTR_DEFAULT; - size_t size; - - if (!test_opt(sbi, POSIX_ACL)) - return 0; - - if (type == ACL_TYPE_ACCESS) - xname = POSIX_ACL_XATTR_ACCESS; - - size = strlen(xname) + 1; - if (list && size <= list_size) - memcpy(list, xname, size); - return size; -} - -static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(sbi, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = f2fs_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(sbi, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else { - acl = NULL; + if (default_acl) { + error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, + ipage); + posix_acl_release(default_acl); + } + if (acl) { + if (error) + error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, + ipage); + posix_acl_release(acl); } - error = f2fs_set_acl(inode, type, acl, NULL); - -release_and_out: - posix_acl_release(acl); return error; } - -const struct xattr_handler f2fs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = f2fs_xattr_list_acl, - .get = f2fs_xattr_get_acl, - .set = f2fs_xattr_set_acl, -}; - -const struct xattr_handler f2fs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = f2fs_xattr_list_acl, - .get = f2fs_xattr_get_acl, - .set = f2fs_xattr_set_acl, -}; diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index 49633131e038..e0864651cdc1 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -37,18 +37,13 @@ struct f2fs_acl_header { #ifdef CONFIG_F2FS_FS_POSIX_ACL extern struct posix_acl *f2fs_get_acl(struct inode *, int); -extern int f2fs_acl_chmod(struct inode *); +extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int f2fs_init_acl(struct inode *, struct inode *, struct page *); #else #define f2fs_check_acl NULL #define f2fs_get_acl NULL #define f2fs_set_acl NULL -static inline int f2fs_acl_chmod(struct inode *inode) -{ - return 0; -} - static inline int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *page) { diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index af51a0bd2dee..fc3c558cb4f3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1023,6 +1023,10 @@ static inline int f2fs_readonly(struct super_block *sb) return sb->s_flags & MS_RDONLY; } +#define get_inode_mode(i) \ + ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ + (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) + /* * file.c */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 85e91ca88d57..0dfcef53a6ed 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -382,7 +382,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) __setattr_copy(inode, attr); if (attr->ia_valid & ATTR_MODE) { - err = f2fs_acl_chmod(inode); + err = posix_acl_chmod(inode, get_inode_mode(inode)); if (err || is_inode_flag_set(fi, FI_ACL_MODE)) { inode->i_mode = fi->i_acl_mode; clear_inode_flag(fi, FI_ACL_MODE); @@ -397,6 +397,7 @@ const struct inode_operations f2fs_file_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 3d32f2969c5e..397d459e97bf 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -501,6 +501,7 @@ const struct inode_operations f2fs_dir_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, @@ -527,6 +528,7 @@ const struct inode_operations f2fs_special_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, + .set_acl = f2fs_set_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index b0fb8a27f3da..89d0422a91a8 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -21,6 +21,7 @@ #include <linux/rwsem.h> #include <linux/f2fs_fs.h> #include <linux/security.h> +#include <linux/posix_acl_xattr.h> #include "f2fs.h" #include "xattr.h" @@ -216,8 +217,8 @@ const struct xattr_handler f2fs_xattr_security_handler = { static const struct xattr_handler *f2fs_xattr_handler_map[] = { [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL - [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler, - [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, + [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, + [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, #ifdef CONFIG_F2FS_FS_SECURITY @@ -229,8 +230,8 @@ static const struct xattr_handler *f2fs_xattr_handler_map[] = { const struct xattr_handler *f2fs_xattr_handlers[] = { &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL - &f2fs_xattr_acl_access_handler, - &f2fs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &f2fs_xattr_trusted_handler, #ifdef CONFIG_F2FS_FS_SECURITY diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 02a08fb88a15..b21d9ebdeff3 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -108,8 +108,6 @@ struct f2fs_xattr_entry { #ifdef CONFIG_F2FS_FS_XATTR extern const struct xattr_handler f2fs_xattr_user_handler; extern const struct xattr_handler f2fs_xattr_trusted_handler; -extern const struct xattr_handler f2fs_xattr_acl_access_handler; -extern const struct xattr_handler f2fs_xattr_acl_default_handler; extern const struct xattr_handler f2fs_xattr_advise_handler; extern const struct xattr_handler f2fs_xattr_security_handler; diff --git a/fs/file.c b/fs/file.c index 4a78f981557a..771578b33fb6 100644 --- a/fs/file.c +++ b/fs/file.c @@ -348,21 +348,16 @@ out: return NULL; } -static void close_files(struct files_struct * files) +static struct fdtable *close_files(struct files_struct * files) { - int i, j; - struct fdtable *fdt; - - j = 0; - /* * It is safe to dereference the fd table without RCU or * ->file_lock because this is the last reference to the - * files structure. But use RCU to shut RCU-lockdep up. + * files structure. */ - rcu_read_lock(); - fdt = files_fdtable(files); - rcu_read_unlock(); + struct fdtable *fdt = rcu_dereference_raw(files->fdt); + int i, j = 0; + for (;;) { unsigned long set; i = j * BITS_PER_LONG; @@ -381,6 +376,8 @@ static void close_files(struct files_struct * files) set >>= 1; } } + + return fdt; } struct files_struct *get_files_struct(struct task_struct *task) @@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task) void put_files_struct(struct files_struct *files) { - struct fdtable *fdt; - if (atomic_dec_and_test(&files->count)) { - close_files(files); - /* not really needed, since nobody can see us */ - rcu_read_lock(); - fdt = files_fdtable(files); - rcu_read_unlock(); + struct fdtable *fdt = close_files(files); + /* free the arrays if they are not embedded */ if (fdt != &files->fdtab) __free_fdtable(fdt); @@ -645,16 +637,16 @@ void do_close_on_exec(struct files_struct *files) spin_unlock(&files->file_lock); } -struct file *fget(unsigned int fd) +static struct file *__fget(unsigned int fd, fmode_t mask) { - struct file *file; struct files_struct *files = current->files; + struct file *file; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { /* File object ref couldn't be taken */ - if (file->f_mode & FMODE_PATH || + if ((file->f_mode & mask) || !atomic_long_inc_not_zero(&file->f_count)) file = NULL; } @@ -663,25 +655,16 @@ struct file *fget(unsigned int fd) return file; } +struct file *fget(unsigned int fd) +{ + return __fget(fd, FMODE_PATH); +} EXPORT_SYMBOL(fget); struct file *fget_raw(unsigned int fd) { - struct file *file; - struct files_struct *files = current->files; - - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - /* File object ref couldn't be taken */ - if (!atomic_long_inc_not_zero(&file->f_count)) - file = NULL; - } - rcu_read_unlock(); - - return file; + return __fget(fd, 0); } - EXPORT_SYMBOL(fget_raw); /* @@ -700,56 +683,33 @@ EXPORT_SYMBOL(fget_raw); * The fput_needed flag returned by fget_light should be passed to the * corresponding fput_light. */ -struct file *fget_light(unsigned int fd, int *fput_needed) +struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed) { - struct file *file; struct files_struct *files = current->files; + struct file *file; *fput_needed = 0; if (atomic_read(&files->count) == 1) { - file = fcheck_files(files, fd); - if (file && (file->f_mode & FMODE_PATH)) + file = __fcheck_files(files, fd); + if (file && (file->f_mode & mask)) file = NULL; } else { - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (!(file->f_mode & FMODE_PATH) && - atomic_long_inc_not_zero(&file->f_count)) - *fput_needed = 1; - else - /* Didn't get the reference, someone's freed */ - file = NULL; - } - rcu_read_unlock(); + file = __fget(fd, mask); + if (file) + *fput_needed = 1; } return file; } +struct file *fget_light(unsigned int fd, int *fput_needed) +{ + return __fget_light(fd, FMODE_PATH, fput_needed); +} EXPORT_SYMBOL(fget_light); struct file *fget_raw_light(unsigned int fd, int *fput_needed) { - struct file *file; - struct files_struct *files = current->files; - - *fput_needed = 0; - if (atomic_read(&files->count) == 1) { - file = fcheck_files(files, fd); - } else { - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (atomic_long_inc_not_zero(&file->f_count)) - *fput_needed = 1; - else - /* Didn't get the reference, someone's freed */ - file = NULL; - } - rcu_read_unlock(); - } - - return file; + return __fget_light(fd, 0, fput_needed); } void set_close_on_exec(unsigned int fd, int flag) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 74f6ca500504..77bcc303c3ae 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2727,6 +2727,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, inode = file->f_mapping->host; i_size = i_size_read(inode); + if ((rw == READ) && (offset > i_size)) + return 0; + /* optimization for short read */ if (async_dio && rw != WRITE && offset + count > i_size) { if (offset >= i_size) diff --git a/fs/generic_acl.c b/fs/generic_acl.c deleted file mode 100644 index b3f3676796d3..000000000000 --- a/fs/generic_acl.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * (C) 2005 Andreas Gruenbacher <agruen@suse.de> - * - * This file is released under the GPL. - * - * Generic ACL support for in-memory filesystems. - */ - -#include <linux/sched.h> -#include <linux/gfp.h> -#include <linux/fs.h> -#include <linux/generic_acl.h> -#include <linux/posix_acl.h> -#include <linux/posix_acl_xattr.h> - - -static size_t -generic_acl_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - struct posix_acl *acl; - const char *xname; - size_t size; - - acl = get_cached_acl(dentry->d_inode, type); - if (!acl) - return 0; - posix_acl_release(acl); - - switch (type) { - case ACL_TYPE_ACCESS: - xname = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - xname = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return 0; - } - size = strlen(xname) + 1; - if (list && size <= list_size) - memcpy(list, xname, size); - return size; -} - -static int -generic_acl_get(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - - acl = get_cached_acl(dentry->d_inode, type); - if (!acl) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -generic_acl_set(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (acl) { - error = posix_acl_valid(acl); - if (error) - goto failed; - switch (type) { - case ACL_TYPE_ACCESS: - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) - goto failed; - inode->i_ctime = CURRENT_TIME; - if (error == 0) { - posix_acl_release(acl); - acl = NULL; - } - break; - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) { - error = -EINVAL; - goto failed; - } - break; - } - } - set_cached_acl(inode, type, acl); - error = 0; -failed: - posix_acl_release(acl); - return error; -} - -/** - * generic_acl_init - Take care of acl inheritance at @inode create time - * - * Files created inside a directory with a default ACL inherit the - * directory's default ACL. - */ -int -generic_acl_init(struct inode *inode, struct inode *dir) -{ - struct posix_acl *acl = NULL; - int error; - - if (!S_ISLNK(inode->i_mode)) - acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); - if (acl) { - if (S_ISDIR(inode->i_mode)) - set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - } else { - inode->i_mode &= ~current_umask(); - } - error = 0; - - posix_acl_release(acl); - return error; -} - -/** - * generic_acl_chmod - change the access acl of @inode upon chmod() - * - * A chmod also changes the permissions of the owner, group/mask, and - * other ACL entries. - */ -int -generic_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error = 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = get_cached_acl(inode, ACL_TYPE_ACCESS); - if (acl) { - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - } - return error; -} - -const struct xattr_handler generic_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = generic_acl_list, - .get = generic_acl_get, - .set = generic_acl_set, -}; - -const struct xattr_handler generic_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = generic_acl_list, - .get = generic_acl_get, - .set = generic_acl_set, -}; diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index f69ac0af5496..ba9456685f47 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -49,10 +49,6 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type) if (!ip->i_eattr) return NULL; - acl = get_cached_acl(&ip->i_inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - name = gfs2_acl_name(type); if (name == NULL) return ERR_PTR(-EINVAL); @@ -80,7 +76,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode) return error; } -static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) +int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int error; int len; @@ -88,219 +84,49 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) const char *name = gfs2_acl_name(type); BUG_ON(name == NULL); - len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); - if (len == 0) - return 0; - data = kmalloc(len, GFP_NOFS); - if (data == NULL) - return -ENOMEM; - error = posix_acl_to_xattr(&init_user_ns, acl, data, len); - if (error < 0) - goto out; - error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); - if (!error) - set_cached_acl(inode, type, acl); -out: - kfree(data); - return error; -} - -int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct posix_acl *acl; - umode_t mode = inode->i_mode; - int error = 0; - - if (!sdp->sd_args.ar_posix_acl) - return 0; - if (S_ISLNK(inode->i_mode)) - return 0; - - acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) { - mode &= ~current_umask(); - return gfs2_set_mode(inode, mode); - } - - if (S_ISDIR(inode->i_mode)) { - error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto out; - } - - error = posix_acl_create(&acl, GFP_NOFS, &mode); - if (error < 0) - return error; - if (error == 0) - goto munge; - - error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl); - if (error) - goto out; -munge: - error = gfs2_set_mode(inode, mode); -out: - posix_acl_release(acl); - return error; -} - -int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) -{ - struct inode *inode = &ip->i_inode; - struct posix_acl *acl; - char *data; - unsigned int len; - int error; - - acl = gfs2_get_acl(&ip->i_inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - return gfs2_setattr_simple(inode, attr); - - error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode); - if (error) - return error; - - len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); - data = kmalloc(len, GFP_NOFS); - error = -ENOMEM; - if (data == NULL) - goto out; - posix_acl_to_xattr(&init_user_ns, acl, data, len); - error = gfs2_xattr_acl_chmod(ip, attr, data); - kfree(data); - set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl); - -out: - posix_acl_release(acl); - return error; -} - -static int gfs2_acl_type(const char *name) -{ - if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0) - return ACL_TYPE_ACCESS; - if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0) - return ACL_TYPE_DEFAULT; - return -EINVAL; -} - -static int gfs2_xattr_system_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int xtype) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct posix_acl *acl; - int type; - int error; - - if (!sdp->sd_args.ar_posix_acl) - return -EOPNOTSUPP; - - type = gfs2_acl_type(name); - if (type < 0) - return type; - - acl = gfs2_get_acl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, - int xtype) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct posix_acl *acl = NULL; - int error = 0, type; - - if (!sdp->sd_args.ar_posix_acl) - return -EOPNOTSUPP; - - type = gfs2_acl_type(name); - if (type < 0) - return type; - if (flags & XATTR_CREATE) - return -EINVAL; - if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) - return value ? -EACCES : 0; - if (!uid_eq(current_fsuid(), inode->i_uid) && !capable(CAP_FOWNER)) - return -EPERM; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!value) - goto set_acl; - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (!acl) { - /* - * acl_set_file(3) may request that we set default ACLs with - * zero length -- defend (gracefully) against that here. - */ - goto out; - } - if (IS_ERR(acl)) { - error = PTR_ERR(acl); - goto out; - } - - error = posix_acl_valid(acl); - if (error) - goto out_release; - - error = -EINVAL; if (acl->a_count > GFS2_ACL_MAX_ENTRIES) - goto out_release; + return -EINVAL; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + return error; - if (error <= 0) { - posix_acl_release(acl); + if (error == 0) acl = NULL; - if (error < 0) - return error; - } - error = gfs2_set_mode(inode, mode); if (error) - goto out_release; + return error; } -set_acl: - error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS); - if (!error) { - if (acl) - set_cached_acl(inode, type, acl); - else - forget_cached_acl(inode, type); + if (acl) { + len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0); + if (len == 0) + return 0; + data = kmalloc(len, GFP_NOFS); + if (data == NULL) + return -ENOMEM; + error = posix_acl_to_xattr(&init_user_ns, acl, data, len); + if (error < 0) + goto out; + } else { + data = NULL; + len = 0; } -out_release: - posix_acl_release(acl); + + error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); + if (error) + goto out; + + if (acl) + set_cached_acl(inode, type, acl); + else + forget_cached_acl(inode, type); out: + kfree(data); return error; } - -const struct xattr_handler gfs2_xattr_system_handler = { - .prefix = XATTR_SYSTEM_PREFIX, - .flags = GFS2_EATYPE_SYS, - .get = gfs2_xattr_system_get, - .set = gfs2_xattr_system_set, -}; - diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 0da38dc7efec..301260c999ba 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -17,8 +17,6 @@ #define GFS2_ACL_MAX_ENTRIES 25 extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type); -extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); -extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); -extern const struct xattr_handler gfs2_xattr_system_handler; +extern int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); #endif /* __ACL_DOT_H__ */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 890588c7fb33..5c524180c98e 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -571,6 +571,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, unsigned int size, int excl, int *opened) { const struct qstr *name = &dentry->d_name; + struct posix_acl *default_acl, *acl; struct gfs2_holder ghs[2]; struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; @@ -633,10 +634,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (!inode) goto fail_gunlock; + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) + goto fail_free_vfs_inode; + ip = GFS2_I(inode); error = gfs2_rs_alloc(ip); if (error) - goto fail_free_inode; + goto fail_free_acls; inode->i_mode = mode; set_nlink(inode, S_ISDIR(mode) ? 2 : 1); @@ -704,7 +709,16 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, gfs2_set_iop(inode); insert_inode_hash(inode); - error = gfs2_acl_create(dip, inode); + if (default_acl) { + error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); + } + if (acl) { + if (!error) + error = gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + } + if (error) goto fail_gunlock3; @@ -738,6 +752,12 @@ fail_free_inode: if (ip->i_gl) gfs2_glock_put(ip->i_gl); gfs2_rs_delete(ip, NULL); +fail_free_acls: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); +fail_free_vfs_inode: free_inode_nonrcu(inode); inode = NULL; fail_gunlock: @@ -1716,10 +1736,11 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) error = gfs2_setattr_size(inode, attr->ia_size); else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) error = setattr_chown(inode, attr); - else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) - error = gfs2_acl_chmod(ip, attr); - else + else { error = gfs2_setattr_simple(inode, attr); + if (!error && attr->ia_valid & ATTR_MODE) + error = posix_acl_chmod(inode, inode->i_mode); + } out: if (!error) @@ -1879,6 +1900,7 @@ const struct inode_operations gfs2_file_iops = { .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, .get_acl = gfs2_get_acl, + .set_acl = gfs2_set_acl, }; const struct inode_operations gfs2_dir_iops = { @@ -1900,6 +1922,7 @@ const struct inode_operations gfs2_dir_iops = { .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, .get_acl = gfs2_get_acl, + .set_acl = gfs2_set_acl, .atomic_open = gfs2_atomic_open, }; @@ -1915,6 +1938,5 @@ const struct inode_operations gfs2_symlink_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .get_acl = gfs2_get_acl, }; diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 8c6a6f6bdba9..0b81f783f787 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -13,6 +13,7 @@ #include <linux/buffer_head.h> #include <linux/xattr.h> #include <linux/gfs2_ondisk.h> +#include <linux/posix_acl_xattr.h> #include <asm/uaccess.h> #include "gfs2.h" @@ -1500,7 +1501,8 @@ static const struct xattr_handler gfs2_xattr_security_handler = { const struct xattr_handler *gfs2_xattr_handlers[] = { &gfs2_xattr_user_handler, &gfs2_xattr_security_handler, - &gfs2_xattr_system_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, NULL, }; diff --git a/fs/hfsplus/acl.h b/fs/hfsplus/acl.h index 07c0d4947527..95c8ed9ec17f 100644 --- a/fs/hfsplus/acl.h +++ b/fs/hfsplus/acl.h @@ -12,16 +12,13 @@ /* posix_acl.c */ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type); -extern int hfsplus_posix_acl_chmod(struct inode *); +int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, + int type); extern int hfsplus_init_posix_acl(struct inode *, struct inode *); #else /* CONFIG_HFSPLUS_FS_POSIX_ACL */ #define hfsplus_get_posix_acl NULL - -static inline int hfsplus_posix_acl_chmod(struct inode *inode) -{ - return 0; -} +#define hfsplus_set_posix_acl NULL static inline int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) { diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 4a4fea002673..9ee62985e739 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -532,6 +532,7 @@ const struct inode_operations hfsplus_dir_inode_operations = { .removexattr = hfsplus_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, + .set_acl = hfsplus_set_posix_acl, #endif }; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 3ebda928229c..4551cbd6bd43 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -261,7 +261,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) mark_inode_dirty(inode); if (attr->ia_valid & ATTR_MODE) { - error = hfsplus_posix_acl_chmod(inode); + error = posix_acl_chmod(inode, inode->i_mode); if (unlikely(error)) return error; } @@ -334,6 +334,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { .removexattr = hfsplus_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, + .set_acl = hfsplus_set_posix_acl, #endif }; diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c index b609cc14c72e..df0c9af68d05 100644 --- a/fs/hfsplus/posix_acl.c +++ b/fs/hfsplus/posix_acl.c @@ -17,9 +17,7 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) char *value = NULL; ssize_t size; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; + hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); switch (type) { case ACL_TYPE_ACCESS: @@ -56,17 +54,15 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) return acl; } -static int hfsplus_set_posix_acl(struct inode *inode, - int type, - struct posix_acl *acl) +int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, + int type) { int err; char *xattr_name; size_t size = 0; char *value = NULL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; + hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); switch (type) { case ACL_TYPE_ACCESS: @@ -115,7 +111,7 @@ end_set_acl: int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) { int err = 0; - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; hfs_dbg(ACL_MOD, "[%s]: ino %lu, dir->ino %lu\n", @@ -124,151 +120,21 @@ int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) if (S_ISLNK(inode->i_mode)) return 0; - acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (acl) { - if (S_ISDIR(inode->i_mode)) { - err = hfsplus_set_posix_acl(inode, - ACL_TYPE_DEFAULT, - acl); - if (unlikely(err)) - goto init_acl_cleanup; - } - - err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (unlikely(err < 0)) - return err; - - if (err > 0) - err = hfsplus_set_posix_acl(inode, - ACL_TYPE_ACCESS, - acl); - } else - inode->i_mode &= ~current_umask(); - -init_acl_cleanup: - posix_acl_release(acl); - return err; -} - -int hfsplus_posix_acl_chmod(struct inode *inode) -{ - int err; - struct posix_acl *acl; - - hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (unlikely(err)) + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (err) return err; - err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return err; -} - -static int hfsplus_xattr_get_posix_acl(struct dentry *dentry, - const char *name, - void *buffer, - size_t size, - int type) -{ - int err = 0; - struct posix_acl *acl; - - hfs_dbg(ACL_MOD, - "[%s]: ino %lu, buffer %p, size %zu, type %#x\n", - __func__, dentry->d_inode->i_ino, buffer, size, type); - - if (strcmp(name, "") != 0) - return -EINVAL; - - acl = hfsplus_get_posix_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return err; -} - -static int hfsplus_xattr_set_posix_acl(struct dentry *dentry, - const char *name, - const void *value, - size_t size, - int flags, - int type) -{ - int err = 0; - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; - - hfs_dbg(ACL_MOD, - "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n", - __func__, inode->i_ino, value, size, flags, type); - - if (strcmp(name, "") != 0) - return -EINVAL; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - err = posix_acl_valid(acl); - if (err) - goto end_xattr_set_acl; - } + if (default_acl) { + err = hfsplus_set_posix_acl(inode, default_acl, + ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); } - err = hfsplus_set_posix_acl(inode, type, acl); - -end_xattr_set_acl: - posix_acl_release(acl); + if (acl) { + if (!err) + err = hfsplus_set_posix_acl(inode, acl, + ACL_TYPE_ACCESS); + posix_acl_release(acl); + } return err; } - -static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry, - char *list, - size_t list_size, - const char *name, - size_t name_len, - int type) -{ - /* - * This method is not used. - * It is used hfsplus_listxattr() instead of generic_listxattr(). - */ - return -EOPNOTSUPP; -} - -const struct xattr_handler hfsplus_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = hfsplus_xattr_list_posix_acl, - .get = hfsplus_xattr_get_posix_acl, - .set = hfsplus_xattr_set_posix_acl, -}; - -const struct xattr_handler hfsplus_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = hfsplus_xattr_list_posix_acl, - .get = hfsplus_xattr_get_posix_acl, - .set = hfsplus_xattr_set_posix_acl, -}; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index 3c6136f98c73..0b4a5c9b93c4 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -7,6 +7,7 @@ */ #include "hfsplus_fs.h" +#include <linux/posix_acl_xattr.h> #include "xattr.h" #include "acl.h" @@ -15,8 +16,8 @@ const struct xattr_handler *hfsplus_xattr_handlers[] = { &hfsplus_xattr_user_handler, &hfsplus_xattr_trusted_handler, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL - &hfsplus_xattr_acl_access_handler, - &hfsplus_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &hfsplus_xattr_security_handler, NULL @@ -51,82 +52,6 @@ static inline int is_known_namespace(const char *name) return true; } -static int can_set_system_xattr(struct inode *inode, const char *name, - const void *value, size_t size) -{ -#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL - struct posix_acl *acl; - int err; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - /* - * POSIX_ACL_XATTR_ACCESS is tied to i_mode - */ - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - err = posix_acl_equiv_mode(acl, &inode->i_mode); - posix_acl_release(acl); - if (err < 0) - return err; - mark_inode_dirty(inode); - } - /* - * We're changing the ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_ACCESS); - - return 0; - } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - posix_acl_release(acl); - - /* - * We're changing the default ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_DEFAULT); - - return 0; - } -#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */ - return -EOPNOTSUPP; -} - -static int can_set_xattr(struct inode *inode, const char *name, - const void *value, size_t value_len) -{ - if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) - return can_set_system_xattr(inode, name, value, value_len); - - if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { - /* - * This makes sure that we aren't trying to set an - * attribute in a different namespace by prefixing it - * with "osx." - */ - if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) - return -EOPNOTSUPP; - - return 0; - } - - /* - * Don't allow setting an attribute in an unknown namespace. - */ - if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && - strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && - strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) - return -EOPNOTSUPP; - - return 0; -} - static void hfsplus_init_header_node(struct inode *attr_file, u32 clump_size, char *buf, u16 node_size) @@ -349,10 +274,6 @@ int __hfsplus_setxattr(struct inode *inode, const char *name, HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; - err = can_set_xattr(inode, name, value, size); - if (err) - return err; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN) == 0) name += XATTR_MAC_OSX_PREFIX_LEN; @@ -840,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name) if (!HFSPLUS_SB(inode->i_sb)->attr_tree) return -EOPNOTSUPP; - err = can_set_xattr(inode, name, NULL, 0); - if (err) - return err; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN) == 0) name += XATTR_MAC_OSX_PREFIX_LEN; @@ -940,6 +857,9 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, if (len > HFSPLUS_ATTR_MAX_STRLEN) return -EOPNOTSUPP; + if (is_known_namespace(name)) + return -EOPNOTSUPP; + strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 841b5698c0fc..9e214490c313 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -14,8 +14,6 @@ extern const struct xattr_handler hfsplus_xattr_osx_handler; extern const struct xattr_handler hfsplus_xattr_user_handler; extern const struct xattr_handler hfsplus_xattr_trusted_handler; -extern const struct xattr_handler hfsplus_xattr_acl_access_handler; -extern const struct xattr_handler hfsplus_xattr_acl_default_handler; extern const struct xattr_handler hfsplus_xattr_security_handler; extern const struct xattr_handler *hfsplus_xattr_handlers[]; diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 223283c30111..009ec0b5993d 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -178,10 +178,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type) char *value = NULL; int rc, xprefix; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; @@ -232,13 +228,10 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a return rc; } -static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int rc, xprefix; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; @@ -277,30 +270,21 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int rc; cache_no_acl(inode); - if (S_ISLNK(*i_mode)) - return 0; /* Symlink always has no-ACL */ - - acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (!acl) { - *i_mode &= ~current_umask(); - } else { - if (S_ISDIR(*i_mode)) - set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); - - rc = posix_acl_create(&acl, GFP_KERNEL, i_mode); - if (rc < 0) - return rc; - if (rc > 0) - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl); + if (rc) + return rc; + if (default_acl) { + set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); + posix_acl_release(default_acl); + } + if (acl) { + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return 0; @@ -324,106 +308,3 @@ int jffs2_init_acl_post(struct inode *inode) return 0; } - -int jffs2_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int rc; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (rc) - return rc; - rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return rc; -} - -static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (list && retlen <= list_size) - strcpy(list, POSIX_ACL_XATTR_ACCESS); - return retlen; -} - -static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (list && retlen <= list_size) - strcpy(list, POSIX_ACL_XATTR_DEFAULT); - return retlen; -} - -static int jffs2_acl_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct posix_acl *acl; - int rc; - - if (name[0] != '\0') - return -EINVAL; - - acl = jffs2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) - return -ENODATA; - rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return rc; -} - -static int jffs2_acl_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct posix_acl *acl; - int rc; - - if (name[0] != '\0') - return -EINVAL; - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - rc = posix_acl_valid(acl); - if (rc) - goto out; - } - } else { - acl = NULL; - } - rc = jffs2_set_acl(dentry->d_inode, type, acl); - out: - posix_acl_release(acl); - return rc; -} - -const struct xattr_handler jffs2_acl_access_xattr_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_DEFAULT, - .list = jffs2_acl_access_listxattr, - .get = jffs2_acl_getxattr, - .set = jffs2_acl_setxattr, -}; - -const struct xattr_handler jffs2_acl_default_xattr_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = jffs2_acl_default_listxattr, - .get = jffs2_acl_getxattr, - .set = jffs2_acl_setxattr, -}; diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 9b477246f2a6..2e2b5745c3b7 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -27,17 +27,14 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL struct posix_acl *jffs2_get_acl(struct inode *inode, int type); -extern int jffs2_acl_chmod(struct inode *); +int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *); extern int jffs2_init_acl_post(struct inode *); -extern const struct xattr_handler jffs2_acl_access_xattr_handler; -extern const struct xattr_handler jffs2_acl_default_xattr_handler; - #else #define jffs2_get_acl (NULL) -#define jffs2_acl_chmod(inode) (0) +#define jffs2_set_acl (NULL) #define jffs2_init_acl_pre(dir_i,inode,mode) (0) #define jffs2_init_acl_post(inode) (0) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index e3aac222472e..938556025d64 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -59,6 +59,7 @@ const struct inode_operations jffs2_dir_inode_operations = .mknod = jffs2_mknod, .rename = jffs2_rename, .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 1506673c087e..256cd19a3b78 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -66,6 +66,7 @@ const struct file_operations jffs2_file_operations = const struct inode_operations jffs2_file_inode_operations = { .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 09b3ed455724..a69e426435dd 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -190,15 +190,16 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) { + struct inode *inode = dentry->d_inode; int rc; - rc = inode_change_ok(dentry->d_inode, iattr); + rc = inode_change_ok(inode, iattr); if (rc) return rc; - rc = jffs2_do_setattr(dentry->d_inode, iattr); + rc = jffs2_do_setattr(inode, iattr); if (!rc && (iattr->ia_valid & ATTR_MODE)) - rc = jffs2_acl_chmod(dentry->d_inode); + rc = posix_acl_chmod(inode, inode->i_mode); return rc; } diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 4f47aa24b556..b8fd651307a4 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -288,6 +288,8 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) struct jffs2_xattr_datum *xd; xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); dbg_memalloc("%p\n", xd); + if (!xd) + return NULL; xd->class = RAWNODE_CLASS_XATTR_DATUM; xd->node = (void *)xd; @@ -306,6 +308,8 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) struct jffs2_xattr_ref *ref; ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); dbg_memalloc("%p\n", ref); + if (!ref) + return NULL; ref->class = RAWNODE_CLASS_XATTR_REF; ref->node = (void *)ref; diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 6e563332bb24..c7c77b0dfccd 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -22,7 +22,6 @@ const struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, - .get_acl = jffs2_get_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 3034e970eb9a..ad0f2e2a1700 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -22,6 +22,7 @@ #include <linux/crc32.h> #include <linux/jffs2.h> #include <linux/xattr.h> +#include <linux/posix_acl_xattr.h> #include <linux/mtd/mtd.h> #include "nodelist.h" /* -------- xdatum related functions ---------------- @@ -921,8 +922,8 @@ const struct xattr_handler *jffs2_xattr_handlers[] = { &jffs2_security_xattr_handler, #endif #ifdef CONFIG_JFFS2_FS_POSIX_ACL - &jffs2_acl_access_xattr_handler, - &jffs2_acl_default_xattr_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif &jffs2_trusted_xattr_handler, NULL @@ -942,10 +943,10 @@ static const struct xattr_handler *xprefix_to_handler(int xprefix) { #endif #ifdef CONFIG_JFFS2_FS_POSIX_ACL case JFFS2_XPREFIX_ACL_ACCESS: - ret = &jffs2_acl_access_xattr_handler; + ret = &posix_acl_access_xattr_handler; break; case JFFS2_XPREFIX_ACL_DEFAULT: - ret = &jffs2_acl_default_xattr_handler; + ret = &posix_acl_default_xattr_handler; break; #endif case JFFS2_XPREFIX_TRUSTED: diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index d254d6d35995..e973b85d6afd 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -72,7 +72,7 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type) return acl; } -static int jfs_set_acl(tid_t tid, struct inode *inode, int type, +static int __jfs_set_acl(tid_t tid, struct inode *inode, int type, struct posix_acl *acl) { char *ea_name; @@ -80,21 +80,22 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, int size = 0; char *value = NULL; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - switch(type) { - case ACL_TYPE_ACCESS: - ea_name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - ea_name = POSIX_ACL_XATTR_DEFAULT; - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - break; - default: - return -EINVAL; + switch (type) { + case ACL_TYPE_ACCESS: + ea_name = POSIX_ACL_XATTR_ACCESS; + rc = posix_acl_equiv_mode(acl, &inode->i_mode); + if (rc < 0) + return rc; + if (rc == 0) + acl = NULL; + break; + case ACL_TYPE_DEFAULT: + ea_name = POSIX_ACL_XATTR_DEFAULT; + break; + default: + return -EINVAL; } + if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_KERNEL); @@ -114,65 +115,43 @@ out: return rc; } +int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int rc; + tid_t tid; + + tid = txBegin(inode->i_sb, 0); + mutex_lock(&JFS_IP(inode)->commit_mutex); + rc = __jfs_set_acl(tid, inode, type, acl); + if (!rc) + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + mutex_unlock(&JFS_IP(inode)->commit_mutex); + return rc; +} + int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; int rc = 0; - if (S_ISLNK(inode->i_mode)) - return 0; + rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (rc) + return rc; - acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); + if (default_acl) { + rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); + posix_acl_release(default_acl); + } if (acl) { - if (S_ISDIR(inode->i_mode)) { - rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl); - if (rc) - goto cleanup; - } - rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (rc < 0) - goto cleanup; /* posix_acl_release(NULL) is no-op */ - if (rc > 0) - rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); -cleanup: + if (!rc) + rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); - } else - inode->i_mode &= ~current_umask(); + } JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | inode->i_mode; return rc; } - -int jfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int rc; - tid_t tid; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (rc) - return rc; - - tid = txBegin(inode->i_sb, 0); - mutex_lock(&JFS_IP(inode)->commit_mutex); - rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); - if (!rc) - rc = txCommit(tid, 1, &inode, 0); - txEnd(tid); - mutex_unlock(&JFS_IP(inode)->commit_mutex); - - posix_acl_release(acl); - return rc; -} diff --git a/fs/jfs/file.c b/fs/jfs/file.c index dd7442c58358..794da944d5cd 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -19,6 +19,7 @@ #include <linux/mm.h> #include <linux/fs.h> +#include <linux/posix_acl.h> #include <linux/quotaops.h> #include "jfs_incore.h" #include "jfs_inode.h" @@ -131,7 +132,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) mark_inode_dirty(inode); if (iattr->ia_valid & ATTR_MODE) - rc = jfs_acl_chmod(inode); + rc = posix_acl_chmod(inode, inode->i_mode); return rc; } @@ -143,6 +144,7 @@ const struct inode_operations jfs_file_inode_operations = { .setattr = jfs_setattr, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, + .set_acl = jfs_set_acl, #endif }; diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index ad84fe50ca9e..489f993b7b13 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -21,8 +21,8 @@ #ifdef CONFIG_JFS_POSIX_ACL struct posix_acl *jfs_get_acl(struct inode *inode, int type); +int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int jfs_init_acl(tid_t, struct inode *, struct inode *); -int jfs_acl_chmod(struct inode *inode); #else @@ -32,10 +32,5 @@ static inline int jfs_init_acl(tid_t tid, struct inode *inode, return 0; } -static inline int jfs_acl_chmod(struct inode *inode) -{ - return 0; -} - #endif #endif /* _H_JFS_ACL */ diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h index e9e100fd7c09..e8d717dabca3 100644 --- a/fs/jfs/jfs_xattr.h +++ b/fs/jfs/jfs_xattr.h @@ -61,6 +61,8 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); extern int jfs_removexattr(struct dentry *, const char *); +extern const struct xattr_handler *jfs_xattr_handlers[]; + #ifdef CONFIG_JFS_SECURITY extern int jfs_init_security(tid_t, struct inode *, struct inode *, const struct qstr *); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index aa8a3370631b..d59c7defb1ef 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1524,6 +1524,7 @@ const struct inode_operations jfs_dir_inode_operations = { .setattr = jfs_setattr, #ifdef CONFIG_JFS_POSIX_ACL .get_acl = jfs_get_acl, + .set_acl = jfs_set_acl, #endif }; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 6669aa2042c3..e2b7483444fd 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -44,6 +44,7 @@ #include "jfs_imap.h" #include "jfs_acl.h" #include "jfs_debug.h" +#include "jfs_xattr.h" MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); @@ -522,6 +523,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) */ sb->s_op = &jfs_super_operations; sb->s_export_op = &jfs_export_operations; + sb->s_xattr = jfs_xattr_handlers; #ifdef CONFIG_QUOTA sb->dq_op = &dquot_operations; sb->s_qcop = &dquot_quotactl_ops; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index d3472f4cd530..5324e4e2b992 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -666,81 +666,12 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf, } /* - * can_set_system_xattr - * - * This code is specific to the system.* namespace. It contains policy - * which doesn't belong in the main xattr codepath. - */ -static int can_set_system_xattr(struct inode *inode, const char *name, - const void *value, size_t value_len) -{ -#ifdef CONFIG_JFS_POSIX_ACL - struct posix_acl *acl; - int rc; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - /* - * POSIX_ACL_XATTR_ACCESS is tied to i_mode - */ - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, value_len); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - printk(KERN_ERR "posix_acl_from_xattr returned %d\n", - rc); - return rc; - } - if (acl) { - rc = posix_acl_equiv_mode(acl, &inode->i_mode); - posix_acl_release(acl); - if (rc < 0) { - printk(KERN_ERR - "posix_acl_equiv_mode returned %d\n", - rc); - return rc; - } - mark_inode_dirty(inode); - } - /* - * We're changing the ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_ACCESS); - - return 0; - } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, value_len); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - printk(KERN_ERR "posix_acl_from_xattr returned %d\n", - rc); - return rc; - } - posix_acl_release(acl); - - /* - * We're changing the default ACL. Get rid of the cached one - */ - forget_cached_acl(inode, ACL_TYPE_DEFAULT); - - return 0; - } -#endif /* CONFIG_JFS_POSIX_ACL */ - return -EOPNOTSUPP; -} - -/* * Most of the permission checking is done by xattr_permission in the vfs. - * The local file system is responsible for handling the system.* namespace. * We also need to verify that this is a namespace that we recognize. */ static int can_set_xattr(struct inode *inode, const char *name, const void *value, size_t value_len) { - if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) - return can_set_system_xattr(inode, name, value, value_len); - if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) { /* * This makes sure that we aren't trying to set an @@ -748,7 +679,7 @@ static int can_set_xattr(struct inode *inode, const char *name, * with "os2." */ if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN)) - return -EOPNOTSUPP; + return -EOPNOTSUPP; return 0; } @@ -913,6 +844,14 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, if ((rc = can_set_xattr(inode, name, value, value_len))) return rc; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_setxattr(dentry, name, value, value_len, flags); + if (value == NULL) { /* empty EA, do not remove */ value = ""; value_len = 0; @@ -986,6 +925,14 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, { int err; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_getxattr(dentry, name, data, buf_size); + if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { /* * skip past "os2." prefix @@ -1077,6 +1024,14 @@ int jfs_removexattr(struct dentry *dentry, const char *name) if ((rc = can_set_xattr(inode, name, NULL, 0))) return rc; + /* + * If this is a request for a synthetic attribute in the system.* + * namespace use the generic infrastructure to resolve a handler + * for it via sb->s_xattr. + */ + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return generic_removexattr(dentry, name); + tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); @@ -1088,6 +1043,19 @@ int jfs_removexattr(struct dentry *dentry, const char *name) return rc; } +/* + * List of handlers for synthetic system.* attributes. All real ondisk + * attributes are handled directly. + */ +const struct xattr_handler *jfs_xattr_handlers[] = { +#ifdef JFS_POSIX_ACL + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, +#endif + NULL, +}; + + #ifdef CONFIG_JFS_SECURITY static int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *fs_info) diff --git a/fs/mount.h b/fs/mount.h index d64c594be6c4..a17458ca6f29 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -74,7 +74,7 @@ static inline int mnt_has_parent(struct mount *mnt) static inline int is_mounted(struct vfsmount *mnt) { /* neither detached nor internal? */ - return !IS_ERR_OR_NULL(real_mount(mnt)); + return !IS_ERR_OR_NULL(real_mount(mnt)->mnt_ns); } extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); diff --git a/fs/namei.c b/fs/namei.c index 3531deebad30..bcb838e2e52f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -235,27 +235,9 @@ static int check_acl(struct inode *inode, int mask) return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); } - acl = get_cached_acl(inode, ACL_TYPE_ACCESS); - - /* - * A filesystem can force a ACL callback by just never filling the - * ACL cache. But normally you'd fill the cache either at inode - * instantiation time, or on the first ->get_acl call. - * - * If the filesystem doesn't have a get_acl() function at all, we'll - * just create the negative cache entry. - */ - if (acl == ACL_NOT_CACHED) { - if (inode->i_op->get_acl) { - acl = inode->i_op->get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } else { - set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); - return -EAGAIN; - } - } - + acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); if (acl) { int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 812154aff981..b266f734bd53 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1404,7 +1404,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, /* Expect a negative dentry */ BUG_ON(dentry->d_inode); - dfprintk(VFS, "NFS: atomic_open(%s/%ld), %pd\n", + dfprintk(VFS, "NFS: atomic_open(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); err = nfs_check_flags(open_flags); @@ -1594,7 +1594,7 @@ int nfs_create(struct inode *dir, struct dentry *dentry, int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT; int error; - dfprintk(VFS, "NFS: create(%s/%ld), %pd\n", + dfprintk(VFS, "NFS: create(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); attr.ia_mode = mode; @@ -1621,7 +1621,7 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) struct iattr attr; int status; - dfprintk(VFS, "NFS: mknod(%s/%ld), %pd\n", + dfprintk(VFS, "NFS: mknod(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); if (!new_valid_dev(rdev)) @@ -1650,7 +1650,7 @@ int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct iattr attr; int error; - dfprintk(VFS, "NFS: mkdir(%s/%ld), %pd\n", + dfprintk(VFS, "NFS: mkdir(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); attr.ia_valid = ATTR_MODE; @@ -1678,7 +1678,7 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry) { int error; - dfprintk(VFS, "NFS: rmdir(%s/%ld), %pd\n", + dfprintk(VFS, "NFS: rmdir(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); trace_nfs_rmdir_enter(dir, dentry); @@ -1747,7 +1747,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) int error; int need_rehash = 0; - dfprintk(VFS, "NFS: unlink(%s/%ld, %pd)\n", dir->i_sb->s_id, + dfprintk(VFS, "NFS: unlink(%s/%lu, %pd)\n", dir->i_sb->s_id, dir->i_ino, dentry); trace_nfs_unlink_enter(dir, dentry); @@ -1798,7 +1798,7 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) unsigned int pathlen = strlen(symname); int error; - dfprintk(VFS, "NFS: symlink(%s/%ld, %pd, %s)\n", dir->i_sb->s_id, + dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry, symname); if (pathlen > PAGE_SIZE) @@ -1821,7 +1821,7 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); trace_nfs_symlink_exit(dir, dentry, error); if (error != 0) { - dfprintk(VFS, "NFS: symlink(%s/%ld, %pd, %s) error %d\n", + dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s) error %d\n", dir->i_sb->s_id, dir->i_ino, dentry, symname, error); d_drop(dentry); @@ -2304,7 +2304,7 @@ out: if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) res = -EACCES; - dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", + dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n", inode->i_sb->s_id, inode->i_ino, mask, res); return res; out_notsup: diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index d71d66c9e0a1..b8797ae6831f 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -222,14 +222,31 @@ out: * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust * the iocb is still valid here if this is a synchronous request. */ -static void nfs_direct_complete(struct nfs_direct_req *dreq) +static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) { + struct inode *inode = dreq->inode; + + if (dreq->iocb && write) { + loff_t pos = dreq->iocb->ki_pos + dreq->count; + + spin_lock(&inode->i_lock); + if (i_size_read(inode) < pos) + i_size_write(inode, pos); + spin_unlock(&inode->i_lock); + } + + if (write) + nfs_zap_mapping(inode, inode->i_mapping); + + inode_dio_done(inode); + if (dreq->iocb) { long res = (long) dreq->error; if (!res) res = (long) dreq->count; aio_complete(dreq->iocb, res, 0); } + complete_all(&dreq->completion); nfs_direct_req_release(dreq); @@ -237,9 +254,9 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) static void nfs_direct_readpage_release(struct nfs_page *req) { - dprintk("NFS: direct read done (%s/%lld %d@%lld)\n", + dprintk("NFS: direct read done (%s/%llu %d@%lld)\n", req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); nfs_release_request(req); @@ -272,7 +289,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) } out_put: if (put_dreq(dreq)) - nfs_direct_complete(dreq); + nfs_direct_complete(dreq, false); hdr->release(hdr); } @@ -402,6 +419,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, loff_t pos, bool uio) { struct nfs_pageio_descriptor desc; + struct inode *inode = dreq->inode; ssize_t result = -EINVAL; size_t requested_bytes = 0; unsigned long seg; @@ -410,6 +428,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, &nfs_direct_read_completion_ops); get_dreq(dreq); desc.pg_dreq = dreq; + atomic_inc(&inode->i_dio_count); for (seg = 0; seg < nr_segs; seg++) { const struct iovec *vec = &iov[seg]; @@ -429,26 +448,69 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, * generic layer handle the completion. */ if (requested_bytes == 0) { + inode_dio_done(inode); nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } if (put_dreq(dreq)) - nfs_direct_complete(dreq); + nfs_direct_complete(dreq, false); return 0; } -static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos, bool uio) +/** + * nfs_file_direct_read - file direct read operation for NFS files + * @iocb: target I/O control block + * @iov: vector of user buffers into which to read data + * @nr_segs: size of iov vector + * @pos: byte offset in file where reading starts + * + * We use this function for direct reads instead of calling + * generic_file_aio_read() in order to avoid gfar's check to see if + * the request starts before the end of the file. For that check + * to work, we must generate a GETATTR before each direct read, and + * even then there is a window between the GETATTR and the subsequent + * READ where the file size could change. Our preference is simply + * to do all reads the application wants, and the server will take + * care of managing the end of file boundary. + * + * This function also eliminates unnecessarily updating the file's + * atime locally, as the NFS server sets the file's atime, and this + * client must read the updated atime from the server back into its + * cache. + */ +ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos, bool uio) { - ssize_t result = -ENOMEM; - struct inode *inode = iocb->ki_filp->f_mapping->host; + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; struct nfs_direct_req *dreq; struct nfs_lock_context *l_ctx; + ssize_t result = -EINVAL; + size_t count; + count = iov_length(iov, nr_segs); + nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); + + dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n", + file, count, (long long) pos); + + result = 0; + if (!count) + goto out; + + mutex_lock(&inode->i_mutex); + result = nfs_sync_mapping(mapping); + if (result) + goto out_unlock; + + task_io_account_read(count); + + result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (dreq == NULL) - goto out; + goto out_unlock; dreq->inode = inode; dreq->bytes_left = iov_length(iov, nr_segs); @@ -464,20 +526,26 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, NFS_I(inode)->read_io += iov_length(iov, nr_segs); result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio); - if (!result) + + mutex_unlock(&inode->i_mutex); + + if (!result) { result = nfs_direct_wait(dreq); + if (result > 0) + iocb->ki_pos = pos + result; + } + + nfs_direct_req_release(dreq); + return result; + out_release: nfs_direct_req_release(dreq); +out_unlock: + mutex_unlock(&inode->i_mutex); out: return result; } -static void nfs_inode_dio_write_done(struct inode *inode) -{ - nfs_zap_mapping(inode, inode->i_mapping); - inode_dio_done(inode); -} - #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) { @@ -593,8 +661,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) nfs_direct_write_reschedule(dreq); break; default: - nfs_inode_dio_write_done(dreq->inode); - nfs_direct_complete(dreq); + nfs_direct_complete(dreq, true); } } @@ -610,8 +677,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) { - nfs_inode_dio_write_done(inode); - nfs_direct_complete(dreq); + nfs_direct_complete(dreq, true); } #endif @@ -842,93 +908,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, return 0; } -static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos, - size_t count, bool uio) -{ - ssize_t result = -ENOMEM; - struct inode *inode = iocb->ki_filp->f_mapping->host; - struct nfs_direct_req *dreq; - struct nfs_lock_context *l_ctx; - - dreq = nfs_direct_req_alloc(); - if (!dreq) - goto out; - - dreq->inode = inode; - dreq->bytes_left = count; - dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); - l_ctx = nfs_get_lock_context(dreq->ctx); - if (IS_ERR(l_ctx)) { - result = PTR_ERR(l_ctx); - goto out_release; - } - dreq->l_ctx = l_ctx; - if (!is_sync_kiocb(iocb)) - dreq->iocb = iocb; - - result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio); - if (!result) - result = nfs_direct_wait(dreq); -out_release: - nfs_direct_req_release(dreq); -out: - return result; -} - -/** - * nfs_file_direct_read - file direct read operation for NFS files - * @iocb: target I/O control block - * @iov: vector of user buffers into which to read data - * @nr_segs: size of iov vector - * @pos: byte offset in file where reading starts - * - * We use this function for direct reads instead of calling - * generic_file_aio_read() in order to avoid gfar's check to see if - * the request starts before the end of the file. For that check - * to work, we must generate a GETATTR before each direct read, and - * even then there is a window between the GETATTR and the subsequent - * READ where the file size could change. Our preference is simply - * to do all reads the application wants, and the server will take - * care of managing the end of file boundary. - * - * This function also eliminates unnecessarily updating the file's - * atime locally, as the NFS server sets the file's atime, and this - * client must read the updated atime from the server back into its - * cache. - */ -ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos, bool uio) -{ - ssize_t retval = -EINVAL; - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - size_t count; - - count = iov_length(iov, nr_segs); - nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); - - dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n", - file, count, (long long) pos); - - retval = 0; - if (!count) - goto out; - - retval = nfs_sync_mapping(mapping); - if (retval) - goto out; - - task_io_account_read(count); - - retval = nfs_direct_read(iocb, iov, nr_segs, pos, uio); - if (retval > 0) - iocb->ki_pos = pos + retval; - -out: - return retval; -} - /** * nfs_file_direct_write - file direct write operation for NFS files * @iocb: target I/O control block @@ -954,46 +933,96 @@ out: ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos, bool uio) { - ssize_t retval = -EINVAL; + ssize_t result = -EINVAL; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + struct nfs_direct_req *dreq; + struct nfs_lock_context *l_ctx; + loff_t end; size_t count; count = iov_length(iov, nr_segs); + end = (pos + count - 1) >> PAGE_CACHE_SHIFT; + nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", file, count, (long long) pos); - retval = generic_write_checks(file, &pos, &count, 0); - if (retval) + result = generic_write_checks(file, &pos, &count, 0); + if (result) goto out; - retval = -EINVAL; + result = -EINVAL; if ((ssize_t) count < 0) goto out; - retval = 0; + result = 0; if (!count) goto out; - retval = nfs_sync_mapping(mapping); - if (retval) - goto out; + mutex_lock(&inode->i_mutex); + + result = nfs_sync_mapping(mapping); + if (result) + goto out_unlock; + + if (mapping->nrpages) { + result = invalidate_inode_pages2_range(mapping, + pos >> PAGE_CACHE_SHIFT, end); + if (result) + goto out_unlock; + } task_io_account_write(count); - retval = nfs_direct_write(iocb, iov, nr_segs, pos, count, uio); - if (retval > 0) { - struct inode *inode = mapping->host; + result = -ENOMEM; + dreq = nfs_direct_req_alloc(); + if (!dreq) + goto out_unlock; - iocb->ki_pos = pos + retval; - spin_lock(&inode->i_lock); - if (i_size_read(inode) < iocb->ki_pos) - i_size_write(inode, iocb->ki_pos); - spin_unlock(&inode->i_lock); + dreq->inode = inode; + dreq->bytes_left = count; + dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); + l_ctx = nfs_get_lock_context(dreq->ctx); + if (IS_ERR(l_ctx)) { + result = PTR_ERR(l_ctx); + goto out_release; + } + dreq->l_ctx = l_ctx; + if (!is_sync_kiocb(iocb)) + dreq->iocb = iocb; + + result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio); + + if (mapping->nrpages) { + invalidate_inode_pages2_range(mapping, + pos >> PAGE_CACHE_SHIFT, end); } + + mutex_unlock(&inode->i_mutex); + + if (!result) { + result = nfs_direct_wait(dreq); + if (result > 0) { + struct inode *inode = mapping->host; + + iocb->ki_pos = pos + result; + spin_lock(&inode->i_lock); + if (i_size_read(inode) < iocb->ki_pos) + i_size_write(inode, iocb->ki_pos); + spin_unlock(&inode->i_lock); + } + } + nfs_direct_req_release(dreq); + return result; + +out_release: + nfs_direct_req_release(dreq); +out_unlock: + mutex_unlock(&inode->i_mutex); out: - return retval; + return result; } /** diff --git a/fs/nfs/file.c b/fs/nfs/file.c index e2fcacf07de3..5bb790a69c71 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -354,7 +354,7 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, struct page *page; int once_thru = 0; - dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%ld), %u@%lld)\n", + dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n", file, mapping->host->i_ino, len, (long long) pos); start: @@ -395,7 +395,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, struct nfs_open_context *ctx = nfs_file_open_context(file); int status; - dfprintk(PAGECACHE, "NFS: write_end(%pD2(%ld), %u@%lld)\n", + dfprintk(PAGECACHE, "NFS: write_end(%pD2(%lu), %u@%lld)\n", file, mapping->host->i_ino, len, (long long) pos); /* @@ -585,7 +585,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) int ret = VM_FAULT_NOPAGE; struct address_space *mapping; - dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%ld), offset %lld)\n", + dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n", filp, filp->f_mapping->host->i_ino, (long long)page_offset(page)); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 00ad1c2b217d..ea00b34ff071 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -458,9 +458,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st unlock_new_inode(inode); } else nfs_refresh_inode(inode, fattr); - dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", + dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n", inode->i_sb->s_id, - (long long)NFS_FILEID(inode), + (unsigned long long)NFS_FILEID(inode), nfs_display_fhandle_hash(fh), atomic_read(&inode->i_count)); @@ -870,8 +870,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) struct nfs_fattr *fattr = NULL; struct nfs_inode *nfsi = NFS_I(inode); - dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", - inode->i_sb->s_id, (long long)NFS_FILEID(inode)); + dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n", + inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode)); trace_nfs_revalidate_inode_enter(inode); @@ -895,9 +895,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label); if (status != 0) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n", inode->i_sb->s_id, - (long long)NFS_FILEID(inode), status); + (unsigned long long)NFS_FILEID(inode), status); if (status == -ESTALE) { nfs_zap_caches(inode); if (!S_ISDIR(inode->i_mode)) @@ -908,9 +908,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) status = nfs_refresh_inode(inode, fattr); if (status) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n", inode->i_sb->s_id, - (long long)NFS_FILEID(inode), status); + (unsigned long long)NFS_FILEID(inode), status); goto err_out; } @@ -919,9 +919,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) nfs_setsecurity(inode, fattr, label); - dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", + dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n", inode->i_sb->s_id, - (long long)NFS_FILEID(inode)); + (unsigned long long)NFS_FILEID(inode)); err_out: nfs4_label_free(label); @@ -985,8 +985,9 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); nfs_fscache_wait_on_invalidate(inode); - dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", - inode->i_sb->s_id, (long long)NFS_FILEID(inode)); + dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n", + inode->i_sb->s_id, + (unsigned long long)NFS_FILEID(inode)); return 0; } @@ -1282,12 +1283,28 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); } +/* + * Don't trust the change_attribute, mtime, ctime or size if + * a pnfs LAYOUTCOMMIT is outstanding + */ +static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode, + struct nfs_fattr *fattr) +{ + if (pnfs_layoutcommit_outstanding(inode)) + fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE | + NFS_ATTR_FATTR_MTIME | + NFS_ATTR_FATTR_CTIME | + NFS_ATTR_FATTR_SIZE); +} + static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) { int ret; trace_nfs_refresh_inode_enter(inode); + nfs_inode_attrs_handle_layoutcommit(inode, fattr); + if (nfs_inode_attrs_need_update(inode, fattr)) ret = nfs_update_inode(inode, fattr); else @@ -1434,7 +1451,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) unsigned long now = jiffies; unsigned long save_cache_validity; - dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n", + dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", __func__, inode->i_sb->s_id, inode->i_ino, nfs_display_fhandle_hash(NFS_FH(inode)), atomic_read(&inode->i_count), fattr->valid); @@ -1455,7 +1472,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) /* * Big trouble! The inode has become a different object. */ - printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n", + printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n", __func__, inode->i_ino, inode->i_mode, fattr->mode); goto out_err; } @@ -1517,8 +1534,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) if (new_isize != cur_isize) { /* Do we perhaps have any outstanding writes, or has * the file grown beyond our last write? */ - if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) || - new_isize > cur_isize) { + if ((nfsi->npages == 0) || new_isize > cur_isize) { i_size_write(inode, new_isize); invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } @@ -1641,10 +1657,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb) return NULL; nfsi->flags = 0UL; nfsi->cache_validity = 0UL; -#ifdef CONFIG_NFS_V3_ACL - nfsi->acl_access = ERR_PTR(-EAGAIN); - nfsi->acl_default = ERR_PTR(-EAGAIN); -#endif #if IS_ENABLED(CONFIG_NFS_V4) nfsi->nfs4_acl = NULL; #endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 4a1aafba6a20..9a5ca03fa539 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -10,179 +10,7 @@ #define NFSDBG_FACILITY NFSDBG_PROC -ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int pos=0, len=0; - -# define output(s) do { \ - if (pos + sizeof(s) <= size) { \ - memcpy(buffer + pos, s, sizeof(s)); \ - pos += sizeof(s); \ - } \ - len += sizeof(s); \ - } while(0) - - acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - output("system.posix_acl_access"); - posix_acl_release(acl); - } - - if (S_ISDIR(inode->i_mode)) { - acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - output("system.posix_acl_default"); - posix_acl_release(acl); - } - } - -# undef output - - if (!buffer || len <= size) - return len; - return -ERANGE; -} - -ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int type, error = 0; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - acl = nfs3_proc_getacl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - if (type == ACL_TYPE_ACCESS && acl->a_count == 0) - error = -ENODATA; - else - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - } else - error = -ENODATA; - - return error; -} - -int nfs3_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; - int type, error; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - error = nfs3_proc_setacl(inode, type, acl); - posix_acl_release(acl); - - return error; -} - -int nfs3_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = dentry->d_inode; - int type; - - if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) - type = ACL_TYPE_ACCESS; - else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) - type = ACL_TYPE_DEFAULT; - else - return -EOPNOTSUPP; - - return nfs3_proc_setacl(inode, type, NULL); -} - -static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) -{ - if (!IS_ERR(nfsi->acl_access)) { - posix_acl_release(nfsi->acl_access); - nfsi->acl_access = ERR_PTR(-EAGAIN); - } - if (!IS_ERR(nfsi->acl_default)) { - posix_acl_release(nfsi->acl_default); - nfsi->acl_default = ERR_PTR(-EAGAIN); - } -} - -void nfs3_forget_cached_acls(struct inode *inode) -{ - dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, - inode->i_ino); - spin_lock(&inode->i_lock); - __nfs3_forget_cached_acls(NFS_I(inode)); - spin_unlock(&inode->i_lock); -} - -static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) -{ - struct nfs_inode *nfsi = NFS_I(inode); - struct posix_acl *acl = ERR_PTR(-EINVAL); - - spin_lock(&inode->i_lock); - switch(type) { - case ACL_TYPE_ACCESS: - acl = nfsi->acl_access; - break; - - case ACL_TYPE_DEFAULT: - acl = nfsi->acl_default; - break; - - default: - goto out; - } - if (IS_ERR(acl)) - acl = ERR_PTR(-EAGAIN); - else - acl = posix_acl_dup(acl); -out: - spin_unlock(&inode->i_lock); - dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, - inode->i_ino, type, acl); - return acl; -} - -static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, - struct posix_acl *dfacl) -{ - struct nfs_inode *nfsi = NFS_I(inode); - - dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, - inode->i_ino, acl, dfacl); - spin_lock(&inode->i_lock); - __nfs3_forget_cached_acls(NFS_I(inode)); - if (!IS_ERR(acl)) - nfsi->acl_access = posix_acl_dup(acl); - if (!IS_ERR(dfacl)) - nfsi->acl_default = posix_acl_dup(dfacl); - spin_unlock(&inode->i_lock); -} - -struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) +struct posix_acl *nfs3_get_acl(struct inode *inode, int type) { struct nfs_server *server = NFS_SERVER(inode); struct page *pages[NFSACL_MAXPAGES] = { }; @@ -198,7 +26,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) .rpc_argp = &args, .rpc_resp = &res, }; - struct posix_acl *acl; int status, count; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) @@ -207,10 +34,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); - acl = nfs3_get_cached_acl(inode, type); - if (acl != ERR_PTR(-EAGAIN)) - return acl; - acl = NULL; /* * Only get the access acl when explicitly requested: We don't @@ -257,40 +80,41 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) } if (res.acl_access != NULL) { - if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { + if (posix_acl_equiv_mode(res.acl_access, NULL) || + res.acl_access->a_count == 0) { posix_acl_release(res.acl_access); res.acl_access = NULL; } } - nfs3_cache_acls(inode, - (res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL), - (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL)); - switch(type) { - case ACL_TYPE_ACCESS: - acl = res.acl_access; - res.acl_access = NULL; - break; + if (res.mask & NFS_ACL) + set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access); + else + forget_cached_acl(inode, ACL_TYPE_ACCESS); - case ACL_TYPE_DEFAULT: - acl = res.acl_default; - res.acl_default = NULL; + if (res.mask & NFS_DFACL) + set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default); + else + forget_cached_acl(inode, ACL_TYPE_DEFAULT); + + nfs_free_fattr(res.fattr); + if (type == ACL_TYPE_ACCESS) { + posix_acl_release(res.acl_default); + return res.acl_access; + } else { + posix_acl_release(res.acl_access); + return res.acl_default; } getout: posix_acl_release(res.acl_access); posix_acl_release(res.acl_default); nfs_free_fattr(res.fattr); - - if (status != 0) { - posix_acl_release(acl); - acl = ERR_PTR(status); - } - return acl; + return ERR_PTR(status); } -static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, - struct posix_acl *dfacl) +int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_fattr *fattr; @@ -353,7 +177,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, switch (status) { case 0: status = nfs_refresh_inode(inode, fattr); - nfs3_cache_acls(inode, acl, dfacl); + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + set_cached_acl(inode, ACL_TYPE_DEFAULT, dfacl); break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: @@ -373,33 +198,27 @@ out: return status; } -int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) +int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type) { struct posix_acl *alloc = NULL, *dfacl = NULL; int status; if (S_ISDIR(inode->i_mode)) { switch(type) { - case ACL_TYPE_ACCESS: - alloc = dfacl = nfs3_proc_getacl(inode, - ACL_TYPE_DEFAULT); - if (IS_ERR(alloc)) - goto fail; - break; - - case ACL_TYPE_DEFAULT: - dfacl = acl; - alloc = acl = nfs3_proc_getacl(inode, - ACL_TYPE_ACCESS); - if (IS_ERR(alloc)) - goto fail; - break; - - default: - return -EINVAL; + case ACL_TYPE_ACCESS: + alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT); + if (IS_ERR(alloc)) + goto fail; + break; + + case ACL_TYPE_DEFAULT: + dfacl = acl; + alloc = acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(alloc)) + goto fail; + break; } - } else if (type != ACL_TYPE_ACCESS) - return -EINVAL; + } if (acl == NULL) { alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); @@ -417,24 +236,24 @@ fail: int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, umode_t mode) { - struct posix_acl *dfacl, *acl; - int error = 0; + struct posix_acl *default_acl, *acl; + int error; - dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(dfacl)) { - error = PTR_ERR(dfacl); + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) return (error == -EOPNOTSUPP) ? 0 : error; - } - if (!dfacl) - return 0; - acl = posix_acl_dup(dfacl); - error = posix_acl_create(&acl, GFP_KERNEL, &mode); - if (error < 0) - goto out_release_dfacl; - error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? - dfacl : NULL); - posix_acl_release(acl); -out_release_dfacl: - posix_acl_release(dfacl); + + error = nfs3_proc_setacls(inode, acl, default_acl); + + if (acl) + posix_acl_release(acl); + if (default_acl) + posix_acl_release(default_acl); return error; } + +const struct xattr_handler *nfs3_xattr_handlers[] = { + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, + NULL, +}; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 01b6f6a49d16..d2255d705421 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -317,8 +317,8 @@ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call create %pd\n", dentry); @@ -340,7 +340,9 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, data->arg.create.verifier[1] = cpu_to_be32(current->pid); } - sattr->ia_mode &= ~current_umask(); + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; for (;;) { status = nfs3_do_create(dir, dentry, data); @@ -366,7 +368,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, } if (status != 0) - goto out; + goto out_release_acls; /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ @@ -385,9 +387,14 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) - goto out; + goto out_release_acls; } - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply create: %d\n", status); @@ -572,18 +579,20 @@ out: static int nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mkdir %pd\n", dentry); - sattr->ia_mode &= ~current_umask(); - data = nfs3_alloc_createdata(); if (data == NULL) goto out; + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; + data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; data->arg.mkdir.fh = NFS_FH(dir); data->arg.mkdir.name = dentry->d_name.name; @@ -592,9 +601,13 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) status = nfs3_do_create(dir, dentry, data); if (status != 0) - goto out; + goto out_release_acls; - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mkdir: %d\n", status); @@ -691,19 +704,21 @@ static int nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { + struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; - umode_t mode = sattr->ia_mode; int status = -ENOMEM; dprintk("NFS call mknod %pd %u:%u\n", dentry, MAJOR(rdev), MINOR(rdev)); - sattr->ia_mode &= ~current_umask(); - data = nfs3_alloc_createdata(); if (data == NULL) goto out; + status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); + if (status) + goto out; + data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; data->arg.mknod.fh = NFS_FH(dir); data->arg.mknod.name = dentry->d_name.name; @@ -731,8 +746,13 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, status = nfs3_do_create(dir, dentry, data); if (status != 0) - goto out; - status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); + goto out_release_acls; + + status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + +out_release_acls: + posix_acl_release(acl); + posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mknod: %d\n", status); @@ -904,20 +924,28 @@ static const struct inode_operations nfs3_dir_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, - .listxattr = nfs3_listxattr, - .getxattr = nfs3_getxattr, - .setxattr = nfs3_setxattr, - .removexattr = nfs3_removexattr, + .listxattr = generic_listxattr, + .getxattr = generic_getxattr, + .setxattr = generic_setxattr, + .removexattr = generic_removexattr, +#ifdef CONFIG_NFS_V3_ACL + .get_acl = nfs3_get_acl, + .set_acl = nfs3_set_acl, +#endif }; static const struct inode_operations nfs3_file_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, - .listxattr = nfs3_listxattr, - .getxattr = nfs3_getxattr, - .setxattr = nfs3_setxattr, - .removexattr = nfs3_removexattr, + .listxattr = generic_listxattr, + .getxattr = generic_getxattr, + .setxattr = generic_setxattr, + .removexattr = generic_removexattr, +#ifdef CONFIG_NFS_V3_ACL + .get_acl = nfs3_get_acl, + .set_acl = nfs3_set_acl, +#endif }; const struct nfs_rpc_ops nfs_v3_clientops = { @@ -965,7 +993,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare, .commit_done = nfs3_commit_done, .lock = nfs3_proc_lock, - .clear_acl_cache = nfs3_forget_cached_acls, + .clear_acl_cache = forget_all_cached_acls, .close_context = nfs_close_context, .have_delegation = nfs3_have_delegation, .return_delegation = nfs3_return_delegation, diff --git a/fs/nfs/nfs3super.c b/fs/nfs/nfs3super.c index cc471c725230..d6a98949af19 100644 --- a/fs/nfs/nfs3super.c +++ b/fs/nfs/nfs3super.c @@ -12,6 +12,9 @@ static struct nfs_subversion nfs_v3 = { .rpc_vers = &nfs_version3, .rpc_ops = &nfs_v3_clientops, .sops = &nfs_sops, +#ifdef CONFIG_NFS_V3_ACL + .xattr = nfs3_xattr_handlers, +#endif }; static int __init init_nfs_v3(void) diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index b4a160a405ce..73d4ecda1e36 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -10,6 +10,7 @@ #include <linux/sunrpc/auth.h> #include <linux/sunrpc/xprt.h> #include <linux/sunrpc/bc_xprt.h> +#include <linux/sunrpc/rpc_pipe_fs.h> #include "internal.h" #include "callback.h" #include "delegation.h" @@ -370,7 +371,11 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); - error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); + + error = -EINVAL; + if (gssd_running(clp->cl_net)) + error = nfs_create_rpc_client(clp, timeparms, + RPC_AUTH_GSS_KRB5I); if (error == -EINVAL) error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); if (error < 0) @@ -409,13 +414,11 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, error = nfs4_discover_server_trunking(clp, &old); if (error < 0) goto error; - nfs_put_client(clp); - if (clp != old) { - clp->cl_preserve_clid = true; - clp = old; - } - return clp; + if (clp != old) + clp->cl_preserve_clid = true; + nfs_put_client(clp); + return old; error: nfs_mark_client_ready(clp, error); @@ -493,9 +496,10 @@ int nfs40_walk_client_list(struct nfs_client *new, prev = pos; status = nfs_wait_client_init_complete(pos); - spin_lock(&nn->nfs_client_lock); if (status < 0) - continue; + goto out; + status = -NFS4ERR_STALE_CLIENTID; + spin_lock(&nn->nfs_client_lock); } if (pos->cl_cons_state != NFS_CS_READY) continue; @@ -633,7 +637,8 @@ int nfs41_walk_client_list(struct nfs_client *new, } spin_lock(&nn->nfs_client_lock); if (status < 0) - continue; + break; + status = -NFS4ERR_STALE_CLIENTID; } if (pos->cl_cons_state != NFS_CS_READY) continue; diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index b86464ba25e1..03fd8be8c0c5 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -91,10 +91,10 @@ static void filelayout_reset_write(struct nfs_write_data *data) if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { dprintk("%s Reset task %5u for i/o through MDS " - "(req %s/%lld, %u bytes @ offset %llu)\n", __func__, + "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, data->task.tk_pid, hdr->inode->i_sb->s_id, - (long long)NFS_FILEID(hdr->inode), + (unsigned long long)NFS_FILEID(hdr->inode), data->args.count, (unsigned long long)data->args.offset); @@ -112,10 +112,10 @@ static void filelayout_reset_read(struct nfs_read_data *data) if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { dprintk("%s Reset task %5u for i/o through MDS " - "(req %s/%lld, %u bytes @ offset %llu)\n", __func__, + "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, data->task.tk_pid, hdr->inode->i_sb->s_id, - (long long)NFS_FILEID(hdr->inode), + (unsigned long long)NFS_FILEID(hdr->inode), data->args.count, (unsigned long long)data->args.offset); @@ -1216,17 +1216,17 @@ static void filelayout_recover_commit_reqs(struct list_head *dst, struct pnfs_commit_bucket *b; int i; - /* NOTE cinfo->lock is NOT held, relying on fact that this is - * only called on single thread per dreq. - * Can't take the lock because need to do pnfs_put_lseg - */ + spin_lock(cinfo->lock); for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { if (transfer_commit_list(&b->written, dst, cinfo, 0)) { + spin_unlock(cinfo->lock); pnfs_put_lseg(b->wlseg); b->wlseg = NULL; + spin_lock(cinfo->lock); } } cinfo->ds->nwritten = 0; + spin_unlock(cinfo->lock); } static unsigned int diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index c7c295e556ed..efac602edb37 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -95,7 +95,7 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) b6 = (struct sockaddr_in6 *)addr2; /* LINKLOCAL addresses must have matching scope_id */ - if (ipv6_addr_scope(&a6->sin6_addr) == + if (ipv6_addr_src_scope(&a6->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && a6->sin6_scope_id != b6->sin6_scope_id) return false; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 15052b81df42..a1965329a12c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7409,9 +7409,9 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) struct nfs_server *server = NFS_SERVER(inode); struct pnfs_layout_hdr *lo; struct nfs4_state *state = NULL; - unsigned long timeo, giveup; + unsigned long timeo, now, giveup; - dprintk("--> %s\n", __func__); + dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); if (!nfs41_sequence_done(task, &lgp->res.seq_res)) goto out; @@ -7419,12 +7419,38 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) switch (task->tk_status) { case 0: goto out; + /* + * NFS4ERR_LAYOUTTRYLATER is a conflict with another client + * (or clients) writing to the same RAID stripe + */ case -NFS4ERR_LAYOUTTRYLATER: + /* + * NFS4ERR_RECALLCONFLICT is when conflict with self (must recall + * existing layout before getting a new one). + */ case -NFS4ERR_RECALLCONFLICT: timeo = rpc_get_timeout(task->tk_client); giveup = lgp->args.timestamp + timeo; - if (time_after(giveup, jiffies)) - task->tk_status = -NFS4ERR_DELAY; + now = jiffies; + if (time_after(giveup, now)) { + unsigned long delay; + + /* Delay for: + * - Not less then NFS4_POLL_RETRY_MIN. + * - One last time a jiffie before we give up + * - exponential backoff (time_now minus start_attempt) + */ + delay = max_t(unsigned long, NFS4_POLL_RETRY_MIN, + min((giveup - now - 1), + now - lgp->args.timestamp)); + + dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", + __func__, delay); + rpc_delay(task, delay); + task->tk_status = 0; + rpc_restart_call_prepare(task); + goto out; /* Do not call nfs4_async_handle_error() */ + } break; case -NFS4ERR_EXPIRED: case -NFS4ERR_BAD_STATEID: @@ -7780,10 +7806,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) case -NFS4ERR_BADLAYOUT: /* no layout */ case -NFS4ERR_GRACE: /* loca_recalim always false */ task->tk_status = 0; - break; case 0: - nfs_post_op_update_inode_force_wcc(data->args.inode, - data->res.fattr); break; default: if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { @@ -7798,6 +7821,8 @@ static void nfs4_layoutcommit_release(void *calldata) struct nfs4_layoutcommit_data *data = calldata; pnfs_cleanup_layoutcommit(data); + nfs_post_op_update_inode_force_wcc(data->args.inode, + data->res.fattr); put_rpccred(data->cred); kfree(data); } @@ -7920,7 +7945,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, switch (err) { case 0: case -NFS4ERR_WRONGSEC: - case -NFS4ERR_NOTSUPP: + case -ENOTSUPP: goto out; default: err = nfs4_handle_exception(server, err, &exception); @@ -7954,7 +7979,7 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, * Fall back on "guess and check" method if * the server doesn't support SECINFO_NO_NAME */ - if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) { + if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) { err = nfs4_find_root_sec(server, fhandle, info); goto out_freepage; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 059c01b67a71..e5be72518bd7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1071,7 +1071,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid) /* * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or * failed with a seqid incrementing error - - * see comments nfs_fs.h:seqid_mutating_error() + * see comments nfs4.h:seqid_mutating_error() */ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) { @@ -1116,7 +1116,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) /* * Increment the seqid if the LOCK/LOCKU succeeded, or * failed with a seqid incrementing error - - * see comments nfs_fs.h:seqid_mutating_error() + * see comments nfs4.h:seqid_mutating_error() */ void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) { diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 65ab0a0ca1c4..808f29574412 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -77,17 +77,9 @@ static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc) { int ret = nfs_write_inode(inode, wbc); - if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { - int status; - bool sync = true; - - if (wbc->sync_mode == WB_SYNC_NONE) - sync = false; - - status = pnfs_layoutcommit_inode(inode, sync); - if (status < 0) - return status; - } + if (ret == 0) + ret = pnfs_layoutcommit_inode(inode, + wbc->sync_mode == WB_SYNC_ALL); return ret; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5be2868c02f1..8c21d69a9dc1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3097,7 +3097,8 @@ out_overflow: return -EIO; } -static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, + int *nfs_retval) { __be32 *p; uint32_t opnum; @@ -3107,19 +3108,32 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) if (unlikely(!p)) goto out_overflow; opnum = be32_to_cpup(p++); - if (opnum != expected) { - dprintk("nfs: Server returned operation" - " %d but we issued a request for %d\n", - opnum, expected); - return -EIO; - } + if (unlikely(opnum != expected)) + goto out_bad_operation; nfserr = be32_to_cpup(p); - if (nfserr != NFS_OK) - return nfs4_stat_to_errno(nfserr); - return 0; + if (nfserr == NFS_OK) + *nfs_retval = 0; + else + *nfs_retval = nfs4_stat_to_errno(nfserr); + return true; +out_bad_operation: + dprintk("nfs: Server returned operation" + " %d but we issued a request for %d\n", + opnum, expected); + *nfs_retval = -EREMOTEIO; + return false; out_overflow: print_overflow_msg(__func__, xdr); - return -EIO; + *nfs_retval = -EIO; + return false; +} + +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +{ + int retval; + + __decode_op_hdr(xdr, expected, &retval); + return retval; } /* Dummy routine */ @@ -5001,11 +5015,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) uint32_t savewords, bmlen, i; int status; - status = decode_op_hdr(xdr, OP_OPEN); - if (status != -EIO) - nfs_increment_open_seqid(status, res->seqid); - if (!status) - status = decode_stateid(xdr, &res->stateid); + if (!__decode_op_hdr(xdr, OP_OPEN, &status)) + return status; + nfs_increment_open_seqid(status, res->seqid); + if (status) + return status; + status = decode_stateid(xdr, &res->stateid); if (unlikely(status)) return status; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index d75d938d36cb..4755858e37a0 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1790,6 +1790,15 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) } EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); +static void pnfs_clear_layoutcommitting(struct inode *inode) +{ + unsigned long *bitlock = &NFS_I(inode)->flags; + + clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); + smp_mb__after_clear_bit(); + wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); +} + /* * There can be multiple RW segments. */ @@ -1807,7 +1816,6 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) { struct pnfs_layout_segment *lseg, *tmp; - unsigned long *bitlock = &NFS_I(inode)->flags; /* Matched by references in pnfs_set_layoutcommit */ list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { @@ -1815,9 +1823,7 @@ static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *lis pnfs_put_lseg(lseg); } - clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); - wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); + pnfs_clear_layoutcommitting(inode); } void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) @@ -1881,43 +1887,37 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) struct nfs4_layoutcommit_data *data; struct nfs_inode *nfsi = NFS_I(inode); loff_t end_pos; - int status = 0; + int status; - dprintk("--> %s inode %lu\n", __func__, inode->i_ino); - - if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) + if (!pnfs_layoutcommit_outstanding(inode)) return 0; - /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ - data = kzalloc(sizeof(*data), GFP_NOFS); - if (!data) { - status = -ENOMEM; - goto out; - } - - if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) - goto out_free; + dprintk("--> %s inode %lu\n", __func__, inode->i_ino); + status = -EAGAIN; if (test_and_set_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags)) { - if (!sync) { - status = -EAGAIN; - goto out_free; - } - status = wait_on_bit_lock(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING, - nfs_wait_bit_killable, TASK_KILLABLE); + if (!sync) + goto out; + status = wait_on_bit_lock(&nfsi->flags, + NFS_INO_LAYOUTCOMMITTING, + nfs_wait_bit_killable, + TASK_KILLABLE); if (status) - goto out_free; + goto out; } - INIT_LIST_HEAD(&data->lseg_list); + status = -ENOMEM; + /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ + data = kzalloc(sizeof(*data), GFP_NOFS); + if (!data) + goto clear_layoutcommitting; + + status = 0; spin_lock(&inode->i_lock); - if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { - clear_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags); - spin_unlock(&inode->i_lock); - wake_up_bit(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING); - goto out_free; - } + if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) + goto out_unlock; + INIT_LIST_HEAD(&data->lseg_list); pnfs_list_write_lseg(inode, &data->lseg_list); end_pos = nfsi->layout->plh_lwb; @@ -1940,8 +1940,11 @@ out: mark_inode_dirty_sync(inode); dprintk("<-- %s status %d\n", __func__, status); return status; -out_free: +out_unlock: + spin_unlock(&inode->i_lock); kfree(data); +clear_layoutcommitting: + pnfs_clear_layoutcommitting(inode); goto out; } diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index a4f41810a7f4..023793909778 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -359,6 +359,15 @@ pnfs_ld_layoutret_on_setattr(struct inode *inode) PNFS_LAYOUTRET_ON_SETATTR; } +static inline bool +pnfs_layoutcommit_outstanding(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + return test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags) != 0 || + test_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags) != 0; +} + static inline int pnfs_return_layout(struct inode *ino) { struct nfs_inode *nfsi = NFS_I(ino); @@ -515,6 +524,13 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src, return false; } +static inline bool +pnfs_layoutcommit_outstanding(struct inode *inode) +{ + return false; +} + + static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void) { return NULL; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 31db5c366b81..411aedda14bb 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -163,9 +163,9 @@ static void nfs_readpage_release(struct nfs_page *req) unlock_page(req->wb_page); - dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", + dprintk("NFS: read done (%s/%Lu %d@%Ld)\n", req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); nfs_release_request(req); @@ -228,11 +228,11 @@ int nfs_initiate_read(struct rpc_clnt *clnt, /* Set up the initial task struct. */ NFS_PROTO(inode)->read_setup(data, &msg); - dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " + dprintk("NFS: %5u initiated read call (req %s/%llu, %u bytes @ " "offset %llu)\n", data->task.tk_pid, inode->i_sb->s_id, - (long long)NFS_FILEID(inode), + (unsigned long long)NFS_FILEID(inode), data->args.count, (unsigned long long)data->args.offset); @@ -630,9 +630,9 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, unsigned long npages; int ret = -ESTALE; - dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", + dprintk("NFS: nfs_readpages (%s/%Lu %d)\n", inode->i_sb->s_id, - (long long)NFS_FILEID(inode), + (unsigned long long)NFS_FILEID(inode), nr_pages); nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index c1d548211c31..a44a87268a6e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -922,19 +922,20 @@ out: * extend the write to cover the entire page in order to avoid fragmentation * inefficiencies. * - * If the file is opened for synchronous writes or if we have a write delegation - * from the server then we can just skip the rest of the checks. + * If the file is opened for synchronous writes then we can just skip the rest + * of the checks. */ static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) { if (file->f_flags & O_DSYNC) return 0; + if (!nfs_write_pageuptodate(page, inode)) + return 0; if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) return 1; - if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL || - (inode->i_flock->fl_start == 0 && + if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 && inode->i_flock->fl_end == OFFSET_MAX && - inode->i_flock->fl_type != F_RDLCK))) + inode->i_flock->fl_type != F_RDLCK)) return 1; return 0; } @@ -1013,10 +1014,10 @@ int nfs_initiate_write(struct rpc_clnt *clnt, NFS_PROTO(inode)->write_setup(data, &msg); dprintk("NFS: %5u initiated write call " - "(req %s/%lld, %u bytes @ offset %llu)\n", + "(req %s/%llu, %u bytes @ offset %llu)\n", data->task.tk_pid, inode->i_sb->s_id, - (long long)NFS_FILEID(inode), + (unsigned long long)NFS_FILEID(inode), data->args.count, (unsigned long long)data->args.offset); @@ -1606,9 +1607,9 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) nfs_list_remove_request(req); nfs_clear_page_commit(req->wb_page); - dprintk("NFS: commit (%s/%lld %d@%lld)", + dprintk("NFS: commit (%s/%llu %d@%lld)", req->wb_context->dentry->d_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index 8b186a4955cc..8b68218e2c1c 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h @@ -35,7 +35,9 @@ #ifndef LINUX_NFS4_ACL_H #define LINUX_NFS4_ACL_H -#include <linux/posix_acl.h> +struct nfs4_acl; +struct svc_fh; +struct svc_rqst; /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to * fit in a page: */ @@ -45,13 +47,9 @@ struct nfs4_acl *nfs4_acl_new(int); int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_write_who(int who, char *p); -#define NFS4_ACL_TYPE_DEFAULT 0x01 -#define NFS4_ACL_DIR 0x02 -#define NFS4_ACL_OWNER 0x04 - -struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *, - struct posix_acl *, unsigned int flags); -int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **, - struct posix_acl **, unsigned int flags); +int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct nfs4_acl **acl); +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct nfs4_acl *acl); #endif /* LINUX_NFS4_ACL_H */ diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 95d76dc6c5da..11c1fba29312 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { - svc_fh *fh; struct posix_acl *acl; + struct inode *inode; + svc_fh *fh; __be32 nfserr = 0; dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); @@ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); + inode = fh->fh_dentry->d_inode; + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; @@ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, goto fail; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { - acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } if (acl == NULL) { /* Solaris returns the inode's minimum ACL. */ - - struct inode *inode = fh->fh_dentry->d_inode; acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } resp->acl_access = acl; @@ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { /* Check how Solaris handles requests for the Default ACL of a non-directory! */ - - acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } resp->acl_default = acl; } @@ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd_attrstat *resp) { + struct inode *inode; svc_fh *fh; __be32 nfserr = 0; + int error; dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (nfserr) + goto out; - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_ACCESS, argp->acl_access) ); - } - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_DEFAULT, argp->acl_default) ); - } - if (!nfserr) { - nfserr = fh_getattr(fh, &resp->stat); + inode = fh->fh_dentry->d_inode; + if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { + error = -EOPNOTSUPP; + goto out_errno; } + error = fh_want_write(fh); + if (error) + goto out_errno; + + error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); + if (error) + goto out_drop_write; + error = inode->i_op->set_acl(inode, argp->acl_default, + ACL_TYPE_DEFAULT); + if (error) + goto out_drop_write; + + fh_drop_write(fh); + + nfserr = fh_getattr(fh, &resp->stat); + +out: /* argp->acl_{access,default} may have been allocated in nfssvc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); return nfserr; +out_drop_write: + fh_drop_write(fh); +out_errno: + nfserr = nfserrno(error); + goto out; } /* diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 9cbc1a841f87..adc5f1b1dc26 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -29,8 +29,9 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { - svc_fh *fh; struct posix_acl *acl; + struct inode *inode; + svc_fh *fh; __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); @@ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); + inode = fh->fh_dentry->d_inode; + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { - acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } if (acl == NULL) { /* Solaris returns the inode's minimum ACL. */ - - struct inode *inode = fh->fh_dentry->d_inode; acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } resp->acl_access = acl; @@ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { /* Check how Solaris handles requests for the Default ACL of a non-directory! */ - - acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - int err = PTR_ERR(acl); - - if (err == -ENODATA || err == -EOPNOTSUPP) - acl = NULL; - else { - nfserr = nfserrno(err); - goto fail; - } + nfserr = nfserrno(PTR_ERR(acl)); + goto fail; } resp->acl_default = acl; } @@ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd3_attrstat *resp) { + struct inode *inode; svc_fh *fh; __be32 nfserr = 0; + int error; fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (nfserr) + goto out; - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_ACCESS, argp->acl_access) ); - } - if (!nfserr) { - nfserr = nfserrno( nfsd_set_posix_acl( - fh, ACL_TYPE_DEFAULT, argp->acl_default) ); + inode = fh->fh_dentry->d_inode; + if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { + error = -EOPNOTSUPP; + goto out_errno; } + error = fh_want_write(fh); + if (error) + goto out_errno; + + error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); + if (error) + goto out_drop_write; + error = inode->i_op->set_acl(inode, argp->acl_default, + ACL_TYPE_DEFAULT); + +out_drop_write: + fh_drop_write(fh); +out_errno: + nfserr = nfserrno(error); +out: /* argp->acl_{access,default} may have been allocated in nfs3svc_decode_setaclargs. */ posix_acl_release(argp->acl_access); diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 8a50b3c18093..649ad7cf2204 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -37,8 +37,13 @@ #include <linux/slab.h> #include <linux/nfs_fs.h> #include <linux/export.h> +#include "nfsfh.h" #include "acl.h" +#include "vfs.h" +#define NFS4_ACL_TYPE_DEFAULT 0x01 +#define NFS4_ACL_DIR 0x02 +#define NFS4_ACL_OWNER 0x04 /* mode bit translations: */ #define NFS4_READ_MODE (NFS4_ACE_READ_DATA) @@ -130,36 +135,50 @@ static short ace2type(struct nfs4_ace *); static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); -struct nfs4_acl * -nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, - unsigned int flags) +int +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct nfs4_acl **acl) { - struct nfs4_acl *acl; + struct inode *inode = dentry->d_inode; + int error = 0; + struct posix_acl *pacl = NULL, *dpacl = NULL; + unsigned int flags = 0; int size = 0; - if (pacl) { - if (posix_acl_valid(pacl) < 0) - return ERR_PTR(-EINVAL); - size += 2*pacl->a_count; + pacl = get_acl(inode, ACL_TYPE_ACCESS); + if (!pacl) { + pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + if (IS_ERR(pacl)) + return PTR_ERR(pacl); + /* allocate for worst case: one (deny, allow) pair each: */ + size += 2 * pacl->a_count; } - if (dpacl) { - if (posix_acl_valid(dpacl) < 0) - return ERR_PTR(-EINVAL); - size += 2*dpacl->a_count; + + if (S_ISDIR(inode->i_mode)) { + flags = NFS4_ACL_DIR; + dpacl = get_acl(inode, ACL_TYPE_DEFAULT); + if (dpacl) + size += 2 * dpacl->a_count; + } else { + dpacl = NULL; } - /* Allocate for worst case: one (deny, allow) pair each: */ - acl = nfs4_acl_new(size); - if (acl == NULL) - return ERR_PTR(-ENOMEM); + *acl = nfs4_acl_new(size); + if (*acl == NULL) { + error = -ENOMEM; + goto out; + } if (pacl) - _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT); + _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); if (dpacl) - _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT); + _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); - return acl; + out: + posix_acl_release(pacl); + posix_acl_release(dpacl); + return error; } struct posix_acl_summary { @@ -719,8 +738,9 @@ static void process_one_v4_ace(struct posix_acl_state *state, } } -int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, - struct posix_acl **dpacl, unsigned int flags) +static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, + struct posix_acl **pacl, struct posix_acl **dpacl, + unsigned int flags) { struct posix_acl_state effective_acl_state, default_acl_state; struct nfs4_ace *ace; @@ -780,6 +800,57 @@ out_estate: return ret; } +__be32 +nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct nfs4_acl *acl) +{ + __be32 error; + int host_error; + struct dentry *dentry; + struct inode *inode; + struct posix_acl *pacl = NULL, *dpacl = NULL; + unsigned int flags = 0; + + /* Get inode */ + error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); + if (error) + return error; + + dentry = fhp->fh_dentry; + inode = dentry->d_inode; + + if (!inode->i_op->set_acl || !IS_POSIXACL(inode)) + return nfserr_attrnotsupp; + + if (S_ISDIR(inode->i_mode)) + flags = NFS4_ACL_DIR; + + host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + if (host_error == -EINVAL) + return nfserr_attrnotsupp; + if (host_error < 0) + goto out_nfserr; + + host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS); + if (host_error < 0) + goto out_release; + + if (S_ISDIR(inode->i_mode)) { + host_error = inode->i_op->set_acl(inode, dpacl, + ACL_TYPE_DEFAULT); + } + +out_release: + posix_acl_release(pacl); + posix_acl_release(dpacl); +out_nfserr: + if (host_error == -EOPNOTSUPP) + return nfserr_attrnotsupp; + else + return nfserrno(host_error); +} + + static short ace2type(struct nfs4_ace *ace) { @@ -798,9 +869,6 @@ ace2type(struct nfs4_ace *ace) return -1; } -EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); -EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); - struct nfs4_acl * nfs4_acl_new(int n) { @@ -862,7 +930,3 @@ nfs4_acl_write_who(int who, char *p) BUG(); return -1; } - -EXPORT_SYMBOL(nfs4_acl_new); -EXPORT_SYMBOL(nfs4_acl_get_whotype); -EXPORT_SYMBOL(nfs4_acl_write_who); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 419572f33b72..825b8a99b99b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -41,6 +41,7 @@ #include "vfs.h" #include "current_stateid.h" #include "netns.h" +#include "acl.h" #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #include <linux/security.h> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7eea63cada1d..1426eb66c8c6 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -468,158 +468,7 @@ out: return err; } -#if defined(CONFIG_NFSD_V2_ACL) || \ - defined(CONFIG_NFSD_V3_ACL) || \ - defined(CONFIG_NFSD_V4) -static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) -{ - ssize_t buflen; - ssize_t ret; - - buflen = vfs_getxattr(dentry, key, NULL, 0); - if (buflen <= 0) - return buflen; - - *buf = kmalloc(buflen, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - - ret = vfs_getxattr(dentry, key, *buf, buflen); - if (ret < 0) - kfree(*buf); - return ret; -} -#endif - #if defined(CONFIG_NFSD_V4) -static int -set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) -{ - int len; - size_t buflen; - char *buf = NULL; - int error = 0; - - buflen = posix_acl_xattr_size(pacl->a_count); - buf = kmalloc(buflen, GFP_KERNEL); - error = -ENOMEM; - if (buf == NULL) - goto out; - - len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen); - if (len < 0) { - error = len; - goto out; - } - - error = vfs_setxattr(dentry, key, buf, len, 0); -out: - kfree(buf); - return error; -} - -__be32 -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl) -{ - __be32 error; - int host_error; - struct dentry *dentry; - struct inode *inode; - struct posix_acl *pacl = NULL, *dpacl = NULL; - unsigned int flags = 0; - - /* Get inode */ - error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); - if (error) - return error; - - dentry = fhp->fh_dentry; - inode = dentry->d_inode; - if (S_ISDIR(inode->i_mode)) - flags = NFS4_ACL_DIR; - - host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); - if (host_error == -EINVAL) { - return nfserr_attrnotsupp; - } else if (host_error < 0) - goto out_nfserr; - - host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (host_error < 0) - goto out_release; - - if (S_ISDIR(inode->i_mode)) - host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); - -out_release: - posix_acl_release(pacl); - posix_acl_release(dpacl); -out_nfserr: - if (host_error == -EOPNOTSUPP) - return nfserr_attrnotsupp; - else - return nfserrno(host_error); -} - -static struct posix_acl * -_get_posix_acl(struct dentry *dentry, char *key) -{ - void *buf = NULL; - struct posix_acl *pacl = NULL; - int buflen; - - buflen = nfsd_getxattr(dentry, key, &buf); - if (!buflen) - buflen = -ENODATA; - if (buflen <= 0) - return ERR_PTR(buflen); - - pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen); - kfree(buf); - return pacl; -} - -int -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - struct posix_acl *pacl = NULL, *dpacl = NULL; - unsigned int flags = 0; - - pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); - if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) - pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); - if (IS_ERR(pacl)) { - error = PTR_ERR(pacl); - pacl = NULL; - goto out; - } - - if (S_ISDIR(inode->i_mode)) { - dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); - if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) - dpacl = NULL; - else if (IS_ERR(dpacl)) { - error = PTR_ERR(dpacl); - dpacl = NULL; - goto out; - } - flags = NFS4_ACL_DIR; - } - - *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags); - if (IS_ERR(*acl)) { - error = PTR_ERR(*acl); - *acl = NULL; - } - out: - posix_acl_release(pacl); - posix_acl_release(dpacl); - return error; -} - /* * NFS junction information is stored in an extended attribute. */ @@ -2284,93 +2133,3 @@ out_nomem: nfsd_racache_shutdown(); return -ENOMEM; } - -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -struct posix_acl * -nfsd_get_posix_acl(struct svc_fh *fhp, int type) -{ - struct inode *inode = fhp->fh_dentry->d_inode; - char *name; - void *value = NULL; - ssize_t size; - struct posix_acl *acl; - - if (!IS_POSIXACL(inode)) - return ERR_PTR(-EOPNOTSUPP); - - switch (type) { - case ACL_TYPE_ACCESS: - name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return ERR_PTR(-EOPNOTSUPP); - } - - size = nfsd_getxattr(fhp->fh_dentry, name, &value); - if (size < 0) - return ERR_PTR(size); - - acl = posix_acl_from_xattr(&init_user_ns, value, size); - kfree(value); - return acl; -} - -int -nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) -{ - struct inode *inode = fhp->fh_dentry->d_inode; - char *name; - void *value = NULL; - size_t size; - int error; - - if (!IS_POSIXACL(inode) || - !inode->i_op->setxattr || !inode->i_op->removexattr) - return -EOPNOTSUPP; - switch(type) { - case ACL_TYPE_ACCESS: - name = POSIX_ACL_XATTR_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name = POSIX_ACL_XATTR_DEFAULT; - break; - default: - return -EOPNOTSUPP; - } - - if (acl && acl->a_count) { - size = posix_acl_xattr_size(acl->a_count); - value = kmalloc(size, GFP_KERNEL); - if (!value) - return -ENOMEM; - error = posix_acl_to_xattr(&init_user_ns, acl, value, size); - if (error < 0) - goto getout; - size = error; - } else - size = 0; - - error = fh_want_write(fhp); - if (error) - goto getout; - if (size) - error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); - else { - if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) - error = 0; - else { - error = vfs_removexattr(fhp->fh_dentry, name); - if (error == -ENODATA) - error = 0; - } - } - fh_drop_write(fhp); - -getout: - kfree(value); - return error; -} -#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index a4be2e389670..1bc1d440a1a5 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -52,9 +52,6 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *, int, time_t); int nfsd_mountpoint(struct dentry *, struct svc_export *); #ifdef CONFIG_NFSD_V4 -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, - struct nfs4_acl *); -int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, struct xdr_netobj *); #endif /* CONFIG_NFSD_V4 */ @@ -101,11 +98,6 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, struct dentry *, int); -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); -int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); -#endif - static inline int fh_want_write(struct svc_fh *fh) { int ret = mnt_want_write(fh->fh_export->ex_path.mnt); diff --git a/fs/nls/mac-celtic.c b/fs/nls/mac-celtic.c index 634a8b717b02..266c2d7d50bd 100644 --- a/fs/nls/mac-celtic.c +++ b/fs/nls/mac-celtic.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macceltic(void) diff --git a/fs/nls/mac-centeuro.c b/fs/nls/mac-centeuro.c index 979e6265ac5e..9789c6057551 100644 --- a/fs/nls/mac-centeuro.c +++ b/fs/nls/mac-centeuro.c @@ -513,7 +513,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccenteuro(void) diff --git a/fs/nls/mac-croatian.c b/fs/nls/mac-croatian.c index dd3f675911ee..bb19e7a07d43 100644 --- a/fs/nls/mac-croatian.c +++ b/fs/nls/mac-croatian.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccroatian(void) diff --git a/fs/nls/mac-cyrillic.c b/fs/nls/mac-cyrillic.c index 1112c84dd8bb..2a7dea36acba 100644 --- a/fs/nls/mac-cyrillic.c +++ b/fs/nls/mac-cyrillic.c @@ -478,7 +478,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maccyrillic(void) diff --git a/fs/nls/mac-gaelic.c b/fs/nls/mac-gaelic.c index 2de9158409c8..77b001653588 100644 --- a/fs/nls/mac-gaelic.c +++ b/fs/nls/mac-gaelic.c @@ -548,7 +548,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macgaelic(void) diff --git a/fs/nls/mac-greek.c b/fs/nls/mac-greek.c index a86310082802..1eccf499e2eb 100644 --- a/fs/nls/mac-greek.c +++ b/fs/nls/mac-greek.c @@ -478,7 +478,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macgreek(void) diff --git a/fs/nls/mac-iceland.c b/fs/nls/mac-iceland.c index babe2998d5ce..cbd0875c6d69 100644 --- a/fs/nls/mac-iceland.c +++ b/fs/nls/mac-iceland.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_maciceland(void) diff --git a/fs/nls/mac-inuit.c b/fs/nls/mac-inuit.c index 312364f010dc..fba8357aaf03 100644 --- a/fs/nls/mac-inuit.c +++ b/fs/nls/mac-inuit.c @@ -513,7 +513,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macinuit(void) diff --git a/fs/nls/mac-roman.c b/fs/nls/mac-roman.c index 53ce0809cbd2..b6a98a5208cd 100644 --- a/fs/nls/mac-roman.c +++ b/fs/nls/mac-roman.c @@ -618,7 +618,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macroman(void) diff --git a/fs/nls/mac-romanian.c b/fs/nls/mac-romanian.c index add6f7a0c666..25547f023638 100644 --- a/fs/nls/mac-romanian.c +++ b/fs/nls/mac-romanian.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macromanian(void) diff --git a/fs/nls/mac-turkish.c b/fs/nls/mac-turkish.c index dffa96d5de00..b5454bc7b7fa 100644 --- a/fs/nls/mac-turkish.c +++ b/fs/nls/mac-turkish.c @@ -583,7 +583,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_macturkish(void) diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c index 7020e940f74e..a2620650d5e4 100644 --- a/fs/nls/nls_ascii.c +++ b/fs/nls/nls_ascii.c @@ -148,7 +148,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_ascii(void) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index fea6bd5831dc..52ccd34b1e79 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -232,13 +232,14 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, } EXPORT_SYMBOL(utf16s_to_utf8s); -int register_nls(struct nls_table * nls) +int __register_nls(struct nls_table *nls, struct module *owner) { struct nls_table ** tmp = &tables; if (nls->next) return -EBUSY; + nls->owner = owner; spin_lock(&nls_lock); while (*tmp) { if (nls == *tmp) { @@ -252,6 +253,7 @@ int register_nls(struct nls_table * nls) spin_unlock(&nls_lock); return 0; } +EXPORT_SYMBOL(__register_nls); int unregister_nls(struct nls_table * nls) { @@ -538,7 +540,6 @@ struct nls_table *load_nls_default(void) return &default_table; } -EXPORT_SYMBOL(register_nls); EXPORT_SYMBOL(unregister_nls); EXPORT_SYMBOL(unload_nls); EXPORT_SYMBOL(load_nls); diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c index c8471fe78e4e..ace3e19d3407 100644 --- a/fs/nls/nls_cp1250.c +++ b/fs/nls/nls_cp1250.c @@ -329,7 +329,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1250(void) diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c index 1939b46e772f..9273ddfd08a1 100644 --- a/fs/nls/nls_cp1251.c +++ b/fs/nls/nls_cp1251.c @@ -283,7 +283,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1251(void) diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c index 8120ae2e091a..1caf5dfed85b 100644 --- a/fs/nls/nls_cp1255.c +++ b/fs/nls/nls_cp1255.c @@ -365,7 +365,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp1255(void) diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c index ff37a4628ce4..7ddb830da3fd 100644 --- a/fs/nls/nls_cp437.c +++ b/fs/nls/nls_cp437.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp437(void) diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c index f5576b8be1b9..c593f683a0cd 100644 --- a/fs/nls/nls_cp737.c +++ b/fs/nls/nls_cp737.c @@ -332,7 +332,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp737(void) diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c index 4905635d1c00..554c863745f2 100644 --- a/fs/nls/nls_cp775.c +++ b/fs/nls/nls_cp775.c @@ -301,7 +301,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp775(void) diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c index fe5bdad50e2b..56cccd14b40b 100644 --- a/fs/nls/nls_cp850.c +++ b/fs/nls/nls_cp850.c @@ -297,7 +297,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp850(void) diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c index ceb1c0166dd8..7cdc05ac1d40 100644 --- a/fs/nls/nls_cp852.c +++ b/fs/nls/nls_cp852.c @@ -319,7 +319,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp852(void) diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c index cc7f5fb2e0c2..7426eea05663 100644 --- a/fs/nls/nls_cp855.c +++ b/fs/nls/nls_cp855.c @@ -281,7 +281,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp855(void) diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c index e418e198e8d8..098309733ebd 100644 --- a/fs/nls/nls_cp857.c +++ b/fs/nls/nls_cp857.c @@ -283,7 +283,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp857(void) diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c index a86c97d1aa34..84224478e731 100644 --- a/fs/nls/nls_cp860.c +++ b/fs/nls/nls_cp860.c @@ -346,7 +346,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp860(void) diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c index bd920227acdf..dc873e4be092 100644 --- a/fs/nls/nls_cp861.c +++ b/fs/nls/nls_cp861.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp861(void) diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c index e9b68eb3daf0..d5263e3c5566 100644 --- a/fs/nls/nls_cp862.c +++ b/fs/nls/nls_cp862.c @@ -403,7 +403,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp862(void) diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c index f8a9b07ab4e2..051c9832e36a 100644 --- a/fs/nls/nls_cp863.c +++ b/fs/nls/nls_cp863.c @@ -363,7 +363,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp863(void) diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c index 8d31f435fc6f..97eb1273b2f7 100644 --- a/fs/nls/nls_cp864.c +++ b/fs/nls/nls_cp864.c @@ -389,7 +389,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp864(void) diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c index 4bd902fe3ec9..111214228525 100644 --- a/fs/nls/nls_cp865.c +++ b/fs/nls/nls_cp865.c @@ -369,7 +369,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp865(void) diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c index bdc7cb391398..ffdcbc3fc38d 100644 --- a/fs/nls/nls_cp866.c +++ b/fs/nls/nls_cp866.c @@ -287,7 +287,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp866(void) diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c index 9f283a2b151a..3b5a34589354 100644 --- a/fs/nls/nls_cp869.c +++ b/fs/nls/nls_cp869.c @@ -297,7 +297,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp869(void) diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c index 0b3c4886f8c0..8dfaa10710fa 100644 --- a/fs/nls/nls_cp874.c +++ b/fs/nls/nls_cp874.c @@ -256,7 +256,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp874(void) diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c index 0ffed6f1cebb..67b7398e8483 100644 --- a/fs/nls/nls_cp932.c +++ b/fs/nls/nls_cp932.c @@ -7914,7 +7914,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp932(void) diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c index 82770301bc3d..c96546cfec9f 100644 --- a/fs/nls/nls_cp936.c +++ b/fs/nls/nls_cp936.c @@ -11092,7 +11092,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp936(void) diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c index 8a7a2fe85c65..199171e97aa4 100644 --- a/fs/nls/nls_cp949.c +++ b/fs/nls/nls_cp949.c @@ -13927,7 +13927,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp949(void) diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c index ef2536829aa5..8e1418708209 100644 --- a/fs/nls/nls_cp950.c +++ b/fs/nls/nls_cp950.c @@ -9463,7 +9463,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_cp950(void) diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 7424929a278b..162b3f160353 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -553,7 +553,6 @@ static struct nls_table table = { .charset = "euc-jp", .uni2char = uni2char, .char2uni = char2uni, - .owner = THIS_MODULE, }; static int __init init_nls_euc_jp(void) diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c index 7b951bb5849c..69ac020d43b1 100644 --- a/fs/nls/nls_iso8859-1.c +++ b/fs/nls/nls_iso8859-1.c @@ -239,7 +239,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_1(void) diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c index c4d52ea9f092..afb3f8f275f0 100644 --- a/fs/nls/nls_iso8859-13.c +++ b/fs/nls/nls_iso8859-13.c @@ -267,7 +267,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_13(void) diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c index dc02600c7fe1..046370f0b6f0 100644 --- a/fs/nls/nls_iso8859-14.c +++ b/fs/nls/nls_iso8859-14.c @@ -323,7 +323,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_14(void) diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c index 3c7dfc832ef1..7e34a841a056 100644 --- a/fs/nls/nls_iso8859-15.c +++ b/fs/nls/nls_iso8859-15.c @@ -289,7 +289,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_15(void) diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c index a2d2197e4c77..7dd571181741 100644 --- a/fs/nls/nls_iso8859-2.c +++ b/fs/nls/nls_iso8859-2.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_2(void) diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c index a61e0daa3a86..740b75ec4493 100644 --- a/fs/nls/nls_iso8859-3.c +++ b/fs/nls/nls_iso8859-3.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_3(void) diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c index e8ff555483b6..8826021e32f5 100644 --- a/fs/nls/nls_iso8859-4.c +++ b/fs/nls/nls_iso8859-4.c @@ -290,7 +290,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_4(void) diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c index 4721e8930124..7c04057a1ad8 100644 --- a/fs/nls/nls_iso8859-5.c +++ b/fs/nls/nls_iso8859-5.c @@ -254,7 +254,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_5(void) diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c index 01a517d6d306..d4a881400d74 100644 --- a/fs/nls/nls_iso8859-6.c +++ b/fs/nls/nls_iso8859-6.c @@ -245,7 +245,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_6(void) diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c index 2d27b93ef19e..37b75d825a75 100644 --- a/fs/nls/nls_iso8859-7.c +++ b/fs/nls/nls_iso8859-7.c @@ -299,7 +299,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_7(void) diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c index 694bf070c721..557b98250d37 100644 --- a/fs/nls/nls_iso8859-9.c +++ b/fs/nls/nls_iso8859-9.c @@ -254,7 +254,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_iso8859_9(void) diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c index 43875310540d..811f232fccfb 100644 --- a/fs/nls/nls_koi8-r.c +++ b/fs/nls/nls_koi8-r.c @@ -305,7 +305,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_r(void) diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c index e7bc1d75c78c..a80a741a8676 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -55,7 +55,6 @@ static struct nls_table table = { .charset = "koi8-ru", .uni2char = uni2char, .char2uni = char2uni, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_ru(void) diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c index 8c9f0292b5ae..7e029e4c188a 100644 --- a/fs/nls/nls_koi8-u.c +++ b/fs/nls/nls_koi8-u.c @@ -312,7 +312,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = charset2lower, .charset2upper = charset2upper, - .owner = THIS_MODULE, }; static int __init init_nls_koi8_u(void) diff --git a/fs/nls/nls_utf8.c b/fs/nls/nls_utf8.c index 0d60a44acacd..afcfbc4a14db 100644 --- a/fs/nls/nls_utf8.c +++ b/fs/nls/nls_utf8.c @@ -46,7 +46,6 @@ static struct nls_table table = { .char2uni = char2uni, .charset2lower = identity, /* no conversion */ .charset2upper = identity, - .owner = THIS_MODULE, }; static int __init init_nls_utf8(void) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 58772623f02a..0e792f5e3147 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -16,12 +16,6 @@ static bool should_merge(struct fsnotify_event *old_fsn, { struct fanotify_event_info *old, *new; -#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS - /* dont merge two permission events */ - if ((old_fsn->mask & FAN_ALL_PERM_EVENTS) && - (new_fsn->mask & FAN_ALL_PERM_EVENTS)) - return false; -#endif pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); old = FANOTIFY_E(old_fsn); new = FANOTIFY_E(new_fsn); @@ -34,14 +28,23 @@ static bool should_merge(struct fsnotify_event *old_fsn, } /* and the list better be locked by something too! */ -static struct fsnotify_event *fanotify_merge(struct list_head *list, - struct fsnotify_event *event) +static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) { struct fsnotify_event *test_event; bool do_merge = false; pr_debug("%s: list=%p event=%p\n", __func__, list, event); +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + /* + * Don't merge a permission event with any other event so that we know + * the event structure we have created in fanotify_handle_event() is the + * one we should check for permission response. + */ + if (event->mask & FAN_ALL_PERM_EVENTS) + return 0; +#endif + list_for_each_entry_reverse(test_event, list, list) { if (should_merge(test_event, event)) { do_merge = true; @@ -50,10 +53,10 @@ static struct fsnotify_event *fanotify_merge(struct list_head *list, } if (!do_merge) - return NULL; + return 0; test_event->mask |= event->mask; - return test_event; + return 1; } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS @@ -149,7 +152,6 @@ static int fanotify_handle_event(struct fsnotify_group *group, int ret = 0; struct fanotify_event_info *event; struct fsnotify_event *fsn_event; - struct fsnotify_event *notify_fsn_event; BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); @@ -188,21 +190,19 @@ static int fanotify_handle_event(struct fsnotify_group *group, event->response = 0; #endif - notify_fsn_event = fsnotify_add_notify_event(group, fsn_event, - fanotify_merge); - if (notify_fsn_event) { + ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); + if (ret) { + BUG_ON(mask & FAN_ALL_PERM_EVENTS); /* Our event wasn't used in the end. Free it. */ fsnotify_destroy_event(group, fsn_event); - if (IS_ERR(notify_fsn_event)) - return PTR_ERR(notify_fsn_event); - /* We need to ask about a different events after a merge... */ - event = FANOTIFY_E(notify_fsn_event); - fsn_event = notify_fsn_event; + ret = 0; } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS - if (fsn_event->mask & FAN_ALL_PERM_EVENTS) + if (mask & FAN_ALL_PERM_EVENTS) { ret = fanotify_get_response_from_access(group, event); + fsnotify_destroy_event(group, fsn_event); + } #endif return ret; } diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 0e90174a116a..32a2f034fb94 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -4,6 +4,13 @@ extern struct kmem_cache *fanotify_event_cachep; +/* + * Lifetime of the structure differs for normal and permission events. In both + * cases the structure is allocated in fanotify_handle_event(). For normal + * events the structure is freed immediately after reporting it to userspace. + * For permission events we free it only after we receive response from + * userspace. + */ struct fanotify_event_info { struct fsnotify_event fse; /* diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 57d7c083cb4b..b6175fa11bf8 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -319,7 +319,12 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, if (IS_ERR(kevent)) break; ret = copy_event_to_user(group, kevent, buf); - fsnotify_destroy_event(group, kevent); + /* + * Permission events get destroyed after we + * receive response + */ + if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) + fsnotify_destroy_event(group, kevent); if (ret < 0) break; buf += ret; @@ -886,9 +891,9 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark, { return sys_fanotify_mark(fanotify_fd, flags, #ifdef __BIG_ENDIAN - ((__u64)mask1 << 32) | mask0, -#else ((__u64)mask0 << 32) | mask1, +#else + ((__u64)mask1 << 32) | mask0, #endif dfd, pathname); } diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index aad1a35e9af1..d5ee56348bb8 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -53,15 +53,13 @@ static bool event_compare(struct fsnotify_event *old_fsn, return false; } -static struct fsnotify_event *inotify_merge(struct list_head *list, - struct fsnotify_event *event) +static int inotify_merge(struct list_head *list, + struct fsnotify_event *event) { struct fsnotify_event *last_event; last_event = list_entry(list->prev, struct fsnotify_event, list); - if (!event_compare(last_event, event)) - return NULL; - return last_event; + return event_compare(last_event, event); } int inotify_handle_event(struct fsnotify_group *group, @@ -73,9 +71,8 @@ int inotify_handle_event(struct fsnotify_group *group, { struct inotify_inode_mark *i_mark; struct inotify_event_info *event; - struct fsnotify_event *added_event; struct fsnotify_event *fsn_event; - int ret = 0; + int ret; int len = 0; int alloc_len = sizeof(struct inotify_event_info); @@ -110,18 +107,16 @@ int inotify_handle_event(struct fsnotify_group *group, if (len) strcpy(event->name, file_name); - added_event = fsnotify_add_notify_event(group, fsn_event, inotify_merge); - if (added_event) { + ret = fsnotify_add_notify_event(group, fsn_event, inotify_merge); + if (ret) { /* Our event wasn't used in the end. Free it. */ fsnotify_destroy_event(group, fsn_event); - if (IS_ERR(added_event)) - ret = PTR_ERR(added_event); } if (inode_mark->mask & IN_ONESHOT) fsnotify_destroy_mark(inode_mark, group); - return ret; + return 0; } static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group) diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 952237b8e2d2..18b3c4427dca 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c @@ -79,15 +79,15 @@ void fsnotify_destroy_event(struct fsnotify_group *group, /* * Add an event to the group notification queue. The group can later pull this - * event off the queue to deal with. If the event is successfully added to the - * group's notification queue, a reference is taken on event. + * event off the queue to deal with. The function returns 0 if the event was + * added to the queue, 1 if the event was merged with some other queued event. */ -struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, - struct fsnotify_event *event, - struct fsnotify_event *(*merge)(struct list_head *, - struct fsnotify_event *)) +int fsnotify_add_notify_event(struct fsnotify_group *group, + struct fsnotify_event *event, + int (*merge)(struct list_head *, + struct fsnotify_event *)) { - struct fsnotify_event *return_event = NULL; + int ret = 0; struct list_head *list = &group->notification_list; pr_debug("%s: group=%p event=%p\n", __func__, group, event); @@ -98,14 +98,14 @@ struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, /* Queue overflow event only if it isn't already queued */ if (list_empty(&group->overflow_event.list)) event = &group->overflow_event; - return_event = event; + ret = 1; } if (!list_empty(list) && merge) { - return_event = merge(list, event); - if (return_event) { + ret = merge(list, event); + if (ret) { mutex_unlock(&group->notification_mutex); - return return_event; + return ret; } } @@ -115,7 +115,7 @@ struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, wake_up(&group->notification_waitq); kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); - return return_event; + return ret; } /* diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index b4f788e0ca31..555f4cddefe3 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -160,36 +160,6 @@ static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, return acl; } - -/* - * Get posix acl. - */ -static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct buffer_head *di_bh = NULL; - struct posix_acl *acl; - int ret; - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return NULL; - - ret = ocfs2_inode_lock(inode, &di_bh, 0); - if (ret < 0) { - mlog_errno(ret); - acl = ERR_PTR(ret); - return acl; - } - - acl = ocfs2_get_acl_nolock(inode, type, di_bh); - - ocfs2_inode_unlock(inode, 0); - - brelse(di_bh); - - return acl; -} - /* * Helper function to set i_mode in memory and disk. Some call paths * will not have di_bh or a journal handle to pass, in which case it @@ -250,7 +220,7 @@ out: /* * Set the access or default ACL of an inode. */ -static int ocfs2_set_acl(handle_t *handle, +int ocfs2_set_acl(handle_t *handle, struct inode *inode, struct buffer_head *di_bh, int type, @@ -313,6 +283,11 @@ static int ocfs2_set_acl(handle_t *handle, return ret; } +int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); +} + struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) { struct ocfs2_super *osb; @@ -334,200 +309,3 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) return acl; } - -int ocfs2_acl_chmod(struct inode *inode) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl; - int ret; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (ret) - return ret; - ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, - acl, NULL, NULL); - posix_acl_release(acl); - return ret; -} - -/* - * Initialize the ACLs of a new inode. If parent directory has default ACL, - * then clone to new inode. Called from ocfs2_mknod. - */ -int ocfs2_init_acl(handle_t *handle, - struct inode *inode, - struct inode *dir, - struct buffer_head *di_bh, - struct buffer_head *dir_bh, - struct ocfs2_alloc_context *meta_ac, - struct ocfs2_alloc_context *data_ac) -{ - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl = NULL; - int ret = 0, ret2; - umode_t mode; - - if (!S_ISLNK(inode->i_mode)) { - if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { - acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, - dir_bh); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) { - mode = inode->i_mode & ~current_umask(); - ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret) { - mlog_errno(ret); - goto cleanup; - } - } - } - if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - ret = ocfs2_set_acl(handle, inode, di_bh, - ACL_TYPE_DEFAULT, acl, - meta_ac, data_ac); - if (ret) - goto cleanup; - } - mode = inode->i_mode; - ret = posix_acl_create(&acl, GFP_NOFS, &mode); - if (ret < 0) - return ret; - - ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); - if (ret2) { - mlog_errno(ret2); - ret = ret2; - goto cleanup; - } - if (ret > 0) { - ret = ocfs2_set_acl(handle, inode, - di_bh, ACL_TYPE_ACCESS, - acl, meta_ac, data_ac); - } - } -cleanup: - posix_acl_release(acl); - return ret; -} - -static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry, - char *list, - size_t list_len, - const char *name, - size_t name_len, - int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry, - char *list, - size_t list_len, - const char *name, - size_t name_len, - int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return 0; - - if (list && size <= list_len) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); - struct posix_acl *acl; - int ret; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ocfs2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - - return ret; -} - -static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct posix_acl *acl; - int ret = 0; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) - return -EOPNOTSUPP; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - ret = posix_acl_valid(acl); - if (ret) - goto cleanup; - } - } else - acl = NULL; - - ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); - -cleanup: - posix_acl_release(acl); - return ret; -} - -const struct xattr_handler ocfs2_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ocfs2_xattr_list_acl_access, - .get = ocfs2_xattr_get_acl, - .set = ocfs2_xattr_set_acl, -}; - -const struct xattr_handler ocfs2_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ocfs2_xattr_list_acl_default, - .get = ocfs2_xattr_get_acl, - .set = ocfs2_xattr_set_acl, -}; diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h index 071fbd380f2f..3fce68d08625 100644 --- a/fs/ocfs2/acl.h +++ b/fs/ocfs2/acl.h @@ -27,10 +27,13 @@ struct ocfs2_acl_entry { }; struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type); -extern int ocfs2_acl_chmod(struct inode *); -extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, - struct buffer_head *, struct buffer_head *, - struct ocfs2_alloc_context *, - struct ocfs2_alloc_context *); +int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type); +int ocfs2_set_acl(handle_t *handle, + struct inode *inode, + struct buffer_head *di_bh, + int type, + struct posix_acl *acl, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_alloc_context *data_ac); #endif /* OCFS2_ACL_H */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index f42eecef6478..d77d71ead8d1 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1236,7 +1236,7 @@ bail: dqput(transfer_to[qtype]); if (!status && attr->ia_valid & ATTR_MODE) { - status = ocfs2_acl_chmod(inode); + status = posix_acl_chmod(inode, inode->i_mode); if (status < 0) mlog_errno(status); } @@ -2662,6 +2662,7 @@ const struct inode_operations ocfs2_file_iops = { .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; const struct inode_operations ocfs2_special_file_iops = { @@ -2669,6 +2670,7 @@ const struct inode_operations ocfs2_special_file_iops = { .getattr = ocfs2_getattr, .permission = ocfs2_permission, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; /* diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 4f791f6d27d0..f4d609be9400 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -230,6 +230,7 @@ static int ocfs2_mknod(struct inode *dir, struct ocfs2_dir_lookup_result lookup = { NULL, }; sigset_t oldset; int did_block_signals = 0; + struct posix_acl *default_acl = NULL, *acl = NULL; trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno, @@ -331,6 +332,12 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } + status = posix_acl_create(dir, &mode, &default_acl, &acl); + if (status) { + mlog_errno(status); + goto leave; + } + handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), xattr_credits)); @@ -379,8 +386,17 @@ static int ocfs2_mknod(struct inode *dir, inc_nlink(dir); } - status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, - meta_ac, data_ac); + if (default_acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_DEFAULT, default_acl, + meta_ac, data_ac); + } + if (!status && acl) { + status = ocfs2_set_acl(handle, inode, new_fe_bh, + ACL_TYPE_ACCESS, acl, + meta_ac, data_ac); + } + if (status < 0) { mlog_errno(status); goto leave; @@ -419,6 +435,10 @@ static int ocfs2_mknod(struct inode *dir, d_instantiate(dentry, inode); status = 0; leave: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (status < 0 && did_quota_inode) dquot_free_inode(inode); if (handle) @@ -948,7 +968,7 @@ leave: ocfs2_free_dir_lookup_result(&orphan_insert); ocfs2_free_dir_lookup_result(&lookup); - if (status && (status != -ENOTEMPTY)) + if (status && (status != -ENOTEMPTY) && (status != -ENOENT)) mlog_errno(status); return status; @@ -2504,4 +2524,5 @@ const struct inode_operations ocfs2_dir_iops = { .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, }; diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 55767e1ba724..6ba4bcbc4796 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -46,6 +46,7 @@ #include <linux/quotaops.h> #include <linux/namei.h> #include <linux/mount.h> +#include <linux/posix_acl.h> struct ocfs2_cow_context { struct inode *inode; @@ -4268,11 +4269,20 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, struct inode *inode = old_dentry->d_inode; struct buffer_head *old_bh = NULL; struct inode *new_orphan_inode = NULL; + struct posix_acl *default_acl, *acl; + umode_t mode; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; - error = ocfs2_create_inode_in_orphan(dir, inode->i_mode, + mode = inode->i_mode; + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) { + mlog_errno(error); + goto out; + } + + error = ocfs2_create_inode_in_orphan(dir, mode, &new_orphan_inode); if (error) { mlog_errno(error); @@ -4303,11 +4313,16 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, /* If the security isn't preserved, we need to re-initialize them. */ if (!preserve) { error = ocfs2_init_security_and_acl(dir, new_orphan_inode, - &new_dentry->d_name); + &new_dentry->d_name, + default_acl, acl); if (error) mlog_errno(error); } out: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); if (!error) { error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode, new_dentry); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index f0a1326d9bba..185fa3b7f962 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -99,8 +99,8 @@ static struct ocfs2_xattr_def_value_root def_xv = { const struct xattr_handler *ocfs2_xattr_handlers[] = { &ocfs2_xattr_user_handler, - &ocfs2_xattr_acl_access_handler, - &ocfs2_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, &ocfs2_xattr_trusted_handler, &ocfs2_xattr_security_handler, NULL @@ -109,9 +109,9 @@ const struct xattr_handler *ocfs2_xattr_handlers[] = { static const struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS] - = &ocfs2_xattr_acl_access_handler, + = &posix_acl_access_xattr_handler, [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT] - = &ocfs2_xattr_acl_default_handler, + = &posix_acl_default_xattr_handler, [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, }; @@ -7190,10 +7190,12 @@ out: */ int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr) + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl) { - int ret = 0; struct buffer_head *dir_bh = NULL; + int ret = 0; ret = ocfs2_init_security_get(inode, dir, qstr, NULL); if (ret) { @@ -7207,9 +7209,10 @@ int ocfs2_init_security_and_acl(struct inode *dir, goto leave; } - ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL); - if (ret) - mlog_errno(ret); + if (!ret && default_acl) + ret = ocfs2_iop_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + if (!ret && acl) + ret = ocfs2_iop_set_acl(inode, acl, ACL_TYPE_ACCESS); ocfs2_inode_unlock(dir, 0); brelse(dir_bh); diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index 19f134e896a9..f10d5b93c366 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h @@ -40,8 +40,6 @@ struct ocfs2_security_xattr_info { extern const struct xattr_handler ocfs2_xattr_user_handler; extern const struct xattr_handler ocfs2_xattr_trusted_handler; extern const struct xattr_handler ocfs2_xattr_security_handler; -extern const struct xattr_handler ocfs2_xattr_acl_access_handler; -extern const struct xattr_handler ocfs2_xattr_acl_default_handler; extern const struct xattr_handler *ocfs2_xattr_handlers[]; ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); @@ -96,5 +94,7 @@ int ocfs2_reflink_xattrs(struct inode *old_inode, bool preserve_security); int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode, - const struct qstr *qstr); + const struct qstr *qstr, + struct posix_acl *default_acl, + struct posix_acl *acl); #endif /* OCFS2_XATTR_H */ diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 551e61ba15b6..38bae5a0ea25 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -1,10 +1,8 @@ /* - * linux/fs/posix_acl.c + * Copyright (C) 2002,2003 by Andreas Gruenbacher <a.gruenbacher@computer.org> * - * Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org> - * - * Fixes from William Schumacher incorporated on 15 March 2001. - * (Reported by Charles Bertsch, <CBertsch@microtest.com>). + * Fixes from William Schumacher incorporated on 15 March 2001. + * (Reported by Charles Bertsch, <CBertsch@microtest.com>). */ /* @@ -18,9 +16,10 @@ #include <linux/fs.h> #include <linux/sched.h> #include <linux/posix_acl.h> +#include <linux/posix_acl_xattr.h> +#include <linux/xattr.h> #include <linux/export.h> - -#include <linux/errno.h> +#include <linux/user_namespace.h> struct posix_acl **acl_by_type(struct inode *inode, int type) { @@ -97,6 +96,33 @@ void forget_all_cached_acls(struct inode *inode) } EXPORT_SYMBOL(forget_all_cached_acls); +struct posix_acl *get_acl(struct inode *inode, int type) +{ + struct posix_acl *acl; + + acl = get_cached_acl(inode, type); + if (acl != ACL_NOT_CACHED) + return acl; + + if (!IS_POSIXACL(inode)) + return NULL; + + /* + * A filesystem can force a ACL callback by just never filling the + * ACL cache. But normally you'd fill the cache either at inode + * instantiation time, or on the first ->get_acl call. + * + * If the filesystem doesn't have a get_acl() function at all, we'll + * just create the negative cache entry. + */ + if (!inode->i_op->get_acl) { + set_cached_acl(inode, type, NULL); + return NULL; + } + return inode->i_op->get_acl(inode, type); +} +EXPORT_SYMBOL(get_acl); + /* * Init a fresh posix_acl */ @@ -402,7 +428,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) /* * Modify the ACL for the chmod syscall. */ -static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) +static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) { struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; struct posix_acl_entry *pa, *pe; @@ -448,7 +474,7 @@ static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) } int -posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) +__posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; @@ -463,15 +489,15 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) *acl = clone; return err; } -EXPORT_SYMBOL(posix_acl_create); +EXPORT_SYMBOL(__posix_acl_create); int -posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) +__posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) { struct posix_acl *clone = posix_acl_clone(*acl, gfp); int err = -ENOMEM; if (clone) { - err = posix_acl_chmod_masq(clone, mode); + err = __posix_acl_chmod_masq(clone, mode); if (err) { posix_acl_release(clone); clone = NULL; @@ -481,4 +507,382 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) *acl = clone; return err; } +EXPORT_SYMBOL(__posix_acl_chmod); + +int +posix_acl_chmod(struct inode *inode, umode_t mode) +{ + struct posix_acl *acl; + int ret = 0; + + if (!IS_POSIXACL(inode)) + return 0; + if (!inode->i_op->set_acl) + return -EOPNOTSUPP; + + acl = get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR_OR_NULL(acl)) + return PTR_ERR(acl); + + ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode); + if (ret) + return ret; + ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS); + posix_acl_release(acl); + return ret; +} EXPORT_SYMBOL(posix_acl_chmod); + +int +posix_acl_create(struct inode *dir, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl) +{ + struct posix_acl *p; + int ret; + + if (S_ISLNK(*mode) || !IS_POSIXACL(dir)) + goto no_acl; + + p = get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (!p) { + *mode &= ~current_umask(); + goto no_acl; + } + + *acl = posix_acl_clone(p, GFP_NOFS); + if (!*acl) + return -ENOMEM; + + ret = posix_acl_create_masq(*acl, mode); + if (ret < 0) { + posix_acl_release(*acl); + return -ENOMEM; + } + + if (ret == 0) { + posix_acl_release(*acl); + *acl = NULL; + } + + if (!S_ISDIR(*mode)) { + posix_acl_release(p); + *default_acl = NULL; + } else { + *default_acl = p; + } + return 0; + +no_acl: + *default_acl = NULL; + *acl = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(posix_acl_create); + +/* + * Fix up the uids and gids in posix acl extended attributes in place. + */ +static void posix_acl_fix_xattr_userns( + struct user_namespace *to, struct user_namespace *from, + void *value, size_t size) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + int count; + kuid_t uid; + kgid_t gid; + + if (!value) + return; + if (size < sizeof(posix_acl_xattr_header)) + return; + if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return; + + count = posix_acl_xattr_count(size); + if (count < 0) + return; + if (count == 0) + return; + + for (end = entry + count; entry != end; entry++) { + switch(le16_to_cpu(entry->e_tag)) { + case ACL_USER: + uid = make_kuid(from, le32_to_cpu(entry->e_id)); + entry->e_id = cpu_to_le32(from_kuid(to, uid)); + break; + case ACL_GROUP: + gid = make_kgid(from, le32_to_cpu(entry->e_id)); + entry->e_id = cpu_to_le32(from_kgid(to, gid)); + break; + default: + break; + } + } +} + +void posix_acl_fix_xattr_from_user(void *value, size_t size) +{ + struct user_namespace *user_ns = current_user_ns(); + if (user_ns == &init_user_ns) + return; + posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); +} + +void posix_acl_fix_xattr_to_user(void *value, size_t size) +{ + struct user_namespace *user_ns = current_user_ns(); + if (user_ns == &init_user_ns) + return; + posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); +} + +/* + * Convert from extended attribute to in-memory representation. + */ +struct posix_acl * +posix_acl_from_xattr(struct user_namespace *user_ns, + const void *value, size_t size) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + int count; + struct posix_acl *acl; + struct posix_acl_entry *acl_e; + + if (!value) + return NULL; + if (size < sizeof(posix_acl_xattr_header)) + return ERR_PTR(-EINVAL); + if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return ERR_PTR(-EOPNOTSUPP); + + count = posix_acl_xattr_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = posix_acl_alloc(count, GFP_NOFS); + if (!acl) + return ERR_PTR(-ENOMEM); + acl_e = acl->a_entries; + + for (end = entry + count; entry != end; acl_e++, entry++) { + acl_e->e_tag = le16_to_cpu(entry->e_tag); + acl_e->e_perm = le16_to_cpu(entry->e_perm); + + switch(acl_e->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + break; + + case ACL_USER: + acl_e->e_uid = + make_kuid(user_ns, + le32_to_cpu(entry->e_id)); + if (!uid_valid(acl_e->e_uid)) + goto fail; + break; + case ACL_GROUP: + acl_e->e_gid = + make_kgid(user_ns, + le32_to_cpu(entry->e_id)); + if (!gid_valid(acl_e->e_gid)) + goto fail; + break; + + default: + goto fail; + } + } + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL (posix_acl_from_xattr); + +/* + * Convert from in-memory to extended attribute representation. + */ +int +posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, + void *buffer, size_t size) +{ + posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; + posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; + int real_size, n; + + real_size = posix_acl_xattr_size(acl->a_count); + if (!buffer) + return real_size; + if (real_size > size) + return -ERANGE; + + ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); + + for (n=0; n < acl->a_count; n++, ext_entry++) { + const struct posix_acl_entry *acl_e = &acl->a_entries[n]; + ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); + ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); + switch(acl_e->e_tag) { + case ACL_USER: + ext_entry->e_id = + cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); + break; + case ACL_GROUP: + ext_entry->e_id = + cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); + break; + default: + ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); + break; + } + } + return real_size; +} +EXPORT_SYMBOL (posix_acl_to_xattr); + +static int +posix_acl_xattr_get(struct dentry *dentry, const char *name, + void *value, size_t size, int type) +{ + struct posix_acl *acl; + int error; + + if (!IS_POSIXACL(dentry->d_inode)) + return -EOPNOTSUPP; + if (S_ISLNK(dentry->d_inode->i_mode)) + return -EOPNOTSUPP; + + acl = get_acl(dentry->d_inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + + error = posix_acl_to_xattr(&init_user_ns, acl, value, size); + posix_acl_release(acl); + + return error; +} + +static int +posix_acl_xattr_set(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct inode *inode = dentry->d_inode; + struct posix_acl *acl = NULL; + int ret; + + if (!IS_POSIXACL(inode)) + return -EOPNOTSUPP; + if (!inode->i_op->set_acl) + return -EOPNOTSUPP; + + if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) + return value ? -EACCES : 0; + if (!inode_owner_or_capable(inode)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(&init_user_ns, value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + + if (acl) { + ret = posix_acl_valid(acl); + if (ret) + goto out; + } + } + + ret = inode->i_op->set_acl(inode, acl, type); +out: + posix_acl_release(acl); + return ret; +} + +static size_t +posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size, + const char *name, size_t name_len, int type) +{ + const char *xname; + size_t size; + + if (!IS_POSIXACL(dentry->d_inode)) + return -EOPNOTSUPP; + if (S_ISLNK(dentry->d_inode->i_mode)) + return -EOPNOTSUPP; + + if (type == ACL_TYPE_ACCESS) + xname = POSIX_ACL_XATTR_ACCESS; + else + xname = POSIX_ACL_XATTR_DEFAULT; + + size = strlen(xname) + 1; + if (list && size <= list_size) + memcpy(list, xname, size); + return size; +} + +const struct xattr_handler posix_acl_access_xattr_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .flags = ACL_TYPE_ACCESS, + .list = posix_acl_xattr_list, + .get = posix_acl_xattr_get, + .set = posix_acl_xattr_set, +}; +EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); + +const struct xattr_handler posix_acl_default_xattr_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .flags = ACL_TYPE_DEFAULT, + .list = posix_acl_xattr_list, + .get = posix_acl_xattr_get, + .set = posix_acl_xattr_set, +}; +EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); + +int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int error; + + if (type == ACL_TYPE_ACCESS) { + error = posix_acl_equiv_mode(acl, &inode->i_mode); + if (error < 0) + return 0; + if (error == 0) + acl = NULL; + } + + inode->i_ctime = CURRENT_TIME; + set_cached_acl(inode, type, acl); + return 0; +} + +int simple_acl_create(struct inode *dir, struct inode *inode) +{ + struct posix_acl *default_acl, *acl; + int error; + + error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (error) + return error; + + set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); + set_cached_acl(inode, ACL_TYPE_ACCESS, acl); + + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); + return 0; +} diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 2e8caa62da78..89558810381c 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -27,7 +27,6 @@ static const struct super_operations qnx4_sops; -static void qnx4_put_super(struct super_block *sb); static struct inode *qnx4_alloc_inode(struct super_block *sb); static void qnx4_destroy_inode(struct inode *inode); static int qnx4_remount(struct super_block *sb, int *flags, char *data); @@ -37,7 +36,6 @@ static const struct super_operations qnx4_sops = { .alloc_inode = qnx4_alloc_inode, .destroy_inode = qnx4_destroy_inode, - .put_super = qnx4_put_super, .statfs = qnx4_statfs, .remount_fs = qnx4_remount, }; @@ -148,18 +146,19 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf) * it really _is_ a qnx4 filesystem, and to check the size * of the directory entry. */ -static const char *qnx4_checkroot(struct super_block *sb) +static const char *qnx4_checkroot(struct super_block *sb, + struct qnx4_super_block *s) { struct buffer_head *bh; struct qnx4_inode_entry *rootdir; int rd, rl; int i, j; - if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') + if (s->RootDir.di_fname[0] != '/' || s->RootDir.di_fname[1] != '\0') return "no qnx4 filesystem (no root dir)."; QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); - rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; - rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); + rd = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_blk) - 1; + rl = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { bh = sb_bread(sb, rd + j); /* root dir, first block */ if (bh == NULL) @@ -189,7 +188,6 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) struct inode *root; const char *errmsg; struct qnx4_sb_info *qs; - int ret = -EINVAL; qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL); if (!qs) @@ -198,67 +196,50 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) sb_set_blocksize(s, QNX4_BLOCK_SIZE); + s->s_op = &qnx4_sops; + s->s_magic = QNX4_SUPER_MAGIC; + s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ + /* Check the superblock signature. Since the qnx4 code is dangerous, we should leave as quickly as possible if we don't belong here... */ bh = sb_bread(s, 1); if (!bh) { printk(KERN_ERR "qnx4: unable to read the superblock\n"); - goto outnobh; + return -EINVAL; } - if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { - if (!silent) - printk(KERN_ERR "qnx4: wrong fsid in superblock.\n"); - goto out; - } - s->s_op = &qnx4_sops; - s->s_magic = QNX4_SUPER_MAGIC; - s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ - qnx4_sb(s)->sb_buf = bh; - qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data; - /* check before allocating dentries, inodes, .. */ - errmsg = qnx4_checkroot(s); + errmsg = qnx4_checkroot(s, (struct qnx4_super_block *) bh->b_data); + brelse(bh); if (errmsg != NULL) { if (!silent) printk(KERN_ERR "qnx4: %s\n", errmsg); - goto out; + return -EINVAL; } /* does root not have inode number QNX4_ROOT_INO ?? */ root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); if (IS_ERR(root)) { printk(KERN_ERR "qnx4: get inode failed\n"); - ret = PTR_ERR(root); - goto outb; + return PTR_ERR(root); } - ret = -ENOMEM; s->s_root = d_make_root(root); if (s->s_root == NULL) - goto outb; + return -ENOMEM; - brelse(bh); return 0; - - outb: - kfree(qs->BitMap); - out: - brelse(bh); - outnobh: - kfree(qs); - s->s_fs_info = NULL; - return ret; } -static void qnx4_put_super(struct super_block *sb) +static void qnx4_kill_sb(struct super_block *sb) { struct qnx4_sb_info *qs = qnx4_sb(sb); - kfree( qs->BitMap ); - kfree( qs ); - sb->s_fs_info = NULL; - return; + kill_block_super(sb); + if (qs) { + kfree(qs->BitMap); + kfree(qs); + } } static int qnx4_readpage(struct file *file, struct page *page) @@ -409,7 +390,7 @@ static struct file_system_type qnx4_fs_type = { .owner = THIS_MODULE, .name = "qnx4", .mount = qnx4_mount, - .kill_sb = kill_block_super, + .kill_sb = qnx4_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("qnx4"); diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h index 34e2d329c97e..c9b1be2c164d 100644 --- a/fs/qnx4/qnx4.h +++ b/fs/qnx4/qnx4.h @@ -10,8 +10,6 @@ #endif struct qnx4_sb_info { - struct buffer_head *sb_buf; /* superblock buffer */ - struct qnx4_super_block *sb; /* our superblock */ unsigned int Version; /* may be useful */ struct qnx4_inode_entry *BitMap; /* useful */ }; diff --git a/fs/read_write.c b/fs/read_write.c index 1193ffd03565..edc5746a902a 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -964,9 +964,9 @@ out: return ret; } -COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, +COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen) + compat_ulong_t, vlen) { struct fd f = fdget(fd); ssize_t ret; @@ -1001,9 +1001,9 @@ COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, return ret; } -COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd, +COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen, u32, pos_low, u32, pos_high) + compat_ulong_t, vlen, u32, pos_low, u32, pos_high) { loff_t pos = ((loff_t)pos_high << 32) | pos_low; return compat_sys_preadv64(fd, vec, vlen, pos); @@ -1031,9 +1031,9 @@ out: return ret; } -COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, +COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, const struct compat_iovec __user *, vec, - unsigned long, vlen) + compat_ulong_t, vlen) { struct fd f = fdget(fd); ssize_t ret; @@ -1068,9 +1068,9 @@ COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, return ret; } -COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd, +COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen, u32, pos_low, u32, pos_high) + compat_ulong_t, vlen, u32, pos_low, u32, pos_high) { loff_t pos = ((loff_t)pos_high << 32) | pos_low; return compat_sys_pwritev64(fd, vec, vlen, pos); diff --git a/fs/reiserfs/acl.h b/fs/reiserfs/acl.h index f096b80e73d8..4a211f5b34b8 100644 --- a/fs/reiserfs/acl.h +++ b/fs/reiserfs/acl.h @@ -48,18 +48,18 @@ static inline int reiserfs_acl_count(size_t size) #ifdef CONFIG_REISERFS_FS_POSIX_ACL struct posix_acl *reiserfs_get_acl(struct inode *inode, int type); +int reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); int reiserfs_acl_chmod(struct inode *inode); int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode); int reiserfs_cache_default_acl(struct inode *dir); -extern const struct xattr_handler reiserfs_posix_acl_default_handler; -extern const struct xattr_handler reiserfs_posix_acl_access_handler; #else #define reiserfs_cache_default_acl(inode) 0 #define reiserfs_get_acl NULL +#define reiserfs_set_acl NULL static inline int reiserfs_acl_chmod(struct inode *inode) { diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index dcaafcfc23b0..ed58d843d578 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -260,4 +260,5 @@ const struct inode_operations reiserfs_file_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index dc5236f6de1b..e825f8b63e6b 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1522,6 +1522,7 @@ const struct inode_operations reiserfs_dir_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; /* @@ -1538,8 +1539,6 @@ const struct inode_operations reiserfs_symlink_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .get_acl = reiserfs_get_acl, - }; /* @@ -1553,4 +1552,5 @@ const struct inode_operations reiserfs_special_inode_operations = { .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, .get_acl = reiserfs_get_acl, + .set_acl = reiserfs_set_acl, }; diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index a958444a75fc..02b0b7d0f7d5 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -419,7 +419,7 @@ int reiserfs_proc_info_init(struct super_block *sb) char *s; /* Some block devices use /'s */ - strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE); + strlcpy(b, sb->s_id, BDEVNAME_SIZE); s = strchr(b, '/'); if (s) *s = '!'; @@ -449,7 +449,7 @@ int reiserfs_proc_info_done(struct super_block *sb) char *s; /* Some block devices use /'s */ - strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE); + strlcpy(b, sb->s_id, BDEVNAME_SIZE); s = strchr(b, '/'); if (s) *s = '!'; diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index dfb617b2bad2..8d06adf89948 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -608,14 +608,6 @@ int reiserfs_resize(struct super_block *, unsigned long); #define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->) -/* A safe version of the "bdevname", which returns the "s_id" field of - * a superblock or else "Null superblock" if the super block is NULL. - */ -static inline char *reiserfs_bdevname(struct super_block *s) -{ - return (s == NULL) ? "Null superblock" : s->s_id; -} - #define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal))) static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal *journal) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 3ead145dadc4..2c803353f8ac 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1479,7 +1479,7 @@ static int read_super_block(struct super_block *s, int offset) if (!bh) { reiserfs_warning(s, "sh-2006", "bread failed (dev %s, block %lu, size %lu)", - reiserfs_bdevname(s), offset / s->s_blocksize, + s->s_id, offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -1500,7 +1500,7 @@ static int read_super_block(struct super_block *s, int offset) if (!bh) { reiserfs_warning(s, "sh-2007", "bread failed (dev %s, block %lu, size %lu)", - reiserfs_bdevname(s), offset / s->s_blocksize, + s->s_id, offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -1509,7 +1509,7 @@ static int read_super_block(struct super_block *s, int offset) if (sb_blocksize(rs) != s->s_blocksize) { reiserfs_warning(s, "sh-2011", "can't find a reiserfs " "filesystem on (dev %s, block %Lu, size %lu)", - reiserfs_bdevname(s), + s->s_id, (unsigned long long)bh->b_blocknr, s->s_blocksize); brelse(bh); @@ -1825,7 +1825,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) /* try new format (64-th 1k block), which can contain reiserfs super block */ else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) { SWARN(silent, s, "sh-2021", "can not find reiserfs on %s", - reiserfs_bdevname(s)); + s->s_id); goto error_unlocked; } diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 8a9e2dcfe004..5cdfbd638b5c 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -50,6 +50,7 @@ #include <linux/stat.h> #include <linux/quotaops.h> #include <linux/security.h> +#include <linux/posix_acl_xattr.h> #define PRIVROOT_NAME ".reiserfs_priv" #define XAROOT_NAME "xattrs" @@ -904,8 +905,8 @@ static const struct xattr_handler *reiserfs_xattr_handlers[] = { &reiserfs_xattr_security_handler, #endif #ifdef CONFIG_REISERFS_FS_POSIX_ACL - &reiserfs_posix_acl_access_handler, - &reiserfs_posix_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 06c04f73da65..a6ce532402dc 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -11,35 +11,19 @@ #include "acl.h" #include <asm/uaccess.h> -static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, +static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, int type, struct posix_acl *acl); -static int -posix_acl_set(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) + +int +reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct inode *inode = dentry->d_inode; - struct posix_acl *acl; int error, error2; struct reiserfs_transaction_handle th; size_t jcreate_blocks; - if (!reiserfs_posixacl(inode->i_sb)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) { - return PTR_ERR(acl); - } else if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else - acl = NULL; + int size = acl ? posix_acl_xattr_size(acl->a_count) : 0; + /* Pessimism: We can't assume that anything from the xattr root up * has been created. */ @@ -51,7 +35,7 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value, error = journal_begin(&th, inode->i_sb, jcreate_blocks); reiserfs_write_unlock(inode->i_sb); if (error == 0) { - error = reiserfs_set_acl(&th, inode, type, acl); + error = __reiserfs_set_acl(&th, inode, type, acl); reiserfs_write_lock(inode->i_sb); error2 = journal_end(&th, inode->i_sb, jcreate_blocks); reiserfs_write_unlock(inode->i_sb); @@ -59,36 +43,13 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value, error = error2; } - release_and_out: - posix_acl_release(acl); - return error; -} - -static int -posix_acl_get(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - struct posix_acl *acl; - int error; - - if (!reiserfs_posixacl(dentry->d_sb)) - return -EOPNOTSUPP; - - acl = reiserfs_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); - posix_acl_release(acl); - return error; } /* * Convert from filesystem to in-memory representation. */ -static struct posix_acl *posix_acl_from_disk(const void *value, size_t size) +static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; int n, count; @@ -158,7 +119,7 @@ static struct posix_acl *posix_acl_from_disk(const void *value, size_t size) /* * Convert from in-memory to filesystem representation. */ -static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) +static void *reiserfs_posix_acl_to_disk(const struct posix_acl *acl, size_t * size) { reiserfs_acl_header *ext_acl; char *e; @@ -221,10 +182,6 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) int size; int retval; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -257,7 +214,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) } else if (retval < 0) { acl = ERR_PTR(retval); } else { - acl = posix_acl_from_disk(value, retval); + acl = reiserfs_posix_acl_from_disk(value, retval); } if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); @@ -273,7 +230,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) * BKL held [before 2.5.x] */ static int -reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, +__reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, int type, struct posix_acl *acl) { char *name; @@ -281,9 +238,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, size_t size = 0; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; @@ -307,7 +261,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, } if (acl) { - value = posix_acl_to_disk(acl, &size); + value = reiserfs_posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } @@ -343,7 +297,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode) { - struct posix_acl *acl; + struct posix_acl *default_acl, *acl; int err = 0; /* ACLs only get applied to files and directories */ @@ -363,37 +317,28 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, goto apply_umask; } - acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (err) + return err; + if (default_acl) { + err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, + default_acl); + posix_acl_release(default_acl); + } if (acl) { - /* Copy the default ACL to the default ACL of a new directory */ - if (S_ISDIR(inode->i_mode)) { - err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, - acl); - if (err) - goto cleanup; - } - - /* Now we reconcile the new ACL and the mode, - potentially modifying both */ - err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (err < 0) - return err; - - /* If we need an ACL.. */ - if (err > 0) - err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl); - cleanup: + if (!err) + err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, + acl); posix_acl_release(acl); - } else { - apply_umask: - /* no ACL, apply umask */ - inode->i_mode &= ~current_umask(); } return err; + + apply_umask: + /* no ACL, apply umask */ + inode->i_mode &= ~current_umask(); + return err; } /* This is used to cache the default acl before a new object is created. @@ -442,84 +387,11 @@ int reiserfs_cache_default_acl(struct inode *inode) */ int reiserfs_acl_chmod(struct inode *inode) { - struct reiserfs_transaction_handle th; - struct posix_acl *acl; - size_t size; - int error; - if (IS_PRIVATE(inode)) return 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (get_inode_sd_version(inode) == STAT_DATA_V1 || - !reiserfs_posixacl(inode->i_sb)) { + !reiserfs_posixacl(inode->i_sb)) return 0; - } - acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); - if (!acl) - return 0; - if (IS_ERR(acl)) - return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode); - if (error) - return error; - - size = reiserfs_xattr_nblocks(inode, reiserfs_acl_size(acl->a_count)); - reiserfs_write_lock(inode->i_sb); - error = journal_begin(&th, inode->i_sb, size * 2); - reiserfs_write_unlock(inode->i_sb); - if (!error) { - int error2; - error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, acl); - reiserfs_write_lock(inode->i_sb); - error2 = journal_end(&th, inode->i_sb, size * 2); - reiserfs_write_unlock(inode->i_sb); - if (error2) - error = error2; - } - posix_acl_release(acl); - return error; -} - -static size_t posix_acl_access_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, - size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - if (!reiserfs_posixacl(dentry->d_sb)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; + return posix_acl_chmod(inode, inode->i_mode); } - -const struct xattr_handler reiserfs_posix_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = posix_acl_get, - .set = posix_acl_set, - .list = posix_acl_access_list, -}; - -static size_t posix_acl_default_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, - size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - if (!reiserfs_posixacl(dentry->d_sb)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -const struct xattr_handler reiserfs_posix_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = posix_acl_get, - .set = posix_acl_set, - .list = posix_acl_default_list, -}; diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c deleted file mode 100644 index 9fbea87fdb6e..000000000000 --- a/fs/xattr_acl.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * linux/fs/xattr_acl.c - * - * Almost all from linux/fs/ext2/acl.c: - * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> - */ - -#include <linux/export.h> -#include <linux/fs.h> -#include <linux/posix_acl_xattr.h> -#include <linux/gfp.h> -#include <linux/user_namespace.h> - -/* - * Fix up the uids and gids in posix acl extended attributes in place. - */ -static void posix_acl_fix_xattr_userns( - struct user_namespace *to, struct user_namespace *from, - void *value, size_t size) -{ - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; - int count; - kuid_t uid; - kgid_t gid; - - if (!value) - return; - if (size < sizeof(posix_acl_xattr_header)) - return; - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return; - - count = posix_acl_xattr_count(size); - if (count < 0) - return; - if (count == 0) - return; - - for (end = entry + count; entry != end; entry++) { - switch(le16_to_cpu(entry->e_tag)) { - case ACL_USER: - uid = make_kuid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kuid(to, uid)); - break; - case ACL_GROUP: - gid = make_kgid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kgid(to, gid)); - break; - default: - break; - } - } -} - -void posix_acl_fix_xattr_from_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); -} - -void posix_acl_fix_xattr_to_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); -} - -/* - * Convert from extended attribute to in-memory representation. - */ -struct posix_acl * -posix_acl_from_xattr(struct user_namespace *user_ns, - const void *value, size_t size) -{ - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; - int count; - struct posix_acl *acl; - struct posix_acl_entry *acl_e; - - if (!value) - return NULL; - if (size < sizeof(posix_acl_xattr_header)) - return ERR_PTR(-EINVAL); - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return ERR_PTR(-EOPNOTSUPP); - - count = posix_acl_xattr_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - - acl = posix_acl_alloc(count, GFP_NOFS); - if (!acl) - return ERR_PTR(-ENOMEM); - acl_e = acl->a_entries; - - for (end = entry + count; entry != end; acl_e++, entry++) { - acl_e->e_tag = le16_to_cpu(entry->e_tag); - acl_e->e_perm = le16_to_cpu(entry->e_perm); - - switch(acl_e->e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - break; - - case ACL_USER: - acl_e->e_uid = - make_kuid(user_ns, - le32_to_cpu(entry->e_id)); - if (!uid_valid(acl_e->e_uid)) - goto fail; - break; - case ACL_GROUP: - acl_e->e_gid = - make_kgid(user_ns, - le32_to_cpu(entry->e_id)); - if (!gid_valid(acl_e->e_gid)) - goto fail; - break; - - default: - goto fail; - } - } - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} -EXPORT_SYMBOL (posix_acl_from_xattr); - -/* - * Convert from in-memory to extended attribute representation. - */ -int -posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, - void *buffer, size_t size) -{ - posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; - posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; - int real_size, n; - - real_size = posix_acl_xattr_size(acl->a_count); - if (!buffer) - return real_size; - if (real_size > size) - return -ERANGE; - - ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); - - for (n=0; n < acl->a_count; n++, ext_entry++) { - const struct posix_acl_entry *acl_e = &acl->a_entries[n]; - ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); - ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); - switch(acl_e->e_tag) { - case ACL_USER: - ext_entry->e_id = - cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); - break; - case ACL_GROUP: - ext_entry->e_id = - cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); - break; - default: - ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); - break; - } - } - return real_size; -} -EXPORT_SYMBOL (posix_acl_to_xattr); diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 370eb3e121d1..0ecec1896f25 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -124,16 +124,12 @@ struct posix_acl * xfs_get_acl(struct inode *inode, int type) { struct xfs_inode *ip = XFS_I(inode); - struct posix_acl *acl; + struct posix_acl *acl = NULL; struct xfs_acl *xfs_acl; unsigned char *ea_name; int error; int len; - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - trace_xfs_get_acl(ip); switch (type) { @@ -164,10 +160,8 @@ xfs_get_acl(struct inode *inode, int type) * cache entry, for any other error assume it is transient and * leave the cache entry as ACL_NOT_CACHED. */ - if (error == -ENOATTR) { - acl = NULL; + if (error == -ENOATTR) goto out_update_cache; - } goto out; } @@ -183,15 +177,12 @@ out: } STATIC int -xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct xfs_inode *ip = XFS_I(inode); unsigned char *ea_name; int error; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; @@ -282,131 +273,23 @@ posix_acl_default_exists(struct inode *inode) return xfs_acl_exists(inode, SGI_ACL_DEFAULT); } -/* - * No need for i_mutex because the inode is not yet exposed to the VFS. - */ int -xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) +xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - umode_t mode = inode->i_mode; - int error = 0, inherit = 0; - - if (S_ISDIR(inode->i_mode)) { - error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto out; - } - - error = posix_acl_create(&acl, GFP_KERNEL, &mode); - if (error < 0) - return error; - - /* - * If posix_acl_create returns a positive value we need to - * inherit a permission that can't be represented using the Unix - * mode bits and we actually need to set an ACL. - */ - if (error > 0) - inherit = 1; - - error = xfs_set_mode(inode, mode); - if (error) - goto out; - - if (inherit) - error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); - -out: - posix_acl_release(acl); - return error; -} - -int -xfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = xfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; - - error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return error; -} - -static int -xfs_xattr_acl_get(struct dentry *dentry, const char *name, - void *value, size_t size, int type) -{ - struct posix_acl *acl; - int error; - - acl = xfs_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - error = posix_acl_to_xattr(&init_user_ns, acl, value, size); - posix_acl_release(acl); - - return error; -} - -static int -xfs_xattr_acl_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - struct posix_acl *acl = NULL; int error = 0; - if (flags & XATTR_CREATE) - return -EINVAL; - if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) - return value ? -EACCES : 0; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (!value) + if (!acl) goto set_acl; - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (!acl) { - /* - * acl_set_file(3) may request that we set default ACLs with - * zero length -- defend (gracefully) against that here. - */ - goto out; - } - if (IS_ERR(acl)) { - error = PTR_ERR(acl); - goto out; - } - - error = posix_acl_valid(acl); - if (error) - goto out_release; - error = -EINVAL; if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) - goto out_release; + return error; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { - posix_acl_release(acl); acl = NULL; if (error < 0) @@ -415,27 +298,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name, error = xfs_set_mode(inode, mode); if (error) - goto out_release; + return error; } set_acl: - error = xfs_set_acl(inode, type, acl); - out_release: - posix_acl_release(acl); - out: - return error; + return __xfs_set_acl(inode, type, acl); } - -const struct xattr_handler xfs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .get = xfs_xattr_acl_get, - .set = xfs_xattr_acl_set, -}; - -const struct xattr_handler xfs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .get = xfs_xattr_acl_get, - .set = xfs_xattr_acl_set, -}; diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 4016a567b83c..5dc163744511 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -60,20 +60,15 @@ struct xfs_acl { #ifdef CONFIG_XFS_POSIX_ACL extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); -extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); -extern int xfs_acl_chmod(struct inode *inode); +extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); extern int posix_acl_access_exists(struct inode *inode); extern int posix_acl_default_exists(struct inode *inode); - -extern const struct xattr_handler xfs_xattr_acl_access_handler; -extern const struct xattr_handler xfs_xattr_acl_default_handler; #else static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) { return NULL; } -# define xfs_inherit_acl(inode, default_acl) 0 -# define xfs_acl_chmod(inode) 0 +# define xfs_set_acl NULL # define posix_acl_access_exists(inode) 0 # define posix_acl_default_exists(inode) 0 #endif /* CONFIG_XFS_POSIX_ACL */ diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 9fccfb594291..51757113a822 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -445,8 +445,8 @@ _xfs_buf_find( numbytes = BBTOB(numblks); /* Check for IOs smaller than the sector size / not sector aligned */ - ASSERT(!(numbytes < (1 << btp->bt_sshift))); - ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_smask)); + ASSERT(!(numbytes < btp->bt_meta_sectorsize)); + ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_meta_sectormask)); /* * Corrupted block numbers can get through to here, unfortunately, so we @@ -1599,9 +1599,9 @@ xfs_setsize_buftarg( unsigned int blocksize, unsigned int sectorsize) { - btp->bt_bsize = blocksize; - btp->bt_sshift = ffs(sectorsize) - 1; - btp->bt_smask = sectorsize - 1; + /* Set up metadata sector size info */ + btp->bt_meta_sectorsize = sectorsize; + btp->bt_meta_sectormask = sectorsize - 1; if (set_blocksize(btp->bt_bdev, sectorsize)) { char name[BDEVNAME_SIZE]; @@ -1614,6 +1614,10 @@ xfs_setsize_buftarg( return EINVAL; } + /* Set up device logical sector size mask */ + btp->bt_logical_sectorsize = bdev_logical_block_size(btp->bt_bdev); + btp->bt_logical_sectormask = bdev_logical_block_size(btp->bt_bdev) - 1; + return 0; } diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index 1cf21a4a9f22..995339534db6 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -88,14 +88,28 @@ typedef unsigned int xfs_buf_flags_t; */ #define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */ +/* + * The xfs_buftarg contains 2 notions of "sector size" - + * + * 1) The metadata sector size, which is the minimum unit and + * alignment of IO which will be performed by metadata operations. + * 2) The device logical sector size + * + * The first is specified at mkfs time, and is stored on-disk in the + * superblock's sb_sectsize. + * + * The latter is derived from the underlying device, and controls direct IO + * alignment constraints. + */ typedef struct xfs_buftarg { dev_t bt_dev; struct block_device *bt_bdev; struct backing_dev_info *bt_bdi; struct xfs_mount *bt_mount; - unsigned int bt_bsize; - unsigned int bt_sshift; - size_t bt_smask; + unsigned int bt_meta_sectorsize; + size_t bt_meta_sectormask; + size_t bt_logical_sectorsize; + size_t bt_logical_sectormask; /* LRU control structures */ struct shrinker bt_shrinker; diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index e00121592632..2e7989e3a2d6 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -261,7 +261,8 @@ xfs_file_aio_read( xfs_buftarg_t *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; - if ((pos & target->bt_smask) || (size & target->bt_smask)) { + /* DIO must be aligned to device logical sector size */ + if ((pos | size) & target->bt_logical_sectormask) { if (pos == i_size_read(inode)) return 0; return -XFS_ERROR(EINVAL); @@ -641,9 +642,11 @@ xfs_file_dio_aio_write( struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; - if ((pos & target->bt_smask) || (count & target->bt_smask)) + /* DIO must be aligned to device logical sector size */ + if ((pos | count) & target->bt_logical_sectormask) return -XFS_ERROR(EINVAL); + /* "unaligned" here means not aligned to a filesystem block */ if ((pos & mp->m_blockmask) || ((pos + count) & mp->m_blockmask)) unaligned_io = 1; diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 518aa56b8f2e..bcfe61202115 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1583,7 +1583,7 @@ xfs_file_ioctl( XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; - da.d_mem = da.d_miniosz = 1 << target->bt_sshift; + da.d_mem = da.d_miniosz = target->bt_logical_sectorsize; da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); if (copy_to_user(arg, &da, sizeof(da))) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 0ce1d759156e..f35d5c953ff9 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -123,7 +123,7 @@ xfs_vn_mknod( { struct inode *inode; struct xfs_inode *ip = NULL; - struct posix_acl *default_acl = NULL; + struct posix_acl *default_acl, *acl; struct xfs_name name; int error; @@ -139,14 +139,9 @@ xfs_vn_mknod( rdev = 0; } - if (IS_POSIXACL(dir)) { - default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(default_acl)) - return PTR_ERR(default_acl); - - if (!default_acl) - mode &= ~current_umask(); - } + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) + return error; xfs_dentry_to_name(&name, dentry, mode); error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); @@ -159,22 +154,30 @@ xfs_vn_mknod( if (unlikely(error)) goto out_cleanup_inode; +#ifdef CONFIG_XFS_POSIX_ACL if (default_acl) { - error = -xfs_inherit_acl(inode, default_acl); - default_acl = NULL; - if (unlikely(error)) + error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); + if (error) goto out_cleanup_inode; } - + if (acl) { + error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); + if (error) + goto out_cleanup_inode; + } +#endif d_instantiate(dentry, inode); + out_free_acl: + if (default_acl) + posix_acl_release(default_acl); + if (acl) + posix_acl_release(acl); return -error; out_cleanup_inode: xfs_cleanup_inode(dir, inode, dentry); - out_free_acl: - posix_acl_release(default_acl); - return -error; + goto out_free_acl; } STATIC int @@ -391,18 +394,6 @@ xfs_vn_follow_link( return NULL; } -STATIC void -xfs_vn_put_link( - struct dentry *dentry, - struct nameidata *nd, - void *p) -{ - char *s = nd_get_link(nd); - - if (!IS_ERR(s)) - kfree(s); -} - STATIC int xfs_vn_getattr( struct vfsmount *mnt, @@ -688,7 +679,7 @@ xfs_setattr_nonsize( * Posix ACL code seems to care about this issue either. */ if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { - error = -xfs_acl_chmod(inode); + error = -posix_acl_chmod(inode, inode->i_mode); if (error) return XFS_ERROR(error); } @@ -1045,6 +1036,7 @@ xfs_vn_fiemap( static const struct inode_operations xfs_inode_operations = { .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1072,6 +1064,7 @@ static const struct inode_operations xfs_dir_inode_operations = { .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1098,6 +1091,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .get_acl = xfs_get_acl, + .set_acl = xfs_set_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1110,8 +1104,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { static const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, - .put_link = xfs_vn_put_link, - .get_acl = xfs_get_acl, + .put_link = kfree_put_link, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h index d2c5057b5cc4..1c34e4335920 100644 --- a/fs/xfs/xfs_iops.h +++ b/fs/xfs/xfs_iops.h @@ -30,7 +30,7 @@ extern void xfs_setup_inode(struct xfs_inode *); /* * Internal setattr interfaces. */ -#define XFS_ATTR_NOACL 0x01 /* Don't call xfs_acl_chmod */ +#define XFS_ATTR_NOACL 0x01 /* Don't call posix_acl_chmod */ extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags); diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 9d479073ba41..78ed92a46fdd 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -102,8 +102,8 @@ const struct xattr_handler *xfs_xattr_handlers[] = { &xfs_xattr_trusted_handler, &xfs_xattr_security_handler, #ifdef CONFIG_XFS_POSIX_ACL - &xfs_xattr_acl_access_handler, - &xfs_xattr_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index db0923458940..8e4f41d9af4d 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -558,6 +558,18 @@ static inline pmd_t pmd_read_atomic(pmd_t *pmdp) } #endif +#ifndef pmd_move_must_withdraw +static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl, + spinlock_t *old_pmd_ptl) +{ + /* + * With split pmd lock we also need to move preallocated + * PTE page table if new_pmd is on different PMD page table. + */ + return new_pmd_ptl != old_pmd_ptl; +} +#endif + /* * This function is meant to be used by sites walking pagetables with * the mmap_sem hold in read mode to protect against MADV_DONTNEED and diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8974.h b/include/dt-bindings/clock/qcom,mmcc-msm8974.h index 04d318d1187a..032ed87ef0f3 100644 --- a/include/dt-bindings/clock/qcom,mmcc-msm8974.h +++ b/include/dt-bindings/clock/qcom,mmcc-msm8974.h @@ -57,7 +57,7 @@ #define EXTPCLK_CLK_SRC 40 #define HDMI_CLK_SRC 41 #define VSYNC_CLK_SRC 42 -#define RBCPR_CLK_SRC 43 +#define MMSS_RBCPR_CLK_SRC 43 #define CAMSS_CCI_CCI_AHB_CLK 44 #define CAMSS_CCI_CCI_CLK 45 #define CAMSS_CSI0_AHB_CLK 46 diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 2fae55def608..b388223bd4a9 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -175,6 +175,27 @@ static inline void * __init memblock_virt_alloc_nopanic( NUMA_NO_NODE); } +#ifndef ARCH_LOW_ADDRESS_LIMIT +#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL +#endif + +static inline void * __init memblock_virt_alloc_low( + phys_addr_t size, phys_addr_t align) +{ + return memblock_virt_alloc_try_nid(size, align, + BOOTMEM_LOW_LIMIT, + ARCH_LOW_ADDRESS_LIMIT, + NUMA_NO_NODE); +} +static inline void * __init memblock_virt_alloc_low_nopanic( + phys_addr_t size, phys_addr_t align) +{ + return memblock_virt_alloc_try_nid_nopanic(size, align, + BOOTMEM_LOW_LIMIT, + ARCH_LOW_ADDRESS_LIMIT, + NUMA_NO_NODE); +} + static inline void * __init memblock_virt_alloc_from_nopanic( phys_addr_t size, phys_addr_t align, phys_addr_t min_addr) { @@ -238,6 +259,22 @@ static inline void * __init memblock_virt_alloc_nopanic( return __alloc_bootmem_nopanic(size, align, BOOTMEM_LOW_LIMIT); } +static inline void * __init memblock_virt_alloc_low( + phys_addr_t size, phys_addr_t align) +{ + if (!align) + align = SMP_CACHE_BYTES; + return __alloc_bootmem_low(size, align, BOOTMEM_LOW_LIMIT); +} + +static inline void * __init memblock_virt_alloc_low_nopanic( + phys_addr_t size, phys_addr_t align) +{ + if (!align) + align = SMP_CACHE_BYTES; + return __alloc_bootmem_low_nopanic(size, align, BOOTMEM_LOW_LIMIT); +} + static inline void * __init memblock_virt_alloc_from_nopanic( phys_addr_t size, phys_addr_t align, phys_addr_t min_addr) { diff --git a/include/linux/ceph/buffer.h b/include/linux/ceph/buffer.h index 58d19014068f..07ad423cc37f 100644 --- a/include/linux/ceph/buffer.h +++ b/include/linux/ceph/buffer.h @@ -17,7 +17,6 @@ struct ceph_buffer { struct kref kref; struct kvec vec; size_t alloc_len; - bool is_vmalloc; }; extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp); diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h index 4c42080347af..138448f766b4 100644 --- a/include/linux/ceph/ceph_features.h +++ b/include/linux/ceph/ceph_features.h @@ -4,42 +4,73 @@ /* * feature bits */ -#define CEPH_FEATURE_UID (1<<0) -#define CEPH_FEATURE_NOSRCADDR (1<<1) -#define CEPH_FEATURE_MONCLOCKCHECK (1<<2) -#define CEPH_FEATURE_FLOCK (1<<3) -#define CEPH_FEATURE_SUBSCRIBE2 (1<<4) -#define CEPH_FEATURE_MONNAMES (1<<5) -#define CEPH_FEATURE_RECONNECT_SEQ (1<<6) -#define CEPH_FEATURE_DIRLAYOUTHASH (1<<7) -#define CEPH_FEATURE_OBJECTLOCATOR (1<<8) -#define CEPH_FEATURE_PGID64 (1<<9) -#define CEPH_FEATURE_INCSUBOSDMAP (1<<10) -#define CEPH_FEATURE_PGPOOL3 (1<<11) -#define CEPH_FEATURE_OSDREPLYMUX (1<<12) -#define CEPH_FEATURE_OSDENC (1<<13) -#define CEPH_FEATURE_OMAP (1<<14) -#define CEPH_FEATURE_MONENC (1<<15) -#define CEPH_FEATURE_QUERY_T (1<<16) -#define CEPH_FEATURE_INDEP_PG_MAP (1<<17) -#define CEPH_FEATURE_CRUSH_TUNABLES (1<<18) -#define CEPH_FEATURE_CHUNKY_SCRUB (1<<19) -#define CEPH_FEATURE_MON_NULLROUTE (1<<20) -#define CEPH_FEATURE_MON_GV (1<<21) -#define CEPH_FEATURE_BACKFILL_RESERVATION (1<<22) -#define CEPH_FEATURE_MSG_AUTH (1<<23) -#define CEPH_FEATURE_RECOVERY_RESERVATION (1<<24) -#define CEPH_FEATURE_CRUSH_TUNABLES2 (1<<25) -#define CEPH_FEATURE_CREATEPOOLID (1<<26) -#define CEPH_FEATURE_REPLY_CREATE_INODE (1<<27) -#define CEPH_FEATURE_OSD_HBMSGS (1<<28) -#define CEPH_FEATURE_MDSENC (1<<29) -#define CEPH_FEATURE_OSDHASHPSPOOL (1<<30) +#define CEPH_FEATURE_UID (1ULL<<0) +#define CEPH_FEATURE_NOSRCADDR (1ULL<<1) +#define CEPH_FEATURE_MONCLOCKCHECK (1ULL<<2) +#define CEPH_FEATURE_FLOCK (1ULL<<3) +#define CEPH_FEATURE_SUBSCRIBE2 (1ULL<<4) +#define CEPH_FEATURE_MONNAMES (1ULL<<5) +#define CEPH_FEATURE_RECONNECT_SEQ (1ULL<<6) +#define CEPH_FEATURE_DIRLAYOUTHASH (1ULL<<7) +#define CEPH_FEATURE_OBJECTLOCATOR (1ULL<<8) +#define CEPH_FEATURE_PGID64 (1ULL<<9) +#define CEPH_FEATURE_INCSUBOSDMAP (1ULL<<10) +#define CEPH_FEATURE_PGPOOL3 (1ULL<<11) +#define CEPH_FEATURE_OSDREPLYMUX (1ULL<<12) +#define CEPH_FEATURE_OSDENC (1ULL<<13) +#define CEPH_FEATURE_OMAP (1ULL<<14) +#define CEPH_FEATURE_MONENC (1ULL<<15) +#define CEPH_FEATURE_QUERY_T (1ULL<<16) +#define CEPH_FEATURE_INDEP_PG_MAP (1ULL<<17) +#define CEPH_FEATURE_CRUSH_TUNABLES (1ULL<<18) +#define CEPH_FEATURE_CHUNKY_SCRUB (1ULL<<19) +#define CEPH_FEATURE_MON_NULLROUTE (1ULL<<20) +#define CEPH_FEATURE_MON_GV (1ULL<<21) +#define CEPH_FEATURE_BACKFILL_RESERVATION (1ULL<<22) +#define CEPH_FEATURE_MSG_AUTH (1ULL<<23) +#define CEPH_FEATURE_RECOVERY_RESERVATION (1ULL<<24) +#define CEPH_FEATURE_CRUSH_TUNABLES2 (1ULL<<25) +#define CEPH_FEATURE_CREATEPOOLID (1ULL<<26) +#define CEPH_FEATURE_REPLY_CREATE_INODE (1ULL<<27) +#define CEPH_FEATURE_OSD_HBMSGS (1ULL<<28) +#define CEPH_FEATURE_MDSENC (1ULL<<29) +#define CEPH_FEATURE_OSDHASHPSPOOL (1ULL<<30) +#define CEPH_FEATURE_MON_SINGLE_PAXOS (1ULL<<31) +#define CEPH_FEATURE_OSD_SNAPMAPPER (1ULL<<32) +#define CEPH_FEATURE_MON_SCRUB (1ULL<<33) +#define CEPH_FEATURE_OSD_PACKED_RECOVERY (1ULL<<34) +#define CEPH_FEATURE_OSD_CACHEPOOL (1ULL<<35) +#define CEPH_FEATURE_CRUSH_V2 (1ULL<<36) /* new indep; SET_* steps */ +#define CEPH_FEATURE_EXPORT_PEER (1ULL<<37) +#define CEPH_FEATURE_OSD_ERASURE_CODES (1ULL<<38) + +/* + * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature + * vector to evaluate to 64 bit ~0. To cope, we designate 1ULL << 63 + * to mean 33 bit ~0, and introduce a helper below to do the + * translation. + * + * This was introduced by ceph.git commit + * 9ea02b84104045c2ffd7e7f4e7af512953855ecd v0.58-657-g9ea02b8 + * and fixed by ceph.git commit + * 4255b5c2fb54ae40c53284b3ab700fdfc7e61748 v0.65-263-g4255b5c + */ +#define CEPH_FEATURE_RESERVED (1ULL<<63) + +static inline u64 ceph_sanitize_features(u64 features) +{ + if (features & CEPH_FEATURE_RESERVED) { + /* everything through OSD_SNAPMAPPER */ + return 0x1ffffffffull; + } else { + return features; + } +} /* * Features supported. */ -#define CEPH_FEATURES_SUPPORTED_DEFAULT \ +#define CEPH_FEATURES_SUPPORTED_DEFAULT \ (CEPH_FEATURE_NOSRCADDR | \ CEPH_FEATURE_RECONNECT_SEQ | \ CEPH_FEATURE_PGID64 | \ @@ -48,7 +79,10 @@ CEPH_FEATURE_CRUSH_TUNABLES | \ CEPH_FEATURE_CRUSH_TUNABLES2 | \ CEPH_FEATURE_REPLY_CREATE_INODE | \ - CEPH_FEATURE_OSDHASHPSPOOL) + CEPH_FEATURE_OSDHASHPSPOOL | \ + CEPH_FEATURE_OSD_CACHEPOOL | \ + CEPH_FEATURE_CRUSH_V2 | \ + CEPH_FEATURE_EXPORT_PEER) #define CEPH_FEATURES_REQUIRED_DEFAULT \ (CEPH_FEATURE_NOSRCADDR | \ @@ -56,4 +90,5 @@ CEPH_FEATURE_PGID64 | \ CEPH_FEATURE_PGPOOL3 | \ CEPH_FEATURE_OSDENC) + #endif diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 2ad7b860f062..2623cffc73a1 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -53,6 +53,29 @@ struct ceph_file_layout { __le32 fl_pg_pool; /* namespace, crush ruleset, rep level */ } __attribute__ ((packed)); +#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit)) +#define ceph_file_layout_stripe_count(l) \ + ((__s32)le32_to_cpu((l).fl_stripe_count)) +#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size)) +#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash)) +#define ceph_file_layout_object_su(l) \ + ((__s32)le32_to_cpu((l).fl_object_stripe_unit)) +#define ceph_file_layout_pg_pool(l) \ + ((__s32)le32_to_cpu((l).fl_pg_pool)) + +static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l) +{ + return le32_to_cpu(l->fl_stripe_unit) * + le32_to_cpu(l->fl_stripe_count); +} + +/* "period" == bytes before i start on a new set of objects */ +static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l) +{ + return le32_to_cpu(l->fl_object_size) * + le32_to_cpu(l->fl_stripe_count); +} + #define CEPH_MIN_STRIPE_UNIT 65536 int ceph_file_layout_is_valid(const struct ceph_file_layout *layout); @@ -282,6 +305,8 @@ enum { CEPH_SESSION_RENEWCAPS, CEPH_SESSION_STALE, CEPH_SESSION_RECALL_STATE, + CEPH_SESSION_FLUSHMSG, + CEPH_SESSION_FLUSHMSG_ACK, }; extern const char *ceph_session_op_name(int op); @@ -457,7 +482,8 @@ struct ceph_mds_reply_cap { __u8 flags; /* CEPH_CAP_FLAG_* */ } __attribute__ ((packed)); -#define CEPH_CAP_FLAG_AUTH 1 /* cap is issued by auth mds */ +#define CEPH_CAP_FLAG_AUTH (1 << 0) /* cap is issued by auth mds */ +#define CEPH_CAP_FLAG_RELEASE (1 << 1) /* release the cap */ /* inode record, for bundling with mds reply */ struct ceph_mds_reply_inode { @@ -658,6 +684,14 @@ struct ceph_mds_caps { __le32 time_warp_seq; } __attribute__ ((packed)); +struct ceph_mds_cap_peer { + __le64 cap_id; + __le32 seq; + __le32 mseq; + __le32 mds; + __u8 flags; +} __attribute__ ((packed)); + /* cap release msg head */ struct ceph_mds_cap_release { __le32 num; /* number of cap_items that follow */ diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 2e3024881a5e..2f49aa4c4f7f 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -122,8 +122,8 @@ struct ceph_client { int (*extra_mon_dispatch)(struct ceph_client *, struct ceph_msg *); - u32 supported_features; - u32 required_features; + u64 supported_features; + u64 required_features; struct ceph_messenger msgr; /* messenger instance */ struct ceph_mon_client monc; @@ -173,15 +173,18 @@ static inline int calc_pages_for(u64 off, u64 len) (off >> PAGE_CACHE_SHIFT); } +extern struct kmem_cache *ceph_inode_cachep; +extern struct kmem_cache *ceph_cap_cachep; +extern struct kmem_cache *ceph_dentry_cachep; +extern struct kmem_cache *ceph_file_cachep; + /* ceph_common.c */ extern bool libceph_compatible(void *data); extern const char *ceph_msg_type_name(int type); extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid); -extern struct kmem_cache *ceph_inode_cachep; -extern struct kmem_cache *ceph_cap_cachep; -extern struct kmem_cache *ceph_dentry_cachep; -extern struct kmem_cache *ceph_file_cachep; +extern void *ceph_kvmalloc(size_t size, gfp_t flags); +extern void ceph_kvfree(const void *ptr); extern struct ceph_options *ceph_parse_options(char *options, const char *dev_name, const char *dev_name_end, @@ -192,8 +195,8 @@ extern int ceph_compare_options(struct ceph_options *new_opt, struct ceph_client *client); extern struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, - unsigned supported_features, - unsigned required_features); + u64 supported_features, + u64 required_features); extern u64 ceph_client_id(struct ceph_client *client); extern void ceph_destroy_client(struct ceph_client *client); extern int __ceph_open_session(struct ceph_client *client, diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 7c1420bb1dce..20ee8b63a968 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -60,8 +60,8 @@ struct ceph_messenger { u32 global_seq; spinlock_t global_seq_lock; - u32 supported_features; - u32 required_features; + u64 supported_features; + u64 required_features; }; enum ceph_msg_data_type { @@ -154,10 +154,9 @@ struct ceph_msg { struct list_head list_head; /* links for connection lists */ struct kref kref; - bool front_is_vmalloc; bool more_to_follow; bool needs_out_seq; - int front_max; + int front_alloc_len; unsigned long ack_stamp; /* tx: when we were acked */ struct ceph_msgpool *pool; @@ -192,7 +191,7 @@ struct ceph_connection { struct ceph_entity_name peer_name; /* peer name */ - unsigned peer_features; + u64 peer_features; u32 connect_seq; /* identify the most recent connection attempt for this connection, client */ u32 peer_global_seq; /* peer's global seq for this connection */ @@ -256,8 +255,8 @@ extern void ceph_msgr_flush(void); extern void ceph_messenger_init(struct ceph_messenger *msgr, struct ceph_entity_addr *myaddr, - u32 supported_features, - u32 required_features, + u64 supported_features, + u64 required_features, bool nocrc); extern void ceph_con_init(struct ceph_connection *con, void *private, diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 8f47625a0661..fd47e872ebcc 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -12,12 +12,6 @@ #include <linux/ceph/auth.h> #include <linux/ceph/pagelist.h> -/* - * Maximum object name size - * (must be at least as big as RBD_MAX_MD_NAME_LEN -- currently 100) - */ -#define MAX_OBJ_NAME_SIZE 100 - struct ceph_msg; struct ceph_snap_context; struct ceph_osd_request; @@ -138,6 +132,7 @@ struct ceph_osd_request { __le64 *r_request_pool; void *r_request_pgid; __le32 *r_request_attempts; + bool r_paused; struct ceph_eversion *r_request_reassert_version; int r_result; @@ -158,15 +153,21 @@ struct ceph_osd_request { struct inode *r_inode; /* for use by callbacks */ void *r_priv; /* ditto */ - char r_oid[MAX_OBJ_NAME_SIZE]; /* object name */ - int r_oid_len; + struct ceph_object_locator r_base_oloc; + struct ceph_object_id r_base_oid; + struct ceph_object_locator r_target_oloc; + struct ceph_object_id r_target_oid; + u64 r_snapid; unsigned long r_stamp; /* send OR check time */ - struct ceph_file_layout r_file_layout; struct ceph_snap_context *r_snapc; /* snap context for writes */ }; +struct ceph_request_redirect { + struct ceph_object_locator oloc; +}; + struct ceph_osd_event { u64 cookie; int one_shot; diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index d05cc4451af6..49ff69f0746b 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -35,13 +35,26 @@ struct ceph_pg_pool_info { u8 object_hash; u32 pg_num, pgp_num; int pg_num_mask, pgp_num_mask; + s64 read_tier; + s64 write_tier; /* wins for read+write ops */ u64 flags; char *name; }; struct ceph_object_locator { - uint64_t pool; - char *key; + s64 pool; +}; + +/* + * Maximum supported by kernel client object name length + * + * (probably outdated: must be >= RBD_MAX_MD_NAME_LEN -- currently 100) + */ +#define CEPH_MAX_OID_NAME_LEN 100 + +struct ceph_object_id { + char name[CEPH_MAX_OID_NAME_LEN]; + int name_len; }; struct ceph_pg_mapping { @@ -73,33 +86,30 @@ struct ceph_osdmap { struct crush_map *crush; }; -/* - * file layout helpers - */ -#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit)) -#define ceph_file_layout_stripe_count(l) \ - ((__s32)le32_to_cpu((l).fl_stripe_count)) -#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size)) -#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash)) -#define ceph_file_layout_object_su(l) \ - ((__s32)le32_to_cpu((l).fl_object_stripe_unit)) -#define ceph_file_layout_pg_pool(l) \ - ((__s32)le32_to_cpu((l).fl_pg_pool)) - -static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l) +static inline void ceph_oid_set_name(struct ceph_object_id *oid, + const char *name) { - return le32_to_cpu(l->fl_stripe_unit) * - le32_to_cpu(l->fl_stripe_count); + int len; + + len = strlen(name); + if (len > sizeof(oid->name)) { + WARN(1, "ceph_oid_set_name '%s' len %d vs %zu, truncating\n", + name, len, sizeof(oid->name)); + len = sizeof(oid->name); + } + + memcpy(oid->name, name, len); + oid->name_len = len; } -/* "period" == bytes before i start on a new set of objects */ -static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l) +static inline void ceph_oid_copy(struct ceph_object_id *dest, + struct ceph_object_id *src) { - return le32_to_cpu(l->fl_object_size) * - le32_to_cpu(l->fl_stripe_count); + BUG_ON(src->name_len > sizeof(dest->name)); + memcpy(dest->name, src->name, src->name_len); + dest->name_len = src->name_len; } - static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd) { return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP); @@ -155,14 +165,20 @@ extern int ceph_calc_file_object_mapping(struct ceph_file_layout *layout, u64 *bno, u64 *oxoff, u64 *oxlen); /* calculate mapping of object to a placement group */ -extern int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid, - struct ceph_osdmap *osdmap, uint64_t pool); +extern int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap, + struct ceph_object_locator *oloc, + struct ceph_object_id *oid, + struct ceph_pg *pg_out); + extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid, int *acting); extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid); +extern struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map, + u64 id); + extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id); extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name); diff --git a/include/linux/ceph/rados.h b/include/linux/ceph/rados.h index 68c96a508ac2..96292df4041b 100644 --- a/include/linux/ceph/rados.h +++ b/include/linux/ceph/rados.h @@ -344,6 +344,10 @@ enum { CEPH_OSD_FLAG_EXEC_PUBLIC = 0x1000, /* DEPRECATED op may exec (public) */ CEPH_OSD_FLAG_LOCALIZE_READS = 0x2000, /* read from nearby replica, if any */ CEPH_OSD_FLAG_RWORDERED = 0x4000, /* order wrt concurrent reads */ + CEPH_OSD_FLAG_IGNORE_CACHE = 0x8000, /* ignore cache logic */ + CEPH_OSD_FLAG_SKIPRWLOCKS = 0x10000, /* skip rw locks */ + CEPH_OSD_FLAG_IGNORE_OVERLAY = 0x20000, /* ignore pool overlay */ + CEPH_OSD_FLAG_FLUSH = 0x40000, /* this is part of flush */ }; enum { diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 999b28ba38f7..448b2294820f 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -488,6 +488,8 @@ struct clk_onecell_data { unsigned int clk_num; }; +extern struct of_device_id __clk_of_table; + #define CLK_OF_DECLARE(name, compat, fn) \ static const struct of_device_id __clk_of_table_##name \ __used __section(__clk_of_table) \ diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h new file mode 100644 index 000000000000..092b64168d7f --- /dev/null +++ b/include/linux/clk/ti.h @@ -0,0 +1,298 @@ +/* + * TI clock drivers support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __LINUX_CLK_TI_H__ +#define __LINUX_CLK_TI_H__ + +#include <linux/clkdev.h> + +/** + * struct dpll_data - DPLL registers and integration data + * @mult_div1_reg: register containing the DPLL M and N bitfields + * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg + * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg + * @clk_bypass: struct clk pointer to the clock's bypass clock input + * @clk_ref: struct clk pointer to the clock's reference clock input + * @control_reg: register containing the DPLL mode bitfield + * @enable_mask: mask of the DPLL mode bitfield in @control_reg + * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() + * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() + * @last_rounded_m4xen: cache of the last M4X result of + * omap4_dpll_regm4xen_round_rate() + * @last_rounded_lpmode: cache of the last lpmode result of + * omap4_dpll_lpmode_recalc() + * @max_multiplier: maximum valid non-bypass multiplier value (actual) + * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() + * @min_divider: minimum valid non-bypass divider value (actual) + * @max_divider: maximum valid non-bypass divider value (actual) + * @modes: possible values of @enable_mask + * @autoidle_reg: register containing the DPLL autoidle mode bitfield + * @idlest_reg: register containing the DPLL idle status bitfield + * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg + * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg + * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg + * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg + * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg + * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg + * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs + * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs + * @flags: DPLL type/features (see below) + * + * Possible values for @flags: + * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs) + * + * @freqsel_mask is only used on the OMAP34xx family and AM35xx. + * + * XXX Some DPLLs have multiple bypass inputs, so it's not technically + * correct to only have one @clk_bypass pointer. + * + * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m, + * @last_rounded_n) should be separated from the runtime-fixed fields + * and placed into a different structure, so that the runtime-fixed data + * can be placed into read-only space. + */ +struct dpll_data { + void __iomem *mult_div1_reg; + u32 mult_mask; + u32 div1_mask; + struct clk *clk_bypass; + struct clk *clk_ref; + void __iomem *control_reg; + u32 enable_mask; + unsigned long last_rounded_rate; + u16 last_rounded_m; + u8 last_rounded_m4xen; + u8 last_rounded_lpmode; + u16 max_multiplier; + u8 last_rounded_n; + u8 min_divider; + u16 max_divider; + u8 modes; + void __iomem *autoidle_reg; + void __iomem *idlest_reg; + u32 autoidle_mask; + u32 freqsel_mask; + u32 idlest_mask; + u32 dco_mask; + u32 sddiv_mask; + u32 lpmode_mask; + u32 m4xen_mask; + u8 auto_recal_bit; + u8 recal_en_bit; + u8 recal_st_bit; + u8 flags; +}; + +struct clk_hw_omap_ops; + +/** + * struct clk_hw_omap - OMAP struct clk + * @node: list_head connecting this clock into the full clock list + * @enable_reg: register to write to enable the clock (see @enable_bit) + * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) + * @flags: see "struct clk.flags possibilities" above + * @clksel_reg: for clksel clks, register va containing src/divisor select + * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector + * @clksel: for clksel clks, pointer to struct clksel for this clock + * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock + * @clkdm_name: clockdomain name that this clock is contained in + * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime + * @ops: clock ops for this clock + */ +struct clk_hw_omap { + struct clk_hw hw; + struct list_head node; + unsigned long fixed_rate; + u8 fixed_div; + void __iomem *enable_reg; + u8 enable_bit; + u8 flags; + void __iomem *clksel_reg; + u32 clksel_mask; + const struct clksel *clksel; + struct dpll_data *dpll_data; + const char *clkdm_name; + struct clockdomain *clkdm; + const struct clk_hw_omap_ops *ops; +}; + +/* + * struct clk_hw_omap.flags possibilities + * + * XXX document the rest of the clock flags here + * + * ENABLE_REG_32BIT: (OMAP1 only) clock control register must be accessed + * with 32bit ops, by default OMAP1 uses 16bit ops. + * CLOCK_IDLE_CONTROL: (OMAP1 only) clock has autoidle support. + * CLOCK_NO_IDLE_PARENT: (OMAP1 only) when clock is enabled, its parent + * clock is put to no-idle mode. + * ENABLE_ON_INIT: Clock is enabled on init. + * INVERT_ENABLE: By default, clock enable bit behavior is '1' enable, '0' + * disable. This inverts the behavior making '0' enable and '1' disable. + * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL + * bits share the same register. This flag allows the + * omap4_dpllmx*() code to determine which GATE_CTRL bit field + * should be used. This is a temporary solution - a better approach + * would be to associate clock type-specific data with the clock, + * similar to the struct dpll_data approach. + * MEMMAP_ADDRESSING: Use memmap addressing to access clock registers. + */ +#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */ +#define CLOCK_IDLE_CONTROL (1 << 1) +#define CLOCK_NO_IDLE_PARENT (1 << 2) +#define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */ +#define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */ +#define CLOCK_CLKOUTX2 (1 << 5) +#define MEMMAP_ADDRESSING (1 << 6) + +/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ +#define DPLL_LOW_POWER_STOP 0x1 +#define DPLL_LOW_POWER_BYPASS 0x5 +#define DPLL_LOCKED 0x7 + +/* DPLL Type and DCO Selection Flags */ +#define DPLL_J_TYPE 0x1 + +/* Composite clock component types */ +enum { + CLK_COMPONENT_TYPE_GATE = 0, + CLK_COMPONENT_TYPE_DIVIDER, + CLK_COMPONENT_TYPE_MUX, + CLK_COMPONENT_TYPE_MAX, +}; + +/** + * struct ti_dt_clk - OMAP DT clock alias declarations + * @lk: clock lookup definition + * @node_name: clock DT node to map to + */ +struct ti_dt_clk { + struct clk_lookup lk; + char *node_name; +}; + +#define DT_CLK(dev, con, name) \ + { \ + .lk = { \ + .dev_id = dev, \ + .con_id = con, \ + }, \ + .node_name = name, \ + } + +/* Maximum number of clock memmaps */ +#define CLK_MAX_MEMMAPS 4 + +typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); + +/** + * struct clk_omap_reg - OMAP register declaration + * @offset: offset from the master IP module base address + * @index: index of the master IP module + */ +struct clk_omap_reg { + u16 offset; + u16 index; +}; + +/** + * struct ti_clk_ll_ops - low-level register access ops for a clock + * @clk_readl: pointer to register read function + * @clk_writel: pointer to register write function + * + * Low-level register access ops are generally used by the basic clock types + * (clk-gate, clk-mux, clk-divider etc.) to provide support for various + * low-level hardware interfaces (direct MMIO, regmap etc.), but can also be + * used by other hardware-specific clock drivers if needed. + */ +struct ti_clk_ll_ops { + u32 (*clk_readl)(void __iomem *reg); + void (*clk_writel)(u32 val, void __iomem *reg); +}; + +extern struct ti_clk_ll_ops *ti_clk_ll_ops; + +extern const struct clk_ops ti_clk_divider_ops; +extern const struct clk_ops ti_clk_mux_ops; + +#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) + +void omap2_init_clk_hw_omap_clocks(struct clk *clk); +int omap3_noncore_dpll_enable(struct clk_hw *hw); +void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate); +long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, + unsigned long target_rate, + unsigned long *parent_rate); +u8 omap2_init_dpll_parent(struct clk_hw *hw); +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); +long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +void omap2_init_clk_clkdm(struct clk_hw *clk); +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, + unsigned long parent_rate); +int omap2_clkops_enable_clkdm(struct clk_hw *hw); +void omap2_clkops_disable_clkdm(struct clk_hw *hw); +int omap2_clk_disable_autoidle_all(void); +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); +int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, + unsigned long parent_rate); +int omap2_dflt_clk_enable(struct clk_hw *hw); +void omap2_dflt_clk_disable(struct clk_hw *hw); +int omap2_dflt_clk_is_enabled(struct clk_hw *hw); +void omap3_clk_lock_dpll5(void); + +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); +void ti_dt_clocks_register(struct ti_dt_clk *oclks); +void ti_dt_clk_init_provider(struct device_node *np, int index); +void ti_dt_clockdomains_setup(void); +int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func); +int of_ti_clk_autoidle_setup(struct device_node *node); +int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); + +int omap3430_dt_clk_init(void); +int omap3630_dt_clk_init(void); +int am35xx_dt_clk_init(void); +int ti81xx_dt_clk_init(void); +int omap4xxx_dt_clk_init(void); +int omap5xxx_dt_clk_init(void); +int dra7xx_dt_clk_init(void); +int am33xx_dt_clk_init(void); +int am43xx_dt_clk_init(void); + +#ifdef CONFIG_OF +void of_ti_clk_allow_autoidle_all(void); +void of_ti_clk_deny_autoidle_all(void); +#else +static inline void of_ti_clk_allow_autoidle_all(void) { } +static inline void of_ti_clk_deny_autoidle_all(void) { } +#endif + +extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; +extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; +extern const struct clk_hw_omap_ops clkhwops_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; +extern const struct clk_hw_omap_ops clkhwops_iclk; +extern const struct clk_hw_omap_ops clkhwops_iclk_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; + +#endif diff --git a/include/linux/compat.h b/include/linux/compat.h index eb8a49d75ab3..19f6003291de 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -327,16 +327,16 @@ asmlinkage long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5); asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32); -asmlinkage ssize_t compat_sys_readv(unsigned long fd, - const struct compat_iovec __user *vec, unsigned long vlen); -asmlinkage ssize_t compat_sys_writev(unsigned long fd, - const struct compat_iovec __user *vec, unsigned long vlen); -asmlinkage ssize_t compat_sys_preadv(unsigned long fd, +asmlinkage ssize_t compat_sys_readv(compat_ulong_t fd, + const struct compat_iovec __user *vec, compat_ulong_t vlen); +asmlinkage ssize_t compat_sys_writev(compat_ulong_t fd, + const struct compat_iovec __user *vec, compat_ulong_t vlen); +asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high); -asmlinkage ssize_t compat_sys_pwritev(unsigned long fd, + compat_ulong_t vlen, u32 pos_low, u32 pos_high); +asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high); + compat_ulong_t vlen, u32 pos_low, u32 pos_high); asmlinkage long comat_sys_lseek(unsigned int, compat_off_t, unsigned int); asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv, @@ -422,7 +422,7 @@ extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request, asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, compat_long_t addr, compat_long_t data); -asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, size_t); +asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); /* * epoll (fs/eventpoll.c) compat bits follow ... */ diff --git a/include/linux/cramfs_fs_sb.h b/include/linux/cramfs_fs_sb.h deleted file mode 100644 index 8390693568fd..000000000000 --- a/include/linux/cramfs_fs_sb.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _CRAMFS_FS_SB -#define _CRAMFS_FS_SB - -/* - * cramfs super-block data in memory - */ -struct cramfs_sb_info { - unsigned long magic; - unsigned long size; - unsigned long blocks; - unsigned long files; - unsigned long flags; -}; - -static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -#endif diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 6a1101f24cfb..acaa5615d634 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -19,11 +19,12 @@ #define CRUSH_MAGIC 0x00010000ul /* for detecting algorithm revisions */ - #define CRUSH_MAX_DEPTH 10 /* max crush hierarchy depth */ -#define CRUSH_MAX_SET 10 /* max size of a mapping result */ +#define CRUSH_ITEM_UNDEF 0x7ffffffe /* undefined result (internal use only) */ +#define CRUSH_ITEM_NONE 0x7fffffff /* no result */ + /* * CRUSH uses user-defined "rules" to describe how inputs should be * mapped to devices. A rule consists of sequence of steps to perform @@ -43,8 +44,13 @@ enum { /* arg2 = type */ CRUSH_RULE_CHOOSE_INDEP = 3, /* same */ CRUSH_RULE_EMIT = 4, /* no args */ - CRUSH_RULE_CHOOSE_LEAF_FIRSTN = 6, - CRUSH_RULE_CHOOSE_LEAF_INDEP = 7, + CRUSH_RULE_CHOOSELEAF_FIRSTN = 6, + CRUSH_RULE_CHOOSELEAF_INDEP = 7, + + CRUSH_RULE_SET_CHOOSE_TRIES = 8, /* override choose_total_tries */ + CRUSH_RULE_SET_CHOOSELEAF_TRIES = 9, /* override chooseleaf_descend_once */ + CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES = 10, + CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11, }; /* @@ -162,7 +168,10 @@ struct crush_map { __u32 choose_local_fallback_tries; /* choose attempts before giving up */ __u32 choose_total_tries; - /* attempt chooseleaf inner descent once; on failure retry outer descent */ + /* attempt chooseleaf inner descent once for firstn mode; on + * reject retry outer descent. Note that this does *not* + * apply to a collision: in that case we will retry as we used + * to. */ __u32 chooseleaf_descend_once; }; @@ -174,6 +183,7 @@ extern void crush_destroy_bucket_list(struct crush_bucket_list *b); extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b); extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b); extern void crush_destroy_bucket(struct crush_bucket *b); +extern void crush_destroy_rule(struct crush_rule *r); extern void crush_destroy(struct crush_map *map); static inline int crush_calc_tree_node(int i) diff --git a/include/linux/crush/mapper.h b/include/linux/crush/mapper.h index 5772dee3ecbf..eab367446eea 100644 --- a/include/linux/crush/mapper.h +++ b/include/linux/crush/mapper.h @@ -14,6 +14,7 @@ extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, i extern int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, - const __u32 *weights); + const __u32 *weights, int weight_max, + int *scratch); #endif diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 085197bd8812..70e8e21c0a30 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -59,29 +59,36 @@ struct files_struct { struct file __rcu * fd_array[NR_OPEN_DEFAULT]; }; -#define rcu_dereference_check_fdtable(files, fdtfd) \ - (rcu_dereference_check((fdtfd), \ - lockdep_is_held(&(files)->file_lock) || \ - atomic_read(&(files)->count) == 1 || \ - rcu_my_thread_group_empty())) - -#define files_fdtable(files) \ - (rcu_dereference_check_fdtable((files), (files)->fdt)) - struct file_operations; struct vfsmount; struct dentry; extern void __init files_defer_init(void); -static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) +#define rcu_dereference_check_fdtable(files, fdtfd) \ + rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock)) + +#define files_fdtable(files) \ + rcu_dereference_check_fdtable((files), (files)->fdt) + +/* + * The caller must ensure that fd table isn't shared or hold rcu or file lock + */ +static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd) { - struct file * file = NULL; - struct fdtable *fdt = files_fdtable(files); + struct fdtable *fdt = rcu_dereference_raw(files->fdt); if (fd < fdt->max_fds) - file = rcu_dereference_check_fdtable(files, fdt->fd[fd]); - return file; + return rcu_dereference_raw(fdt->fd[fd]); + return NULL; +} + +static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) +{ + rcu_lockdep_assert(rcu_read_lock_held() || + lockdep_is_held(&files->file_lock), + "suspicious rcu_dereference_check() usage"); + return __fcheck_files(files, fd); } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 121f11f001c0..09f553c59813 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1580,6 +1580,7 @@ struct inode_operations { struct file *, unsigned open_flag, umode_t create_mode, int *opened); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*set_acl)(struct inode *, struct posix_acl *, int); } ____cacheline_aligned; ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 7d8d5e608594..3d286ff49ab0 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -322,10 +322,10 @@ extern int fsnotify_fasync(int fd, struct file *file, int on); extern void fsnotify_destroy_event(struct fsnotify_group *group, struct fsnotify_event *event); /* attach the event to the group notification queue */ -extern struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, - struct fsnotify_event *event, - struct fsnotify_event *(*merge)(struct list_head *, - struct fsnotify_event *)); +extern int fsnotify_add_notify_event(struct fsnotify_group *group, + struct fsnotify_event *event, + int (*merge)(struct list_head *, + struct fsnotify_event *)); /* true if the group notification queue is empty */ extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); /* return, but do not dequeue the first event on the notification queue */ diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h deleted file mode 100644 index b6d657544ef1..000000000000 --- a/include/linux/generic_acl.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef LINUX_GENERIC_ACL_H -#define LINUX_GENERIC_ACL_H - -#include <linux/xattr.h> - -struct inode; - -extern const struct xattr_handler generic_acl_access_handler; -extern const struct xattr_handler generic_acl_default_handler; - -int generic_acl_init(struct inode *, struct inode *); -int generic_acl_chmod(struct inode *); - -#endif /* LINUX_GENERIC_ACL_H */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index db43b58a3355..0053adde0ed9 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -360,7 +360,7 @@ enum /* map softirq index to softirq name. update 'softirq_to_name' in * kernel/softirq.c when adding a new softirq. */ -extern char *softirq_to_name[NR_SOFTIRQS]; +extern const char * const softirq_to_name[NR_SOFTIRQS]; /* softirq mask and active fields moved to irq_cpustat_t in * asm/hardirq.h to get better cache usage. KAO diff --git a/include/linux/ipc.h b/include/linux/ipc.h index 8d861b2651f7..9d84942ae2e5 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -11,7 +11,7 @@ struct kern_ipc_perm { spinlock_t lock; - int deleted; + bool deleted; int id; key_t key; kuid_t uid; diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index f6c82de12541..e7831d203737 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h @@ -21,7 +21,6 @@ struct user_namespace; struct ipc_ids { int in_use; unsigned short seq; - unsigned short seq_max; struct rw_semaphore rwsem; struct idr ipcs_idr; int next_id; diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index 6156686bf108..ac39d910e70b 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -110,9 +110,6 @@ struct mc13xxx_led_platform_data { int id; const char *name; const char *default_trigger; - -/* Three or two bits current selection depending on the led */ - char max_current; }; #define MAX_LED_CONTROL_REGS 6 @@ -121,7 +118,7 @@ struct mc13xxx_leds_platform_data { struct mc13xxx_led_platform_data *led; int num_leds; -/* LED Control 0 */ +/* MC13783 LED Control 0 */ #define MC13783_LED_C0_ENABLE (1 << 0) #define MC13783_LED_C0_TRIODE_MD (1 << 7) #define MC13783_LED_C0_TRIODE_AD (1 << 8) @@ -129,21 +126,43 @@ struct mc13xxx_leds_platform_data { #define MC13783_LED_C0_BOOST (1 << 10) #define MC13783_LED_C0_ABMODE(x) (((x) & 0x7) << 11) #define MC13783_LED_C0_ABREF(x) (((x) & 0x3) << 14) -/* LED Control 1 */ +/* MC13783 LED Control 1 */ #define MC13783_LED_C1_TC1HALF (1 << 18) #define MC13783_LED_C1_SLEWLIM (1 << 23) -/* LED Control 2 */ +/* MC13783 LED Control 2 */ +#define MC13783_LED_C2_CURRENT_MD(x) (((x) & 0x7) << 0) +#define MC13783_LED_C2_CURRENT_AD(x) (((x) & 0x7) << 3) +#define MC13783_LED_C2_CURRENT_KP(x) (((x) & 0x7) << 6) #define MC13783_LED_C2_PERIOD(x) (((x) & 0x3) << 21) #define MC13783_LED_C2_SLEWLIM (1 << 23) -/* LED Control 3 */ +/* MC13783 LED Control 3 */ +#define MC13783_LED_C3_CURRENT_R1(x) (((x) & 0x3) << 0) +#define MC13783_LED_C3_CURRENT_G1(x) (((x) & 0x3) << 2) +#define MC13783_LED_C3_CURRENT_B1(x) (((x) & 0x3) << 4) #define MC13783_LED_C3_PERIOD(x) (((x) & 0x3) << 21) #define MC13783_LED_C3_TRIODE_TC1 (1 << 23) -/* LED Control 4 */ +/* MC13783 LED Control 4 */ +#define MC13783_LED_C4_CURRENT_R2(x) (((x) & 0x3) << 0) +#define MC13783_LED_C4_CURRENT_G2(x) (((x) & 0x3) << 2) +#define MC13783_LED_C4_CURRENT_B2(x) (((x) & 0x3) << 4) #define MC13783_LED_C4_PERIOD(x) (((x) & 0x3) << 21) #define MC13783_LED_C4_TRIODE_TC2 (1 << 23) -/* LED Control 5 */ +/* MC13783 LED Control 5 */ +#define MC13783_LED_C5_CURRENT_R3(x) (((x) & 0x3) << 0) +#define MC13783_LED_C5_CURRENT_G3(x) (((x) & 0x3) << 2) +#define MC13783_LED_C5_CURRENT_B3(x) (((x) & 0x3) << 4) #define MC13783_LED_C5_PERIOD(x) (((x) & 0x3) << 21) #define MC13783_LED_C5_TRIODE_TC3 (1 << 23) +/* MC13892 LED Control 0 */ +#define MC13892_LED_C0_CURRENT_MD(x) (((x) & 0x7) << 9) +#define MC13892_LED_C0_CURRENT_AD(x) (((x) & 0x7) << 21) +/* MC13892 LED Control 1 */ +#define MC13892_LED_C1_CURRENT_KP(x) (((x) & 0x7) << 9) +/* MC13892 LED Control 2 */ +#define MC13892_LED_C2_CURRENT_R(x) (((x) & 0x7) << 9) +#define MC13892_LED_C2_CURRENT_G(x) (((x) & 0x7) << 21) +/* MC13892 LED Control 3 */ +#define MC13892_LED_C3_CURRENT_B(x) (((x) & 0x7) << 9) u32 led_control[MAX_LED_CONTROL_REGS]; }; diff --git a/include/linux/mm.h b/include/linux/mm.h index d9992fc128ca..f28f46eade6a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1895,7 +1895,7 @@ static inline pgprot_t vm_get_page_prot(unsigned long vm_flags) } #endif -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE +#ifdef CONFIG_NUMA_BALANCING unsigned long change_prot_numa(struct vm_area_struct *vma, unsigned long start, unsigned long end); #endif diff --git a/include/linux/msg.h b/include/linux/msg.h index e21f9d44307f..f3f302f9c197 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -9,7 +9,7 @@ struct msg_msg { struct list_head m_list; long m_type; size_t m_ts; /* message text size */ - struct msg_msgseg* next; + struct msg_msgseg *next; void *security; /* the actual message follows immediately */ }; diff --git a/include/linux/mtd/mtdram.h b/include/linux/mtd/mtdram.h index 68891313875d..628a6a21ddf0 100644 --- a/include/linux/mtd/mtdram.h +++ b/include/linux/mtd/mtdram.h @@ -3,6 +3,6 @@ #include <linux/mtd/mtd.h> int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name); + unsigned long size, const char *name); #endif /* __MTD_MTDRAM_H__ */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9e6c8f9f306e..32f8612469d8 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -219,6 +219,9 @@ struct nand_chip; /* ONFI feature address */ #define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 +/* Vendor-specific feature address (Micron) */ +#define ONFI_FEATURE_ADDR_READ_RETRY 0x89 + /* ONFI subfeature parameters length */ #define ONFI_SUBFEATURE_PARAM_LEN 4 @@ -279,16 +282,17 @@ struct nand_onfi_params { __le16 io_pin_capacitance_typ; __le16 input_pin_capacitance_typ; u8 input_pin_capacitance_max; - u8 driver_strenght_support; + u8 driver_strength_support; __le16 t_int_r; __le16 t_ald; u8 reserved4[7]; /* vendor */ - u8 reserved5[90]; + __le16 vendor_revision; + u8 vendor[88]; __le16 crc; -} __attribute__((packed)); +} __packed; #define ONFI_CRC_BASE 0x4F4E @@ -326,6 +330,26 @@ struct onfi_ext_param_page { */ } __packed; +struct nand_onfi_vendor_micron { + u8 two_plane_read; + u8 read_cache; + u8 read_unique_id; + u8 dq_imped; + u8 dq_imped_num_settings; + u8 dq_imped_feat_addr; + u8 rb_pulldown_strength; + u8 rb_pulldown_strength_feat_addr; + u8 rb_pulldown_strength_num_settings; + u8 otp_mode; + u8 otp_page_start; + u8 otp_data_prot_addr; + u8 otp_num_pages; + u8 otp_feat_addr; + u8 read_retry_options; + u8 reserved[72]; + u8 param_revision; +} __packed; + /** * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices * @lock: protection lock @@ -432,6 +456,8 @@ struct nand_buffers { * flash device. * @read_byte: [REPLACEABLE] read one byte from the chip * @read_word: [REPLACEABLE] read one word from the chip + * @write_byte: [REPLACEABLE] write a single byte to the chip on the + * low 8 I/O lines * @write_buf: [REPLACEABLE] write data from the buffer to the chip * @read_buf: [REPLACEABLE] read data from the chip into the buffer * @select_chip: [REPLACEABLE] select chip nr @@ -451,6 +477,8 @@ struct nand_buffers { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. + * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for + * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure @@ -497,6 +525,7 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. + * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @bbt: [INTERN] bad block table pointer @@ -521,6 +550,7 @@ struct nand_chip { uint8_t (*read_byte)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, uint8_t byte); void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip); @@ -544,6 +574,7 @@ struct nand_chip { int feature_addr, uint8_t *subfeature_para); int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); + int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); int chip_delay; unsigned int options; @@ -568,6 +599,8 @@ struct nand_chip { int onfi_version; struct nand_onfi_params onfi_params; + int read_retries; + flstate_t state; uint8_t *oob_poi; @@ -600,6 +633,8 @@ struct nand_chip { #define NAND_MFR_AMD 0x01 #define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_EON 0x92 +#define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_INTEL 0x89 /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 1f8d24bdafda..6a35e6de5da1 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -37,7 +37,7 @@ */ struct mtd_partition { - char *name; /* identifier string */ + const char *name; /* identifier string */ uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ @@ -76,11 +76,11 @@ struct mtd_part_parser { struct mtd_part_parser_data *); }; -extern int register_mtd_parser(struct mtd_part_parser *parser); -extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern void register_mtd_parser(struct mtd_part_parser *parser); +extern void deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); -int mtd_add_partition(struct mtd_info *master, char *name, +int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length); int mtd_del_partition(struct mtd_info *master, int partno); uint64_t mtd_get_device_size(const struct mtd_info *mtd); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 48997374eaf0..2b00625952a7 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -154,10 +154,6 @@ struct nfs_inode { struct rb_root access_cache; struct list_head access_cache_entry_lru; struct list_head access_cache_inode_lru; -#ifdef CONFIG_NFS_V3_ACL - struct posix_acl *acl_access; - struct posix_acl *acl_default; -#endif /* * This is the cookie verifier used for NFSv3 readdir @@ -564,23 +560,17 @@ extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, * linux/fs/nfs3proc.c */ #ifdef CONFIG_NFS_V3_ACL -extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); -extern int nfs3_proc_setacl(struct inode *inode, int type, - struct posix_acl *acl); -extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, - umode_t mode); -extern void nfs3_forget_cached_acls(struct inode *inode); +extern struct posix_acl *nfs3_get_acl(struct inode *inode, int type); +extern int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type); +extern int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl); +extern const struct xattr_handler *nfs3_xattr_handlers[]; #else -static inline int nfs3_proc_set_default_acl(struct inode *dir, - struct inode *inode, - umode_t mode) +static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) { return 0; } - -static inline void nfs3_forget_cached_acls(struct inode *inode) -{ -} #endif /* CONFIG_NFS_V3_ACL */ /* diff --git a/include/linux/nls.h b/include/linux/nls.h index 5dc635f8d79e..520681b68208 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h @@ -44,11 +44,12 @@ enum utf16_endian { }; /* nls_base.c */ -extern int register_nls(struct nls_table *); +extern int __register_nls(struct nls_table *, struct module *); extern int unregister_nls(struct nls_table *); extern struct nls_table *load_nls(char *); extern void unload_nls(struct nls_table *); extern struct nls_table *load_nls_default(void); +#define register_nls(nls) __register_nls((nls), THIS_MODULE) extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu); extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 0beaee9dac1f..2b77058a7335 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -116,6 +116,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match, extern void unflatten_device_tree(void); extern void unflatten_and_copy_device_tree(void); extern void early_init_devtree(void *); +extern void early_get_first_memblock_info(void *, phys_addr_t *); #else /* CONFIG_OF_FLATTREE */ static inline const char *of_flat_dt_get_machine_name(void) { return NULL; } static inline void unflatten_device_tree(void) {} diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h index 6f10e938ff7e..cb32d9c1e8dc 100644 --- a/include/linux/of_mtd.h +++ b/include/linux/of_mtd.h @@ -7,7 +7,7 @@ */ #ifndef __LINUX_OF_MTD_H -#define __LINUX_OF_NET_H +#define __LINUX_OF_MTD_H #ifdef CONFIG_OF_MTD diff --git a/include/linux/platform_data/leds-kirkwood-netxbig.h b/include/linux/platform_data/leds-kirkwood-netxbig.h index 24b536ebdf13..d2be19a51acd 100644 --- a/include/linux/platform_data/leds-kirkwood-netxbig.h +++ b/include/linux/platform_data/leds-kirkwood-netxbig.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-kirkwood/include/mach/leds-netxbig.h - * * Platform data structure for netxbig LED driver * * This file is licensed under the terms of the GNU General Public @@ -8,8 +6,8 @@ * warranty of any kind, whether express or implied. */ -#ifndef __MACH_LEDS_NETXBIG_H -#define __MACH_LEDS_NETXBIG_H +#ifndef __LEDS_KIRKWOOD_NETXBIG_H +#define __LEDS_KIRKWOOD_NETXBIG_H struct netxbig_gpio_ext { unsigned *addr; @@ -52,4 +50,4 @@ struct netxbig_led_platform_data { int num_leds; }; -#endif /* __MACH_LEDS_NETXBIG_H */ +#endif /* __LEDS_KIRKWOOD_NETXBIG_H */ diff --git a/include/linux/platform_data/leds-kirkwood-ns2.h b/include/linux/platform_data/leds-kirkwood-ns2.h index e21272e5f668..6a9fed57f346 100644 --- a/include/linux/platform_data/leds-kirkwood-ns2.h +++ b/include/linux/platform_data/leds-kirkwood-ns2.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-kirkwood/include/mach/leds-ns2.h - * * Platform data structure for Network Space v2 LED driver * * This file is licensed under the terms of the GNU General Public @@ -8,8 +6,8 @@ * warranty of any kind, whether express or implied. */ -#ifndef __MACH_LEDS_NS2_H -#define __MACH_LEDS_NS2_H +#ifndef __LEDS_KIRKWOOD_NS2_H +#define __LEDS_KIRKWOOD_NS2_H struct ns2_led { const char *name; @@ -23,4 +21,4 @@ struct ns2_led_platform_data { struct ns2_led *leds; }; -#endif /* __MACH_LEDS_NS2_H */ +#endif /* __LEDS_KIRKWOOD_NS2_H */ diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 4da5bfa2147f..3e9dd6676b97 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -1,6 +1,4 @@ /* - * arch/arm/plat-omap/include/mach/nand.h - * * Copyright (C) 2006 Micron Technology Inc. * * This program is free software; you can redistribute it and/or modify diff --git a/include/linux/platform_data/mtd-nand-pxa3xx.h b/include/linux/platform_data/mtd-nand-pxa3xx.h index ffb801998e5d..a94147124929 100644 --- a/include/linux/platform_data/mtd-nand-pxa3xx.h +++ b/include/linux/platform_data/mtd-nand-pxa3xx.h @@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data { /* indicate how many chip selects will be used */ int num_cs; + /* use an flash-based bad block table */ + bool flash_bbt; + const struct mtd_partition *parts[NUM_CHIP_SELECT]; unsigned int nr_parts[NUM_CHIP_SELECT]; diff --git a/include/linux/platform_data/mtd-onenand-omap2.h b/include/linux/platform_data/mtd-onenand-omap2.h index e9a9fb188f97..56ff0e6f5ad1 100644 --- a/include/linux/platform_data/mtd-onenand-omap2.h +++ b/include/linux/platform_data/mtd-onenand-omap2.h @@ -1,6 +1,4 @@ /* - * arch/arm/plat-omap/include/mach/onenand.h - * * Copyright (C) 2006 Nokia Corporation * Author: Juha Yrjola * diff --git a/include/linux/platform_data/mtd-orion_nand.h b/include/linux/platform_data/mtd-orion_nand.h index 9f3c180834d1..a7ce77c7c1a8 100644 --- a/include/linux/platform_data/mtd-orion_nand.h +++ b/include/linux/platform_data/mtd-orion_nand.h @@ -1,13 +1,11 @@ /* - * arch/arm/plat-orion/include/plat/orion_nand.h - * * 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. */ -#ifndef __PLAT_ORION_NAND_H -#define __PLAT_ORION_NAND_H +#ifndef __MTD_ORION_NAND_H +#define __MTD_ORION_NAND_H /* * Device bus NAND private data diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h index 54334393ab92..a947ab8b441a 100644 --- a/include/linux/platform_data/si5351.h +++ b/include/linux/platform_data/si5351.h @@ -8,20 +8,6 @@ struct clk; /** - * enum si5351_variant - SiLabs Si5351 chip variant - * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input) - * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input) - * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input) - * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input) - */ -enum si5351_variant { - SI5351_VARIANT_A = 1, - SI5351_VARIANT_A3 = 2, - SI5351_VARIANT_B = 3, - SI5351_VARIANT_C = 4, -}; - -/** * enum si5351_pll_src - Si5351 pll clock source * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config * @SI5351_PLL_SRC_XTAL: pll source clock is XTAL input @@ -115,14 +101,12 @@ struct si5351_clkout_config { /** * struct si5351_platform_data - Platform data for the Si5351 clock driver - * @variant: Si5351 chip variant * @clk_xtal: xtal input clock * @clk_clkin: clkin input clock * @pll_src: array of pll source clock setting * @clkout: array of clkout configuration */ struct si5351_platform_data { - enum si5351_variant variant; struct clk *clk_xtal; struct clk *clk_clkin; enum si5351_pll_src pll_src[2]; diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 833099bf8090..3e96a6a76103 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -85,12 +85,20 @@ extern int posix_acl_valid(const struct posix_acl *); extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); -extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); -extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); +extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *); +extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); extern struct posix_acl *get_posix_acl(struct inode *, int); extern int set_posix_acl(struct inode *, int, struct posix_acl *); +#ifdef CONFIG_FS_POSIX_ACL +extern int posix_acl_chmod(struct inode *, umode_t); +extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, + struct posix_acl **); + +extern int simple_set_acl(struct inode *, struct posix_acl *, int); +extern int simple_acl_create(struct inode *, struct inode *); + struct posix_acl **acl_by_type(struct inode *inode, int type); struct posix_acl *get_cached_acl(struct inode *inode, int type); struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type); @@ -100,10 +108,37 @@ void forget_all_cached_acls(struct inode *inode); static inline void cache_no_acl(struct inode *inode) { -#ifdef CONFIG_FS_POSIX_ACL inode->i_acl = NULL; inode->i_default_acl = NULL; -#endif } +#else +static inline int posix_acl_chmod(struct inode *inode, umode_t mode) +{ + return 0; +} + +#define simple_set_acl NULL + +static inline int simple_acl_create(struct inode *dir, struct inode *inode) +{ + return 0; +} +static inline void cache_no_acl(struct inode *inode) +{ +} + +static inline int posix_acl_create(struct inode *inode, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl) +{ + *default_acl = *acl = NULL; + return 0; +} + +static inline void forget_all_cached_acls(struct inode *inode) +{ +} +#endif /* CONFIG_FS_POSIX_ACL */ + +struct posix_acl *get_acl(struct inode *inode, int type); #endif /* __LINUX_POSIX_ACL_H */ diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h index ad93ad0f1db0..6f14ee295822 100644 --- a/include/linux/posix_acl_xattr.h +++ b/include/linux/posix_acl_xattr.h @@ -69,4 +69,7 @@ struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns, int posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, void *buffer, size_t size); +extern const struct xattr_handler posix_acl_access_xattr_handler; +extern const struct xattr_handler posix_acl_default_xattr_handler; + #endif /* _POSIX_ACL_XATTR_H */ diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 3e355c688618..72bf3a01a4ee 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -449,8 +449,6 @@ static inline int rcu_read_lock_sched_held(void) #ifdef CONFIG_PROVE_RCU -int rcu_my_thread_group_empty(void); - /** * rcu_lockdep_assert - emit lockdep splat if specified condition not met * @c: condition to check diff --git a/include/linux/shm.h b/include/linux/shm.h index 429c1995d756..1e2cd2e6b540 100644 --- a/include/linux/shm.h +++ b/include/linux/shm.h @@ -9,7 +9,7 @@ struct shmid_kernel /* private to the kernel */ { struct kern_ipc_perm shm_perm; - struct file * shm_file; + struct file *shm_file; unsigned long shm_nattch; unsigned long shm_segsz; time_t shm_atim; diff --git a/include/linux/splice.h b/include/linux/splice.h index 74575cbf2d6f..0e43906d2fda 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -24,7 +24,8 @@ * Passed to the actors */ struct splice_desc { - unsigned int len, total_len; /* current and remaining length */ + size_t total_len; /* remaining length */ + unsigned int len; /* current length */ unsigned int flags; /* splice flags */ /* * actor() private data diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a353e0300b54..7f490bef9e99 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -84,7 +84,8 @@ enum { extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, const unsigned char *dir_name); -extern void rpc_pipefs_init_net(struct net *net); +extern int rpc_pipefs_init_net(struct net *net); +extern void rpc_pipefs_exit_net(struct net *net); extern struct super_block *rpc_get_sb_net(const struct net *net); extern void rpc_put_sb_net(const struct net *net); @@ -130,5 +131,7 @@ extern int rpc_unlink(struct dentry *); extern int register_rpc_pipefs(void); extern void unregister_rpc_pipefs(void); +extern bool gssd_running(struct net *net); + #endif #endif diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index e4b948080d20..a67b38415768 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -142,8 +142,6 @@ static inline unsigned long zone_page_state_snapshot(struct zone *zone, return x; } -extern unsigned long global_reclaimable_pages(void); - #ifdef CONFIG_NUMA /* * Determine the per node value of a stat item. This function diff --git a/include/math-emu/op-common.h b/include/math-emu/op-common.h index 9696a5e2c437..6bdf8c61d221 100644 --- a/include/math-emu/op-common.h +++ b/include/math-emu/op-common.h @@ -685,7 +685,7 @@ do { \ else \ { \ r = 0; \ - if (X##_s) \ + if (!X##_s) \ r = ~r; \ } \ FP_SET_EXCEPTION(FP_EX_INVALID); \ @@ -743,12 +743,17 @@ do { \ } \ else \ { \ + int _lz0, _lz1; \ if (X##_e <= -_FP_WORKBITS - 1) \ _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ else \ _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e, \ _FP_WFRACBITS_##fs); \ + _FP_FRAC_CLZ_##wc(_lz0, X); \ _FP_ROUND(wc, X); \ + _FP_FRAC_CLZ_##wc(_lz1, X); \ + if (_lz1 < _lz0) \ + X##_e++; /* For overflow detection. */ \ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ } \ @@ -762,7 +767,7 @@ do { \ if (!rsigned) \ { \ r = 0; \ - if (X##_s) \ + if (!X##_s) \ r = ~r; \ } \ else if (rsigned != 2) \ diff --git a/include/scsi/osd_ore.h b/include/scsi/osd_ore.h index a5f9b960dfc8..6ca3265a4dca 100644 --- a/include/scsi/osd_ore.h +++ b/include/scsi/osd_ore.h @@ -102,6 +102,7 @@ struct ore_striping_info { unsigned unit_off; unsigned cur_pg; unsigned cur_comp; + unsigned maxdevUnits; }; struct ore_io_state; diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index d51d16c7afd8..ddc179b7a105 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -301,6 +301,7 @@ DECLARE_EVENT_CLASS(xs_socket_event_done, DEFINE_RPC_SOCKET_EVENT(rpc_socket_state_change); DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_connect); +DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_error); DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_reset_connection); DEFINE_RPC_SOCKET_EVENT(rpc_socket_close); DEFINE_RPC_SOCKET_EVENT(rpc_socket_shutdown); diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 7c098ac9068a..a8227022e3a0 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -13,7 +13,7 @@ #include <linux/minix_fs.h> #include <linux/ext2_fs.h> #include <linux/romfs_fs.h> -#include <linux/cramfs_fs.h> +#include <uapi/linux/cramfs_fs.h> #include <linux/initrd.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/init/main.c b/init/main.c index 3f1f4e4b61f7..2fd9cef70ee8 100644 --- a/init/main.c +++ b/init/main.c @@ -92,8 +92,6 @@ static int kernel_init(void *); extern void init_IRQ(void); extern void fork_init(unsigned long); -extern void mca_init(void); -extern void sbus_init(void); extern void radix_tree_init(void); #ifndef CONFIG_DEBUG_RODATA static inline void mark_rodata_ro(void) { } diff --git a/ipc/compat.c b/ipc/compat.c index 892f6585dd60..f486b0096a67 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -197,7 +197,7 @@ static inline int __put_compat_ipc_perm(struct ipc64_perm *p, static inline int get_compat_semid64_ds(struct semid64_ds *s64, struct compat_semid64_ds __user *up64) { - if (!access_ok (VERIFY_READ, up64, sizeof(*up64))) + if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) return -EFAULT; return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); } @@ -205,7 +205,7 @@ static inline int get_compat_semid64_ds(struct semid64_ds *s64, static inline int get_compat_semid_ds(struct semid64_ds *s, struct compat_semid_ds __user *up) { - if (!access_ok (VERIFY_READ, up, sizeof(*up))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); } @@ -215,7 +215,7 @@ static inline int put_compat_semid64_ds(struct semid64_ds *s64, { int err; - if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64))) + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) return -EFAULT; err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); err |= __put_user(s64->sem_otime, &up64->sem_otime); @@ -229,7 +229,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s, { int err; - if (!access_ok (VERIFY_WRITE, up, sizeof(*up))) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); err |= __put_user(s->sem_otime, &up->sem_otime); @@ -288,11 +288,11 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) break; case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_semid64_ds(&s64, compat_ptr(pad)); - } else { + else err = get_compat_semid_ds(&s64, compat_ptr(pad)); - } + up64 = compat_alloc_user_space(sizeof(s64)); if (copy_to_user(up64, &s64, sizeof(s64))) err = -EFAULT; @@ -376,12 +376,12 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, struct compat_ipc_kludge ipck; if (!uptr) return -EINVAL; - if (copy_from_user (&ipck, uptr, sizeof(ipck))) + if (copy_from_user(&ipck, uptr, sizeof(ipck))) return -EFAULT; uptr = compat_ptr(ipck.msgp); fifth = ipck.msgtyp; } - return do_msgrcv(first, uptr, second, fifth, third, + return do_msgrcv(first, uptr, second, (s32)fifth, third, compat_do_msg_fill); } case MSGGET: @@ -515,11 +515,11 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) break; case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_msqid64(&m64, uptr); - } else { + else err = get_compat_msqid(&m64, uptr); - } + if (err) break; p = compat_alloc_user_space(sizeof(m64)); @@ -702,11 +702,11 @@ long compat_sys_shmctl(int first, int second, void __user *uptr) case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_shmid64_ds(&s64, uptr); - } else { + else err = get_compat_shmid_ds(&s64, uptr); - } + if (err) break; p = compat_alloc_user_space(sizeof(s64)); diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c index 380ea4fe08e7..63d7c6de335b 100644 --- a/ipc/compat_mq.c +++ b/ipc/compat_mq.c @@ -64,7 +64,7 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name, return sys_mq_open(u_name, oflag, mode, p); } -static int compat_prepare_timeout(struct timespec __user * *p, +static int compat_prepare_timeout(struct timespec __user **p, const struct compat_timespec __user *u) { struct timespec ts; diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index b0e99deb6d05..17028648cfeb 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -164,21 +164,21 @@ static struct ctl_table ipc_kern_table[] = { { .procname = "shmmax", .data = &init_ipc_ns.shm_ctlmax, - .maxlen = sizeof (init_ipc_ns.shm_ctlmax), + .maxlen = sizeof(init_ipc_ns.shm_ctlmax), .mode = 0644, .proc_handler = proc_ipc_doulongvec_minmax, }, { .procname = "shmall", .data = &init_ipc_ns.shm_ctlall, - .maxlen = sizeof (init_ipc_ns.shm_ctlall), + .maxlen = sizeof(init_ipc_ns.shm_ctlall), .mode = 0644, .proc_handler = proc_ipc_doulongvec_minmax, }, { .procname = "shmmni", .data = &init_ipc_ns.shm_ctlmni, - .maxlen = sizeof (init_ipc_ns.shm_ctlmni), + .maxlen = sizeof(init_ipc_ns.shm_ctlmni), .mode = 0644, .proc_handler = proc_ipc_dointvec, }, @@ -194,7 +194,7 @@ static struct ctl_table ipc_kern_table[] = { { .procname = "msgmax", .data = &init_ipc_ns.msg_ctlmax, - .maxlen = sizeof (init_ipc_ns.msg_ctlmax), + .maxlen = sizeof(init_ipc_ns.msg_ctlmax), .mode = 0644, .proc_handler = proc_ipc_dointvec_minmax, .extra1 = &zero, @@ -203,7 +203,7 @@ static struct ctl_table ipc_kern_table[] = { { .procname = "msgmni", .data = &init_ipc_ns.msg_ctlmni, - .maxlen = sizeof (init_ipc_ns.msg_ctlmni), + .maxlen = sizeof(init_ipc_ns.msg_ctlmni), .mode = 0644, .proc_handler = proc_ipc_callback_dointvec_minmax, .extra1 = &zero, @@ -212,7 +212,7 @@ static struct ctl_table ipc_kern_table[] = { { .procname = "msgmnb", .data = &init_ipc_ns.msg_ctlmnb, - .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), + .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), .mode = 0644, .proc_handler = proc_ipc_dointvec_minmax, .extra1 = &zero, @@ -221,7 +221,7 @@ static struct ctl_table ipc_kern_table[] = { { .procname = "sem", .data = &init_ipc_ns.sem_ctls, - .maxlen = 4*sizeof (int), + .maxlen = 4*sizeof(int), .mode = 0644, .proc_handler = proc_ipc_dointvec, }, diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 95827ce2f3c7..ccf1f9fd263a 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -6,7 +6,7 @@ * * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) * Lockless receive & send, fd based notify: - * Manfred Spraul (manfred@colorfullife.com) + * Manfred Spraul (manfred@colorfullife.com) * * Audit: George Wilson (ltcgcw@us.ibm.com) * @@ -73,7 +73,7 @@ struct mqueue_inode_info { struct mq_attr attr; struct sigevent notify; - struct pid* notify_owner; + struct pid *notify_owner; struct user_namespace *notify_user_ns; struct user_struct *user; /* user who created, for accounting */ struct sock *notify_sock; @@ -92,7 +92,7 @@ static void remove_notification(struct mqueue_inode_info *info); static struct kmem_cache *mqueue_inode_cachep; -static struct ctl_table_header * mq_sysctl_table; +static struct ctl_table_header *mq_sysctl_table; static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) { @@ -466,13 +466,13 @@ out_unlock: static int mqueue_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = dentry->d_inode; dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; dir->i_size -= DIRENT_SIZE; - drop_nlink(inode); - dput(dentry); - return 0; + drop_nlink(inode); + dput(dentry); + return 0; } /* @@ -622,7 +622,7 @@ static struct ext_wait_queue *wq_get_first_waiter( static inline void set_cookie(struct sk_buff *skb, char code) { - ((char*)skb->data)[NOTIFY_COOKIE_LEN-1] = code; + ((char *)skb->data)[NOTIFY_COOKIE_LEN-1] = code; } /* @@ -1303,11 +1303,11 @@ retry: out_fput: fdput(f); out: - if (sock) { + if (sock) netlink_detachskb(sock, nc); - } else if (nc) { + else if (nc) dev_kfree_skb(nc); - } + return ret; } diff --git a/ipc/msg.c b/ipc/msg.c index 558aa91186b6..245db1140ad6 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -253,8 +253,14 @@ static void expunge_all(struct msg_queue *msq, int res) struct msg_receiver *msr, *t; list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { - msr->r_msg = NULL; + msr->r_msg = NULL; /* initialize expunge ordering */ wake_up_process(msr->r_tsk); + /* + * Ensure that the wakeup is visible before setting r_msg as + * the receiving end depends on it: either spinning on a nil, + * or dealing with -EAGAIN cases. See lockless receive part 1 + * and 2 in do_msgrcv(). + */ smp_mb(); msr->r_msg = ERR_PTR(res); } @@ -318,7 +324,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) static inline unsigned long copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) { - switch(version) { + switch (version) { case IPC_64: return copy_to_user(buf, in, sizeof(*in)); case IPC_OLD: @@ -363,7 +369,7 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) static inline unsigned long copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) { - switch(version) { + switch (version) { case IPC_64: if (copy_from_user(out, buf, sizeof(*out))) return -EFAULT; @@ -375,9 +381,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) return -EFAULT; - out->msg_perm.uid = tbuf_old.msg_perm.uid; - out->msg_perm.gid = tbuf_old.msg_perm.gid; - out->msg_perm.mode = tbuf_old.msg_perm.mode; + out->msg_perm.uid = tbuf_old.msg_perm.uid; + out->msg_perm.gid = tbuf_old.msg_perm.gid; + out->msg_perm.mode = tbuf_old.msg_perm.mode; if (tbuf_old.msg_qbytes == 0) out->msg_qbytes = tbuf_old.msg_lqbytes; @@ -606,13 +612,13 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) static int testmsg(struct msg_msg *msg, long type, int mode) { - switch(mode) + switch (mode) { case SEARCH_ANY: case SEARCH_NUMBER: return 1; case SEARCH_LESSEQUAL: - if (msg->m_type <=type) + if (msg->m_type <= type) return 1; break; case SEARCH_EQUAL: @@ -638,15 +644,22 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) list_del(&msr->r_list); if (msr->r_maxsize < msg->m_ts) { + /* initialize pipelined send ordering */ msr->r_msg = NULL; wake_up_process(msr->r_tsk); - smp_mb(); + smp_mb(); /* see barrier comment below */ msr->r_msg = ERR_PTR(-E2BIG); } else { msr->r_msg = NULL; msq->q_lrpid = task_pid_vnr(msr->r_tsk); msq->q_rtime = get_seconds(); wake_up_process(msr->r_tsk); + /* + * Ensure that the wakeup is visible before + * setting r_msg, as the receiving end depends + * on it. See lockless receive part 1 and 2 in + * do_msgrcv(). + */ smp_mb(); msr->r_msg = msg; @@ -654,6 +667,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) } } } + return 0; } @@ -696,7 +710,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, goto out_unlock0; /* raced with RMID? */ - if (msq->q_perm.deleted) { + if (!ipc_valid_object(&msq->q_perm)) { err = -EIDRM; goto out_unlock0; } @@ -716,6 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, goto out_unlock0; } + /* enqueue the sender and prepare to block */ ss_add(msq, &s); if (!ipc_rcu_getref(msq)) { @@ -731,7 +746,8 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, ipc_lock_object(&msq->q_perm); ipc_rcu_putref(msq, ipc_rcu_free); - if (msq->q_perm.deleted) { + /* raced with RMID? */ + if (!ipc_valid_object(&msq->q_perm)) { err = -EIDRM; goto out_unlock0; } @@ -909,7 +925,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl ipc_lock_object(&msq->q_perm); /* raced with RMID? */ - if (msq->q_perm.deleted) { + if (!ipc_valid_object(&msq->q_perm)) { msg = ERR_PTR(-EIDRM); goto out_unlock0; } @@ -983,7 +999,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl * wake_up_process(). There is a race with exit(), see * ipc/mqueue.c for the details. */ - msg = (struct msg_msg*)msr_d.r_msg; + msg = (struct msg_msg *)msr_d.r_msg; while (msg == NULL) { cpu_relax(); msg = (struct msg_msg *)msr_d.r_msg; @@ -1004,7 +1020,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl /* Lockless receive, part 4: * Repeat test after acquiring the spinlock. */ - msg = (struct msg_msg*)msr_d.r_msg; + msg = (struct msg_msg *)msr_d.r_msg; if (msg != ERR_PTR(-EAGAIN)) goto out_unlock0; diff --git a/ipc/sem.c b/ipc/sem.c index db9d241af133..bee555417312 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -188,7 +188,7 @@ void sem_exit_ns(struct ipc_namespace *ns) } #endif -void __init sem_init (void) +void __init sem_init(void) { sem_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/sem", @@ -225,7 +225,7 @@ static void unmerge_queues(struct sem_array *sma) } /** - * merge_queues - Merge single semop queues into global queue + * merge_queues - merge single semop queues into global queue * @sma: semaphore array * * This function merges all per-semaphore queues into the global queue. @@ -394,7 +394,7 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns, /* ipc_rmid() may have already freed the ID while sem_lock * was spinning: verify that the structure is still valid */ - if (!ipcp->deleted) + if (ipc_valid_object(ipcp)) return container_of(ipcp, struct sem_array, sem_perm); sem_unlock(sma, *locknum); @@ -445,11 +445,11 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) * * call wake_up_process * * set queue.status to the final value. * - the previously blocked thread checks queue.status: - * * if it's IN_WAKEUP, then it must wait until the value changes - * * if it's not -EINTR, then the operation was completed by - * update_queue. semtimedop can return queue.status without - * performing any operation on the sem array. - * * otherwise it must acquire the spinlock and check what's up. + * * if it's IN_WAKEUP, then it must wait until the value changes + * * if it's not -EINTR, then the operation was completed by + * update_queue. semtimedop can return queue.status without + * performing any operation on the sem array. + * * otherwise it must acquire the spinlock and check what's up. * * The two-stage algorithm is necessary to protect against the following * races: @@ -474,7 +474,6 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) * * Called with sem_ids.rwsem held (as a writer) */ - static int newary(struct ipc_namespace *ns, struct ipc_params *params) { int id; @@ -491,12 +490,12 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) if (ns->used_sems + nsems > ns->sc_semmns) return -ENOSPC; - size = sizeof (*sma) + nsems * sizeof (struct sem); + size = sizeof(*sma) + nsems * sizeof(struct sem); sma = ipc_rcu_alloc(size); - if (!sma) { + if (!sma) return -ENOMEM; - } - memset (sma, 0, size); + + memset(sma, 0, size); sma->sem_perm.mode = (semflg & S_IRWXUGO); sma->sem_perm.key = key; @@ -584,10 +583,11 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); } -/** perform_atomic_semop - Perform (if possible) a semaphore operation +/** + * perform_atomic_semop - Perform (if possible) a semaphore operation * @sma: semaphore array * @sops: array with operations that should be checked - * @nsems: number of sops + * @nsops: number of operations * @un: undo array * @pid: pid that did the change * @@ -595,19 +595,18 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) * Returns 1 if the operation is impossible, the caller must sleep. * Negative values are error codes. */ - static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops, int nsops, struct sem_undo *un, int pid) { int result, sem_op; struct sembuf *sop; - struct sem * curr; + struct sem *curr; for (sop = sops; sop < sops + nsops; sop++) { curr = sma->sem_base + sop->sem_num; sem_op = sop->sem_op; result = curr->semval; - + if (!sem_op && result) goto would_block; @@ -616,25 +615,24 @@ static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops, goto would_block; if (result > SEMVMX) goto out_of_range; + if (sop->sem_flg & SEM_UNDO) { int undo = un->semadj[sop->sem_num] - sem_op; - /* - * Exceeding the undo range is an error. - */ + /* Exceeding the undo range is an error. */ if (undo < (-SEMAEM - 1) || undo > SEMAEM) goto out_of_range; + un->semadj[sop->sem_num] = undo; } + curr->semval = result; } sop--; while (sop >= sops) { sma->sem_base[sop->sem_num].sempid = pid; - if (sop->sem_flg & SEM_UNDO) - un->semadj[sop->sem_num] -= sop->sem_op; sop--; } - + return 0; out_of_range: @@ -650,7 +648,10 @@ would_block: undo: sop--; while (sop >= sops) { - sma->sem_base[sop->sem_num].semval -= sop->sem_op; + sem_op = sop->sem_op; + sma->sem_base[sop->sem_num].semval -= sem_op; + if (sop->sem_flg & SEM_UNDO) + un->semadj[sop->sem_num] += sem_op; sop--; } @@ -680,7 +681,7 @@ static void wake_up_sem_queue_prepare(struct list_head *pt, } /** - * wake_up_sem_queue_do(pt) - do the actual wake-up + * wake_up_sem_queue_do - do the actual wake-up * @pt: list of tasks to be woken up * * Do the actual wake-up. @@ -746,7 +747,7 @@ static int check_restart(struct sem_array *sma, struct sem_queue *q) } /** - * wake_const_ops(sma, semnum, pt) - Wake up non-alter tasks + * wake_const_ops - wake up non-alter tasks * @sma: semaphore array. * @semnum: semaphore that was modified. * @pt: list head for the tasks that must be woken up. @@ -796,15 +797,14 @@ static int wake_const_ops(struct sem_array *sma, int semnum, } /** - * do_smart_wakeup_zero(sma, sops, nsops, pt) - wakeup all wait for zero tasks + * do_smart_wakeup_zero - wakeup all wait for zero tasks * @sma: semaphore array * @sops: operations that were performed * @nsops: number of operations * @pt: list head of the tasks that must be woken up. * - * do_smart_wakeup_zero() checks all required queue for wait-for-zero - * operations, based on the actual changes that were performed on the - * semaphore array. + * Checks all required queue for wait-for-zero operations, based + * on the actual changes that were performed on the semaphore array. * The function returns 1 if at least one operation was completed successfully. */ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops, @@ -848,7 +848,7 @@ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops, /** - * update_queue(sma, semnum): Look for tasks that can be completed. + * update_queue - look for tasks that can be completed. * @sma: semaphore array. * @semnum: semaphore that was modified. * @pt: list head for the tasks that must be woken up. @@ -918,7 +918,7 @@ again: } /** - * set_semotime(sma, sops) - set sem_otime + * set_semotime - set sem_otime * @sma: semaphore array * @sops: operations that modified the array, may be NULL * @@ -936,7 +936,7 @@ static void set_semotime(struct sem_array *sma, struct sembuf *sops) } /** - * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue + * do_smart_update - optimized update_queue * @sma: semaphore array * @sops: operations that were performed * @nsops: number of operations @@ -998,21 +998,21 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop * The counts we return here are a rough approximation, but still * warrant that semncnt+semzcnt>0 if the task is on the pending queue. */ -static int count_semncnt (struct sem_array * sma, ushort semnum) +static int count_semncnt(struct sem_array *sma, ushort semnum) { int semncnt; - struct sem_queue * q; + struct sem_queue *q; semncnt = 0; list_for_each_entry(q, &sma->sem_base[semnum].pending_alter, list) { - struct sembuf * sops = q->sops; + struct sembuf *sops = q->sops; BUG_ON(sops->sem_num != semnum); if ((sops->sem_op < 0) && !(sops->sem_flg & IPC_NOWAIT)) semncnt++; } list_for_each_entry(q, &sma->pending_alter, list) { - struct sembuf * sops = q->sops; + struct sembuf *sops = q->sops; int nsops = q->nsops; int i; for (i = 0; i < nsops; i++) @@ -1024,21 +1024,21 @@ static int count_semncnt (struct sem_array * sma, ushort semnum) return semncnt; } -static int count_semzcnt (struct sem_array * sma, ushort semnum) +static int count_semzcnt(struct sem_array *sma, ushort semnum) { int semzcnt; - struct sem_queue * q; + struct sem_queue *q; semzcnt = 0; list_for_each_entry(q, &sma->sem_base[semnum].pending_const, list) { - struct sembuf * sops = q->sops; + struct sembuf *sops = q->sops; BUG_ON(sops->sem_num != semnum); if ((sops->sem_op == 0) && !(sops->sem_flg & IPC_NOWAIT)) semzcnt++; } list_for_each_entry(q, &sma->pending_const, list) { - struct sembuf * sops = q->sops; + struct sembuf *sops = q->sops; int nsops = q->nsops; int i; for (i = 0; i < nsops; i++) @@ -1108,7 +1108,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version) { - switch(version) { + switch (version) { case IPC_64: return copy_to_user(buf, in, sizeof(*in)); case IPC_OLD: @@ -1151,7 +1151,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int err; struct sem_array *sma; - switch(cmd) { + switch (cmd) { case IPC_INFO: case SEM_INFO: { @@ -1162,7 +1162,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, if (err) return err; - memset(&seminfo,0,sizeof(seminfo)); + memset(&seminfo, 0, sizeof(seminfo)); seminfo.semmni = ns->sc_semmni; seminfo.semmns = ns->sc_semmns; seminfo.semmsl = ns->sc_semmsl; @@ -1183,7 +1183,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, up_read(&sem_ids(ns).rwsem); if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) return -EFAULT; - return (max_id < 0) ? 0: max_id; + return (max_id < 0) ? 0 : max_id; } case IPC_STAT: case SEM_STAT: @@ -1239,7 +1239,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, { struct sem_undo *un; struct sem_array *sma; - struct sem* curr; + struct sem *curr; int err; struct list_head tasks; int val; @@ -1282,7 +1282,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, sem_lock(sma, NULL, -1); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { sem_unlock(sma, -1); rcu_read_unlock(); return -EIDRM; @@ -1309,10 +1309,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, int cmd, void __user *p) { struct sem_array *sma; - struct sem* curr; + struct sem *curr; int err, nsems; ushort fast_sem_io[SEMMSL_FAST]; - ushort* sem_io = fast_sem_io; + ushort *sem_io = fast_sem_io; struct list_head tasks; INIT_LIST_HEAD(&tasks); @@ -1342,11 +1342,11 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, int i; sem_lock(sma, NULL, -1); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { err = -EIDRM; goto out_unlock; } - if(nsems > SEMMSL_FAST) { + if (nsems > SEMMSL_FAST) { if (!ipc_rcu_getref(sma)) { err = -EIDRM; goto out_unlock; @@ -1354,14 +1354,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, sem_unlock(sma, -1); rcu_read_unlock(); sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) { + if (sem_io == NULL) { ipc_rcu_putref(sma, ipc_rcu_free); return -ENOMEM; } rcu_read_lock(); sem_lock_and_putref(sma); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { err = -EIDRM; goto out_unlock; } @@ -1371,7 +1371,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, sem_unlock(sma, -1); rcu_read_unlock(); err = 0; - if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) + if (copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; goto out_free; } @@ -1386,15 +1386,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, } rcu_read_unlock(); - if(nsems > SEMMSL_FAST) { + if (nsems > SEMMSL_FAST) { sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) { + if (sem_io == NULL) { ipc_rcu_putref(sma, ipc_rcu_free); return -ENOMEM; } } - if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) { + if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) { ipc_rcu_putref(sma, ipc_rcu_free); err = -EFAULT; goto out_free; @@ -1409,7 +1409,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, } rcu_read_lock(); sem_lock_and_putref(sma); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { err = -EIDRM; goto out_unlock; } @@ -1435,7 +1435,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, goto out_rcu_wakeup; sem_lock(sma, NULL, -1); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { err = -EIDRM; goto out_unlock; } @@ -1449,10 +1449,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, err = curr->sempid; goto out_unlock; case GETNCNT: - err = count_semncnt(sma,semnum); + err = count_semncnt(sma, semnum); goto out_unlock; case GETZCNT: - err = count_semzcnt(sma,semnum); + err = count_semzcnt(sma, semnum); goto out_unlock; } @@ -1462,7 +1462,7 @@ out_rcu_wakeup: rcu_read_unlock(); wake_up_sem_queue_do(&tasks); out_free: - if(sem_io != fast_sem_io) + if (sem_io != fast_sem_io) ipc_free(sem_io, sizeof(ushort)*nsems); return err; } @@ -1470,7 +1470,7 @@ out_free: static inline unsigned long copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) { - switch(version) { + switch (version) { case IPC_64: if (copy_from_user(out, buf, sizeof(*out))) return -EFAULT; @@ -1479,7 +1479,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) { struct semid_ds tbuf_old; - if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) + if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) return -EFAULT; out->sem_perm.uid = tbuf_old.sem_perm.uid; @@ -1506,7 +1506,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, struct semid64_ds semid64; struct kern_ipc_perm *ipcp; - if(cmd == IPC_SET) { + if (cmd == IPC_SET) { if (copy_semid_from_user(&semid64, p, version)) return -EFAULT; } @@ -1566,7 +1566,7 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) version = ipc_parse_version(&cmd); ns = current->nsproxy->ipc_ns; - switch(cmd) { + switch (cmd) { case IPC_INFO: case SEM_INFO: case IPC_STAT: @@ -1634,7 +1634,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) { struct sem_undo *un; - assert_spin_locked(&ulp->lock); + assert_spin_locked(&ulp->lock); un = __lookup_undo(ulp, semid); if (un) { @@ -1645,7 +1645,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) } /** - * find_alloc_undo - Lookup (and if not present create) undo array + * find_alloc_undo - lookup (and if not present create) undo array * @ns: namespace * @semid: semaphore array id * @@ -1670,7 +1670,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) spin_lock(&ulp->lock); un = lookup_undo(ulp, semid); spin_unlock(&ulp->lock); - if (likely(un!=NULL)) + if (likely(un != NULL)) goto out; /* no undo structure around - allocate one. */ @@ -1699,7 +1699,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) /* step 3: Acquire the lock on semaphore array */ rcu_read_lock(); sem_lock_and_putref(sma); - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { sem_unlock(sma, -1); rcu_read_unlock(); kfree(new); @@ -1735,7 +1735,7 @@ out: /** - * get_queue_result - Retrieve the result code from sem_queue + * get_queue_result - retrieve the result code from sem_queue * @q: Pointer to queue structure * * Retrieve the return code from the pending queue. If IN_WAKEUP is found in @@ -1765,7 +1765,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, int error = -EINVAL; struct sem_array *sma; struct sembuf fast_sops[SEMOPM_FAST]; - struct sembuf* sops = fast_sops, *sop; + struct sembuf *sops = fast_sops, *sop; struct sem_undo *un; int undos = 0, alter = 0, max, locknum; struct sem_queue queue; @@ -1779,13 +1779,13 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, return -EINVAL; if (nsops > ns->sc_semopm) return -E2BIG; - if(nsops > SEMOPM_FAST) { - sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); - if(sops==NULL) + if (nsops > SEMOPM_FAST) { + sops = kmalloc(sizeof(*sops)*nsops, GFP_KERNEL); + if (sops == NULL) return -ENOMEM; } - if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { - error=-EFAULT; + if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { + error = -EFAULT; goto out_free; } if (timeout) { @@ -1846,7 +1846,15 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, error = -EIDRM; locknum = sem_lock(sma, sops, nsops); - if (sma->sem_perm.deleted) + /* + * We eventually might perform the following check in a lockless + * fashion, considering ipc_valid_object() locking constraints. + * If nsops == 1 and there is no contention for sem_perm.lock, then + * only a per-semaphore lock is held and it's OK to proceed with the + * check below. More details on the fine grained locking scheme + * entangled here and why it's RMID race safe on comments at sem_lock() + */ + if (!ipc_valid_object(&sma->sem_perm)) goto out_unlock_free; /* * semid identifiers are not unique - find_alloc_undo may have @@ -1959,10 +1967,8 @@ sleep_again: * If queue.status != -EINTR we are woken up by another process. * Leave without unlink_queue(), but with sem_unlock(). */ - - if (error != -EINTR) { + if (error != -EINTR) goto out_unlock_free; - } /* * If an interrupt occurred we have to clean up the queue @@ -1984,7 +1990,7 @@ out_rcu_wakeup: rcu_read_unlock(); wake_up_sem_queue_do(&tasks); out_free: - if(sops != fast_sops) + if (sops != fast_sops) kfree(sops); return error; } @@ -2068,7 +2074,7 @@ void exit_sem(struct task_struct *tsk) sem_lock(sma, NULL, -1); /* exit_sem raced with IPC_RMID, nothing to do */ - if (sma->sem_perm.deleted) { + if (!ipc_valid_object(&sma->sem_perm)) { sem_unlock(sma, -1); rcu_read_unlock(); continue; @@ -2093,7 +2099,7 @@ void exit_sem(struct task_struct *tsk) /* perform adjustments registered in un */ for (i = 0; i < sma->sem_nsems; i++) { - struct sem * semaphore = &sma->sem_base[i]; + struct sem *semaphore = &sma->sem_base[i]; if (un->semadj[i]) { semaphore->semval += un->semadj[i]; /* @@ -2107,7 +2113,7 @@ void exit_sem(struct task_struct *tsk) * Linux caps the semaphore value, both at 0 * and at SEMVMX. * - * Manfred <manfred@colorfullife.com> + * Manfred <manfred@colorfullife.com> */ if (semaphore->semval < 0) semaphore->semval = 0; diff --git a/ipc/shm.c b/ipc/shm.c index 7a51443a51d6..76459616a7fa 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -67,7 +67,7 @@ static const struct vm_operations_struct shm_vm_ops; static int newseg(struct ipc_namespace *, struct ipc_params *); static void shm_open(struct vm_area_struct *vma); static void shm_close(struct vm_area_struct *vma); -static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); +static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp); #ifdef CONFIG_PROC_FS static int sysvipc_shm_proc_show(struct seq_file *s, void *it); #endif @@ -91,7 +91,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) struct shmid_kernel *shp; shp = container_of(ipcp, struct shmid_kernel, shm_perm); - if (shp->shm_nattch){ + if (shp->shm_nattch) { shp->shm_perm.mode |= SHM_DEST; /* Do not find it any more */ shp->shm_perm.key = IPC_PRIVATE; @@ -116,7 +116,7 @@ static int __init ipc_ns_init(void) pure_initcall(ipc_ns_init); -void __init shm_init (void) +void __init shm_init(void) { ipc_init_proc_interface("sysvipc/shm", #if BITS_PER_LONG <= 32 @@ -248,7 +248,7 @@ static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) */ static void shm_close(struct vm_area_struct *vma) { - struct file * file = vma->vm_file; + struct file *file = vma->vm_file; struct shm_file_data *sfd = shm_file_data(file); struct shmid_kernel *shp; struct ipc_namespace *ns = sfd->ns; @@ -379,7 +379,7 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma, } #endif -static int shm_mmap(struct file * file, struct vm_area_struct * vma) +static int shm_mmap(struct file *file, struct vm_area_struct *vma) { struct shm_file_data *sfd = shm_file_data(file); int ret; @@ -477,7 +477,6 @@ static const struct vm_operations_struct shm_vm_ops = { * * Called with shm_ids.rwsem held as a writer. */ - static int newseg(struct ipc_namespace *ns, struct ipc_params *params) { key_t key = params->key; @@ -486,7 +485,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) int error; struct shmid_kernel *shp; size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - struct file * file; + struct file *file; char name[13]; int id; vm_flags_t acctflag = 0; @@ -512,7 +511,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) return error; } - sprintf (name, "SYSV%08x", key); + sprintf(name, "SYSV%08x", key); if (shmflg & SHM_HUGETLB) { struct hstate *hs; size_t hugesize; @@ -533,7 +532,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) } else { /* * Do not allow no accounting for OVERCOMMIT_NEVER, even - * if it's asked for. + * if it's asked for. */ if ((shmflg & SHM_NORESERVE) && sysctl_overcommit_memory != OVERCOMMIT_NEVER) @@ -628,7 +627,7 @@ SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg) static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) { - switch(version) { + switch (version) { case IPC_64: return copy_to_user(buf, in, sizeof(*in)); case IPC_OLD: @@ -655,7 +654,7 @@ static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ static inline unsigned long copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version) { - switch(version) { + switch (version) { case IPC_64: if (copy_from_user(out, buf, sizeof(*out))) return -EFAULT; @@ -680,14 +679,14 @@ copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version) static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version) { - switch(version) { + switch (version) { case IPC_64: return copy_to_user(buf, in, sizeof(*in)); case IPC_OLD: { struct shminfo out; - if(in->shmmax > INT_MAX) + if (in->shmmax > INT_MAX) out.shmmax = INT_MAX; else out.shmmax = (int)in->shmmax; @@ -846,14 +845,14 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid, shminfo.shmall = ns->shm_ctlall; shminfo.shmmin = SHMMIN; - if(copy_shminfo_to_user (buf, &shminfo, version)) + if (copy_shminfo_to_user(buf, &shminfo, version)) return -EFAULT; down_read(&shm_ids(ns).rwsem); err = ipc_get_maxid(&shm_ids(ns)); up_read(&shm_ids(ns).rwsem); - if(err<0) + if (err < 0) err = 0; goto out; } @@ -864,7 +863,7 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid, memset(&shm_info, 0, sizeof(shm_info)); down_read(&shm_ids(ns).rwsem); shm_info.used_ids = shm_ids(ns).in_use; - shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); + shm_get_stat(ns, &shm_info.shm_rss, &shm_info.shm_swp); shm_info.shm_tot = ns->shm_tot; shm_info.swap_attempts = 0; shm_info.swap_successes = 0; @@ -975,6 +974,13 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) goto out_unlock1; ipc_lock_object(&shp->shm_perm); + + /* check if shm_destroy() is tearing down shp */ + if (!ipc_valid_object(&shp->shm_perm)) { + err = -EIDRM; + goto out_unlock0; + } + if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { kuid_t euid = current_euid(); if (!uid_eq(euid, shp->shm_perm.uid) && @@ -989,13 +995,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) } shm_file = shp->shm_file; - - /* check if shm_destroy() is tearing down shp */ - if (shm_file == NULL) { - err = -EIDRM; - goto out_unlock0; - } - if (is_file_hugepages(shm_file)) goto out_unlock0; @@ -1047,7 +1046,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, struct shmid_kernel *shp; unsigned long addr; unsigned long size; - struct file * file; + struct file *file; int err; unsigned long flags; unsigned long prot; @@ -1116,7 +1115,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, ipc_lock_object(&shp->shm_perm); /* check if shm_destroy() is tearing down shp */ - if (shp->shm_file == NULL) { + if (!ipc_valid_object(&shp->shm_perm)) { ipc_unlock_object(&shp->shm_perm); err = -EIDRM; goto out_unlock; diff --git a/ipc/util.c b/ipc/util.c index 3ae17a4ace5b..e1b4c6db8aa0 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -110,15 +110,15 @@ static struct notifier_block ipc_memory_nb = { }; /** - * ipc_init - initialise IPC subsystem + * ipc_init - initialise ipc subsystem * - * The various system5 IPC resources (semaphores, messages and shared - * memory) are initialised - * A callback routine is registered into the memory hotplug notifier - * chain: since msgmni scales to lowmem this callback routine will be - * called upon successful memory add / remove to recompute msmgni. + * The various sysv ipc resources (semaphores, messages and shared + * memory) are initialised. + * + * A callback routine is registered into the memory hotplug notifier + * chain: since msgmni scales to lowmem this callback routine will be + * called upon successful memory add / remove to recompute msmgni. */ - static int __init ipc_init(void) { sem_init(); @@ -131,39 +131,29 @@ static int __init ipc_init(void) __initcall(ipc_init); /** - * ipc_init_ids - initialise IPC identifiers - * @ids: Identifier set + * ipc_init_ids - initialise ipc identifiers + * @ids: ipc identifier set * - * Set up the sequence range to use for the ipc identifier range (limited - * below IPCMNI) then initialise the ids idr. + * Set up the sequence range to use for the ipc identifier range (limited + * below IPCMNI) then initialise the ids idr. */ - void ipc_init_ids(struct ipc_ids *ids) { - init_rwsem(&ids->rwsem); - ids->in_use = 0; ids->seq = 0; ids->next_id = -1; - { - int seq_limit = INT_MAX/SEQ_MULTIPLIER; - if (seq_limit > USHRT_MAX) - ids->seq_max = USHRT_MAX; - else - ids->seq_max = seq_limit; - } - + init_rwsem(&ids->rwsem); idr_init(&ids->ipcs_idr); } #ifdef CONFIG_PROC_FS static const struct file_operations sysvipc_proc_fops; /** - * ipc_init_proc_interface - Create a proc interface for sysipc types using a seq_file interface. - * @path: Path in procfs - * @header: Banner to be printed at the beginning of the file. - * @ids: ipc id table to iterate. - * @show: show routine. + * ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface. + * @path: Path in procfs + * @header: Banner to be printed at the beginning of the file. + * @ids: ipc id table to iterate. + * @show: show routine. */ void __init ipc_init_proc_interface(const char *path, const char *header, int ids, int (*show)(struct seq_file *, void *)) @@ -184,23 +174,21 @@ void __init ipc_init_proc_interface(const char *path, const char *header, NULL, /* parent dir */ &sysvipc_proc_fops, iface); - if (!pde) { + if (!pde) kfree(iface); - } } #endif /** - * ipc_findkey - find a key in an ipc identifier set - * @ids: Identifier set - * @key: The key to find + * ipc_findkey - find a key in an ipc identifier set + * @ids: ipc identifier set + * @key: key to find * - * Requires ipc_ids.rwsem locked. - * Returns the LOCKED pointer to the ipc structure if found or NULL - * if not. - * If key is found ipc points to the owning ipc structure + * Returns the locked pointer to the ipc structure if found or NULL + * otherwise. If key is found ipc points to the owning ipc structure + * + * Called with ipc_ids.rwsem held. */ - static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) { struct kern_ipc_perm *ipc; @@ -227,12 +215,11 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) } /** - * ipc_get_maxid - get the last assigned id - * @ids: IPC identifier set + * ipc_get_maxid - get the last assigned id + * @ids: ipc identifier set * - * Called with ipc_ids.rwsem held. + * Called with ipc_ids.rwsem held. */ - int ipc_get_maxid(struct ipc_ids *ids) { struct kern_ipc_perm *ipc; @@ -258,19 +245,19 @@ int ipc_get_maxid(struct ipc_ids *ids) } /** - * ipc_addid - add an IPC identifier - * @ids: IPC identifier set - * @new: new IPC permission set - * @size: limit for the number of used ids + * ipc_addid - add an ipc identifier + * @ids: ipc identifier set + * @new: new ipc permission set + * @size: limit for the number of used ids * - * Add an entry 'new' to the IPC ids idr. The permissions object is - * initialised and the first free entry is set up and the id assigned - * is returned. The 'new' entry is returned in a locked state on success. - * On failure the entry is not locked and a negative err-code is returned. + * Add an entry 'new' to the ipc ids idr. The permissions object is + * initialised and the first free entry is set up and the id assigned + * is returned. The 'new' entry is returned in a locked state on success. + * On failure the entry is not locked and a negative err-code is returned. * - * Called with writer ipc_ids.rwsem held. + * Called with writer ipc_ids.rwsem held. */ -int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) +int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) { kuid_t euid; kgid_t egid; @@ -286,7 +273,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) idr_preload(GFP_KERNEL); spin_lock_init(&new->lock); - new->deleted = 0; + new->deleted = false; rcu_read_lock(); spin_lock(&new->lock); @@ -308,7 +295,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) if (next_id < 0) { new->seq = ids->seq++; - if (ids->seq > ids->seq_max) + if (ids->seq > IPCID_SEQ_MAX) ids->seq = 0; } else { new->seq = ipcid_to_seqx(next_id); @@ -320,14 +307,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) } /** - * ipcget_new - create a new ipc object - * @ns: namespace - * @ids: IPC identifer set - * @ops: the actual creation routine to call - * @params: its parameters - * - * This routine is called by sys_msgget, sys_semget() and sys_shmget() - * when the key is IPC_PRIVATE. + * ipcget_new - create a new ipc object + * @ns: ipc namespace + * @ids: ipc identifer set + * @ops: the actual creation routine to call + * @params: its parameters + * + * This routine is called by sys_msgget, sys_semget() and sys_shmget() + * when the key is IPC_PRIVATE. */ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, struct ipc_ops *ops, struct ipc_params *params) @@ -341,19 +328,19 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, } /** - * ipc_check_perms - check security and permissions for an IPC - * @ns: IPC namespace - * @ipcp: ipc permission set - * @ops: the actual security routine to call - * @params: its parameters + * ipc_check_perms - check security and permissions for an ipc object + * @ns: ipc namespace + * @ipcp: ipc permission set + * @ops: the actual security routine to call + * @params: its parameters * - * This routine is called by sys_msgget(), sys_semget() and sys_shmget() - * when the key is not IPC_PRIVATE and that key already exists in the - * ids IDR. + * This routine is called by sys_msgget(), sys_semget() and sys_shmget() + * when the key is not IPC_PRIVATE and that key already exists in the + * ds IDR. * - * On success, the IPC id is returned. + * On success, the ipc id is returned. * - * It is called with ipc_ids.rwsem and ipcp->lock held. + * It is called with ipc_ids.rwsem and ipcp->lock held. */ static int ipc_check_perms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, @@ -374,18 +361,18 @@ static int ipc_check_perms(struct ipc_namespace *ns, } /** - * ipcget_public - get an ipc object or create a new one - * @ns: namespace - * @ids: IPC identifer set - * @ops: the actual creation routine to call - * @params: its parameters - * - * This routine is called by sys_msgget, sys_semget() and sys_shmget() - * when the key is not IPC_PRIVATE. - * It adds a new entry if the key is not found and does some permission - * / security checkings if the key is found. - * - * On success, the ipc id is returned. + * ipcget_public - get an ipc object or create a new one + * @ns: ipc namespace + * @ids: ipc identifer set + * @ops: the actual creation routine to call + * @params: its parameters + * + * This routine is called by sys_msgget, sys_semget() and sys_shmget() + * when the key is not IPC_PRIVATE. + * It adds a new entry if the key is not found and does some permission + * / security checkings if the key is found. + * + * On success, the ipc id is returned. */ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, struct ipc_ops *ops, struct ipc_params *params) @@ -431,39 +418,33 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, /** - * ipc_rmid - remove an IPC identifier - * @ids: IPC identifier set - * @ipcp: ipc perm structure containing the identifier to remove + * ipc_rmid - remove an ipc identifier + * @ids: ipc identifier set + * @ipcp: ipc perm structure containing the identifier to remove * - * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held - * before this function is called, and remain locked on the exit. + * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held + * before this function is called, and remain locked on the exit. */ - void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp) { int lid = ipcid_to_idx(ipcp->id); idr_remove(&ids->ipcs_idr, lid); - ids->in_use--; - - ipcp->deleted = 1; - - return; + ipcp->deleted = true; } /** - * ipc_alloc - allocate ipc space - * @size: size desired + * ipc_alloc - allocate ipc space + * @size: size desired * - * Allocate memory from the appropriate pools and return a pointer to it. - * NULL is returned if the allocation fails + * Allocate memory from the appropriate pools and return a pointer to it. + * NULL is returned if the allocation fails */ - void *ipc_alloc(int size) { void *out; - if(size > PAGE_SIZE) + if (size > PAGE_SIZE) out = vmalloc(size); else out = kmalloc(size, GFP_KERNEL); @@ -471,28 +452,27 @@ void *ipc_alloc(int size) } /** - * ipc_free - free ipc space - * @ptr: pointer returned by ipc_alloc - * @size: size of block + * ipc_free - free ipc space + * @ptr: pointer returned by ipc_alloc + * @size: size of block * - * Free a block created with ipc_alloc(). The caller must know the size - * used in the allocation call. + * Free a block created with ipc_alloc(). The caller must know the size + * used in the allocation call. */ - -void ipc_free(void* ptr, int size) +void ipc_free(void *ptr, int size) { - if(size > PAGE_SIZE) + if (size > PAGE_SIZE) vfree(ptr); else kfree(ptr); } /** - * ipc_rcu_alloc - allocate ipc and rcu space - * @size: size desired + * ipc_rcu_alloc - allocate ipc and rcu space + * @size: size desired * - * Allocate memory for the rcu header structure + the object. - * Returns the pointer to the object or NULL upon failure. + * Allocate memory for the rcu header structure + the object. + * Returns the pointer to the object or NULL upon failure. */ void *ipc_rcu_alloc(int size) { @@ -534,17 +514,16 @@ void ipc_rcu_free(struct rcu_head *head) } /** - * ipcperms - check IPC permissions - * @ns: IPC namespace - * @ipcp: IPC permission set - * @flag: desired permission set. + * ipcperms - check ipc permissions + * @ns: ipc namespace + * @ipcp: ipc permission set + * @flag: desired permission set * - * Check user, group, other permissions for access - * to ipc resources. return 0 if allowed + * Check user, group, other permissions for access + * to ipc resources. return 0 if allowed * - * @flag will most probably be 0 or S_...UGO from <linux/stat.h> + * @flag will most probably be 0 or S_...UGO from <linux/stat.h> */ - int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) { kuid_t euid = current_euid(); @@ -572,16 +551,14 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) */ /** - * kernel_to_ipc64_perm - convert kernel ipc permissions to user - * @in: kernel permissions - * @out: new style IPC permissions + * kernel_to_ipc64_perm - convert kernel ipc permissions to user + * @in: kernel permissions + * @out: new style ipc permissions * - * Turn the kernel object @in into a set of permissions descriptions - * for returning to userspace (@out). + * Turn the kernel object @in into a set of permissions descriptions + * for returning to userspace (@out). */ - - -void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) +void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out) { out->key = in->key; out->uid = from_kuid_munged(current_user_ns(), in->uid); @@ -593,15 +570,14 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) } /** - * ipc64_perm_to_ipc_perm - convert new ipc permissions to old - * @in: new style IPC permissions - * @out: old style IPC permissions + * ipc64_perm_to_ipc_perm - convert new ipc permissions to old + * @in: new style ipc permissions + * @out: old style ipc permissions * - * Turn the new style permissions object @in into a compatibility - * object and store it into the @out pointer. + * Turn the new style permissions object @in into a compatibility + * object and store it into the @out pointer. */ - -void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out) +void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out) { out->key = in->key; SET_UID(out->uid, in->uid); @@ -635,8 +611,8 @@ struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id) } /** - * ipc_lock - Lock an ipc structure without rwsem held - * @ids: IPC identifier set + * ipc_lock - lock an ipc structure without rwsem held + * @ids: ipc identifier set * @id: ipc id to look for * * Look for an id in the ipc ids idr and lock the associated ipc object. @@ -657,7 +633,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) /* ipc_rmid() may have already freed the ID while ipc_lock * was spinning: here verify that the structure is still valid */ - if (!out->deleted) + if (ipc_valid_object(out)) return out; spin_unlock(&out->lock); @@ -693,11 +669,11 @@ out: /** * ipcget - Common sys_*get() code - * @ns : namsepace - * @ids : IPC identifier set - * @ops : operations to be called on ipc object creation, permission checks - * and further checks - * @params : the parameters needed by the previous operations. + * @ns: namsepace + * @ids: ipc identifier set + * @ops: operations to be called on ipc object creation, permission checks + * and further checks + * @params: the parameters needed by the previous operations. * * Common routine called by sys_msgget(), sys_semget() and sys_shmget(). */ @@ -711,7 +687,7 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, } /** - * ipc_update_perm - update the permissions of an IPC. + * ipc_update_perm - update the permissions of an ipc object * @in: the permission given as input. * @out: the permission of the ipc to set. */ @@ -732,7 +708,7 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) /** * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd - * @ns: the ipc namespace + * @ns: ipc namespace * @ids: the table of ids where to look for the ipc * @id: the id of the ipc to retrieve * @cmd: the cmd to check @@ -779,15 +755,14 @@ err: /** - * ipc_parse_version - IPC call version - * @cmd: pointer to command + * ipc_parse_version - ipc call version + * @cmd: pointer to command * - * Return IPC_64 for new style IPC and IPC_OLD for old style IPC. - * The @cmd value is turned from an encoding command and version into - * just the command code. + * Return IPC_64 for new style IPC and IPC_OLD for old style IPC. + * The @cmd value is turned from an encoding command and version into + * just the command code. */ - -int ipc_parse_version (int *cmd) +int ipc_parse_version(int *cmd) { if (*cmd & IPC_64) { *cmd ^= IPC_64; @@ -824,7 +799,7 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, if (total >= ids->in_use) return NULL; - for ( ; pos < IPCMNI; pos++) { + for (; pos < IPCMNI; pos++) { ipc = idr_find(&ids->ipcs_idr, pos); if (ipc != NULL) { *new_pos = pos + 1; @@ -927,8 +902,10 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file) goto out; ret = seq_open(file, &sysvipc_proc_seqops); - if (ret) - goto out_kfree; + if (ret) { + kfree(iter); + goto out; + } seq = file->private_data; seq->private = iter; @@ -937,9 +914,6 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file) iter->ns = get_ipc_ns(current->nsproxy->ipc_ns); out: return ret; -out_kfree: - kfree(iter); - goto out; } static int sysvipc_proc_release(struct inode *inode, struct file *file) diff --git a/ipc/util.h b/ipc/util.h index 59d78aa94987..9c47d6f6c7b4 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -15,9 +15,9 @@ #define SEQ_MULTIPLIER (IPCMNI) -void sem_init (void); -void msg_init (void); -void shm_init (void); +void sem_init(void); +void msg_init(void); +void shm_init(void); struct ipc_namespace; @@ -100,6 +100,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header, #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER) +#define IPCID_SEQ_MAX min_t(int, INT_MAX/SEQ_MULTIPLIER, USHRT_MAX) /* must be called with ids->rwsem acquired for writing */ int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); @@ -116,8 +117,8 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); /* for rare, potentially huge allocations. * both function can sleep */ -void* ipc_alloc(int size); -void ipc_free(void* ptr, int size); +void *ipc_alloc(int size); +void ipc_free(void *ptr, int size); /* * For allocation that need to be freed by RCU. @@ -125,7 +126,7 @@ void ipc_free(void* ptr, int size); * getref increases the refcount, the putref call that reduces the recount * to 0 schedules the rcu destruction. Caller must guarantee locking. */ -void* ipc_rcu_alloc(int size); +void *ipc_rcu_alloc(int size); int ipc_rcu_getref(void *ptr); void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head)); void ipc_rcu_free(struct rcu_head *head); @@ -144,7 +145,7 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns, /* On IA-64, we always use the "64-bit version" of the IPC structures. */ # define ipc_parse_version(cmd) IPC_64 #else -int ipc_parse_version (int *cmd); +int ipc_parse_version(int *cmd); #endif extern void free_msg(struct msg_msg *msg); @@ -185,6 +186,19 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm) rcu_read_unlock(); } +/* + * ipc_valid_object() - helper to sort out IPC_RMID races for codepaths + * where the respective ipc_ids.rwsem is not being held down. + * Checks whether the ipc object is still around or if it's gone already, as + * ipc_rmid() may have already freed the ID while the ipc lock was spinning. + * Needs to be called with kern_ipc_perm.lock held -- exception made for one + * checkpoint case at sys_semtimedop() as noted in code commentary. + */ +static inline bool ipc_valid_object(struct kern_ipc_perm *perm) +{ + return !perm->deleted; +} + struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id); int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, struct ipc_ops *ops, struct ipc_params *params); diff --git a/kernel/kexec.c b/kernel/kexec.c index ac738781d356..60bafbed06ab 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1537,7 +1537,7 @@ void vmcoreinfo_append_str(const char *fmt, ...) size_t r; va_start(args, fmt); - r = vsnprintf(buf, sizeof(buf), fmt, args); + r = vscnprintf(buf, sizeof(buf), fmt, args); va_end(args); r = min(r, vmcoreinfo_max_size - vmcoreinfo_size); diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 802365ccd591..c54609faf233 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -200,17 +200,6 @@ void wait_rcu_gp(call_rcu_func_t crf) } EXPORT_SYMBOL_GPL(wait_rcu_gp); -#ifdef CONFIG_PROVE_RCU -/* - * wrapper function to avoid #include problems. - */ -int rcu_my_thread_group_empty(void) -{ - return thread_group_empty(current); -} -EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty); -#endif /* #ifdef CONFIG_PROVE_RCU */ - #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD static inline void debug_init_rcu_head(struct rcu_head *head) { diff --git a/kernel/softirq.c b/kernel/softirq.c index 8a1e6e104892..850967068aaf 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -8,6 +8,8 @@ * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903) */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/export.h> #include <linux/kernel_stat.h> #include <linux/interrupt.h> @@ -54,7 +56,7 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp DEFINE_PER_CPU(struct task_struct *, ksoftirqd); -char *softirq_to_name[NR_SOFTIRQS] = { +const char * const softirq_to_name[NR_SOFTIRQS] = { "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", "TASKLET", "SCHED", "HRTIMER", "RCU" }; @@ -136,7 +138,6 @@ void _local_bh_enable(void) WARN_ON_ONCE(in_irq()); __local_bh_enable(SOFTIRQ_DISABLE_OFFSET); } - EXPORT_SYMBOL(_local_bh_enable); void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) @@ -153,7 +154,7 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) /* * Keep preemption disabled until we are done with * softirq processing: - */ + */ preempt_count_sub(cnt - 1); if (unlikely(!in_interrupt() && local_softirq_pending())) { @@ -229,6 +230,7 @@ asmlinkage void __do_softirq(void) struct softirq_action *h; bool in_hardirq; __u32 pending; + int softirq_bit; int cpu; /* @@ -253,30 +255,30 @@ restart: h = softirq_vec; - do { - if (pending & 1) { - unsigned int vec_nr = h - softirq_vec; - int prev_count = preempt_count(); - - kstat_incr_softirqs_this_cpu(vec_nr); - - trace_softirq_entry(vec_nr); - h->action(h); - trace_softirq_exit(vec_nr); - if (unlikely(prev_count != preempt_count())) { - printk(KERN_ERR "huh, entered softirq %u %s %p" - "with preempt_count %08x," - " exited with %08x?\n", vec_nr, - softirq_to_name[vec_nr], h->action, - prev_count, preempt_count()); - preempt_count_set(prev_count); - } + while ((softirq_bit = ffs(pending))) { + unsigned int vec_nr; + int prev_count; - rcu_bh_qs(cpu); + h += softirq_bit - 1; + + vec_nr = h - softirq_vec; + prev_count = preempt_count(); + + kstat_incr_softirqs_this_cpu(vec_nr); + + trace_softirq_entry(vec_nr); + h->action(h); + trace_softirq_exit(vec_nr); + if (unlikely(prev_count != preempt_count())) { + pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", + vec_nr, softirq_to_name[vec_nr], h->action, + prev_count, preempt_count()); + preempt_count_set(prev_count); } + rcu_bh_qs(cpu); h++; - pending >>= 1; - } while (pending); + pending >>= softirq_bit; + } local_irq_disable(); @@ -433,8 +435,7 @@ void open_softirq(int nr, void (*action)(struct softirq_action *)) /* * Tasklets */ -struct tasklet_head -{ +struct tasklet_head { struct tasklet_struct *head; struct tasklet_struct **tail; }; @@ -453,7 +454,6 @@ void __tasklet_schedule(struct tasklet_struct *t) raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_restore(flags); } - EXPORT_SYMBOL(__tasklet_schedule); void __tasklet_hi_schedule(struct tasklet_struct *t) @@ -467,7 +467,6 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) raise_softirq_irqoff(HI_SOFTIRQ); local_irq_restore(flags); } - EXPORT_SYMBOL(__tasklet_hi_schedule); void __tasklet_hi_schedule_first(struct tasklet_struct *t) @@ -478,7 +477,6 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t) __this_cpu_write(tasklet_hi_vec.head, t); __raise_softirq_irqoff(HI_SOFTIRQ); } - EXPORT_SYMBOL(__tasklet_hi_schedule_first); static void tasklet_action(struct softirq_action *a) @@ -498,7 +496,8 @@ static void tasklet_action(struct softirq_action *a) if (tasklet_trylock(t)) { if (!atomic_read(&t->count)) { - if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + if (!test_and_clear_bit(TASKLET_STATE_SCHED, + &t->state)) BUG(); t->func(t->data); tasklet_unlock(t); @@ -533,7 +532,8 @@ static void tasklet_hi_action(struct softirq_action *a) if (tasklet_trylock(t)) { if (!atomic_read(&t->count)) { - if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + if (!test_and_clear_bit(TASKLET_STATE_SCHED, + &t->state)) BUG(); t->func(t->data); tasklet_unlock(t); @@ -551,7 +551,6 @@ static void tasklet_hi_action(struct softirq_action *a) } } - void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data) { @@ -561,13 +560,12 @@ void tasklet_init(struct tasklet_struct *t, t->func = func; t->data = data; } - EXPORT_SYMBOL(tasklet_init); void tasklet_kill(struct tasklet_struct *t) { if (in_interrupt()) - printk("Attempt to kill tasklet from interrupt\n"); + pr_notice("Attempt to kill tasklet from interrupt\n"); while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { do { @@ -577,7 +575,6 @@ void tasklet_kill(struct tasklet_struct *t) tasklet_unlock_wait(t); clear_bit(TASKLET_STATE_SCHED, &t->state); } - EXPORT_SYMBOL(tasklet_kill); /* @@ -727,9 +724,8 @@ static void takeover_tasklets(unsigned int cpu) } #endif /* CONFIG_HOTPLUG_CPU */ -static int cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) +static int cpu_callback(struct notifier_block *nfb, unsigned long action, + void *hcpu) { switch (action) { #ifdef CONFIG_HOTPLUG_CPU diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 20c755e018ca..815c878f409b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -455,6 +455,9 @@ int __trace_puts(unsigned long ip, const char *str, int size) unsigned long irq_flags; int alloc; + if (unlikely(tracing_selftest_running || tracing_disabled)) + return 0; + alloc = sizeof(*entry) + size + 2; /* possible \n added */ local_save_flags(irq_flags); @@ -495,6 +498,9 @@ int __trace_bputs(unsigned long ip, const char *str) unsigned long irq_flags; int size = sizeof(struct bputs_entry); + if (unlikely(tracing_selftest_running || tracing_disabled)) + return 0; + local_save_flags(irq_flags); buffer = global_trace.trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, @@ -3519,60 +3525,103 @@ static const char readme_msg[] = " instances\t\t- Make sub-buffers with: mkdir instances/foo\n" "\t\t\t Remove sub-buffer with rmdir\n" " trace_options\t\t- Set format or modify how tracing happens\n" - "\t\t\t Disable an option by adding a suffix 'no' to the option name\n" + "\t\t\t Disable an option by adding a suffix 'no' to the\n" + "\t\t\t option name\n" #ifdef CONFIG_DYNAMIC_FTRACE "\n available_filter_functions - list of functions that can be filtered on\n" - " set_ftrace_filter\t- echo function name in here to only trace these functions\n" - " accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" - " modules: Can select a group via module\n" - " Format: :mod:<module-name>\n" - " example: echo :mod:ext3 > set_ftrace_filter\n" - " triggers: a command to perform when function is hit\n" - " Format: <function>:<trigger>[:count]\n" - " trigger: traceon, traceoff\n" - " enable_event:<system>:<event>\n" - " disable_event:<system>:<event>\n" + " set_ftrace_filter\t- echo function name in here to only trace these\n" + "\t\t\t functions\n" + "\t accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" + "\t modules: Can select a group via module\n" + "\t Format: :mod:<module-name>\n" + "\t example: echo :mod:ext3 > set_ftrace_filter\n" + "\t triggers: a command to perform when function is hit\n" + "\t Format: <function>:<trigger>[:count]\n" + "\t trigger: traceon, traceoff\n" + "\t\t enable_event:<system>:<event>\n" + "\t\t disable_event:<system>:<event>\n" #ifdef CONFIG_STACKTRACE - " stacktrace\n" + "\t\t stacktrace\n" #endif #ifdef CONFIG_TRACER_SNAPSHOT - " snapshot\n" + "\t\t snapshot\n" #endif - " example: echo do_fault:traceoff > set_ftrace_filter\n" - " echo do_trap:traceoff:3 > set_ftrace_filter\n" - " The first one will disable tracing every time do_fault is hit\n" - " The second will disable tracing at most 3 times when do_trap is hit\n" - " The first time do trap is hit and it disables tracing, the counter\n" - " will decrement to 2. If tracing is already disabled, the counter\n" - " will not decrement. It only decrements when the trigger did work\n" - " To remove trigger without count:\n" - " echo '!<function>:<trigger> > set_ftrace_filter\n" - " To remove trigger with a count:\n" - " echo '!<function>:<trigger>:0 > set_ftrace_filter\n" + "\t example: echo do_fault:traceoff > set_ftrace_filter\n" + "\t echo do_trap:traceoff:3 > set_ftrace_filter\n" + "\t The first one will disable tracing every time do_fault is hit\n" + "\t The second will disable tracing at most 3 times when do_trap is hit\n" + "\t The first time do trap is hit and it disables tracing, the\n" + "\t counter will decrement to 2. If tracing is already disabled,\n" + "\t the counter will not decrement. It only decrements when the\n" + "\t trigger did work\n" + "\t To remove trigger without count:\n" + "\t echo '!<function>:<trigger> > set_ftrace_filter\n" + "\t To remove trigger with a count:\n" + "\t echo '!<function>:<trigger>:0 > set_ftrace_filter\n" " set_ftrace_notrace\t- echo function name in here to never trace.\n" - " accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" - " modules: Can select a group via module command :mod:\n" - " Does not accept triggers\n" + "\t accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" + "\t modules: Can select a group via module command :mod:\n" + "\t Does not accept triggers\n" #endif /* CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_FUNCTION_TRACER - " set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n" + " set_ftrace_pid\t- Write pid(s) to only function trace those pids\n" + "\t\t (function)\n" #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER " set_graph_function\t- Trace the nested calls of a function (function_graph)\n" " max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n" #endif #ifdef CONFIG_TRACER_SNAPSHOT - "\n snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n" - "\t\t\t Read the contents for more information\n" + "\n snapshot\t\t- Like 'trace' but shows the content of the static\n" + "\t\t\t snapshot buffer. Read the contents for more\n" + "\t\t\t information\n" #endif #ifdef CONFIG_STACK_TRACER " stack_trace\t\t- Shows the max stack trace when active\n" " stack_max_size\t- Shows current max stack size that was traced\n" - "\t\t\t Write into this file to reset the max size (trigger a new trace)\n" + "\t\t\t Write into this file to reset the max size (trigger a\n" + "\t\t\t new trace)\n" #ifdef CONFIG_DYNAMIC_FTRACE - " stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n" + " stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace\n" + "\t\t\t traces\n" #endif #endif /* CONFIG_STACK_TRACER */ + " events/\t\t- Directory containing all trace event subsystems:\n" + " enable\t\t- Write 0/1 to enable/disable tracing of all events\n" + " events/<system>/\t- Directory containing all trace events for <system>:\n" + " enable\t\t- Write 0/1 to enable/disable tracing of all <system>\n" + "\t\t\t events\n" + " filter\t\t- If set, only events passing filter are traced\n" + " events/<system>/<event>/\t- Directory containing control files for\n" + "\t\t\t <event>:\n" + " enable\t\t- Write 0/1 to enable/disable tracing of <event>\n" + " filter\t\t- If set, only events passing filter are traced\n" + " trigger\t\t- If set, a command to perform when event is hit\n" + "\t Format: <trigger>[:count][if <filter>]\n" + "\t trigger: traceon, traceoff\n" + "\t enable_event:<system>:<event>\n" + "\t disable_event:<system>:<event>\n" +#ifdef CONFIG_STACKTRACE + "\t\t stacktrace\n" +#endif +#ifdef CONFIG_TRACER_SNAPSHOT + "\t\t snapshot\n" +#endif + "\t example: echo traceoff > events/block/block_unplug/trigger\n" + "\t echo traceoff:3 > events/block/block_unplug/trigger\n" + "\t echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n" + "\t events/block/block_unplug/trigger\n" + "\t The first disables tracing every time block_unplug is hit.\n" + "\t The second disables tracing the first 3 times block_unplug is hit.\n" + "\t The third enables the kmalloc event the first 3 times block_unplug\n" + "\t is hit and has value of greater than 1 for the 'nr_rq' event field.\n" + "\t Like function triggers, the counter is only decremented if it\n" + "\t enabled or disabled tracing.\n" + "\t To remove a trigger without a count:\n" + "\t echo '!<trigger> > <system>/<event>/trigger\n" + "\t To remove a trigger with a count:\n" + "\t echo '!<trigger>:0 > <system>/<event>/trigger\n" + "\t Filters can be ignored when removing a trigger.\n" ; static ssize_t diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e0e2eebf7ab3..dbf94a7d25a8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1556,17 +1556,6 @@ config PROVIDE_OHCI1394_DMA_INIT See Documentation/debugging-via-ohci1394.txt for more information. -config FIREWIRE_OHCI_REMOTE_DMA - bool "Remote debugging over FireWire with firewire-ohci" - depends on FIREWIRE_OHCI - help - This option lets you use the FireWire bus for remote debugging - with help of the firewire-ohci driver. It enables unfiltered - remote DMA in firewire-ohci. - See Documentation/debugging-via-ohci1394.txt for more information. - - If unsure, say N. - config BUILD_DOCSRC bool "Build targets in Documentation/ tree" depends on HEADERS_CHECK diff --git a/lib/dma-debug.c b/lib/dma-debug.c index c38083871f11..2defd1308b04 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -463,7 +463,7 @@ static int active_pfn_set_overlap(unsigned long pfn, int overlap) int i; if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0) - return 0; + return overlap; for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--) if (overlap & 1 << i) @@ -486,7 +486,7 @@ static void active_pfn_inc_overlap(unsigned long pfn) * debug_dma_assert_idle() as the pfn may be marked idle * prematurely. */ - WARN_ONCE(overlap == 0, + WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP, "DMA-API: exceeded %d overlapping mappings of pfn %lx\n", ACTIVE_PFN_MAX_OVERLAP, pfn); } @@ -517,7 +517,11 @@ static void active_pfn_remove(struct dma_debug_entry *entry) unsigned long flags; spin_lock_irqsave(&radix_lock, flags); - if (active_pfn_dec_overlap(entry->pfn) == 0) + /* since we are counting overlaps the final put of the + * entry->pfn will occur when the overlap count is 0. + * active_pfn_dec_overlap() returns -1 in that case + */ + if (active_pfn_dec_overlap(entry->pfn) < 0) radix_tree_delete(&dma_active_pfn, entry->pfn); spin_unlock_irqrestore(&radix_lock, flags); } diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 600ac57e2777..7288e38e1757 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -268,14 +268,12 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) */ static inline int parse_lineno(const char *str, unsigned int *val) { - char *end = NULL; BUG_ON(str == NULL); if (*str == '\0') { *val = 0; return 0; } - *val = simple_strtoul(str, &end, 10); - if (end == NULL || end == str || *end != '\0') { + if (kstrtouint(str, 10, val) < 0) { pr_err("bad line-number: %s\n", str); return -EINVAL; } @@ -348,14 +346,14 @@ static int ddebug_parse_query(char *words[], int nwords, } if (last) *last++ = '\0'; - if (parse_lineno(first, &query->first_lineno) < 0) { - pr_err("line-number is <0\n"); + if (parse_lineno(first, &query->first_lineno) < 0) return -EINVAL; - } if (last) { /* range <first>-<last> */ - if (parse_lineno(last, &query->last_lineno) - < query->first_lineno) { + if (parse_lineno(last, &query->last_lineno) < 0) + return -EINVAL; + + if (query->last_lineno < query->first_lineno) { pr_err("last-line:%d < 1st-line:%d\n", query->last_lineno, query->first_lineno); diff --git a/lib/genalloc.c b/lib/genalloc.c index dda31168844f..bdb9a456bcbb 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -316,7 +316,7 @@ EXPORT_SYMBOL(gen_pool_alloc); * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage * @pool: pool to allocate from * @size: number of bytes to allocate from the pool - * @dma: dma-view physical address + * @dma: dma-view physical address return value. Use NULL if unneeded. * * Allocate the requested number of bytes from the specified pool. * Uses the pool allocation function (with first-fit algorithm by default). @@ -334,7 +334,8 @@ void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma) if (!vaddr) return NULL; - *dma = gen_pool_virt_to_phys(pool, vaddr); + if (dma) + *dma = gen_pool_virt_to_phys(pool, vaddr); return (void *)vaddr; } diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 615f3de4b5ce..b604b831f4d1 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -172,7 +172,7 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) /* * Get the overflow emergency buffer */ - v_overflow_buffer = memblock_virt_alloc_nopanic( + v_overflow_buffer = memblock_virt_alloc_low_nopanic( PAGE_ALIGN(io_tlb_overflow), PAGE_SIZE); if (!v_overflow_buffer) @@ -220,7 +220,7 @@ swiotlb_init(int verbose) bytes = io_tlb_nslabs << IO_TLB_SHIFT; /* Get IO TLB memory from the low pages */ - vstart = memblock_virt_alloc_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE); + vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE); if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose)) return; @@ -510,7 +510,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, not_found: spin_unlock_irqrestore(&io_tlb_lock, flags); - dev_warn(hwdev, "swiotlb buffer is full\n"); + if (printk_ratelimit()) + dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size); return SWIOTLB_MAP_ERROR; found: spin_unlock_irqrestore(&io_tlb_lock, flags); diff --git a/mm/filemap.c b/mm/filemap.c index 7a7f3e0db738..d56d3c145b9f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1428,30 +1428,28 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (!count) goto out; /* skip atime */ size = i_size_read(inode); - if (pos < size) { - retval = filemap_write_and_wait_range(mapping, pos, + retval = filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1); - if (!retval) { - retval = mapping->a_ops->direct_IO(READ, iocb, - iov, pos, nr_segs); - } - if (retval > 0) { - *ppos = pos + retval; - count -= retval; - } + if (!retval) { + retval = mapping->a_ops->direct_IO(READ, iocb, + iov, pos, nr_segs); + } + if (retval > 0) { + *ppos = pos + retval; + count -= retval; + } - /* - * Btrfs can have a short DIO read if we encounter - * compressed extents, so if there was an error, or if - * we've already read everything we wanted to, or if - * there was a short read because we hit EOF, go ahead - * and return. Otherwise fallthrough to buffered io for - * the rest of the read. - */ - if (retval < 0 || !count || *ppos >= size) { - file_accessed(filp); - goto out; - } + /* + * Btrfs can have a short DIO read if we encounter + * compressed extents, so if there was an error, or if + * we've already read everything we wanted to, or if + * there was a short read because we hit EOF, go ahead + * and return. Otherwise fallthrough to buffered io for + * the rest of the read. + */ + if (retval < 0 || !count || *ppos >= size) { + file_accessed(filp); + goto out; } } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 65c98eb5483c..82166bf974e1 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1508,19 +1508,15 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma, spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING); pmd = pmdp_get_and_clear(mm, old_addr, old_pmd); VM_BUG_ON(!pmd_none(*new_pmd)); - set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd)); - if (new_ptl != old_ptl) { - pgtable_t pgtable; - /* - * Move preallocated PTE page table if new_pmd is on - * different PMD page table. - */ + if (pmd_move_must_withdraw(new_ptl, old_ptl)) { + pgtable_t pgtable; pgtable = pgtable_trans_huge_withdraw(mm, old_pmd); pgtable_trans_huge_deposit(mm, new_pmd, pgtable); - - spin_unlock(new_ptl); } + set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd)); + if (new_ptl != old_ptl) + spin_unlock(new_ptl); spin_unlock(old_ptl); } out: diff --git a/mm/internal.h b/mm/internal.h index 612c14f5e0f5..29e1e761f9eb 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -83,7 +83,6 @@ extern unsigned long highest_memmap_pfn; */ extern int isolate_lru_page(struct page *page); extern void putback_lru_page(struct page *page); -extern unsigned long zone_reclaimable_pages(struct zone *zone); extern bool zone_reclaimable(struct zone *zone); /* diff --git a/mm/memblock.c b/mm/memblock.c index 9c0aeef19440..39a31e7f0045 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -984,9 +984,6 @@ static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size, if (!align) align = SMP_CACHE_BYTES; - /* align @size to avoid excessive fragmentation on reserved array */ - size = round_up(size, align); - found = memblock_find_in_range_node(size, align, 0, max_addr, nid); if (found && !memblock_reserve(found, size)) return found; @@ -1080,8 +1077,8 @@ static void * __init memblock_virt_alloc_internal( if (!align) align = SMP_CACHE_BYTES; - /* align @size to avoid excessive fragmentation on reserved array */ - size = round_up(size, align); + if (max_addr > memblock.current_limit) + max_addr = memblock.current_limit; again: alloc = memblock_find_in_range_node(size, align, min_addr, max_addr, diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 463b7fbf0d1d..873de7e542bc 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -613,7 +613,7 @@ static inline int queue_pages_pgd_range(struct vm_area_struct *vma, return 0; } -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE +#ifdef CONFIG_NUMA_BALANCING /* * This is used to mark a range of virtual addresses to be inaccessible. * These are later cleared by a NUMA hinting fault. Depending on these @@ -627,7 +627,6 @@ unsigned long change_prot_numa(struct vm_area_struct *vma, unsigned long addr, unsigned long end) { int nr_updated; - BUILD_BUG_ON(_PAGE_NUMA != _PAGE_PROTNONE); nr_updated = change_protection(vma, addr, end, vma->vm_page_prot, 0, 1); if (nr_updated) @@ -641,7 +640,7 @@ static unsigned long change_prot_numa(struct vm_area_struct *vma, { return 0; } -#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */ +#endif /* CONFIG_NUMA_BALANCING */ /* * Walk through page tables and collect pages to be migrated. @@ -2655,7 +2654,7 @@ void mpol_free_shared_policy(struct shared_policy *p) } #ifdef CONFIG_NUMA_BALANCING -static bool __initdata numabalancing_override; +static int __initdata numabalancing_override; static void __init check_numabalancing_enable(void) { @@ -2664,9 +2663,15 @@ static void __init check_numabalancing_enable(void) if (IS_ENABLED(CONFIG_NUMA_BALANCING_DEFAULT_ENABLED)) numabalancing_default = true; + /* Parsed by setup_numabalancing. override == 1 enables, -1 disables */ + if (numabalancing_override) + set_numabalancing_state(numabalancing_override == 1); + if (nr_node_ids > 1 && !numabalancing_override) { - printk(KERN_INFO "Enabling automatic NUMA balancing. " - "Configure with numa_balancing= or the kernel.numa_balancing sysctl"); + pr_info("%s automatic NUMA balancing. " + "Configure with numa_balancing= or the " + "kernel.numa_balancing sysctl", + numabalancing_default ? "Enabling" : "Disabling"); set_numabalancing_state(numabalancing_default); } } @@ -2676,18 +2681,17 @@ static int __init setup_numabalancing(char *str) int ret = 0; if (!str) goto out; - numabalancing_override = true; if (!strcmp(str, "enable")) { - set_numabalancing_state(true); + numabalancing_override = 1; ret = 1; } else if (!strcmp(str, "disable")) { - set_numabalancing_state(false); + numabalancing_override = -1; ret = 1; } out: if (!ret) - printk(KERN_WARNING "Unable to parse numa_balancing=\n"); + pr_warn("Unable to parse numa_balancing=\n"); return ret; } diff --git a/mm/migrate.c b/mm/migrate.c index 734704f6f29b..482a33d89134 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1548,8 +1548,6 @@ static struct page *alloc_misplaced_dst_page(struct page *page, __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) & ~GFP_IOFS, 0); - if (newpage) - page_cpupid_xchg_last(newpage, page_cpupid_last(page)); return newpage; } diff --git a/mm/mm_init.c b/mm/mm_init.c index 857a6434e3a5..4074caf9936b 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -202,4 +202,4 @@ static int __init mm_sysfs_init(void) return 0; } -pure_initcall(mm_sysfs_init); +postcore_initcall(mm_sysfs_init); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 63807583d8e8..2d30e2cfe804 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -191,6 +191,26 @@ static unsigned long writeout_period_time = 0; * global dirtyable memory first. */ +/** + * zone_dirtyable_memory - number of dirtyable pages in a zone + * @zone: the zone + * + * Returns the zone's number of pages potentially available for dirty + * page cache. This is the base value for the per-zone dirty limits. + */ +static unsigned long zone_dirtyable_memory(struct zone *zone) +{ + unsigned long nr_pages; + + nr_pages = zone_page_state(zone, NR_FREE_PAGES); + nr_pages -= min(nr_pages, zone->dirty_balance_reserve); + + nr_pages += zone_page_state(zone, NR_INACTIVE_FILE); + nr_pages += zone_page_state(zone, NR_ACTIVE_FILE); + + return nr_pages; +} + static unsigned long highmem_dirtyable_memory(unsigned long total) { #ifdef CONFIG_HIGHMEM @@ -198,11 +218,9 @@ static unsigned long highmem_dirtyable_memory(unsigned long total) unsigned long x = 0; for_each_node_state(node, N_HIGH_MEMORY) { - struct zone *z = - &NODE_DATA(node)->node_zones[ZONE_HIGHMEM]; + struct zone *z = &NODE_DATA(node)->node_zones[ZONE_HIGHMEM]; - x += zone_page_state(z, NR_FREE_PAGES) + - zone_reclaimable_pages(z) - z->dirty_balance_reserve; + x += zone_dirtyable_memory(z); } /* * Unreclaimable memory (kernel memory or anonymous memory @@ -238,9 +256,12 @@ static unsigned long global_dirtyable_memory(void) { unsigned long x; - x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages(); + x = global_page_state(NR_FREE_PAGES); x -= min(x, dirty_balance_reserve); + x += global_page_state(NR_INACTIVE_FILE); + x += global_page_state(NR_ACTIVE_FILE); + if (!vm_highmem_is_dirtyable) x -= highmem_dirtyable_memory(x); @@ -289,32 +310,6 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty) } /** - * zone_dirtyable_memory - number of dirtyable pages in a zone - * @zone: the zone - * - * Returns the zone's number of pages potentially available for dirty - * page cache. This is the base value for the per-zone dirty limits. - */ -static unsigned long zone_dirtyable_memory(struct zone *zone) -{ - /* - * The effective global number of dirtyable pages may exclude - * highmem as a big-picture measure to keep the ratio between - * dirty memory and lowmem reasonable. - * - * But this function is purely about the individual zone and a - * highmem zone can hold its share of dirty pages, so we don't - * care about vm_highmem_is_dirtyable here. - */ - unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) + - zone_reclaimable_pages(zone); - - /* don't allow this to underflow */ - nr_pages -= min(nr_pages, zone->dirty_balance_reserve); - return nr_pages; -} - -/** * zone_dirty_limit - maximum number of dirty pages allowed in a zone * @zone: the zone * diff --git a/mm/readahead.c b/mm/readahead.c index 7cdbb44aa90b..0de2360d65f3 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -211,8 +211,6 @@ out: int force_page_cache_readahead(struct address_space *mapping, struct file *filp, pgoff_t offset, unsigned long nr_to_read) { - int ret = 0; - if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages)) return -EINVAL; @@ -226,15 +224,13 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, this_chunk = nr_to_read; err = __do_page_cache_readahead(mapping, filp, offset, this_chunk, 0); - if (err < 0) { - ret = err; - break; - } - ret += err; + if (err < 0) + return err; + offset += this_chunk; nr_to_read -= this_chunk; } - return ret; + return 0; } /* @@ -576,8 +572,7 @@ do_readahead(struct address_space *mapping, struct file *filp, if (!mapping || !mapping->a_ops) return -EINVAL; - force_page_cache_readahead(mapping, filp, index, nr); - return 0; + return force_page_cache_readahead(mapping, filp, index, nr); } SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) diff --git a/mm/shmem.c b/mm/shmem.c index 8156f95ec0cf..1f18c9d0d93e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -45,7 +45,7 @@ static struct vfsmount *shm_mnt; #include <linux/xattr.h> #include <linux/exportfs.h> #include <linux/posix_acl.h> -#include <linux/generic_acl.h> +#include <linux/posix_acl_xattr.h> #include <linux/mman.h> #include <linux/string.h> #include <linux/slab.h> @@ -620,10 +620,8 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) } setattr_copy(inode, attr); -#ifdef CONFIG_TMPFS_POSIX_ACL if (attr->ia_valid & ATTR_MODE) - error = generic_acl_chmod(inode); -#endif + error = posix_acl_chmod(inode, inode->i_mode); return error; } @@ -1937,22 +1935,14 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE); if (inode) { -#ifdef CONFIG_TMPFS_POSIX_ACL - error = generic_acl_init(inode, dir); - if (error) { - iput(inode); - return error; - } -#endif + error = simple_acl_create(dir, inode); + if (error) + goto out_iput; error = security_inode_init_security(inode, dir, &dentry->d_name, shmem_initxattrs, NULL); - if (error) { - if (error != -EOPNOTSUPP) { - iput(inode); - return error; - } - } + if (error && error != -EOPNOTSUPP) + goto out_iput; error = 0; dir->i_size += BOGO_DIRENT_SIZE; @@ -1961,6 +1951,9 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) dget(dentry); /* Extra count - pin the dentry in core */ } return error; +out_iput: + iput(inode); + return error; } static int @@ -1974,24 +1967,17 @@ shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) error = security_inode_init_security(inode, dir, NULL, shmem_initxattrs, NULL); - if (error) { - if (error != -EOPNOTSUPP) { - iput(inode); - return error; - } - } -#ifdef CONFIG_TMPFS_POSIX_ACL - error = generic_acl_init(inode, dir); - if (error) { - iput(inode); - return error; - } -#else - error = 0; -#endif + if (error && error != -EOPNOTSUPP) + goto out_iput; + error = simple_acl_create(dir, inode); + if (error) + goto out_iput; d_tmpfile(dentry, inode); } return error; +out_iput: + iput(inode); + return error; } static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) @@ -2223,8 +2209,8 @@ static int shmem_initxattrs(struct inode *inode, static const struct xattr_handler *shmem_xattr_handlers[] = { #ifdef CONFIG_TMPFS_POSIX_ACL - &generic_acl_access_handler, - &generic_acl_default_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, #endif NULL }; @@ -2740,6 +2726,7 @@ static const struct inode_operations shmem_inode_operations = { .getxattr = shmem_getxattr, .listxattr = shmem_listxattr, .removexattr = shmem_removexattr, + .set_acl = simple_set_acl, #endif }; @@ -2764,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = { #endif #ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_setattr, + .set_acl = simple_set_acl, #endif }; @@ -2776,6 +2764,7 @@ static const struct inode_operations shmem_special_inode_operations = { #endif #ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_setattr, + .set_acl = simple_set_acl, #endif }; diff --git a/mm/slab_common.c b/mm/slab_common.c index 8e40321da091..1ec3c619ba04 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -233,14 +233,17 @@ out_unlock: mutex_unlock(&slab_mutex); put_online_cpus(); - /* - * There is no point in flooding logs with warnings or especially - * crashing the system if we fail to create a cache for a memcg. In - * this case we will be accounting the memcg allocation to the root - * cgroup until we succeed to create its own cache, but it isn't that - * critical. - */ - if (err && !memcg) { + if (err) { + /* + * There is no point in flooding logs with warnings or + * especially crashing the system if we fail to create a cache + * for a memcg. In this case we will be accounting the memcg + * allocation to the root cgroup until we succeed to create its + * own cache, but it isn't that critical. + */ + if (!memcg) + return NULL; + if (flags & SLAB_PANIC) panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n", name, err); diff --git a/mm/slub.c b/mm/slub.c index 34bb8c65a2d8..545a170ebf9f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1559,7 +1559,7 @@ static inline void *acquire_slab(struct kmem_cache *s, new.freelist = freelist; } - VM_BUG_ON_PAGE(new.frozen, &new); + VM_BUG_ON(new.frozen); new.frozen = 1; if (!__cmpxchg_double_slab(s, page, @@ -1812,7 +1812,7 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page, set_freepointer(s, freelist, prior); new.counters = counters; new.inuse--; - VM_BUG_ON_PAGE(!new.frozen, &new); + VM_BUG_ON(!new.frozen); } while (!__cmpxchg_double_slab(s, page, prior, counters, @@ -1840,7 +1840,7 @@ redo: old.freelist = page->freelist; old.counters = page->counters; - VM_BUG_ON_PAGE(!old.frozen, &old); + VM_BUG_ON(!old.frozen); /* Determine target state of the slab */ new.counters = old.counters; @@ -1952,7 +1952,7 @@ static void unfreeze_partials(struct kmem_cache *s, old.freelist = page->freelist; old.counters = page->counters; - VM_BUG_ON_PAGE(!old.frozen, &old); + VM_BUG_ON(!old.frozen); new.counters = old.counters; new.freelist = old.freelist; @@ -2225,7 +2225,7 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page) counters = page->counters; new.counters = counters; - VM_BUG_ON_PAGE(!new.frozen, &new); + VM_BUG_ON(!new.frozen); new.inuse = page->objects; new.frozen = freelist != NULL; @@ -2319,7 +2319,7 @@ load_freelist: * page is pointing to the page from which the objects are obtained. * That page must be frozen for per cpu allocations to work. */ - VM_BUG_ON_PAGE(!c->page->frozen, c->page); + VM_BUG_ON(!c->page->frozen); c->freelist = get_freepointer(s, freelist); c->tid = next_tid(c->tid); local_irq_restore(flags); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index e4f0db2a3eae..0fdf96803c5b 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -220,12 +220,12 @@ int is_vmalloc_or_module_addr(const void *x) } /* - * Walk a vmap address to the physical pfn it maps to. + * Walk a vmap address to the struct page it maps. */ -unsigned long vmalloc_to_pfn(const void *vmalloc_addr) +struct page *vmalloc_to_page(const void *vmalloc_addr) { unsigned long addr = (unsigned long) vmalloc_addr; - unsigned long pfn = 0; + struct page *page = NULL; pgd_t *pgd = pgd_offset_k(addr); /* @@ -244,23 +244,23 @@ unsigned long vmalloc_to_pfn(const void *vmalloc_addr) ptep = pte_offset_map(pmd, addr); pte = *ptep; if (pte_present(pte)) - pfn = pte_pfn(pte); + page = pte_page(pte); pte_unmap(ptep); } } } - return pfn; + return page; } -EXPORT_SYMBOL(vmalloc_to_pfn); +EXPORT_SYMBOL(vmalloc_to_page); /* - * Map a vmalloc()-space virtual address to the struct page. + * Map a vmalloc()-space virtual address to the physical page frame number. */ -struct page *vmalloc_to_page(const void *vmalloc_addr) +unsigned long vmalloc_to_pfn(const void *vmalloc_addr) { - return pfn_to_page(vmalloc_to_pfn(vmalloc_addr)); + return page_to_pfn(vmalloc_to_page(vmalloc_addr)); } -EXPORT_SYMBOL(vmalloc_to_page); +EXPORT_SYMBOL(vmalloc_to_pfn); /*** Global kva allocator ***/ diff --git a/mm/vmscan.c b/mm/vmscan.c index 90c4075d8d75..a9c74b409681 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -147,7 +147,7 @@ static bool global_reclaim(struct scan_control *sc) } #endif -unsigned long zone_reclaimable_pages(struct zone *zone) +static unsigned long zone_reclaimable_pages(struct zone *zone) { int nr; @@ -3315,27 +3315,6 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) wake_up_interruptible(&pgdat->kswapd_wait); } -/* - * The reclaimable count would be mostly accurate. - * The less reclaimable pages may be - * - mlocked pages, which will be moved to unevictable list when encountered - * - mapped pages, which may require several travels to be reclaimed - * - dirty pages, which is not "instantly" reclaimable - */ -unsigned long global_reclaimable_pages(void) -{ - int nr; - - nr = global_page_state(NR_ACTIVE_FILE) + - global_page_state(NR_INACTIVE_FILE); - - if (get_nr_swap_pages() > 0) - nr += global_page_state(NR_ACTIVE_ANON) + - global_page_state(NR_INACTIVE_ANON); - - return nr; -} - #ifdef CONFIG_HIBERNATION /* * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of diff --git a/net/ceph/buffer.c b/net/ceph/buffer.c index bf3e6a13c215..621b5f65407f 100644 --- a/net/ceph/buffer.c +++ b/net/ceph/buffer.c @@ -6,6 +6,7 @@ #include <linux/ceph/buffer.h> #include <linux/ceph/decode.h> +#include <linux/ceph/libceph.h> /* for ceph_kv{malloc,free} */ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) { @@ -15,16 +16,10 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) if (!b) return NULL; - b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN); - if (b->vec.iov_base) { - b->is_vmalloc = false; - } else { - b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL); - if (!b->vec.iov_base) { - kfree(b); - return NULL; - } - b->is_vmalloc = true; + b->vec.iov_base = ceph_kvmalloc(len, gfp); + if (!b->vec.iov_base) { + kfree(b); + return NULL; } kref_init(&b->kref); @@ -40,12 +35,7 @@ void ceph_buffer_release(struct kref *kref) struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref); dout("buffer_release %p\n", b); - if (b->vec.iov_base) { - if (b->is_vmalloc) - vfree(b->vec.iov_base); - else - kfree(b->vec.iov_base); - } + ceph_kvfree(b->vec.iov_base); kfree(b); } EXPORT_SYMBOL(ceph_buffer_release); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 34b11ee8124e..67d7721d237e 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/statfs.h> #include <linux/string.h> +#include <linux/vmalloc.h> #include <linux/nsproxy.h> #include <net/net_namespace.h> @@ -170,6 +171,25 @@ int ceph_compare_options(struct ceph_options *new_opt, } EXPORT_SYMBOL(ceph_compare_options); +void *ceph_kvmalloc(size_t size, gfp_t flags) +{ + if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { + void *ptr = kmalloc(size, flags | __GFP_NOWARN); + if (ptr) + return ptr; + } + + return __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL); +} + +void ceph_kvfree(const void *ptr) +{ + if (is_vmalloc_addr(ptr)) + vfree(ptr); + else + kfree(ptr); +} + static int parse_fsid(const char *str, struct ceph_fsid *fsid) { @@ -461,8 +481,8 @@ EXPORT_SYMBOL(ceph_client_id); * create a fresh client instance */ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, - unsigned int supported_features, - unsigned int required_features) + u64 supported_features, + u64 required_features) { struct ceph_client *client; struct ceph_entity_addr *myaddr = NULL; diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 089613234f03..16bc199d9a62 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -116,11 +116,14 @@ void crush_destroy(struct crush_map *map) if (map->rules) { __u32 b; for (b = 0; b < map->max_rules; b++) - kfree(map->rules[b]); + crush_destroy_rule(map->rules[b]); kfree(map->rules); } kfree(map); } - +void crush_destroy_rule(struct crush_rule *rule) +{ + kfree(rule); +} diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index cbd06a91941c..b703790b4e44 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -189,7 +189,7 @@ static int terminal(int x) static int bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r) { - int n, l; + int n; __u32 w; __u64 t; @@ -197,6 +197,7 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket, n = bucket->num_nodes >> 1; while (!terminal(n)) { + int l; /* pick point in [0, w) */ w = bucket->node_weights[n]; t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r, @@ -264,8 +265,12 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r) * true if device is marked "out" (failed, fully offloaded) * of the cluster */ -static int is_out(const struct crush_map *map, const __u32 *weight, int item, int x) +static int is_out(const struct crush_map *map, + const __u32 *weight, int weight_max, + int item, int x) { + if (item >= weight_max) + return 1; if (weight[item] >= 0x10000) return 0; if (weight[item] == 0) @@ -277,7 +282,7 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in } /** - * crush_choose - choose numrep distinct items of given type + * crush_choose_firstn - choose numrep distinct items of given type * @map: the crush_map * @bucket: the bucket we are choose an item from * @x: crush input value @@ -285,18 +290,24 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in * @type: the type of item to choose * @out: pointer to output vector * @outpos: our position in that vector - * @firstn: true if choosing "first n" items, false if choosing "indep" - * @recurse_to_leaf: true if we want one device under each item of given type - * @descend_once: true if we should only try one descent before giving up + * @tries: number of attempts to make + * @recurse_tries: number of attempts to have recursive chooseleaf make + * @local_tries: localized retries + * @local_fallback_tries: localized fallback retries + * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose) * @out2: second output vector for leaf items (if @recurse_to_leaf) */ -static int crush_choose(const struct crush_map *map, - struct crush_bucket *bucket, - const __u32 *weight, - int x, int numrep, int type, - int *out, int outpos, - int firstn, int recurse_to_leaf, - int descend_once, int *out2) +static int crush_choose_firstn(const struct crush_map *map, + struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int numrep, int type, + int *out, int outpos, + unsigned int tries, + unsigned int recurse_tries, + unsigned int local_tries, + unsigned int local_fallback_tries, + int recurse_to_leaf, + int *out2) { int rep; unsigned int ftotal, flocal; @@ -325,35 +336,17 @@ static int crush_choose(const struct crush_map *map, collide = 0; retry_bucket = 0; r = rep; - if (in->alg == CRUSH_BUCKET_UNIFORM) { - /* be careful */ - if (firstn || (__u32)numrep >= in->size) - /* r' = r + f_total */ - r += ftotal; - else if (in->size % numrep == 0) - /* r'=r+(n+1)*f_local */ - r += (numrep+1) * - (flocal+ftotal); - else - /* r' = r + n*f_local */ - r += numrep * (flocal+ftotal); - } else { - if (firstn) - /* r' = r + f_total */ - r += ftotal; - else - /* r' = r + n*f_local */ - r += numrep * (flocal+ftotal); - } + /* r' = r + f_total */ + r += ftotal; /* bucket choose */ if (in->size == 0) { reject = 1; goto reject; } - if (map->choose_local_fallback_tries > 0 && + if (local_fallback_tries > 0 && flocal >= (in->size>>1) && - flocal > map->choose_local_fallback_tries) + flocal > local_fallback_tries) item = bucket_perm_choose(in, x, r); else item = crush_bucket_choose(in, x, r); @@ -394,13 +387,15 @@ static int crush_choose(const struct crush_map *map, reject = 0; if (!collide && recurse_to_leaf) { if (item < 0) { - if (crush_choose(map, + if (crush_choose_firstn(map, map->buckets[-1-item], - weight, + weight, weight_max, x, outpos+1, 0, out2, outpos, - firstn, 0, - map->chooseleaf_descend_once, + recurse_tries, 0, + local_tries, + local_fallback_tries, + 0, NULL) <= outpos) /* didn't get leaf */ reject = 1; @@ -414,6 +409,7 @@ static int crush_choose(const struct crush_map *map, /* out? */ if (itemtype == 0) reject = is_out(map, weight, + weight_max, item, x); else reject = 0; @@ -424,17 +420,14 @@ reject: ftotal++; flocal++; - if (reject && descend_once) - /* let outer call try again */ - skip_rep = 1; - else if (collide && flocal <= map->choose_local_tries) + if (collide && flocal <= local_tries) /* retry locally a few times */ retry_bucket = 1; - else if (map->choose_local_fallback_tries > 0 && - flocal <= in->size + map->choose_local_fallback_tries) + else if (local_fallback_tries > 0 && + flocal <= in->size + local_fallback_tries) /* exhaustive bucket search */ retry_bucket = 1; - else if (ftotal <= map->choose_total_tries) + else if (ftotal <= tries) /* then retry descent */ retry_descent = 1; else @@ -464,21 +457,179 @@ reject: /** + * crush_choose_indep: alternative breadth-first positionally stable mapping + * + */ +static void crush_choose_indep(const struct crush_map *map, + struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int left, int numrep, int type, + int *out, int outpos, + unsigned int tries, + unsigned int recurse_tries, + int recurse_to_leaf, + int *out2, + int parent_r) +{ + struct crush_bucket *in = bucket; + int endpos = outpos + left; + int rep; + unsigned int ftotal; + int r; + int i; + int item = 0; + int itemtype; + int collide; + + dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", + bucket->id, x, outpos, numrep); + + /* initially my result is undefined */ + for (rep = outpos; rep < endpos; rep++) { + out[rep] = CRUSH_ITEM_UNDEF; + if (out2) + out2[rep] = CRUSH_ITEM_UNDEF; + } + + for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { + for (rep = outpos; rep < endpos; rep++) { + if (out[rep] != CRUSH_ITEM_UNDEF) + continue; + + in = bucket; /* initial bucket */ + + /* choose through intervening buckets */ + for (;;) { + /* note: we base the choice on the position + * even in the nested call. that means that + * if the first layer chooses the same bucket + * in a different position, we will tend to + * choose a different item in that bucket. + * this will involve more devices in data + * movement and tend to distribute the load. + */ + r = rep + parent_r; + + /* be careful */ + if (in->alg == CRUSH_BUCKET_UNIFORM && + in->size % numrep == 0) + /* r'=r+(n+1)*f_total */ + r += (numrep+1) * ftotal; + else + /* r' = r + n*f_total */ + r += numrep * ftotal; + + /* bucket choose */ + if (in->size == 0) { + dprintk(" empty bucket\n"); + break; + } + + item = crush_bucket_choose(in, x, r); + if (item >= map->max_devices) { + dprintk(" bad item %d\n", item); + out[rep] = CRUSH_ITEM_NONE; + if (out2) + out2[rep] = CRUSH_ITEM_NONE; + left--; + break; + } + + /* desired type? */ + if (item < 0) + itemtype = map->buckets[-1-item]->type; + else + itemtype = 0; + dprintk(" item %d type %d\n", item, itemtype); + + /* keep going? */ + if (itemtype != type) { + if (item >= 0 || + (-1-item) >= map->max_buckets) { + dprintk(" bad item type %d\n", type); + out[rep] = CRUSH_ITEM_NONE; + if (out2) + out2[rep] = + CRUSH_ITEM_NONE; + left--; + break; + } + in = map->buckets[-1-item]; + continue; + } + + /* collision? */ + collide = 0; + for (i = outpos; i < endpos; i++) { + if (out[i] == item) { + collide = 1; + break; + } + } + if (collide) + break; + + if (recurse_to_leaf) { + if (item < 0) { + crush_choose_indep(map, + map->buckets[-1-item], + weight, weight_max, + x, 1, numrep, 0, + out2, rep, + recurse_tries, 0, + 0, NULL, r); + if (out2[rep] == CRUSH_ITEM_NONE) { + /* placed nothing; no leaf */ + break; + } + } else { + /* we already have a leaf! */ + out2[rep] = item; + } + } + + /* out? */ + if (itemtype == 0 && + is_out(map, weight, weight_max, item, x)) + break; + + /* yay! */ + out[rep] = item; + left--; + break; + } + } + } + for (rep = outpos; rep < endpos; rep++) { + if (out[rep] == CRUSH_ITEM_UNDEF) { + out[rep] = CRUSH_ITEM_NONE; + } + if (out2 && out2[rep] == CRUSH_ITEM_UNDEF) { + out2[rep] = CRUSH_ITEM_NONE; + } + } +} + +/** * crush_do_rule - calculate a mapping with the given input and rule * @map: the crush_map * @ruleno: the rule id * @x: hash input * @result: pointer to result vector * @result_max: maximum result size + * @weight: weight vector (for map leaves) + * @weight_max: size of weight vector + * @scratch: scratch vector for private use; must be >= 3 * result_max */ int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, - const __u32 *weight) + const __u32 *weight, int weight_max, + int *scratch) { int result_len; - int a[CRUSH_MAX_SET]; - int b[CRUSH_MAX_SET]; - int c[CRUSH_MAX_SET]; + int *a = scratch; + int *b = scratch + result_max; + int *c = scratch + result_max*2; int recurse_to_leaf; int *w; int wsize = 0; @@ -489,8 +640,10 @@ int crush_do_rule(const struct crush_map *map, __u32 step; int i, j; int numrep; - int firstn; - const int descend_once = 0; + int choose_tries = map->choose_total_tries; + int choose_local_tries = map->choose_local_tries; + int choose_local_fallback_tries = map->choose_local_fallback_tries; + int choose_leaf_tries = 0; if ((__u32)ruleno >= map->max_rules) { dprintk(" bad ruleno %d\n", ruleno); @@ -503,29 +656,49 @@ int crush_do_rule(const struct crush_map *map, o = b; for (step = 0; step < rule->len; step++) { + int firstn = 0; struct crush_rule_step *curstep = &rule->steps[step]; - firstn = 0; switch (curstep->op) { case CRUSH_RULE_TAKE: w[0] = curstep->arg1; wsize = 1; break; - case CRUSH_RULE_CHOOSE_LEAF_FIRSTN: + case CRUSH_RULE_SET_CHOOSE_TRIES: + if (curstep->arg1 > 0) + choose_tries = curstep->arg1; + break; + + case CRUSH_RULE_SET_CHOOSELEAF_TRIES: + if (curstep->arg1 > 0) + choose_leaf_tries = curstep->arg1; + break; + + case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES: + if (curstep->arg1 > 0) + choose_local_tries = curstep->arg1; + break; + + case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES: + if (curstep->arg1 > 0) + choose_local_fallback_tries = curstep->arg1; + break; + + case CRUSH_RULE_CHOOSELEAF_FIRSTN: case CRUSH_RULE_CHOOSE_FIRSTN: firstn = 1; /* fall through */ - case CRUSH_RULE_CHOOSE_LEAF_INDEP: + case CRUSH_RULE_CHOOSELEAF_INDEP: case CRUSH_RULE_CHOOSE_INDEP: if (wsize == 0) break; recurse_to_leaf = curstep->op == - CRUSH_RULE_CHOOSE_LEAF_FIRSTN || + CRUSH_RULE_CHOOSELEAF_FIRSTN || curstep->op == - CRUSH_RULE_CHOOSE_LEAF_INDEP; + CRUSH_RULE_CHOOSELEAF_INDEP; /* reset output */ osize = 0; @@ -543,22 +716,51 @@ int crush_do_rule(const struct crush_map *map, continue; } j = 0; - osize += crush_choose(map, - map->buckets[-1-w[i]], - weight, - x, numrep, - curstep->arg2, - o+osize, j, - firstn, - recurse_to_leaf, - descend_once, c+osize); + if (firstn) { + int recurse_tries; + if (choose_leaf_tries) + recurse_tries = + choose_leaf_tries; + else if (map->chooseleaf_descend_once) + recurse_tries = 1; + else + recurse_tries = choose_tries; + osize += crush_choose_firstn( + map, + map->buckets[-1-w[i]], + weight, weight_max, + x, numrep, + curstep->arg2, + o+osize, j, + choose_tries, + recurse_tries, + choose_local_tries, + choose_local_fallback_tries, + recurse_to_leaf, + c+osize); + } else { + crush_choose_indep( + map, + map->buckets[-1-w[i]], + weight, weight_max, + x, numrep, numrep, + curstep->arg2, + o+osize, j, + choose_tries, + choose_leaf_tries ? + choose_leaf_tries : 1, + recurse_to_leaf, + c+osize, + 0); + osize += numrep; + } } if (recurse_to_leaf) /* copy final _leaf_ values to output set */ memcpy(o, c, osize*sizeof(*o)); - /* swap t and w arrays */ + /* swap o and w arrays */ tmp = o; o = w; w = tmp; diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 83661cdc0766..258a382e75ed 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -132,7 +132,8 @@ static int osdc_show(struct seq_file *s, void *pp) req->r_osd ? req->r_osd->o_osd : -1, req->r_pgid.pool, req->r_pgid.seed); - seq_printf(s, "%.*s", req->r_oid_len, req->r_oid); + seq_printf(s, "%.*s", req->r_base_oid.name_len, + req->r_base_oid.name); if (req->r_reassert_version.epoch) seq_printf(s, "\t%u'%llu", diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 4a5df7b1cc9f..2ed1304d22a7 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -15,6 +15,7 @@ #include <linux/dns_resolver.h> #include <net/tcp.h> +#include <linux/ceph/ceph_features.h> #include <linux/ceph/libceph.h> #include <linux/ceph/messenger.h> #include <linux/ceph/decode.h> @@ -1865,7 +1866,9 @@ int ceph_parse_ips(const char *c, const char *end, port = (port * 10) + (*p - '0'); p++; } - if (port > 65535 || port == 0) + if (port == 0) + port = CEPH_MON_PORT; + else if (port > 65535) goto bad; } else { port = CEPH_MON_PORT; @@ -1945,7 +1948,8 @@ static int process_connect(struct ceph_connection *con) { u64 sup_feat = con->msgr->supported_features; u64 req_feat = con->msgr->required_features; - u64 server_feat = le64_to_cpu(con->in_reply.features); + u64 server_feat = ceph_sanitize_features( + le64_to_cpu(con->in_reply.features)); int ret; dout("process_connect on %p tag %d\n", con, (int)con->in_tag); @@ -2853,8 +2857,8 @@ static void con_fault(struct ceph_connection *con) */ void ceph_messenger_init(struct ceph_messenger *msgr, struct ceph_entity_addr *myaddr, - u32 supported_features, - u32 required_features, + u64 supported_features, + u64 required_features, bool nocrc) { msgr->supported_features = supported_features; @@ -3126,15 +3130,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, INIT_LIST_HEAD(&m->data); /* front */ - m->front_max = front_len; if (front_len) { - if (front_len > PAGE_CACHE_SIZE) { - m->front.iov_base = __vmalloc(front_len, flags, - PAGE_KERNEL); - m->front_is_vmalloc = true; - } else { - m->front.iov_base = kmalloc(front_len, flags); - } + m->front.iov_base = ceph_kvmalloc(front_len, flags); if (m->front.iov_base == NULL) { dout("ceph_msg_new can't allocate %d bytes\n", front_len); @@ -3143,7 +3140,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags, } else { m->front.iov_base = NULL; } - m->front.iov_len = front_len; + m->front_alloc_len = m->front.iov_len = front_len; dout("ceph_msg_new %p front %d\n", m, front_len); return m; @@ -3256,10 +3253,7 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) void ceph_msg_kfree(struct ceph_msg *m) { dout("msg_kfree %p\n", m); - if (m->front_is_vmalloc) - vfree(m->front.iov_base); - else - kfree(m->front.iov_base); + ceph_kvfree(m->front.iov_base); kmem_cache_free(ceph_msg_cache, m); } @@ -3301,8 +3295,8 @@ EXPORT_SYMBOL(ceph_msg_last_put); void ceph_msg_dump(struct ceph_msg *msg) { - pr_debug("msg_dump %p (front_max %d length %zd)\n", msg, - msg->front_max, msg->data_length); + pr_debug("msg_dump %p (front_alloc_len %d length %zd)\n", msg, + msg->front_alloc_len, msg->data_length); print_hex_dump(KERN_DEBUG, "header: ", DUMP_PREFIX_OFFSET, 16, 1, &msg->hdr, sizeof(msg->hdr), true); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 1fe25cd29d0e..2ac9ef35110b 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -152,7 +152,7 @@ static int __open_session(struct ceph_mon_client *monc) /* initiatiate authentication handshake */ ret = ceph_auth_build_hello(monc->auth, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); __send_prepared_auth_request(monc, ret); } else { dout("open_session mon%d already open\n", monc->cur_mon); @@ -196,7 +196,7 @@ static void __send_subscribe(struct ceph_mon_client *monc) int num; p = msg->front.iov_base; - end = p + msg->front_max; + end = p + msg->front_alloc_len; num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap; ceph_encode_32(&p, num); @@ -897,7 +897,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc, ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base, msg->front.iov_len, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); if (ret < 0) { monc->client->auth_err = ret; wake_up_all(&monc->client->auth_wq); @@ -939,7 +939,7 @@ static int __validate_auth(struct ceph_mon_client *monc) return 0; ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base, - monc->m_auth->front_max); + monc->m_auth->front_alloc_len); if (ret <= 0) return ret; /* either an error, or no need to authenticate */ __send_prepared_auth_request(monc, ret); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 2b4b32aaa893..010ff3bd58ad 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -338,7 +338,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, msg_size = 4 + 4 + 8 + 8 + 4+8; msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */ msg_size += 1 + 8 + 4 + 4; /* pg_t */ - msg_size += 4 + MAX_OBJ_NAME_SIZE; + msg_size += 4 + CEPH_MAX_OID_NAME_LEN; /* oid */ msg_size += 2 + num_ops*sizeof(struct ceph_osd_op); msg_size += 8; /* snapid */ msg_size += 8; /* snap_seq */ @@ -368,6 +368,9 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, INIT_LIST_HEAD(&req->r_req_lru_item); INIT_LIST_HEAD(&req->r_osd_item); + req->r_base_oloc.pool = -1; + req->r_target_oloc.pool = -1; + /* create reply message */ if (use_mempool) msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0); @@ -761,11 +764,11 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, if (num_ops > 1) osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); - req->r_file_layout = *layout; /* keep a copy */ + req->r_base_oloc.pool = ceph_file_layout_pg_pool(*layout); - snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx", - vino.ino, objnum); - req->r_oid_len = strlen(req->r_oid); + snprintf(req->r_base_oid.name, sizeof(req->r_base_oid.name), + "%llx.%08llx", vino.ino, objnum); + req->r_base_oid.name_len = strlen(req->r_base_oid.name); return req; } @@ -1044,8 +1047,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) !ceph_con_opened(&osd->o_con)) { struct ceph_osd_request *req; - dout(" osd addr hasn't changed and connection never opened," - " letting msgr retry"); + dout("osd addr hasn't changed and connection never opened, " + "letting msgr retry\n"); /* touch each r_stamp for handle_timeout()'s benfit */ list_for_each_entry(req, &osd->o_requests, r_osd_item) req->r_stamp = jiffies; @@ -1232,6 +1235,61 @@ void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc, EXPORT_SYMBOL(ceph_osdc_set_request_linger); /* + * Returns whether a request should be blocked from being sent + * based on the current osdmap and osd_client settings. + * + * Caller should hold map_sem for read. + */ +static bool __req_should_be_paused(struct ceph_osd_client *osdc, + struct ceph_osd_request *req) +{ + bool pauserd = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD); + bool pausewr = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL); + return (req->r_flags & CEPH_OSD_FLAG_READ && pauserd) || + (req->r_flags & CEPH_OSD_FLAG_WRITE && pausewr); +} + +/* + * Calculate mapping of a request to a PG. Takes tiering into account. + */ +static int __calc_request_pg(struct ceph_osdmap *osdmap, + struct ceph_osd_request *req, + struct ceph_pg *pg_out) +{ + bool need_check_tiering; + + need_check_tiering = false; + if (req->r_target_oloc.pool == -1) { + req->r_target_oloc = req->r_base_oloc; /* struct */ + need_check_tiering = true; + } + if (req->r_target_oid.name_len == 0) { + ceph_oid_copy(&req->r_target_oid, &req->r_base_oid); + need_check_tiering = true; + } + + if (need_check_tiering && + (req->r_flags & CEPH_OSD_FLAG_IGNORE_OVERLAY) == 0) { + struct ceph_pg_pool_info *pi; + + pi = ceph_pg_pool_by_id(osdmap, req->r_target_oloc.pool); + if (pi) { + if ((req->r_flags & CEPH_OSD_FLAG_READ) && + pi->read_tier >= 0) + req->r_target_oloc.pool = pi->read_tier; + if ((req->r_flags & CEPH_OSD_FLAG_WRITE) && + pi->write_tier >= 0) + req->r_target_oloc.pool = pi->write_tier; + } + /* !pi is caught in ceph_oloc_oid_to_pg() */ + } + + return ceph_oloc_oid_to_pg(osdmap, &req->r_target_oloc, + &req->r_target_oid, pg_out); +} + +/* * Pick an osd (the first 'up' osd in the pg), allocate the osd struct * (as needed), and set the request r_osd appropriately. If there is * no up osd, set r_osd to NULL. Move the request to the appropriate list @@ -1248,10 +1306,11 @@ static int __map_request(struct ceph_osd_client *osdc, int acting[CEPH_PG_MAX_SIZE]; int o = -1, num = 0; int err; + bool was_paused; dout("map_request %p tid %lld\n", req, req->r_tid); - err = ceph_calc_ceph_pg(&pgid, req->r_oid, osdc->osdmap, - ceph_file_layout_pg_pool(req->r_file_layout)); + + err = __calc_request_pg(osdc->osdmap, req, &pgid); if (err) { list_move(&req->r_req_lru_item, &osdc->req_notarget); return err; @@ -1264,12 +1323,18 @@ static int __map_request(struct ceph_osd_client *osdc, num = err; } + was_paused = req->r_paused; + req->r_paused = __req_should_be_paused(osdc, req); + if (was_paused && !req->r_paused) + force_resend = 1; + if ((!force_resend && req->r_osd && req->r_osd->o_osd == o && req->r_sent >= req->r_osd->o_incarnation && req->r_num_pg_osds == num && memcmp(req->r_pg_osds, acting, sizeof(acting[0])*num) == 0) || - (req->r_osd == NULL && o == -1)) + (req->r_osd == NULL && o == -1) || + req->r_paused) return 0; /* no change */ dout("map_request tid %llu pgid %lld.%x osd%d (was osd%d)\n", @@ -1331,7 +1396,7 @@ static void __send_request(struct ceph_osd_client *osdc, /* fill in message content that changes each time we send it */ put_unaligned_le32(osdc->osdmap->epoch, req->r_request_osdmap_epoch); put_unaligned_le32(req->r_flags, req->r_request_flags); - put_unaligned_le64(req->r_pgid.pool, req->r_request_pool); + put_unaligned_le64(req->r_target_oloc.pool, req->r_request_pool); p = req->r_request_pgid; ceph_encode_64(&p, req->r_pgid.pool); ceph_encode_32(&p, req->r_pgid.seed); @@ -1432,6 +1497,109 @@ static void handle_osds_timeout(struct work_struct *work) round_jiffies_relative(delay)); } +static int ceph_oloc_decode(void **p, void *end, + struct ceph_object_locator *oloc) +{ + u8 struct_v, struct_cv; + u32 len; + void *struct_end; + int ret = 0; + + ceph_decode_need(p, end, 1 + 1 + 4, e_inval); + struct_v = ceph_decode_8(p); + struct_cv = ceph_decode_8(p); + if (struct_v < 3) { + pr_warn("got v %d < 3 cv %d of ceph_object_locator\n", + struct_v, struct_cv); + goto e_inval; + } + if (struct_cv > 6) { + pr_warn("got v %d cv %d > 6 of ceph_object_locator\n", + struct_v, struct_cv); + goto e_inval; + } + len = ceph_decode_32(p); + ceph_decode_need(p, end, len, e_inval); + struct_end = *p + len; + + oloc->pool = ceph_decode_64(p); + *p += 4; /* skip preferred */ + + len = ceph_decode_32(p); + if (len > 0) { + pr_warn("ceph_object_locator::key is set\n"); + goto e_inval; + } + + if (struct_v >= 5) { + len = ceph_decode_32(p); + if (len > 0) { + pr_warn("ceph_object_locator::nspace is set\n"); + goto e_inval; + } + } + + if (struct_v >= 6) { + s64 hash = ceph_decode_64(p); + if (hash != -1) { + pr_warn("ceph_object_locator::hash is set\n"); + goto e_inval; + } + } + + /* skip the rest */ + *p = struct_end; +out: + return ret; + +e_inval: + ret = -EINVAL; + goto out; +} + +static int ceph_redirect_decode(void **p, void *end, + struct ceph_request_redirect *redir) +{ + u8 struct_v, struct_cv; + u32 len; + void *struct_end; + int ret; + + ceph_decode_need(p, end, 1 + 1 + 4, e_inval); + struct_v = ceph_decode_8(p); + struct_cv = ceph_decode_8(p); + if (struct_cv > 1) { + pr_warn("got v %d cv %d > 1 of ceph_request_redirect\n", + struct_v, struct_cv); + goto e_inval; + } + len = ceph_decode_32(p); + ceph_decode_need(p, end, len, e_inval); + struct_end = *p + len; + + ret = ceph_oloc_decode(p, end, &redir->oloc); + if (ret) + goto out; + + len = ceph_decode_32(p); + if (len > 0) { + pr_warn("ceph_request_redirect::object_name is set\n"); + goto e_inval; + } + + len = ceph_decode_32(p); + *p += len; /* skip osd_instructions */ + + /* skip the rest */ + *p = struct_end; +out: + return ret; + +e_inval: + ret = -EINVAL; + goto out; +} + static void complete_request(struct ceph_osd_request *req) { complete_all(&req->r_safe_completion); /* fsync waiter */ @@ -1446,6 +1614,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, { void *p, *end; struct ceph_osd_request *req; + struct ceph_request_redirect redir; u64 tid; int object_len; unsigned int numops; @@ -1525,10 +1694,41 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, for (i = 0; i < numops; i++) req->r_reply_op_result[i] = ceph_decode_32(&p); - already_completed = req->r_got_reply; + if (le16_to_cpu(msg->hdr.version) >= 6) { + p += 8 + 4; /* skip replay_version */ + p += 8; /* skip user_version */ - if (!req->r_got_reply) { + err = ceph_redirect_decode(&p, end, &redir); + if (err) + goto bad_put; + } else { + redir.oloc.pool = -1; + } + + if (redir.oloc.pool != -1) { + dout("redirect pool %lld\n", redir.oloc.pool); + + __unregister_request(osdc, req); + mutex_unlock(&osdc->request_mutex); + + req->r_target_oloc = redir.oloc; /* struct */ + + /* + * Start redirect requests with nofail=true. If + * mapping fails, request will end up on the notarget + * list, waiting for the new osdmap (which can take + * a while), even though the original request mapped + * successfully. In the future we might want to follow + * original request's nofail setting here. + */ + err = ceph_osdc_start_request(osdc, req, true); + BUG_ON(err); + goto done; + } + + already_completed = req->r_got_reply; + if (!req->r_got_reply) { req->r_result = result; dout("handle_reply result %d bytes %d\n", req->r_result, bytes); @@ -1581,6 +1781,13 @@ done: return; bad_put: + req->r_result = -EIO; + __unregister_request(osdc, req); + if (req->r_callback) + req->r_callback(req, msg); + else + complete_all(&req->r_completion); + complete_request(req); ceph_osdc_put_request(req); bad_mutex: mutex_unlock(&osdc->request_mutex); @@ -1613,14 +1820,17 @@ static void reset_changed_osds(struct ceph_osd_client *osdc) * * Caller should hold map_sem for read. */ -static void kick_requests(struct ceph_osd_client *osdc, int force_resend) +static void kick_requests(struct ceph_osd_client *osdc, bool force_resend, + bool force_resend_writes) { struct ceph_osd_request *req, *nreq; struct rb_node *p; int needmap = 0; int err; + bool force_resend_req; - dout("kick_requests %s\n", force_resend ? " (force resend)" : ""); + dout("kick_requests %s %s\n", force_resend ? " (force resend)" : "", + force_resend_writes ? " (force resend writes)" : ""); mutex_lock(&osdc->request_mutex); for (p = rb_first(&osdc->requests); p; ) { req = rb_entry(p, struct ceph_osd_request, r_node); @@ -1645,7 +1855,10 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) continue; } - err = __map_request(osdc, req, force_resend); + force_resend_req = force_resend || + (force_resend_writes && + req->r_flags & CEPH_OSD_FLAG_WRITE); + err = __map_request(osdc, req, force_resend_req); if (err < 0) continue; /* error */ if (req->r_osd == NULL) { @@ -1665,7 +1878,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend) r_linger_item) { dout("linger req=%p req->r_osd=%p\n", req, req->r_osd); - err = __map_request(osdc, req, force_resend); + err = __map_request(osdc, req, + force_resend || force_resend_writes); dout("__map_request returned %d\n", err); if (err == 0) continue; /* no change and no osd was specified */ @@ -1707,6 +1921,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) struct ceph_osdmap *newmap = NULL, *oldmap; int err; struct ceph_fsid fsid; + bool was_full; dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0); p = msg->front.iov_base; @@ -1720,6 +1935,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) down_write(&osdc->map_sem); + was_full = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL); + /* incremental maps */ ceph_decode_32_safe(&p, end, nr_maps, bad); dout(" %d inc maps\n", nr_maps); @@ -1744,7 +1961,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) ceph_osdmap_destroy(osdc->osdmap); osdc->osdmap = newmap; } - kick_requests(osdc, 0); + was_full = was_full || + ceph_osdmap_flag(osdc->osdmap, + CEPH_OSDMAP_FULL); + kick_requests(osdc, 0, was_full); } else { dout("ignoring incremental map %u len %d\n", epoch, maplen); @@ -1787,7 +2007,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg) skipped_map = 1; ceph_osdmap_destroy(oldmap); } - kick_requests(osdc, skipped_map); + was_full = was_full || + ceph_osdmap_flag(osdc->osdmap, + CEPH_OSDMAP_FULL); + kick_requests(osdc, skipped_map, was_full); } p += maplen; nr_maps--; @@ -1804,7 +2027,9 @@ done: * we find out when we are no longer full and stop returning * ENOSPC. */ - if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) + if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR)) ceph_monc_request_next_osdmap(&osdc->client->monc); mutex_lock(&osdc->request_mutex); @@ -2068,10 +2293,11 @@ void ceph_osdc_build_request(struct ceph_osd_request *req, u64 off, ceph_encode_32(&p, -1); /* preferred */ /* oid */ - ceph_encode_32(&p, req->r_oid_len); - memcpy(p, req->r_oid, req->r_oid_len); - dout("oid '%.*s' len %d\n", req->r_oid_len, req->r_oid, req->r_oid_len); - p += req->r_oid_len; + ceph_encode_32(&p, req->r_base_oid.name_len); + memcpy(p, req->r_base_oid.name, req->r_base_oid.name_len); + dout("oid '%.*s' len %d\n", req->r_base_oid.name_len, + req->r_base_oid.name, req->r_base_oid.name_len); + p += req->r_base_oid.name_len; /* ops--can imply data */ ceph_encode_16(&p, (u16)req->r_num_ops); @@ -2454,7 +2680,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, struct ceph_osd_client *osdc = osd->o_osdc; struct ceph_msg *m; struct ceph_osd_request *req; - int front = le32_to_cpu(hdr->front_len); + int front_len = le32_to_cpu(hdr->front_len); int data_len = le32_to_cpu(hdr->data_len); u64 tid; @@ -2474,12 +2700,13 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, req->r_reply, req->r_reply->con); ceph_msg_revoke_incoming(req->r_reply); - if (front > req->r_reply->front.iov_len) { + if (front_len > req->r_reply->front_alloc_len) { pr_warning("get_reply front %d > preallocated %d (%u#%llu)\n", - front, (int)req->r_reply->front.iov_len, + front_len, req->r_reply->front_alloc_len, (unsigned int)con->peer_name.type, le64_to_cpu(con->peer_name.num)); - m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, GFP_NOFS, false); + m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS, + false); if (!m) goto out; ceph_msg_put(req->r_reply); diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index dbd9a4792427..aade4a5c1c07 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -464,6 +464,11 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, u64 id) return NULL; } +struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map, u64 id) +{ + return __lookup_pg_pool(&map->pg_pools, id); +} + const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) { struct ceph_pg_pool_info *pi; @@ -514,8 +519,8 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) pr_warning("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv); return -EINVAL; } - if (cv > 7) { - pr_warning("got v %d cv %d > 7 of ceph_pg_pool\n", ev, cv); + if (cv > 9) { + pr_warning("got v %d cv %d > 9 of ceph_pg_pool\n", ev, cv); return -EINVAL; } len = ceph_decode_32(p); @@ -543,12 +548,34 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) *p += len; } - /* skip removed snaps */ + /* skip removed_snaps */ num = ceph_decode_32(p); *p += num * (8 + 8); *p += 8; /* skip auid */ pi->flags = ceph_decode_64(p); + *p += 4; /* skip crash_replay_interval */ + + if (ev >= 7) + *p += 1; /* skip min_size */ + + if (ev >= 8) + *p += 8 + 8; /* skip quota_max_* */ + + if (ev >= 9) { + /* skip tiers */ + num = ceph_decode_32(p); + *p += num * 8; + + *p += 8; /* skip tier_of */ + *p += 1; /* skip cache_mode */ + + pi->read_tier = ceph_decode_64(p); + pi->write_tier = ceph_decode_64(p); + } else { + pi->read_tier = -1; + pi->write_tier = -1; + } /* ignore the rest */ @@ -1090,25 +1117,40 @@ invalid: EXPORT_SYMBOL(ceph_calc_file_object_mapping); /* - * calculate an object layout (i.e. pgid) from an oid, - * file_layout, and osdmap + * Calculate mapping of a (oloc, oid) pair to a PG. Should only be + * called with target's (oloc, oid), since tiering isn't taken into + * account. */ -int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid, - struct ceph_osdmap *osdmap, uint64_t pool) +int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap, + struct ceph_object_locator *oloc, + struct ceph_object_id *oid, + struct ceph_pg *pg_out) { - struct ceph_pg_pool_info *pool_info; + struct ceph_pg_pool_info *pi; - BUG_ON(!osdmap); - pool_info = __lookup_pg_pool(&osdmap->pg_pools, pool); - if (!pool_info) + pi = __lookup_pg_pool(&osdmap->pg_pools, oloc->pool); + if (!pi) return -EIO; - pg->pool = pool; - pg->seed = ceph_str_hash(pool_info->object_hash, oid, strlen(oid)); - dout("%s '%s' pgid %lld.%x\n", __func__, oid, pg->pool, pg->seed); + pg_out->pool = oloc->pool; + pg_out->seed = ceph_str_hash(pi->object_hash, oid->name, + oid->name_len); + + dout("%s '%.*s' pgid %llu.%x\n", __func__, oid->name_len, oid->name, + pg_out->pool, pg_out->seed); return 0; } -EXPORT_SYMBOL(ceph_calc_ceph_pg); +EXPORT_SYMBOL(ceph_oloc_oid_to_pg); + +static int crush_do_rule_ary(const struct crush_map *map, int ruleno, int x, + int *result, int result_max, + const __u32 *weight, int weight_max) +{ + int scratch[result_max * 3]; + + return crush_do_rule(map, ruleno, x, result, result_max, + weight, weight_max, scratch); +} /* * Calculate raw osd vector for the given pgid. Return pointer to osd @@ -1163,9 +1205,9 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid, pool->pgp_num_mask) + (unsigned)pgid.pool; } - r = crush_do_rule(osdmap->crush, ruleno, pps, osds, - min_t(int, pool->size, *num), - osdmap->osd_weight); + r = crush_do_rule_ary(osdmap->crush, ruleno, pps, + osds, min_t(int, pool->size, *num), + osdmap->osd_weight, osdmap->max_osd); if (r < 0) { pr_err("error %d from crush rule: pool %lld ruleset %d type %d" " size %d\n", r, pgid.pool, pool->crush_ruleset, diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 42fdfc634e56..0a2aee060f9f 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -536,8 +536,7 @@ static void warn_gssd(void) unsigned long now = jiffies; if (time_after(now, ratelimit)) { - printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" - "Please check user daemon is running.\n"); + pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n"); ratelimit = now + 15*HZ; } } @@ -600,7 +599,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) struct rpc_pipe *pipe; struct rpc_cred *cred = &gss_cred->gc_base; struct gss_upcall_msg *gss_msg; - unsigned long timeout; DEFINE_WAIT(wait); int err; @@ -608,17 +606,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) __func__, from_kuid(&init_user_ns, cred->cr_uid)); retry: err = 0; - /* Default timeout is 15s unless we know that gssd is not running */ - timeout = 15 * HZ; - if (!sn->gssd_running) - timeout = HZ >> 2; + /* if gssd is down, just skip upcalling altogether */ + if (!gssd_running(net)) { + warn_gssd(); + return -EACCES; + } gss_msg = gss_setup_upcall(gss_auth, cred); if (PTR_ERR(gss_msg) == -EAGAIN) { err = wait_event_interruptible_timeout(pipe_version_waitqueue, - sn->pipe_version >= 0, timeout); + sn->pipe_version >= 0, 15 * HZ); if (sn->pipe_version < 0) { - if (err == 0) - sn->gssd_running = 0; warn_gssd(); err = -EACCES; } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f09b7db2c492..0edada973434 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1529,9 +1529,13 @@ call_refreshresult(struct rpc_task *task) task->tk_action = call_refresh; switch (status) { case 0: - if (rpcauth_uptodatecred(task)) + if (rpcauth_uptodatecred(task)) { task->tk_action = call_allocate; - return; + return; + } + /* Use rate-limiting and a max number of retries if refresh + * had status 0 but failed to update the cred. + */ case -ETIMEDOUT: rpc_delay(task, 3*HZ); case -EAGAIN: @@ -1729,6 +1733,7 @@ call_bind_status(struct rpc_task *task) return; case -ECONNREFUSED: /* connection problems */ case -ECONNRESET: + case -ECONNABORTED: case -ENOTCONN: case -EHOSTDOWN: case -EHOSTUNREACH: @@ -1799,7 +1804,9 @@ call_connect_status(struct rpc_task *task) return; case -ECONNREFUSED: case -ECONNRESET: + case -ECONNABORTED: case -ENETUNREACH: + case -EHOSTUNREACH: /* retry with existing socket, after a delay */ rpc_delay(task, 3*HZ); if (RPC_IS_SOFTCONN(task)) @@ -1902,6 +1909,7 @@ call_transmit_status(struct rpc_task *task) break; } case -ECONNRESET: + case -ECONNABORTED: case -ENOTCONN: case -EPIPE: rpc_task_force_reencode(task); @@ -2011,8 +2019,9 @@ call_status(struct rpc_task *task) xprt_conditional_disconnect(req->rq_xprt, req->rq_connect_cookie); break; - case -ECONNRESET: case -ECONNREFUSED: + case -ECONNRESET: + case -ECONNABORTED: rpc_force_rebind(clnt); rpc_delay(task, 3*HZ); case -EPIPE: diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 779742cfc1ff..94e506f9d72b 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -14,6 +14,7 @@ struct sunrpc_net { struct cache_detail *rsi_cache; struct super_block *pipefs_sb; + struct rpc_pipe *gssd_dummy; struct mutex pipefs_sb_lock; struct list_head all_clients; @@ -32,8 +33,6 @@ struct sunrpc_net { int pipe_version; atomic_t pipe_users; struct proc_dir_entry *use_gssp_proc; - - unsigned int gssd_running; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index bf04b30a788a..b18554898562 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -17,6 +17,7 @@ #include <linux/fsnotify.h> #include <linux/kernel.h> #include <linux/rcupdate.h> +#include <linux/utsname.h> #include <asm/ioctls.h> #include <linux/poll.h> @@ -38,7 +39,7 @@ #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") static struct file_system_type rpc_pipe_fs_type; - +static const struct rpc_pipe_ops gssd_dummy_pipe_ops; static struct kmem_cache *rpc_inode_cachep __read_mostly; @@ -216,14 +217,11 @@ rpc_destroy_inode(struct inode *inode) static int rpc_pipe_open(struct inode *inode, struct file *filp) { - struct net *net = inode->i_sb->s_fs_info; - struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct rpc_pipe *pipe; int first_open; int res = -ENXIO; mutex_lock(&inode->i_mutex); - sn->gssd_running = 1; pipe = RPC_I(inode)->pipe; if (pipe == NULL) goto out; @@ -1159,6 +1157,7 @@ enum { RPCAUTH_nfsd4_cb, RPCAUTH_cache, RPCAUTH_nfsd, + RPCAUTH_gssd, RPCAUTH_RootEOF }; @@ -1195,6 +1194,10 @@ static const struct rpc_filelist files[] = { .name = "nfsd", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_gssd] = { + .name = "gssd", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, }; /* @@ -1208,13 +1211,24 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb, } EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); -void rpc_pipefs_init_net(struct net *net) +int rpc_pipefs_init_net(struct net *net) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); + if (IS_ERR(sn->gssd_dummy)) + return PTR_ERR(sn->gssd_dummy); + mutex_init(&sn->pipefs_sb_lock); - sn->gssd_running = 1; sn->pipe_version = -1; + return 0; +} + +void rpc_pipefs_exit_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + rpc_destroy_pipe_data(sn->gssd_dummy); } /* @@ -1244,11 +1258,134 @@ void rpc_put_sb_net(const struct net *net) } EXPORT_SYMBOL_GPL(rpc_put_sb_net); +static const struct rpc_filelist gssd_dummy_clnt_dir[] = { + [0] = { + .name = "clntXX", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, +}; + +static ssize_t +dummy_downcall(struct file *filp, const char __user *src, size_t len) +{ + return -EINVAL; +} + +static const struct rpc_pipe_ops gssd_dummy_pipe_ops = { + .upcall = rpc_pipe_generic_upcall, + .downcall = dummy_downcall, +}; + +/* + * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect + * that it will ever use this info to handle an upcall, but rpc.gssd expects + * that this file will be there and have a certain format. + */ +static int +rpc_show_dummy_info(struct seq_file *m, void *v) +{ + seq_printf(m, "RPC server: %s\n", utsname()->nodename); + seq_printf(m, "service: foo (1) version 0\n"); + seq_printf(m, "address: 127.0.0.1\n"); + seq_printf(m, "protocol: tcp\n"); + seq_printf(m, "port: 0\n"); + return 0; +} + +static int +rpc_dummy_info_open(struct inode *inode, struct file *file) +{ + return single_open(file, rpc_show_dummy_info, NULL); +} + +static const struct file_operations rpc_dummy_info_operations = { + .owner = THIS_MODULE, + .open = rpc_dummy_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct rpc_filelist gssd_dummy_info_file[] = { + [0] = { + .name = "info", + .i_fop = &rpc_dummy_info_operations, + .mode = S_IFREG | S_IRUSR, + }, +}; + +/** + * rpc_gssd_dummy_populate - create a dummy gssd pipe + * @root: root of the rpc_pipefs filesystem + * @pipe_data: pipe data created when netns is initialized + * + * Create a dummy set of directories and a pipe that gssd can hold open to + * indicate that it is up and running. + */ +static struct dentry * +rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data) +{ + int ret = 0; + struct dentry *gssd_dentry; + struct dentry *clnt_dentry = NULL; + struct dentry *pipe_dentry = NULL; + struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name, + strlen(files[RPCAUTH_gssd].name)); + + /* We should never get this far if "gssd" doesn't exist */ + gssd_dentry = d_hash_and_lookup(root, &q); + if (!gssd_dentry) + return ERR_PTR(-ENOENT); + + ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL); + if (ret) { + pipe_dentry = ERR_PTR(ret); + goto out; + } + + q.name = gssd_dummy_clnt_dir[0].name; + q.len = strlen(gssd_dummy_clnt_dir[0].name); + clnt_dentry = d_hash_and_lookup(gssd_dentry, &q); + if (!clnt_dentry) { + pipe_dentry = ERR_PTR(-ENOENT); + goto out; + } + + ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL); + if (ret) { + __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); + pipe_dentry = ERR_PTR(ret); + goto out; + } + + pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data); + if (IS_ERR(pipe_dentry)) { + __rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1); + __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); + } +out: + dput(clnt_dentry); + dput(gssd_dentry); + return pipe_dentry; +} + +static void +rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) +{ + struct dentry *clnt_dir = pipe_dentry->d_parent; + struct dentry *gssd_dir = clnt_dir->d_parent; + + __rpc_rmpipe(clnt_dir->d_inode, pipe_dentry); + __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); + __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); + dput(pipe_dentry); +} + static int rpc_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; - struct dentry *root; + struct dentry *root, *gssd_dentry; struct net *net = data; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); int err; @@ -1266,6 +1403,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; + + gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy); + if (IS_ERR(gssd_dentry)) { + __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); + return PTR_ERR(gssd_dentry); + } + dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net, NET_NAME(net)); mutex_lock(&sn->pipefs_sb_lock); @@ -1280,6 +1424,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) return 0; err_depopulate: + rpc_gssd_dummy_depopulate(gssd_dentry); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, sb); @@ -1289,6 +1434,16 @@ err_depopulate: return err; } +bool +gssd_running(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct rpc_pipe *pipe = sn->gssd_dummy; + + return pipe->nreaders || pipe->nwriters; +} +EXPORT_SYMBOL_GPL(gssd_running); + static struct dentry * rpc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 3d6498af9adc..cd30120de9e4 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net) if (err) goto err_unixgid; - rpc_pipefs_init_net(net); + err = rpc_pipefs_init_net(net); + if (err) + goto err_pipefs; + INIT_LIST_HEAD(&sn->all_clients); spin_lock_init(&sn->rpc_client_lock); spin_lock_init(&sn->rpcb_clnt_lock); return 0; +err_pipefs: + unix_gid_cache_destroy(net); err_unixgid: ip_map_cache_destroy(net); err_ipmap: @@ -60,6 +65,7 @@ err_proc: static __net_exit void sunrpc_exit_net(struct net *net) { + rpc_pipefs_exit_net(net); unix_gid_cache_destroy(net); ip_map_cache_destroy(net); rpc_proc_exit(net); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1750048130a7..7d4df99f761f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -749,6 +749,11 @@ static void xprt_connect_status(struct rpc_task *task) } switch (task->tk_status) { + case -ECONNREFUSED: + case -ECONNRESET: + case -ECONNABORTED: + case -ENETUNREACH: + case -EHOSTUNREACH: case -EAGAIN: dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); break; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 75b045e1cd50..2a7ca8ffe83a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -257,6 +257,7 @@ struct sock_xprt { void (*old_data_ready)(struct sock *, int); void (*old_state_change)(struct sock *); void (*old_write_space)(struct sock *); + void (*old_error_report)(struct sock *); }; /* @@ -274,6 +275,11 @@ struct sock_xprt { */ #define TCP_RPC_REPLY (1UL << 6) +static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) +{ + return (struct rpc_xprt *) sk->sk_user_data; +} + static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) { return (struct sockaddr *) &xprt->addr; @@ -799,6 +805,7 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) transport->old_data_ready = sk->sk_data_ready; transport->old_state_change = sk->sk_state_change; transport->old_write_space = sk->sk_write_space; + transport->old_error_report = sk->sk_error_report; } static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) @@ -806,6 +813,34 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s sk->sk_data_ready = transport->old_data_ready; sk->sk_state_change = transport->old_state_change; sk->sk_write_space = transport->old_write_space; + sk->sk_error_report = transport->old_error_report; +} + +/** + * xs_error_report - callback to handle TCP socket state errors + * @sk: socket + * + * Note: we don't call sock_error() since there may be a rpc_task + * using the socket, and so we don't want to clear sk->sk_err. + */ +static void xs_error_report(struct sock *sk) +{ + struct rpc_xprt *xprt; + int err; + + read_lock_bh(&sk->sk_callback_lock); + if (!(xprt = xprt_from_sock(sk))) + goto out; + + err = -sk->sk_err; + if (err == 0) + goto out; + dprintk("RPC: xs_error_report client %p, error=%d...\n", + xprt, -err); + trace_rpc_socket_error(xprt, sk->sk_socket, err); + xprt_wake_pending_tasks(xprt, err); + out: + read_unlock_bh(&sk->sk_callback_lock); } static void xs_reset_transport(struct sock_xprt *transport) @@ -885,11 +920,6 @@ static void xs_destroy(struct rpc_xprt *xprt) module_put(THIS_MODULE); } -static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) -{ - return (struct rpc_xprt *) sk->sk_user_data; -} - static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) { struct xdr_skb_reader desc = { @@ -1869,6 +1899,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, sk->sk_user_data = xprt; sk->sk_data_ready = xs_local_data_ready; sk->sk_write_space = xs_udp_write_space; + sk->sk_error_report = xs_error_report; sk->sk_allocation = GFP_ATOMIC; xprt_clear_connected(xprt); @@ -2146,6 +2177,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) sk->sk_data_ready = xs_tcp_data_ready; sk->sk_state_change = xs_tcp_state_change; sk->sk_write_space = xs_tcp_write_space; + sk->sk_error_report = xs_error_report; sk->sk_allocation = GFP_ATOMIC; /* socket options */ diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1dbd6d1cd1b5..0ea2a1e24ade 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2665,6 +2665,15 @@ sub process { $herecurr); } +# check for function declarations without arguments like "int foo()" + if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { + if (ERROR("FUNCTION_WITHOUT_ARGS", + "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; + } + } + # check for uses of DEFINE_PCI_DEVICE_TABLE if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) { if (WARN("DEFINE_PCI_DEVICE_TABLE", diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 17855761e6b7..40610984a1b5 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -584,12 +584,16 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || - strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0) + strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || + strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || + strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) return 1; if (info->hdr->e_machine == EM_PPC64) /* Special register function linked on all modules during final link of .ko */ if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || - strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0) + strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || + strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || + strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) return 1; /* Do not ignore this symbol */ return 0; |