diff options
257 files changed, 4402 insertions, 1003 deletions
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards new file mode 100644 index 00000000000..91f26148af7 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -0,0 +1,20 @@ +ARM Versatile Application and Platform Baseboards +------------------------------------------------- +ARM's development hardware platform with connectors for customizable +core tiles. The hardware configuration of the Versatile boards is +highly customizable. + +Required properties (in root node): + compatible = "arm,versatile-ab"; /* Application baseboard */ + compatible = "arm,versatile-pb"; /* Platform baseboard */ + +Interrupt controllers: +- VIC required properties: + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + +- SIC required properties: + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; diff --git a/Documentation/devicetree/bindings/arm/freescale.txt b/Documentation/devicetree/bindings/arm/freescale.txt new file mode 100644 index 00000000000..8c52102b225 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale.txt @@ -0,0 +1,7 @@ +mx51 "Babbage" evalutation board +Required root node properties: + - compatible = "fsl,mx51-babbage", "fsl,mx51"; + +mx53 "Loco" evaluation board +Required root node properties: + - compatible = "fsl,mx53-loco", "fsl,mx53"; diff --git a/Documentation/devicetree/bindings/arm/genesi.txt b/Documentation/devicetree/bindings/arm/genesi.txt new file mode 100644 index 00000000000..b353489acd4 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/genesi.txt @@ -0,0 +1,8 @@ +Genesi EfikaMX based on Freescale mx51 +Required root node properties: + - compatible = "genesi,efikamx", "fsl,mx51"; + +Genesi EfikaMX Smartbook based on Freescale mx51 +Required root node properties: + - compatible = "genesi,efikasb", "fsl,mx51"; + diff --git a/Documentation/devicetree/bindings/arm/primecell.txt b/Documentation/devicetree/bindings/arm/primecell.txt new file mode 100644 index 00000000000..951ca46789d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/primecell.txt @@ -0,0 +1,23 @@ +* ARM Primecell Peripherals + +ARM, Ltd. Primecell peripherals have a standard id register that can be used to +identify the peripheral type, vendor, and revision. This value can be used for +driver matching. + +Required properties: + +- compatible : should be a specific name for the peripheral and + "arm,primecell". The specific name will match the ARM + engineering name for the logic block in the form: "arm,pl???" + +Optional properties: + +- arm,primecell-periphid : Value to override the h/w value with + +Example: + +serial@fff36000 { + compatible = "arm,pl011", "arm,primecell"; + arm,primecell-periphid = <0x00341011>; +}; + diff --git a/Documentation/devicetree/bindings/arm/samsung.txt b/Documentation/devicetree/bindings/arm/samsung.txt new file mode 100644 index 00000000000..594cb97e3d8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/samsung.txt @@ -0,0 +1,9 @@ +Samsung Exynos4 S5PV310 SoC based SMDKV310 eval board + + SMDKV310 eval board is based on S5PV310 SoC which belongs to + Samsung's Exynos4 family of application processors. + +Required root node properties: + - compatible = "samsung,smdkv310","samsung,s5pv310" + (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board. + (b) "samsung,s5pv310" - for boards based on S5PV310 SoC. diff --git a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt index 2b6f2d45c45..38988ef1336 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt @@ -1,4 +1,4 @@ -Freescale SoC SEC Security Engines +Freescale SoC SEC Security Engines versions 2.x-3.x Required properties: diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index edaa84d288a..4e16ba4feab 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -4,17 +4,45 @@ Specifying GPIO information for devices 1) gpios property ----------------- -Nodes that makes use of GPIOs should define them using `gpios' property, -format of which is: <&gpio-controller1-phandle gpio1-specifier - &gpio-controller2-phandle gpio2-specifier - 0 /* holes are permitted, means no GPIO 3 */ - &gpio-controller4-phandle gpio4-specifier - ...>; +Nodes that makes use of GPIOs should specify them using one or more +properties, each containing a 'gpio-list': -Note that gpio-specifier length is controller dependent. + gpio-list ::= <single-gpio> [gpio-list] + single-gpio ::= <gpio-phandle> <gpio-specifier> + gpio-phandle : phandle to gpio controller node + gpio-specifier : Array of #gpio-cells specifying specific gpio + (controller specific) + +GPIO properties should be named "[<name>-]gpios". Exact +meaning of each gpios property must be documented in the device tree +binding for each device. + +For example, the following could be used to describe gpios pins to use +as chip select lines; with chip selects 0, 1 and 3 populated, and chip +select 2 left empty: + + gpio1: gpio1 { + gpio-controller + #gpio-cells = <2>; + }; + gpio2: gpio2 { + gpio-controller + #gpio-cells = <1>; + }; + [...] + chipsel-gpios = <&gpio1 12 0>, + <&gpio1 13 0>, + <0>, /* holes are permitted, means no GPIO 2 */ + <&gpio2 2>; + +Note that gpio-specifier length is controller dependent. In the +above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 +only uses one. gpio-specifier may encode: bank, pin position inside the bank, whether pin is open-drain and whether pin is logically inverted. +Exact meaning of each specifier cell is controller specific, and must +be documented in the device tree binding for the device. Example of the node using GPIOs: @@ -28,8 +56,8 @@ and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller. 2) gpio-controller nodes ------------------------ -Every GPIO controller node must have #gpio-cells property defined, -this information will be used to translate gpio-specifiers. +Every GPIO controller node must both an empty "gpio-controller" +property, and have #gpio-cells contain the size of the gpio-specifier. Example of two SOC GPIO banks defined as gpio-controller nodes: diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt new file mode 100644 index 00000000000..64aac39e6ed --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -0,0 +1,7 @@ +NVIDIA Tegra 2 GPIO controller + +Required properties: +- compatible : "nvidia,tegra20-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller : Marks the device node as a GPIO controller. diff --git a/Documentation/devicetree/bindings/i2c/arm-versatile.txt b/Documentation/devicetree/bindings/i2c/arm-versatile.txt new file mode 100644 index 00000000000..361d31c51b6 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/arm-versatile.txt @@ -0,0 +1,10 @@ +i2c Controller on ARM Versatile platform: + +Required properties: +- compatible : Must be "arm,versatile-i2c"; +- reg +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding diff --git a/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/Documentation/devicetree/bindings/mtd/arm-versatile.txt new file mode 100644 index 00000000000..476845db94d --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/arm-versatile.txt @@ -0,0 +1,8 @@ +Flash device on ARM Versatile board + +Required properties: +- compatible : must be "arm,versatile-flash"; +- bank-width : width in bytes of flash interface. + +Optional properties: +- Subnode partition map from mtd flash binding diff --git a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt new file mode 100644 index 00000000000..953049b4248 --- /dev/null +++ b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt @@ -0,0 +1,10 @@ +SMSC LAN91c111 Ethernet mac + +Required properties: +- compatible = "smsc,lan91c111"; +- reg : physical address and size of registers +- interrupts : interrupt connection + +Optional properties: +- phy-device : phandle to Ethernet phy +- local-mac-address : Ethernet mac address to use diff --git a/Documentation/devicetree/bindings/spi/spi_nvidia.txt b/Documentation/devicetree/bindings/spi/spi_nvidia.txt new file mode 100644 index 00000000000..6b9e5189669 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi_nvidia.txt @@ -0,0 +1,5 @@ +NVIDIA Tegra 2 SPI device + +Required properties: +- compatible : should be "nvidia,tegra20-spi". +- gpios : should specify GPIOs used for chipselect. diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt new file mode 100644 index 00000000000..b8b27b0aca1 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -0,0 +1,36 @@ +* UART (Universal Asynchronous Receiver/Transmitter) + +Required properties: +- compatible : one of: + - "ns8250" + - "ns16450" + - "ns16550a" + - "ns16550" + - "ns16750" + - "ns16850" + - "nvidia,tegra20-uart" + - "ibm,qpace-nwp-serial" + - "serial" if the port type is unknown. +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clock-frequency : the input clock frequency for the UART. + +Optional properties: +- current-speed : the current active speed of the UART. +- reg-offset : offset to apply to the mapbase from the start of the registers. +- reg-shift : quantity to shift the register offsets by. +- reg-io-width : the size (in bytes) of the IO accesses that should be + performed on the device. There are some systems that require 32-bit + accesses to the UART (e.g. TI davinci). +- used-by-rtas : set to indicate that the port is in use by the OpenFirmware + RTAS and should not be registered. + +Example: + + uart@80230000 { + compatible = "ns8250"; + reg = <0x80230000 0x100>; + clock-frequency = <3686400>; + interrupts = <10>; + reg-shift = <2>; + }; diff --git a/Documentation/devicetree/usage-model b/Documentation/devicetree/usage-model new file mode 100644 index 00000000000..45e03b8dd04 --- /dev/null +++ b/Documentation/devicetree/usage-model @@ -0,0 +1,403 @@ +Linux and the Device Tree +The Linux usage model for device tree data + +Author: Grant Likely <grant.likely@secretlab.ca> + +This article describes how Linux uses the device tree. An overview of +the device tree data format can be found at the <a +href="http://devicetree.org/Device_Tree_Usage">Device Tree Usage</a> +page on <a href="http://devicetree.org">devicetree.org</a>. + + + All the cool architectures are using device tree. I want to + use device tree too! + +The "Open Firmware Device Tree", or simply Device Tree (DT), is a data +structure and language for describing hardware. More specifically, it +is a description of hardware that is readable by an operating system +so that the operating system doesn't need to hard code details of the +machine. + +Structurally, the DT is a tree, or acyclic graph with named nodes, and +nodes may have an arbitrary number of named properties encapsulating +arbitrary data. A mechanism also exists to create arbitrary +links from one node to another outside of the natural tree structure. + +Conceptually, a common set of usage conventions, called 'bindings', +is defined for how data should appear in the tree to describe typical +hardware characteristics including data busses, interrupt lines, GPIO +connections, and peripheral devices. + +As much as possible, hardware is described using existing bindings to +maximize use of existing support code, but since property and node +names are simply text strings, it is easy to extend existing bindings +or create new ones by defining new nodes and properties. + +<h2>History</h2> +The DT was originally created by Open Firmware as part of the +communication method for passing data from Open Firmware to a client +program (like to an operating system). An operating system used the +Device Tree to discover the topology of the hardware at runtime, and +thereby support a majority of available hardware without hard coded +information (assuming drivers were available for all devices). + +Since Open Firmware is commonly used on PowerPC and SPARC platforms, +the Linux support for those architectures has for a long time used the +Device Tree. + +In 2005, when PowerPC Linux began a major cleanup and to merge 32-bit +and 64-bit support, the decision was made to require DT support on all +powerpc platforms, regardless of whether or not they used Open +Firmware. To do this, a DT representation called the Flattened Device +Tree (FDT) was created which could be passed to the kernel as a binary +blob without requiring a real Open Firmware implementation. U-Boot, +kexec, and other bootloaders were modified to support both passing a +Device Tree Binary (dtb) and to modify a dtb at boot time. + +Some time later, FDT infrastructure was generalized to be usable by +all architectures. At the time of this writing, 6 mainlined +architectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1 +out of mainline (nios) have some level of DT support. + +<h2>Data Model</h2> +If you haven't already read the +href="http://devicetree.org/Device_Tree_Usage">Device Tree Usage</a> +page, then go read it now. It's okay, I'll wait.... + +<h3>High Level View</h3> +The most important thing to understand is that the DT is simply a data +structure that describes the hardware. There is nothing magical about +it, and it doesn't magically make all hardware configuration problems +go away. What it does do is provide a language for decoupling the +hardware configuration from the board and device driver support in the +Linux kernel (or any other operating system for that matter). Using +it allows board and device support to become data driven; to make +setup decisions based on data passed into the kernel instead of on +per-machine hard coded selections. + +Ideally, data driven platform setup should result in less code +duplication and make it easier to support a wide range of hardware +with a single kernel image. + +Linux uses DT data for three major purposes: +1) platform identification, +2) runtime configuration, and +3) device population. + +<h4>Platform Identification</h4> +First and foremost, the kernel will use data in the DT to identify the +specific machine. In a perfect world, the specific platform shouldn't +matter to the kernel because all platform details would be described +perfectly by the device tree in a consistent and reliable manner. +Hardware is not perfect though, and so the kernel must identify the +machine during early boot so that it has the opportunity to run +machine-specific fixups. + +In the majority of cases, the machine identity is irrelevant, and the +kernel will instead select setup code based on the machine's core +CPU or SoC. On ARM for example, setup_arch() in +arch/arm/kernel/setup.c will call setup_machine_fdt() in +arch/arm/kernel/devicetree.c which searches through the machine_desc +table and selects the machine_desc which best matches the device tree +data. It determines the best match by looking at the 'compatible' +property in the root device tree node, and comparing it with the +dt_compat list in struct machine_desc. + +The 'compatible' property contains a sorted list of strings starting +with the exact name of the machine, followed by an optional list of +boards it is compatible with sorted from most compatible to least. For +example, the root compatible properties for the TI BeagleBoard and its +successor, the BeagleBoard xM board might look like: + + compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3"; + compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3"; + +Where "ti,omap3-beagleboard-xm" specifies the exact model, it also +claims that it compatible with the OMAP 3450 SoC, and the omap3 family +of SoCs in general. You'll notice that the list is sorted from most +specific (exact board) to least specific (SoC family). + +Astute readers might point out that the Beagle xM could also claim +compatibility with the original Beagle board. However, one should be +cautioned about doing so at the board level since there is typically a +high level of change from one board to another, even within the same +product line, and it is hard to nail down exactly what is meant when one +board claims to be compatible with another. For the top level, it is +better to err on the side of caution and not claim one board is +compatible with another. The notable exception would be when one +board is a carrier for another, such as a CPU module attached to a +carrier board. + +One more note on compatible values. Any string used in a compatible +property must be documented as to what it indicates. Add +documentation for compatible strings in Documentation/devicetree/bindings. + +Again on ARM, for each machine_desc, the kernel looks to see if +any of the dt_compat list entries appear in the compatible property. +If one does, then that machine_desc is a candidate for driving the +machine. After searching the entire table of machine_descs, +setup_machine_fdt() returns the 'most compatible' machine_desc based +on which entry in the compatible property each machine_desc matches +against. If no matching machine_desc is found, then it returns NULL. + +The reasoning behind this scheme is the observation that in the majority +of cases, a single machine_desc can support a large number of boards +if they all use the same SoC, or same family of SoCs. However, +invariably there will be some exceptions where a specific board will +require special setup code that is not useful in the generic case. +Special cases could be handled by explicitly checking for the +troublesome board(s) in generic setup code, but doing so very quickly +becomes ugly and/or unmaintainable if it is more than just a couple of +cases. + +Instead, the compatible list allows a generic machine_desc to provide +support for a wide common set of boards by specifying "less +compatible" value in the dt_compat list. In the example above, +generic board support can claim compatibility with "ti,omap3" or +"ti,omap3450". If a bug was discovered on the original beagleboard +that required special workaround code during early boot, then a new +machine_desc could be added which implements the workarounds and only +matches on "ti,omap3-beagleboard". + +PowerPC uses a slightly different scheme where it calls the .probe() +hook from each machine_desc, and the first one returning TRUE is used. +However, this approach does not take into account the priority of the +compatible list, and probably should be avoided for new architecture +support. + +<h4>Runtime configuration</h4> +In most cases, a DT will be the sole method of communicating data from +firmware to the kernel, so also gets used to pass in runtime and +configuration data like the kernel parameters string and the location +of an initrd image. + +Most of this data is contained in the /chosen node, and when booting +Linux it will look something like this: + + chosen { + bootargs = "console=ttyS0,115200 loglevel=8"; + initrd-start = <0xc8000000>; + initrd-end = <0xc8200000>; + }; + +The bootargs property contains the kernel arguments, and the initrd-* +properties define the address and size of an initrd blob. The +chosen node may also optionally contain an arbitrary number of +additional properties for platform-specific configuration data. + +During early boot, the architecture setup code calls of_scan_flat_dt() +several times with different helper callbacks to parse device tree +data before paging is setup. The of_scan_flat_dt() code scans through +the device tree and uses the helpers to extract information required +during early boot. Typically the early_init_dt_scan_chosen() helper +is used to parse the chosen node including kernel parameters, +early_init_dt_scan_root() to initialize the DT address space model, +and early_init_dt_scan_memory() to determine the size and +location of usable RAM. + +On ARM, the function setup_machine_fdt() is responsible for early +scanning of the device tree after selecting the correct machine_desc +that supports the board. + +<h4>Device population</h4> +After the board has been identified, and after the early configuration data +has been parsed, then kernel initialization can proceed in the normal +way. At some point in this process, unflatten_device_tree() is called +to convert the data into a more efficient runtime representation. +This is also when machine-specific setup hooks will get called, like +the machine_desc .init_early(), .init_irq() and .init_machine() hooks +on ARM. The remainder of this section uses examples from the ARM +implementation, but all architectures will do pretty much the same +thing when using a DT. + +As can be guessed by the names, .init_early() is used for any machine- +specific setup that needs to be executed early in the boot process, +and .init_irq() is used to set up interrupt handling. Using a DT +doesn't materially change the behaviour of either of these functions. +If a DT is provided, then both .init_early() and .init_irq() are able +to call any of the DT query functions (of_* in include/linux/of*.h) to +get additional data about the platform. + +The most interesting hook in the DT context is .init_machine() which +is primarily responsible for populating the Linux device model with +data about the platform. Historically this has been implemented on +embedded platforms by defining a set of static clock structures, +platform_devices, and other data in the board support .c file, and +registering it en-masse in .init_machine(). When DT is used, then +instead of hard coding static devices for each platform, the list of +devices can be obtained by parsing the DT, and allocating device +structures dynamically. + +The simplest case is when .init_machine() is only responsible for +registering a block of platform_devices. A platform_device is a concept +used by Linux for memory or I/O mapped devices which cannot be detected +by hardware, and for 'composite' or 'virtual' devices (more on those +later). While there is no 'platform device' terminology for the DT, +platform devices roughly correspond to device nodes at the root of the +tree and children of simple memory mapped bus nodes. + +About now is a good time to lay out an example. Here is part of the +device tree for the NVIDIA Tegra board. + +/{ + compatible = "nvidia,harmony", "nvidia,tegra20"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + chosen { }; + aliases { }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; + }; + + soc { + compatible = "nvidia,tegra20-soc", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + intc: interrupt-controller@50041000 { + compatible = "nvidia,tegra20-gic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >; + }; + + serial@70006300 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006300 0x100>; + interrupts = <122>; + }; + + i2s-1: i2s@70002800 { + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x100>; + interrupts = <77>; + codec = <&wm8903>; + }; + + i2c@7000c000 { + compatible = "nvidia,tegra20-i2c"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x7000c000 0x100>; + interrupts = <70>; + + wm8903: codec@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = <347>; + }; + }; + }; + + sound { + compatible = "nvidia,harmony-sound"; + i2s-controller = <&i2s-1>; + i2s-codec = <&wm8903>; + }; +}; + +At .machine_init() time, Tegra board support code will need to look at +this DT and decide which nodes to create platform_devices for. +However, looking at the tree, it is not immediately obvious what kind +of device each node represents, or even if a node represents a device +at all. The /chosen, /aliases, and /memory nodes are informational +nodes that don't describe devices (although arguably memory could be +considered a device). The children of the /soc node are memory mapped +devices, but the codec@1a is an i2c device, and the sound node +represents not a device, but rather how other devices are connected +together to create the audio subsystem. I know what each device is +because I'm familiar with the board design, but how does the kernel +know what to do with each node? + +The trick is that the kernel starts at the root of the tree and looks +for nodes that have a 'compatible' property. First, it is generally +assumed that any node with a 'compatible' property represents a device +of some kind, and second, it can be assumed that any node at the root +of the tree is either directly attached to the processor bus, or is a +miscellaneous system device that cannot be described any other way. +For each of these nodes, Linux allocates and registers a +platform_device, which in turn may get bound to a platform_driver. + +Why is using a platform_device for these nodes a safe assumption? +Well, for the way that Linux models devices, just about all bus_types +assume that its devices are children of a bus controller. For +example, each i2c_client is a child of an i2c_master. Each spi_device +is a child of an SPI bus. Similarly for USB, PCI, MDIO, etc. The +same hierarchy is also found in the DT, where I2C device nodes only +ever appear as children of an I2C bus node. Ditto for SPI, MDIO, USB, +etc. The only devices which do not require a specific type of parent +device are platform_devices (and amba_devices, but more on that +later), which will happily live at the base of the Linux /sys/devices +tree. Therefore, if a DT node is at the root of the tree, then it +really probably is best registered as a platform_device. + +Linux board support code calls of_platform_populate(NULL, NULL, NULL) +to kick off discovery of devices at the root of the tree. The +parameters are all NULL because when starting from the root of the +tree, there is no need to provide a starting node (the first NULL), a +parent struct device (the last NULL), and we're not using a match +table (yet). For a board that only needs to register devices, +.init_machine() can be completely empty except for the +of_platform_populate() call. + +In the Tegra example, this accounts for the /soc and /sound nodes, but +what about the children of the SoC node? Shouldn't they be registered +as platform devices too? For Linux DT support, the generic behaviour +is for child devices to be registered by the parent's device driver at +driver .probe() time. So, an i2c bus device driver will register a +i2c_client for each child node, an SPI bus driver will register +its spi_device children, and similarly for other bus_types. +According to that model, a driver could be written that binds to the +SoC node and simply registers platform_devices for each of its +children. The board support code would allocate and register an SoC +device, an SoC device driver would bind to the SoC device, and +register platform_devices for /soc/interrupt-controller, /soc/serial, +/soc/i2s, and /soc/i2c in its .probe() hook. Easy, right? Although +it is a lot of mucking about for just registering platform devices. + +It turns out that registering children of certain platform_devices as +more platform_devices is a common pattern, and the device tree support +code reflects that. The second argument to of_platform_populate() is +an of_device_id table, and any node that matches an entry in that +table will also get its child nodes registered. In the tegra case, +the code can look something like this: + +static struct of_device_id harmony_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, + {} +}; + +static void __init harmony_init_machine(void) +{ + /* ... */ + of_platform_populate(NULL, harmony_bus_ids, NULL); +} + +"simple-bus" is defined in the ePAPR 1.0 specification as a property +meaning a simple memory mapped bus, so the of_platform_populate() code +could be written to just assume simple-bus compatible nodes will +always be traversed. However, we pass it in as an argument so that +board support code can always override the default behaviour. + +<h2>Appendix A: AMBA devices</h2> + +ARM Primecells are a certain kind of device attached to the ARM AMBA +bus which include some support for hardware detection and power +management. In Linux, struct amba_device and the amba_bus_type is +used to represent Primecell devices. However, the fiddly bit is that +not all devices on an AMBA bus are Primecells, and for Linux it is +typical for both amba_device and platform_device instances to be +siblings of the same bus segment. + +When using the DT, this creates problems for of_platform_populate() +because it must decide whether to register each node as either a +platform_device or an amba_device. This unfortunately complicates the +device creation model a little bit, but the solution turns out not to +be too invasive. If a node is compatible with "arm,amba-primecell", then +of_platform_populate() will register it as an amba_device instead of a +platform_device. diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index d5c0cef38a7..873a2ab2e9f 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt @@ -40,7 +40,6 @@ Features which NILFS2 does not support yet: - POSIX ACLs - quotas - fsck - - resize - defragmentation Mount options diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d3d653a5f9b..bfe924217f2 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -346,7 +346,7 @@ tcp_orphan_retries - INTEGER when RTO retransmissions remain unacknowledged. See tcp_retries2 for more details. - The default value is 7. + The default value is 8. If your machine is a loaded WEB server, you should think about lowering this value, such sockets may consume significant resources. Cf. tcp_max_orphans. diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 9b7221a86df..7c3a8801b7c 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -674,7 +674,7 @@ Protocol: 2.10+ Field name: init_size Type: read -Offset/size: 0x25c/4 +Offset/size: 0x260/4 This field indicates the amount of linear contiguous memory starting at the kernel runtime start address that the kernel needs before it @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc7 +EXTRAVERSION = NAME = Sneaky Weasel # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 68b456129be..f38e275bea3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1344,6 +1344,31 @@ config SMP_ON_UP If you don't know what to do here, say Y. +config ARM_CPU_TOPOLOGY + bool "Support cpu topology definition" + depends on SMP && CPU_V7 + default y + help + Support ARM cpu topology definition. The MPIDR register defines + affinity between processors which is then used to describe the cpu + topology of an ARM System. + +config SCHED_MC + bool "Multi-core scheduler support" + depends on ARM_CPU_TOPOLOGY + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + +config SCHED_SMT + bool "SMT scheduler support" + depends on ARM_CPU_TOPOLOGY + help + Improves the CPU scheduler's decision making when dealing with + MultiThreading at a cost of slightly increased overhead in some + places. If unsure say N here. + config HAVE_ARM_SCU bool depends on SMP @@ -1727,6 +1752,25 @@ config ZBOOT_ROM_MMCIF which in turn loads the rest the kernel image to RAM using the MMCIF hardware block. +config ARM_APPENDED_DTB + bool "Use appended device tree blob to zImage" + depends on OF && !ZBOOT_ROM + help + With this option, the boot code will look for a device tree binary + (dtb) appended to zImage + (e.g. cat zImage <filename>.dtb > zImage_w_dtb). + +config ARM_ATAG_DTB_COMPAT + bool "Supplement the appended DTB with traditional ATAG information" + depends on ARM_APPENDED_DTB + help + Some old bootloaders can't be updated to a DTB capable one, yet + they provide ATAGs with memory configuration, the ramdisk address, + the kernel cmdline string, etc. To allow a device tree enabled + kernel to be used with such bootloaders, this option allows + zImage to extract the information from the ATAG list and store it + at run time into the appended DTB. + config CMDLINE string "Default kernel command string" default "" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b390c8f..f7135595eb7 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -281,6 +281,12 @@ zImage Image xipImage bootpImage uImage: vmlinux zinstall uinstall install: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ +%.dtb: + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ + +dtbs: + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ + # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) @@ -297,6 +303,7 @@ define archhelp echo ' uImage - U-Boot wrapped zImage' echo ' bootpImage - Combined zImage and initial RAM disk' echo ' (supply initrd image via make variable INITRD=<path>)' + echo ' dtbs - Build device tree blobs for enabled boards' echo ' install - Install uncompressed kernel' echo ' zinstall - Install compressed kernel' echo ' uinstall - Install U-Boot wrapped compressed kernel' diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 9128fddf110..a1edfd5a129 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -59,6 +59,12 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE endif +# Rule to build device tree blobs +$(obj)/%.dtb: $(src)/dts/%.dts + $(call cmd,dtc) + +$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) + quiet_cmd_uimage = UIMAGE $@ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \ -C none -a $(LOADADDR) -e $(STARTADDR) \ diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index c6028967d33..e0936a14851 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore @@ -5,3 +5,12 @@ piggy.lzo piggy.lzma vmlinux vmlinux.lds + +# borrowed libfdt files +fdt.c +fdt.h +fdt_ro.c +fdt_rw.c +fdt_wip.c +libfdt.h +libfdt_internal.h diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 23aad072230..4b94995fc47 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -83,21 +83,41 @@ suffix_$(CONFIG_KERNEL_GZIP) = gzip suffix_$(CONFIG_KERNEL_LZO) = lzo suffix_$(CONFIG_KERNEL_LZMA) = lzma +# libfdt files for the ATAG compatibility mode + +libfdt := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c +libfdt_hdrs := fdt.h libfdt.h libfdt_internal.h + +libfdt_objs := $(addsuffix .o, $(basename $(libfdt))) + +$(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/% + $(call if_changed,shipped) + +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \ + $(addprefix $(obj)/,$(libfdt_hdrs)) + +ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y) +OBJS += $(libfdt_objs) atags_to_fdt.o +endif + targets := vmlinux vmlinux.lds \ piggy.$(suffix_y) piggy.$(suffix_y).o \ font.o font.c head.o misc.o $(OBJS) # Make sure files are removed during clean -extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S +extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs) ifeq ($(CONFIG_FUNCTION_TRACER),y) ORIG_CFLAGS := $(KBUILD_CFLAGS) KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) endif -ccflags-y := -fpic -fno-builtin +ccflags-y := -fpic -fno-builtin -I$(src) asflags-y := -Wa,-march=all +# Supply kernel BSS size to the decompressor via a linker symbol. +KBSS_SZ = $(shell size $(obj)/../../../../vmlinux | awk 'END{print $$3}') +LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ) # Supply ZRELADDR to the decompressor via a linker symbol. ifneq ($(CONFIG_AUTO_ZRELADDR),y) LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR) @@ -115,7 +135,7 @@ LDFLAGS_vmlinux += -X LDFLAGS_vmlinux += -T # For __aeabi_uidivmod -lib1funcs = $(obj)/lib1funcs.o +lib1funcs = $(obj)/lib1funcs.o $(obj)/../../lib/lib.a $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE $(call cmd,shipped) diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c new file mode 100644 index 00000000000..d79afd7300b --- /dev/null +++ b/arch/arm/boot/compressed/atags_to_fdt.c @@ -0,0 +1,97 @@ +#include <asm/setup.h> +#include <libfdt.h> + +static int node_offset(void *fdt, const char *node_path) +{ + int offset = fdt_path_offset(fdt, node_path); + if (offset == -FDT_ERR_NOTFOUND) + offset = fdt_add_subnode(fdt, 0, node_path); + return offset; +} + +static int setprop(void *fdt, const char *node_path, const char *property, + uint32_t *val_array, int size) +{ + int offset = node_offset(fdt, node_path); + if (offset < 0) + return offset; + return fdt_setprop(fdt, offset, property, val_array, size); +} + +static int setprop_string(void *fdt, const char *node_path, + const char *property, const char *string) +{ + int offset = node_offset(fdt, node_path); + if (offset < 0) + return offset; + return fdt_setprop_string(fdt, offset, property, string); +} + +static int setprop_cell(void *fdt, const char *node_path, + const char *property, uint32_t val) +{ + int offset = node_offset(fdt, node_path); + if (offset < 0) + return offset; + return fdt_setprop_cell(fdt, offset, property, val); +} + +/* + * Convert and fold provided ATAGs into the provided FDT. + * + * REturn values: + * = 0 -> pretend success + * = 1 -> bad ATAG (may retry with another possible ATAG pointer) + * < 0 -> error from libfdt + */ +int atags_to_fdt(void *atag_list, void *fdt, int total_space) +{ + struct tag *atag = atag_list; + uint32_t mem_reg_property[16]; + int memcount = 0; + int ret; + + /* make sure we've got an aligned pointer */ + if ((u32)atag_list & 0x3) + return 1; + + /* if we get a DTB here we're done already */ + if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) + return 0; + + /* validate the ATAG */ + if (atag->hdr.tag != ATAG_CORE || + (atag->hdr.size != tag_size(tag_core) && + atag->hdr.size != 2)) + return 1; + + /* let's give it all the room it could need */ + ret = fdt_open_into(fdt, fdt, total_space); + if (ret < 0) + return ret; + + for_each_tag(atag, atag_list) { + if (atag->hdr.tag == ATAG_CMDLINE) { + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); + } else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/sizeof(uint32_t)) + continue; + mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); + mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); + } else if (atag->hdr.tag == ATAG_INITRD2) { + uint32_t initrd_start, initrd_size; + initrd_start = atag->u.initrd.start; + initrd_size = atag->u.initrd.size; + setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_start); + setprop_cell(fdt, "/chosen", "linux,initrd-end", + initrd_start + initrd_size); + } + } + + if (memcount) + setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount); + + return fdt_pack(fdt); +} diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 940b2017810..5a07162568f 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -216,6 +216,103 @@ restart: adr r0, LC0 mov r10, r6 #endif + mov r5, #0 @ init dtb size to 0 +#ifdef CONFIG_ARM_APPENDED_DTB +/* + * r0 = delta + * r2 = BSS start + * r3 = BSS end + * r4 = final kernel address + * r5 = appended dtb size (still unknown) + * r6 = _edata + * r7 = architecture ID + * r8 = atags/device tree pointer + * r9 = size of decompressed image + * r10 = end of this image, including bss/stack/malloc space if non XIP + * r11 = GOT start + * r12 = GOT end + * sp = stack pointer + * + * if there are device trees (dtb) appended to zImage, advance r10 so that the + * dtb data will get relocated along with the kernel if necessary. + */ + + ldr lr, [r6, #0] +#ifndef __ARMEB__ + ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian +#else + ldr r1, =0xd00dfeed +#endif + cmp lr, r1 + bne dtb_check_done @ not found + +#ifdef CONFIG_ARM_ATAG_DTB_COMPAT + /* + * OK... Let's do some funky business here. + * If we do have a DTB appended to zImage, and we do have + * an ATAG list around, we want the later to be translated + * and folded into the former here. To be on the safe side, + * let's temporarily move the stack away into the malloc + * area. No GOT fixup has occurred yet, but none of the + * code we're about to call uses any global variable. + */ + add sp, sp, #0x10000 + stmfd sp!, {r0-r3, ip, lr} + mov r0, r8 + mov r1, r6 + sub r2, sp, r6 + bl atags_to_fdt + + /* + * If returned value is 1, there is no ATAG at the location + * pointed by r8. Try the typical 0x100 offset from start + * of RAM and hope for the best. + */ + cmp r0, #1 + sub r0, r4, #(TEXT_OFFSET - 0x100) + mov r1, r6 + sub r2, sp, r6 + blne atags_to_fdt + + ldmfd sp!, {r0-r3, ip, lr} + sub sp, sp, #0x10000 +#endif + + mov r8, r6 @ use the appended device tree + + /* + * Make sure that the DTB doesn't end up in the final + * kernel's .bss area. To do so, we adjust the decompressed + * kernel size to compensate if that .bss size is larger + * than the relocated code. + */ + ldr r5, =_kernel_bss_size + adr r1, wont_overwrite + sub r1, r6, r1 + subs r1, r5, r1 + addhi r9, r9, r1 + + /* Get the dtb's size */ + ldr r5, [r6, #4] +#ifndef __ARMEB__ + /* convert r5 (dtb size) to little endian */ + eor r1, r5, r5, ror #16 + bic r1, r1, #0x00ff0000 + mov r5, r5, ror #8 + eor r5, r5, r1, lsr #8 +#endif + + /* preserve 64-bit alignment */ + add r5, r5, #7 + bic r5, r5, #7 + + /* relocate some pointers past the appended dtb */ + add r6, r6, r5 + add r10, r10, r5 + add sp, sp, r5 +dtb_check_done: +#endif + /* * Check to see if we will overwrite ourselves. * r4 = final kernel address @@ -223,15 +320,14 @@ restart: adr r0, LC0 * r10 = end of this image, including bss/stack/malloc space if non XIP * We basically want: * r4 - 16k page directory >= r10 -> OK - * r4 + image length <= current position (pc) -> OK + * r4 + image length <= address of wont_overwrite -> OK */ add r10, r10, #16384 cmp r4, r10 bhs wont_overwrite add r10, r4, r9 - ARM( cmp r10, pc ) - THUMB( mov lr, pc ) - THUMB( cmp r10, lr ) + adr r9, wont_overwrite + cmp r10, r9 bls wont_overwrite /* @@ -285,14 +381,16 @@ wont_overwrite: * r2 = BSS start * r3 = BSS end * r4 = kernel execution address + * r5 = appended dtb size (0 if not present) * r7 = architecture ID * r8 = atags pointer * r11 = GOT start * r12 = GOT end * sp = stack pointer */ - teq r0, #0 + orrs r1, r0, r5 beq not_relocated + add r11, r11, r0 add r12, r12, r0 @@ -307,12 +405,21 @@ wont_overwrite: /* * Relocate all entries in the GOT table. + * Bump bss entries to _edata + dtb size */ 1: ldr r1, [r11, #0] @ relocate entries in the GOT - add r1, r1, r0 @ table. This fixes up the - str r1, [r11], #4 @ C references. + add r1, r1, r0 @ This fixes up C references + cmp r1, r2 @ if entry >= bss_start && + cmphs r3, r1 @ bss_end > entry + addhi r1, r1, r5 @ entry += dtb size + str r1, [r11], #4 @ next entry cmp r11, r12 blo 1b + + /* bump our bss pointers too */ + add r2, r2, r5 + add r3, r3, r5 + #else /* diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h new file mode 100644 index 00000000000..1f4e71876b0 --- /dev/null +++ b/arch/arm/boot/compressed/libfdt_env.h @@ -0,0 +1,15 @@ +#ifndef _ARM_LIBFDT_ENV_H +#define _ARM_LIBFDT_ENV_H + +#include <linux/types.h> +#include <linux/string.h> +#include <asm/byteorder.h> + +#define fdt16_to_cpu(x) be16_to_cpu(x) +#define cpu_to_fdt16(x) cpu_to_be16(x) +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) +#define fdt64_to_cpu(x) be64_to_cpu(x) +#define cpu_to_fdt64(x) cpu_to_be64(x) + +#endif diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 832d37236c5..16c98d8c28a 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -136,6 +136,58 @@ void *memcpy(void *__dest, __const void *__src, size_t __n) return __dest; } +void *memmove(void *__dest, __const void *__src, size_t __n) +{ + unsigned char *d = __dest; + const unsigned char *s = __src; + + if (__dest == __src) + return __dest; + + if (__dest < __src) + return memcpy(__dest, __src, __n); + + while (__n--) + d[__n] = s[__n]; + + return __dest; +} + +size_t strlen(const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +int memcmp(const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +int strcmp(const char *cs, const char *ct) +{ + unsigned char c1, c2; + + while (1) { + c1 = *cs++; + c2 = *ct++; + if (c1 != c2) + return c1 < c2 ? -1 : 1; + if (!c1) + break; + } + return 0; +} + /* * gzip declarations */ diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index ea80abe7884..6c02db134f2 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -47,6 +47,9 @@ SECTIONS .got : { *(.got) } _got_end = .; .got.plt : { *(.got.plt) } + + /* ensure the zImage file size is always a multiple of 64 bits */ + .pad : { BYTE(0); . = ALIGN(8); } _edata = .; . = BSS_START; diff --git a/arch/arm/boot/dts/exynos4-smdkv310.dts b/arch/arm/boot/dts/exynos4-smdkv310.dts new file mode 100644 index 00000000000..dd6c80a7ffc --- /dev/null +++ b/arch/arm/boot/dts/exynos4-smdkv310.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Samsung Exynos4 SMDKV310 eval board"; + compatible = "samsung,smdkv310", "samsung,s5pv310"; + + memory { + reg = <0x40000000 0x08000000>; + }; +}; diff --git a/arch/arm/boot/dts/genesi-efikamx.dts b/arch/arm/boot/dts/genesi-efikamx.dts new file mode 100644 index 00000000000..e81ffcc8443 --- /dev/null +++ b/arch/arm/boot/dts/genesi-efikamx.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Genesi EfikaMX nettop"; + compatible = "genesi,efikamx", "fsl,mx51"; + + memory { + reg = <0x90000000 0x20000000>; + }; +}; diff --git a/arch/arm/boot/dts/genesi-efikasb.dts b/arch/arm/boot/dts/genesi-efikasb.dts new file mode 100644 index 00000000000..9fda6ae314e --- /dev/null +++ b/arch/arm/boot/dts/genesi-efikasb.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Genesi Efika Smartbook"; + compatible = "genesi,efikasb", "fsl,mx51"; + + memory { + reg = <0x90000000 0x20000000>; + }; +}; diff --git a/arch/arm/boot/dts/isee-igep-v2.dts b/arch/arm/boot/dts/isee-igep-v2.dts new file mode 100644 index 00000000000..72caabb85b7 --- /dev/null +++ b/arch/arm/boot/dts/isee-igep-v2.dts @@ -0,0 +1,7 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "ISSE IGEPv2 Board"; + compatible = "ISEE,igep-v2"; +}; diff --git a/arch/arm/boot/dts/isee-igep-v3.dts b/arch/arm/boot/dts/isee-igep-v3.dts new file mode 100644 index 00000000000..f40886fef69 --- /dev/null +++ b/arch/arm/boot/dts/isee-igep-v3.dts @@ -0,0 +1,7 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "ISSE IGEPv3 Module"; + compatible = "ISEE,igep-v3"; +}; diff --git a/arch/arm/boot/dts/mx51-babbage.dts b/arch/arm/boot/dts/mx51-babbage.dts new file mode 100644 index 00000000000..e5e9c8913d0 --- /dev/null +++ b/arch/arm/boot/dts/mx51-babbage.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Freescale i.MX51 Babbage"; + compatible = "fsl,mx51-babbage", "fsl,mx51"; + + memory { + reg = <0x90000000 0x20000000>; + }; +}; diff --git a/arch/arm/boot/dts/mx53-loco.dts b/arch/arm/boot/dts/mx53-loco.dts new file mode 100644 index 00000000000..8426c620614 --- /dev/null +++ b/arch/arm/boot/dts/mx53-loco.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Freescale i.MX53 LOCO"; + compatible = "fsl,mx53-loco", "fsl,mx53"; + + memory { + reg = <0x70000000 0x40000000>; + }; +}; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts new file mode 100644 index 00000000000..44394660006 --- /dev/null +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -0,0 +1,7 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "TI OMAP3 BeagleBoard"; + compatible = "ti,omap3-beagle"; +}; diff --git a/arch/arm/boot/dts/omap3-overo.dts b/arch/arm/boot/dts/omap3-overo.dts new file mode 100644 index 00000000000..c61f0112bf3 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo.dts @@ -0,0 +1,7 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "Gumstix Overo"; + compatible = "gumstix,omap3-overo"; +}; diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts new file mode 100644 index 00000000000..58909e9b664 --- /dev/null +++ b/arch/arm/boot/dts/omap4-panda.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/memreserve/ 0x9D000000 0x03000000; /* Frame buffer */ +/memreserve/ 0xB0000000 0x10000000; /* Top 256MB is unaccessable */ + +/include/ "skeleton.dtsi" + +/ { + model = "TI OMAP4 PandaBoard"; + compatible = "ti,omap4-panda", "ti,omap4430"; +}; diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi new file mode 100644 index 00000000000..b41d241de2c --- /dev/null +++ b/arch/arm/boot/dts/skeleton.dtsi @@ -0,0 +1,13 @@ +/* + * Skeleton device tree; the bare minimum needed to boot; just include and + * add a compatible value. The bootloader will typically populate the memory + * node. + */ + +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { }; + aliases { }; + memory { device_type = "memory"; reg = <0 0>; }; +}; diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts new file mode 100644 index 00000000000..4c053340ce3 --- /dev/null +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -0,0 +1,70 @@ +/dts-v1/; + +/memreserve/ 0x1c000000 0x04000000; +/include/ "tegra20.dtsi" + +/ { + model = "NVIDIA Tegra2 Harmony evaluation board"; + compatible = "nvidia,harmony", "nvidia,tegra20"; + + chosen { + bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait"; + }; + + memory@0 { + reg = < 0x00000000 0x40000000 >; + }; + + i2c@7000c000 { + clock-frequency = <400000>; + + codec: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + gpio-controller; + #gpio-cells = <2>; + + /* 0x8000 = Not configured */ + gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; + }; + }; + + i2c@7000c400 { + clock-frequency = <400000>; + }; + + i2c@7000c500 { + clock-frequency = <400000>; + }; + + i2c@7000d000 { + clock-frequency = <400000>; + }; + + sound { + compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903"; + + spkr-en-gpios = <&codec 2 0>; + hp-det-gpios = <&gpio 178 0>; + int-mic-en-gpios = <&gpio 184 0>; + ext-mic-en-gpios = <&gpio 185 0>; + }; + + serial@70006300 { + clock-frequency = < 216000000 >; + }; + + sdhci@c8000200 { + gpios = <&gpio 69 0>, /* cd, gpio PI5 */ + <&gpio 57 0>, /* wp, gpio PH1 */ + <&gpio 155 0>; /* power, gpio PT3 */ + }; + + sdhci@c8000600 { + gpios = <&gpio 58 0>, /* cd, gpio PH2 */ + <&gpio 59 0>, /* wp, gpio PH3 */ + <&gpio 70 0>; /* power, gpio PI6 */ + }; +}; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts new file mode 100644 index 00000000000..1940cae0074 --- /dev/null +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +/memreserve/ 0x1c000000 0x04000000; +/include/ "tegra20.dtsi" + +/ { + model = "NVIDIA Seaboard"; + compatible = "nvidia,seaboard", "nvidia,tegra20"; + + chosen { + bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk1p3 rw rootwait"; + }; + + memory { + device_type = "memory"; + reg = < 0x00000000 0x40000000 >; + }; + + serial@70006300 { + clock-frequency = < 216000000 >; + }; + + sdhci@c8000400 { + gpios = <&gpio 69 0>, /* cd, gpio PI5 */ + <&gpio 57 0>, /* wp, gpio PH1 */ + <&gpio 70 0>; /* power, gpio PI6 */ + }; +}; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi new file mode 100644 index 00000000000..5727595cde6 --- /dev/null +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -0,0 +1,139 @@ +/include/ "skeleton.dtsi" + +/ { + compatible = "nvidia,tegra20"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@50041000 { + compatible = "nvidia,tegra20-gic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = < 0x50041000 0x1000 >, + < 0x50040100 0x0100 >; + }; + + i2c@7000c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C000 0x100>; + interrupts = < 70 >; + }; + + i2c@7000c400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C400 0x100>; + interrupts = < 116 >; + }; + + i2c@7000c500 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000C500 0x100>; + interrupts = < 124 >; + }; + + i2c@7000d000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000D000 0x200>; + interrupts = < 85 >; + }; + + i2s@70002800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x200>; + interrupts = < 45 >; + dma-channel = < 2 >; + }; + + i2s@70002a00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002a00 0x200>; + interrupts = < 35 >; + dma-channel = < 1 >; + }; + + das@70000c00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; + }; + + gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 64 65 66 67 87 119 121 >; + #gpio-cells = <2>; + gpio-controller; + }; + + serial@70006000 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006000 0x40>; + reg-shift = <2>; + interrupts = < 68 >; + }; + + serial@70006040 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006040 0x40>; + reg-shift = <2>; + interrupts = < 69 >; + }; + + serial@70006200 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006200 0x100>; + reg-shift = <2>; + interrupts = < 78 >; + }; + + serial@70006300 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006300 0x100>; + reg-shift = <2>; + interrupts = < 122 >; + }; + + serial@70006400 { + compatible = "nvidia,tegra20-uart"; + reg = <0x70006400 0x100>; + reg-shift = <2>; + interrupts = < 123 >; + }; + + sdhci@c8000000 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000000 0x200>; + interrupts = < 46 >; + }; + + sdhci@c8000200 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000200 0x200>; + interrupts = < 47 >; + }; + + sdhci@c8000400 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000400 0x200>; + interrupts = < 51 >; + }; + + sdhci@c8000600 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000600 0x200>; + interrupts = < 63 >; + }; +}; + diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts new file mode 100644 index 00000000000..0b32925f214 --- /dev/null +++ b/arch/arm/boot/dts/versatile-ab.dts @@ -0,0 +1,192 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "ARM Versatile AB"; + compatible = "arm,versatile-ab"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&vic>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + i2c0 = &i2c0; + }; + + memory { + reg = <0x0 0x08000000>; + }; + + flash@34000000 { + compatible = "arm,versatile-flash"; + reg = <0x34000000 0x4000000>; + bank-width = <4>; + }; + + i2c0: i2c@10002000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "arm,versatile-i2c"; + reg = <0x10002000 0x1000>; + + rtc@68 { + compatible = "dallas,ds1338"; + reg = <0x68>; + }; + }; + + net@10010000 { + compatible = "smsc,lan91c111"; + reg = <0x10010000 0x10000>; + interrupts = <25>; + }; + + lcd@10008000 { + compatible = "arm,versatile-lcd"; + reg = <0x10008000 0x1000>; + }; + + amba { + compatible = "arm,amba-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + vic: intc@10140000 { + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10140000 0x1000>; + }; + + sic: intc@10003000 { + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10003000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <31>; /* Cascaded to vic */ + }; + + dma@10130000 { + compatible = "arm,pl081", "arm,primecell"; + reg = <0x10130000 0x1000>; + interrupts = <17>; + }; + + uart0: uart@101f1000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x101f1000 0x1000>; + interrupts = <12>; + }; + + uart1: uart@101f2000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x101f2000 0x1000>; + interrupts = <13>; + }; + + uart2: uart@101f3000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x101f3000 0x1000>; + interrupts = <14>; + }; + + smc@10100000 { + compatible = "arm,primecell"; + reg = <0x10100000 0x1000>; + }; + + mpmc@10110000 { + compatible = "arm,primecell"; + reg = <0x10110000 0x1000>; + }; + + display@10120000 { + compatible = "arm,pl110", "arm,primecell"; + reg = <0x10120000 0x1000>; + interrupts = <16>; + }; + + sctl@101e0000 { + compatible = "arm,primecell"; + reg = <0x101e0000 0x1000>; + }; + + watchdog@101e1000 { + compatible = "arm,primecell"; + reg = <0x101e1000 0x1000>; + interrupts = <0>; + }; + + gpio0: gpio@101e4000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x101e4000 0x1000>; + gpio-controller; + interrupts = <6>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@101e5000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x101e5000 0x1000>; + interrupts = <7>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + rtc@101e8000 { + compatible = "arm,pl030", "arm,primecell"; + reg = <0x101e8000 0x1000>; + interrupts = <10>; + }; + + sci@101f0000 { + compatible = "arm,primecell"; + reg = <0x101f0000 0x1000>; + interrupts = <15>; + }; + + ssp@101f4000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x101f4000 0x1000>; + interrupts = <11>; + }; + + fpga { + compatible = "arm,versatile-fpga", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10000000 0x10000>; + + aaci@4000 { + compatible = "arm,primecell"; + reg = <0x4000 0x1000>; + interrupts = <24>; + }; + mmc@5000 { + compatible = "arm,primecell"; + reg = < 0x5000 0x1000>; + interrupts = <22>; + }; + kmi@6000 { + compatible = "arm,pl050", "arm,primecell"; + reg = <0x6000 0x1000>; + interrupt-parent = <&sic>; + interrupts = <3>; + }; + kmi@7000 { + compatible = "arm,pl050", "arm,primecell"; + reg = <0x7000 0x1000>; + interrupt-parent = <&sic>; + interrupts = <4>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts new file mode 100644 index 00000000000..8a614e39800 --- /dev/null +++ b/arch/arm/boot/dts/versatile-pb.dts @@ -0,0 +1,48 @@ +/include/ "versatile-ab.dts" + +/ { + model = "ARM Versatile PB"; + compatible = "arm,versatile-pb"; + + amba { + gpio2: gpio@101e6000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x101e6000 0x1000>; + interrupts = <8>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@101e7000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0x101e7000 0x1000>; + interrupts = <9>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + fpga { + uart@9000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x9000 0x1000>; + interrupt-parent = <&sic>; + interrupts = <6>; + }; + sci@a000 { + compatible = "arm,primecell"; + reg = <0xa000 0x1000>; + interrupt-parent = <&sic>; + interrupts = <5>; + }; + mmc@b000 { + compatible = "arm,primecell"; + reg = <0xb000 0x1000>; + interrupts = <23>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/vexpress.dts b/arch/arm/boot/dts/vexpress.dts new file mode 100644 index 00000000000..5f3bc1d1f1c --- /dev/null +++ b/arch/arm/boot/dts/vexpress.dts @@ -0,0 +1,10 @@ +/dts-v1/; +/include/ "skeleton.dtsi" + +/ { + model = "ARM Versatile Express"; + compatible = "arm,vexpress"; + memory { + reg = <0x60000000 0x40000000>; + }; +}; diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index cd4458f6417..cb47d28cbe1 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -8,6 +8,7 @@ #define CPUID_CACHETYPE 1 #define CPUID_TCM 2 #define CPUID_TLBTYPE 3 +#define CPUID_MPIDR 5 #define CPUID_EXT_PFR0 "c1, 0" #define CPUID_EXT_PFR1 "c1, 1" @@ -70,6 +71,11 @@ static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void) return read_cpuid(CPUID_TCM); } +static inline unsigned int __attribute_const__ read_cpuid_mpidr(void) +{ + return read_cpuid(CPUID_MPIDR); +} + /* * Intel's XScale3 core supports some v6 features (supersections, L2) * but advertises itself as v5 as it does not support the v6 ISA. For diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 3281fb4b12e..217aa1911dd 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -74,4 +74,11 @@ static const struct machine_desc __mach_desc_##_type \ #define MACHINE_END \ }; +#define DT_MACHINE_START(_name, _namestr) \ +static const struct machine_desc __mach_desc_##_name \ + __used \ + __attribute__((__section__(".arch.info.init"))) = { \ + .nr = ~0, \ + .name = _namestr, + #endif diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h index 11b8708fc4d..6f65ca86a5e 100644 --- a/arch/arm/include/asm/prom.h +++ b/arch/arm/include/asm/prom.h @@ -16,11 +16,6 @@ #include <asm/setup.h> #include <asm/irq.h> -static inline void irq_dispose_mapping(unsigned int virq) -{ - return; -} - extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); extern void arm_dt_memblock_reserve(void); diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index accbd7cad9b..a7e457ed27c 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -1,6 +1,39 @@ #ifndef _ASM_ARM_TOPOLOGY_H #define _ASM_ARM_TOPOLOGY_H +#ifdef CONFIG_ARM_CPU_TOPOLOGY + +#include <linux/cpumask.h> + +struct cputopo_arm { + int thread_id; + int core_id; + int socket_id; + cpumask_t thread_sibling; + cpumask_t core_sibling; +}; + +extern struct cputopo_arm cpu_topology[NR_CPUS]; + +#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) +#define topology_core_id(cpu) (cpu_topology[cpu].core_id) +#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) +#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) + +#define mc_capable() (cpu_topology[0].socket_id != -1) +#define smt_capable() (cpu_topology[0].thread_id != -1) + +void init_cpu_topology(void); +void store_cpu_topology(unsigned int cpuid); +const struct cpumask *cpu_coregroup_mask(unsigned int cpu); + +#else + +static inline void init_cpu_topology(void) { } +static inline void store_cpu_topology(unsigned int cpuid) { } + +#endif + #include <asm-generic/topology.h> #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index f7887dc53c1..c687bceba7d 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o obj-$(CONFIG_CPU_HAS_PMU) += pmu.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt +obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o ifneq ($(CONFIG_ARCH_EBSA110),y) obj-y += io.o diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 0cdd7b456cb..1a33e9d6bb1 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -132,17 +132,3 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) return mdesc_best; } - -/** - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# - * - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are - * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not - * supported. - */ -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index e7f92a4321f..8e3a000ee0a 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -31,6 +31,7 @@ #include <asm/cacheflush.h> #include <asm/cpu.h> #include <asm/cputype.h> +#include <asm/topology.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -268,6 +269,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid) struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); cpu_info->loops_per_jiffy = loops_per_jiffy; + + store_cpu_topology(cpuid); } /* @@ -358,6 +361,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { unsigned int ncores = num_possible_cpus(); + init_cpu_topology(); + smp_store_cpu_info(smp_processor_id()); /* diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c new file mode 100644 index 00000000000..1040c00405d --- /dev/null +++ b/arch/arm/kernel/topology.c @@ -0,0 +1,148 @@ +/* + * arch/arm/kernel/topology.c + * + * Copyright (C) 2011 Linaro Limited. + * Written by: Vincent Guittot + * + * based on arch/sh/kernel/topology.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/init.h> +#include <linux/percpu.h> +#include <linux/node.h> +#include <linux/nodemask.h> +#include <linux/sched.h> + +#include <asm/cputype.h> +#include <asm/topology.h> + +#define MPIDR_SMP_BITMASK (0x3 << 30) +#define MPIDR_SMP_VALUE (0x2 << 30) + +#define MPIDR_MT_BITMASK (0x1 << 24) + +/* + * These masks reflect the current use of the affinity levels. + * The affinity level can be up to 16 bits according to ARM ARM + */ + +#define MPIDR_LEVEL0_MASK 0x3 +#define MPIDR_LEVEL0_SHIFT 0 + +#define MPIDR_LEVEL1_MASK 0xF +#define MPIDR_LEVEL1_SHIFT 8 + +#define MPIDR_LEVEL2_MASK 0xFF +#define MPIDR_LEVEL2_SHIFT 16 + +struct cputopo_arm cpu_topology[NR_CPUS]; + +const struct cpumask *cpu_coregroup_mask(unsigned int cpu) +{ + return &cpu_topology[cpu].core_sibling; +} + +/* + * store_cpu_topology is called at boot when only one cpu is running + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted, + * which prevents simultaneous write access to cpu_topology array + */ +void store_cpu_topology(unsigned int cpuid) +{ + struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid]; + unsigned int mpidr; + unsigned int cpu; + + /* If the cpu topology has been already set, just return */ + if (cpuid_topo->core_id != -1) + return; + + mpidr = read_cpuid_mpidr(); + + /* create cpu topology mapping */ + if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) { + /* + * This is a multiprocessor system + * multiprocessor format & multiprocessor mode field are set + */ + + if (mpidr & MPIDR_MT_BITMASK) { + /* core performance interdependency */ + cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT) + & MPIDR_LEVEL0_MASK; + cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT) + & MPIDR_LEVEL1_MASK; + cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT) + & MPIDR_LEVEL2_MASK; + } else { + /* largely independent cores */ + cpuid_topo->thread_id = -1; + cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT) + & MPIDR_LEVEL0_MASK; + cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT) + & MPIDR_LEVEL1_MASK; + } + } else { + /* + * This is an uniprocessor system + * we are in multiprocessor format but uniprocessor system + * or in the old uniprocessor format + */ + cpuid_topo->thread_id = -1; + cpuid_topo->core_id = 0; + cpuid_topo->socket_id = -1; + } + + /* update core and thread sibling masks */ + for_each_possible_cpu(cpu) { + struct cputopo_arm *cpu_topo = &cpu_topology[cpu]; + + if (cpuid_topo->socket_id == cpu_topo->socket_id) { + cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); + if (cpu != cpuid) + cpumask_set_cpu(cpu, + &cpuid_topo->core_sibling); + + if (cpuid_topo->core_id == cpu_topo->core_id) { + cpumask_set_cpu(cpuid, + &cpu_topo->thread_sibling); + if (cpu != cpuid) + cpumask_set_cpu(cpu, + &cpuid_topo->thread_sibling); + } + } + } + smp_wmb(); + + printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n", + cpuid, cpu_topology[cpuid].thread_id, + cpu_topology[cpuid].core_id, + cpu_topology[cpuid].socket_id, mpidr); +} + +/* + * init_cpu_topology is called at boot when only one cpu is running + * which prevent simultaneous write access to cpu_topology array + */ +void init_cpu_topology(void) +{ + unsigned int cpu; + + /* init core mask */ + for_each_possible_cpu(cpu) { + struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); + + cpu_topo->thread_id = -1; + cpu_topo->core_id = -1; + cpu_topo->socket_id = -1; + cpumask_clear(&cpu_topo->core_sibling); + cpumask_clear(&cpu_topo->thread_sibling); + } + smp_wmb(); +} diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 9844fa4cadc..9818f214d4f 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -520,7 +520,7 @@ fail: */ if (have_imager()) { label = "HD imager"; - mux |= 1; + mux |= 2; /* externally mux MMC1/ENET/AIC33 to imager */ mux |= BIT(6) | BIT(5) | BIT(3); @@ -540,7 +540,7 @@ fail: resets &= ~BIT(1); if (have_tvp7002()) { - mux |= 2; + mux |= 1; resets &= ~BIT(2); label = "tvp7002 HD"; } else { diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c index e7221398e5a..cafbe13a82a 100644 --- a/arch/arm/mach-davinci/gpio.c +++ b/arch/arm/mach-davinci/gpio.c @@ -254,8 +254,10 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; + struct davinci_gpio_controller *d; - g = (__force struct davinci_gpio_regs __iomem *) irq_desc_get_handler_data(desc); + d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc); + g = (struct davinci_gpio_regs __iomem *)d->regs; /* we only care about one bank */ if (irq & 1) @@ -274,11 +276,14 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) if (!status) break; __raw_writel(status, &g->intstat); - if (irq & 1) - status >>= 16; /* now demux them to the right lowlevel handler */ - n = (int)irq_get_handler_data(irq); + n = d->irq_base; + if (irq & 1) { + n += 16; + status >>= 16; + } + while (status) { res = ffs(status); n += res; @@ -424,7 +429,13 @@ static int __init davinci_gpio_irq_setup(void) /* set up all irqs in this bank */ irq_set_chained_handler(bank_irq, gpio_irq_handler); - irq_set_handler_data(bank_irq, (__force void *)g); + + /* + * Each chip handles 32 gpios, and each irq bank consists of 16 + * gpio irqs. Pass the irq bank's corresponding controller to + * the chained irq handler. + */ + irq_set_handler_data(bank_irq, &chips[gpio / 32]); for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { irq_set_chip(irq, &gpio_irqchip); diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c index bfe68ec4e1a..952dc126c39 100644 --- a/arch/arm/mach-davinci/irq.c +++ b/arch/arm/mach-davinci/irq.c @@ -52,8 +52,14 @@ davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) struct irq_chip_type *ct; gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq); + if (!gc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n", + __func__, irq_start); + return; + } + ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; diff --git a/arch/arm/mach-exynos4/Makefile.boot b/arch/arm/mach-exynos4/Makefile.boot index d65956ffb43..fcee6b5384a 100644 --- a/arch/arm/mach-exynos4/Makefile.boot +++ b/arch/arm/mach-exynos4/Makefile.boot @@ -1,2 +1,4 @@ zreladdr-y := 0x40008000 params_phys-y := 0x40000100 + +dtb-$(CONFIG_MACH_SMDKV310) += exynos4-smdkv310.dtb diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c index edd814110da..13b4bb733ef 100644 --- a/arch/arm/mach-exynos4/mach-smdkv310.c +++ b/arch/arm/mach-exynos4/mach-smdkv310.c @@ -233,6 +233,11 @@ static void __init smdkv310_machine_init(void) platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); } +static char const *smdkv310_dt_compat[] __initdata = { + "samsung,smdkv310", + NULL +}; + MACHINE_START(SMDKV310, "SMDKV310") /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ /* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */ @@ -241,4 +246,5 @@ MACHINE_START(SMDKV310, "SMDKV310") .map_io = smdkv310_map_io, .init_machine = smdkv310_machine_init, .timer = &exynos4_timer, + .dt_compat = smdkv310_dt_compat, MACHINE_END diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 74ed81a3cb1..07772575d7a 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -419,14 +419,20 @@ static void notrace ixp4xx_update_sched_clock(void) /* * clocksource */ + +static cycle_t ixp4xx_clocksource_read(struct clocksource *c) +{ + return *IXP4XX_OSTS; +} + unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ; EXPORT_SYMBOL(ixp4xx_timer_freq); static void __init ixp4xx_clocksource_init(void) { init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq); - clocksource_mmio_init(&IXP4XX_OSTS, "OSTS", ixp4xx_timer_freq, 200, 32, - clocksource_mmio_readl_up); + clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32, + ixp4xx_clocksource_read); } /* diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c index 72b4e763158..ab9f999106c 100644 --- a/arch/arm/mach-mmp/pxa168.c +++ b/arch/arm/mach-mmp/pxa168.c @@ -79,7 +79,7 @@ static APBC_CLK(ssp4, PXA168_SSP4, 4, 0); static APBC_CLK(ssp5, PXA168_SSP5, 4, 0); static APBC_CLK(keypad, PXA168_KPC, 0, 32000); -static APMU_CLK(nand, NAND, 0x01db, 208000000); +static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(lcd, LCD, 0x7f, 312000000); /* device and clock bindings */ diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index 8f92ccd26ed..1464607aa60 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -110,7 +110,7 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000); static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000); static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000); -static APMU_CLK(nand, NAND, 0x01db, 208000000); +static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(u2o, USB, 0x1b, 480000000); /* device and clock bindings */ diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot index e928be1b675..4111462e242 100644 --- a/arch/arm/mach-mx5/Makefile.boot +++ b/arch/arm/mach-mx5/Makefile.boot @@ -7,3 +7,8 @@ initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000 zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000 params_phys-$(CONFIG_ARCH_MX53) := 0x70000100 initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000 + +dtb-$(CONFIG_MACH_MX51_BABBAGE) += mx51-babbage.dtb +dtb-$(CONFIG_MACH_MX51_EFIKAMX) += genesi-efikamx.dtb +dtb-$(CONFIG_MACH_MX51_EFIKASB) += genesi-efikasb.dtb +dtb-$(CONFIG_MACH_MX53_LOCO) += mx53-loco.dtb diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index c7b3fabf50f..d508e5ea54b 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -392,6 +392,11 @@ static struct sys_timer mx51_babbage_timer = { .init = mx51_babbage_timer_init, }; +static const char *mx51_babbage_dt_match[] __initdata = { + "fsl,mx51-babbage", + NULL +}; + MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") /* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */ .boot_params = MX51_PHYS_OFFSET + 0x100, @@ -400,4 +405,5 @@ MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") .init_irq = mx51_init_irq, .timer = &mx51_babbage_timer, .init_machine = mx51_babbage_init, + .dt_compat = mx51_babbage_dt_match, MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c index 6e362315291..7b07179a09d 100644 --- a/arch/arm/mach-mx5/board-mx51_efikamx.c +++ b/arch/arm/mach-mx5/board-mx51_efikamx.c @@ -283,6 +283,11 @@ static struct sys_timer mx51_efikamx_timer = { .init = mx51_efikamx_timer_init, }; +static const char *mx51_efikamx_dt_match[] __initdata = { + "genesi,efikamx", + NULL +}; + MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop") /* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */ .boot_params = MX51_PHYS_OFFSET + 0x100, @@ -291,4 +296,5 @@ MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop") .init_irq = mx51_init_irq, .timer = &mx51_efikamx_timer, .init_machine = mx51_efikamx_init, + .dt_compat = mx51_efikamx_dt_match, MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c index 474fc6e4c6d..e90dcd58135 100644 --- a/arch/arm/mach-mx5/board-mx51_efikasb.c +++ b/arch/arm/mach-mx5/board-mx51_efikasb.c @@ -270,6 +270,11 @@ static struct sys_timer mx51_efikasb_timer = { .init = mx51_efikasb_timer_init, }; +static const char *mx51_efikasb_dt_match[] __initdata = { + "genesi,efikasb", + NULL +}; + MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook") .boot_params = MX51_PHYS_OFFSET + 0x100, .map_io = mx51_map_io, @@ -277,4 +282,5 @@ MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook") .init_irq = mx51_init_irq, .init_machine = efikasb_board_init, .timer = &mx51_efikasb_timer, + .dt_compat = mx51_efikasb_dt_match, MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c index 1b947e8c9c0..bead01802fb 100644 --- a/arch/arm/mach-mx5/board-mx53_loco.c +++ b/arch/arm/mach-mx5/board-mx53_loco.c @@ -249,10 +249,15 @@ static struct sys_timer mx53_loco_timer = { .init = mx53_loco_timer_init, }; +static const char *mx53_loco_dt_match[] __initdata = { + "fsl,mx53-loco", + NULL +}; MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board") .map_io = mx53_map_io, .init_early = imx53_init_early, .init_irq = mx53_init_irq, .timer = &mx53_loco_timer, .init_machine = mx53_loco_board_init, + .dt_compat = mx53_loco_dt_match, MACHINE_END diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot index 565aff7f37a..422c1700ccf 100644 --- a/arch/arm/mach-omap2/Makefile.boot +++ b/arch/arm/mach-omap2/Makefile.boot @@ -1,3 +1,9 @@ zreladdr-y := 0x80008000 params_phys-y := 0x80000100 initrd_phys-y := 0x80800000 + +dtb-$(CONFIG_MACH_OMAP3_BEAGLE) += omap3-beagle.dtb +dtb-$(CONFIG_MACH_OMAP4_PANDA) += omap4-panda.dtb +dtb-$(CONFIG_MACH_OVERO) += omap3-overo.dtb +dtb-$(CONFIG_MACH_IGEP0020) += isee-igep-v2.dtb +dtb-$(CONFIG_MACH_IGEP0030) += isee-igep-v3.dtb diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 0c1bfca3f73..4bcbee37ca9 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -698,6 +698,11 @@ static void __init igep_init(void) } } +static const char *igep2_dt_compat[] __initdata = { + "ISEE,igep-v2", + NULL +}; + MACHINE_START(IGEP0020, "IGEP v2 board") .boot_params = 0x80000100, .reserve = omap_reserve, @@ -706,8 +711,14 @@ MACHINE_START(IGEP0020, "IGEP v2 board") .init_irq = omap_init_irq, .init_machine = igep_init, .timer = &omap_timer, + .dt_compat = igep2_dt_compat, MACHINE_END +static const char *igep3_dt_compat[] __initdata = { + "ISEE,igep-v3", + NULL +}; + MACHINE_START(IGEP0030, "IGEP OMAP3 module") .boot_params = 0x80000100, .reserve = omap_reserve, @@ -716,4 +727,5 @@ MACHINE_START(IGEP0030, "IGEP OMAP3 module") .init_irq = omap_init_irq, .init_machine = igep_init, .timer = &omap_timer, + .dt_compat = &igep3_dt_compat, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 7f21d24bd43..1ae6be6e76b 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -591,6 +591,11 @@ static void __init omap3_beagle_init(void) beagle_opp_init(); } +static const char *omap3_beagle_dt_match[] __initdata = { + "ti,omap3-beagle", + NULL +}; + MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */ .boot_params = 0x80000100, @@ -600,4 +605,5 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") .init_irq = omap3_beagle_init_irq, .init_machine = omap3_beagle_init, .timer = &omap_timer, + .dt_compat = omap3_beagle_dt_match, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 0cfe2005cb5..c9d1e136677 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -708,6 +708,11 @@ static void __init omap4_panda_map_io(void) omap44xx_map_common_io(); } +static const char *omap4_panda_match[] __initdata = { + "ti,omap4-panda", + NULL, +}; + MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") /* Maintainer: David Anders - Texas Instruments Inc */ .boot_params = 0x80000100, @@ -717,4 +722,5 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") .init_irq = gic_init_irq, .init_machine = omap4_panda_init, .timer = &omap_timer, + .dt_compat = omap4_panda_match, MACHINE_END diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 175e1ab2b04..b32b4928fe8 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -610,6 +610,11 @@ static void __init overo_init(void) "OVERO_GPIO_USBH_CPEN\n"); } +static const char *omap3_overo_dt_match[] __initdata = { + "gumstix,omap3-overo", + NULL +}; + MACHINE_START(OVERO, "Gumstix Overo") .boot_params = 0x80000100, .reserve = omap_reserve, @@ -618,4 +623,5 @@ MACHINE_START(OVERO, "Gumstix Overo") .init_irq = omap_init_irq, .init_machine = overo_init, .timer = &omap_timer, + .dt_compat = omap3_overo_dt_match, MACHINE_END diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 87ae3129f4f..b27544bcafc 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -347,9 +347,9 @@ static int pxa2xx_mfp_suspend(void) if ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && (GPDR(i) & GPIO_bit(i))) { if (GPLR(i) & GPIO_bit(i)) - PGSR(i) |= GPIO_bit(i); + PGSR(gpio_to_bank(i)) |= GPIO_bit(i); else - PGSR(i) &= ~GPIO_bit(i); + PGSR(gpio_to_bank(i)) &= ~GPIO_bit(i); } } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index d130f77b6d1..2f37d43f51b 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -573,10 +573,10 @@ static struct pxafb_mode_info sharp_lq043t3dx02_mode = { .xres = 480, .yres = 272, .bpp = 16, - .hsync_len = 4, + .hsync_len = 41, .left_margin = 2, .right_margin = 1, - .vsync_len = 1, + .vsync_len = 10, .upper_margin = 3, .lower_margin = 1, .sync = 0, @@ -596,29 +596,31 @@ static void __init raumfeld_lcd_init(void) { int ret; - pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info); - - /* Earlier devices had the backlight regulator controlled - * via PWM, later versions use another controller for that */ - if ((system_rev & 0xff) < 2) { - mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT; - pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1); - platform_device_register(&raumfeld_pwm_backlight_device); - } else - platform_device_register(&raumfeld_lt3593_device); - ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); if (ret < 0) pr_warning("Unable to request GPIO_TFT_VA_EN\n"); else gpio_direction_output(GPIO_TFT_VA_EN, 1); + msleep(100); + ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); if (ret < 0) pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); else gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); + /* Hardware revision 2 has the backlight regulator controlled + * by an LT3593, earlier and later devices use PWM for that. */ + if ((system_rev & 0xff) == 2) { + platform_device_register(&raumfeld_lt3593_device); + } else { + mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT; + pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1); + platform_device_register(&raumfeld_pwm_backlight_device); + } + + pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info); platform_device_register(&pxa3xx_device_gcu); } @@ -657,10 +659,10 @@ static struct lis3lv02d_platform_data lis3_pdata = { #define SPI_AK4104 \ { \ - .modalias = "ak4104", \ - .max_speed_hz = 10000, \ - .bus_num = 0, \ - .chip_select = 0, \ + .modalias = "ak4104-codec", \ + .max_speed_hz = 10000, \ + .bus_num = 0, \ + .chip_select = 0, \ .controller_data = (void *) GPIO_SPDIF_CS, \ } diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c index b197171e7d0..204bfafe4bf 100644 --- a/arch/arm/mach-s3c64xx/dma.c +++ b/arch/arm/mach-s3c64xx/dma.c @@ -113,7 +113,7 @@ found: return chan; } -int s3c2410_dma_config(unsigned int channel, int xferunit) +int s3c2410_dma_config(enum dma_ch channel, int xferunit) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -297,7 +297,7 @@ static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan) return 0; } -int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op) +int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -331,7 +331,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl); * */ -int s3c2410_dma_enqueue(unsigned int channel, void *id, +int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -415,7 +415,7 @@ err_buff: EXPORT_SYMBOL(s3c2410_dma_enqueue); -int s3c2410_dma_devconfig(unsigned int channel, +int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr) { @@ -463,7 +463,7 @@ int s3c2410_dma_devconfig(unsigned int channel, EXPORT_SYMBOL(s3c2410_dma_devconfig); -int s3c2410_dma_getposition(unsigned int channel, +int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -487,7 +487,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition); * get control of an dma channel */ -int s3c2410_dma_request(unsigned int channel, +int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *client, void *dev) { @@ -533,7 +533,7 @@ EXPORT_SYMBOL(s3c2410_dma_request); * allowed to go through. */ -int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned long flags; diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 5ec1846aa1d..4b8abf93bd9 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -51,6 +51,12 @@ config MACH_SEABOARD also be included for some of the derivative boards that have large similarities with the seaboard design. +config MACH_TEGRA_DT + bool "Generic Tegra board (FDT support)" + select USE_OF + help + Support for generic nVidia Tegra boards using Flattened Device Tree + config MACH_TRIMSLICE bool "TrimSlice board" select TEGRA_PCI diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 823c703e573..6d3d695dc10 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -30,5 +30,8 @@ obj-${CONFIG_MACH_PAZ00} += board-paz00-pinmux.o obj-${CONFIG_MACH_SEABOARD} += board-seaboard.o obj-${CONFIG_MACH_SEABOARD} += board-seaboard-pinmux.o +obj-${CONFIG_MACH_TEGRA_DT} += board-dt.o +obj-${CONFIG_MACH_TEGRA_DT} += board-harmony-pinmux.o + obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice.o obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice-pinmux.o diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot index db52d61a738..428ad122be0 100644 --- a/arch/arm/mach-tegra/Makefile.boot +++ b/arch/arm/mach-tegra/Makefile.boot @@ -1,3 +1,6 @@ zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00008000 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00000100 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00800000 + +dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb +dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb diff --git a/arch/arm/mach-tegra/board-dt.c b/arch/arm/mach-tegra/board-dt.c new file mode 100644 index 00000000000..1e3fbc30758 --- /dev/null +++ b/arch/arm/mach-tegra/board-dt.c @@ -0,0 +1,117 @@ +/* + * nVidia Tegra device tree board support + * + * Copyright (C) 2010 Secret Lab Technologies, Ltd. + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/pda_power.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c-tegra.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/setup.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#include "board.h" +#include "board-harmony.h" +#include "clock.h" +#include "devices.h" + +void harmony_pinmux_init(void); +void seaboard_pinmux_init(void); + + +struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL), + {} +}; + +static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { + /* name parent rate enabled */ + { "uartd", "pll_p", 216000000, true }, + { NULL, NULL, 0, 0}, +}; + +static struct of_device_id tegra_dt_match_table[] __initdata = { + { .compatible = "simple-bus", }, + {} +}; + +static struct of_device_id tegra_dt_gic_match[] __initdata = { + { .compatible = "nvidia,tegra20-gic", }, + {} +}; + +static void __init tegra_dt_init(void) +{ + struct device_node *node; + + node = of_find_matching_node_by_address(NULL, tegra_dt_gic_match, + TEGRA_ARM_INT_DIST_BASE); + if (node) + irq_domain_add_simple(node, INT_GIC_BASE); + + tegra_clk_init_from_table(tegra_dt_clk_init_table); + + if (of_machine_is_compatible("nvidia,harmony")) + harmony_pinmux_init(); + else if (of_machine_is_compatible("nvidia,seaboard")) + seaboard_pinmux_init(); + + /* + * Finished with the static registrations now; fill in the missing + * devices + */ + of_platform_populate(NULL, tegra_dt_match_table, tegra20_auxdata_lookup, NULL); +} + +static const char * tegra_dt_board_compat[] = { + "nvidia,tegra20", + NULL +}; + +DT_MACHINE_START(TEGRA_DT, "nVidia Tegra (Flattened Device Tree)") + .map_io = tegra_map_common_io, + .init_early = tegra_init_early, + .init_irq = tegra_init_irq, + .timer = &tegra_timer, + .init_machine = tegra_dt_init, + .dt_compat = tegra_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c index 919d6383773..747eb40e8af 100644 --- a/arch/arm/mach-tegra/gpio.c +++ b/arch/arm/mach-tegra/gpio.c @@ -23,6 +23,7 @@ #include <linux/io.h> #include <linux/gpio.h> +#include <linux/of.h> #include <asm/mach/irq.h> @@ -340,6 +341,15 @@ static int __init tegra_gpio_init(void) } } +#ifdef CONFIG_OF_GPIO + /* + * This isn't ideal, but it gets things hooked up until this + * driver is converted into a platform_device + */ + tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL, + "nvidia,tegra20-gpio"); +#endif /* CONFIG_OF_GPIO */ + gpiochip_add(&tegra_gpio_chip); for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig index 9cdec5aa04a..c1f38f6625b 100644 --- a/arch/arm/mach-versatile/Kconfig +++ b/arch/arm/mach-versatile/Kconfig @@ -17,4 +17,12 @@ config MACH_VERSATILE_AB Include support for the ARM(R) Versatile Application Baseboard for the ARM926EJ-S. +config MACH_VERSATILE_DT + bool "Support Versatile platform from device tree" + select USE_OF + select CPU_ARM926T + help + Include support for the ARM(R) Versatile/PB platform, + using the device tree for discovery + endmenu diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index 97cf4d831b0..81fa3fe25e1 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile @@ -5,4 +5,5 @@ obj-y := core.o obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o +obj-$(CONFIG_MACH_VERSATILE_DT) += versatile_dt.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot index c7e75acfe6c..e2227d3c23c 100644 --- a/arch/arm/mach-versatile/Makefile.boot +++ b/arch/arm/mach-versatile/Makefile.boot @@ -2,3 +2,5 @@ params_phys-y := 0x00000100 initrd_phys-y := 0x00800000 +dtb-$(CONFIG_ARCH_VERSATILE_PB) += versatile-pb.dtb +dtb-$(CONFIG_MACH_VERSATILE_AB) += versatile-ab.dtb diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 0c99cf076c6..4770dcd0986 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -24,6 +24,8 @@ #include <linux/platform_device.h> #include <linux/sysdev.h> #include <linux/interrupt.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> #include <linux/amba/pl061.h> @@ -83,13 +85,26 @@ static struct fpga_irq_data sic_irq = { #define PIC_MASK 0 #endif +/* Lookup table for finding a DT node that represents the vic instance */ +static const struct of_device_id vic_of_match[] __initconst = { + { .compatible = "arm,versatile-vic", }, + {} +}; + +static const struct of_device_id sic_of_match[] __initconst = { + { .compatible = "arm,versatile-sic", }, + {} +}; + void __init versatile_init_irq(void) { vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); + irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq); + irq_domain_generate_simple(sic_of_match, VERSATILE_SIC_BASE, IRQ_SIC_START); /* * Interrupts on secondary controller from 0 to 8 are routed to @@ -646,6 +661,52 @@ static struct amba_device *amba_devs[] __initdata = { &kmi1_device, }; +#ifdef CONFIG_OF +/* + * Lookup table for attaching a specific name and platform_data pointer to + * devices as they get created by of_platform_populate(). Ideally this table + * would not exist, but the current clock implementation depends on some devices + * having a specific name. + */ +struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI0_BASE, "fpga:06", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI1_BASE, "fpga:07", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART3_BASE, "fpga:09", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", NULL), + + OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART0_BASE, "dev:f1", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART1_BASE, "dev:f2", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART2_BASE, "dev:f3", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_SSP_BASE, "dev:f4", NULL), + +#if 0 + /* + * These entries are unnecessary because no clocks referencing + * them. I've left them in for now as place holders in case + * any of them need to be added back, but they should be + * removed before actually committing this patch. --gcl + */ + OF_DEV_AUXDATA("arm,primecell", VERSATILE_AACI_BASE, "fpga:04", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI1_BASE, "fpga:0a", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_SMC_BASE, "dev:00", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_MPMC_BASE, "dev:10", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_DMAC_BASE, "dev:30", NULL), + + OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCTL_BASE, "dev:e0", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_WATCHDOG_BASE, "dev:e1", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO0_BASE, "dev:e4", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO1_BASE, "dev:e5", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO2_BASE, "dev:e6", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO3_BASE, "dev:e7", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_RTC_BASE, "dev:e8", NULL), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI_BASE, "dev:f0", NULL), +#endif + {} +}; +#endif + #ifdef CONFIG_LEDS #define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h index fd6404e5d78..70b155512f0 100644 --- a/arch/arm/mach-versatile/core.h +++ b/arch/arm/mach-versatile/core.h @@ -23,6 +23,7 @@ #define __ASM_ARCH_VERSATILE_H #include <linux/amba/bus.h> +#include <linux/of_platform.h> extern void __init versatile_init(void); extern void __init versatile_init_early(void); @@ -30,6 +31,7 @@ extern void __init versatile_init_irq(void); extern void __init versatile_map_io(void); extern struct sys_timer versatile_timer; extern unsigned int mmc_status(struct device *dev); +extern struct of_dev_auxdata versatile_auxdata_lookup[]; #define AMBA_DEVICE(name,busid,base,plat) \ static struct amba_device name##_device = { \ diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c new file mode 100644 index 00000000000..54e037c090f --- /dev/null +++ b/arch/arm/mach-versatile/versatile_dt.c @@ -0,0 +1,51 @@ +/* + * Versatile board support using the device tree + * + * Copyright (C) 2010 Secret Lab Technologies Ltd. + * Copyright (C) 2009 Jeremy Kerr <jeremy.kerr@canonical.com> + * Copyright (C) 2004 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * 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 + */ + +#include <linux/init.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "core.h" + +static void __init versatile_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + versatile_auxdata_lookup, NULL); +} + +static const char *versatile_dt_match[] __initconst = { + "arm,versatile-ab", + "arm,versatile-pb", + NULL, +}; + +DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)") + .map_io = versatile_map_io, + .init_early = versatile_init_early, + .init_irq = versatile_init_irq, + .timer = &versatile_timer, + .init_machine = versatile_dt_init, + .dt_compat = versatile_dt_match, +MACHINE_END diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot index 07c2d9c457e..9920a1053e2 100644 --- a/arch/arm/mach-vexpress/Makefile.boot +++ b/arch/arm/mach-vexpress/Makefile.boot @@ -1,3 +1,5 @@ zreladdr-y := 0x60008000 params_phys-y := 0x60000100 initrd_phys-y := 0x60800000 + +dtb-$(CONFIG_ARCH_VEXPRESS_CA9X4) += vexpress.dtb diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 9e6b93b1a04..08b7ce91d71 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -435,6 +435,11 @@ static void __init v2m_init(void) ct_desc->init_tile(); } +static const char *vexpress_dt_match[] __initdata = { + "arm,vexpress", + NULL, +}; + MACHINE_START(VEXPRESS, "ARM-Versatile Express") .boot_params = PLAT_PHYS_OFFSET + 0x00000100, .map_io = v2m_map_io, @@ -442,4 +447,5 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express") .init_irq = v2m_init_irq, .timer = &v2m_timer, .init_machine = v2m_init, + .dt_compat = vexpress_dt_match, MACHINE_END diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index 5b4fffab1eb..41ab97ebe4c 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -432,7 +432,7 @@ void __init orion_gpio_init(int gpio_base, int ngpio, ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; ct->regs.ack = GPIO_EDGE_CAUSE_OFF; ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_clr_bit; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_set_type = gpio_irq_set_type; diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c index 48ebb9479b6..a11dc367050 100644 --- a/arch/arm/plat-pxa/gpio.c +++ b/arch/arm/plat-pxa/gpio.c @@ -50,7 +50,7 @@ static inline void __iomem *gpio_chip_base(struct gpio_chip *c) return container_of(c, struct pxa_gpio_chip, chip)->regbase; } -static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio) +static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) { return &pxa_gpio_chips[gpio_to_bank(gpio)]; } @@ -161,7 +161,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) int gpio = irq_to_gpio(d->irq); unsigned long gpdr, mask = GPIO_bit(gpio); - c = gpio_to_chip(gpio); + c = gpio_to_pxachip(gpio); if (type == IRQ_TYPE_PROBE) { /* Don't mess with enabled GPIOs using preconfigured edges or @@ -230,7 +230,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) static void pxa_ack_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); } @@ -238,7 +238,7 @@ static void pxa_ack_muxed_gpio(struct irq_data *d) static void pxa_mask_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); uint32_t grer, gfer; c->irq_mask &= ~GPIO_bit(gpio); @@ -252,7 +252,7 @@ static void pxa_mask_muxed_gpio(struct irq_data *d) static void pxa_unmask_muxed_gpio(struct irq_data *d) { int gpio = irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); c->irq_mask |= GPIO_bit(gpio); update_edge_detect(c); diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index a79a8ccd25f..539bd0e3def 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -712,7 +712,7 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); * get control of an dma channel */ -int s3c2410_dma_request(unsigned int channel, +int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *client, void *dev) { @@ -783,7 +783,7 @@ EXPORT_SYMBOL(s3c2410_dma_request); * allowed to go through. */ -int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned long flags; @@ -974,7 +974,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan) } int -s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op) +s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -1021,7 +1021,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl); * xfersize: size of unit in bytes (1,2,4) */ -int s3c2410_dma_config(unsigned int channel, +int s3c2410_dma_config(enum dma_ch channel, int xferunit) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -1100,7 +1100,7 @@ EXPORT_SYMBOL(s3c2410_dma_config); * devaddr: physical address of the source */ -int s3c2410_dma_devconfig(unsigned int channel, +int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr) { @@ -1173,7 +1173,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig); * returns the current transfer points for the dma source and destination */ -int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst) +int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index 135abda31c9..327ab9f662e 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -152,7 +152,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) if (!gc) return -ENOMEM; ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->chip.irq_set_type = s5p_gpioint_set_type, diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c index cb459dd9545..6143aa14768 100644 --- a/arch/arm/plat-samsung/dma.c +++ b/arch/arm/plat-samsung/dma.c @@ -41,7 +41,7 @@ struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel) * irq? */ -int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) +int s3c2410_dma_set_opfn(enum dma_ch channel, s3c2410_dma_opfn_t rtn) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -56,7 +56,7 @@ int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) } EXPORT_SYMBOL(s3c2410_dma_set_opfn); -int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) +int s3c2410_dma_set_buffdone_fn(enum dma_ch channel, s3c2410_dma_cbfn_t rtn) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -71,7 +71,7 @@ int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) } EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); -int s3c2410_dma_setflags(unsigned int channel, unsigned int flags) +int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index 2e8f8c6560d..8c273b7a6f5 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -42,6 +42,7 @@ struct s3c2410_dma_client { }; struct s3c2410_dma_chan; +enum dma_ch; /* s3c2410_dma_cbfn_t * @@ -62,7 +63,7 @@ typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, * request a dma channel exclusivley */ -extern int s3c2410_dma_request(unsigned int channel, +extern int s3c2410_dma_request(enum dma_ch channel, struct s3c2410_dma_client *, void *dev); @@ -71,14 +72,14 @@ extern int s3c2410_dma_request(unsigned int channel, * change the state of the dma channel */ -extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op); +extern int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op); /* s3c2410_dma_setflags * * set the channel's flags to a given state */ -extern int s3c2410_dma_setflags(unsigned int channel, +extern int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags); /* s3c2410_dma_free @@ -86,7 +87,7 @@ extern int s3c2410_dma_setflags(unsigned int channel, * free the dma channel (will also abort any outstanding operations) */ -extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); +extern int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *); /* s3c2410_dma_enqueue * @@ -95,7 +96,7 @@ extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); * drained before the buffer is given to the DMA system. */ -extern int s3c2410_dma_enqueue(unsigned int channel, void *id, +extern int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size); /* s3c2410_dma_config @@ -103,14 +104,14 @@ extern int s3c2410_dma_enqueue(unsigned int channel, void *id, * configure the dma channel */ -extern int s3c2410_dma_config(unsigned int channel, int xferunit); +extern int s3c2410_dma_config(enum dma_ch channel, int xferunit); /* s3c2410_dma_devconfig * * configure the device we're talking to */ -extern int s3c2410_dma_devconfig(unsigned int channel, +extern int s3c2410_dma_devconfig(enum dma_ch channel, enum s3c2410_dmasrc source, unsigned long devaddr); /* s3c2410_dma_getposition @@ -118,10 +119,10 @@ extern int s3c2410_dma_devconfig(unsigned int channel, * get the position that the dma transfer is currently at */ -extern int s3c2410_dma_getposition(unsigned int channel, +extern int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dest); -extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn); -extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn); +extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); +extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c index 32582c0958e..657405c481d 100644 --- a/arch/arm/plat-samsung/irq-uart.c +++ b/arch/arm/plat-samsung/irq-uart.c @@ -54,8 +54,15 @@ static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq) gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base, handle_level_irq); + + if (!gc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n", + __func__, uirq->base_irq); + return; + } + ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->regs.ack = S3C64XX_UINTP; diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c index a607546ddbd..f714d060370 100644 --- a/arch/arm/plat-samsung/irq-vic-timer.c +++ b/arch/arm/plat-samsung/irq-vic-timer.c @@ -54,6 +54,13 @@ void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq) s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq, S3C64XX_TINT_CSTAT, handle_level_irq); + + if (!s3c_tgc) { + pr_err("%s: irq_alloc_generic_chip for IRQ %d failed\n", + __func__, timer_irq); + return; + } + ct = s3c_tgc->chip_types; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index cc54187f3d3..6a6d83bfc1a 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -16,6 +16,7 @@ * be big enough to enclose whatever representation is used by a given * platform. */ +#define _IRQ_HW_NUMBER_T typedef unsigned long irq_hw_number_t; extern unsigned int nr_irq; @@ -25,15 +26,6 @@ extern unsigned int nr_irq; struct pt_regs; extern void do_IRQ(struct pt_regs *regs); -/** FIXME - not implement - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ - return; -} - struct irq_host; /** diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index ce7ac8435d5..59bb560018e 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -54,10 +54,3 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) return hwirq; } EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 0ec01294b06..dc650aeac78 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -16,11 +16,6 @@ #include <irq.h> -static inline void irq_dispose_mapping(unsigned int virq) -{ - return; -} - #ifdef CONFIG_I8259 static inline int irq_canonicalize(int irq) { diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index c018696765d..5c74eb797f0 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -14,7 +14,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spinlock.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> #include <linux/irq.h> #include <asm/i8259.h> @@ -215,14 +215,13 @@ spurious_8259A_irq: } } -static int i8259A_resume(struct sys_device *dev) +static void i8259A_resume(void) { if (i8259A_auto_eoi >= 0) init_8259A(i8259A_auto_eoi); - return 0; } -static int i8259A_shutdown(struct sys_device *dev) +static void i8259A_shutdown(void) { /* Put the i8259A into a quiescent state that * the kernel initialization code can get it @@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_device *dev) outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ } - return 0; } -static struct sysdev_class i8259_sysdev_class = { - .name = "i8259", +static struct syscore_ops i8259_syscore_ops = { .resume = i8259A_resume, .shutdown = i8259A_shutdown, }; -static struct sys_device device_i8259A = { - .id = 0, - .cls = &i8259_sysdev_class, -}; - static int __init i8259A_init_sysfs(void) { - int error = sysdev_class_register(&i8259_sysdev_class); - if (!error) - error = sysdev_register(&device_i8259A); - return error; + register_syscore_ops(&i8259_syscore_ops); + return 0; } device_initcall(i8259A_init_sysfs); diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 5b7eade41fa..010aaaf2278 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start, } #endif -/* - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# - * - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are - * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not - * supported. - */ -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - void __init early_init_devtree(void *params) { /* Setup flat device-tree pointer */ diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 1bff591f7f7..66bf09e21cb 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -45,6 +45,7 @@ extern atomic_t ppc_n_lost_interrupts; * be big enough to enclose whatever representation is used by a given * platform. */ +#define _IRQ_HW_NUMBER_T typedef unsigned long irq_hw_number_t; /* Interrupt controller "host" data structure. This could be defined as a diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 33867ec4a23..9d6a8effeda 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -12,6 +12,8 @@ #include <linux/of.h> #include <linux/memblock.h> #include <linux/vmalloc.h> +#include <linux/memory.h> + #include <asm/firmware.h> #include <asm/machdep.h> #include <asm/pSeries_reconfig.h> @@ -20,24 +22,25 @@ static unsigned long get_memblock_size(void) { struct device_node *np; - unsigned int memblock_size = 0; + unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE; + struct resource r; np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); if (np) { - const unsigned long *size; + const __be64 *size; size = of_get_property(np, "ibm,lmb-size", NULL); - memblock_size = size ? *size : 0; - + if (size) + memblock_size = be64_to_cpup(size); of_node_put(np); - } else { + } else if (machine_is(pseries)) { + /* This fallback really only applies to pseries */ unsigned int memzero_size = 0; - const unsigned int *regs; np = of_find_node_by_path("/memory@0"); if (np) { - regs = of_get_property(np, "reg", NULL); - memzero_size = regs ? regs[3] : 0; + if (!of_address_to_resource(np, 0, &r)) + memzero_size = resource_size(&r); of_node_put(np); } @@ -50,16 +53,21 @@ static unsigned long get_memblock_size(void) sprintf(buf, "/memory@%x", memzero_size); np = of_find_node_by_path(buf); if (np) { - regs = of_get_property(np, "reg", NULL); - memblock_size = regs ? regs[3] : 0; + if (!of_address_to_resource(np, 0, &r)) + memblock_size = resource_size(&r); of_node_put(np); } } } - return memblock_size; } +/* WARNING: This is going to override the generic definition whenever + * pseries is built-in regardless of what platform is active at boot + * time. This is fine for now as this is the only "option" and it + * should work everywhere. If not, we'll have to turn this into a + * ppc_md. callback + */ unsigned long memory_block_size_bytes(void) { return get_memblock_size(); diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h index d4d0711de0f..14848909e0d 100644 --- a/arch/sparc/include/asm/irqflags_32.h +++ b/arch/sparc/include/asm/irqflags_32.h @@ -18,7 +18,7 @@ extern void arch_local_irq_restore(unsigned long); extern unsigned long arch_local_irq_save(void); extern void arch_local_irq_enable(void); -static inline unsigned long arch_local_save_flags(void) +static inline notrace unsigned long arch_local_save_flags(void) { unsigned long flags; @@ -26,17 +26,17 @@ static inline unsigned long arch_local_save_flags(void) return flags; } -static inline void arch_local_irq_disable(void) +static inline notrace void arch_local_irq_disable(void) { arch_local_irq_save(); } -static inline bool arch_irqs_disabled_flags(unsigned long flags) +static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) { return (flags & PSR_PIL) != 0; } -static inline bool arch_irqs_disabled(void) +static inline notrace bool arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h index aab969c82c2..23cd27f6beb 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h @@ -14,7 +14,7 @@ #ifndef __ASSEMBLY__ -static inline unsigned long arch_local_save_flags(void) +static inline notrace unsigned long arch_local_save_flags(void) { unsigned long flags; @@ -26,7 +26,7 @@ static inline unsigned long arch_local_save_flags(void) return flags; } -static inline void arch_local_irq_restore(unsigned long flags) +static inline notrace void arch_local_irq_restore(unsigned long flags) { __asm__ __volatile__( "wrpr %0, %%pil" @@ -36,7 +36,7 @@ static inline void arch_local_irq_restore(unsigned long flags) ); } -static inline void arch_local_irq_disable(void) +static inline notrace void arch_local_irq_disable(void) { __asm__ __volatile__( "wrpr %0, %%pil" @@ -46,7 +46,7 @@ static inline void arch_local_irq_disable(void) ); } -static inline void arch_local_irq_enable(void) +static inline notrace void arch_local_irq_enable(void) { __asm__ __volatile__( "wrpr 0, %%pil" @@ -56,17 +56,17 @@ static inline void arch_local_irq_enable(void) ); } -static inline int arch_irqs_disabled_flags(unsigned long flags) +static inline notrace int arch_irqs_disabled_flags(unsigned long flags) { return (flags > 0); } -static inline int arch_irqs_disabled(void) +static inline notrace int arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } -static inline unsigned long arch_local_irq_save(void) +static inline notrace unsigned long arch_local_irq_save(void) { unsigned long flags, tmp; diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index c7ad3fe2b25..b928b31424b 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -205,6 +205,7 @@ do { current_thread_info()->syscall_noerror = 1; \ } while (0) #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) #define instruction_pointer(regs) ((regs)->tpc) +#define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) #define regs_return_value(regs) ((regs)->u_regs[UREG_I0]) #ifdef CONFIG_SMP diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 9fe08a1ea6c..f445e98463e 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -293,7 +293,7 @@ maybe_smp4m_msg: WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE - sll %o3, 28, %o2 ! shift for simpler checks below + srl %o3, 28, %o2 ! shift for simpler checks below maybe_smp4m_msg_check_single: andcc %o2, 0x1, %g0 beq,a maybe_smp4m_msg_check_mask diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index c0e01297e64..e485a680499 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -226,7 +226,7 @@ void leon3_getCacheRegs(struct leon3_cacheregs *regs) * Leon2 and Leon3 differ in their way of telling cache information * */ -int leon_flush_needed(void) +int __init leon_flush_needed(void) { int flush_needed = -1; unsigned int ssize, sets; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index da349723d41..37357a599dc 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1170,7 +1170,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" - depends on NUMA && PCI + depends on X86_64 && NUMA && PCI ---help--- Enable AMD NUMA node topology detection. You should say Y here if you have a multi processor AMD system. This uses an old method to diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h deleted file mode 100644 index 423bbbddf36..00000000000 --- a/arch/x86/include/asm/irq_controller.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __IRQ_CONTROLLER__ -#define __IRQ_CONTROLLER__ - -struct irq_domain { - int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type); - void *priv; - struct device_node *controller; - struct list_head l; -}; - -#endif diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h index 971e0b46446..2c8101e9279 100644 --- a/arch/x86/include/asm/prom.h +++ b/arch/x86/include/asm/prom.h @@ -21,7 +21,6 @@ #include <asm/irq.h> #include <asm/atomic.h> #include <asm/setup.h> -#include <asm/irq_controller.h> #ifdef CONFIG_OF extern int of_ioapic; @@ -54,15 +53,6 @@ extern char cmd_line[COMMAND_LINE_SIZE]; #define pci_address_to_pio pci_address_to_pio unsigned long pci_address_to_pio(phys_addr_t addr); -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - * - * FIXME: We really should implement proper virq handling like power, - * but that's going to be major surgery. - */ -static inline void irq_dispose_mapping(unsigned int virq) { } - #define HAVE_ARCH_DEVTREE_FIXUPS #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 9aeb78a23de..250c2d583f6 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -16,64 +16,14 @@ #include <linux/initrd.h> #include <asm/hpet.h> -#include <asm/irq_controller.h> #include <asm/apic.h> #include <asm/pci_x86.h> __initdata u64 initial_dtb; char __initdata cmd_line[COMMAND_LINE_SIZE]; -static LIST_HEAD(irq_domains); -static DEFINE_RAW_SPINLOCK(big_irq_lock); int __initdata of_ioapic; -#ifdef CONFIG_X86_IO_APIC -static void add_interrupt_host(struct irq_domain *ih) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_add(&ih->l, &irq_domains); - raw_spin_unlock_irqrestore(&big_irq_lock, flags); -} -#endif - -static struct irq_domain *get_ih_from_node(struct device_node *controller) -{ - struct irq_domain *ih, *found = NULL; - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_for_each_entry(ih, &irq_domains, l) { - if (ih->controller == controller) { - found = ih; - break; - } - } - raw_spin_unlock_irqrestore(&big_irq_lock, flags); - return found; -} - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_domain *ih; - u32 virq, type; - int ret; - - ih = get_ih_from_node(controller); - if (!ih) - return 0; - ret = ih->xlate(ih, intspec, intsize, &virq, &type); - if (ret) - return 0; - if (type == IRQ_TYPE_NONE) - return virq; - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - unsigned long pci_address_to_pio(phys_addr_t address) { /* @@ -377,36 +327,49 @@ static struct of_ioapic_type of_ioapic_type[] = }, }; -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type) +static int ioapic_dt_translate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, u32 intsize, + irq_hw_number_t *out_hwirq, u32 *out_type) { - struct mp_ioapic_gsi *gsi_cfg; struct io_apic_irq_attr attr; struct of_ioapic_type *it; u32 line, idx, type; + int rc; - if (intsize < 2) + if (controller != domain->of_node) return -EINVAL; - line = *intspec; - idx = (u32) id->priv; - gsi_cfg = mp_ioapic_gsi_routing(idx); - *out_hwirq = line + gsi_cfg->gsi_base; + if (intsize < 2) + return -EINVAL; - intspec++; - type = *intspec; + line = intspec[0]; - if (type >= ARRAY_SIZE(of_ioapic_type)) + if (intspec[1] >= ARRAY_SIZE(of_ioapic_type)) return -EINVAL; - it = of_ioapic_type + type; - *out_type = it->out_type; + it = of_ioapic_type + intspec[1]; + type = it->out_type; + idx = (u32) domain->priv; set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); - return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); + rc = io_apic_setup_irq_pin_once(irq_domain_to_irq(domain, line), + cpu_to_node(0), &attr); + if (rc) + return rc; + + if (out_hwirq) + *out_hwirq = line; + if (out_type) + *out_type = type; + return 0; } +const struct irq_domain_ops ioapic_irq_domain_ops = { + .dt_translate = ioapic_dt_translate, +}; + static void __init ioapic_add_ofnode(struct device_node *np) { struct resource r; @@ -422,13 +385,17 @@ static void __init ioapic_add_ofnode(struct device_node *np) for (i = 0; i < nr_ioapics; i++) { if (r.start == mpc_ioapic_addr(i)) { struct irq_domain *id; + struct mp_ioapic_gsi *gsi_cfg; + + gsi_cfg = mp_ioapic_gsi_routing(i); id = kzalloc(sizeof(*id), GFP_KERNEL); BUG_ON(!id); - id->controller = np; - id->xlate = ioapic_xlate; + id->ops = &ioapic_irq_domain_ops; + id->irq_base = gsi_cfg->gsi_base; + id->of_node = np; id->priv = (void *)i; - add_interrupt_host(id); + irq_domain_add(id); return; } } diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 4f0d46fefa7..9242436e993 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -419,6 +419,30 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), }, }, + { /* Handle problems with rebooting on the Latitude E6320. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E6320", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), + }, + }, + { /* Handle problems with rebooting on the Latitude E5420. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E5420", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), + }, + }, + { /* Handle problems with rebooting on the Latitude E6420. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E6420", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), + }, + }, { } }; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index d865c4aeec5..bbaaa005bf0 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -28,6 +28,7 @@ #include <linux/poison.h> #include <linux/dma-mapping.h> #include <linux/module.h> +#include <linux/memory.h> #include <linux/memory_hotplug.h> #include <linux/nmi.h> #include <linux/gfp.h> @@ -895,8 +896,6 @@ const char *arch_vma_name(struct vm_area_struct *vma) } #ifdef CONFIG_X86_UV -#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) - unsigned long memory_block_size_bytes(void) { if (is_uv_system()) { diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index abda3786a5d..181bc2f7bb7 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -139,13 +139,23 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) { struct platform_device *ghes_dev; struct ghes_arr *ghes_arr = data; - int rc; + int rc, i; if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) return 0; if (!((struct acpi_hest_generic *)hest_hdr)->enabled) return 0; + for (i = 0; i < ghes_arr->count; i++) { + struct acpi_hest_header *hdr; + ghes_dev = ghes_arr->ghes_devs[i]; + hdr = *(struct acpi_hest_header **)ghes_dev->dev.platform_data; + if (hdr->source_id == hest_hdr->source_id) { + pr_warning(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n", + hdr->source_id); + return -EIO; + } + } ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id); if (!ghes_dev) return -ENOMEM; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 52ca9649d76..372f9b70f7f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1333,23 +1333,6 @@ int acpi_resources_are_enforced(void) EXPORT_SYMBOL(acpi_resources_are_enforced); /* - * Create and initialize a spinlock. - */ -acpi_status -acpi_os_create_lock(acpi_spinlock *out_handle) -{ - spinlock_t *lock; - - lock = ACPI_ALLOCATE(sizeof(spinlock_t)); - if (!lock) - return AE_NO_MEMORY; - spin_lock_init(lock); - *out_handle = lock; - - return AE_OK; -} - -/* * Deallocate the memory for a spinlock. */ void acpi_os_delete_lock(acpi_spinlock handle) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 9f9b2359f71..45d7c8fc73b 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -30,7 +30,6 @@ static DEFINE_MUTEX(mem_sysfs_mutex); #define MEMORY_CLASS_NAME "memory" -#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) static int sections_per_block; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 6c7fd7db6df..fb1975d82a7 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1155,12 +1155,19 @@ static int __devinit ace_probe(struct platform_device *dev) { resource_size_t physaddr = 0; int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */ - int id = dev->id; + u32 id = dev->id; int irq = NO_IRQ; int i; dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); + /* device id and bus width */ + of_property_read_u32(dev->dev.of_node, "port-number", &id); + if (id < 0) + id = 0; + if (of_find_property(dev->dev.of_node, "8-bit", NULL)) + bus_width = ACE_BUS_WIDTH_8; + for (i = 0; i < dev->num_resources; i++) { if (dev->resource[i].flags & IORESOURCE_MEM) physaddr = dev->resource[i].start; @@ -1181,57 +1188,7 @@ static int __devexit ace_remove(struct platform_device *dev) return 0; } -static struct platform_driver ace_platform_driver = { - .probe = ace_probe, - .remove = __devexit_p(ace_remove), - .driver = { - .owner = THIS_MODULE, - .name = "xsysace", - }, -}; - -/* --------------------------------------------------------------------- - * OF_Platform Bus Support - */ - #if defined(CONFIG_OF) -static int __devinit ace_of_probe(struct platform_device *op) -{ - struct resource res; - resource_size_t physaddr; - const u32 *id; - int irq, bus_width, rc; - - /* device id */ - id = of_get_property(op->dev.of_node, "port-number", NULL); - - /* physaddr */ - rc = of_address_to_resource(op->dev.of_node, 0, &res); - if (rc) { - dev_err(&op->dev, "invalid address\n"); - return rc; - } - physaddr = res.start; - - /* irq */ - irq = irq_of_parse_and_map(op->dev.of_node, 0); - - /* bus width */ - bus_width = ACE_BUS_WIDTH_16; - if (of_find_property(op->dev.of_node, "8-bit", NULL)) - bus_width = ACE_BUS_WIDTH_8; - - /* Call the bus-independent setup code */ - return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0, - physaddr, irq, bus_width); -} - -static int __devexit ace_of_remove(struct platform_device *op) -{ - ace_free(&op->dev); - return 0; -} - /* Match table for of_platform binding */ static const struct of_device_id ace_of_match[] __devinitconst = { { .compatible = "xlnx,opb-sysace-1.00.b", }, @@ -1241,34 +1198,20 @@ static const struct of_device_id ace_of_match[] __devinitconst = { {}, }; MODULE_DEVICE_TABLE(of, ace_of_match); +#else /* CONFIG_OF */ +#define ace_of_match NULL +#endif /* CONFIG_OF */ -static struct platform_driver ace_of_driver = { - .probe = ace_of_probe, - .remove = __devexit_p(ace_of_remove), +static struct platform_driver ace_platform_driver = { + .probe = ace_probe, + .remove = __devexit_p(ace_remove), .driver = { - .name = "xsysace", .owner = THIS_MODULE, + .name = "xsysace", .of_match_table = ace_of_match, }, }; -/* Registration helpers to keep the number of #ifdefs to a minimum */ -static inline int __init ace_of_register(void) -{ - pr_debug("xsysace: registering OF binding\n"); - return platform_driver_register(&ace_of_driver); -} - -static inline void __exit ace_of_unregister(void) -{ - platform_driver_unregister(&ace_of_driver); -} -#else /* CONFIG_OF */ -/* CONFIG_OF not enabled; do nothing helpers */ -static inline int __init ace_of_register(void) { return 0; } -static inline void __exit ace_of_unregister(void) { } -#endif /* CONFIG_OF */ - /* --------------------------------------------------------------------- * Module init/exit routines */ @@ -1282,11 +1225,6 @@ static int __init ace_init(void) goto err_blk; } - rc = ace_of_register(); - if (rc) - goto err_of; - - pr_debug("xsysace: registering platform binding\n"); rc = platform_driver_register(&ace_platform_driver); if (rc) goto err_plat; @@ -1295,21 +1233,17 @@ static int __init ace_init(void) return 0; err_plat: - ace_of_unregister(); -err_of: unregister_blkdev(ace_major, "xsysace"); err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); return rc; } +module_init(ace_init); static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); platform_driver_unregister(&ace_platform_driver); - ace_of_unregister(); unregister_blkdev(ace_major, "xsysace"); } - -module_init(ace_init); module_exit(ace_exit); diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 999803ce10d..5da67f165af 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -90,9 +90,10 @@ #define G4x_GMCH_SIZE_MASK (0xf << 8) #define G4x_GMCH_SIZE_1M (0x1 << 8) #define G4x_GMCH_SIZE_2M (0x3 << 8) -#define G4x_GMCH_SIZE_VT_1M (0x9 << 8) -#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8) -#define G4x_GMCH_SIZE_VT_2M (0xc << 8) +#define G4x_GMCH_SIZE_VT_EN (0x8 << 8) +#define G4x_GMCH_SIZE_VT_1M (G4x_GMCH_SIZE_1M | G4x_GMCH_SIZE_VT_EN) +#define G4x_GMCH_SIZE_VT_1_5M ((0x2 << 8) | G4x_GMCH_SIZE_VT_EN) +#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN) #define GFX_FLSH_CNTL 0x2170 /* 915+ */ diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index 309644cf4d9..2bcfb0be09f 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -180,6 +180,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) break; case WM831X_GPIO_PULL_UP: pull = "pullup"; + break; default: pull = "INVALID PULL"; break; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e1787022d6c..296fbd66f0e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1943,7 +1943,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!dev_priv->mm.gtt) { DRM_ERROR("Failed to initialize GTT\n"); ret = -ENODEV; - goto out_iomapfree; + goto out_rmmap; } agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; @@ -1987,7 +1987,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); ret = -ENOMEM; - goto out_iomapfree; + goto out_mtrrfree; } /* enable GEM by default */ @@ -2074,13 +2074,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; out_gem_unload: + if (dev_priv->mm.inactive_shrinker.shrink) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); + if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); -out_iomapfree: +out_mtrrfree: + if (dev_priv->mm.gtt_mtrr >= 0) { + mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, + dev->agp->agp_info.aper_size * 1024 * 1024); + dev_priv->mm.gtt_mtrr = -1; + } io_mapping_free(dev_priv->mm.gtt_mapping); out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 013d304455b..eb91e2dd791 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -52,7 +52,7 @@ module_param_named(powersave, i915_powersave, int, 0600); unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); -unsigned int i915_enable_rc6 = 1; +unsigned int i915_enable_rc6 = 0; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); unsigned int i915_enable_fbc = 0; @@ -577,6 +577,7 @@ int i915_reset(struct drm_device *dev, u8 flags) if (get_seconds() - dev_priv->last_gpu_reset < 5) { DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); } else switch (INTEL_INFO(dev)->gen) { + case 7: case 6: ret = gen6_do_reset(dev, flags); /* If reset with a user forcewake, try to restore */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f245c588ae9..ce7914c4c04 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -262,6 +262,7 @@ enum intel_pch { }; #define QUIRK_PIPEA_FORCE (1<<0) +#define QUIRK_LVDS_SSC_DISABLE (1<<1) struct intel_fbdev; @@ -1194,7 +1195,9 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); +i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode); /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5c0d1247f45..a087e1bf0c2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1374,25 +1374,24 @@ i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj) } static uint32_t -i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { - struct drm_device *dev = obj->base.dev; - uint32_t size; + uint32_t gtt_size; if (INTEL_INFO(dev)->gen >= 4 || - obj->tiling_mode == I915_TILING_NONE) - return obj->base.size; + tiling_mode == I915_TILING_NONE) + return size; /* Previous chips need a power-of-two fence region when tiling */ if (INTEL_INFO(dev)->gen == 3) - size = 1024*1024; + gtt_size = 1024*1024; else - size = 512*1024; + gtt_size = 512*1024; - while (size < obj->base.size) - size <<= 1; + while (gtt_size < size) + gtt_size <<= 1; - return size; + return gtt_size; } /** @@ -1403,59 +1402,52 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) * potential fence register mapping. */ static uint32_t -i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) +i915_gem_get_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode) { - struct drm_device *dev = obj->base.dev; - /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4 || - obj->tiling_mode == I915_TILING_NONE) + tiling_mode == I915_TILING_NONE) return 4096; /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ - return i915_gem_get_gtt_size(obj); + return i915_gem_get_gtt_size(dev, size, tiling_mode); } /** * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an * unfenced object - * @obj: object to check + * @dev: the device + * @size: size of the object + * @tiling_mode: tiling mode of the object * * Return the required GTT alignment for an object, only taking into account * unfenced tiled surface requirements. */ uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj) +i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, + uint32_t size, + int tiling_mode) { - struct drm_device *dev = obj->base.dev; - int tile_height; - /* * Minimum alignment is 4k (GTT page size) for sane hw. */ if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || - obj->tiling_mode == I915_TILING_NONE) + tiling_mode == I915_TILING_NONE) return 4096; - /* - * Older chips need unfenced tiled buffers to be aligned to the left - * edge of an even tile row (where tile rows are counted as if the bo is - * placed in a fenced gtt region). + /* Previous hardware however needs to be aligned to a power-of-two + * tile height. The simplest method for determining this is to reuse + * the power-of-tile object size. */ - if (IS_GEN2(dev)) - tile_height = 16; - else if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) - tile_height = 32; - else - tile_height = 8; - - return tile_height * obj->stride * 2; + return i915_gem_get_gtt_size(dev, size, tiling_mode); } int @@ -2744,9 +2736,16 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, return -EINVAL; } - fence_size = i915_gem_get_gtt_size(obj); - fence_alignment = i915_gem_get_gtt_alignment(obj); - unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj); + fence_size = i915_gem_get_gtt_size(dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode); + unfenced_alignment = + i915_gem_get_unfenced_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 82d70fd9e93..99c4faa59d8 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -348,7 +348,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, /* Rebind if we need a change of alignment */ if (!obj->map_and_fenceable) { u32 unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(obj); + i915_gem_get_unfenced_gtt_alignment(dev, + obj->base.size, + args->tiling_mode); if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 21b6f93fe91..0f1c799afea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4305,7 +4305,8 @@ static void intel_update_watermarks(struct drm_device *dev) static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { - return dev_priv->lvds_use_ssc && i915_panel_use_ssc; + return dev_priv->lvds_use_ssc && i915_panel_use_ssc + && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); } static int i9xx_crtc_mode_set(struct drm_crtc *crtc, @@ -7810,6 +7811,15 @@ static void quirk_pipea_force (struct drm_device *dev) DRM_DEBUG_DRIVER("applying pipe a force quirk\n"); } +/* + * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason + */ +static void quirk_ssc_force_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE; +} + struct intel_quirk { int device; int subsystem_vendor; @@ -7838,6 +7848,9 @@ struct intel_quirk intel_quirks[] = { /* 855 & before need to leave pipe A & dpll A up */ { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, + + /* Lenovo U160 cannot use SSC on LVDS */ + { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 391b55f1cc7..e2aced6eec4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -50,7 +50,6 @@ struct intel_dp { bool has_audio; int force_audio; uint32_t color_range; - int dpms_mode; uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[4]; @@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) { int max_lane_count = 4; - if (intel_dp->dpcd[0] >= 0x11) { - max_lane_count = intel_dp->dpcd[2] & 0x1f; + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) { + max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f; switch (max_lane_count) { case 1: case 2: case 4: break; @@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { - int max_link_bw = intel_dp->dpcd[1]; + int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; switch (max_link_bw) { case DP_LINK_BW_1_62: @@ -774,7 +773,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* * Check for DPCD version > 1.1 and enhanced framing support */ - if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && + (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) { intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; intel_dp->DP |= DP_ENHANCED_FRAMING; } @@ -942,11 +942,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder) udelay(200); } +/* If the sink supports it, try to set the power state appropriately */ +static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +{ + int ret, i; + + /* Should have a valid DPCD by this point */ + if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) + return; + + if (mode != DRM_MODE_DPMS_ON) { + ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER, + DP_SET_POWER_D3); + if (ret != 1) + DRM_DEBUG_DRIVER("failed to write sink power state\n"); + } else { + /* + * When turning on, we need to retry for 1ms to give the sink + * time to wake up. + */ + for (i = 0; i < 3; i++) { + ret = intel_dp_aux_native_write_1(intel_dp, + DP_SET_POWER, + DP_SET_POWER_D0); + if (ret == 1) + break; + msleep(1); + } + } +} + static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; + /* Wake up the sink first */ + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + if (is_edp(intel_dp)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_off(dev); @@ -990,6 +1023,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (mode != DRM_MODE_DPMS_ON) { if (is_edp(intel_dp)) ironlake_edp_backlight_off(dev); + intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); if (is_edp(intel_dp)) ironlake_edp_panel_off(dev); @@ -998,6 +1032,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) } else { if (is_edp(intel_dp)) ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_sink_dpms(intel_dp, mode); if (!(dp_reg & DP_PORT_EN)) { intel_dp_start_link_train(intel_dp); if (is_edp(intel_dp)) { @@ -1009,7 +1044,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); } - intel_dp->dpms_mode = mode; +} + +/* + * Native read with retry for link status and receiver capability reads for + * cases where the sink may still be asleep. + */ +static bool +intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address, + uint8_t *recv, int recv_bytes) +{ + int ret, i; + + /* + * Sinks are *supposed* to come up within 1ms from an off state, + * but we're also supposed to retry 3 times per the spec. + */ + for (i = 0; i < 3; i++) { + ret = intel_dp_aux_native_read(intel_dp, address, recv, + recv_bytes); + if (ret == recv_bytes) + return true; + msleep(1); + } + + return false; } /* @@ -1019,14 +1078,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) static bool intel_dp_get_link_status(struct intel_dp *intel_dp) { - int ret; - - ret = intel_dp_aux_native_read(intel_dp, - DP_LANE0_1_STATUS, - intel_dp->link_status, DP_LINK_STATUS_SIZE); - if (ret != DP_LINK_STATUS_SIZE) - return false; - return true; + return intel_dp_aux_native_read_retry(intel_dp, + DP_LANE0_1_STATUS, + intel_dp->link_status, + DP_LINK_STATUS_SIZE); } static uint8_t @@ -1515,6 +1570,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { + int ret; + if (!intel_dp->base.base.crtc) return; @@ -1523,6 +1580,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) return; } + /* Try to read receiver status if the link appears to be up */ + ret = intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)); + if (ret != sizeof(intel_dp->dpcd)) { + intel_dp_link_down(intel_dp); + return; + } + if (!intel_channel_eq_ok(intel_dp)) { intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); @@ -1533,6 +1599,7 @@ static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; + bool ret; /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) { @@ -1543,13 +1610,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp) } status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_dp, - 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)) - == sizeof(intel_dp->dpcd)) { - if (intel_dp->dpcd[0] != 0) - status = connector_status_connected; - } + ret = intel_dp_aux_native_read_retry(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)); + if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0) + status = connector_status_connected; DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); return status; @@ -1586,7 +1651,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (intel_dp->dpcd[0] != 0) + if (intel_dp->dpcd[DP_DPCD_REV] != 0) status = connector_status_connected; } @@ -1790,8 +1855,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder) { struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON) - intel_dp_check_link_status(intel_dp); + intel_dp_check_link_status(intel_dp); } /* Return which DP Port should be selected for Transcoder DP control */ @@ -1859,7 +1923,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; - intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { @@ -1954,8 +2017,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) sizeof(intel_dp->dpcd)); ironlake_edp_panel_vdd_off(intel_dp); if (ret == sizeof(intel_dp->dpcd)) { - if (intel_dp->dpcd[0] >= 0x11) - dev_priv->no_aux_handshake = intel_dp->dpcd[3] & + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) + dev_priv->no_aux_handshake = + intel_dp->dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING; } else { /* if this fails, presume the device is a ghost */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c0e0ee63fbf..39ac2b634ae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -165,7 +165,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring) { - return intel_wait_ring_buffer(ring, ring->space - 8); + return intel_wait_ring_buffer(ring, ring->size - 8); } int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 660f96401a0..15bd0477a3e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2000,7 +2000,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) gb_backend_map = 0x66442200; break; case CHIP_JUNIPER: - gb_backend_map = 0x00006420; + gb_backend_map = 0x00002200; break; default: gb_backend_map = diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index 57f3bc17b87..2eb251858e7 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -252,7 +252,7 @@ draw_auto(struct radeon_device *rdev) } -/* emits 36 */ +/* emits 39 */ static void set_default_state(struct radeon_device *rdev) { @@ -531,6 +531,11 @@ set_default_state(struct radeon_device *rdev) radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2); radeon_ring_write(rdev, 0); + /* setup LDS */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (SQ_LDS_RESOURCE_MGMT - PACKET3_SET_CONFIG_REG_START) >> 2); + radeon_ring_write(rdev, 0x10001000); + /* SQ config */ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11)); radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2); @@ -773,7 +778,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) /* calculate number of loops correctly */ ring_size = num_loops * dwords_per_loop; /* set default + shaders */ - ring_size += 52; /* shaders + def state */ + ring_size += 55; /* shaders + def state */ ring_size += 10; /* fence emit for VB IB */ ring_size += 5; /* done copy */ ring_size += 10; /* fence emit for done copy */ diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 3fc5fa1aefd..229a20f10e2 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -331,7 +331,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(RV370_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -350,7 +350,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, @@ -367,7 +367,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(RV370_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); @@ -390,7 +390,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + if (rdev->flags & RADEON_IS_PCIE) + bus_cntl = RREG32(RV370_BUS_CNTL); + else + bus_cntl = RREG32(RADEON_BUS_CNTL); crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); crtc2_gen_cntl = 0; crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); @@ -412,7 +415,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + if (rdev->flags & RADEON_IS_PCIE) + WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM)); + else + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); /* Turn off mem requests and CRTC for both controllers */ WREG32(RADEON_CRTC_GEN_CNTL, @@ -439,7 +445,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + if (rdev->flags & RADEON_IS_PCIE) + WREG32(RV370_BUS_CNTL, bus_cntl); + else + WREG32(RADEON_BUS_CNTL, bus_cntl); WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); if (!(rdev->flags & RADEON_SINGLE_CRTC)) { WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index cbfca3a24fd..9792d4ffdc8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -52,6 +52,12 @@ void radeon_connector_hotplug(struct drm_connector *connector) struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); + /* bail if the connector does not have hpd pin, e.g., + * VGA, TV, etc. + */ + if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) + return; + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); /* powering up/down the eDP panel generates hpd events which diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index ec93a75369e..bc44a3d35ec 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -300,6 +300,8 @@ # define RADEON_BUS_READ_BURST (1 << 30) #define RADEON_BUS_CNTL1 0x0034 # define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) +#define RV370_BUS_CNTL 0x004c +# define RV370_BUS_BIOS_DIS_ROM (1 << 2) /* rv370/rv380, rv410, r423/r430/r480, r5xx */ #define RADEON_MSI_REARM_EN 0x0160 # define RV370_MSI_REARM_EN (1 << 0) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6e3b11e5abb..1f5850e473c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -426,7 +426,7 @@ int rs600_gart_init(struct radeon_device *rdev) return radeon_gart_table_vram_alloc(rdev); } -int rs600_gart_enable(struct radeon_device *rdev) +static int rs600_gart_enable(struct radeon_device *rdev) { u32 tmp; int r, i; @@ -440,8 +440,8 @@ int rs600_gart_enable(struct radeon_device *rdev) return r; radeon_gart_restore(rdev); /* Enable bus master */ - tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS; - WREG32(R_00004C_BUS_CNTL, tmp); + tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); /* FIXME: setup default page */ WREG32_MC(R_000100_MC_PT0_CNTL, (S_000100_EFFECTIVE_L2_CACHE_SIZE(6) | diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c index b9b7caf4a1d..8bc1bd66372 100644 --- a/drivers/hwmon/adm1275.c +++ b/drivers/hwmon/adm1275.c @@ -53,23 +53,23 @@ static int adm1275_probe(struct i2c_client *client, info->direct[PSC_VOLTAGE_IN] = true; info->direct[PSC_VOLTAGE_OUT] = true; info->direct[PSC_CURRENT_OUT] = true; - info->m[PSC_CURRENT_OUT] = 800; + info->m[PSC_CURRENT_OUT] = 807; info->b[PSC_CURRENT_OUT] = 20475; info->R[PSC_CURRENT_OUT] = -1; info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; if (config & ADM1275_VRANGE) { - info->m[PSC_VOLTAGE_IN] = 19045; + info->m[PSC_VOLTAGE_IN] = 19199; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -2; - info->m[PSC_VOLTAGE_OUT] = 19045; + info->m[PSC_VOLTAGE_OUT] = 19199; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = -2; } else { - info->m[PSC_VOLTAGE_IN] = 6666; + info->m[PSC_VOLTAGE_IN] = 6720; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 6666; + info->m[PSC_VOLTAGE_OUT] = 6720; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = -1; } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index dcb78a7a804..00e98517f94 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -674,6 +674,7 @@ static int atk_debugfs_gitm_get(void *p, u64 *val) else err = -EIO; + ACPI_FREE(ret); return err; } diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index bb6405b9200..5f524775043 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -1538,7 +1538,7 @@ static struct attribute *it87_attributes_label[] = { }; static const struct attribute_group it87_group_label = { - .attrs = it87_attributes_vid, + .attrs = it87_attributes_label, }; /* SuperIO detection - will change isa_address if a chip is found */ diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 12a54aa2977..14335bbc9bd 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -40,6 +40,8 @@ struct max1111_data { struct spi_transfer xfer[2]; uint8_t *tx_buf; uint8_t *rx_buf; + struct mutex drvdata_lock; + /* protect msg, xfer and buffers from multiple access */ }; static int max1111_read(struct device *dev, int channel) @@ -48,6 +50,9 @@ static int max1111_read(struct device *dev, int channel) uint8_t v1, v2; int err; + /* writing to drvdata struct is not thread safe, wait on mutex */ + mutex_lock(&data->drvdata_lock); + data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) | MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 | MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR; @@ -55,12 +60,15 @@ static int max1111_read(struct device *dev, int channel) err = spi_sync(data->spi, &data->msg); if (err < 0) { dev_err(dev, "spi_sync failed with %d\n", err); + mutex_unlock(&data->drvdata_lock); return err; } v1 = data->rx_buf[0]; v2 = data->rx_buf[1]; + mutex_unlock(&data->drvdata_lock); + if ((v1 & 0xc0) || (v2 & 0x3f)) return -EINVAL; @@ -176,6 +184,8 @@ static int __devinit max1111_probe(struct spi_device *spi) if (err) goto err_free_data; + mutex_init(&data->drvdata_lock); + data->spi = spi; spi_set_drvdata(spi, data); @@ -213,6 +223,7 @@ static int __devexit max1111_remove(struct spi_device *spi) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); + mutex_destroy(&data->drvdata_lock); kfree(data->rx_buf); kfree(data->tx_buf); kfree(data); diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index 744672c1f26..8e31a8e2c74 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -362,8 +362,8 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) * Convert linear sensor values to milli- or micro-units * depending on sensor type. */ -static int pmbus_reg2data_linear(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static long pmbus_reg2data_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor) { s16 exponent; s32 mantissa; @@ -397,15 +397,15 @@ static int pmbus_reg2data_linear(struct pmbus_data *data, else val >>= -exponent; - return (int)val; + return val; } /* * Convert direct sensor values to milli- or micro-units * depending on sensor type. */ -static int pmbus_reg2data_direct(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static long pmbus_reg2data_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor) { long val = (s16) sensor->data; long m, b, R; @@ -440,12 +440,12 @@ static int pmbus_reg2data_direct(struct pmbus_data *data, R++; } - return (int)((val - b) / m); + return (val - b) / m; } -static int pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) +static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) { - int val; + long val; if (data->info->direct[sensor->class]) val = pmbus_reg2data_direct(data, sensor); @@ -619,7 +619,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) if (!s1 && !s2) *val = !!regval; else { - int v1, v2; + long v1, v2; struct pmbus_sensor *sensor1, *sensor2; sensor1 = &data->sensors[s1]; @@ -661,7 +661,7 @@ static ssize_t pmbus_show_sensor(struct device *dev, if (sensor->data < 0) return sensor->data; - return snprintf(buf, PAGE_SIZE, "%d\n", pmbus_reg2data(data, sensor)); + return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); } static ssize_t pmbus_set_sensor(struct device *dev, diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 3a20961bef1..b1d9cd28d8d 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -662,11 +662,8 @@ static int __devinit cpm_i2c_probe(struct platform_device *ofdev) /* register new adapter to i2c module... */ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); - if (data && len == 4) { - cpm->adap.nr = *data; - result = i2c_add_numbered_adapter(&cpm->adap); - } else - result = i2c_add_adapter(&cpm->adap); + cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; + result = i2c_add_numbered_adapter(&cpm->adap); if (result < 0) { dev_err(&ofdev->dev, "Unable to register with I2C\n"); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index f59224a5c76..d6036465099 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1079,7 +1079,7 @@ static int i2c_pxa_probe(struct platform_device *dev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - i2c->adap.nr = dev->id != -1 ? dev->id : 0; + i2c->adap.nr = dev->id; snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u", i2c->adap.nr); @@ -1142,10 +1142,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - if (i2c_type == REGS_CE4100) - ret = i2c_add_adapter(&i2c->adap); - else - ret = i2c_add_numbered_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); goto eadapt; diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c index cb5d01e279c..c64ba736f48 100644 --- a/drivers/i2c/busses/i2c-s6000.c +++ b/drivers/i2c/busses/i2c-s6000.c @@ -341,10 +341,7 @@ static int __devinit s6i2c_probe(struct platform_device *dev) i2c_wr16(iface, S6_I2C_TXTL, 0); platform_set_drvdata(dev, iface); - if (bus_num < 0) - rc = i2c_add_adapter(p_adap); - else - rc = i2c_add_numbered_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc) goto err_irq_free; return 0; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index fb3b4f8f815..7ac2f7a87e6 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/i2c-tegra.h> +#include <linux/of_i2c.h> #include <asm/unaligned.h> @@ -546,6 +547,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) struct resource *iomem; struct clk *clk; struct clk *i2c_clk; + const unsigned int *prop; void *base; int irq; int ret = 0; @@ -603,7 +605,17 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; - i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000; + + i2c_dev->bus_clk_rate = 100000; /* default clock rate */ + if (pdata) { + i2c_dev->bus_clk_rate = pdata->bus_clk_rate; + } else if (i2c_dev->dev->of_node) { + /* if there is a device tree node ... */ + prop = of_get_property(i2c_dev->dev->of_node, + "clock-frequency", NULL); + if (prop) + i2c_dev->bus_clk_rate = be32_to_cpup(prop); + } if (pdev->id == 3) i2c_dev->is_dvc = 1; @@ -633,6 +645,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; + i2c_dev->adapter.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { @@ -640,6 +653,8 @@ static int tegra_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(&i2c_dev->adapter); + return 0; err_free_irq: free_irq(i2c_dev->irq, i2c_dev); @@ -704,6 +719,17 @@ static int tegra_i2c_resume(struct platform_device *pdev) } #endif +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); +#else +#define tegra_i2c_of_match NULL +#endif + static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, @@ -714,6 +740,7 @@ static struct platform_driver tegra_i2c_driver = { .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, + .of_match_table = tegra_i2c_of_match, }, }; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9a58994ff7e..131079a3e29 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -925,6 +925,9 @@ EXPORT_SYMBOL(i2c_add_adapter); * or otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * + * If the requested bus number is set to -1, then this function will behave + * identically to i2c_add_adapter, and will dynamically assign a bus number. + * * If no devices have pre-been declared for this bus, then be sure to * register the adapter before any dynamically allocated ones. Otherwise * the required bus ID may not be available. @@ -940,6 +943,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap) int id; int status; + if (adap->nr == -1) /* -1 means dynamically assign bus id */ + return i2c_add_adapter(adap); if (adap->nr & ~MAX_ID_MASK) return -EINVAL; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 98278041d75..5b6b451d469 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1988,6 +1988,14 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) goto err0; + + /* If we took control of the bus, we need to force + reinitialization. This is because many ts_bus_ctrl() + functions strobe the RESET pin on the demod, and if the + frontend thread already exists then the dvb_init() routine + won't get called (which is what usually does initial + register configuration). */ + fepriv->reinitialise = 1; } if ((ret = dvb_generic_open (inode, file)) < 0) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index e4c97fd6f05..52798a111e1 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -168,7 +168,7 @@ config RADIO_MAXIRADIO config RADIO_MIROPCM20 tristate "miroSOUND PCM20 radio" - depends on ISA && VIDEO_V4L2 && SND + depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND select SND_ISA select SND_MIRO ---help--- @@ -201,7 +201,7 @@ config RADIO_SF16FMI config RADIO_SF16FMR2 tristate "SF16FMR2 Radio" - depends on ISA && VIDEO_V4L2 + depends on ISA && VIDEO_V4L2 && SND ---help--- Choose Y here if you have one of these FM radio cards. diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index deca2e06ff2..c9f4a8e65dc 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1033,7 +1033,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, char ps_name[MAX_RDS_PS_NAME + 1]; len = control->size - 1; - if (len > MAX_RDS_PS_NAME) { + if (len < 0 || len > MAX_RDS_PS_NAME) { rval = -ERANGE; goto exit; } @@ -1057,7 +1057,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, char radio_text[MAX_RDS_RADIO_TEXT + 1]; len = control->size - 1; - if (len > MAX_RDS_RADIO_TEXT) { + if (len < 0 || len > MAX_RDS_RADIO_TEXT) { rval = -ERANGE; goto exit; } diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 06dfe0957b5..ec972dc2579 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -558,9 +558,10 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, inout, data1); break; case MCE_CMD_S_TIMEOUT: - /* value is in units of 50us, so x*50/100 or x/2 ms */ + /* value is in units of 50us, so x*50/1000 ms */ dev_info(dev, "%s receive timeout of %d ms\n", - inout, ((data1 << 8) | data2) / 2); + inout, + ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000); break; case MCE_CMD_G_TIMEOUT: dev_info(dev, "Get receive timeout\n"); @@ -847,7 +848,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2); + ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT); break; /* 1-byte return value commands */ @@ -1078,7 +1079,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = US_TO_NS(1000); + rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 565f24c20d7..ce595f9ab4c 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1110,7 +1110,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) rdev->dev.parent = &pdev->dev; rdev->driver_name = NVT_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; - rdev->timeout = US_TO_NS(1000); + rdev->timeout = MS_TO_NS(100); /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); #if 0 diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 64d9b2136ff..419777a832e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -2060,12 +2060,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, goto fail_irq; } - if (!pci_enable_msi(pci_dev)) - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_DISABLED, dev->name, dev); - else - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, pci_dev->irq); @@ -2114,7 +2110,6 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) /* unregister stuff */ free_irq(pci_dev->irq, dev); - pci_disable_msi(pci_dev); cx23885_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index cfa9f7efe93..a03945ab9f0 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -714,10 +714,19 @@ static int tuner_remove(struct i2c_client *client) * returns 0. * This function is needed for boards that have a separate tuner for * radio (like devices with tea5767). + * NOTE: mt20xx uses V4L2_TUNER_DIGITAL_TV and calls set_tv_freq to + * select a TV frequency. So, t_mode = T_ANALOG_TV could actually + * be used to represent a Digital TV too. */ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) { - if ((1 << mode & t->mode_mask) == 0) + int t_mode; + if (mode == V4L2_TUNER_RADIO) + t_mode = T_RADIO; + else + t_mode = T_ANALOG_TV; + + if ((t_mode & t->mode_mask) == 0) return -EINVAL; return 0; @@ -984,7 +993,7 @@ static void tuner_status(struct dvb_frontend *fe) case V4L2_TUNER_RADIO: p = "radio"; break; - case V4L2_TUNER_DIGITAL_TV: + case V4L2_TUNER_DIGITAL_TV: /* Used by mt20xx */ p = "digital TV"; break; case V4L2_TUNER_ANALOG_TV: @@ -1135,9 +1144,8 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; if (vt->type == t->mode && analog_ops->get_afc) vt->afc = analog_ops->get_afc(&t->fe); - if (vt->type == V4L2_TUNER_ANALOG_TV) + if (t->mode != V4L2_TUNER_RADIO) { vt->capability |= V4L2_TUNER_CAP_NORM; - if (vt->type != V4L2_TUNER_RADIO) { vt->rangelow = tv_range[0] * 16; vt->rangehigh = tv_range[1] * 16; return 0; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2a7e43bc796..aa7d1d79b8c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ + card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { - int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE]; - if (ext_csd_struct > 2) { + if (card->ext_csd.raw_ext_csd_structure > 2) { printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), - ext_csd_struct); + card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } @@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) goto out; } + card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; + card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; + card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; + card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | @@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } - + card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: @@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host)); } + card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; + card->ext_csd.raw_erase_timeout_mult = + ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; + card->ext_csd.raw_hc_erase_grp_size = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; @@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; } + card->ext_csd.raw_hc_erase_gap_size = + ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; + card->ext_csd.raw_sec_trim_mult = + ext_csd[EXT_CSD_SEC_TRIM_MULT]; + card->ext_csd.raw_sec_erase_mult = + ext_csd[EXT_CSD_SEC_ERASE_MULT]; + card->ext_csd.raw_sec_feature_support = + ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; + card->ext_csd.raw_trim_mult = + ext_csd[EXT_CSD_TRIM_MULT]; if (card->ext_csd.rev >= 4) { /* * Enhanced area feature support -- check whether the eMMC @@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * area offset and size to user by adding sysfs interface. */ if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && - (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { u8 hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; u8 hc_wp_grp_sz = @@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd) } -static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, - unsigned bus_width) +static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; int err; + if (bus_width == MMC_BUS_WIDTH_1) + return 0; + err = mmc_get_ext_csd(card, &bw_ext_csd); - if (err) - return err; - if ((ext_csd == NULL || bw_ext_csd == NULL)) { + if (err || bw_ext_csd == NULL) { if (bus_width != MMC_BUS_WIDTH_1) err = -EINVAL; goto out; @@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, goto out; /* only compare read only fields */ - err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == + err = (!(card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && - (ext_csd[EXT_CSD_ERASED_MEM_CONT] == + (card->ext_csd.raw_erased_mem_count == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && - (ext_csd[EXT_CSD_REV] == + (card->ext_csd.rev == bw_ext_csd[EXT_CSD_REV]) && - (ext_csd[EXT_CSD_STRUCTURE] == + (card->ext_csd.raw_ext_csd_structure == bw_ext_csd[EXT_CSD_STRUCTURE]) && - (ext_csd[EXT_CSD_CARD_TYPE] == + (card->ext_csd.raw_card_type == bw_ext_csd[EXT_CSD_CARD_TYPE]) && - (ext_csd[EXT_CSD_S_A_TIMEOUT] == + (card->ext_csd.raw_s_a_timeout == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && - (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_gap_size == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && - (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == + (card->ext_csd.raw_erase_timeout_mult == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && - (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_grp_size == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && - (ext_csd[EXT_CSD_SEC_TRIM_MULT] == + (card->ext_csd.raw_sec_trim_mult == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && - (ext_csd[EXT_CSD_SEC_ERASE_MULT] == + (card->ext_csd.raw_sec_erase_mult == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && - (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == + (card->ext_csd.raw_sec_feature_support == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && - (ext_csd[EXT_CSD_TRIM_MULT] == + (card->ext_csd.raw_trim_mult == bw_ext_csd[EXT_CSD_TRIM_MULT]) && - memcmp(&ext_csd[EXT_CSD_SEC_CNT], - &bw_ext_csd[EXT_CSD_SEC_CNT], - 4) != 0); + (card->ext_csd.raw_sectors[0] == + bw_ext_csd[EXT_CSD_SEC_CNT + 0]) && + (card->ext_csd.raw_sectors[1] == + bw_ext_csd[EXT_CSD_SEC_CNT + 1]) && + (card->ext_csd.raw_sectors[2] == + bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && + (card->ext_csd.raw_sectors[3] == + bw_ext_csd[EXT_CSD_SEC_CNT + 3])); if (err) err = -EINVAL; @@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) err = mmc_compare_ext_csds(card, - ext_csd, bus_width); else err = mmc_bus_test(card, bus_width); diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index dbab0407f4b..e231f917225 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -49,10 +49,30 @@ static struct sdhci_ops sdhci_pltfm_ops = { * Device probing/removal * * * \*****************************************************************************/ +#if defined(CONFIG_OF) +#include <linux/of_device.h> +static const struct of_device_id sdhci_dt_ids[] = { + { .compatible = "nvidia,tegra20-sdhci", .data = &sdhci_tegra_dt_pdata }, + { } +}; +MODULE_DEVICE_TABLE(platform, sdhci_dt_ids); + +static const struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return of_match_device(sdhci_dt_ids, &pdev->dev); +} +#else +#define sdhci_dt_ids NULL +static inline struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return NULL; +} +#endif static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); struct sdhci_pltfm_data *pdata; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -61,6 +81,8 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) if (platid && platid->driver_data) pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; else pdata = pdev->dev.platform_data; @@ -140,12 +162,21 @@ err: static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) { - struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; + const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); + struct sdhci_pltfm_data *pdata; struct sdhci_host *host = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int dead; u32 scratch; + if (platid && platid->driver_data) + pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; + else + pdata = pdev->dev.platform_data; + dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -203,6 +234,7 @@ static struct platform_driver sdhci_pltfm_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, + .of_match_table = sdhci_dt_ids, }, .probe = sdhci_pltfm_probe, .remove = __devexit_p(sdhci_pltfm_remove), diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 2b37016ad0a..2a438175839 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -24,5 +24,6 @@ extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; extern struct sdhci_pltfm_data sdhci_dove_pdata; extern struct sdhci_pltfm_data sdhci_tegra_pdata; +extern struct sdhci_pltfm_data sdhci_tegra_dt_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 343c97edba3..c9d4d282041 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -18,8 +18,10 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> +#include <linux/slab.h> #include <mach/gpio.h> #include <mach/sdhci.h> @@ -216,6 +218,33 @@ out: return rc; } +static int tegra_sdhci_pltfm_dt_init(struct sdhci_host *host, + struct sdhci_pltfm_data *pdata) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + + if (pdev->dev.platform_data) { + dev_err(&pdev->dev, "%s: platform_data not NULL; aborting\n", + __func__); + return -ENODEV; + } + + plat = kzalloc(sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + pdev->dev.platform_data = plat; + + plat->cd_gpio = of_get_gpio(pdev->dev.of_node, 0); + plat->wp_gpio = of_get_gpio(pdev->dev.of_node, 1); + plat->power_gpio = of_get_gpio(pdev->dev.of_node, 2); + + dev_info(&pdev->dev, "using gpios cd=%i, wp=%i power=%i\n", + plat->cd_gpio, plat->wp_gpio, plat->power_gpio); + + return tegra_sdhci_pltfm_init(host, pdata); +} + static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -244,6 +273,16 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) clk_put(pltfm_host->clk); } +static void tegra_sdhci_pltfm_dt_exit(struct sdhci_host *host) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + + tegra_sdhci_pltfm_exit(host); + + kfree(pdev->dev.platform_data); + pdev->dev.platform_data = NULL; +} + static struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_l = tegra_sdhci_readl, @@ -261,3 +300,13 @@ struct sdhci_pltfm_data sdhci_tegra_pdata = { .init = tegra_sdhci_pltfm_init, .exit = tegra_sdhci_pltfm_exit, }; + +struct sdhci_pltfm_data sdhci_tegra_dt_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, + .init = tegra_sdhci_pltfm_dt_init, + .exit = tegra_sdhci_pltfm_dt_exit, +}; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index eafe44a528a..63c22b0bb5a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1428,9 +1428,9 @@ out: return features; } -#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \ - NETIF_F_SOFT_FEATURES | \ - NETIF_F_LRO) +#define BOND_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ + NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ + NETIF_F_HIGHDMA | NETIF_F_LRO) static void bond_compute_features(struct bonding *bond) { diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 2dfcc804784..dfa55f94ba7 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2289,6 +2289,23 @@ static int gfar_set_mac_address(struct net_device *dev) return 0; } +/* Check if rx parser should be activated */ +void gfar_check_rx_parser_mode(struct gfar_private *priv) +{ + struct gfar __iomem *regs; + u32 tempval; + + regs = priv->gfargrp[0].regs; + + tempval = gfar_read(®s->rctrl); + /* If parse is no longer required, then disable parser */ + if (tempval & RCTRL_REQ_PARSER) + tempval |= RCTRL_PRSDEP_INIT; + else + tempval &= ~RCTRL_PRSDEP_INIT; + gfar_write(®s->rctrl, tempval); +} + /* Enables and disables VLAN insertion/extraction */ static void gfar_vlan_rx_register(struct net_device *dev, @@ -2325,12 +2342,9 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Disable VLAN tag extraction */ tempval = gfar_read(®s->rctrl); tempval &= ~RCTRL_VLEX; - /* If parse is no longer required, then disable parser */ - if (tempval & RCTRL_REQ_PARSER) - tempval |= RCTRL_PRSDEP_INIT; - else - tempval &= ~RCTRL_PRSDEP_INIT; gfar_write(®s->rctrl, tempval); + + gfar_check_rx_parser_mode(priv); } gfar_change_mtu(dev, dev->mtu); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index ba36dc7a343..440e69d8bef 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -274,7 +274,7 @@ extern const char gfar_driver_version[]; #define RCTRL_PROM 0x00000008 #define RCTRL_EMEN 0x00000002 #define RCTRL_REQ_PARSER (RCTRL_VLEX | RCTRL_IPCSEN | \ - RCTRL_TUCSEN) + RCTRL_TUCSEN | RCTRL_FILREN) #define RCTRL_CHECKSUMMING (RCTRL_IPCSEN | RCTRL_TUCSEN | \ RCTRL_PRSDEP_INIT) #define RCTRL_EXTHASH (RCTRL_GHTX) @@ -1156,6 +1156,7 @@ extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); int gfar_set_features(struct net_device *dev, u32 features); +extern void gfar_check_rx_parser_mode(struct gfar_private *priv); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 8f8b65af9ed..60f46bc2bf6 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -140,7 +140,7 @@ MODULE_LICENSE("GPL"); module_param(mtu, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); -module_param(dspcfg_workaround, int, 1); +module_param(dspcfg_workaround, int, 0); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); @@ -2028,8 +2028,8 @@ static void drain_rx(struct net_device *dev) np->rx_ring[i].cmd_status = 0; np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_skbuff[i]) { - pci_unmap_single(np->pci_dev, - np->rx_dma[i], buflen, + pci_unmap_single(np->pci_dev, np->rx_dma[i], + buflen + NATSEMI_PADDING, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 718879b35b7..bc9a4bb3198 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -348,8 +348,9 @@ static int pppoe_device_event(struct notifier_block *this, /* Only look at sockets that are using this specific device. */ switch (event) { + case NETDEV_CHANGEADDR: case NETDEV_CHANGEMTU: - /* A change in mtu is a bad thing, requiring + /* A change in mtu or address is a bad thing, requiring * LCP re-negotiation. */ diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 200a363c3bf..0ffec460844 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -677,9 +677,11 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) if (status & RX_FIFO_FULL) dev->stats.rx_fifo_errors++; - /* Mask off RX interrupt */ - misr &= ~RX_INTS; - napi_schedule(&lp->napi); + if (likely(napi_schedule_prep(&lp->napi))) { + /* Mask off RX interrupt */ + misr &= ~RX_INTS; + __napi_schedule(&lp->napi); + } } /* TX interrupt request */ diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 8ec1a9a0bb9..2f110fb30da 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -182,11 +182,11 @@ static int sl_alloc_bufs(struct slip *sl, int mtu) #ifdef SL_INCLUDE_CSLIP cbuff = xchg(&sl->cbuff, cbuff); slcomp = xchg(&sl->slcomp, slcomp); +#endif #ifdef CONFIG_SLIP_MODE_SLIP6 sl->xdata = 0; sl->xbits = 0; #endif -#endif spin_unlock_bh(&sl->lock); err = 0; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 46851273196..9a21ca3873f 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -879,7 +879,6 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); - pr_debug("tdes0=%x\n", tdes0); if (tdes0 & 0x80000000) break; @@ -889,7 +888,6 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { - pr_debug("tdes0=%x\n", tdes0); dev->stats.collisions += (tdes0 >> 3) & 0xf; dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { @@ -986,7 +984,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* error summary bit check */ if (rdes0 & 0x8000) { /* This is a error packet */ - pr_debug("rdes0: %x\n", rdes0); dev->stats.rx_errors++; if (rdes0 & 1) dev->stats.rx_fifo_errors++; @@ -1638,7 +1635,6 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db) else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - pr_debug("Phy_mode %x\n", phy_mode); switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 387ca43f26f..304fe78ff60 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2421,10 +2421,8 @@ static void hso_free_net_device(struct hso_device *hso_dev) remove_net_device(hso_net->parent); - if (hso_net->net) { + if (hso_net->net) unregister_netdev(hso_net->net); - free_netdev(hso_net->net); - } /* start freeing */ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { @@ -2436,6 +2434,9 @@ static void hso_free_net_device(struct hso_device *hso_dev) kfree(hso_net->mux_bulk_tx_buf); hso_net->mux_bulk_tx_buf = NULL; + if (hso_net->net) + free_netdev(hso_net->net); + kfree(hso_dev); } diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 296c316a834..f2c0c236392 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -297,7 +297,9 @@ ath5k_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { - struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; ath5k_led_off(sc); return 0; @@ -306,7 +308,8 @@ static int ath5k_pci_suspend(struct device *dev) static int ath5k_pci_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct ath5k_softc *sc = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; /* * Suspend/Resume resets the PCI configuration space, so we have to diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 929c68cdf8a..a073cdce1f1 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -10,7 +10,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ \ @@ -18,7 +19,8 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ int val; \ \ val = (int)simple_strtoul(buf, NULL, 10); \ @@ -33,7 +35,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3779b8977d4..33443bcaa8d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -671,7 +671,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * TODO - this could be improved to be dependent on the rate. * The hardware can keep up at lower rates, but not higher rates */ - if (fi->keyix != ATH9K_TXKEYIX_INVALID) + if ((fi->keyix != ATH9K_TXKEYIX_INVALID) && + !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) ndelim += ATH_AGGR_ENCRYPTDELIM; /* diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 2fb53d06751..333b69ef2ae 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -112,6 +112,8 @@ static struct usb_device_id carl9170_usb_ids[] = { { USB_DEVICE(0x04bb, 0x093f) }, /* NEC WL300NU-G */ { USB_DEVICE(0x0409, 0x0249) }, + /* NEC WL300NU-AG */ + { USB_DEVICE(0x0409, 0x02b4) }, /* AVM FRITZ!WLAN USB Stick N */ { USB_DEVICE(0x057c, 0x8401) }, /* AVM FRITZ!WLAN USB Stick N 2.4 */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 092e342c19d..942f7a3969a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -298,6 +298,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ + {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ /* HP - Lite-On ,8188CUS Slim Combo */ diff --git a/drivers/of/address.c b/drivers/of/address.c index b4559c58c09..da1f4b9605d 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -577,6 +577,24 @@ int of_address_to_resource(struct device_node *dev, int index, } EXPORT_SYMBOL_GPL(of_address_to_resource); +struct device_node *of_find_matching_node_by_address(struct device_node *from, + const struct of_device_id *matches, + u64 base_address) +{ + struct device_node *dn = of_find_matching_node(from, matches); + struct resource res; + + while (dn) { + if (of_address_to_resource(dn, 0, &res)) + continue; + if (res.start == base_address) + return dn; + dn = of_find_matching_node(dn, matches); + } + + return NULL; +} + /** * of_iomap - Maps the memory mapped IO for a given device_node diff --git a/drivers/of/base.c b/drivers/of/base.c index 632ebae7f17..02ed36719de 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -596,6 +596,71 @@ struct device_node *of_find_node_by_phandle(phandle handle) EXPORT_SYMBOL(of_find_node_by_phandle); /** + * of_property_read_u32_array - Find and read an array of 32 bit integers + * from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * + * Search for a property in a device node and read 32-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid u32 value can be decoded. + */ +int of_property_read_u32_array(const struct device_node *np, char *propname, + u32 *out_values, size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + const __be32 *val; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if ((sz * sizeof(*out_values)) > prop->length) + return -EOVERFLOW; + + val = prop->value; + while (sz--) + *out_values++ = be32_to_cpup(val++); + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u32_array); + +/** + * of_property_read_string - Find and read a string from a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy). Returns 0 on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string(struct device_node *np, char *propname, + const char **out_string) +{ + struct property *prop = of_find_property(np, propname, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + *out_string = prop->value; + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_string); + +/** * of_parse_phandle - Resolve a phandle property to a device_node pointer * @np: Pointer to device node holding phandle property * @phandle_name: Name of property holding a phandle value diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 905960338fb..3007662ac61 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -21,8 +21,9 @@ #include <linux/slab.h> /** - * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API + * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from + * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * @@ -30,8 +31,8 @@ * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -int of_get_gpio_flags(struct device_node *np, int index, - enum of_gpio_flags *flags) +int of_get_named_gpio_flags(struct device_node *np, const char *propname, + int index, enum of_gpio_flags *flags) { int ret; struct device_node *gpio_np; @@ -40,7 +41,7 @@ int of_get_gpio_flags(struct device_node *np, int index, const void *gpio_spec; const __be32 *gpio_cells; - ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, + ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index, &gpio_np, &gpio_spec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); @@ -79,7 +80,7 @@ err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; } -EXPORT_SYMBOL(of_get_gpio_flags); +EXPORT_SYMBOL(of_get_named_gpio_flags); /** * of_gpio_count - Count GPIOs for a device diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 63d3cb73bdb..e75af391e28 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -13,6 +13,7 @@ */ #include <linux/errno.h> #include <linux/module.h> +#include <linux/amba/bus.h> #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/slab.h> @@ -22,6 +23,14 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> +const struct of_device_id of_default_bus_match_table[] = { + { .compatible = "simple-bus", }, +#ifdef CONFIG_ARM_AMBA + { .compatible = "arm,amba-bus", }, +#endif /* CONFIG_ARM_AMBA */ + {} /* Empty terminated list */ +}; + static int of_dev_node_match(struct device *dev, void *data) { return dev->of_node == data; @@ -168,17 +177,20 @@ struct platform_device *of_device_alloc(struct device_node *np, EXPORT_SYMBOL(of_device_alloc); /** - * of_platform_device_create - Alloc, initialize and register an of_device + * of_platform_device_create_pdata - Alloc, initialize and register an of_device * @np: pointer to node to create device for * @bus_id: name to assign device + * @platform_data: pointer to populate platform_data pointer with * @parent: Linux device model parent device. * * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -struct platform_device *of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent) +struct platform_device *of_platform_device_create_pdata( + struct device_node *np, + const char *bus_id, + void *platform_data, + struct device *parent) { struct platform_device *dev; @@ -194,6 +206,7 @@ struct platform_device *of_platform_device_create(struct device_node *np, #endif dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); dev->dev.bus = &platform_bus_type; + dev->dev.platform_data = platform_data; /* We do not fill the DMA ops for platform devices by default. * This is currently the responsibility of the platform code @@ -207,8 +220,111 @@ struct platform_device *of_platform_device_create(struct device_node *np, return dev; } + +/** + * of_platform_device_create - Alloc, initialize and register an of_device + * @np: pointer to node to create device for + * @bus_id: name to assign device + * @parent: Linux device model parent device. + * + * Returns pointer to created platform device, or NULL if a device was not + * registered. Unavailable devices will not get registered. + */ +struct platform_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + return of_platform_device_create_pdata(np, bus_id, NULL, parent); +} EXPORT_SYMBOL(of_platform_device_create); +#ifdef CONFIG_ARM_AMBA +static struct amba_device *of_amba_device_create(struct device_node *node, + const char *bus_id, + void *platform_data, + struct device *parent) +{ + struct amba_device *dev; + const void *prop; + int i, ret; + + pr_debug("Creating amba device %s\n", node->full_name); + + if (!of_device_is_available(node)) + return NULL; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + /* setup generic device info */ + dev->dev.coherent_dma_mask = ~0; + dev->dev.of_node = of_node_get(node); + dev->dev.parent = parent; + dev->dev.platform_data = platform_data; + if (bus_id) + dev_set_name(&dev->dev, "%s", bus_id); + else + of_device_make_bus_id(&dev->dev); + + /* setup amba-specific device info */ + dev->dma_mask = ~0; + + /* Allow the HW Peripheral ID to be overridden */ + prop = of_get_property(node, "arm,primecell-periphid", NULL); + if (prop) + dev->periphid = of_read_ulong(prop, 1); + + /* Decode the IRQs and address ranges */ + for (i = 0; i < AMBA_NR_IRQS; i++) + dev->irq[i] = irq_of_parse_and_map(node, i); + + ret = of_address_to_resource(node, 0, &dev->res); + if (ret) + goto err_free; + + ret = amba_device_register(dev, &iomem_resource); + if (ret) + goto err_free; + + return dev; + +err_free: + kfree(dev); + return NULL; +} +#else /* CONFIG_ARM_AMBA */ +static struct amba_device *of_amba_device_create(struct device_node *node, + const char *bus_id, + void *platform_data, + struct device *parent) +{ + return NULL; +} +#endif /* CONFIG_ARM_AMBA */ + +/** + * of_devname_lookup() - Given a device node, lookup the preferred Linux name + */ +static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup, + struct device_node *np) +{ + struct resource res; + if (lookup) { + for(; lookup->name != NULL; lookup++) { + if (!of_device_is_compatible(np, lookup->compatible)) + continue; + if (of_address_to_resource(np, 0, &res)) + continue; + if (res.start != lookup->phys_addr) + continue; + pr_debug("%s: devname=%s\n", np->full_name, lookup->name); + return lookup; + } + } + return NULL; +} + /** * of_platform_bus_create() - Create a device for a node and its children. * @bus: device node of the bus to instantiate @@ -221,19 +337,41 @@ EXPORT_SYMBOL(of_platform_device_create); */ static int of_platform_bus_create(struct device_node *bus, const struct of_device_id *matches, - struct device *parent) + const struct of_dev_auxdata *lookup, + struct device *parent, bool strict) { + const struct of_dev_auxdata *auxdata; struct device_node *child; struct platform_device *dev; + const char *bus_id = NULL; + void *platform_data = NULL; int rc = 0; - dev = of_platform_device_create(bus, NULL, parent); + /* Make sure it has a compatible property */ + if (strict && (!of_get_property(bus, "compatible", NULL))) { + pr_debug("%s() - skipping %s, no compatible prop\n", + __func__, bus->full_name); + return 0; + } + + auxdata = of_dev_lookup(lookup, bus); + if (auxdata) { + bus_id = auxdata->name; + platform_data = auxdata->platform_data; + } + + if (of_device_is_compatible(bus, "arm,primecell")) { + of_amba_device_create(bus, bus_id, platform_data, parent); + return 0; + } + + dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); if (!dev || !of_match_node(matches, bus)) return 0; for_each_child_of_node(bus, child) { pr_debug(" create child: %s\n", child->full_name); - rc = of_platform_bus_create(child, matches, &dev->dev); + rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); if (rc) { of_node_put(child); break; @@ -267,11 +405,11 @@ int of_platform_bus_probe(struct device_node *root, /* Do a self check of bus type, if there's a match, create children */ if (of_match_node(matches, root)) { - rc = of_platform_bus_create(root, matches, parent); + rc = of_platform_bus_create(root, matches, NULL, parent, false); } else for_each_child_of_node(root, child) { if (!of_match_node(matches, child)) continue; - rc = of_platform_bus_create(child, matches, parent); + rc = of_platform_bus_create(child, matches, NULL, parent, false); if (rc) break; } @@ -280,4 +418,44 @@ int of_platform_bus_probe(struct device_node *root, return rc; } EXPORT_SYMBOL(of_platform_bus_probe); + +/** + * of_platform_populate() - Populate platform_devices from device tree data + * @root: parent of the first level to probe or NULL for the root of the tree + * @matches: match table, NULL to use the default + * @parent: parent to hook devices from, NULL for toplevel + * + * Similar to of_platform_bus_probe(), this function walks the device tree + * and creates devices from nodes. It differs in that it follows the modern + * convention of requiring all device nodes to have a 'compatible' property, + * and it is suitable for creating devices which are children of the root + * node (of_platform_bus_probe will only create children of the root which + * are selected by the @matches argument). + * + * New board support should be using this function instead of + * of_platform_bus_probe(). + * + * Returns 0 on success, < 0 on failure. + */ +int of_platform_populate(struct device_node *root, + const struct of_device_id *matches, + const struct of_dev_auxdata *lookup, + struct device *parent) +{ + struct device_node *child; + int rc = 0; + + root = root ? of_node_get(root) : of_find_node_by_path("/"); + if (!root) + return -EINVAL; + + for_each_child_of_node(root, child) { + rc = of_platform_bus_create(child, matches, lookup, parent, true); + if (rc) + break; + } + + of_node_put(root); + return rc; +} #endif /* !CONFIG_SPARC */ diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 712baab3c83..e956f659089 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -76,10 +76,10 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { if (skt->nr == 0) - gpio_request_array(vpac270_pcmcia_gpios, + gpio_free_array(vpac270_pcmcia_gpios, ARRAY_SIZE(vpac270_pcmcia_gpios)); else - gpio_request_array(vpac270_cf_gpios, + gpio_free_array(vpac270_cf_gpios, ARRAY_SIZE(vpac270_cf_gpios)); } diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c index 6c3aa6ecaad..b0e3586d1e1 100644 --- a/drivers/spi/spi_tegra.c +++ b/drivers/spi/spi_tegra.c @@ -546,6 +546,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev) tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; tspi->rx_dma_req.dev = tspi; + master->dev.of_node = pdev->dev.of_node; ret = spi_register_master(master); if (ret < 0) @@ -595,10 +596,21 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev) MODULE_ALIAS("platform:spi_tegra"); +#ifdef CONFIG_OF +static struct of_device_id spi_tegra_of_match_table[] __devinitdata = { + { .compatible = "nvidia,tegra20-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_tegra_of_match_table); +#else /* CONFIG_OF */ +#define spi_tegra_of_match_table NULL +#endif /* CONFIG_OF */ + static struct platform_driver spi_tegra_driver = { .driver = { .name = "spi_tegra", .owner = THIS_MODULE, + .of_match_table = spi_tegra_of_match_table, }, .remove = __devexit_p(spi_tegra_remove), }; diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 2a20dabec76..d6620ad309c 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -516,8 +516,17 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) { + ssb_pcicore_fix_sprom_core_index(pc); + /* Disable PCI interrupts. */ ssb_write32(pc->dev, SSB_INTVEC, 0); + + /* Additional PCIe always once-executed workarounds */ + if (pc->dev->id.coreid == SSB_DEV_PCIE) { + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ + } } void ssb_pcicore_init(struct ssb_pcicore *pc) @@ -529,8 +538,6 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); - ssb_pcicore_fix_sprom_core_index(pc); - #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) @@ -538,13 +545,6 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); - - /* Additional PCIe always once-executed workarounds */ - if (dev->id.coreid == SSB_DEV_PCIE) { - ssb_pcicore_serdes_workaround(pc); - /* TODO: ASPM */ - /* TODO: Clock Request Update */ - } } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index c911b2419ab..e58cece6f44 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -32,17 +32,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, { struct resource resource; struct device_node *np = ofdev->dev.of_node; - const __be32 *clk, *spd; - const __be32 *prop; - int ret, prop_size; + u32 clk, spd, prop; + int ret; memset(port, 0, sizeof *port); - spd = of_get_property(np, "current-speed", NULL); - clk = of_get_property(np, "clock-frequency", NULL); - if (!clk) { + if (of_property_read_u32(np, "clock-frequency", &clk)) { dev_warn(&ofdev->dev, "no clock-frequency property set\n"); return -ENODEV; } + /* If current-speed was set, then try not to change it. */ + if (of_property_read_u32(np, "current-speed", &spd) == 0) + port->custom_divisor = clk / (16 * spd); ret = of_address_to_resource(np, 0, &resource); if (ret) { @@ -54,25 +54,35 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, port->mapbase = resource.start; /* Check for shifted address mapping */ - prop = of_get_property(np, "reg-offset", &prop_size); - if (prop && (prop_size == sizeof(u32))) - port->mapbase += be32_to_cpup(prop); + if (of_property_read_u32(np, "reg-offset", &prop) == 0) + port->mapbase += prop; /* Check for registers offset within the devices address range */ - prop = of_get_property(np, "reg-shift", &prop_size); - if (prop && (prop_size == sizeof(u32))) - port->regshift = be32_to_cpup(prop); + if (of_property_read_u32(np, "reg-shift", &prop) == 0) + port->regshift = prop; port->irq = irq_of_parse_and_map(np, 0); port->iotype = UPIO_MEM; + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + port->iotype = UPIO_MEM; + break; + case 4: + port->iotype = UPIO_MEM32; + break; + default: + dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", + prop); + return -EINVAL; + } + } + port->type = type; - port->uartclk = be32_to_cpup(clk); + port->uartclk = clk; port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; - /* If current-speed was set, then try not to change it. */ - if (spd) - port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd))); return 0; } @@ -171,6 +181,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { .compatible = "ns16550", .data = (void *)PORT_16550, }, { .compatible = "ns16750", .data = (void *)PORT_16750, }, { .compatible = "ns16850", .data = (void *)PORT_16850, }, + { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9536d386bb3..21d816e9dfa 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -599,8 +599,7 @@ config IT87_WDT config HP_WATCHDOG tristate "HP ProLiant iLO2+ Hardware Watchdog Timer" - depends on X86 - default m + depends on X86 && PCI help A software monitoring watchdog and NMI sourcing driver. This driver will detect lockups and provide a stack trace. This is a driver that diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 79743d146be..0c1d9175652 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, struct dentry *temp; char *path; int len, pos; + unsigned seq; if (dentry == NULL) return ERR_PTR(-EINVAL); retry: len = 0; + seq = read_seqbegin(&rename_lock); + rcu_read_lock(); for (temp = dentry; !IS_ROOT(temp);) { struct inode *inode = temp->d_inode; if (inode && ceph_snap(inode) == CEPH_SNAPDIR) @@ -1455,10 +1458,12 @@ retry: len += 1 + temp->d_name.len; temp = temp->d_parent; if (temp == NULL) { + rcu_read_unlock(); pr_err("build_path corrupt dentry %p\n", dentry); return ERR_PTR(-EINVAL); } } + rcu_read_unlock(); if (len) len--; /* no leading '/' */ @@ -1467,9 +1472,12 @@ retry: return ERR_PTR(-ENOMEM); pos = len; path[pos] = 0; /* trailing null */ + rcu_read_lock(); for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { - struct inode *inode = temp->d_inode; + struct inode *inode; + spin_lock(&temp->d_lock); + inode = temp->d_inode; if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { dout("build_path path+%d: %p SNAPDIR\n", pos, temp); @@ -1478,21 +1486,26 @@ retry: break; } else { pos -= temp->d_name.len; - if (pos < 0) + if (pos < 0) { + spin_unlock(&temp->d_lock); break; + } strncpy(path + pos, temp->d_name.name, temp->d_name.len); } + spin_unlock(&temp->d_lock); if (pos) path[--pos] = '/'; temp = temp->d_parent; if (temp == NULL) { + rcu_read_unlock(); pr_err("build_path corrupt dentry\n"); kfree(path); return ERR_PTR(-EINVAL); } } - if (pos != 0) { + rcu_read_unlock(); + if (pos != 0 || read_seqretry(&rename_lock, seq)) { pr_err("build_path did not end path lookup where " "expected, namelen is %d, pos is %d\n", len, pos); /* presumably this is only possible if racing with a diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3e298997629..bc4b12ca537 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/namei.h> #include <net/ipv6.h> #include "cifsfs.h" #include "cifspdu.h" @@ -542,14 +543,12 @@ static const struct super_operations cifs_super_ops = { static struct dentry * cifs_get_root(struct smb_vol *vol, struct super_block *sb) { - int xid, rc; - struct inode *inode; - struct qstr name; - struct dentry *dparent = NULL, *dchild = NULL, *alias; + struct dentry *dentry; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - unsigned int i, full_len, len; - char *full_path = NULL, *pstart; + char *full_path = NULL; + char *s, *p; char sep; + int xid; full_path = cifs_build_path_to_root(vol, cifs_sb, cifs_sb_master_tcon(cifs_sb)); @@ -560,73 +559,32 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) xid = GetXid(); sep = CIFS_DIR_SEP(cifs_sb); - dparent = dget(sb->s_root); - full_len = strlen(full_path); - full_path[full_len] = sep; - pstart = full_path + 1; - - for (i = 1, len = 0; i <= full_len; i++) { - if (full_path[i] != sep || !len) { - len++; - continue; - } - - full_path[i] = 0; - cFYI(1, "get dentry for %s", pstart); - - name.name = pstart; - name.len = len; - name.hash = full_name_hash(pstart, len); - dchild = d_lookup(dparent, &name); - if (dchild == NULL) { - cFYI(1, "not exists"); - dchild = d_alloc(dparent, &name); - if (dchild == NULL) { - dput(dparent); - dparent = ERR_PTR(-ENOMEM); - goto out; - } - } - - cFYI(1, "get inode"); - if (dchild->d_inode == NULL) { - cFYI(1, "not exists"); - inode = NULL; - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) - rc = cifs_get_inode_info_unix(&inode, full_path, - sb, xid); - else - rc = cifs_get_inode_info(&inode, full_path, - NULL, sb, xid, NULL); - if (rc) { - dput(dchild); - dput(dparent); - dparent = ERR_PTR(rc); - goto out; - } - alias = d_materialise_unique(dchild, inode); - if (alias != NULL) { - dput(dchild); - if (IS_ERR(alias)) { - dput(dparent); - dparent = ERR_PTR(-EINVAL); /* XXX */ - goto out; - } - dchild = alias; - } - } - cFYI(1, "parent %p, child %p", dparent, dchild); - - dput(dparent); - dparent = dchild; - len = 0; - pstart = full_path + i + 1; - full_path[i] = sep; - } -out: + dentry = dget(sb->s_root); + p = s = full_path; + + do { + struct inode *dir = dentry->d_inode; + struct dentry *child; + + /* skip separators */ + while (*s == sep) + s++; + if (!*s) + break; + p = s++; + /* next separator */ + while (*s && *s != sep) + s++; + + mutex_lock(&dir->i_mutex); + child = lookup_one_len(p, dentry, s - p); + mutex_unlock(&dir->i_mutex); + dput(dentry); + dentry = child; + } while (!IS_ERR(dentry)); _FreeXid(xid); kfree(full_path); - return dparent; + return dentry; } static int cifs_set_super(struct super_block *sb, void *data) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 0900e1658c9..036ca83e5f4 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "1.73" +#define CIFS_VERSION "1.74" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index dbd669cc5bc..ccc1afa0bf3 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3485,7 +3485,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) goto out; } - snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid); + snprintf(username, sizeof(username), "krb50x%x", fsuid); vol_info->username = username; vol_info->local_nls = cifs_sb->local_nls; vol_info->linux_uid = fsuid; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 81914df47ef..fa8c21d913b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry) char dirsep; struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + unsigned seq; if (direntry == NULL) return NULL; /* not much we can do if dentry is freed and @@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry) dfsplen = 0; cifs_bp_rename_retry: namelen = dfsplen; + seq = read_seqbegin(&rename_lock); + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); return NULL; } } + rcu_read_unlock(); full_path = kmalloc(namelen+1, GFP_KERNEL); if (full_path == NULL) return full_path; full_path[namelen] = 0; /* trailing null */ + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { + spin_lock(&temp->d_lock); namelen -= 1 + temp->d_name.len; if (namelen < 0) { + spin_unlock(&temp->d_lock); break; } else { full_path[namelen] = dirsep; @@ -91,14 +99,17 @@ cifs_bp_rename_retry: temp->d_name.len); cFYI(0, "name: %s", full_path + namelen); } + spin_unlock(&temp->d_lock); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); kfree(full_path); return NULL; } } - if (namelen != dfsplen) { + rcu_read_unlock(); + if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { cERROR(1, "did not end path lookup where expected namelen is %d", namelen); /* presumably this is only possible if racing with a rename diff --git a/fs/cifs/file.c b/fs/cifs/file.c index bb71471a4d9..a9b4a24f2a1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1737,7 +1737,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, io_parms.pid = pid; io_parms.tcon = pTcon; io_parms.offset = *poffset; - io_parms.length = len; + io_parms.length = cur_len; rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &read_data, &buf_type); pSMBr = (struct smb_com_read_rsp *)read_data; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 3892ab817a3..d3e619692ee 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -428,8 +428,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { flags |= NTLMSSP_NEGOTIATE_SIGN; if (!ses->server->session_estab) - flags |= NTLMSSP_NEGOTIATE_KEY_XCH | - NTLMSSP_NEGOTIATE_EXTENDED_SEC; + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; } sec_blob->NegotiateFlags = cpu_to_le32(flags); @@ -465,10 +464,11 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (ses->server->sec_mode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + if (!ses->server->session_estab) + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; + } tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); sec_blob->NegotiateFlags = cpu_to_le32(flags); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index e141939080f..739fb59bcdc 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -37,7 +37,7 @@ static DEFINE_MUTEX(read_mutex); /* These macros may change in future, to provide better st_ino semantics. */ #define OFFSET(x) ((x)->i_ino) -static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) +static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset) { if (!cino->offset) return offset + 1; @@ -61,7 +61,7 @@ static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) } static struct inode *get_cramfs_inode(struct super_block *sb, - struct cramfs_inode *cramfs_inode, unsigned int offset) + const struct cramfs_inode *cramfs_inode, unsigned int offset) { struct inode *inode; static struct timespec zerotime; @@ -317,7 +317,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) /* Set it all up.. */ sb->s_op = &cramfs_ops; root = get_cramfs_inode(sb, &super.root, 0); - if (!root) + if (IS_ERR(root)) goto out; sb->s_root = d_alloc_root(root); if (!sb->s_root) { @@ -423,6 +423,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned int offset = 0; + struct inode *inode = NULL; int sorted; mutex_lock(&read_mutex); @@ -449,8 +450,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s for (;;) { if (!namelen) { - mutex_unlock(&read_mutex); - return ERR_PTR(-EIO); + inode = ERR_PTR(-EIO); + goto out; } if (name[namelen-1]) break; @@ -462,17 +463,18 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s if (retval > 0) continue; if (!retval) { - struct cramfs_inode entry = *de; - mutex_unlock(&read_mutex); - d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off)); - return NULL; + inode = get_cramfs_inode(dir->i_sb, de, dir_off); + break; } /* else (retval < 0) */ if (sorted) break; } +out: mutex_unlock(&read_mutex); - d_add(dentry, NULL); + if (IS_ERR(inode)) + return ERR_CAST(inode); + d_add(dentry, inode); return NULL; } diff --git a/fs/dcache.c b/fs/dcache.c index 37f72ee5bf7..fbdcbca4072 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1813,8 +1813,6 @@ seqretry: tname = dentry->d_name.name; i = dentry->d_inode; prefetch(tname); - if (i) - prefetch(i); /* * This seqcount check is required to ensure name and * len are loaded atomically, so as not to walk off the @@ -2213,14 +2211,15 @@ static void dentry_unlock_parents_for_move(struct dentry *dentry, * The hash value has to match the hash queue that the dentry is on.. */ /* - * d_move - move a dentry + * __d_move - move a dentry * @dentry: entry to move * @target: new dentry * * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. + * dcache entries should not be moved in this way. Caller hold + * rename_lock. */ -void d_move(struct dentry * dentry, struct dentry * target) +static void __d_move(struct dentry * dentry, struct dentry * target) { if (!dentry->d_inode) printk(KERN_WARNING "VFS: moving negative dcache entry\n"); @@ -2228,8 +2227,6 @@ void d_move(struct dentry * dentry, struct dentry * target) BUG_ON(d_ancestor(dentry, target)); BUG_ON(d_ancestor(target, dentry)); - write_seqlock(&rename_lock); - dentry_lock_for_move(dentry, target); write_seqcount_begin(&dentry->d_seq); @@ -2275,6 +2272,20 @@ void d_move(struct dentry * dentry, struct dentry * target) spin_unlock(&target->d_lock); fsnotify_d_move(dentry); spin_unlock(&dentry->d_lock); +} + +/* + * d_move - move a dentry + * @dentry: entry to move + * @target: new dentry + * + * Update the dcache to reflect the move of a file name. Negative + * dcache entries should not be moved in this way. + */ +void d_move(struct dentry *dentry, struct dentry *target) +{ + write_seqlock(&rename_lock); + __d_move(dentry, target); write_sequnlock(&rename_lock); } EXPORT_SYMBOL(d_move); @@ -2302,7 +2313,7 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) * This helper attempts to cope with remotely renamed directories * * It assumes that the caller is already holding - * dentry->d_parent->d_inode->i_mutex and the inode->i_lock + * dentry->d_parent->d_inode->i_mutex, inode->i_lock and rename_lock * * Note: If ever the locking in lock_rename() changes, then please * remember to update this too... @@ -2317,11 +2328,6 @@ static struct dentry *__d_unalias(struct inode *inode, if (alias->d_parent == dentry->d_parent) goto out_unalias; - /* Check for loops */ - ret = ERR_PTR(-ELOOP); - if (d_ancestor(alias, dentry)) - goto out_err; - /* See lock_rename() */ ret = ERR_PTR(-EBUSY); if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) @@ -2331,7 +2337,7 @@ static struct dentry *__d_unalias(struct inode *inode, goto out_err; m2 = &alias->d_parent->d_inode->i_mutex; out_unalias: - d_move(alias, dentry); + __d_move(alias, dentry); ret = alias; out_err: spin_unlock(&inode->i_lock); @@ -2416,15 +2422,24 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) alias = __d_find_alias(inode, 0); if (alias) { actual = alias; - /* Is this an anonymous mountpoint that we could splice - * into our tree? */ - if (IS_ROOT(alias)) { + write_seqlock(&rename_lock); + + if (d_ancestor(alias, dentry)) { + /* Check for loops */ + actual = ERR_PTR(-ELOOP); + } else if (IS_ROOT(alias)) { + /* Is this an anonymous mountpoint that we + * could splice into our tree? */ __d_materialise_dentry(dentry, alias); + write_sequnlock(&rename_lock); __d_drop(alias); goto found; + } else { + /* Nope, but we must(!) avoid directory + * aliasing */ + actual = __d_unalias(inode, dentry, alias); } - /* Nope, but we must(!) avoid directory aliasing */ - actual = __d_unalias(inode, dentry, alias); + write_sequnlock(&rename_lock); if (IS_ERR(actual)) dput(alias); goto out_nolock; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 06065bd37fc..c57beddcc21 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -913,7 +913,7 @@ struct dentry *exofs_get_parent(struct dentry *child) unsigned long ino = exofs_parent_ino(child); if (!ino) - return NULL; + return ERR_PTR(-ESTALE); return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino)); } diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 2f343b4d7a7..3f7a59bfa7a 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -976,16 +976,12 @@ void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, pagevec_init(&pvec, 0); next = 0; - while (next <= (loff_t)-1 && - pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE) - ) { + do { + if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) + break; for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; - pgoff_t page_index = page->index; - - ASSERTCMP(page_index, >=, next); - next = page_index + 1; - + next = page->index; if (PageFsCache(page)) { __fscache_wait_on_page_write(cookie, page); __fscache_uncache_page(cookie, page); @@ -993,7 +989,7 @@ void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, } pagevec_release(&pvec); cond_resched(); - } + } while (++next); _leave(""); } diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 802ac5eeba2..f9fbbe96c22 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1069,6 +1069,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) return 0; gfs2_log_lock(sdp); + spin_lock(&sdp->sd_ail_lock); head = bh = page_buffers(page); do { if (atomic_read(&bh->b_count)) @@ -1080,6 +1081,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) goto not_possible; bh = bh->b_this_page; } while(bh != head); + spin_unlock(&sdp->sd_ail_lock); gfs2_log_unlock(sdp); head = bh = page_buffers(page); @@ -1112,6 +1114,7 @@ not_possible: /* Should never happen */ WARN_ON(buffer_dirty(bh)); WARN_ON(buffer_pinned(bh)); cannot_release: + spin_unlock(&sdp->sd_ail_lock); gfs2_log_unlock(sdp); return 0; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8ef70f46473..2cca29316bd 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -47,10 +47,10 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl) bd_ail_gl_list); bh = bd->bd_bh; gfs2_remove_from_ail(bd); - spin_unlock(&sdp->sd_ail_lock); - bd->bd_bh = NULL; bh->b_private = NULL; + spin_unlock(&sdp->sd_ail_lock); + bd->bd_blkno = bh->b_blocknr; gfs2_log_lock(sdp); gfs2_assert_withdraw(sdp, !buffer_busy(bh)); @@ -221,8 +221,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) } } - if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) + if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { + gfs2_log_flush(gl->gl_sbd, NULL); gl->gl_sbd->sd_rindex_uptodate = 0; + } if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 0a064e91ac7..81206e70cbf 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -17,6 +17,7 @@ #include <linux/buffer_head.h> #include <linux/rcupdate.h> #include <linux/rculist_bl.h> +#include <linux/completion.h> #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -546,6 +547,7 @@ struct gfs2_sbd { struct gfs2_glock *sd_trans_gl; wait_queue_head_t sd_glock_wait; atomic_t sd_glock_disposal; + struct completion sd_locking_init; /* Inode Stuff */ diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 903115f2bb3..85c62923ee2 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -903,6 +903,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) if (gfs2_ail1_empty(sdp)) break; } + gfs2_log_flush(sdp, NULL); } static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 8ac9ae189b5..2a77071fb7b 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -72,6 +72,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) init_waitqueue_head(&sdp->sd_glock_wait); atomic_set(&sdp->sd_glock_disposal, 0); + init_completion(&sdp->sd_locking_init); spin_lock_init(&sdp->sd_statfs_spin); spin_lock_init(&sdp->sd_rindex_spin); @@ -1017,11 +1018,13 @@ hostdata_error: fsname++; if (lm->lm_mount == NULL) { fs_info(sdp, "Now mounting FS...\n"); + complete(&sdp->sd_locking_init); return 0; } ret = lm->lm_mount(sdp, fsname); if (ret == 0) fs_info(sdp, "Joined cluster. Now mounting FS...\n"); + complete(&sdp->sd_locking_init); return ret; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index ed540e7018b..fb0edf73548 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -757,13 +757,17 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) struct timespec atime; struct gfs2_dinode *di; int ret = -EAGAIN; + int unlock_required = 0; /* Skip timestamp update, if this is from a memalloc */ if (current->flags & PF_MEMALLOC) goto do_flush; - ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - if (ret) - goto do_flush; + if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { + ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (ret) + goto do_flush; + unlock_required = 1; + } ret = gfs2_trans_begin(sdp, RES_DINODE, 0); if (ret) goto do_unlock; @@ -780,7 +784,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) } gfs2_trans_end(sdp); do_unlock: - gfs2_glock_dq_uninit(&gh); + if (unlock_required) + gfs2_glock_dq_uninit(&gh); do_flush: if (wbc->sync_mode == WB_SYNC_ALL) gfs2_log_flush(GFS2_SB(inode), ip->i_gl); @@ -1427,7 +1432,20 @@ out: return error; } -/* +/** + * gfs2_evict_inode - Remove an inode from cache + * @inode: The inode to evict + * + * There are three cases to consider: + * 1. i_nlink == 0, we are final opener (and must deallocate) + * 2. i_nlink == 0, we are not the final opener (and cannot deallocate) + * 3. i_nlink > 0 + * + * If the fs is read only, then we have to treat all cases as per #3 + * since we are unable to do any deallocation. The inode will be + * deallocated by the next read/write node to attempt an allocation + * in the same resource group + * * We have to (at the moment) hold the inodes main lock to cover * the gap between unlocking the shared lock on the iopen lock and * taking the exclusive lock. I'd rather do a shared -> exclusive @@ -1470,6 +1488,8 @@ static void gfs2_evict_inode(struct inode *inode) if (error) goto out_truncate; + /* Case 1 starts here */ + if (S_ISDIR(inode->i_mode) && (ip->i_diskflags & GFS2_DIF_EXHASH)) { error = gfs2_dir_exhash_dealloc(ip); @@ -1493,13 +1513,16 @@ static void gfs2_evict_inode(struct inode *inode) goto out_unlock; out_truncate: + /* Case 2 starts here */ error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) goto out_unlock; - gfs2_final_release_pages(ip); + /* Needs to be done before glock release & also in a transaction */ + truncate_inode_pages(&inode->i_data, 0); gfs2_trans_end(sdp); out_unlock: + /* Error path for case 1 */ if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) gfs2_glock_dq(&ip->i_iopen_gh); gfs2_holder_uninit(&ip->i_iopen_gh); @@ -1507,6 +1530,7 @@ out_unlock: if (error && error != GLR_TRYFAILED && error != -EROFS) fs_warn(sdp, "gfs2_evict_inode: %d\n", error); out: + /* Case 3 starts here */ truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index e20eab37bc8..443cabcfcd2 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -338,6 +338,9 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len) rv = sscanf(buf, "%u", &first); if (rv != 1 || first > 1) return -EINVAL; + rv = wait_for_completion_killable(&sdp->sd_locking_init); + if (rv) + return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) @@ -414,7 +417,9 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len) rv = sscanf(buf, "%d", &jid); if (rv != 1) return -EINVAL; - + rv = wait_for_completion_killable(&sdp->sd_locking_init); + if (rv) + return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EINVAL; if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 87ed48e0343..85c098a499f 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -139,7 +139,8 @@ static int file_removed(struct dentry *dentry, const char *file) static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, struct nameidata *nd) { - struct dentry *proc_dentry, *new, *parent; + struct dentry *proc_dentry, *parent; + struct qstr *name = &dentry->d_name; struct inode *inode; int err, deleted; @@ -149,23 +150,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, else if (deleted) return ERR_PTR(-ENOENT); - err = -ENOMEM; parent = HPPFS_I(ino)->proc_dentry; mutex_lock(&parent->d_inode->i_mutex); - proc_dentry = d_lookup(parent, &dentry->d_name); - if (proc_dentry == NULL) { - proc_dentry = d_alloc(parent, &dentry->d_name); - if (proc_dentry == NULL) { - mutex_unlock(&parent->d_inode->i_mutex); - goto out; - } - new = (*parent->d_inode->i_op->lookup)(parent->d_inode, - proc_dentry, NULL); - if (new) { - dput(proc_dentry); - proc_dentry = new; - } - } + proc_dentry = lookup_one_len(name->name, parent, name->len); mutex_unlock(&parent->d_inode->i_mutex); if (IS_ERR(proc_dentry)) @@ -174,13 +161,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, err = -ENOMEM; inode = get_inode(ino->i_sb, proc_dentry); if (!inode) - goto out_dput; + goto out; d_add(dentry, inode); return NULL; - out_dput: - dput(proc_dentry); out: return ERR_PTR(err); } @@ -690,8 +675,10 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) struct inode *proc_ino = dentry->d_inode; struct inode *inode = new_inode(sb); - if (!inode) + if (!inode) { + dput(dentry); return ERR_PTR(-ENOMEM); + } if (S_ISDIR(dentry->d_inode->i_mode)) { inode->i_op = &hppfs_dir_iops; @@ -704,7 +691,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) inode->i_fop = &hppfs_file_fops; } - HPPFS_I(inode)->proc_dentry = dget(dentry); + HPPFS_I(inode)->proc_dentry = dentry; inode->i_uid = proc_ino->i_uid; inode->i_gid = proc_ino->i_gid; @@ -737,7 +724,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) sb->s_fs_info = proc_mnt; err = -ENOMEM; - root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); + root_inode = get_inode(sb, dget(proc_mnt->mnt_sb->s_root)); if (!root_inode) goto out_mntput; diff --git a/fs/libfs.c b/fs/libfs.c index c88eab55aec..275ca4749a2 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -822,7 +822,7 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, goto out; attr->set_buf[size] = '\0'; - val = simple_strtol(attr->set_buf, NULL, 0); + val = simple_strtoll(attr->set_buf, NULL, 0); ret = attr->set(attr->data, val); if (ret == 0) ret = len; /* on success, claim we got the whole input */ diff --git a/fs/namei.c b/fs/namei.c index 0223c41fb11..14ab8d3f2f0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -433,6 +433,8 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) goto err_parent; BUG_ON(nd->inode != parent->d_inode); } else { + if (dentry->d_parent != parent) + goto err_parent; spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (!__d_rcu_to_refcount(dentry, nd->seq)) goto err_child; @@ -940,7 +942,6 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, * Don't forget we might have a non-mountpoint managed dentry * that wants to block transit. */ - *inode = path->dentry->d_inode; if (unlikely(managed_dentry_might_block(path->dentry))) return false; @@ -953,6 +954,12 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, path->mnt = mounted; path->dentry = mounted->mnt_root; nd->seq = read_seqcount_begin(&path->dentry->d_seq); + /* + * Update the inode too. We don't need to re-check the + * dentry sequence number here after this d_inode read, + * because a mount-point is always pinned. + */ + *inode = path->dentry->d_inode; } return true; } diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 0bafcc91c27..f9d03abcd04 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -398,7 +398,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) * this offset and save the original offset. */ data->args.offset = filelayout_get_dserver_offset(lseg, offset); - data->mds_offset = offset; /* Perform an asynchronous write */ status = nfs_initiate_write(data, ds->ds_clp->cl_rpcclient, diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6870bc61cee..e6e8f3b9a1d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -91,7 +91,7 @@ static int nfs4_stat_to_errno(int); #define encode_getfh_maxsz (op_encode_hdr_maxsz) #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ ((3+NFS4_FHSIZE) >> 2)) -#define nfs4_fattr_bitmap_maxsz 3 +#define nfs4_fattr_bitmap_maxsz 4 #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e268e3b2349..72716805968 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -864,6 +864,8 @@ static int nfs_write_rpcsetup(struct nfs_page *req, data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; + /* pnfs_set_layoutcommit needs this */ + data->mds_offset = data->args.offset; data->args.pgbase = req->wb_pgbase + offset; data->args.pages = data->pagevec; data->args.count = count; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 29309e25417..b57aab9a118 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -56,16 +56,12 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru lock_ufs(dir->i_sb); ino = ufs_inode_by_name(dir, &dentry->d_name); - if (ino) { + if (ino) inode = ufs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) { - unlock_ufs(dir->i_sb); - return ERR_CAST(inode); - } - } unlock_ufs(dir->i_sb); - d_add(dentry, inode); - return NULL; + if (IS_ERR(inode)) + return ERR_CAST(inode); + return d_splice_alias(inode, dentry); } /* diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3a10ef5914e..6cd5b6403a7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -210,7 +210,7 @@ struct acpi_device_power_state { struct acpi_device_power { int state; /* Current state */ struct acpi_device_power_flags flags; - struct acpi_device_power_state states[4]; /* Power states (D0-D3) */ + struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */ }; /* Performance Management */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index a756bc8d866..4543b6f7586 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -98,8 +98,11 @@ acpi_os_table_override(struct acpi_table_header *existing_table, /* * Spinlock primitives */ + +#ifndef acpi_os_create_lock acpi_status acpi_os_create_lock(acpi_spinlock *out_handle); +#endif void acpi_os_delete_lock(acpi_spinlock handle); diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 5d2a5e9544d..2ce1be9f629 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -159,6 +159,24 @@ static inline void *acpi_os_acquire_object(acpi_cache_t * cache) } while (0) #endif +/* + * When lockdep is enabled, the spin_lock_init() macro stringifies it's + * argument and uses that as a name for the lock in debugging. + * By executing spin_lock_init() in a macro the key changes from "lock" for + * all locks to the name of the argument of acpi_os_create_lock(), which + * prevents lockdep from reporting false positives for ACPICA locks. + */ +#define acpi_os_create_lock(__handle) \ +({ \ + spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock)); \ + \ + if (lock) { \ + *(__handle) = lock; \ + spin_lock_init(*(__handle)); \ + } \ + lock ? AE_OK : AE_NO_MEMORY; \ +}) + #endif /* __KERNEL__ */ #endif /* __ACLINUX_H__ */ diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index e08f344c6cf..3d53efd25ab 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -182,6 +182,7 @@ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ @@ -192,6 +193,7 @@ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ diff --git a/include/linux/irq.h b/include/linux/irq.h index 8b453844663..e26ee3a2f06 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -35,6 +35,16 @@ typedef void (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc); typedef void (*irq_preflow_handler_t)(struct irq_data *data); +/* This type is the placeholder for a hardware interrupt number. It has to + * be big enough to enclose whatever representation is used by a given + * platform. + */ +#ifndef _IRQ_HW_NUMBER_T +#define _IRQ_HW_NUMBER_T +typedef unsigned long irq_hw_number_t; +#endif + + /* * IRQ line status. * @@ -113,14 +123,18 @@ enum { }; struct msi_desc; +struct irq_domain; /** * struct irq_data - per irq and irq chip data passed down to chip functions * @irq: interrupt number + * @hwirq: hardware interrupt number, local to the interrupt domain * @node: node index useful for balancing * @state_use_accessors: status information for irq chip functions. * Use accessor functions to deal with it * @chip: low level interrupt hardware access + * @domain: Interrupt translation domain; responsible for mapping + * between hwirq number and linux irq number. * @handler_data: per-IRQ data for the irq_chip methods * @chip_data: platform-specific per-chip private data for the chip * methods, to allow shared chip implementations @@ -133,9 +147,11 @@ struct msi_desc; */ struct irq_data { unsigned int irq; + irq_hw_number_t hwirq; unsigned int node; unsigned int state_use_accessors; struct irq_chip *chip; + struct irq_domain *domain; void *handler_data; void *chip_data; struct msi_desc *msi_desc; @@ -676,7 +692,8 @@ void irq_gc_mask_disable_reg(struct irq_data *d); void irq_gc_mask_set_bit(struct irq_data *d); void irq_gc_mask_clr_bit(struct irq_data *d); void irq_gc_unmask_enable_reg(struct irq_data *d); -void irq_gc_ack(struct irq_data *d); +void irq_gc_ack_set_bit(struct irq_data *d); +void irq_gc_ack_clr_bit(struct irq_data *d); void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); void irq_gc_eoi(struct irq_data *d); int irq_gc_set_wake(struct irq_data *d, unsigned int on); @@ -716,6 +733,82 @@ static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } #endif /* CONFIG_GENERIC_HARDIRQS */ +/* + * irq-domain - IRQ translation domains + * + * Translation infrastructure between hw and linux irq numbers. + */ +struct device_node; + +/** + * struct irq_domain_ops - Methods for irq_domain objects + * @to_irq: (optional) given a local hardware irq number, return the linux + * irq number. If to_irq is not implemented, then the irq_domain + * will use this translation: irq = (domain->irq_base + hwirq) + * @dt_translate: Given a device tree node and interrupt specifier, decode + * the hardware irq number and linux irq type value. + */ +struct irq_domain_ops { + unsigned int (*to_irq)(struct irq_domain *d, irq_hw_number_t hwirq); + +#ifdef CONFIG_OF + int (*dt_translate)(struct irq_domain *d, struct device_node *node, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); +#endif +}; + +/** + * struct irq_domain - Hardware interrupt number translation object + * @list: Element in global irq_domain list. + * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator + * of the irq_domain is responsible for allocating the array of + * irq_desc structures. + * @ops: pointer to irq_domain methods + * @priv: private data pointer for use by owner. Not touched by irq_domain + * core code. + * @of_node: (optional) Pointer to device tree nodes associated with the + * irq_domain. Used when decoding device tree interrupt specifiers. + */ +struct irq_domain { + struct list_head list; + unsigned int irq_base; + const struct irq_domain_ops *ops; + void *priv; + + struct device_node *of_node; +}; + +/** + * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number + * + * Returns the linux irq number associated with a hardware irq. By default, + * the mapping is irq == domain->irq_base + hwirq, but this mapping can + * be overridden if the irq_domain implements a .to_irq() hook. + */ +static inline unsigned int irq_domain_to_irq(struct irq_domain *d, + irq_hw_number_t hwirq) +{ + return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq; +} + +extern void irq_domain_add(struct irq_domain *domain); +extern void irq_domain_del(struct irq_domain *domain); +extern unsigned int irq_domain_map(struct irq_domain *domain, + irq_hw_number_t hwirq); +extern void irq_domain_unmap(struct irq_domain *domain, irq_hw_number_t hw); + +struct of_device_id; +#ifdef CONFIG_OF +extern void irq_domain_add_simple(struct device_node *controller, int irq_base); +extern void irq_domain_generate_simple(const struct of_device_id *match, + u64 phys_base, unsigned int irq_start); +#else +static inline void irq_domain_generate_simple(const struct of_device_id *match, + u64 phys_base, unsigned int irq_start) { } +#endif + + #endif /* !CONFIG_S390 */ #endif /* _LINUX_IRQ_H */ diff --git a/include/linux/memory.h b/include/linux/memory.h index e1e3b2b84f8..935699b30b7 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -20,6 +20,8 @@ #include <linux/compiler.h> #include <linux/mutex.h> +#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) + struct memory_block { unsigned long start_section_nr; unsigned long end_section_nr; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index c6927a4d157..6ad43554ac0 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -64,6 +64,19 @@ struct mmc_ext_csd { unsigned long long enhanced_area_offset; /* Units: Byte */ unsigned int enhanced_area_size; /* Units: KB */ unsigned int boot_size; /* in bytes */ + u8 raw_partition_support; /* 160 */ + u8 raw_erased_mem_count; /* 181 */ + u8 raw_ext_csd_structure; /* 194 */ + u8 raw_card_type; /* 196 */ + u8 raw_s_a_timeout; /* 217 */ + u8 raw_hc_erase_gap_size; /* 221 */ + u8 raw_erase_timeout_mult; /* 223 */ + u8 raw_hc_erase_grp_size; /* 224 */ + u8 raw_sec_trim_mult; /* 229 */ + u8 raw_sec_erase_mult; /* 230 */ + u8 raw_sec_feature_support;/* 231 */ + u8 raw_trim_mult; /* 232 */ + u8 raw_sectors[4]; /* 212 - 4 bytes */ }; struct sd_scr { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 54b8b4d7b68..9e19477991a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1097,12 +1097,6 @@ struct net_device { #define NETIF_F_ALL_FCOE (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \ NETIF_F_FSO) -#define NETIF_F_ALL_TX_OFFLOADS (NETIF_F_ALL_CSUM | NETIF_F_SG | \ - NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ - NETIF_F_HIGHDMA | \ - NETIF_F_SCTP_CSUM | \ - NETIF_F_ALL_FCOE) - /* * If one device supports one of these features, then enable them * for all in netdev_increment_features. diff --git a/include/linux/of.h b/include/linux/of.h index bfc0ed1b0ce..bd716f8908d 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -195,6 +195,13 @@ extern struct device_node *of_find_node_with_property( extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); +extern int of_property_read_u32_array(const struct device_node *np, + char *propname, + u32 *out_values, + size_t sz); + +extern int of_property_read_string(struct device_node *np, char *propname, + const char **out_string); extern int of_device_is_compatible(const struct device_node *device, const char *); extern int of_device_is_available(const struct device_node *device); @@ -227,12 +234,32 @@ extern void of_attach_node(struct device_node *); extern void of_detach_node(struct device_node *); #endif -#else +#else /* CONFIG_OF */ static inline bool of_have_populated_dt(void) { return false; } +static inline int of_property_read_u32_array(const struct device_node *np, + char *propname, u32 *out_values, size_t sz) +{ + return -ENOSYS; +} + +static inline int of_property_read_string(struct device_node *np, + char *propname, const char **out_string) +{ + return -ENOSYS; +} + #endif /* CONFIG_OF */ + +static inline int of_property_read_u32(const struct device_node *np, + char *propname, + u32 *out_value) +{ + return of_property_read_u32_array(np, propname, out_value, 1); +} + #endif /* _LINUX_OF_H */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 2feda6ee614..3118623c2c1 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -1,11 +1,16 @@ #ifndef __OF_ADDRESS_H #define __OF_ADDRESS_H #include <linux/ioport.h> +#include <linux/errno.h> #include <linux/of.h> extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); +extern struct device_node *of_find_matching_node_by_address( + struct device_node *from, + const struct of_device_id *matches, + u64 base_address); extern void __iomem *of_iomap(struct device_node *device, int index); /* Extract an address from a device, returns the region size and diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 6598c04dab0..aec8025c786 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -46,8 +46,9 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc) return container_of(gc, struct of_mm_gpio_chip, gc); } -extern int of_get_gpio_flags(struct device_node *np, int index, - enum of_gpio_flags *flags); +extern int of_get_named_gpio_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags); + extern unsigned int of_gpio_count(struct device_node *np); extern int of_mm_gpiochip_add(struct device_node *np, @@ -60,8 +61,8 @@ extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np); #else /* CONFIG_OF_GPIO */ /* Drivers may not strictly depend on the GPIO support, so let them link. */ -static inline int of_get_gpio_flags(struct device_node *np, int index, - enum of_gpio_flags *flags) +static inline int of_get_named_gpio_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags) { return -ENOSYS; } @@ -77,7 +78,38 @@ static inline void of_gpiochip_remove(struct gpio_chip *gc) { } #endif /* CONFIG_OF_GPIO */ /** - * of_get_gpio - Get a GPIO number to use with GPIO API + * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * @np: device node to get GPIO from + * @index: index of the GPIO + * @flags: a flags pointer to fill in + * + * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * value on the error condition. If @flags is not NULL the function also fills + * in flags for the GPIO. + */ +static inline int of_get_gpio_flags(struct device_node *np, int index, + enum of_gpio_flags *flags) +{ + return of_get_named_gpio_flags(np, "gpios", index, flags); +} + +/** + * of_get_named_gpio() - Get a GPIO number to use with GPIO API + * @np: device node to get GPIO from + * @propname: Name of property containing gpio specifier(s) + * @index: index of the GPIO + * + * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * value on the error condition. + */ +static inline int of_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + return of_get_named_gpio_flags(np, propname, index, NULL); +} + +/** + * of_get_gpio() - Get a GPIO number to use with GPIO API * @np: device node to get GPIO from * @index: index of the GPIO * diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index e6955f5d1f0..67a2a572894 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -63,6 +63,7 @@ extern int of_irq_map_one(struct device_node *device, int index, extern unsigned int irq_create_of_mapping(struct device_node *controller, const u32 *intspec, unsigned int intsize); +extern void irq_dispose_mapping(unsigned int irq); extern int of_irq_to_resource(struct device_node *dev, int index, struct resource *r); extern int of_irq_count(struct device_node *dev); @@ -70,6 +71,7 @@ extern int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int nr_irqs); extern struct device_node *of_irq_find_parent(struct device_node *child); + #endif /* CONFIG_OF_IRQ */ #endif /* CONFIG_OF */ #endif /* __OF_IRQ_H */ diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index fb51ae38cea..5a6f458a4bb 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -20,6 +20,40 @@ #include <linux/platform_device.h> /** + * struct of_dev_auxdata - lookup table entry for device names & platform_data + * @compatible: compatible value of node to match against node + * @phys_addr: Start address of registers to match against node + * @name: Name to assign for matching nodes + * @platform_data: platform_data to assign for matching nodes + * + * This lookup table allows the caller of of_platform_populate() to override + * the names of devices when creating devices from the device tree. The table + * should be terminated with an empty entry. It also allows the platform_data + * pointer to be set. + * + * The reason for this functionality is that some Linux infrastructure uses + * the device name to look up a specific device, but the Linux-specific names + * are not encoded into the device tree, so the kernel needs to provide specific + * values. + * + * Note: Using an auxdata lookup table should be considered a last resort when + * converting a platform to use the DT. Normally the automatically generated + * device name will not matter, and drivers should obtain data from the device + * node instead of from an anonymouns platform_data pointer. + */ +struct of_dev_auxdata { + char *compatible; + resource_size_t phys_addr; + char *name; + void *platform_data; +}; + +/* Macro to simplify populating a lookup table */ +#define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \ + { .compatible = _compat, .phys_addr = _phys, .name = _name, \ + .platform_data = _pdata } + +/** * of_platform_driver - Legacy of-aware driver for platform devices. * * An of_platform_driver driver is attached to a basic platform_device on @@ -40,6 +74,8 @@ struct of_platform_driver #define to_of_platform_driver(drv) \ container_of(drv,struct of_platform_driver, driver) +extern const struct of_device_id of_default_bus_match_table[]; + /* Platform drivers register/unregister */ extern struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id, @@ -55,6 +91,10 @@ extern struct platform_device *of_platform_device_create(struct device_node *np, extern int of_platform_bus_probe(struct device_node *root, const struct of_device_id *matches, struct device *parent); +extern int of_platform_populate(struct device_node *root, + const struct of_device_id *matches, + const struct of_dev_auxdata *lookup, + struct device *parent); #endif /* !CONFIG_SPARC */ #endif /* CONFIG_OF_DEVICE */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 496770a9648..14a6c7b545d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -844,6 +844,7 @@ enum cpu_idle_type { #define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */ #define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */ #define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */ +#define SD_OVERLAP 0x2000 /* sched_domains of this level overlap */ enum powersavings_balance_level { POWERSAVINGS_BALANCE_NONE = 0, /* No power saving load balance */ @@ -893,16 +894,21 @@ static inline int sd_power_saving_flags(void) return 0; } -struct sched_group { - struct sched_group *next; /* Must be a circular list */ +struct sched_group_power { atomic_t ref; - /* * CPU power of this group, SCHED_LOAD_SCALE being max power for a * single CPU. */ - unsigned int cpu_power, cpu_power_orig; + unsigned int power, power_orig; +}; + +struct sched_group { + struct sched_group *next; /* Must be a circular list */ + atomic_t ref; + unsigned int group_weight; + struct sched_group_power *sgp; /* * The CPUs this group covers. @@ -1254,6 +1260,9 @@ struct task_struct { #ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting; char rcu_read_unlock_special; +#if defined(CONFIG_RCU_BOOST) && defined(CONFIG_TREE_PREEMPT_RCU) + int rcu_boosted; +#endif /* #if defined(CONFIG_RCU_BOOST) && defined(CONFIG_TREE_PREEMPT_RCU) */ struct list_head rcu_node_entry; #endif /* #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_TREE_PREEMPT_RCU diff --git a/include/linux/sdla.h b/include/linux/sdla.h index 564acd3a71c..9995c7fc3f6 100644 --- a/include/linux/sdla.h +++ b/include/linux/sdla.h @@ -112,11 +112,7 @@ struct sdla_dlci_conf { short Tb_max; }; -#ifndef __KERNEL__ - -void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet); - -#else +#ifdef __KERNEL__ /* important Z80 window addresses */ #define SDLA_CONTROL_WND 0xE000 diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index dd6847e5d6e..6506458ccd3 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -63,6 +63,7 @@ typedef enum { SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */ SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */ SCTP_CMD_TIMER_START, /* Start a timer. */ + SCTP_CMD_TIMER_START_ONCE, /* Start a timer once */ SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ SCTP_CMD_TIMER_STOP, /* Stop a timer. */ SCTP_CMD_INIT_CHOOSE_TRANSPORT, /* Choose transport for an INIT. */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 99b027b2adc..ca4693b4e09 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -80,7 +80,7 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); -void sctp_queue_purge_ulpevents(struct sk_buff_head *list); +unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list); struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 73290056cfb..aa8feed23b0 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -1,5 +1,5 @@ -obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o +obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o irqdomain.o obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 31a9db71190..3a2cab407b9 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -101,10 +101,10 @@ void irq_gc_unmask_enable_reg(struct irq_data *d) } /** - * irq_gc_ack - Ack pending interrupt + * irq_gc_ack_set_bit - Ack pending interrupt via setting bit * @d: irq_data */ -void irq_gc_ack(struct irq_data *d) +void irq_gc_ack_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); u32 mask = 1 << (d->irq - gc->irq_base); @@ -115,6 +115,20 @@ void irq_gc_ack(struct irq_data *d) } /** + * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit + * @d: irq_data + */ +void irq_gc_ack_clr_bit(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = ~(1 << (d->irq - gc->irq_base)); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_gc_unlock(gc); +} + +/** * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt * @d: irq_data */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c new file mode 100644 index 00000000000..7e251cd810b --- /dev/null +++ b/kernel/irq/irqdomain.c @@ -0,0 +1,215 @@ +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +static LIST_HEAD(irq_domain_list); +static DEFINE_MUTEX(irq_domain_mutex); + +/** + * irq_domain_add() - Register an irq_domain + * @domain: ptr to initialized irq_domain structure + * + * Registers an irq_domain structure. The irq_domain must at a minimum be + * initialized with an ops structure pointer, and either a ->to_irq hook or + * a valid irq_base value. Everything else is optional. + */ +void irq_domain_add(struct irq_domain *domain) +{ + mutex_lock(&irq_domain_mutex); + list_add(&domain->list, &irq_domain_list); + mutex_unlock(&irq_domain_mutex); +} + +/** + * irq_domain_del() - Unregister an irq_domain + * @domain: ptr to registered irq_domain. + */ +void irq_domain_del(struct irq_domain *domain) +{ + mutex_lock(&irq_domain_mutex); + list_del(&domain->list); + mutex_unlock(&irq_domain_mutex); +} + +/** + * irq_domain_map() - Allocate and/or increment a reference to a hwirq + * + * TODO: Establish a linux irq number mapping for a hardware irq. If the + * mapping already exists, then increment the reference count and return the + * linux irq number. + * + * At the moment this function is an empty stub since irq_domain initially + * only supports the common case of mapping hw irq numbers into a contiguous + * range of pre-allocated linux irq_descs based at irq_domain->irq_base. When + * irq_domains are extended either to support non-contiguous mappings (ie. to + * support MSI interrupts) or to remove preallocation of all irq_descs (as + * powerpc does so that irq_descs are only allocated for in-use irq inputs), + * then this function will be extended to implement the irq_desc allocation + * and reference counting. + * + * Any caller to this function must arrange to also call irq_domain_unmap() + * if the irq ever becomes unused again. + */ +unsigned int irq_domain_map(struct irq_domain *domain, irq_hw_number_t hwirq) +{ + int irq = irq_domain_to_irq(domain, hwirq); + struct irq_data *d = irq_get_irq_data(irq); + + d->domain = domain; + d->hwirq = hwirq; + + return irq; +} + +/** + * irq_domain_unmap() - Release a reference to a hwirq + * + * TODO: decrement the reference count on a hardware irq number. If the ref + * count reaches zero, then the irq_desc can be freed. + * + * At the moment this function is an empty stub. See the comment on + * irq_domain_map() for details. + */ +void irq_domain_unmap(struct irq_domain *domain, irq_hw_number_t hwirq) +{ + int irq = irq_domain_to_irq(domain, hwirq); + struct irq_data *d = irq_get_irq_data(irq); + + d->domain = NULL; +} + +#if defined(CONFIG_OF_IRQ) && !defined(CONFIG_PPC) + +/* + * A handful of architectures use NO_IRQ, which must be used to avoid breaking + * things when using the device tree. This is intended to be temporary until + * the remaining NO_IRQ users can be removed + */ +#ifndef NO_IRQ +#define NO_IRQ 0 +#endif + +/** + * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec + * + * Used by the device tree interrupt mapping code to translate a device tree + * interrupt specifier to a valid linux irq number. Returns either a valid + * linux IRQ number or 0. + * + * When the caller no longer need the irq number returned by this function it + * should arrange to call irq_dispose_mapping(). + */ +unsigned int irq_create_of_mapping(struct device_node *controller, + const u32 *intspec, unsigned int intsize) +{ + struct irq_domain *domain; + irq_hw_number_t hwirq; + unsigned int irq, type; + int rc = -ENODEV; + + /* Find a domain which can translate the irq spec */ + mutex_lock(&irq_domain_mutex); + list_for_each_entry(domain, &irq_domain_list, list) { + if (!domain->ops->dt_translate) + continue; + rc = domain->ops->dt_translate(domain, controller, + intspec, intsize, &hwirq, &type); + if (rc == 0) + break; + } + mutex_unlock(&irq_domain_mutex); + +#if defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE) + /* + * Temporary: preserves current behaviour until mips/microblaze + * register an irq_domain + */ + if (rc != 0) { + pr_debug("%s: fallback mapping for irq=%i\n", + controller->full_name, irq); + return intspec[0]; + } +#else + if (rc != 0) + return NO_IRQ; +#endif + + irq = irq_domain_map(domain, hwirq); + if (type != IRQ_TYPE_NONE) + irq_set_irq_type(irq, type); + pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n", + controller->full_name, (int)hwirq, irq, type); + return irq; +} +EXPORT_SYMBOL_GPL(irq_create_of_mapping); + +/** + * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping() + * @irq: linux irq number to be discarded + * + * Calling this function indicates the caller no longer needs a reference to + * the linux irq number returned by a prior call to irq_create_of_mapping(). + */ +void irq_dispose_mapping(unsigned int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + irq_domain_unmap(d->domain, d->hwirq); +} +EXPORT_SYMBOL_GPL(irq_dispose_mapping); + +int irq_domain_simple_dt_translate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + if (d->of_node != controller) + return -EINVAL; + if (intsize != 1) + return -EINVAL; + + *out_hwirq = intspec[0]; + *out_type = IRQ_TYPE_NONE; + return 0; +} + +struct irq_domain_ops irq_domain_simple_ops = { + .dt_translate = irq_domain_simple_dt_translate, +}; + +/** + * irq_domain_create_simple() - Set up a 'simple' translation range + */ +void irq_domain_add_simple(struct device_node *controller, int irq_base) +{ + struct irq_domain *domain; + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) { + WARN_ON(1); + return; + } + + domain->irq_base = irq_base; + domain->of_node = of_node_get(controller); + domain->ops = &irq_domain_simple_ops; + irq_domain_add(domain); +} +EXPORT_SYMBOL_GPL(irq_domain_add_simple); + +void irq_domain_generate_simple(const struct of_device_id *match, + u64 phys_base, unsigned int irq_start) +{ + struct device_node *node; + pr_info("looking for phys_base=%llx, irq_start=%i\n", + (unsigned long long) phys_base, (int) irq_start); + node = of_find_matching_node_by_address(NULL, match, phys_base); + if (node) + irq_domain_add_simple(node, irq_start); + else + pr_info("no node found\n"); +} +EXPORT_SYMBOL_GPL(irq_domain_generate_simple); +#endif diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7e59ffb3d0b..ba06207b1dd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -84,9 +84,32 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); static struct rcu_state *rcu_state; +/* + * The rcu_scheduler_active variable transitions from zero to one just + * before the first task is spawned. So when this variable is zero, RCU + * can assume that there is but one task, allowing RCU to (for example) + * optimized synchronize_sched() to a simple barrier(). When this variable + * is one, RCU must actually do all the hard work required to detect real + * grace periods. This variable is also used to suppress boot-time false + * positives from lockdep-RCU error checking. + */ int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); +/* + * The rcu_scheduler_fully_active variable transitions from zero to one + * during the early_initcall() processing, which is after the scheduler + * is capable of creating new tasks. So RCU processing (for example, + * creating tasks for RCU priority boosting) must be delayed until after + * rcu_scheduler_fully_active transitions from zero to one. We also + * currently delay invocation of any RCU callbacks until after this point. + * + * It might later prove better for people registering RCU callbacks during + * early boot to take responsibility for these callbacks, but one step at + * a time. + */ +static int rcu_scheduler_fully_active __read_mostly; + #ifdef CONFIG_RCU_BOOST /* @@ -98,7 +121,6 @@ DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops); DEFINE_PER_CPU(char, rcu_cpu_has_work); -static char rcu_kthreads_spawnable; #endif /* #ifdef CONFIG_RCU_BOOST */ @@ -1467,6 +1489,8 @@ static void rcu_process_callbacks(struct softirq_action *unused) */ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) { + if (unlikely(!ACCESS_ONCE(rcu_scheduler_fully_active))) + return; if (likely(!rsp->boost)) { rcu_do_batch(rsp, rdp); return; diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 14dc7dd0090..8aafbb80b8b 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -68,6 +68,7 @@ struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state); DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); static struct rcu_state *rcu_state = &rcu_preempt_state; +static void rcu_read_unlock_special(struct task_struct *t); static int rcu_preempted_readers_exp(struct rcu_node *rnp); /* @@ -147,7 +148,7 @@ static void rcu_preempt_note_context_switch(int cpu) struct rcu_data *rdp; struct rcu_node *rnp; - if (t->rcu_read_lock_nesting && + if (t->rcu_read_lock_nesting > 0 && (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) { /* Possibly blocking in an RCU read-side critical section. */ @@ -190,6 +191,14 @@ static void rcu_preempt_note_context_switch(int cpu) rnp->gp_tasks = &t->rcu_node_entry; } raw_spin_unlock_irqrestore(&rnp->lock, flags); + } else if (t->rcu_read_lock_nesting < 0 && + t->rcu_read_unlock_special) { + + /* + * Complete exit from RCU read-side critical section on + * behalf of preempted instance of __rcu_read_unlock(). + */ + rcu_read_unlock_special(t); } /* @@ -284,7 +293,7 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t, * notify RCU core processing or task having blocked during the RCU * read-side critical section. */ -static void rcu_read_unlock_special(struct task_struct *t) +static noinline void rcu_read_unlock_special(struct task_struct *t) { int empty; int empty_exp; @@ -309,7 +318,7 @@ static void rcu_read_unlock_special(struct task_struct *t) } /* Hardware IRQ handlers cannot block. */ - if (in_irq()) { + if (in_irq() || in_serving_softirq()) { local_irq_restore(flags); return; } @@ -342,6 +351,11 @@ static void rcu_read_unlock_special(struct task_struct *t) #ifdef CONFIG_RCU_BOOST if (&t->rcu_node_entry == rnp->boost_tasks) rnp->boost_tasks = np; + /* Snapshot and clear ->rcu_boosted with rcu_node lock held. */ + if (t->rcu_boosted) { + special |= RCU_READ_UNLOCK_BOOSTED; + t->rcu_boosted = 0; + } #endif /* #ifdef CONFIG_RCU_BOOST */ t->rcu_blocked_node = NULL; @@ -358,7 +372,6 @@ static void rcu_read_unlock_special(struct task_struct *t) #ifdef CONFIG_RCU_BOOST /* Unboost if we were boosted. */ if (special & RCU_READ_UNLOCK_BOOSTED) { - t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BOOSTED; rt_mutex_unlock(t->rcu_boost_mutex); t->rcu_boost_mutex = NULL; } @@ -387,13 +400,22 @@ void __rcu_read_unlock(void) struct task_struct *t = current; barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */ - --t->rcu_read_lock_nesting; - barrier(); /* decrement before load of ->rcu_read_unlock_special */ - if (t->rcu_read_lock_nesting == 0 && - unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) - rcu_read_unlock_special(t); + if (t->rcu_read_lock_nesting != 1) + --t->rcu_read_lock_nesting; + else { + t->rcu_read_lock_nesting = INT_MIN; + barrier(); /* assign before ->rcu_read_unlock_special load */ + if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) + rcu_read_unlock_special(t); + barrier(); /* ->rcu_read_unlock_special load before assign */ + t->rcu_read_lock_nesting = 0; + } #ifdef CONFIG_PROVE_LOCKING - WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0); + { + int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting); + + WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2); + } #endif /* #ifdef CONFIG_PROVE_LOCKING */ } EXPORT_SYMBOL_GPL(__rcu_read_unlock); @@ -589,7 +611,8 @@ static void rcu_preempt_check_callbacks(int cpu) rcu_preempt_qs(cpu); return; } - if (per_cpu(rcu_preempt_data, cpu).qs_pending) + if (t->rcu_read_lock_nesting > 0 && + per_cpu(rcu_preempt_data, cpu).qs_pending) t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS; } @@ -695,9 +718,12 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock_irqsave(&rnp->lock, flags); for (;;) { - if (!sync_rcu_preempt_exp_done(rnp)) + if (!sync_rcu_preempt_exp_done(rnp)) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); break; + } if (rnp->parent == NULL) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); wake_up(&sync_rcu_preempt_exp_wq); break; } @@ -707,7 +733,6 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock(&rnp->lock); /* irqs already disabled */ rnp->expmask &= ~mask; } - raw_spin_unlock_irqrestore(&rnp->lock, flags); } /* @@ -1174,7 +1199,7 @@ static int rcu_boost(struct rcu_node *rnp) t = container_of(tb, struct task_struct, rcu_node_entry); rt_mutex_init_proxy_locked(&mtx, t); t->rcu_boost_mutex = &mtx; - t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED; + t->rcu_boosted = 1; raw_spin_unlock_irqrestore(&rnp->lock, flags); rt_mutex_lock(&mtx); /* Side effect: boosts task t's priority. */ rt_mutex_unlock(&mtx); /* Keep lockdep happy. */ @@ -1532,7 +1557,7 @@ static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu) struct sched_param sp; struct task_struct *t; - if (!rcu_kthreads_spawnable || + if (!rcu_scheduler_fully_active || per_cpu(rcu_cpu_kthread_task, cpu) != NULL) return 0; t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu); @@ -1639,7 +1664,7 @@ static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp, struct sched_param sp; struct task_struct *t; - if (!rcu_kthreads_spawnable || + if (!rcu_scheduler_fully_active || rnp->qsmaskinit == 0) return 0; if (rnp->node_kthread_task == NULL) { @@ -1665,7 +1690,7 @@ static int __init rcu_spawn_kthreads(void) int cpu; struct rcu_node *rnp; - rcu_kthreads_spawnable = 1; + rcu_scheduler_fully_active = 1; for_each_possible_cpu(cpu) { per_cpu(rcu_cpu_has_work, cpu) = 0; if (cpu_online(cpu)) @@ -1687,7 +1712,7 @@ static void __cpuinit rcu_prepare_kthreads(int cpu) struct rcu_node *rnp = rdp->mynode; /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */ - if (rcu_kthreads_spawnable) { + if (rcu_scheduler_fully_active) { (void)rcu_spawn_one_cpu_kthread(cpu); if (rnp->node_kthread_task == NULL) (void)rcu_spawn_one_node_kthread(rcu_state, rnp); @@ -1726,6 +1751,13 @@ static void rcu_cpu_kthread_setrt(int cpu, int to_rt) { } +static int __init rcu_scheduler_really_started(void) +{ + rcu_scheduler_fully_active = 1; + return 0; +} +early_initcall(rcu_scheduler_really_started); + static void __cpuinit rcu_prepare_kthreads(int cpu) { } diff --git a/kernel/sched.c b/kernel/sched.c index 9769c756ad6..fde6ff90352 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2544,13 +2544,9 @@ static int ttwu_remote(struct task_struct *p, int wake_flags) } #ifdef CONFIG_SMP -static void sched_ttwu_pending(void) +static void sched_ttwu_do_pending(struct task_struct *list) { struct rq *rq = this_rq(); - struct task_struct *list = xchg(&rq->wake_list, NULL); - - if (!list) - return; raw_spin_lock(&rq->lock); @@ -2563,9 +2559,45 @@ static void sched_ttwu_pending(void) raw_spin_unlock(&rq->lock); } +#ifdef CONFIG_HOTPLUG_CPU + +static void sched_ttwu_pending(void) +{ + struct rq *rq = this_rq(); + struct task_struct *list = xchg(&rq->wake_list, NULL); + + if (!list) + return; + + sched_ttwu_do_pending(list); +} + +#endif /* CONFIG_HOTPLUG_CPU */ + void scheduler_ipi(void) { - sched_ttwu_pending(); + struct rq *rq = this_rq(); + struct task_struct *list = xchg(&rq->wake_list, NULL); + + if (!list) + return; + + /* + * Not all reschedule IPI handlers call irq_enter/irq_exit, since + * traditionally all their work was done from the interrupt return + * path. Now that we actually do some work, we need to make sure + * we do call them. + * + * Some archs already do call them, luckily irq_enter/exit nest + * properly. + * + * Arguably we should visit all archs and update all handlers, + * however a fair share of IPIs are still resched only so this would + * somewhat pessimize the simple resched case. + */ + irq_enter(); + sched_ttwu_do_pending(list); + irq_exit(); } static void ttwu_queue_remote(struct task_struct *p, int cpu) @@ -6557,7 +6589,7 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, break; } - if (!group->cpu_power) { + if (!group->sgp->power) { printk(KERN_CONT "\n"); printk(KERN_ERR "ERROR: domain->cpu_power not " "set\n"); @@ -6581,9 +6613,9 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, cpulist_scnprintf(str, sizeof(str), sched_group_cpus(group)); printk(KERN_CONT " %s", str); - if (group->cpu_power != SCHED_POWER_SCALE) { + if (group->sgp->power != SCHED_POWER_SCALE) { printk(KERN_CONT " (cpu_power = %d)", - group->cpu_power); + group->sgp->power); } group = group->next; @@ -6774,11 +6806,39 @@ static struct root_domain *alloc_rootdomain(void) return rd; } +static void free_sched_groups(struct sched_group *sg, int free_sgp) +{ + struct sched_group *tmp, *first; + + if (!sg) + return; + + first = sg; + do { + tmp = sg->next; + + if (free_sgp && atomic_dec_and_test(&sg->sgp->ref)) + kfree(sg->sgp); + + kfree(sg); + sg = tmp; + } while (sg != first); +} + static void free_sched_domain(struct rcu_head *rcu) { struct sched_domain *sd = container_of(rcu, struct sched_domain, rcu); - if (atomic_dec_and_test(&sd->groups->ref)) + + /* + * If its an overlapping domain it has private groups, iterate and + * nuke them all. + */ + if (sd->flags & SD_OVERLAP) { + free_sched_groups(sd->groups, 1); + } else if (atomic_dec_and_test(&sd->groups->ref)) { + kfree(sd->groups->sgp); kfree(sd->groups); + } kfree(sd); } @@ -6945,6 +7005,7 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0; struct sd_data { struct sched_domain **__percpu sd; struct sched_group **__percpu sg; + struct sched_group_power **__percpu sgp; }; struct s_data { @@ -6964,15 +7025,73 @@ struct sched_domain_topology_level; typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu); typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); +#define SDTL_OVERLAP 0x01 + struct sched_domain_topology_level { sched_domain_init_f init; sched_domain_mask_f mask; + int flags; struct sd_data data; }; -/* - * Assumes the sched_domain tree is fully constructed - */ +static int +build_overlap_sched_groups(struct sched_domain *sd, int cpu) +{ + struct sched_group *first = NULL, *last = NULL, *groups = NULL, *sg; + const struct cpumask *span = sched_domain_span(sd); + struct cpumask *covered = sched_domains_tmpmask; + struct sd_data *sdd = sd->private; + struct sched_domain *child; + int i; + + cpumask_clear(covered); + + for_each_cpu(i, span) { + struct cpumask *sg_span; + + if (cpumask_test_cpu(i, covered)) + continue; + + sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, cpu_to_node(i)); + + if (!sg) + goto fail; + + sg_span = sched_group_cpus(sg); + + child = *per_cpu_ptr(sdd->sd, i); + if (child->child) { + child = child->child; + cpumask_copy(sg_span, sched_domain_span(child)); + } else + cpumask_set_cpu(i, sg_span); + + cpumask_or(covered, covered, sg_span); + + sg->sgp = *per_cpu_ptr(sdd->sgp, cpumask_first(sg_span)); + atomic_inc(&sg->sgp->ref); + + if (cpumask_test_cpu(cpu, sg_span)) + groups = sg; + + if (!first) + first = sg; + if (last) + last->next = sg; + last = sg; + last->next = first; + } + sd->groups = groups; + + return 0; + +fail: + free_sched_groups(first, 0); + + return -ENOMEM; +} + static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) { struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu); @@ -6981,24 +7100,24 @@ static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) if (child) cpu = cpumask_first(sched_domain_span(child)); - if (sg) + if (sg) { *sg = *per_cpu_ptr(sdd->sg, cpu); + (*sg)->sgp = *per_cpu_ptr(sdd->sgp, cpu); + atomic_set(&(*sg)->sgp->ref, 1); /* for claim_allocations */ + } return cpu; } /* - * build_sched_groups takes the cpumask we wish to span, and a pointer - * to a function which identifies what group(along with sched group) a CPU - * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids - * (due to the fact that we keep track of groups covered with a struct cpumask). - * * build_sched_groups will build a circular linked list of the groups * covered by the given span, and will set each group's ->cpumask correctly, * and ->cpu_power to 0. + * + * Assumes the sched_domain tree is fully constructed */ -static void -build_sched_groups(struct sched_domain *sd) +static int +build_sched_groups(struct sched_domain *sd, int cpu) { struct sched_group *first = NULL, *last = NULL; struct sd_data *sdd = sd->private; @@ -7006,6 +7125,12 @@ build_sched_groups(struct sched_domain *sd) struct cpumask *covered; int i; + get_group(cpu, sdd, &sd->groups); + atomic_inc(&sd->groups->ref); + + if (cpu != cpumask_first(sched_domain_span(sd))) + return 0; + lockdep_assert_held(&sched_domains_mutex); covered = sched_domains_tmpmask; @@ -7020,7 +7145,7 @@ build_sched_groups(struct sched_domain *sd) continue; cpumask_clear(sched_group_cpus(sg)); - sg->cpu_power = 0; + sg->sgp->power = 0; for_each_cpu(j, span) { if (get_group(j, sdd, NULL) != group) @@ -7037,6 +7162,8 @@ build_sched_groups(struct sched_domain *sd) last = sg; } last->next = first; + + return 0; } /* @@ -7051,12 +7178,17 @@ build_sched_groups(struct sched_domain *sd) */ static void init_sched_groups_power(int cpu, struct sched_domain *sd) { - WARN_ON(!sd || !sd->groups); + struct sched_group *sg = sd->groups; - if (cpu != group_first_cpu(sd->groups)) - return; + WARN_ON(!sd || !sg); + + do { + sg->group_weight = cpumask_weight(sched_group_cpus(sg)); + sg = sg->next; + } while (sg != sd->groups); - sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups)); + if (cpu != group_first_cpu(sg)) + return; update_group_power(sd, cpu); } @@ -7177,15 +7309,15 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, static void claim_allocations(int cpu, struct sched_domain *sd) { struct sd_data *sdd = sd->private; - struct sched_group *sg = sd->groups; WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd); *per_cpu_ptr(sdd->sd, cpu) = NULL; - if (cpu == cpumask_first(sched_group_cpus(sg))) { - WARN_ON_ONCE(*per_cpu_ptr(sdd->sg, cpu) != sg); + if (atomic_read(&(*per_cpu_ptr(sdd->sg, cpu))->ref)) *per_cpu_ptr(sdd->sg, cpu) = NULL; - } + + if (atomic_read(&(*per_cpu_ptr(sdd->sgp, cpu))->ref)) + *per_cpu_ptr(sdd->sgp, cpu) = NULL; } #ifdef CONFIG_SCHED_SMT @@ -7210,7 +7342,7 @@ static struct sched_domain_topology_level default_topology[] = { #endif { sd_init_CPU, cpu_cpu_mask, }, #ifdef CONFIG_NUMA - { sd_init_NODE, cpu_node_mask, }, + { sd_init_NODE, cpu_node_mask, SDTL_OVERLAP, }, { sd_init_ALLNODES, cpu_allnodes_mask, }, #endif { NULL, }, @@ -7234,9 +7366,14 @@ static int __sdt_alloc(const struct cpumask *cpu_map) if (!sdd->sg) return -ENOMEM; + sdd->sgp = alloc_percpu(struct sched_group_power *); + if (!sdd->sgp) + return -ENOMEM; + for_each_cpu(j, cpu_map) { struct sched_domain *sd; struct sched_group *sg; + struct sched_group_power *sgp; sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), GFP_KERNEL, cpu_to_node(j)); @@ -7251,6 +7388,13 @@ static int __sdt_alloc(const struct cpumask *cpu_map) return -ENOMEM; *per_cpu_ptr(sdd->sg, j) = sg; + + sgp = kzalloc_node(sizeof(struct sched_group_power), + GFP_KERNEL, cpu_to_node(j)); + if (!sgp) + return -ENOMEM; + + *per_cpu_ptr(sdd->sgp, j) = sgp; } } @@ -7266,11 +7410,15 @@ static void __sdt_free(const struct cpumask *cpu_map) struct sd_data *sdd = &tl->data; for_each_cpu(j, cpu_map) { - kfree(*per_cpu_ptr(sdd->sd, j)); + struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j); + if (sd && (sd->flags & SD_OVERLAP)) + free_sched_groups(sd->groups, 0); kfree(*per_cpu_ptr(sdd->sg, j)); + kfree(*per_cpu_ptr(sdd->sgp, j)); } free_percpu(sdd->sd); free_percpu(sdd->sg); + free_percpu(sdd->sgp); } } @@ -7316,8 +7464,13 @@ static int build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_topology_level *tl; sd = NULL; - for (tl = sched_domain_topology; tl->init; tl++) + for (tl = sched_domain_topology; tl->init; tl++) { sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i); + if (tl->flags & SDTL_OVERLAP || sched_feat(FORCE_SD_OVERLAP)) + sd->flags |= SD_OVERLAP; + if (cpumask_equal(cpu_map, sched_domain_span(sd))) + break; + } while (sd->child) sd = sd->child; @@ -7329,13 +7482,13 @@ static int build_sched_domains(const struct cpumask *cpu_map, for_each_cpu(i, cpu_map) { for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { sd->span_weight = cpumask_weight(sched_domain_span(sd)); - get_group(i, sd->private, &sd->groups); - atomic_inc(&sd->groups->ref); - - if (i != cpumask_first(sched_domain_span(sd))) - continue; - - build_sched_groups(sd); + if (sd->flags & SD_OVERLAP) { + if (build_overlap_sched_groups(sd, i)) + goto error; + } else { + if (build_sched_groups(sd, i)) + goto error; + } } } @@ -7757,6 +7910,9 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq) #endif #endif cfs_rq->min_vruntime = (u64)(-(1LL << 20)); +#ifndef CONFIG_64BIT + cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; +#endif } static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 433491c2dc8..c768588e180 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1585,7 +1585,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, } /* Adjust by relative CPU power of the group */ - avg_load = (avg_load * SCHED_POWER_SCALE) / group->cpu_power; + avg_load = (avg_load * SCHED_POWER_SCALE) / group->sgp->power; if (local_group) { this_load = avg_load; @@ -2631,7 +2631,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) power >>= SCHED_POWER_SHIFT; } - sdg->cpu_power_orig = power; + sdg->sgp->power_orig = power; if (sched_feat(ARCH_POWER)) power *= arch_scale_freq_power(sd, cpu); @@ -2647,7 +2647,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) power = 1; cpu_rq(cpu)->cpu_power = power; - sdg->cpu_power = power; + sdg->sgp->power = power; } static void update_group_power(struct sched_domain *sd, int cpu) @@ -2665,11 +2665,11 @@ static void update_group_power(struct sched_domain *sd, int cpu) group = child->groups; do { - power += group->cpu_power; + power += group->sgp->power; group = group->next; } while (group != child->groups); - sdg->cpu_power = power; + sdg->sgp->power = power; } /* @@ -2691,7 +2691,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group) /* * If ~90% of the cpu_power is still there, we're good. */ - if (group->cpu_power * 32 > group->cpu_power_orig * 29) + if (group->sgp->power * 32 > group->sgp->power_orig * 29) return 1; return 0; @@ -2771,7 +2771,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, } /* Adjust by relative CPU power of the group */ - sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / group->cpu_power; + sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / group->sgp->power; /* * Consider the group unbalanced when the imbalance is larger @@ -2788,7 +2788,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, if ((max_cpu_load - min_cpu_load) >= avg_load_per_task && max_nr_running > 1) sgs->group_imb = 1; - sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, + sgs->group_capacity = DIV_ROUND_CLOSEST(group->sgp->power, SCHED_POWER_SCALE); if (!sgs->group_capacity) sgs->group_capacity = fix_small_capacity(sd, group); @@ -2877,7 +2877,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, return; sds->total_load += sgs.group_load; - sds->total_pwr += sg->cpu_power; + sds->total_pwr += sg->sgp->power; /* * In case the child domain prefers tasks go to siblings @@ -2962,7 +2962,7 @@ static int check_asym_packing(struct sched_domain *sd, if (this_cpu > busiest_cpu) return 0; - *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->cpu_power, + *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->sgp->power, SCHED_POWER_SCALE); return 1; } @@ -2993,7 +2993,7 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds, scaled_busy_load_per_task = sds->busiest_load_per_task * SCHED_POWER_SCALE; - scaled_busy_load_per_task /= sds->busiest->cpu_power; + scaled_busy_load_per_task /= sds->busiest->sgp->power; if (sds->max_load - sds->this_load + scaled_busy_load_per_task >= (scaled_busy_load_per_task * imbn)) { @@ -3007,28 +3007,28 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds, * moving them. */ - pwr_now += sds->busiest->cpu_power * + pwr_now += sds->busiest->sgp->power * min(sds->busiest_load_per_task, sds->max_load); - pwr_now += sds->this->cpu_power * + pwr_now += sds->this->sgp->power * min(sds->this_load_per_task, sds->this_load); pwr_now /= SCHED_POWER_SCALE; /* Amount of load we'd subtract */ tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) / - sds->busiest->cpu_power; + sds->busiest->sgp->power; if (sds->max_load > tmp) - pwr_move += sds->busiest->cpu_power * + pwr_move += sds->busiest->sgp->power * min(sds->busiest_load_per_task, sds->max_load - tmp); /* Amount of load we'd add */ - if (sds->max_load * sds->busiest->cpu_power < + if (sds->max_load * sds->busiest->sgp->power < sds->busiest_load_per_task * SCHED_POWER_SCALE) - tmp = (sds->max_load * sds->busiest->cpu_power) / - sds->this->cpu_power; + tmp = (sds->max_load * sds->busiest->sgp->power) / + sds->this->sgp->power; else tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) / - sds->this->cpu_power; - pwr_move += sds->this->cpu_power * + sds->this->sgp->power; + pwr_move += sds->this->sgp->power * min(sds->this_load_per_task, sds->this_load + tmp); pwr_move /= SCHED_POWER_SCALE; @@ -3074,7 +3074,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_POWER_SCALE); - load_above_capacity /= sds->busiest->cpu_power; + load_above_capacity /= sds->busiest->sgp->power; } /* @@ -3090,8 +3090,8 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, max_pull = min(sds->max_load - sds->avg_load, load_above_capacity); /* How much load to actually move to equalise the imbalance */ - *imbalance = min(max_pull * sds->busiest->cpu_power, - (sds->avg_load - sds->this_load) * sds->this->cpu_power) + *imbalance = min(max_pull * sds->busiest->sgp->power, + (sds->avg_load - sds->this_load) * sds->this->sgp->power) / SCHED_POWER_SCALE; /* diff --git a/kernel/sched_features.h b/kernel/sched_features.h index be40f7371ee..1e7066d76c2 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h @@ -70,3 +70,5 @@ SCHED_FEAT(NONIRQ_POWER, 1) * using the scheduler IPI. Reduces rq->lock contention/bounces. */ SCHED_FEAT(TTWU_QUEUE, 1) + +SCHED_FEAT(FORCE_SD_OVERLAP, 0) diff --git a/kernel/signal.c b/kernel/signal.c index ff767860332..415d85d6f6c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1178,18 +1178,25 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, { struct sighand_struct *sighand; - rcu_read_lock(); for (;;) { + local_irq_save(*flags); + rcu_read_lock(); sighand = rcu_dereference(tsk->sighand); - if (unlikely(sighand == NULL)) + if (unlikely(sighand == NULL)) { + rcu_read_unlock(); + local_irq_restore(*flags); break; + } - spin_lock_irqsave(&sighand->siglock, *flags); - if (likely(sighand == tsk->sighand)) + spin_lock(&sighand->siglock); + if (likely(sighand == tsk->sighand)) { + rcu_read_unlock(); break; - spin_unlock_irqrestore(&sighand->siglock, *flags); + } + spin_unlock(&sighand->siglock); + rcu_read_unlock(); + local_irq_restore(*flags); } - rcu_read_unlock(); return sighand; } diff --git a/kernel/softirq.c b/kernel/softirq.c index 40cf63ddd4b..fca82c32042 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -315,16 +315,24 @@ static inline void invoke_softirq(void) { if (!force_irqthreads) __do_softirq(); - else + else { + __local_bh_disable((unsigned long)__builtin_return_address(0), + SOFTIRQ_OFFSET); wakeup_softirqd(); + __local_bh_enable(SOFTIRQ_OFFSET); + } } #else static inline void invoke_softirq(void) { if (!force_irqthreads) do_softirq(); - else + else { + __local_bh_disable((unsigned long)__builtin_return_address(0), + SOFTIRQ_OFFSET); wakeup_softirqd(); + __local_bh_enable(SOFTIRQ_OFFSET); + } } #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 5ed24b94c5e..d036e59d302 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2310,7 +2310,8 @@ static bool pgdat_balanced(pg_data_t *pgdat, unsigned long balanced_pages, for (i = 0; i <= classzone_idx; i++) present_pages += pgdat->node_zones[i].present_pages; - return balanced_pages > (present_pages >> 2); + /* A special case here: if zone has no page, we think it's balanced */ + return balanced_pages >= (present_pages >> 2); } /* is kswapd sleeping prematurely? */ diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 86bff9b1ac4..6e82148edfc 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -528,7 +528,11 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); - dev->hw_features = NETIF_F_ALL_TX_OFFLOADS; + dev->hw_features = NETIF_F_ALL_CSUM | NETIF_F_SG | + NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | + NETIF_F_HIGHDMA | NETIF_F_SCTP_CSUM | + NETIF_F_ALL_FCOE; + dev->features |= real_dev->vlan_features | NETIF_F_LLTX; dev->gso_max_size = real_dev->gso_max_size; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d3a05b9ade7..bcd158f40bb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -393,6 +393,9 @@ int hci_conn_del(struct hci_conn *conn) hci_dev_put(hdev); + if (conn->handle == 0) + kfree(conn); + return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index c405a954a60..43b4c2deb7c 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -464,7 +464,8 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -535,7 +536,8 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(current); } } @@ -706,9 +708,8 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - + set_current_state(TASK_INTERRUPTIBLE); + while (!atomic_read(&session->terminate)) { if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) break; @@ -726,6 +727,7 @@ static int hidp_session(void *arg) hidp_process_transmit(session); schedule(); + set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(intr_sk), &intr_wait); @@ -1060,7 +1062,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); unlink: hidp_del_timer(session); @@ -1111,7 +1114,8 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 19e95004b28..af1bcc823f2 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -142,6 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; + atomic_t terminate; struct task_struct *task; unsigned char keys[8]; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 56fdd9162da..7705e26e699 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -620,7 +620,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; @@ -2323,7 +2324,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk = chan->sk; - if (sk->sk_state != BT_CONFIG) { + if (sk->sk_state != BT_CONFIG && sk->sk_state != BT_CONNECT2) { struct l2cap_cmd_rej rej; rej.reason = cpu_to_le16(0x0002); @@ -2334,7 +2335,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (chan->conf_len + len > sizeof(chan->conf_req)) { + if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); @@ -4009,7 +4010,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; res = L2CAP_CR_SUCCESS; diff --git a/net/ceph/ceph_fs.c b/net/ceph/ceph_fs.c index a3a3a31d3c3..41466ccb972 100644 --- a/net/ceph/ceph_fs.c +++ b/net/ceph/ceph_fs.c @@ -36,16 +36,19 @@ int ceph_flags_to_mode(int flags) if ((flags & O_DIRECTORY) == O_DIRECTORY) return CEPH_FILE_MODE_PIN; #endif - if ((flags & O_APPEND) == O_APPEND) - flags |= O_WRONLY; - if ((flags & O_ACCMODE) == O_RDWR) - mode = CEPH_FILE_MODE_RDWR; - else if ((flags & O_ACCMODE) == O_WRONLY) + switch (flags & O_ACCMODE) { + case O_WRONLY: mode = CEPH_FILE_MODE_WR; - else + break; + case O_RDONLY: mode = CEPH_FILE_MODE_RD; - + break; + case O_RDWR: + case O_ACCMODE: /* this is what the VFS does */ + mode = CEPH_FILE_MODE_RDWR; + break; + } #ifdef O_LAZY if (flags & O_LAZY) mode |= CEPH_FILE_MODE_LAZY; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 58ffa7d069c..669d2e32efb 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -877,7 +877,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_NUM_BANDS; i++) { local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len, + local->scan_ies_len + + req->ie_len, GFP_KERNEL); if (!local->sched_scan_ies.ie[i]) { ret = -ENOMEM; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d91c1a26630..8f6a302d2ac 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -86,6 +86,11 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int queue = rx->queue; + + /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */ + if (rx->queue == NUM_RX_DATA_QUEUES - 1) + queue = 0; /* * it makes no sense to check for MIC errors on anything other @@ -148,8 +153,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) update_iv: /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; - rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; + rx->key->u.tkip.rx[queue].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; @@ -241,6 +246,11 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + int queue = rx->queue; + + /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */ + if (rx->queue == NUM_RX_DATA_QUEUES - 1) + queue = 0; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -261,7 +271,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->sta.addr, - hdr->addr1, hwaccel, rx->queue, + hdr->addr1, hwaccel, queue, &rx->tkip_iv32, &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK) diff --git a/net/sctp/output.c b/net/sctp/output.c index b4f3cf06d8d..08b3cead650 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -500,23 +500,20 @@ int sctp_packet_transmit(struct sctp_packet *packet) * Note: Adler-32 is no longer applicable, as has been replaced * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>. */ - if (!sctp_checksum_disable && - !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) { - __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); + if (!sctp_checksum_disable) { + if (!(dst->dev->features & NETIF_F_SCTP_CSUM)) { + __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); - /* 3) Put the resultant value into the checksum field in the - * common header, and leave the rest of the bits unchanged. - */ - sh->checksum = sctp_end_cksum(crc32); - } else { - if (dst->dev->features & NETIF_F_SCTP_CSUM) { + /* 3) Put the resultant value into the checksum field in the + * common header, and leave the rest of the bits unchanged. + */ + sh->checksum = sctp_end_cksum(crc32); + } else { /* no need to seed pseudo checksum for SCTP */ nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (skb_transport_header(nskb) - nskb->head); nskb->csum_offset = offsetof(struct sctphdr, checksum); - } else { - nskb->ip_summed = CHECKSUM_UNNECESSARY; } } diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1c88c8911dc..d03682109b7 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1582,6 +1582,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, #endif /* SCTP_DEBUG */ if (transport) { if (bytes_acked) { + struct sctp_association *asoc = transport->asoc; + /* We may have counted DATA that was migrated * to this transport due to DEL-IP operation. * Subtract those bytes, since the were never @@ -1600,6 +1602,17 @@ static void sctp_check_transmitted(struct sctp_outq *q, transport->error_count = 0; transport->asoc->overall_error_count = 0; + /* + * While in SHUTDOWN PENDING, we may have started + * the T5 shutdown guard timer after reaching the + * retransmission limit. Stop that timer as soon + * as the receiver acknowledged any data. + */ + if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING && + del_timer(&asoc->timers + [SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD])) + sctp_association_put(asoc); + /* Mark the destination transport address as * active if it is not so marked. */ @@ -1629,10 +1642,15 @@ static void sctp_check_transmitted(struct sctp_outq *q, * A sender is doing zero window probing when the * receiver's advertised window is zero, and there is * only one data chunk in flight to the receiver. + * + * Allow the association to timeout while in SHUTDOWN + * PENDING or SHUTDOWN RECEIVED in case the receiver + * stays in zero window mode forever. */ if (!q->asoc->peer.rwnd && !list_empty(&tlist) && - (sack_ctsn+2 == q->asoc->next_tsn)) { + (sack_ctsn+2 == q->asoc->next_tsn) && + q->asoc->state < SCTP_STATE_SHUTDOWN_PENDING) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", __func__, sack_ctsn); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 534c2e5feb0..6e0f88295aa 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -670,10 +670,19 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the * HEARTBEAT should clear the error counter of the destination * transport address to which the HEARTBEAT was sent. - * The association's overall error count is also cleared. */ t->error_count = 0; - t->asoc->overall_error_count = 0; + + /* + * Although RFC4960 specifies that the overall error count must + * be cleared when a HEARTBEAT ACK is received, we make an + * exception while in SHUTDOWN PENDING. If the peer keeps its + * window shut forever, we may never be able to transmit our + * outstanding data and rely on the retransmission limit be reached + * to shutdown the association. + */ + if (t->asoc->state != SCTP_STATE_SHUTDOWN_PENDING) + t->asoc->overall_error_count = 0; /* Clear the hb_sent flag to signal that we had a good * acknowledgement. @@ -1437,6 +1446,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr); break; + case SCTP_CMD_TIMER_START_ONCE: + timer = &asoc->timers[cmd->obj.to]; + + if (timer_pending(timer)) + break; + /* fall through */ + case SCTP_CMD_TIMER_START: timer = &asoc->timers[cmd->obj.to]; timeout = asoc->timeouts[cmd->obj.to]; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a297283154d..246117142b5 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5154,7 +5154,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown( * The sender of the SHUTDOWN MAY also start an overall guard timer * 'T5-shutdown-guard' to bound the overall time for shutdown sequence. */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); if (asoc->autoclose) @@ -5299,14 +5299,28 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS); if (asoc->overall_error_count >= asoc->max_retrans) { - sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, - SCTP_ERROR(ETIMEDOUT)); - /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_PERR(SCTP_ERROR_NO_ERROR)); - SCTP_INC_STATS(SCTP_MIB_ABORTEDS); - SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); - return SCTP_DISPOSITION_DELETE_TCB; + if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) { + /* + * We are here likely because the receiver had its rwnd + * closed for a while and we have not been able to + * transmit the locally queued data within the maximum + * retransmission attempts limit. Start the T5 + * shutdown guard timer to give the receiver one last + * chance and some additional time to recover before + * aborting. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START_ONCE, + SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_PERR(SCTP_ERROR_NO_ERROR)); + SCTP_INC_STATS(SCTP_MIB_ABORTEDS); + SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); + return SCTP_DISPOSITION_DELETE_TCB; + } } /* E1) For the destination address for which the timer diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 0338dc6fdc9..7c211a7f90f 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -827,7 +827,7 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ /* SCTP_STATE_ESTABLISHED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ + TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \ /* SCTP_STATE_SHUTDOWN_SENT */ \ TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 08c6238802d..d3ccf7973c5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1384,6 +1384,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) struct sctp_endpoint *ep; struct sctp_association *asoc; struct list_head *pos, *temp; + unsigned int data_was_unread; SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); @@ -1393,6 +1394,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ep = sctp_sk(sk)->ep; + /* Clean up any skbs sitting on the receive queue. */ + data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); + data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); + /* Walk all associations on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -1410,7 +1415,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) } } - if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { + if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || + !skb_queue_empty(&asoc->ulpq.reasm) || + (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { struct sctp_chunk *chunk; chunk = sctp_make_abort_user(asoc, NULL, 0); @@ -1420,10 +1427,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) sctp_primitive_SHUTDOWN(asoc, NULL); } - /* Clean up any skbs sitting on the receive queue. */ - sctp_queue_purge_ulpevents(&sk->sk_receive_queue); - sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); - /* On a TCP-style socket, block for at most linger_time if set. */ if (sctp_style(sk, TCP) && timeout) sctp_wait_for_close(sk, timeout); diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index e70e5fc8789..8a84017834c 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -1081,9 +1081,19 @@ void sctp_ulpevent_free(struct sctp_ulpevent *event) } /* Purge the skb lists holding ulpevents. */ -void sctp_queue_purge_ulpevents(struct sk_buff_head *list) +unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list) { struct sk_buff *skb; - while ((skb = skb_dequeue(list)) != NULL) - sctp_ulpevent_free(sctp_skb2event(skb)); + unsigned int data_unread = 0; + + while ((skb = skb_dequeue(list)) != NULL) { + struct sctp_ulpevent *event = sctp_skb2event(skb); + + if (!sctp_ulpevent_is_notification(event)) + data_unread += skb->len; + + sctp_ulpevent_free(event); + } + + return data_unread; } diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 9a80a922c52..e45d2fbbe5a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -597,7 +597,7 @@ void rpcb_getport_async(struct rpc_task *task) u32 bind_version; struct rpc_xprt *xprt; struct rpc_clnt *rpcb_clnt; - static struct rpcbind_args *map; + struct rpcbind_args *map; struct rpc_task *child; struct sockaddr_storage addr; struct sockaddr *sap = (struct sockaddr *)&addr; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index a27406b1654..4814e246a87 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -616,30 +616,25 @@ static void __rpc_execute(struct rpc_task *task) BUG_ON(RPC_IS_QUEUED(task)); for (;;) { + void (*do_action)(struct rpc_task *); /* - * Execute any pending callback. + * Execute any pending callback first. */ - if (task->tk_callback) { - void (*save_callback)(struct rpc_task *); - - /* - * We set tk_callback to NULL before calling it, - * in case it sets the tk_callback field itself: - */ - save_callback = task->tk_callback; - task->tk_callback = NULL; - save_callback(task); - } else { + do_action = task->tk_callback; + task->tk_callback = NULL; + if (do_action == NULL) { /* * Perform the next FSM step. - * tk_action may be NULL when the task has been killed - * by someone else. + * tk_action may be NULL if the task has been killed. + * In particular, note that rpc_killall_tasks may + * do this at any time, so beware when dereferencing. */ - if (task->tk_action == NULL) + do_action = task->tk_action; + if (do_action == NULL) break; - task->tk_action(task); } + do_action(task); /* * Lockless check for whether task is sleeping or not. diff --git a/net/wireless/core.c b/net/wireless/core.c index c22ef3492ee..880dbe2e6f9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -366,6 +366,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); + mutex_init(&rdev->sched_scan_mtx); INIT_LIST_HEAD(&rdev->netdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); @@ -701,6 +702,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) rfkill_destroy(rdev->rfkill); mutex_destroy(&rdev->mtx); mutex_destroy(&rdev->devlist_mtx); + mutex_destroy(&rdev->sched_scan_mtx); list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); cfg80211_rdev_free_wowlan(rdev); @@ -737,12 +739,16 @@ static void wdev_cleanup_work(struct work_struct *work) ___cfg80211_scan_done(rdev, true); } + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->sched_scan_mtx); + if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { __cfg80211_stop_sched_scan(rdev, false); } - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_lock(&rdev->devlist_mtx); rdev->opencount--; @@ -830,9 +836,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, false); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT diff --git a/net/wireless/core.h b/net/wireless/core.h index 3dce1f167eb..a570ff9214e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -65,6 +65,8 @@ struct cfg80211_registered_device { struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; + struct mutex sched_scan_mtx; + #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; #endif diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f07602d7bf6..cea338150d0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3461,9 +3461,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (rdev->sched_scan_req) - return -EINPROGRESS; - if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) return -EINVAL; @@ -3502,12 +3499,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (ie_len > wiphy->max_scan_ie_len) return -EINVAL; + mutex_lock(&rdev->sched_scan_mtx); + + if (rdev->sched_scan_req) { + err = -EINPROGRESS; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); - if (!request) - return -ENOMEM; + if (!request) { + err = -ENOMEM; + goto out; + } if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3605,6 +3611,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, out_free: kfree(request); out: + mutex_unlock(&rdev->sched_scan_mtx); return err; } @@ -3612,12 +3619,17 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || !rdev->ops->sched_scan_stop) return -EOPNOTSUPP; - return __cfg80211_stop_sched_scan(rdev, false); + mutex_lock(&rdev->sched_scan_mtx); + err = __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + return err; } static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7a6c67667d7..ae0c2256ba3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -100,14 +100,14 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); /* we don't have sched_scan_req anymore if the scan is stopping */ if (rdev->sched_scan_req) nl80211_send_sched_scan_results(rdev, rdev->sched_scan_req->dev); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } void cfg80211_sched_scan_results(struct wiphy *wiphy) @@ -123,9 +123,9 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, true); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } EXPORT_SYMBOL(cfg80211_sched_scan_stopped); @@ -135,7 +135,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, int err; struct net_device *dev; - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (!rdev->sched_scan_req) return 0; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d70f85eb786..9414b9c5b1e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1345,6 +1345,8 @@ out: xfrm_state_check_expire(x1); err = 0; + x->km.state = XFRM_STATE_DEAD; + __xfrm_state_put(x); } spin_unlock_bh(&x1->lock); diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 3b029cba2ba..a2723568594 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -21,13 +21,15 @@ fi # older versions of depmod require the version string to start with three # numbers, so we cheat with a symlink here depmod_hack_needed=true -mkdir -p .tmp_depmod/lib/modules/$KERNELRELEASE -if "$DEPMOD" -b .tmp_depmod $KERNELRELEASE 2>/dev/null; then - if test -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep -o \ - -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep.bin; then +tmp_dir=$(mktemp -d ${TMPDIR:-/tmp}/depmod.XXXXXX) +mkdir -p "$tmp_dir/lib/modules/$KERNELRELEASE" +if "$DEPMOD" -b "$tmp_dir" $KERNELRELEASE 2>/dev/null; then + if test -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep" -o \ + -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep.bin"; then depmod_hack_needed=false fi fi +rm -rf "$tmp_dir" if $depmod_hack_needed; then symlink="$INSTALL_MOD_PATH/lib/modules/99.98.$KERNELRELEASE" ln -s "$KERNELRELEASE" "$symlink" diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c2fc0356c2a..83014a7c2e1 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1190,7 +1190,6 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"), SND_SOC_DAPM_INPUT("DMIC2DAT"), SND_SOC_DAPM_INPUT("Clock"), -SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0), SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, SND_SOC_DAPM_PRE_PMU), @@ -1509,8 +1508,10 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { { "AIF2DACDAT", NULL, "AIF1DACDAT" }, { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, - { "MICBIAS", NULL, "CLK_SYS" }, - { "MICBIAS", NULL, "MICBIAS Supply" }, + { "MICBIAS1", NULL, "CLK_SYS" }, + { "MICBIAS1", NULL, "MICBIAS Supply" }, + { "MICBIAS2", NULL, "CLK_SYS" }, + { "MICBIAS2", NULL, "MICBIAS Supply" }, }; static const struct snd_soc_dapm_route wm8994_intercon[] = { @@ -2763,7 +2764,7 @@ static void wm8958_default_micdet(u16 status, void *data) report = SND_JACK_MICROPHONE; /* Everything else is buttons; just assign slots */ - if (status & 0x1c0) + if (status & 0x1c) report |= SND_JACK_BTN_0; done: diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index d6f4703b3c0..770a71a1536 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -97,7 +97,7 @@ static int fsi_ak4642_remove(struct platform_device *pdev) static struct fsi_ak4642_data fsi_a_ak4642 = { .name = "AK4642", - .card = "FSIA (AK4642)", + .card = "FSIA-AK4642", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", @@ -106,7 +106,7 @@ static struct fsi_ak4642_data fsi_a_ak4642 = { static struct fsi_ak4642_data fsi_b_ak4642 = { .name = "AK4642", - .card = "FSIB (AK4642)", + .card = "FSIB-AK4642", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi.0", @@ -115,7 +115,7 @@ static struct fsi_ak4642_data fsi_b_ak4642 = { static struct fsi_ak4642_data fsi_a_ak4643 = { .name = "AK4643", - .card = "FSIA (AK4643)", + .card = "FSIA-AK4643", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi.0", @@ -124,7 +124,7 @@ static struct fsi_ak4642_data fsi_a_ak4643 = { static struct fsi_ak4642_data fsi_b_ak4643 = { .name = "AK4643", - .card = "FSIB (AK4643)", + .card = "FSIB-AK4643", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi.0", @@ -133,7 +133,7 @@ static struct fsi_ak4642_data fsi_b_ak4643 = { static struct fsi_ak4642_data fsi2_a_ak4642 = { .name = "AK4642", - .card = "FSI2A (AK4642)", + .card = "FSI2A-AK4642", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", @@ -142,7 +142,7 @@ static struct fsi_ak4642_data fsi2_a_ak4642 = { static struct fsi_ak4642_data fsi2_b_ak4642 = { .name = "AK4642", - .card = "FSI2B (AK4642)", + .card = "FSI2B-AK4642", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0012", .platform = "sh_fsi2", @@ -151,7 +151,7 @@ static struct fsi_ak4642_data fsi2_b_ak4642 = { static struct fsi_ak4642_data fsi2_a_ak4643 = { .name = "AK4643", - .card = "FSI2A (AK4643)", + .card = "FSI2A-AK4643", .cpu_dai = "fsia-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", @@ -160,7 +160,7 @@ static struct fsi_ak4642_data fsi2_a_ak4643 = { static struct fsi_ak4642_data fsi2_b_ak4643 = { .name = "AK4643", - .card = "FSI2B (AK4643)", + .card = "FSI2B-AK4643", .cpu_dai = "fsib-dai", .codec = "ak4642-codec.0-0013", .platform = "sh_fsi2", diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index dbafd7ac559..59553fd8c2f 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c @@ -42,7 +42,7 @@ static struct snd_soc_dai_link fsi_da7210_dai = { }; static struct snd_soc_card fsi_soc_card = { - .name = "FSI (DA7210)", + .name = "FSI-DA7210", .dai_link = &fsi_da7210_dai, .num_links = 1, }; diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c index 9719985eb82..d3d9fd88068 100644 --- a/sound/soc/sh/fsi-hdmi.c +++ b/sound/soc/sh/fsi-hdmi.c @@ -83,13 +83,13 @@ static int fsi_hdmi_remove(struct platform_device *pdev) static struct fsi_hdmi_data fsi2_a_hdmi = { .cpu_dai = "fsia-dai", - .card = "FSI2A (SH MOBILE HDMI)", + .card = "FSI2A-HDMI", .id = FSI_PORT_A, }; static struct fsi_hdmi_data fsi2_b_hdmi = { .cpu_dai = "fsib-dai", - .card = "FSI2B (SH MOBILE HDMI)", + .card = "FSI2B-HDMI", .id = FSI_PORT_B, }; |