diff options
449 files changed, 10047 insertions, 2542 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index b175808..07c75d1 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -196,13 +196,6 @@ chmod 0644 /dev/cpu/microcode as root before you can use this. You'll probably also want to get the user-space microcode_ctl utility to use with this. -Powertweak ----------- - -If you are running v0.1.17 or earlier, you should upgrade to -version v0.99.0 or higher. Running old versions may cause problems -with programs using shared memory. - udev ---- udev is a userspace application for populating /dev dynamically with @@ -366,10 +359,6 @@ Intel P6 microcode ------------------ o <http://www.urbanmyth.org/microcode/> -Powertweak ----------- -o <http://powertweak.sourceforge.net/> - udev ---- o <http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html> diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 6c9d9d3..f517008 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -58,7 +58,7 @@ </sect1> <sect1><title>Wait queues and Wake events</title> !Iinclude/linux/wait.h -!Ekernel/wait.c +!Ekernel/sched/wait.c </sect1> <sect1><title>High-resolution timers</title> !Iinclude/linux/ktime.h diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt new file mode 100644 index 0000000..cd5e239 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -0,0 +1,339 @@ +Device Tree Clock bindings for arch-at91 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "atmel,at91rm9200-pmc" or + "atmel,at91sam9g45-pmc" or + "atmel,at91sam9n12-pmc" or + "atmel,at91sam9x5-pmc" or + "atmel,sama5d3-pmc": + at91 PMC (Power Management Controller) + All at91 specific clocks (clocks defined below) must be child + node of the PMC node. + + "atmel,at91rm9200-clk-main": + at91 main oscillator + + "atmel,at91rm9200-clk-master" or + "atmel,at91sam9x5-clk-master": + at91 master clock + + "atmel,at91sam9x5-clk-peripheral" or + "atmel,at91rm9200-clk-peripheral": + at91 peripheral clocks + + "atmel,at91rm9200-clk-pll" or + "atmel,at91sam9g45-clk-pll" or + "atmel,at91sam9g20-clk-pllb" or + "atmel,sama5d3-clk-pll": + at91 pll clocks + + "atmel,at91sam9x5-clk-plldiv": + at91 plla divisor + + "atmel,at91rm9200-clk-programmable" or + "atmel,at91sam9g45-clk-programmable" or + "atmel,at91sam9x5-clk-programmable": + at91 programmable clocks + + "atmel,at91sam9x5-clk-smd": + at91 SMD (Soft Modem) clock + + "atmel,at91rm9200-clk-system": + at91 system clocks + + "atmel,at91rm9200-clk-usb" or + "atmel,at91sam9x5-clk-usb" or + "atmel,at91sam9n12-clk-usb": + at91 usb clock + + "atmel,at91sam9x5-clk-utmi": + at91 utmi clock + +Required properties for PMC node: +- reg : defines the IO memory reserved for the PMC. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- interrupts : shall be set to PMC interrupt line. +- interrupt-controller : tell that the PMC is an interrupt controller. +- #interrupt-cells : must be set to 1. The first cell encodes the interrupt id, + and reflect the bit position in the PMC_ER/DR/SR registers. + You can use the dt macros defined in dt-bindings/clk/at91.h. + 0 (AT91_PMC_MOSCS) -> main oscillator ready + 1 (AT91_PMC_LOCKA) -> PLL A ready + 2 (AT91_PMC_LOCKB) -> PLL B ready + 3 (AT91_PMC_MCKRDY) -> master clock ready + 6 (AT91_PMC_LOCKU) -> UTMI PLL clock ready + 8 .. 15 (AT91_PMC_PCKRDY(id)) -> programmable clock ready + 16 (AT91_PMC_MOSCSELS) -> main oscillator selected + 17 (AT91_PMC_MOSCRCS) -> RC main oscillator stabilized + 18 (AT91_PMC_CFDEV) -> clock failure detected + +For example: + pmc: pmc@fffffc00 { + compatible = "atmel,sama5d3-pmc"; + interrupts = <1 4 7>; + interrupt-controller; + #interrupt-cells = <2>; + #size-cells = <0>; + #address-cells = <1>; + + /* put at91 clocks here */ + }; + +Required properties for main clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<0>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks (optional if clock-frequency is provided) : shall be the slow clock + phandle. This clock is used to calculate the main clock rate if + "clock-frequency" is not provided. +- clock-frequency : the main oscillator frequency.Prefer the use of + "clock-frequency" over automatic clock rate calculation. + +For example: + main: mainck { + compatible = "atmel,at91rm9200-clk-main"; + interrupt-parent = <&pmc>; + interrupts = <0>; + #clock-cells = <0>; + clocks = <&ck32k>; + clock-frequency = <18432000>; + }; + +Required properties for master clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<3>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the master clock sources (see atmel datasheet) phandles. + e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>". +- atmel,clk-output-range : minimum and maximum clock frequency (two u32 + fields). + e.g. output = <0 133000000>; <=> 0 to 133MHz. +- atmel,clk-divisors : master clock divisors table (four u32 fields). + 0 <=> reserved value. + e.g. divisors = <1 2 4 6>; +- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the + PRES field as CLOCK_DIV3 (e.g sam9x5). + +For example: + mck: mck { + compatible = "atmel,at91rm9200-clk-master"; + interrupt-parent = <&pmc>; + interrupts = <3>; + #clock-cells = <0>; + atmel,clk-output-range = <0 133000000>; + atmel,clk-divisors = <1 2 4 0>; + }; + +Required properties for peripheral clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the master clock phandle. + e.g. clocks = <&mck>; +- name: device tree node describing a specific system clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: peripheral id. See Atmel's datasheets to get a full + list of peripheral ids. + * atmel,clk-output-range : minimum and maximum clock frequency + (two u32 fields). Only valid on at91sam9x5-clk-peripheral + compatible IPs. + +For example: + periph: periphck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #size-cells = <0>; + #address-cells = <1>; + clocks = <&mck>; + + ssc0_clk { + #clock-cells = <0>; + reg = <2>; + atmel,clk-output-range = <0 133000000>; + }; + + usart0_clk { + #clock-cells = <0>; + reg = <3>; + atmel,clk-output-range = <0 66000000>; + }; + }; + + +Required properties for pll clocks: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<1>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock phandle. +- reg : pll id. + 0 -> PLL A + 1 -> PLL B +- atmel,clk-input-range : minimum and maximum source clock frequency (two u32 + fields). + e.g. input = <1 32000000>; <=> 1 to 32MHz. +- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output + range description. Sould be set to 2, 3 + or 4. + * 1st and 2nd cells represent the frequency range (min-max). + * 3rd cell is optional and represents the OUT field value for the given + range. + * 4th cell is optional and represents the ICPLL field (PLLICPR + register) +- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter + depending on #atmel,pll-output-range-cells + property value. + +For example: + plla: pllack { + compatible = "atmel,at91sam9g45-clk-pll"; + interrupt-parent = <&pmc>; + interrupts = <1>; + #clock-cells = <0>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <2000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <74500000 800000000 0 0 + 69500000 750000000 1 0 + 64500000 700000000 2 0 + 59500000 650000000 3 0 + 54500000 600000000 0 1 + 49500000 550000000 1 1 + 44500000 500000000 2 1 + 40000000 450000000 3 1>; + }; + +Required properties for plldiv clocks (plldiv = pll / 2): +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the plla clock phandle. + +The pll divisor is equal to 2 and cannot be changed. + +For example: + plladiv: plladivck { + compatible = "atmel,at91sam9x5-clk-plldiv"; + #clock-cells = <0>; + clocks = <&plla>; + }; + +Required properties for programmable clocks: +- interrupt-parent : must reference the PMC node. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the programmable clock source phandles. + e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>; +- name: device tree node describing a specific prog clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg : programmable clock id (register offset from PCKx + register). + * interrupts : shall be set to "<(8 + id)>". + +For example: + prog: progck { + compatible = "atmel,at91sam9g45-clk-programmable"; + #size-cells = <0>; + #address-cells = <1>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = <8>; + }; + + prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = <9>; + }; + }; + + +Required properties for smd clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&plladiv>, <&utmi>; + +For example: + smd: smdck { + compatible = "atmel,at91sam9x5-clk-smd"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + +Required properties for system clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- name: device tree node describing a specific system clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: system clock id (bit position in SCER/SCDR/SCSR registers). + See Atmel's datasheet to get a full list of system clock ids. + +For example: + system: systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + ddrck { + #clock-cells = <0>; + reg = <2>; + clocks = <&mck>; + }; + + uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + }; + + +Required properties for usb clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&pllb>; +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"): + usb clock divisor table. + e.g. divisors = <1 2 4 0>; + +For example: + usb: usbck { + compatible = "atmel,at91sam9x5-clk-usb"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + usb: usbck { + compatible = "atmel,at91rm9200-clk-usb"; + #clock-cells = <0>; + clocks = <&pllb>; + atmel,clk-divisors = <1 2 4 0>; + }; + + +Required properties for utmi clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock source phandle. + +For example: + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + interrupt-parent = <&pmc>; + interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>; + #clock-cells = <0>; + clocks = <&main>; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-omap.txt b/Documentation/devicetree/bindings/i2c/i2c-omap.txt index 56564aa..7e49839 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-omap.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-omap.txt @@ -1,7 +1,8 @@ I2C for OMAP platforms Required properties : -- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c" +- compatible : Must be "ti,omap2420-i2c", "ti,omap2430-i2c", "ti,omap3-i2c" + or "ti,omap4-i2c" - ti,hwmods : Must be "i2c<n>", n being the instance number (1-based) - #address-cells = <1>; - #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/mmc/ti-omap.txt b/Documentation/devicetree/bindings/mmc/ti-omap.txt new file mode 100644 index 0000000..8de5799 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/ti-omap.txt @@ -0,0 +1,54 @@ +* TI MMC host controller for OMAP1 and 2420 + +The MMC Host Controller on TI OMAP1 and 2420 family provides +an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the omap mmc driver. + +Note that this driver will not work with omap2430 or later omaps, +please see the omap hsmmc driver for the current omaps. + +Required properties: +- compatible: Must be "ti,omap2420-mmc", for OMAP2420 controllers +- ti,hwmods: For 2420, must be "msdi<n>", where n is controller + instance starting 1 + +Examples: + + msdi1: mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; + +* TI MMC host controller for OMAP1 and 2420 + +The MMC Host Controller on TI OMAP1 and 2420 family provides +an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the omap mmc driver. + +Note that this driver will not work with omap2430 or later omaps, +please see the omap hsmmc driver for the current omaps. + +Required properties: +- compatible: Must be "ti,omap2420-mmc", for OMAP2420 controllers +- ti,hwmods: For 2420, must be "msdi<n>", where n is controller + instance starting 1 + +Examples: + + msdi1: mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; + diff --git a/Documentation/devicetree/bindings/rng/qcom,prng.txt b/Documentation/devicetree/bindings/rng/qcom,prng.txt new file mode 100644 index 0000000..8e5853c --- /dev/null +++ b/Documentation/devicetree/bindings/rng/qcom,prng.txt @@ -0,0 +1,17 @@ +Qualcomm MSM pseudo random number generator. + +Required properties: + +- compatible : should be "qcom,prng" +- reg : specifies base physical address and size of the registers map +- clocks : phandle to clock-controller plus clock-specifier pair +- clock-names : "core" clocks all registers, FIFO and circuits in PRNG IP block + +Example: + + rng@f9bff000 { + compatible = "qcom,prng"; + reg = <0xf9bff000 0x200>; + clocks = <&clock GCC_PRNG_AHB_CLK>; + clock-names = "core"; + }; diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt new file mode 100644 index 0000000..0d03506 --- /dev/null +++ b/Documentation/gpio/board.txt @@ -0,0 +1,115 @@ +GPIO Mappings +============= + +This document explains how GPIOs can be assigned to given devices and functions. +Note that it only applies to the new descriptor-based interface. For a +description of the deprecated integer-based GPIO interface please refer to +gpio-legacy.txt (actually, there is no real mapping possible with the old +interface; you just fetch an integer from somewhere and request the +corresponding GPIO. + +Platforms that make use of GPIOs must select ARCH_REQUIRE_GPIOLIB (if GPIO usage +is mandatory) or ARCH_WANT_OPTIONAL_GPIOLIB (if GPIO support can be omitted) in +their Kconfig. Then, how GPIOs are mapped depends on what the platform uses to +describe its hardware layout. Currently, mappings can be defined through device +tree, ACPI, and platform data. + +Device Tree +----------- +GPIOs can easily be mapped to devices and functions in the device tree. The +exact way to do it depends on the GPIO controller providing the GPIOs, see the +device tree bindings for your controller. + +GPIOs mappings are defined in the consumer device's node, in a property named +<function>-gpios, where <function> is the function the driver will request +through gpiod_get(). For example: + + foo_device { + compatible = "acme,foo"; + ... + led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */ + <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */ + <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */ + + power-gpio = <&gpio 1 GPIO_ACTIVE_LOW>; + }; + +This property will make GPIOs 15, 16 and 17 available to the driver under the +"led" function, and GPIO 1 as the "power" GPIO: + + struct gpio_desc *red, *green, *blue, *power; + + red = gpiod_get_index(dev, "led", 0); + green = gpiod_get_index(dev, "led", 1); + blue = gpiod_get_index(dev, "led", 2); + + power = gpiod_get(dev, "power"); + +The led GPIOs will be active-high, while the power GPIO will be active-low (i.e. +gpiod_is_active_low(power) will be true). + +ACPI +---- +ACPI does not support function names for GPIOs. Therefore, only the "idx" +argument of gpiod_get_index() is useful to discriminate between GPIOs assigned +to a device. The "con_id" argument can still be set for debugging purposes (it +will appear under error messages as well as debug and sysfs nodes). + +Platform Data +------------- +Finally, GPIOs can be bound to devices and functions using platform data. Board +files that desire to do so need to include the following header: + + #include <linux/gpio/driver.h> + +GPIOs are mapped by the means of tables of lookups, containing instances of the +gpiod_lookup structure. Two macros are defined to help declaring such mappings: + + GPIO_LOOKUP(chip_label, chip_hwnum, dev_id, con_id, flags) + GPIO_LOOKUP_IDX(chip_label, chip_hwnum, dev_id, con_id, idx, flags) + +where + + - chip_label is the label of the gpiod_chip instance providing the GPIO + - chip_hwnum is the hardware number of the GPIO within the chip + - dev_id is the identifier of the device that will make use of this GPIO. If + NULL, the GPIO will be available to all devices. + - con_id is the name of the GPIO function from the device point of view. It + can be NULL. + - idx is the index of the GPIO within the function. + - flags is defined to specify the following properties: + * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low + * GPIOF_OPEN_DRAIN - GPIO pin is open drain type. + * GPIOF_OPEN_SOURCE - GPIO pin is open source type. + +In the future, these flags might be extended to support more properties. + +Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. + +A lookup table can then be defined as follows: + + struct gpiod_lookup gpios_table[] = { + GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW), + }; + +And the table can be added by the board code as follows: + + gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table)); + +The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: + + struct gpio_desc *red, *green, *blue, *power; + + red = gpiod_get_index(dev, "led", 0); + green = gpiod_get_index(dev, "led", 1); + blue = gpiod_get_index(dev, "led", 2); + + power = gpiod_get(dev, "power"); + gpiod_direction_output(power, 1); + +Since the "power" GPIO is mapped as active-low, its actual signal will be 0 +after this code. Contrary to the legacy integer GPIO interface, the active-low +property is handled during mapping and is thus transparent to GPIO consumers. diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt new file mode 100644 index 0000000..07c74a3 --- /dev/null +++ b/Documentation/gpio/consumer.txt @@ -0,0 +1,197 @@ +GPIO Descriptor Consumer Interface +================================== + +This document describes the consumer interface of the GPIO framework. Note that +it describes the new descriptor-based interface. For a description of the +deprecated integer-based GPIO interface please refer to gpio-legacy.txt. + + +Guidelines for GPIOs consumers +============================== + +Drivers that can't work without standard GPIO calls should have Kconfig entries +that depend on GPIOLIB. The functions that allow a driver to obtain and use +GPIOs are available by including the following file: + + #include <linux/gpio/consumer.h> + +All the functions that work with the descriptor-based GPIO interface are +prefixed with gpiod_. The gpio_ prefix is used for the legacy interface. No +other function in the kernel should use these prefixes. + + +Obtaining and Disposing GPIOs +============================= + +With the descriptor-based interface, GPIOs are identified with an opaque, +non-forgeable handler that must be obtained through a call to one of the +gpiod_get() functions. Like many other kernel subsystems, gpiod_get() takes the +device that will use the GPIO and the function the requested GPIO is supposed to +fulfill: + + struct gpio_desc *gpiod_get(struct device *dev, const char *con_id) + +If a function is implemented by using several GPIOs together (e.g. a simple LED +device that displays digits), an additional index argument can be specified: + + struct gpio_desc *gpiod_get_index(struct device *dev, + const char *con_id, unsigned int idx) + +Both functions return either a valid GPIO descriptor, or an error code checkable +with IS_ERR(). They will never return a NULL pointer. + +Device-managed variants of these functions are also defined: + + struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id) + + struct gpio_desc *devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) + +A GPIO descriptor can be disposed of using the gpiod_put() function: + + void gpiod_put(struct gpio_desc *desc) + +It is strictly forbidden to use a descriptor after calling this function. The +device-managed variant is, unsurprisingly: + + void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) + + +Using GPIOs +=========== + +Setting Direction +----------------- +The first thing a driver must do with a GPIO is setting its direction. This is +done by invoking one of the gpiod_direction_*() functions: + + int gpiod_direction_input(struct gpio_desc *desc) + int gpiod_direction_output(struct gpio_desc *desc, int value) + +The return value is zero for success, else a negative errno. It should be +checked, since the get/set calls don't return errors and since misconfiguration +is possible. You should normally issue these calls from a task context. However, +for spinlock-safe GPIOs it is OK to use them before tasking is enabled, as part +of early board setup. + +For output GPIOs, the value provided becomes the initial output value. This +helps avoid signal glitching during system startup. + +A driver can also query the current direction of a GPIO: + + int gpiod_get_direction(const struct gpio_desc *desc) + +This function will return either GPIOF_DIR_IN or GPIOF_DIR_OUT. + +Be aware that there is no default direction for GPIOs. Therefore, **using a GPIO +without setting its direction first is illegal and will result in undefined +behavior!** + + +Spinlock-Safe GPIO Access +------------------------- +Most GPIO controllers can be accessed with memory read/write instructions. Those +don't need to sleep, and can safely be done from inside hard (non-threaded) IRQ +handlers and similar contexts. + +Use the following calls to access GPIOs from an atomic context: + + int gpiod_get_value(const struct gpio_desc *desc); + void gpiod_set_value(struct gpio_desc *desc, int value); + +The values are boolean, zero for low, nonzero for high. When reading the value +of an output pin, the value returned should be what's seen on the pin. That +won't always match the specified output value, because of issues including +open-drain signaling and output latencies. + +The get/set calls do not return errors because "invalid GPIO" should have been +reported earlier from gpiod_direction_*(). However, note that not all platforms +can read the value of output pins; those that can't should always return zero. +Also, using these calls for GPIOs that can't safely be accessed without sleeping +(see below) is an error. + + +GPIO Access That May Sleep +-------------------------- +Some GPIO controllers must be accessed using message based buses like I2C or +SPI. Commands to read or write those GPIO values require waiting to get to the +head of a queue to transmit a command and get its response. This requires +sleeping, which can't be done from inside IRQ handlers. + +Platforms that support this type of GPIO distinguish them from other GPIOs by +returning nonzero from this call: + + int gpiod_cansleep(const struct gpio_desc *desc) + +To access such GPIOs, a different set of accessors is defined: + + int gpiod_get_value_cansleep(const struct gpio_desc *desc) + void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) + +Accessing such GPIOs requires a context which may sleep, for example a threaded +IRQ handler, and those accessors must be used instead of spinlock-safe +accessors without the cansleep() name suffix. + +Other than the fact that these accessors might sleep, and will work on GPIOs +that can't be accessed from hardIRQ handlers, these calls act the same as the +spinlock-safe calls. + + +Active-low State and Raw GPIO Values +------------------------------------ +Device drivers like to manage the logical state of a GPIO, i.e. the value their +device will actually receive, no matter what lies between it and the GPIO line. +In some cases, it might make sense to control the actual GPIO line value. The +following set of calls ignore the active-low property of a GPIO and work on the +raw line value: + + int gpiod_get_raw_value(const struct gpio_desc *desc) + void gpiod_set_raw_value(struct gpio_desc *desc, int value) + int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) + void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) + +The active-low state of a GPIO can also be queried using the following call: + + int gpiod_is_active_low(const struct gpio_desc *desc) + +Note that these functions should only be used with great moderation ; a driver +should not have to care about the physical line level. + +GPIOs mapped to IRQs +-------------------- +GPIO lines can quite often be used as IRQs. You can get the IRQ number +corresponding to a given GPIO using the following call: + + int gpiod_to_irq(const struct gpio_desc *desc) + +It will return an IRQ number, or an negative errno code if the mapping can't be +done (most likely because that particular GPIO cannot be used as IRQ). It is an +unchecked error to use a GPIO that wasn't set up as an input using +gpiod_direction_input(), or to use an IRQ number that didn't originally come +from gpiod_to_irq(). gpiod_to_irq() is not allowed to sleep. + +Non-error values returned from gpiod_to_irq() can be passed to request_irq() or +free_irq(). They will often be stored into IRQ resources for platform devices, +by the board-specific initialization code. Note that IRQ trigger options are +part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup +capabilities. + + +Interacting With the Legacy GPIO Subsystem +========================================== +Many kernel subsystems still handle GPIOs using the legacy integer-based +interface. Although it is strongly encouraged to upgrade them to the safer +descriptor-based API, the following two functions allow you to convert a GPIO +descriptor into the GPIO integer namespace and vice-versa: + + int desc_to_gpio(const struct gpio_desc *desc) + struct gpio_desc *gpio_to_desc(unsigned gpio) + +The GPIO number returned by desc_to_gpio() can be safely used as long as the +GPIO descriptor has not been freed. All the same, a GPIO number passed to +gpio_to_desc() must have been properly acquired, and usage of the returned GPIO +descriptor is only possible after the GPIO number has been released. + +Freeing a GPIO obtained by one API with the other API is forbidden and an +unchecked error. diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt new file mode 100644 index 0000000..9da0bfa --- /dev/null +++ b/Documentation/gpio/driver.txt @@ -0,0 +1,75 @@ +GPIO Descriptor Driver Interface +================================ + +This document serves as a guide for GPIO chip drivers writers. Note that it +describes the new descriptor-based interface. For a description of the +deprecated integer-based GPIO interface please refer to gpio-legacy.txt. + +Each GPIO controller driver needs to include the following header, which defines +the structures used to define a GPIO driver: + + #include <linux/gpio/driver.h> + + +Internal Representation of GPIOs +================================ + +Inside a GPIO driver, individual GPIOs are identified by their hardware number, +which is a unique number between 0 and n, n being the number of GPIOs managed by +the chip. This number is purely internal: the hardware number of a particular +GPIO descriptor is never made visible outside of the driver. + +On top of this internal number, each GPIO also need to have a global number in +the integer GPIO namespace so that it can be used with the legacy GPIO +interface. Each chip must thus have a "base" number (which can be automatically +assigned), and for each GPIO the global number will be (base + hardware number). +Although the integer representation is considered deprecated, it still has many +users and thus needs to be maintained. + +So for example one platform could use numbers 32-159 for GPIOs, with a +controller defining 128 GPIOs at a "base" of 32 ; while another platform uses +numbers 0..63 with one set of GPIO controllers, 64-79 with another type of GPIO +controller, and on one particular board 80-95 with an FPGA. The numbers need not +be contiguous; either of those platforms could also use numbers 2000-2063 to +identify GPIOs in a bank of I2C GPIO expanders. + + +Controller Drivers: gpio_chip +============================= + +In the gpiolib framework each GPIO controller is packaged as a "struct +gpio_chip" (see linux/gpio/driver.h for its complete definition) with members +common to each controller of that type: + + - methods to establish GPIO direction + - methods used to access GPIO values + - method to return the IRQ number associated to a given GPIO + - flag saying whether calls to its methods may sleep + - optional debugfs dump method (showing extra state like pullup config) + - optional base number (will be automatically assigned if omitted) + - label for diagnostics and GPIOs mapping using platform data + +The code implementing a gpio_chip should support multiple instances of the +controller, possibly using the driver model. That code will configure each +gpio_chip and issue gpiochip_add(). Removing a GPIO controller should be rare; +use gpiochip_remove() when it is unavoidable. + +Most often a gpio_chip is part of an instance-specific structure with state not +exposed by the GPIO interfaces, such as addressing, power management, and more. +Chips such as codecs will have complex non-GPIO state. + +Any debugfs dump method should normally ignore signals which haven't been +requested as GPIOs. They can use gpiochip_is_requested(), which returns either +NULL or the label associated with that GPIO when it was requested. + +Locking IRQ usage +----------------- +Input GPIOs can be used as IRQ signals. When this happens, a driver is requested +to mark the GPIO as being used as an IRQ: + + int gpiod_lock_as_irq(struct gpio_desc *desc) + +This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock +is released: + + void gpiod_unlock_as_irq(struct gpio_desc *desc) diff --git a/Documentation/gpio.txt b/Documentation/gpio/gpio-legacy.txt index 6f83fa9..6f83fa9 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio/gpio-legacy.txt diff --git a/Documentation/gpio/gpio.txt b/Documentation/gpio/gpio.txt new file mode 100644 index 0000000..cd9b356 --- /dev/null +++ b/Documentation/gpio/gpio.txt @@ -0,0 +1,119 @@ +GPIO Interfaces +=============== + +The documents in this directory give detailed instructions on how to access +GPIOs in drivers, and how to write a driver for a device that provides GPIOs +itself. + +Due to the history of GPIO interfaces in the kernel, there are two different +ways to obtain and use GPIOs: + + - The descriptor-based interface is the preferred way to manipulate GPIOs, +and is described by all the files in this directory excepted gpio-legacy.txt. + - The legacy integer-based interface which is considered deprecated (but still +usable for compatibility reasons) is documented in gpio-legacy.txt. + +The remainder of this document applies to the new descriptor-based interface. +gpio-legacy.txt contains the same information applied to the legacy +integer-based interface. + + +What is a GPIO? +=============== + +A "General Purpose Input/Output" (GPIO) is a flexible software-controlled +digital signal. They are provided from many kinds of chip, and are familiar +to Linux developers working with embedded and custom hardware. Each GPIO +represents a bit connected to a particular pin, or "ball" on Ball Grid Array +(BGA) packages. Board schematics show which external hardware connects to +which GPIOs. Drivers can be written generically, so that board setup code +passes such pin configuration data to drivers. + +System-on-Chip (SOC) processors heavily rely on GPIOs. In some cases, every +non-dedicated pin can be configured as a GPIO; and most chips have at least +several dozen of them. Programmable logic devices (like FPGAs) can easily +provide GPIOs; multifunction chips like power managers, and audio codecs +often have a few such pins to help with pin scarcity on SOCs; and there are +also "GPIO Expander" chips that connect using the I2C or SPI serial buses. +Most PC southbridges have a few dozen GPIO-capable pins (with only the BIOS +firmware knowing how they're used). + +The exact capabilities of GPIOs vary between systems. Common options: + + - Output values are writable (high=1, low=0). Some chips also have + options about how that value is driven, so that for example only one + value might be driven, supporting "wire-OR" and similar schemes for the + other value (notably, "open drain" signaling). + + - Input values are likewise readable (1, 0). Some chips support readback + of pins configured as "output", which is very useful in such "wire-OR" + cases (to support bidirectional signaling). GPIO controllers may have + input de-glitch/debounce logic, sometimes with software controls. + + - Inputs can often be used as IRQ signals, often edge triggered but + sometimes level triggered. Such IRQs may be configurable as system + wakeup events, to wake the system from a low power state. + + - Usually a GPIO will be configurable as either input or output, as needed + by different product boards; single direction ones exist too. + + - Most GPIOs can be accessed while holding spinlocks, but those accessed + through a serial bus normally can't. Some systems support both types. + +On a given board each GPIO is used for one specific purpose like monitoring +MMC/SD card insertion/removal, detecting card write-protect status, driving +a LED, configuring a transceiver, bit-banging a serial bus, poking a hardware +watchdog, sensing a switch, and so on. + + +Common GPIO Properties +====================== + +These properties are met through all the other documents of the GPIO interface +and it is useful to understand them, especially if you need to define GPIO +mappings. + +Active-High and Active-Low +-------------------------- +It is natural to assume that a GPIO is "active" when its output signal is 1 +("high"), and inactive when it is 0 ("low"). However in practice the signal of a +GPIO may be inverted before is reaches its destination, or a device could decide +to have different conventions about what "active" means. Such decisions should +be transparent to device drivers, therefore it is possible to define a GPIO as +being either active-high ("1" means "active", the default) or active-low ("0" +means "active") so that drivers only need to worry about the logical signal and +not about what happens at the line level. + +Open Drain and Open Source +-------------------------- +Sometimes shared signals need to use "open drain" (where only the low signal +level is actually driven), or "open source" (where only the high signal level is +driven) signaling. That term applies to CMOS transistors; "open collector" is +used for TTL. A pullup or pulldown resistor causes the high or low signal level. +This is sometimes called a "wire-AND"; or more practically, from the negative +logic (low=true) perspective this is a "wire-OR". + +One common example of an open drain signal is a shared active-low IRQ line. +Also, bidirectional data bus signals sometimes use open drain signals. + +Some GPIO controllers directly support open drain and open source outputs; many +don't. When you need open drain signaling but your hardware doesn't directly +support it, there's a common idiom you can use to emulate it with any GPIO pin +that can be used as either an input or an output: + + LOW: gpiod_direction_output(gpio, 0) ... this drives the signal and overrides + the pullup. + + HIGH: gpiod_direction_input(gpio) ... this turns off the output, so the pullup + (or some other device) controls the signal. + +The same logic can be applied to emulate open source signaling, by driving the +high signal and configuring the GPIO as input for low. This open drain/open +source emulation can be handled transparently by the GPIO framework. + +If you are "driving" the signal high but gpiod_get_value(gpio) reports a low +value (after the appropriate rise time passes), you know some other component is +driving the shared signal low. That's not necessarily an error. As one common +example, that's how I2C clocks are stretched: a slave that needs a slower clock +delays the rising edge of SCK, and the I2C master adjusts its signaling rate +accordingly. diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt new file mode 100644 index 0000000..c2c3a97 --- /dev/null +++ b/Documentation/gpio/sysfs.txt @@ -0,0 +1,155 @@ +GPIO Sysfs Interface for Userspace +================================== + +Platforms which use the "gpiolib" implementors framework may choose to +configure a sysfs user interface to GPIOs. This is different from the +debugfs interface, since it provides control over GPIO direction and +value instead of just showing a gpio state summary. Plus, it could be +present on production systems without debugging support. + +Given appropriate hardware documentation for the system, userspace could +know for example that GPIO #23 controls the write protect line used to +protect boot loader segments in flash memory. System upgrade procedures +may need to temporarily remove that protection, first importing a GPIO, +then changing its output state, then updating the code before re-enabling +the write protection. In normal use, GPIO #23 would never be touched, +and the kernel would have no need to know about it. + +Again depending on appropriate hardware documentation, on some systems +userspace GPIO can be used to determine system configuration data that +standard kernels won't know about. And for some tasks, simple userspace +GPIO drivers could be all that the system really needs. + +Note that standard kernel drivers exist for common "LEDs and Buttons" +GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those +instead of talking directly to the GPIOs; they integrate with kernel +frameworks better than your userspace code could. + + +Paths in Sysfs +-------------- +There are three kinds of entry in /sys/class/gpio: + + - Control interfaces used to get userspace control over GPIOs; + + - GPIOs themselves; and + + - GPIO controllers ("gpio_chip" instances). + +That's in addition to standard files including the "device" symlink. + +The control interfaces are write-only: + + /sys/class/gpio/ + + "export" ... Userspace may ask the kernel to export control of + a GPIO to userspace by writing its number to this file. + + Example: "echo 19 > export" will create a "gpio19" node + for GPIO #19, if that's not requested by kernel code. + + "unexport" ... Reverses the effect of exporting to userspace. + + Example: "echo 19 > unexport" will remove a "gpio19" + node exported using the "export" file. + +GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42) +and have the following read/write attributes: + + /sys/class/gpio/gpioN/ + + "direction" ... reads as either "in" or "out". This value may + normally be written. Writing as "out" defaults to + initializing the value as low. To ensure glitch free + operation, values "low" and "high" may be written to + configure the GPIO as an output with that initial value. + + Note that this attribute *will not exist* if the kernel + doesn't support changing the direction of a GPIO, or + it was exported by kernel code that didn't explicitly + allow userspace to reconfigure this GPIO's direction. + + "value" ... reads as either 0 (low) or 1 (high). If the GPIO + is configured as an output, this value may be written; + any nonzero value is treated as high. + + If the pin can be configured as interrupt-generating interrupt + and if it has been configured to generate interrupts (see the + description of "edge"), you can poll(2) on that file and + poll(2) will return whenever the interrupt was triggered. If + you use poll(2), set the events POLLPRI and POLLERR. If you + use select(2), set the file descriptor in exceptfds. After + poll(2) returns, either lseek(2) to the beginning of the sysfs + file and read the new value or close the file and re-open it + to read the value. + + "edge" ... reads as either "none", "rising", "falling", or + "both". Write these strings to select the signal edge(s) + that will make poll(2) on the "value" file return. + + This file exists only if the pin can be configured as an + interrupt generating input pin. + + "active_low" ... reads as either 0 (false) or 1 (true). Write + any nonzero value to invert the value attribute both + for reading and writing. Existing and subsequent + poll(2) support configuration via the edge attribute + for "rising" and "falling" edges will follow this + setting. + +GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the +controller implementing GPIOs starting at #42) and have the following +read-only attributes: + + /sys/class/gpio/gpiochipN/ + + "base" ... same as N, the first GPIO managed by this chip + + "label" ... provided for diagnostics (not always unique) + + "ngpio" ... how many GPIOs this manges (N to N + ngpio - 1) + +Board documentation should in most cases cover what GPIOs are used for +what purposes. However, those numbers are not always stable; GPIOs on +a daughtercard might be different depending on the base board being used, +or other cards in the stack. In such cases, you may need to use the +gpiochip nodes (possibly in conjunction with schematics) to determine +the correct GPIO number to use for a given signal. + + +Exporting from Kernel code +-------------------------- +Kernel code can explicitly manage exports of GPIOs which have already been +requested using gpio_request(): + + /* export the GPIO to userspace */ + int gpiod_export(struct gpio_desc *desc, bool direction_may_change); + + /* reverse gpio_export() */ + void gpiod_unexport(struct gpio_desc *desc); + + /* create a sysfs link to an exported GPIO node */ + int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); + + /* change the polarity of a GPIO node in sysfs */ + int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); + +After a kernel driver requests a GPIO, it may only be made available in +the sysfs interface by gpiod_export(). The driver can control whether the +signal direction may change. This helps drivers prevent userspace code +from accidentally clobbering important system state. + +This explicit exporting can help with debugging (by making some kinds +of experiments easier), or can provide an always-there interface that's +suitable for documenting as part of a board support package. + +After the GPIO has been exported, gpiod_export_link() allows creating +symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can +use this to provide the interface under their own device in sysfs with +a descriptive name. + +Drivers can use gpiod_sysfs_set_active_low() to hide GPIO line polarity +differences between boards from user space. Polarity change can be done both +before and after gpiod_export(), and previously enabled poll(2) support for +either rising or falling edge will be reconfigured to follow this setting. diff --git a/MAINTAINERS b/MAINTAINERS index 8285ed4..f216db8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2142,6 +2142,11 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/chipidea/ +CHROME HARDWARE PLATFORM SUPPORT +M: Olof Johansson <olof@lixom.net> +S: Maintained +F: drivers/platform/chrome/ + CISCO VIC ETHERNET NIC DRIVER M: Christian Benvenuti <benve@cisco.com> M: Sujith Sankar <ssujith@cisco.com> @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 13 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = One Giant Leap for Frogkind # *DOCUMENTATION* diff --git a/arch/arm/boot/dts/am335x-base0033.dts b/arch/arm/boot/dts/am335x-base0033.dts index b4f95c2..72a9b3f 100644 --- a/arch/arm/boot/dts/am335x-base0033.dts +++ b/arch/arm/boot/dts/am335x-base0033.dts @@ -13,4 +13,83 @@ / { model = "IGEP COM AM335x on AQUILA Expansion"; compatible = "isee,am335x-base0033", "isee,am335x-igep0033", "ti,am33xx"; + + hdmi { + compatible = "ti,tilcdc,slave"; + i2c = <&i2c0>; + pinctrl-names = "default", "off"; + pinctrl-0 = <&nxp_hdmi_pins>; + pinctrl-1 = <&nxp_hdmi_off_pins>; + status = "okay"; + }; + + leds_base { + pinctrl-names = "default"; + pinctrl-0 = <&leds_base_pins>; + + compatible = "gpio-leds"; + + led@0 { + label = "base:red:user"; + gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; /* gpio1_21 */ + default-state = "off"; + }; + + led@1 { + label = "base:green:user"; + gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>; /* gpio2_0 */ + default-state = "off"; + }; + }; +}; + +&am33xx_pinmux { + nxp_hdmi_pins: pinmux_nxp_hdmi_pins { + pinctrl-single,pins = < + 0x1b0 (PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */ + 0xa0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data0 */ + 0xa4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data1 */ + 0xa8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data2 */ + 0xac (PIN_OUTPUT | MUX_MODE0) /* lcd_data3 */ + 0xb0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data4 */ + 0xb4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data5 */ + 0xb8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data6 */ + 0xbc (PIN_OUTPUT | MUX_MODE0) /* lcd_data7 */ + 0xc0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data8 */ + 0xc4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data9 */ + 0xc8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data10 */ + 0xcc (PIN_OUTPUT | MUX_MODE0) /* lcd_data11 */ + 0xd0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data12 */ + 0xd4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data13 */ + 0xd8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data14 */ + 0xdc (PIN_OUTPUT | MUX_MODE0) /* lcd_data15 */ + 0xe0 (PIN_OUTPUT | MUX_MODE0) /* lcd_vsync */ + 0xe4 (PIN_OUTPUT | MUX_MODE0) /* lcd_hsync */ + 0xe8 (PIN_OUTPUT | MUX_MODE0) /* lcd_pclk */ + 0xec (PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en */ + >; + }; + nxp_hdmi_off_pins: pinmux_nxp_hdmi_off_pins { + pinctrl-single,pins = < + 0x1b0 (PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */ + >; + }; + + leds_base_pins: pinmux_leds_base_pins { + pinctrl-single,pins = < + 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */ + 0x88 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn3.gpio2_0 */ + >; + }; +}; + +&lcdc { + status = "okay"; +}; + +&i2c0 { + eeprom: eeprom@50 { + compatible = "at,24c256"; + reg = <0x50>; + }; }; diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi index 6196244..7063311 100644 --- a/arch/arm/boot/dts/am335x-igep0033.dtsi +++ b/arch/arm/boot/dts/am335x-igep0033.dtsi @@ -199,6 +199,35 @@ pinctrl-0 = <&uart0_pins>; }; +&usb { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + usb-phy@47401300 { + status = "okay"; + }; + + usb-phy@47401b00 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + + usb@47401800 { + status = "okay"; + dr_mode = "host"; + }; + + dma-controller@07402000 { + status = "okay"; + }; +}; + #include "tps65910.dtsi" &tps { diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts index 90ce29d..08a56bc 100644 --- a/arch/arm/boot/dts/armada-370-db.dts +++ b/arch/arm/boot/dts/armada-370-db.dts @@ -99,22 +99,22 @@ spi-max-frequency = <50000000>; }; }; + }; - pcie-controller { + pcie-controller { + status = "okay"; + /* + * The two PCIe units are accessible through + * both standard PCIe slots and mini-PCIe + * slots on the board. + */ + pcie@1,0 { + /* Port 0, Lane 0 */ + status = "okay"; + }; + pcie@2,0 { + /* Port 1, Lane 0 */ status = "okay"; - /* - * The two PCIe units are accessible through - * both standard PCIe slots and mini-PCIe - * slots on the board. - */ - pcie@1,0 { - /* Port 0, Lane 0 */ - status = "okay"; - }; - pcie@2,0 { - /* Port 1, Lane 0 */ - status = "okay"; - }; }; }; }; diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 00d6a79..7f10f62 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -118,7 +118,7 @@ coherency-fabric@20200 { compatible = "marvell,coherency-fabric"; - reg = <0x20200 0xb0>, <0x21810 0x1c>; + reg = <0x20200 0xb0>, <0x21010 0x1c>; }; serial@12000 { diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi index 3f5e612..98335fb 100644 --- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi @@ -47,7 +47,7 @@ /* * MV78230 has 2 PCIe units Gen2.0: One unit can be * configured as x4 or quad x1 lanes. One unit is - * x4/x1. + * x1 only. */ pcie-controller { compatible = "marvell,armada-xp-pcie"; @@ -62,10 +62,10 @@ ranges = <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ - 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */ 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */ 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ + 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */ 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */ @@ -74,8 +74,8 @@ 0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */ 0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */ 0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */ - 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */ - 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */>; + 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ + 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */>; pcie@1,0 { device_type = "pci"; @@ -145,20 +145,20 @@ status = "disabled"; }; - pcie@9,0 { + pcie@5,0 { device_type = "pci"; - assigned-addresses = <0x82000800 0 0x42000 0 0x2000>; - reg = <0x4800 0 0 0 0>; + assigned-addresses = <0x82000800 0 0x80000 0 0x2000>; + reg = <0x2800 0 0 0 0>; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0 - 0x81000000 0 0 0x81000000 0x9 0 1 0>; + ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0 + 0x81000000 0 0 0x81000000 0x5 0 1 0>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 99>; - marvell,pcie-port = <2>; + interrupt-map = <0 0 0 0 &mpic 62>; + marvell,pcie-port = <1>; marvell,pcie-lane = <0>; - clocks = <&gateclk 26>; + clocks = <&gateclk 9>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi index 3e9fd13..6660968 100644 --- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi @@ -48,7 +48,7 @@ /* * MV78260 has 3 PCIe units Gen2.0: Two units can be * configured as x4 or quad x1 lanes. One unit is - * x4/x1. + * x4 only. */ pcie-controller { compatible = "marvell,armada-xp-pcie"; @@ -68,7 +68,9 @@ 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */ - 0x82000000 0 0x82000 MBUS_ID(0xf0, 0x01) 0x82000 0 0x00002000 /* Port 3.0 registers */ + 0x82000000 0 0x84000 MBUS_ID(0xf0, 0x01) 0x84000 0 0x00002000 /* Port 1.1 registers */ + 0x82000000 0 0x88000 MBUS_ID(0xf0, 0x01) 0x88000 0 0x00002000 /* Port 1.2 registers */ + 0x82000000 0 0x8c000 MBUS_ID(0xf0, 0x01) 0x8c000 0 0x00002000 /* Port 1.3 registers */ 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */ @@ -77,10 +79,18 @@ 0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */ 0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */ 0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */ - 0x82000000 0x9 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ - 0x81000000 0x9 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */ - 0x82000000 0xa 0 MBUS_ID(0x08, 0xf8) 0 1 0 /* Port 3.0 MEM */ - 0x81000000 0xa 0 MBUS_ID(0x08, 0xf0) 0 1 0 /* Port 3.0 IO */>; + + 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ + 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */ + 0x82000000 0x6 0 MBUS_ID(0x08, 0xd8) 0 1 0 /* Port 1.1 MEM */ + 0x81000000 0x6 0 MBUS_ID(0x08, 0xd0) 0 1 0 /* Port 1.1 IO */ + 0x82000000 0x7 0 MBUS_ID(0x08, 0xb8) 0 1 0 /* Port 1.2 MEM */ + 0x81000000 0x7 0 MBUS_ID(0x08, 0xb0) 0 1 0 /* Port 1.2 IO */ + 0x82000000 0x8 0 MBUS_ID(0x08, 0x78) 0 1 0 /* Port 1.3 MEM */ + 0x81000000 0x8 0 MBUS_ID(0x08, 0x70) 0 1 0 /* Port 1.3 IO */ + + 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */ + 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */>; pcie@1,0 { device_type = "pci"; @@ -106,8 +116,8 @@ #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 - 0x81000000 0 0 0x81000000 0x2 0 1 0>; + ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 + 0x81000000 0 0 0x81000000 0x2 0 1 0>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &mpic 59>; marvell,pcie-port = <0>; @@ -150,37 +160,88 @@ status = "disabled"; }; - pcie@9,0 { + pcie@5,0 { device_type = "pci"; - assigned-addresses = <0x82000800 0 0x42000 0 0x2000>; - reg = <0x4800 0 0 0 0>; + assigned-addresses = <0x82000800 0 0x80000 0 0x2000>; + reg = <0x2800 0 0 0 0>; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0 - 0x81000000 0 0 0x81000000 0x9 0 1 0>; + ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0 + 0x81000000 0 0 0x81000000 0x5 0 1 0>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 99>; - marvell,pcie-port = <2>; + interrupt-map = <0 0 0 0 &mpic 62>; + marvell,pcie-port = <1>; marvell,pcie-lane = <0>; - clocks = <&gateclk 26>; + clocks = <&gateclk 9>; status = "disabled"; }; - pcie@10,0 { + pcie@6,0 { device_type = "pci"; - assigned-addresses = <0x82000800 0 0x82000 0 0x2000>; - reg = <0x5000 0 0 0 0>; + assigned-addresses = <0x82000800 0 0x84000 0 0x2000>; + reg = <0x3000 0 0 0 0>; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0xa 0 1 0 - 0x81000000 0 0 0x81000000 0xa 0 1 0>; + ranges = <0x82000000 0 0 0x82000000 0x6 0 1 0 + 0x81000000 0 0 0x81000000 0x6 0 1 0>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 103>; - marvell,pcie-port = <3>; + interrupt-map = <0 0 0 0 &mpic 63>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <1>; + clocks = <&gateclk 10>; + status = "disabled"; + }; + + pcie@7,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x88000 0 0x2000>; + reg = <0x3800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x7 0 1 0 + 0x81000000 0 0 0x81000000 0x7 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 64>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <2>; + clocks = <&gateclk 11>; + status = "disabled"; + }; + + pcie@8,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x8c000 0 0x2000>; + reg = <0x4000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x8 0 1 0 + 0x81000000 0 0 0x81000000 0x8 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 65>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <3>; + clocks = <&gateclk 12>; + status = "disabled"; + }; + + pcie@9,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x42000 0 0x2000>; + reg = <0x4800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0 + 0x81000000 0 0 0x81000000 0x9 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 99>; + marvell,pcie-port = <2>; marvell,pcie-lane = <0>; - clocks = <&gateclk 27>; + clocks = <&gateclk 26>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/at91sam9x5_usart3.dtsi b/arch/arm/boot/dts/at91sam9x5_usart3.dtsi index 2347e95..6801106 100644 --- a/arch/arm/boot/dts/at91sam9x5_usart3.dtsi +++ b/arch/arm/boot/dts/at91sam9x5_usart3.dtsi @@ -11,6 +11,10 @@ #include <dt-bindings/interrupt-controller/irq.h> / { + aliases { + serial4 = &usart3; + }; + ahb { apb { pinctrl@fffff400 { diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi index 1e12aef..aa537ed 100644 --- a/arch/arm/boot/dts/bcm2835.dtsi +++ b/arch/arm/boot/dts/bcm2835.dtsi @@ -85,6 +85,8 @@ reg = <0x7e205000 0x1000>; interrupts = <2 21>; clocks = <&clk_i2c>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; @@ -93,6 +95,8 @@ reg = <0x7e804000 0x1000>; interrupts = <2 21>; clocks = <&clk_i2c>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/cros5250-common.dtsi b/arch/arm/boot/dts/cros5250-common.dtsi index dc259e8b..9b186ac 100644 --- a/arch/arm/boot/dts/cros5250-common.dtsi +++ b/arch/arm/boot/dts/cros5250-common.dtsi @@ -27,6 +27,13 @@ i2c2_bus: i2c2-bus { samsung,pin-pud = <0>; }; + + max77686_irq: max77686-irq { + samsung,pins = "gpx3-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; i2c@12C60000 { @@ -35,6 +42,11 @@ max77686@09 { compatible = "maxim,max77686"; + interrupt-parent = <&gpx3>; + interrupts = <2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&max77686_irq>; + wakeup-source; reg = <0x09>; voltage-regulators { diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 59154dc..fb28b2e 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -161,7 +161,7 @@ clocks = <&clks 197>, <&clks 3>, <&clks 197>, <&clks 107>, <&clks 0>, <&clks 118>, - <&clks 62>, <&clks 139>, + <&clks 0>, <&clks 139>, <&clks 0>; clock-names = "core", "rxtx0", "rxtx1", "rxtx2", diff --git a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi index 9c18adf..f577b7d 100644 --- a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi +++ b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi @@ -44,8 +44,8 @@ gpmc,wr-access-ns = <186>; gpmc,cycle2cycle-samecsen; gpmc,cycle2cycle-diffcsen; - vmmc-supply = <&vddvario>; - vmmc_aux-supply = <&vdd33a>; + vddvario-supply = <&vddvario>; + vdd33a-supply = <&vdd33a>; reg-io-width = <4>; smsc,save-mac-address; }; diff --git a/arch/arm/boot/dts/omap-zoom-common.dtsi b/arch/arm/boot/dts/omap-zoom-common.dtsi index b0ee342..68221fa 100644 --- a/arch/arm/boot/dts/omap-zoom-common.dtsi +++ b/arch/arm/boot/dts/omap-zoom-common.dtsi @@ -13,7 +13,7 @@ * they probably share the same GPIO IRQ * REVISIT: Add timing support from slls644g.pdf */ - 8250@3,0 { + uart@3,0 { compatible = "ns16550a"; reg = <3 0 0x100>; bank-width = <2>; diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index a2bfcde..d0c5b37 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -9,6 +9,7 @@ */ #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/pinctrl/omap.h> #include "skeleton.dtsi" @@ -21,6 +22,8 @@ serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; + i2c0 = &i2c1; + i2c1 = &i2c2; }; cpus { @@ -53,6 +56,28 @@ ranges; ti,hwmods = "l3_main"; + aes: aes@480a6000 { + compatible = "ti,omap2-aes"; + ti,hwmods = "aes"; + reg = <0x480a6000 0x50>; + dmas = <&sdma 9 &sdma 10>; + dma-names = "tx", "rx"; + }; + + hdq1w: 1w@480b2000 { + compatible = "ti,omap2420-1w"; + ti,hwmods = "hdq1w"; + reg = <0x480b2000 0x1000>; + interrupts = <58>; + }; + + mailbox: mailbox@48094000 { + compatible = "ti,omap2-mailbox"; + ti,hwmods = "mailbox"; + reg = <0x48094000 0x200>; + interrupts = <26>; + }; + intc: interrupt-controller@1 { compatible = "ti,omap2-intc"; interrupt-controller; @@ -63,6 +88,7 @@ sdma: dma-controller@48056000 { compatible = "ti,omap2430-sdma", "ti,omap2420-sdma"; + ti,hwmods = "dma"; reg = <0x48056000 0x1000>; interrupts = <12>, <13>, @@ -73,21 +99,91 @@ #dma-requests = <64>; }; + i2c1: i2c@48070000 { + compatible = "ti,omap2-i2c"; + ti,hwmods = "i2c1"; + reg = <0x48070000 0x80>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <56>; + dmas = <&sdma 27 &sdma 28>; + dma-names = "tx", "rx"; + }; + + i2c2: i2c@48072000 { + compatible = "ti,omap2-i2c"; + ti,hwmods = "i2c2"; + reg = <0x48072000 0x80>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <57>; + dmas = <&sdma 29 &sdma 30>; + dma-names = "tx", "rx"; + }; + + mcspi1: mcspi@48098000 { + compatible = "ti,omap2-mcspi"; + ti,hwmods = "mcspi1"; + reg = <0x48098000 0x100>; + interrupts = <65>; + dmas = <&sdma 35 &sdma 36 &sdma 37 &sdma 38 + &sdma 39 &sdma 40 &sdma 41 &sdma 42>; + dma-names = "tx0", "rx0", "tx1", "rx1", + "tx2", "rx2", "tx3", "rx3"; + }; + + mcspi2: mcspi@4809a000 { + compatible = "ti,omap2-mcspi"; + ti,hwmods = "mcspi2"; + reg = <0x4809a000 0x100>; + interrupts = <66>; + dmas = <&sdma 43 &sdma 44 &sdma 45 &sdma 46>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + }; + + rng: rng@480a0000 { + compatible = "ti,omap2-rng"; + ti,hwmods = "rng"; + reg = <0x480a0000 0x50>; + interrupts = <36>; + }; + + sham: sham@480a4000 { + compatible = "ti,omap2-sham"; + ti,hwmods = "sham"; + reg = <0x480a4000 0x64>; + interrupts = <51>; + dmas = <&sdma 13>; + dma-names = "rx"; + }; + uart1: serial@4806a000 { compatible = "ti,omap2-uart"; ti,hwmods = "uart1"; + reg = <0x4806a000 0x2000>; + interrupts = <72>; + dmas = <&sdma 49 &sdma 50>; + dma-names = "tx", "rx"; clock-frequency = <48000000>; }; uart2: serial@4806c000 { compatible = "ti,omap2-uart"; ti,hwmods = "uart2"; + reg = <0x4806c000 0x400>; + interrupts = <73>; + dmas = <&sdma 51 &sdma 52>; + dma-names = "tx", "rx"; clock-frequency = <48000000>; }; uart3: serial@4806e000 { compatible = "ti,omap2-uart"; ti,hwmods = "uart3"; + reg = <0x4806e000 0x400>; + interrupts = <74>; + dmas = <&sdma 53 &sdma 54>; + dma-names = "tx", "rx"; clock-frequency = <48000000>; }; diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi index c8f9c55..60c605d 100644 --- a/arch/arm/boot/dts/omap2420.dtsi +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -114,6 +114,15 @@ dma-names = "tx", "rx"; }; + msdi1: mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; + timer1: timer@48028000 { compatible = "ti,omap2420-timer"; reg = <0x48028000 0x400>; @@ -121,5 +130,19 @@ ti,hwmods = "timer1"; ti,timer-alwon; }; + + wd_timer2: wdt@48022000 { + compatible = "ti,omap2-wdt"; + ti,hwmods = "wd_timer2"; + reg = <0x48022000 0x80>; + }; }; }; + +&i2c1 { + compatible = "ti,omap2420-i2c"; +}; + +&i2c2 { + compatible = "ti,omap2420-i2c"; +}; diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index c535a5a..d624345 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -175,6 +175,25 @@ dma-names = "tx", "rx"; }; + mmc1: mmc@4809c000 { + compatible = "ti,omap2-hsmmc"; + reg = <0x4809c000 0x200>; + interrupts = <83>; + ti,hwmods = "mmc1"; + ti,dual-volt; + dmas = <&sdma 61>, <&sdma 62>; + dma-names = "tx", "rx"; + }; + + mmc2: mmc@480b4000 { + compatible = "ti,omap2-hsmmc"; + reg = <0x480b4000 0x200>; + interrupts = <86>; + ti,hwmods = "mmc2"; + dmas = <&sdma 47>, <&sdma 48>; + dma-names = "tx", "rx"; + }; + timer1: timer@49018000 { compatible = "ti,omap2420-timer"; reg = <0x49018000 0x400>; @@ -182,5 +201,35 @@ ti,hwmods = "timer1"; ti,timer-alwon; }; + + mcspi3: mcspi@480b8000 { + compatible = "ti,omap2-mcspi"; + ti,hwmods = "mcspi3"; + reg = <0x480b8000 0x100>; + interrupts = <91>; + dmas = <&sdma 15 &sdma 16 &sdma 23 &sdma 24>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + }; + + usb_otg_hs: usb_otg_hs@480ac000 { + compatible = "ti,omap2-musb"; + ti,hwmods = "usb_otg_hs"; + reg = <0x480ac000 0x1000>; + interrupts = <93>; + }; + + wd_timer2: wdt@49016000 { + compatible = "ti,omap2-wdt"; + ti,hwmods = "wd_timer2"; + reg = <0x49016000 0x80>; + }; }; }; + +&i2c1 { + compatible = "ti,omap2430-i2c"; +}; + +&i2c2 { + compatible = "ti,omap2430-i2c"; +}; diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts index 31a632f..df33a50 100644 --- a/arch/arm/boot/dts/omap3-beagle-xm.dts +++ b/arch/arm/boot/dts/omap3-beagle-xm.dts @@ -215,3 +215,10 @@ &usbhsehci { phys = <0 &hsusb2_phy>; }; + +&vaux2 { + regulator-name = "usb_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +}; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index fa532aa..3ba4a62 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -61,6 +61,14 @@ vcc-supply = <&hsusb2_power>; }; + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + + ti,mcbsp = <&mcbsp2>; + ti,codec = <&twl_audio>; + }; + gpio_keys { compatible = "gpio-keys"; @@ -120,6 +128,12 @@ reg = <0x48>; interrupts = <7>; /* SYS_NIRQ cascaded to intc */ interrupt-parent = <&intc>; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + codec { + }; + }; }; }; @@ -178,3 +192,10 @@ mode = <3>; power = <50>; }; + +&vaux2 { + regulator-name = "vdd_ehci"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +}; diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi index ba1e58b..165aaf7 100644 --- a/arch/arm/boot/dts/omap3-igep.dtsi +++ b/arch/arm/boot/dts/omap3-igep.dtsi @@ -1,5 +1,5 @@ /* - * Device Tree Source for IGEP Technology devices + * Common device tree for IGEP boards based on AM/DM37x * * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk> * Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com> @@ -10,7 +10,7 @@ */ /dts-v1/; -#include "omap34xx.dtsi" +#include "omap36xx.dtsi" / { memory { @@ -24,6 +24,25 @@ ti,mcbsp = <&mcbsp2>; ti,codec = <&twl_audio>; }; + + vdd33: regulator-vdd33 { + compatible = "regulator-fixed"; + regulator-name = "vdd33"; + regulator-always-on; + }; + + lbee1usjyc_vmmc: lbee1usjyc_vmmc { + pinctrl-names = "default"; + pinctrl-0 = <&lbee1usjyc_pins>; + compatible = "regulator-fixed"; + regulator-name = "regulator-lbee1usjyc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 WIFI_PDN */ + startup-delay-us = <10000>; + enable-active-high; + vin-supply = <&vdd33>; + }; }; &omap3_pmx_core { @@ -48,6 +67,15 @@ >; }; + /* WiFi/BT combo */ + lbee1usjyc_pins: pinmux_lbee1usjyc_pins { + pinctrl-single,pins = < + 0x136 (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 */ + 0x138 (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat6.gpio_138 */ + 0x13a (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 */ + >; + }; + mcbsp2_pins: pinmux_mcbsp2_pins { pinctrl-single,pins = < 0x10c (PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx.mcbsp2_fsx */ @@ -65,10 +93,17 @@ 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ - 0x120 (PIN_INPUT | MUX_MODE0) /* sdmmc1_dat4.sdmmc1_dat4 */ - 0x122 (PIN_INPUT | MUX_MODE0) /* sdmmc1_dat5.sdmmc1_dat5 */ - 0x124 (PIN_INPUT | MUX_MODE0) /* sdmmc1_dat6.sdmmc1_dat6 */ - 0x126 (PIN_INPUT | MUX_MODE0) /* sdmmc1_dat7.sdmmc1_dat7 */ + >; + }; + + mmc2_pins: pinmux_mmc2_pins { + pinctrl-single,pins = < + 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */ + 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */ + 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */ + 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */ + 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */ + 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */ >; }; @@ -78,10 +113,33 @@ >; }; + i2c1_pins: pinmux_i2c1_pins { + pinctrl-single,pins = < + 0x18a (PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ + 0x18c (PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + >; + }; + + i2c2_pins: pinmux_i2c2_pins { + pinctrl-single,pins = < + 0x18e (PIN_INPUT | MUX_MODE0) /* i2c2_scl.i2c2_scl */ + 0x190 (PIN_INPUT | MUX_MODE0) /* i2c2_sda.i2c2_sda */ + >; + }; + + i2c3_pins: pinmux_i2c3_pins { + pinctrl-single,pins = < + 0x192 (PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */ + 0x194 (PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */ + >; + }; + leds_pins: pinmux_leds_pins { }; }; &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; clock-frequency = <2600000>; twl: twl@48 { @@ -101,9 +159,16 @@ #include "twl4030_omap3.dtsi" &i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; clock-frequency = <400000>; }; +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; +}; + &mcbsp2 { pinctrl-names = "default"; pinctrl-0 = <&mcbsp2_pins>; @@ -114,11 +179,15 @@ pinctrl-0 = <&mmc1_pins>; vmmc-supply = <&vmmc1>; vmmc_aux-supply = <&vsim>; - bus-width = <8>; + bus-width = <4>; }; &mmc2 { - status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <&lbee1usjyc_vmmc>; + bus-width = <4>; + non-removable; }; &mmc3 { diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts index d5cc792..1c7e74d 100644 --- a/arch/arm/boot/dts/omap3-igep0020.dts +++ b/arch/arm/boot/dts/omap3-igep0020.dts @@ -1,5 +1,5 @@ /* - * Device Tree Source for IGEPv2 board + * Device Tree Source for IGEPv2 Rev. (TI OMAP AM/DM37x) * * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk> * Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com> @@ -13,7 +13,7 @@ #include "omap-gpmc-smsc911x.dtsi" / { - model = "IGEPv2"; + model = "IGEPv2 (TI OMAP AM/DM37x)"; compatible = "isee,omap3-igep0020", "ti,omap3"; leds { @@ -67,6 +67,8 @@ pinctrl-names = "default"; pinctrl-0 = < &hsusbb1_pins + &tfp410_pins + &dss_pins >; hsusbb1_pins: pinmux_hsusbb1_pins { @@ -85,6 +87,45 @@ 0x5ba (PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d7.hsusb1_data3 */ >; }; + + tfp410_pins: tfp410_dvi_pins { + pinctrl-single,pins = < + 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */ + >; + }; + + dss_pins: pinmux_dss_dvi_pins { + pinctrl-single,pins = < + 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */ + 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */ + 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */ + 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */ + 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */ + 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */ + 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */ + 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */ + 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */ + 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */ + 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */ + 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */ + 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */ + 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */ + 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */ + 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */ + 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */ + 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */ + 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */ + 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */ + 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */ + 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */ + 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */ + 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */ + 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */ + 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */ + 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */ + 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */ + >; + }; }; &leds_pins { @@ -174,3 +215,8 @@ &usbhsehci { phys = <&hsusb1_phy>; }; + +&vpll2 { + /* Needed for DSS */ + regulator-name = "vdds_dsi"; +}; diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts index 525e6d9..02a23f8 100644 --- a/arch/arm/boot/dts/omap3-igep0030.dts +++ b/arch/arm/boot/dts/omap3-igep0030.dts @@ -1,5 +1,5 @@ /* - * Device Tree Source for IGEP COM Module + * Device Tree Source for IGEP COM MODULE (TI OMAP AM/DM37x) * * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk> * Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com> @@ -12,7 +12,7 @@ #include "omap3-igep.dtsi" / { - model = "IGEP COM Module"; + model = "IGEP COM MODULE (TI OMAP AM/DM37x)"; compatible = "isee,omap3-igep0030", "ti,omap3"; leds { diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index c4f20bf..c2c306d 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -125,6 +125,21 @@ >; }; + mmc2_pins: pinmux_mmc2_pins { + pinctrl-single,pins = < + 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk */ + 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd */ + 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0 */ + 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1 */ + 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2 */ + 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3 */ + 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat4 */ + 0x136 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat5 */ + 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat6 */ + 0x13a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat7 */ + >; + }; + display_pins: pinmux_display_pins { pinctrl-single,pins = < 0x0d4 (PIN_OUTPUT | MUX_MODE4) /* RX51_LCD_RESET_GPIO */ @@ -358,8 +373,14 @@ cd-gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>; /* 160 */ }; +/* most boards use vaux3, only some old versions use vmmc2 instead */ &mmc2 { - status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <&vaux3>; + vmmc_aux-supply = <&vsim>; + bus-width = <8>; + non-removable; }; &mmc3 { diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index f3a0c26..daabf99 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -82,6 +82,13 @@ ranges; ti,hwmods = "l3_main"; + aes: aes@480c5000 { + compatible = "ti,omap3-aes"; + ti,hwmods = "aes"; + reg = <0x480c5000 0x50>; + interrupts = <0>; + }; + counter32k: counter@48320000 { compatible = "ti,omap-counter32k"; reg = <0x48320000 0x20>; @@ -260,6 +267,13 @@ ti,hwmods = "i2c3"; }; + mailbox: mailbox@48094000 { + compatible = "ti,omap3-mailbox"; + ti,hwmods = "mailbox"; + reg = <0x48094000 0x200>; + interrupts = <26>; + }; + mcspi1: spi@48098000 { compatible = "ti,omap2-mcspi"; reg = <0x48098000 0x100>; @@ -357,6 +371,13 @@ dma-names = "tx", "rx"; }; + mmu_isp: mmu@480bd400 { + compatible = "ti,omap3-mmu-isp"; + ti,hwmods = "mmu_isp"; + reg = <0x480bd400 0x80>; + interrupts = <8>; + }; + wdt2: wdt@48314000 { compatible = "ti,omap3-wdt"; reg = <0x48314000 0x80>; @@ -442,6 +463,27 @@ dma-names = "tx", "rx"; }; + sham: sham@480c3000 { + compatible = "ti,omap3-sham"; + ti,hwmods = "sham"; + reg = <0x480c3000 0x64>; + interrupts = <49>; + }; + + smartreflex_core: smartreflex@480cb000 { + compatible = "ti,omap3-smartreflex-core"; + ti,hwmods = "smartreflex_core"; + reg = <0x480cb000 0x400>; + interrupts = <19>; + }; + + smartreflex_mpu_iva: smartreflex@480c9000 { + compatible = "ti,omap3-smartreflex-iva"; + ti,hwmods = "smartreflex_mpu_iva"; + reg = <0x480c9000 0x400>; + interrupts = <18>; + }; + timer1: timer@48318000 { compatible = "ti,omap3430-timer"; reg = <0x48318000 0x400>; diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi index 298e850..88c6a05 100644 --- a/arch/arm/boot/dts/omap4-panda-common.dtsi +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi @@ -246,15 +246,6 @@ 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */ >; }; -}; - -&omap4_pmx_wkup { - led_wkgpio_pins: pinmux_leds_wkpins { - pinctrl-single,pins = < - 0x1a (PIN_OUTPUT | MUX_MODE3) /* gpio_wk7 */ - 0x1c (PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */ - >; - }; /* * wl12xx GPIO outputs for WLAN_EN, BT_EN, FM_EN, BT_WAKEUP @@ -274,7 +265,7 @@ pinctrl-single,pins = < 0x38 (PIN_INPUT | MUX_MODE3) /* gpmc_ncs2.gpio_52 */ 0x3a (PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */ - 0x108 (PIN_OUTPUT | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */ + 0x108 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */ 0x10a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */ 0x10c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */ 0x10e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */ @@ -284,6 +275,15 @@ }; }; +&omap4_pmx_wkup { + led_wkgpio_pins: pinmux_leds_wkpins { + pinctrl-single,pins = < + 0x1a (PIN_OUTPUT | MUX_MODE3) /* gpio_wk7 */ + 0x1c (PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */ + >; + }; +}; + &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins>; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 5fc3f43..dbc81fb 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -300,12 +300,12 @@ wl12xx_pins: pinmux_wl12xx_pins { pinctrl-single,pins = < 0x3a (PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */ - 0x108 (PIN_OUTPUT | MUX_MODE3) /* sdmmc5_clk.sdmmc5_clk */ - 0x10a (PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc5_cmd.sdmmc5_cmd */ - 0x10c (PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc5_dat0.sdmmc5_dat0 */ - 0x10e (PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc5_dat1.sdmmc5_dat1 */ - 0x110 (PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc5_dat2.sdmmc5_dat2 */ - 0x112 (PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc5_dat3.sdmmc5_dat3 */ + 0x108 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */ + 0x10a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */ + 0x10c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */ + 0x10e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */ + 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2.sdmmc5_dat2 */ + 0x112 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3.sdmmc5_dat3 */ >; }; }; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 5cdaba4..de9fece 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -13,6 +13,7 @@ #include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/clk/at91.h> / { model = "Atmel SAMA5D3 family SoC"; @@ -56,6 +57,14 @@ reg = <0x20000000 0x8000000>; }; + clocks { + adc_op_clk: adc_op_clk{ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <20000000>; + }; + }; + ahb { compatible = "simple-bus"; #address-cells = <1>; @@ -79,6 +88,8 @@ status = "disabled"; #address-cells = <1>; #size-cells = <0>; + clocks = <&mci0_clk>; + clock-names = "mci_clk"; }; spi0: spi@f0004000 { @@ -92,6 +103,8 @@ dma-names = "tx", "rx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi0>; + clocks = <&spi0_clk>; + clock-names = "spi_clk"; status = "disabled"; }; @@ -101,6 +114,8 @@ interrupts = <38 IRQ_TYPE_LEVEL_HIGH 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; + clocks = <&ssc0_clk>; + clock-names = "pclk"; status = "disabled"; }; @@ -108,6 +123,8 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf0010000 0x100>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tcb0_clk>; + clock-names = "t0_clk"; }; i2c0: i2c@f0014000 { @@ -121,6 +138,7 @@ pinctrl-0 = <&pinctrl_i2c0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&twi0_clk>; status = "disabled"; }; @@ -135,6 +153,7 @@ pinctrl-0 = <&pinctrl_i2c1>; #address-cells = <1>; #size-cells = <0>; + clocks = <&twi1_clk>; status = "disabled"; }; @@ -144,6 +163,8 @@ interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart0>; + clocks = <&usart0_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -153,6 +174,8 @@ interrupts = <13 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart1>; + clocks = <&usart1_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -174,6 +197,8 @@ status = "disabled"; #address-cells = <1>; #size-cells = <0>; + clocks = <&mci1_clk>; + clock-names = "mci_clk"; }; spi1: spi@f8008000 { @@ -187,6 +212,8 @@ dma-names = "tx", "rx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi1>; + clocks = <&spi1_clk>; + clock-names = "spi_clk"; status = "disabled"; }; @@ -196,6 +223,8 @@ interrupts = <39 IRQ_TYPE_LEVEL_HIGH 4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; + clocks = <&ssc1_clk>; + clock-names = "pclk"; status = "disabled"; }; @@ -219,6 +248,9 @@ &pinctrl_adc0_ad10 &pinctrl_adc0_ad11 >; + clocks = <&adc_clk>, + <&adc_op_clk>; + clock-names = "adc_clk", "adc_op_clk"; atmel,adc-channel-base = <0x50>; atmel,adc-channels-used = <0xfff>; atmel,adc-drdy-mask = <0x1000000>; @@ -274,6 +306,7 @@ dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; + clocks = <&twi2_clk>; status = "disabled"; }; @@ -283,6 +316,8 @@ interrupts = <14 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart2>; + clocks = <&usart2_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -292,6 +327,8 @@ interrupts = <15 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usart3>; + clocks = <&usart3_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -318,6 +355,8 @@ reg = <0xffffe600 0x200>; interrupts = <30 IRQ_TYPE_LEVEL_HIGH 0>; #dma-cells = <2>; + clocks = <&dma0_clk>; + clock-names = "dma_clk"; }; dma1: dma-controller@ffffe800 { @@ -325,6 +364,8 @@ reg = <0xffffe800 0x200>; interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>; #dma-cells = <2>; + clocks = <&dma1_clk>; + clock-names = "dma_clk"; }; ramc0: ramc@ffffea00 { @@ -338,6 +379,8 @@ interrupts = <2 IRQ_TYPE_LEVEL_HIGH 7>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_dbgu>; + clocks = <&dbgu_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -626,6 +669,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioA_clk>; }; pioB: gpio@fffff400 { @@ -636,6 +680,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioB_clk>; }; pioC: gpio@fffff600 { @@ -646,6 +691,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioC_clk>; }; pioD: gpio@fffff800 { @@ -656,6 +702,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioD_clk>; }; pioE: gpio@fffffa00 { @@ -666,12 +713,334 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; + clocks = <&pioE_clk>; }; }; pmc: pmc@fffffc00 { - compatible = "atmel,at91rm9200-pmc"; + compatible = "atmel,sama5d3-pmc"; reg = <0xfffffc00 0x120>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + + clk32k: slck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + main: mainck { + compatible = "atmel,at91rm9200-clk-main"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = <AT91_PMC_MOSCS>; + clocks = <&clk32k>; + }; + + plla: pllack { + compatible = "atmel,sama5d3-clk-pll"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = <AT91_PMC_LOCKA>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <8000000 50000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <400000000 1000000000 0 0>; + }; + + plladiv: plladivck { + compatible = "atmel,at91sam9x5-clk-plldiv"; + #clock-cells = <0>; + clocks = <&plla>; + }; + + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = <AT91_PMC_LOCKU>; + clocks = <&main>; + }; + + mck: masterck { + compatible = "atmel,at91sam9x5-clk-master"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = <AT91_PMC_MCKRDY>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>; + atmel,clk-output-range = <0 166000000>; + atmel,clk-divisors = <1 2 4 3>; + }; + + usb: usbck { + compatible = "atmel,at91sam9x5-clk-usb"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + prog: progck { + compatible = "atmel,at91sam9x5-clk-programmable"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + prog0: prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = <AT91_PMC_PCKRDY(0)>; + }; + + prog1: prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = <AT91_PMC_PCKRDY(1)>; + }; + + prog2: prog2 { + #clock-cells = <0>; + reg = <2>; + interrupts = <AT91_PMC_PCKRDY(2)>; + }; + }; + + smd: smdclk { + compatible = "atmel,at91sam9x5-clk-smd"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + ddrck: ddrck { + #clock-cells = <0>; + reg = <2>; + clocks = <&mck>; + }; + + smdck: smdck { + #clock-cells = <0>; + reg = <4>; + clocks = <&smd>; + }; + + uhpck: uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck: udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + + pck0: pck0 { + #clock-cells = <0>; + reg = <8>; + clocks = <&prog0>; + }; + + pck1: pck1 { + #clock-cells = <0>; + reg = <9>; + clocks = <&prog1>; + }; + + pck2: pck2 { + #clock-cells = <0>; + reg = <10>; + clocks = <&prog2>; + }; + }; + + periphck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mck>; + + dbgu_clk: dbgu_clk { + #clock-cells = <0>; + reg = <2>; + }; + + pioA_clk: pioA_clk { + #clock-cells = <0>; + reg = <6>; + }; + + pioB_clk: pioB_clk { + #clock-cells = <0>; + reg = <7>; + }; + + pioC_clk: pioC_clk { + #clock-cells = <0>; + reg = <8>; + }; + + pioD_clk: pioD_clk { + #clock-cells = <0>; + reg = <9>; + }; + + pioE_clk: pioE_clk { + #clock-cells = <0>; + reg = <10>; + }; + + usart0_clk: usart0_clk { + #clock-cells = <0>; + reg = <12>; + atmel,clk-output-range = <0 66000000>; + }; + + usart1_clk: usart1_clk { + #clock-cells = <0>; + reg = <13>; + atmel,clk-output-range = <0 66000000>; + }; + + usart2_clk: usart2_clk { + #clock-cells = <0>; + reg = <14>; + atmel,clk-output-range = <0 66000000>; + }; + + usart3_clk: usart3_clk { + #clock-cells = <0>; + reg = <15>; + atmel,clk-output-range = <0 66000000>; + }; + + twi0_clk: twi0_clk { + reg = <18>; + #clock-cells = <0>; + atmel,clk-output-range = <0 16625000>; + }; + + twi1_clk: twi1_clk { + #clock-cells = <0>; + reg = <19>; + atmel,clk-output-range = <0 16625000>; + }; + + twi2_clk: twi2_clk { + #clock-cells = <0>; + reg = <20>; + atmel,clk-output-range = <0 16625000>; + }; + + mci0_clk: mci0_clk { + #clock-cells = <0>; + reg = <21>; + }; + + mci1_clk: mci1_clk { + #clock-cells = <0>; + reg = <22>; + }; + + spi0_clk: spi0_clk { + #clock-cells = <0>; + reg = <24>; + atmel,clk-output-range = <0 133000000>; + }; + + spi1_clk: spi1_clk { + #clock-cells = <0>; + reg = <25>; + atmel,clk-output-range = <0 133000000>; + }; + + tcb0_clk: tcb0_clk { + #clock-cells = <0>; + reg = <26>; + atmel,clk-output-range = <0 133000000>; + }; + + pwm_clk: pwm_clk { + #clock-cells = <0>; + reg = <28>; + }; + + adc_clk: adc_clk { + #clock-cells = <0>; + reg = <29>; + atmel,clk-output-range = <0 66000000>; + }; + + dma0_clk: dma0_clk { + #clock-cells = <0>; + reg = <30>; + }; + + dma1_clk: dma1_clk { + #clock-cells = <0>; + reg = <31>; + }; + + uhphs_clk: uhphs_clk { + #clock-cells = <0>; + reg = <32>; + }; + + udphs_clk: udphs_clk { + #clock-cells = <0>; + reg = <33>; + }; + + isi_clk: isi_clk { + #clock-cells = <0>; + reg = <37>; + }; + + ssc0_clk: ssc0_clk { + #clock-cells = <0>; + reg = <38>; + atmel,clk-output-range = <0 66000000>; + }; + + ssc1_clk: ssc1_clk { + #clock-cells = <0>; + reg = <39>; + atmel,clk-output-range = <0 66000000>; + }; + + sha_clk: sha_clk { + #clock-cells = <0>; + reg = <42>; + }; + + aes_clk: aes_clk { + #clock-cells = <0>; + reg = <43>; + }; + + tdes_clk: tdes_clk { + #clock-cells = <0>; + reg = <44>; + }; + + trng_clk: trng_clk { + #clock-cells = <0>; + reg = <45>; + }; + + fuse_clk: fuse_clk { + #clock-cells = <0>; + reg = <48>; + }; + }; }; rstc@fffffe00 { @@ -683,6 +1052,7 @@ compatible = "atmel,at91sam9260-pit"; reg = <0xfffffe30 0xf>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&mck>; }; watchdog@fffffe40 { @@ -705,6 +1075,8 @@ reg = <0x00500000 0x100000 0xf8030000 0x4000>; interrupts = <33 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&udphs_clk>, <&utmi>; + clock-names = "pclk", "hclk"; status = "disabled"; ep0 { @@ -817,6 +1189,9 @@ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; reg = <0x00600000 0x100000>; interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>, + <&uhpck>; + clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck"; status = "disabled"; }; @@ -824,6 +1199,8 @@ compatible = "atmel,at91sam9g45-ehci", "usb-ehci"; reg = <0x00700000 0x100000>; interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&usb>, <&uhphs_clk>, <&uhpck>; + clock-names = "usb_clk", "ehci_clk", "uhpck"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sama5d3_can.dtsi b/arch/arm/boot/dts/sama5d3_can.dtsi index 8ed3260..a077585 100644 --- a/arch/arm/boot/dts/sama5d3_can.dtsi +++ b/arch/arm/boot/dts/sama5d3_can.dtsi @@ -32,12 +32,30 @@ }; + pmc: pmc@fffffc00 { + periphck { + can0_clk: can0_clk { + #clock-cells = <0>; + reg = <40>; + atmel,clk-output-range = <0 66000000>; + }; + + can1_clk: can0_clk { + #clock-cells = <0>; + reg = <41>; + atmel,clk-output-range = <0 66000000>; + }; + }; + }; + can0: can@f000c000 { compatible = "atmel,at91sam9x5-can"; reg = <0xf000c000 0x300>; interrupts = <40 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_can0_rx_tx>; + clocks = <&can0_clk>; + clock-names = "can_clk"; status = "disabled"; }; @@ -47,6 +65,8 @@ interrupts = <41 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_can1_rx_tx>; + clocks = <&can1_clk>; + clock-names = "can_clk"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sama5d3_emac.dtsi b/arch/arm/boot/dts/sama5d3_emac.dtsi index 4d4f351..fe2af92 100644 --- a/arch/arm/boot/dts/sama5d3_emac.dtsi +++ b/arch/arm/boot/dts/sama5d3_emac.dtsi @@ -31,12 +31,23 @@ }; }; + pmc: pmc@fffffc00 { + periphck { + macb1_clk: macb1_clk { + #clock-cells = <0>; + reg = <35>; + }; + }; + }; + macb1: ethernet@f802c000 { compatible = "cdns,at32ap7000-macb", "cdns,macb"; reg = <0xf802c000 0x100>; interrupts = <35 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_macb1_rmii>; + clocks = <&macb1_clk>, <&macb1_clk>; + clock-names = "hclk", "pclk"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sama5d3_gmac.dtsi b/arch/arm/boot/dts/sama5d3_gmac.dtsi index 0ba8be3..a6cb050 100644 --- a/arch/arm/boot/dts/sama5d3_gmac.dtsi +++ b/arch/arm/boot/dts/sama5d3_gmac.dtsi @@ -64,12 +64,23 @@ }; }; + pmc: pmc@fffffc00 { + periphck { + macb0_clk: macb0_clk { + #clock-cells = <0>; + reg = <34>; + }; + }; + }; + macb0: ethernet@f0028000 { compatible = "cdns,pc302-gem", "cdns,gem"; reg = <0xf0028000 0x100>; interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_macb0_data_rgmii &pinctrl_macb0_signal_rgmii>; + clocks = <&macb0_clk>, <&macb0_clk>; + clock-names = "hclk", "pclk"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi index 01f52a7..85d3027 100644 --- a/arch/arm/boot/dts/sama5d3_lcd.dtsi +++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi @@ -50,6 +50,23 @@ }; }; }; + + pmc: pmc@fffffc00 { + periphck { + lcdc_clk: lcdc_clk { + #clock-cells = <0>; + reg = <36>; + }; + }; + + systemck { + lcdck: lcdck { + #clock-cells = <0>; + reg = <3>; + clocks = <&mck>; + }; + }; + }; }; }; }; diff --git a/arch/arm/boot/dts/sama5d3_mci2.dtsi b/arch/arm/boot/dts/sama5d3_mci2.dtsi index 38e88e3..b029fe7 100644 --- a/arch/arm/boot/dts/sama5d3_mci2.dtsi +++ b/arch/arm/boot/dts/sama5d3_mci2.dtsi @@ -9,6 +9,7 @@ #include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/clk/at91.h> / { ahb { @@ -30,6 +31,15 @@ }; }; + pmc: pmc@fffffc00 { + periphck { + mci2_clk: mci2_clk { + #clock-cells = <0>; + reg = <23>; + }; + }; + }; + mmc2: mmc@f8004000 { compatible = "atmel,hsmci"; reg = <0xf8004000 0x600>; @@ -38,6 +48,8 @@ dma-names = "rxtx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_mmc2_clk_cmd_dat0 &pinctrl_mmc2_dat1_3>; + clocks = <&mci2_clk>; + clock-names = "mci_clk"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi index 5264bb4..382b044 100644 --- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi +++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi @@ -9,6 +9,7 @@ #include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/clk/at91.h> / { aliases { @@ -17,10 +18,21 @@ ahb { apb { + pmc: pmc@fffffc00 { + periphck { + tcb1_clk: tcb1_clk { + #clock-cells = <0>; + reg = <27>; + }; + }; + }; + tcb1: timer@f8014000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8014000 0x100>; interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tcb1_clk>; + clock-names = "t0_clk"; }; }; }; diff --git a/arch/arm/boot/dts/sama5d3_uart.dtsi b/arch/arm/boot/dts/sama5d3_uart.dtsi index 98fcb2d..49d4d76 100644 --- a/arch/arm/boot/dts/sama5d3_uart.dtsi +++ b/arch/arm/boot/dts/sama5d3_uart.dtsi @@ -9,6 +9,7 @@ #include <dt-bindings/pinctrl/at91.h> #include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/clk/at91.h> / { ahb { @@ -31,12 +32,30 @@ }; }; + pmc: pmc@fffffc00 { + periphck { + uart0_clk: uart0_clk { + #clock-cells = <0>; + reg = <16>; + atmel,clk-output-range = <0 66000000>; + }; + + uart1_clk: uart1_clk { + #clock-cells = <0>; + reg = <17>; + atmel,clk-output-range = <0 66000000>; + }; + }; + }; + uart0: serial@f0024000 { compatible = "atmel,at91sam9260-usart"; reg = <0xf0024000 0x200>; interrupts = <16 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart0>; + clocks = <&uart0_clk>; + clock-names = "usart"; status = "disabled"; }; @@ -46,6 +65,8 @@ interrupts = <17 IRQ_TYPE_LEVEL_HIGH 5>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; + clocks = <&uart1_clk>; + clock-names = "usart"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi index 726a0f3..f55ed07 100644 --- a/arch/arm/boot/dts/sama5d3xcm.dtsi +++ b/arch/arm/boot/dts/sama5d3xcm.dtsi @@ -18,17 +18,6 @@ reg = <0x20000000 0x20000000>; }; - clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - }; - ahb { apb { spi0: spi@f0004000 { @@ -38,6 +27,12 @@ macb0: ethernet@f0028000 { phy-mode = "rgmii"; }; + + pmc: pmc@fffffc00 { + main: mainck { + clock-frequency = <12000000>; + }; + }; }; nand0: nand@60000000 { diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 6d09b8d..f936476 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -245,14 +245,14 @@ mpu_periph_clk: mpu_periph_clk { #clock-cells = <0>; - compatible = "altr,socfpga-gate-clk"; + compatible = "altr,socfpga-perip-clk"; clocks = <&mpuclk>; fixed-divider = <4>; }; mpu_l2_ram_clk: mpu_l2_ram_clk { #clock-cells = <0>; - compatible = "altr,socfpga-gate-clk"; + compatible = "altr,socfpga-perip-clk"; clocks = <&mpuclk>; fixed-divider = <2>; }; @@ -266,8 +266,9 @@ l3_main_clk: l3_main_clk { #clock-cells = <0>; - compatible = "altr,socfpga-gate-clk"; + compatible = "altr,socfpga-perip-clk"; clocks = <&mainclk>; + fixed-divider = <1>; }; l3_mp_clk: l3_mp_clk { diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 690e892..0b4e9b5 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -22,7 +22,6 @@ CONFIG_SOC_AT91SAM9X5=y CONFIG_SOC_AT91SAM9N12=y CONFIG_MACH_AT91RM9200_DT=y CONFIG_MACH_AT91SAM9_DT=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y CONFIG_AT91_TIMER_HZ=128 CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig index 75502c4..bf05771 100644 --- a/arch/arm/configs/at91rm9200_defconfig +++ b/arch/arm/configs/at91rm9200_defconfig @@ -31,7 +31,6 @@ CONFIG_MACH_YL9200=y CONFIG_MACH_CPUAT91=y CONFIG_MACH_ECO920=y CONFIG_MTD_AT91_DATAFLASH_CARD=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y CONFIG_AT91_TIMER_HZ=100 # CONFIG_ARM_THUMB is not set CONFIG_PCCARD=y diff --git a/arch/arm/configs/at91sam9260_9g20_defconfig b/arch/arm/configs/at91sam9260_9g20_defconfig index 69b6928..955dc480 100644 --- a/arch/arm/configs/at91sam9260_9g20_defconfig +++ b/arch/arm/configs/at91sam9260_9g20_defconfig @@ -28,7 +28,6 @@ CONFIG_MACH_PCONTROL_G20=y CONFIG_MACH_GSIA18S=y CONFIG_MACH_SNAPPER_9260=y CONFIG_MACH_AT91SAM9_DT=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y CONFIG_AT91_SLOW_CLOCK=y # CONFIG_ARM_THUMB is not set CONFIG_AEABI=y diff --git a/arch/arm/configs/at91sam9261_9g10_defconfig b/arch/arm/configs/at91sam9261_9g10_defconfig index 9d35cd8..f80e993 100644 --- a/arch/arm/configs/at91sam9261_9g10_defconfig +++ b/arch/arm/configs/at91sam9261_9g10_defconfig @@ -18,7 +18,6 @@ CONFIG_ARCH_AT91=y CONFIG_ARCH_AT91SAM9261=y CONFIG_MACH_AT91SAM9261EK=y CONFIG_MACH_AT91SAM9G10EK=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y # CONFIG_ARM_THUMB is not set CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set diff --git a/arch/arm/configs/at91sam9g45_defconfig b/arch/arm/configs/at91sam9g45_defconfig index 08166cd..e181a50 100644 --- a/arch/arm/configs/at91sam9g45_defconfig +++ b/arch/arm/configs/at91sam9g45_defconfig @@ -18,7 +18,6 @@ CONFIG_ARCH_AT91=y CONFIG_ARCH_AT91SAM9G45=y CONFIG_MACH_AT91SAM9M10G45EK=y CONFIG_MACH_AT91SAM9_DT=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y CONFIG_AT91_SLOW_CLOCK=y CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig index 7cf8785..7b6f131 100644 --- a/arch/arm/configs/at91sam9rl_defconfig +++ b/arch/arm/configs/at91sam9rl_defconfig @@ -13,7 +13,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_ARCH_AT91=y CONFIG_ARCH_AT91SAM9RL=y CONFIG_MACH_AT91SAM9RLEK=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y # CONFIG_ARM_THUMB is not set CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 4a5903e..c1df4e9 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -69,6 +69,7 @@ CONFIG_KS8851=y CONFIG_SMSC911X=y CONFIG_STMMAC_ETH=y CONFIG_MDIO_SUN4I=y +CONFIG_TI_CPSW=y CONFIG_KEYBOARD_SPEAR=y CONFIG_SERIO_AMBAKMI=y CONFIG_SERIAL_8250=y @@ -133,12 +134,14 @@ CONFIG_USB_GPIO_VBUS=y CONFIG_USB_ISP1301=y CONFIG_USB_MXS_PHY=y CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_MMC_SDHCI_TEGRA=y CONFIG_MMC_SDHCI_SPEAR=y +CONFIG_MMC_SDHCI_BCM_KONA=y CONFIG_MMC_OMAP=y CONFIG_MMC_OMAP_HS=y CONFIG_EDAC=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 98a50c3..bfa80a1 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -173,6 +173,7 @@ CONFIG_MFD_PALMAS=y CONFIG_MFD_TPS65217=y CONFIG_MFD_TPS65910=y CONFIG_TWL6040_CORE=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PALMAS=y CONFIG_REGULATOR_TPS65023=y CONFIG_REGULATOR_TPS6507X=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index f6e78f8..dc3881e 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -20,7 +20,6 @@ CONFIG_ARCH_AT91=y CONFIG_SOC_SAM_V7=y CONFIG_SOC_SAMA5D3=y CONFIG_MACH_SAMA5_DT=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set CONFIG_UACCESS_WITH_MEMCPY=y diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index d57a85b..3e2259b 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -12,6 +12,9 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set @@ -58,4 +61,8 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y CONFIG_NLS=y +CONFIG_PRINTK_TIME=y diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index ac632cc..c6ebc18 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -22,6 +22,7 @@ CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8" CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_IDLE=y +CONFIG_ARM_U8500_CPUIDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_PM_RUNTIME=y @@ -109,6 +110,8 @@ CONFIG_EXT2_FS_SECURITY=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y CONFIG_VFAT_FS=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y # CONFIG_MISC_FILESYSTEMS is not set diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 699b71e..f1bf952 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -1,15 +1,33 @@ if ARCH_AT91 +config HAVE_AT91_UTMI + bool + +config HAVE_AT91_USB_CLK + bool + config HAVE_AT91_DBGU0 bool config HAVE_AT91_DBGU1 bool +config AT91_USE_OLD_CLK + bool + config AT91_PMC_UNIT bool default !ARCH_AT91X40 +config COMMON_CLK_AT91 + bool + default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK + select COMMON_CLK + +config OLD_CLK_AT91 + bool + default AT91_PMC_UNIT && AT91_USE_OLD_CLK + config AT91_SAM9_ALT_RESET bool default !ARCH_AT91X40 @@ -21,6 +39,9 @@ config AT91_SAM9G45_RESET config AT91_SAM9_TIME bool +config HAVE_AT91_SMD + bool + config SOC_AT91SAM9 bool select AT91_SAM9_TIME @@ -61,10 +82,12 @@ comment "Atmel AT91 Processor" if SOC_SAM_V7 config SOC_SAMA5D3 bool "SAMA5D3 family" - depends on SOC_SAM_V7 select SOC_SAMA5 select HAVE_FB_ATMEL select HAVE_AT91_DBGU1 + select HAVE_AT91_UTMI + select HAVE_AT91_SMD + select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's SAMA5D3 family SoC. This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35. @@ -78,11 +101,15 @@ config SOC_AT91RM9200 select HAVE_AT91_DBGU0 select MULTI_IRQ_HANDLER select SPARSE_IRQ + select AT91_USE_OLD_CLK + select HAVE_AT91_USB_CLK config SOC_AT91SAM9260 bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20" select HAVE_AT91_DBGU0 select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE or AT91SAM9G20 SoC. @@ -92,6 +119,8 @@ config SOC_AT91SAM9261 select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC. @@ -100,18 +129,25 @@ config SOC_AT91SAM9263 select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_USB_CLK config SOC_AT91SAM9RL bool "AT91SAM9RL" select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI config SOC_AT91SAM9G45 bool "AT91SAM9G45 or AT91SAM9M10 families" select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI + select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's AT91SAM9G45 family SoC. This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. @@ -121,6 +157,10 @@ config SOC_AT91SAM9X5 select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_UTMI + select HAVE_AT91_SMD + select HAVE_AT91_USB_CLK help Select this if you are using one of Atmel's AT91SAM9x5 family SoC. This means that your SAM9 name finishes with a '5' (except if it is @@ -133,6 +173,8 @@ config SOC_AT91SAM9N12 select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select SOC_AT91SAM9 + select AT91_USE_OLD_CLK + select HAVE_AT91_USB_CLK help Select this if you are using Atmel's AT91SAM9N12 SoC. @@ -172,12 +214,6 @@ config MACH_SAMA5_DT comment "AT91 Feature Selections" -config AT91_PROGRAMMABLE_CLOCKS - bool "Programmable Clocks" - help - Select this if you need to program one or more of the PCK0..PCK3 - programmable clock outputs. - config AT91_SLOW_CLOCK bool "Suspend-to-RAM disables main oscillator" depends on SUSPEND diff --git a/arch/arm/mach-at91/Kconfig.non_dt b/arch/arm/mach-at91/Kconfig.non_dt index ca900be..b736b57 100644 --- a/arch/arm/mach-at91/Kconfig.non_dt +++ b/arch/arm/mach-at91/Kconfig.non_dt @@ -12,26 +12,32 @@ config ARCH_AT91_NONE config ARCH_AT91RM9200 bool "AT91RM9200" select SOC_AT91RM9200 + select AT91_USE_OLD_CLK config ARCH_AT91SAM9260 bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20" select SOC_AT91SAM9260 + select AT91_USE_OLD_CLK config ARCH_AT91SAM9261 bool "AT91SAM9261 or AT91SAM9G10" select SOC_AT91SAM9261 + select AT91_USE_OLD_CLK config ARCH_AT91SAM9263 bool "AT91SAM9263" select SOC_AT91SAM9263 + select AT91_USE_OLD_CLK config ARCH_AT91SAM9RL bool "AT91SAM9RL" select SOC_AT91SAM9RL + select AT91_USE_OLD_CLK config ARCH_AT91SAM9G45 bool "AT91SAM9G45" select SOC_AT91SAM9G45 + select AT91_USE_OLD_CLK config ARCH_AT91X40 bool "AT91x40" diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 90aab2d..705b38a 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -7,7 +7,7 @@ obj-m := obj-n := obj- := -obj-$(CONFIG_AT91_PMC_UNIT) += clock.o +obj-$(CONFIG_OLD_CLK_AT91) += clock.o obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o obj-$(CONFIG_AT91_SAM9_TIME) += at91sam926x_time.o diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 25805f2..e47f5fd 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -12,13 +12,13 @@ #include <linux/module.h> #include <linux/reboot.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/system_misc.h> #include <mach/at91rm9200.h> -#include <mach/at91_pmc.h> #include <mach/at91_st.h> #include <mach/cpu.h> diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index d6a1fa8..6c821e5 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> #include <asm/irq.h> @@ -20,7 +21,6 @@ #include <mach/cpu.h> #include <mach/at91_dbgu.h> #include <mach/at91sam9260.h> -#include <mach/at91_pmc.h> #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 23ba1d8..6276b4c 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> #include <asm/irq.h> @@ -19,7 +20,6 @@ #include <asm/system_misc.h> #include <mach/cpu.h> #include <mach/at91sam9261.h> -#include <mach/at91_pmc.h> #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 7eccb0f..37b90f4 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> #include <asm/irq.h> @@ -18,7 +19,6 @@ #include <asm/mach/map.h> #include <asm/system_misc.h> #include <mach/at91sam9263.h> -#include <mach/at91_pmc.h> #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c index bb39232..0f04ffe 100644 --- a/arch/arm/mach-at91/at91sam926x_time.c +++ b/arch/arm/mach-at91/at91sam926x_time.c @@ -39,6 +39,7 @@ static u32 pit_cycle; /* write-once */ static u32 pit_cnt; /* access only w/system irq blocked */ static void __iomem *pit_base_addr __read_mostly; +static struct clk *mck; static inline unsigned int pit_read(unsigned int reg_offset) { @@ -195,10 +196,14 @@ static int __init of_at91sam926x_pit_init(void) if (!pit_base_addr) goto node_err; + mck = of_clk_get(np, 0); + /* Get the interrupts property */ ret = irq_of_parse_and_map(np, 0); if (!ret) { pr_crit("AT91: PIT: Unable to get IRQ from DT\n"); + if (!IS_ERR(mck)) + clk_put(mck); goto ioremap_err; } at91sam926x_pit_irq.irq = ret; @@ -230,6 +235,8 @@ void __init at91sam926x_pit_init(void) unsigned bits; int ret; + mck = ERR_PTR(-ENOENT); + /* For device tree enabled device: initialize here */ of_at91sam926x_pit_init(); @@ -237,7 +244,12 @@ void __init at91sam926x_pit_init(void) * Use our actual MCK to figure out how many MCK/16 ticks per * 1/HZ period (instead of a compile-time constant LATCH). */ - pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16; + if (IS_ERR(mck)) + mck = clk_get(NULL, "mck"); + + if (IS_ERR(mck)) + panic("AT91: PIT: Unable to get mck clk\n"); + pit_rate = clk_get_rate(mck) / 16; pit_cycle = (pit_rate + HZ/2) / HZ; WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0); diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 9405aa0..2f455ce 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -12,13 +12,13 @@ #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/system_misc.h> #include <mach/at91sam9g45.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include "at91_aic.h" diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index 388ec3a..4ef088c 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c @@ -8,12 +8,12 @@ #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <mach/at91sam9n12.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include "board.h" diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 0750ffb..3651517 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -10,6 +10,7 @@ */ #include <linux/module.h> +#include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> #include <asm/irq.h> @@ -19,7 +20,6 @@ #include <mach/cpu.h> #include <mach/at91_dbgu.h> #include <mach/at91sam9rl.h> -#include <mach/at91_pmc.h> #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index e8a2e07..3e8ec26 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -8,12 +8,12 @@ #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <mach/at91sam9x5.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include "board.h" diff --git a/arch/arm/mach-at91/board-dt-sama5.c b/arch/arm/mach-at91/board-dt-sama5.c index bf00d15..075ec05 100644 --- a/arch/arm/mach-at91/board-dt-sama5.c +++ b/arch/arm/mach-at91/board-dt-sama5.c @@ -16,6 +16,7 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/phy.h> +#include <linux/clk-provider.h> #include <asm/setup.h> #include <asm/irq.h> @@ -26,6 +27,13 @@ #include "at91_aic.h" #include "generic.h" +static void __init sama5_dt_timer_init(void) +{ +#if defined(CONFIG_COMMON_CLK) + of_clk_init(NULL); +#endif + at91sam926x_pit_init(); +} static const struct of_device_id irq_of_match[] __initconst = { @@ -72,7 +80,7 @@ static const char *sama5_dt_board_compat[] __initdata = { DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = sama5_dt_timer_init, .map_io = at91_map_io, .handle_irq = at91_aic5_handle_irq, .init_early = at91_dt_initialize, diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 6b2630a..034529d 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -24,9 +24,9 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/of_address.h> +#include <linux/clk/at91_pmc.h> #include <mach/hardware.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include <asm/proc-fns.h> @@ -330,8 +330,6 @@ EXPORT_SYMBOL(clk_get_rate); /*------------------------------------------------------------------------*/ -#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS - /* * For now, only the programmable clocks support reparenting (MCK could * do this too, with care) or rate changing (the PLLs could do this too, @@ -459,8 +457,6 @@ static void __init init_programmable_clock(struct clk *clk) clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr); } -#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ - /*------------------------------------------------------------------------*/ #ifdef CONFIG_DEBUG_FS @@ -577,12 +573,10 @@ int __init clk_register(struct clk *clk) clk->parent = &mck; clk->mode = pmc_sys_mode; } -#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS else if (clk_is_programmable(clk)) { clk->mode = pmc_sys_mode; init_programmable_clock(clk); } -#endif at91_clk_add(clk); @@ -884,6 +878,11 @@ static int __init at91_pmc_init(unsigned long main_clock) #if defined(CONFIG_OF) static struct of_device_id pmc_ids[] = { { .compatible = "atmel,at91rm9200-pmc" }, + { .compatible = "atmel,at91sam9260-pmc" }, + { .compatible = "atmel,at91sam9g45-pmc" }, + { .compatible = "atmel,at91sam9n12-pmc" }, + { .compatible = "atmel,at91sam9x5-pmc" }, + { .compatible = "atmel,sama5d3-pmc" }, { /*sentinel*/ } }; diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 26dee3c..631fa3b 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -46,11 +46,12 @@ extern void at91sam926x_pit_init(void); extern void at91x40_timer_init(void); /* Clocks */ -#ifdef CONFIG_AT91_PMC_UNIT +#ifdef CONFIG_OLD_CLK_AT91 extern int __init at91_clock_init(unsigned long main_clock); extern int __init at91_dt_clock_init(void); #else static int inline at91_clock_init(unsigned long main_clock) { return 0; } +static int inline at91_dt_clock_init(void) { return 0; } #endif struct device; diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 9986542..590b52d 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -19,13 +19,13 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <linux/atomic.h> #include <asm/mach/time.h> #include <asm/mach/irq.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include "at91_aic.h" @@ -155,9 +155,6 @@ static int at91_pm_verify_clocks(void) } } - if (!IS_ENABLED(CONFIG_AT91_PROGRAMMABLE_CLOCKS)) - return 1; - /* PCK0..PCK3 must be disabled, or configured to use clk32k */ for (i = 0; i < 4; i++) { u32 css; diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 3ed190c..c5101dc 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -16,7 +16,11 @@ #include <mach/at91_ramc.h> #include <mach/at91rm9200_sdramc.h> +#ifdef CONFIG_PM extern void at91_pm_set_standby(void (*at91_standby)(void)); +#else +static inline void at91_pm_set_standby(void (*at91_standby)(void)) { } +#endif /* * The AT91RM9200 goes into self-refresh mode with this command, and will diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S index 098c28d..2001877 100644 --- a/arch/arm/mach-at91/pm_slowclock.S +++ b/arch/arm/mach-at91/pm_slowclock.S @@ -13,8 +13,8 @@ */ #include <linux/linkage.h> +#include <linux/clk/at91_pmc.h> #include <mach/hardware.h> -#include <mach/at91_pmc.h> #include <mach/at91_ramc.h> diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c index 3ea8642..3d775d0 100644 --- a/arch/arm/mach-at91/sama5d3.c +++ b/arch/arm/mach-at91/sama5d3.c @@ -9,360 +9,19 @@ #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/clk/at91_pmc.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <mach/sama5d3.h> -#include <mach/at91_pmc.h> #include <mach/cpu.h> #include "soc.h" #include "generic.h" -#include "clock.h" #include "sam9_smc.h" /* -------------------------------------------------------------------- - * Clocks - * -------------------------------------------------------------------- */ - -/* - * The peripheral clocks. - */ - -static struct clk pioA_clk = { - .name = "pioA_clk", - .pid = SAMA5D3_ID_PIOA, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk pioB_clk = { - .name = "pioB_clk", - .pid = SAMA5D3_ID_PIOB, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk pioC_clk = { - .name = "pioC_clk", - .pid = SAMA5D3_ID_PIOC, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk pioD_clk = { - .name = "pioD_clk", - .pid = SAMA5D3_ID_PIOD, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk pioE_clk = { - .name = "pioE_clk", - .pid = SAMA5D3_ID_PIOE, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk usart0_clk = { - .name = "usart0_clk", - .pid = SAMA5D3_ID_USART0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk usart1_clk = { - .name = "usart1_clk", - .pid = SAMA5D3_ID_USART1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk usart2_clk = { - .name = "usart2_clk", - .pid = SAMA5D3_ID_USART2, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk usart3_clk = { - .name = "usart3_clk", - .pid = SAMA5D3_ID_USART3, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk uart0_clk = { - .name = "uart0_clk", - .pid = SAMA5D3_ID_UART0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk uart1_clk = { - .name = "uart1_clk", - .pid = SAMA5D3_ID_UART1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk twi0_clk = { - .name = "twi0_clk", - .pid = SAMA5D3_ID_TWI0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk twi1_clk = { - .name = "twi1_clk", - .pid = SAMA5D3_ID_TWI1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk twi2_clk = { - .name = "twi2_clk", - .pid = SAMA5D3_ID_TWI2, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk mmc0_clk = { - .name = "mci0_clk", - .pid = SAMA5D3_ID_HSMCI0, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk mmc1_clk = { - .name = "mci1_clk", - .pid = SAMA5D3_ID_HSMCI1, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk mmc2_clk = { - .name = "mci2_clk", - .pid = SAMA5D3_ID_HSMCI2, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk spi0_clk = { - .name = "spi0_clk", - .pid = SAMA5D3_ID_SPI0, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk spi1_clk = { - .name = "spi1_clk", - .pid = SAMA5D3_ID_SPI1, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk tcb0_clk = { - .name = "tcb0_clk", - .pid = SAMA5D3_ID_TC0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk tcb1_clk = { - .name = "tcb1_clk", - .pid = SAMA5D3_ID_TC1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk adc_clk = { - .name = "adc_clk", - .pid = SAMA5D3_ID_ADC, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk adc_op_clk = { - .name = "adc_op_clk", - .type = CLK_TYPE_PERIPHERAL, - .rate_hz = 5000000, -}; -static struct clk dma0_clk = { - .name = "dma0_clk", - .pid = SAMA5D3_ID_DMA0, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk dma1_clk = { - .name = "dma1_clk", - .pid = SAMA5D3_ID_DMA1, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk uhphs_clk = { - .name = "uhphs", - .pid = SAMA5D3_ID_UHPHS, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk udphs_clk = { - .name = "udphs_clk", - .pid = SAMA5D3_ID_UDPHS, - .type = CLK_TYPE_PERIPHERAL, -}; -/* gmac only for sama5d33, sama5d34, sama5d35 */ -static struct clk macb0_clk = { - .name = "macb0_clk", - .pid = SAMA5D3_ID_GMAC, - .type = CLK_TYPE_PERIPHERAL, -}; -/* emac only for sama5d31, sama5d35 */ -static struct clk macb1_clk = { - .name = "macb1_clk", - .pid = SAMA5D3_ID_EMAC, - .type = CLK_TYPE_PERIPHERAL, -}; -/* lcd only for sama5d31, sama5d33, sama5d34 */ -static struct clk lcdc_clk = { - .name = "lcdc_clk", - .pid = SAMA5D3_ID_LCDC, - .type = CLK_TYPE_PERIPHERAL, -}; -/* isi only for sama5d33, sama5d35 */ -static struct clk isi_clk = { - .name = "isi_clk", - .pid = SAMA5D3_ID_ISI, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk can0_clk = { - .name = "can0_clk", - .pid = SAMA5D3_ID_CAN0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk can1_clk = { - .name = "can1_clk", - .pid = SAMA5D3_ID_CAN1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk ssc0_clk = { - .name = "ssc0_clk", - .pid = SAMA5D3_ID_SSC0, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk ssc1_clk = { - .name = "ssc1_clk", - .pid = SAMA5D3_ID_SSC1, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV2, -}; -static struct clk sha_clk = { - .name = "sha_clk", - .pid = SAMA5D3_ID_SHA, - .type = CLK_TYPE_PERIPHERAL, - .div = AT91_PMC_PCR_DIV8, -}; -static struct clk aes_clk = { - .name = "aes_clk", - .pid = SAMA5D3_ID_AES, - .type = CLK_TYPE_PERIPHERAL, -}; -static struct clk tdes_clk = { - .name = "tdes_clk", - .pid = SAMA5D3_ID_TDES, - .type = CLK_TYPE_PERIPHERAL, -}; - -static struct clk *periph_clocks[] __initdata = { - &pioA_clk, - &pioB_clk, - &pioC_clk, - &pioD_clk, - &pioE_clk, - &usart0_clk, - &usart1_clk, - &usart2_clk, - &usart3_clk, - &uart0_clk, - &uart1_clk, - &twi0_clk, - &twi1_clk, - &twi2_clk, - &mmc0_clk, - &mmc1_clk, - &mmc2_clk, - &spi0_clk, - &spi1_clk, - &tcb0_clk, - &tcb1_clk, - &adc_clk, - &adc_op_clk, - &dma0_clk, - &dma1_clk, - &uhphs_clk, - &udphs_clk, - &macb0_clk, - &macb1_clk, - &lcdc_clk, - &isi_clk, - &can0_clk, - &can1_clk, - &ssc0_clk, - &ssc1_clk, - &sha_clk, - &aes_clk, - &tdes_clk, -}; - -static struct clk pck0 = { - .name = "pck0", - .pmc_mask = AT91_PMC_PCK0, - .type = CLK_TYPE_PROGRAMMABLE, - .id = 0, -}; - -static struct clk pck1 = { - .name = "pck1", - .pmc_mask = AT91_PMC_PCK1, - .type = CLK_TYPE_PROGRAMMABLE, - .id = 1, -}; - -static struct clk pck2 = { - .name = "pck2", - .pmc_mask = AT91_PMC_PCK2, - .type = CLK_TYPE_PROGRAMMABLE, - .id = 2, -}; - -static struct clk_lookup periph_clocks_lookups[] = { - /* lookup table for DT entries */ - CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), - CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk), - CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk), - CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk), - CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioD_clk), - CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioE_clk), - CLKDEV_CON_DEV_ID("usart", "f001c000.serial", &usart0_clk), - CLKDEV_CON_DEV_ID("usart", "f0020000.serial", &usart1_clk), - CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart2_clk), - CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart3_clk), - CLKDEV_CON_DEV_ID(NULL, "f0014000.i2c", &twi0_clk), - CLKDEV_CON_DEV_ID(NULL, "f0018000.i2c", &twi1_clk), - CLKDEV_CON_DEV_ID(NULL, "f801c000.i2c", &twi2_clk), - CLKDEV_CON_DEV_ID("mci_clk", "f0000000.mmc", &mmc0_clk), - CLKDEV_CON_DEV_ID("mci_clk", "f8000000.mmc", &mmc1_clk), - CLKDEV_CON_DEV_ID("mci_clk", "f8004000.mmc", &mmc2_clk), - CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi0_clk), - CLKDEV_CON_DEV_ID("spi_clk", "f8008000.spi", &spi1_clk), - CLKDEV_CON_DEV_ID("t0_clk", "f0010000.timer", &tcb0_clk), - CLKDEV_CON_DEV_ID("t0_clk", "f8014000.timer", &tcb1_clk), - CLKDEV_CON_DEV_ID("tsc_clk", "f8018000.tsadcc", &adc_clk), - CLKDEV_CON_DEV_ID("dma_clk", "ffffe600.dma-controller", &dma0_clk), - CLKDEV_CON_DEV_ID("dma_clk", "ffffe800.dma-controller", &dma1_clk), - CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk), - CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk), - CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk), - CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk), - CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk), - CLKDEV_CON_DEV_ID("hclk", "f0028000.ethernet", &macb0_clk), - CLKDEV_CON_DEV_ID("pclk", "f0028000.ethernet", &macb0_clk), - CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb1_clk), - CLKDEV_CON_DEV_ID("pclk", "f802c000.ethernet", &macb1_clk), - CLKDEV_CON_DEV_ID("pclk", "f0008000.ssc", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "f000c000.ssc", &ssc1_clk), - CLKDEV_CON_DEV_ID("can_clk", "f000c000.can", &can0_clk), - CLKDEV_CON_DEV_ID("can_clk", "f8010000.can", &can1_clk), - CLKDEV_CON_DEV_ID("sha_clk", "f8034000.sha", &sha_clk), - CLKDEV_CON_DEV_ID("aes_clk", "f8038000.aes", &aes_clk), - CLKDEV_CON_DEV_ID("tdes_clk", "f803c000.tdes", &tdes_clk), -}; - -static void __init sama5d3_register_clocks(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) - clk_register(periph_clocks[i]); - - clkdev_add_table(periph_clocks_lookups, - ARRAY_SIZE(periph_clocks_lookups)); - - clk_register(&pck0); - clk_register(&pck1); - clk_register(&pck2); -} - -/* -------------------------------------------------------------------- * AT91SAM9x5 processor initialization * -------------------------------------------------------------------- */ @@ -378,6 +37,5 @@ static void __init sama5d3_initialize(void) AT91_SOC_START(sama5d3) .map_io = sama5d3_map_io, - .register_clocks = sama5d3_register_clocks, .init = sama5d3_initialize, AT91_SOC_END diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 094b345..7d3f7cc 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -11,6 +11,7 @@ #include <linux/pm.h> #include <linux/of_address.h> #include <linux/pinctrl/machine.h> +#include <linux/clk/at91_pmc.h> #include <asm/system_misc.h> #include <asm/mach/map.h> @@ -18,7 +19,6 @@ #include <mach/hardware.h> #include <mach/cpu.h> #include <mach/at91_dbgu.h> -#include <mach/at91_pmc.h> #include "at91_shdwc.h" #include "soc.h" @@ -491,7 +491,8 @@ void __init at91rm9200_dt_initialize(void) at91_dt_clock_init(); /* Register the processor-specific clocks */ - at91_boot_soc.register_clocks(); + if (at91_boot_soc.register_clocks) + at91_boot_soc.register_clocks(); at91_boot_soc.init(); } @@ -506,7 +507,8 @@ void __init at91_dt_initialize(void) at91_dt_clock_init(); /* Register the processor-specific clocks */ - at91_boot_soc.register_clocks(); + if (at91_boot_soc.register_clocks) + at91_boot_soc.register_clocks(); if (at91_boot_soc.init) at91_boot_soc.init(); diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index c122bcf..0d1a892 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -162,7 +162,7 @@ void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) /***************************************************************************** * SoC RTC ****************************************************************************/ -void __init dove_rtc_init(void) +static void __init dove_rtc_init(void) { orion_rtc_init(DOVE_RTC_PHYS_BASE, IRQ_DOVE_RTC); } @@ -257,18 +257,9 @@ void __init dove_timer_init(void) } /***************************************************************************** - * Cryptographic Engines and Security Accelerator (CESA) - ****************************************************************************/ -void __init dove_crypto_init(void) -{ - orion_crypto_init(DOVE_CRYPT_PHYS_BASE, DOVE_CESA_PHYS_BASE, - DOVE_CESA_SIZE, IRQ_DOVE_CRYPTO); -} - -/***************************************************************************** * XOR 0 ****************************************************************************/ -void __init dove_xor0_init(void) +static void __init dove_xor0_init(void) { orion_xor0_init(DOVE_XOR0_PHYS_BASE, DOVE_XOR0_HIGH_PHYS_BASE, IRQ_DOVE_XOR_00, IRQ_DOVE_XOR_01); @@ -277,7 +268,7 @@ void __init dove_xor0_init(void) /***************************************************************************** * XOR 1 ****************************************************************************/ -void __init dove_xor1_init(void) +static void __init dove_xor1_init(void) { orion_xor1_init(DOVE_XOR1_PHYS_BASE, DOVE_XOR1_HIGH_PHYS_BASE, IRQ_DOVE_XOR_10, IRQ_DOVE_XOR_11); diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 58b43e6..ddf73bd 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -64,8 +64,7 @@ static void write_pen_release(int val) { pen_release = val; smp_wmb(); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); } static void __iomem *scu_base_addr(void) diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 1f24c1f..5b57c17 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -92,8 +92,7 @@ static void __init imx_smp_prepare_cpus(unsigned int max_cpus) * secondary cores when booting them. */ asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (g_diag_reg) : : "cc"); - __cpuc_flush_dcache_area(&g_diag_reg, sizeof(g_diag_reg)); - outer_clean_range(__pa(&g_diag_reg), __pa(&g_diag_reg + 1)); + sync_cache_w(&g_diag_reg); } struct smp_operations imx_smp_ops __initdata = { diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index 9caa4fe..7818815 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -10,55 +10,21 @@ * warranty of any kind, whether express or implied. */ +#include <linux/clk.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_net.h> #include <linux/of_platform.h> -#include <linux/clk-provider.h> #include <linux/dma-mapping.h> #include <linux/irqchip.h> #include <linux/kexec.h> #include <asm/mach/arch.h> -#include <asm/mach/map.h> #include <mach/bridge-regs.h> -#include <linux/platform_data/usb-ehci-orion.h> -#include <plat/irq.h> #include <plat/common.h> #include "common.h" -/* - * There are still devices that doesn't know about DT yet. Get clock - * gates here and add a clock lookup alias, so that old platform - * devices still work. -*/ - -static void __init kirkwood_legacy_clk_init(void) -{ - - struct device_node *np = of_find_compatible_node( - NULL, NULL, "marvell,kirkwood-gating-clock"); - struct of_phandle_args clkspec; - struct clk *clk; - - clkspec.np = np; - clkspec.args_count = 1; - - /* - * The ethernet interfaces forget the MAC address assigned by - * u-boot if the clocks are turned off. Until proper DT support - * is available we always enable them for now. - */ - clkspec.args[0] = CGC_BIT_GE0; - clk = of_clk_get_from_provider(&clkspec); - clk_prepare_enable(clk); - - clkspec.args[0] = CGC_BIT_GE1; - clk = of_clk_get_from_provider(&clkspec); - clk_prepare_enable(clk); -} - #define MV643XX_ETH_MAC_ADDR_LOW 0x0414 #define MV643XX_ETH_MAC_ADDR_HIGH 0x0418 @@ -140,7 +106,7 @@ eth_fixup_skip: static void __init kirkwood_dt_init(void) { - pr_info("Kirkwood: %s, TCLK=%d.\n", kirkwood_id(), kirkwood_tclk); + pr_info("Kirkwood: %s.\n", kirkwood_id()); /* * Disable propagation of mbus errors to the CPU local bus, @@ -156,8 +122,6 @@ static void __init kirkwood_dt_init(void) kirkwood_cpufreq_init(); kirkwood_cpuidle_init(); - /* Setup clocks for legacy devices */ - kirkwood_legacy_clk_init(); kirkwood_pm_init(); kirkwood_dt_eth_fixup(); diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig index ebdda83..ebdba87 100644 --- a/arch/arm/mach-mmp/Kconfig +++ b/arch/arm/mach-mmp/Kconfig @@ -136,4 +136,7 @@ config USB_EHCI_MV_U2O help Enables support for OTG controller which can be switched to host mode. +config MMP_SRAM + bool + endif diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile index 9b702a1..98f0f63 100644 --- a/arch/arm/mach-mmp/Makefile +++ b/arch/arm/mach-mmp/Makefile @@ -7,7 +7,8 @@ obj-y += common.o devices.o time.o # SoC support obj-$(CONFIG_CPU_PXA168) += pxa168.o obj-$(CONFIG_CPU_PXA910) += pxa910.o -obj-$(CONFIG_CPU_MMP2) += mmp2.o sram.o +obj-$(CONFIG_CPU_MMP2) += mmp2.o +obj-$(CONFIG_MMP_SRAM) += sram.o ifeq ($(CONFIG_COMMON_CLK), ) obj-y += clock.o diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 3f06edc..f10a1f5 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -99,8 +99,7 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) * "cpu" is Linux's internal ID. */ pen_release = cpu_logical_map(cpu); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); /* * Send the secondary CPU a soft interrupt, thereby causing diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 58adf2f..4e9d581 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -27,6 +27,7 @@ #include <asm/smp_plat.h> #include <asm/cacheflush.h> #include "armada-370-xp.h" +#include "coherency.h" unsigned long coherency_phys_base; static void __iomem *coherency_base; diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h index df33ad8..760226c 100644 --- a/arch/arm/mach-mvebu/coherency.h +++ b/arch/arm/mach-mvebu/coherency.h @@ -14,7 +14,9 @@ #ifndef __MACH_370_XP_COHERENCY_H #define __MACH_370_XP_COHERENCY_H -int set_cpu_coherent(int cpu_id, int smp_group_id); +extern unsigned long coherency_phys_base; + +int set_cpu_coherent(unsigned int cpu_id, int smp_group_id); int coherency_init(void); #endif /* __MACH_370_XP_COHERENCY_H */ diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index e366010..0e6016f 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -26,7 +26,6 @@ void armada_370_xp_handle_irq(struct pt_regs *regs); void armada_xp_cpu_die(unsigned int cpu); int armada_370_xp_coherency_init(void); -int armada_370_xp_pmsu_init(void); void armada_xp_secondary_startup(void); extern struct smp_operations armada_xp_smp_ops; #endif diff --git a/arch/arm/mach-mvebu/hotplug.c b/arch/arm/mach-mvebu/hotplug.c index b228b6a..d95e910 100644 --- a/arch/arm/mach-mvebu/hotplug.c +++ b/arch/arm/mach-mvebu/hotplug.c @@ -15,6 +15,7 @@ #include <linux/errno.h> #include <linux/smp.h> #include <asm/proc-fns.h> +#include "common.h" /* * platform-specific code to shutdown a CPU diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index ff69c2d..a6da03f 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -46,7 +46,7 @@ static struct clk *__init get_cpu_clk(int cpu) return cpu_clk; } -void __init set_secondary_cpus_clock(void) +static void __init set_secondary_cpus_clock(void) { int thiscpu, cpu; unsigned long rate; @@ -94,7 +94,7 @@ static void __init armada_xp_smp_init_cpus(void) set_smp_cross_call(armada_mpic_send_doorbell); } -void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) +static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) { struct device_node *node; struct resource res; diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 27fc4f0..d71ef53 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -22,6 +22,7 @@ #include <linux/io.h> #include <linux/smp.h> #include <asm/smp_plat.h> +#include "pmsu.h" static void __iomem *pmsu_mp_base; static void __iomem *pmsu_reset_base; @@ -58,7 +59,7 @@ int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) } #endif -int __init armada_370_xp_pmsu_init(void) +static int __init armada_370_xp_pmsu_init(void) { struct device_node *np; diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index 5175083c..a7fb89a 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -27,6 +27,7 @@ #include <linux/of_address.h> #include <linux/io.h> #include <linux/reboot.h> +#include "common.h" static void __iomem *system_controller_base; @@ -39,14 +40,14 @@ struct mvebu_system_controller { }; static struct mvebu_system_controller *mvebu_sc; -const struct mvebu_system_controller armada_370_xp_system_controller = { +static const struct mvebu_system_controller armada_370_xp_system_controller = { .rstoutn_mask_offset = 0x60, .system_soft_reset_offset = 0x64, .rstoutn_mask_reset_out_en = 0x1, .system_soft_reset = 0x1, }; -const struct mvebu_system_controller orion_system_controller = { +static const struct mvebu_system_controller orion_system_controller = { .rstoutn_mask_offset = 0x108, .system_soft_reset_offset = 0x10c, .rstoutn_mask_reset_out_en = 0x4, diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1f25f3e..adcef40 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -19,11 +19,11 @@ secure-common = omap-smc.o omap-secure.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common) -obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common) +obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common) $(secure-common) obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common) -obj-$(CONFIG_SOC_OMAP5) += prm44xx.o $(hwmod-common) $(secure-common) +obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common) obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common) -obj-$(CONFIG_SOC_DRA7XX) += prm44xx.o $(hwmod-common) $(secure-common) +obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common) ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),) obj-y += mcbsp.o diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index f7644fe..e30ef67 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -299,7 +299,6 @@ struct omap_sdrc_params; extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, struct omap_sdrc_params *sdrc_cs1); struct omap2_hsmmc_info; -extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers); extern void omap_reserve(void); struct omap_hwmod; diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index a4e536b..58347bb 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -32,7 +32,6 @@ #include "soc.h" #include "iomap.h" -#include "mux.h" #include "control.h" #include "display.h" #include "prm.h" @@ -102,90 +101,13 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = { { "dss_hdmi", "omapdss_hdmi", -1 }, }; -static void __init omap4_tpd12s015_mux_pads(void) -{ - omap_mux_init_signal("hdmi_cec", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_ddc_scl", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_ddc_sda", - OMAP_PIN_INPUT_PULLUP); -} - -static void __init omap4_hdmi_mux_pads(enum omap_hdmi_flags flags) -{ - u32 reg; - u16 control_i2c_1; - - /* - * CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and - * HDMI_DDC_SCL_PULLUPRESX (bit 24) are set to disable - * internal pull up resistor. - */ - if (flags & OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP) { - control_i2c_1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1; - reg = omap4_ctrl_pad_readl(control_i2c_1); - reg |= (OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK | - OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK); - omap4_ctrl_pad_writel(reg, control_i2c_1); - } -} - -static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) -{ - u32 enable_mask, enable_shift; - u32 pipd_mask, pipd_shift; - u32 reg; - - if (dsi_id == 0) { - enable_mask = OMAP4_DSI1_LANEENABLE_MASK; - enable_shift = OMAP4_DSI1_LANEENABLE_SHIFT; - pipd_mask = OMAP4_DSI1_PIPD_MASK; - pipd_shift = OMAP4_DSI1_PIPD_SHIFT; - } else if (dsi_id == 1) { - enable_mask = OMAP4_DSI2_LANEENABLE_MASK; - enable_shift = OMAP4_DSI2_LANEENABLE_SHIFT; - pipd_mask = OMAP4_DSI2_PIPD_MASK; - pipd_shift = OMAP4_DSI2_PIPD_SHIFT; - } else { - return -ENODEV; - } - - reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); - - reg &= ~enable_mask; - reg &= ~pipd_mask; - - reg |= (lanes << enable_shift) & enable_mask; - reg |= (lanes << pipd_shift) & pipd_mask; - - omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); - - return 0; -} - -int __init omap_hdmi_init(enum omap_hdmi_flags flags) -{ - if (cpu_is_omap44xx()) { - omap4_hdmi_mux_pads(flags); - omap4_tpd12s015_mux_pads(); - } - - return 0; -} - static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask) { - if (cpu_is_omap44xx()) - return omap4_dsi_mux_pads(dsi_id, lane_mask); - return 0; } static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask) { - if (cpu_is_omap44xx()) - omap4_dsi_mux_pads(dsi_id, 0); } static int omap_dss_set_min_bus_tput(struct device *dev, unsigned long tput) diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c index 365bfd3..dadccc9 100644 --- a/arch/arm/mach-omap2/dss-common.c +++ b/arch/arm/mach-omap2/dss-common.c @@ -223,7 +223,7 @@ void __init omap_4430sdp_display_init_of(void) static struct connector_dvi_platform_data omap3_igep2_dvi_connector_pdata = { .name = "dvi", .source = "tfp410.0", - .i2c_bus_num = 3, + .i2c_bus_num = 2, }; static struct platform_device omap3_igep2_dvi_connector_device = { diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 81de562..d24926e 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1502,6 +1502,22 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, } /* + * For some GPMC devices we still need to rely on the bootloader + * timings because the devices can be connected via FPGA. So far + * the list is smc91x on the omap2 SDP boards, and 8250 on zooms. + * REVISIT: Add timing support from slls644g.pdf and from the + * lan91c96 manual. + */ + if (of_device_is_compatible(child, "ns16550a") || + of_device_is_compatible(child, "smsc,lan91c94") || + of_device_is_compatible(child, "smsc,lan91c111")) { + dev_warn(&pdev->dev, + "%s using bootloader timings on CS%d\n", + child->name, cs); + goto no_timings; + } + + /* * FIXME: gpmc_cs_request() will map the CS to an arbitary * location in the gpmc address space. When booting with * device-tree we want the NOR flash to be mapped to the @@ -1529,6 +1545,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, gpmc_read_timings_dt(child, &gpmc_t); gpmc_cs_set_timings(cs, &gpmc_t); +no_timings: if (of_platform_device_create(child, NULL, &pdev->dev)) return 0; @@ -1541,42 +1558,6 @@ err: return ret; } -/* - * REVISIT: Add timing support from slls644g.pdf - */ -static int gpmc_probe_8250(struct platform_device *pdev, - struct device_node *child) -{ - struct resource res; - unsigned long base; - int ret, cs; - - if (of_property_read_u32(child, "reg", &cs) < 0) { - dev_err(&pdev->dev, "%s has no 'reg' property\n", - child->full_name); - return -ENODEV; - } - - if (of_address_to_resource(child, 0, &res) < 0) { - dev_err(&pdev->dev, "%s has malformed 'reg' property\n", - child->full_name); - return -ENODEV; - } - - ret = gpmc_cs_request(cs, resource_size(&res), &base); - if (ret < 0) { - dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); - return ret; - } - - if (of_platform_device_create(child, NULL, &pdev->dev)) - return 0; - - dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); - - return -ENODEV; -} - static int gpmc_probe_dt(struct platform_device *pdev) { int ret; @@ -1618,10 +1599,9 @@ static int gpmc_probe_dt(struct platform_device *pdev) else if (of_node_cmp(child->name, "onenand") == 0) ret = gpmc_probe_onenand_child(pdev, child); else if (of_node_cmp(child->name, "ethernet") == 0 || - of_node_cmp(child->name, "nor") == 0) + of_node_cmp(child->name, "nor") == 0 || + of_node_cmp(child->name, "uart") == 0) ret = gpmc_probe_generic_child(pdev, child); - else if (of_node_cmp(child->name, "8250") == 0) - ret = gpmc_probe_8250(pdev, child); if (WARN(ret < 0, "%s: probing gpmc child %s failed\n", __func__, child->full_name)) diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h index 8cc7d33..3e97c6c 100644 --- a/arch/arm/mach-omap2/omap-secure.h +++ b/arch/arm/mach-omap2/omap-secure.h @@ -76,6 +76,13 @@ static inline void omap_barrier_reserve_memblock(void) { } #endif +#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER void set_cntfreq(void); +#else +static inline void set_cntfreq(void) +{ +} +#endif + #endif /* __ASSEMBLER__ */ #endif /* OMAP_ARCH_OMAP_SECURE_H */ diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 5791143..b39efd4 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -35,7 +35,6 @@ #include "iomap.h" #include "common.h" #include "mmc.h" -#include "hsmmc.h" #include "prminst44xx.h" #include "prcm_mpu44xx.h" #include "omap4-sar-layout.h" @@ -284,59 +283,3 @@ skip_errata_init: omap_wakeupgen_init(); irqchip_init(); } - -#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) -static int omap4_twl6030_hsmmc_late_init(struct device *dev) -{ - int irq = 0; - struct platform_device *pdev = container_of(dev, - struct platform_device, dev); - struct omap_mmc_platform_data *pdata = dev->platform_data; - - /* Setting MMC1 Card detect Irq */ - if (pdev->id == 0) { - irq = twl6030_mmc_card_detect_config(); - if (irq < 0) { - dev_err(dev, "%s: Error card detect config(%d)\n", - __func__, irq); - return irq; - } - pdata->slots[0].card_detect_irq = irq; - pdata->slots[0].card_detect = twl6030_mmc_card_detect; - } - return 0; -} - -static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev) -{ - struct omap_mmc_platform_data *pdata; - - /* dev can be null if CONFIG_MMC_OMAP_HS is not set */ - if (!dev) { - pr_err("Failed %s\n", __func__); - return; - } - pdata = dev->platform_data; - pdata->init = omap4_twl6030_hsmmc_late_init; -} - -int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) -{ - struct omap2_hsmmc_info *c; - - omap_hsmmc_init(controllers); - for (c = controllers; c->mmc; c++) { - /* pdev can be null if CONFIG_MMC_OMAP_HS is not set */ - if (!c->pdev) - continue; - omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev); - } - - return 0; -} -#else -int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) -{ - return 0; -} -#endif diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 10c7145..39f020c 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -139,6 +139,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { static struct pdata_init pdata_quirks[] __initdata = { #ifdef CONFIG_ARCH_OMAP3 + { "nokia,omap3-n900", hsmmc2_internal_input_clk, }, { "nokia,omap3-n9", hsmmc2_internal_input_clk, }, { "nokia,omap3-n950", hsmmc2_internal_input_clk, }, { "isee,omap3-igep0020", omap3_igep0020_legacy_init, }, diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 93b80e5..1f3770a 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -120,7 +120,7 @@ static void omap3_save_secure_ram_context(void) * will hang the system. */ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); - ret = _omap_save_secure_sram((u32 *) + ret = _omap_save_secure_sram((u32 *)(unsigned long) __pa(omap3_secure_ram_storage)); pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state); /* Following is for error tracking, it should not happen */ diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index e233dfc..93a2a6e 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -128,7 +128,8 @@ skip_voltdm: for (i = 0; i < pwrdm->banks; i++) pwrdm->ret_mem_off_counter[i] = 0; - arch_pwrdm->pwrdm_wait_transition(pwrdm); + if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition) + arch_pwrdm->pwrdm_wait_transition(pwrdm); pwrdm->state = pwrdm_read_pwrst(pwrdm); pwrdm->state_counter[pwrdm->state] = 1; diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index 7a97606..8d95aa5 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -43,7 +43,7 @@ extern void omap4_prm_vcvp_write(u32 val, u8 offset); extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ - defined(CONFIG_SOC_DRA7XX) + defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX) void omap44xx_prm_reconfigure_io_chain(void); #else static inline void omap44xx_prm_reconfigure_io_chain(void) diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index b91002c..c134a82 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -21,7 +21,7 @@ #include <plat/irq.h> #include "common.h" -struct of_dev_auxdata orion5x_auxdata_lookup[] __initdata = { +static struct of_dev_auxdata orion5x_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL), OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0", NULL), diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 91a5852..3f1de11 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -24,7 +24,6 @@ #include <asm/page.h> #include <asm/setup.h> #include <asm/system_misc.h> -#include <asm/timex.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -135,7 +134,7 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) /***************************************************************************** * SPI ****************************************************************************/ -void __init orion5x_spi_init() +void __init orion5x_spi_init(void) { orion_spi_init(SPI_PHYS_BASE); } @@ -185,7 +184,7 @@ static void __init orion5x_crypto_init(void) /***************************************************************************** * Watchdog ****************************************************************************/ -void __init orion5x_wdt_init(void) +static void __init orion5x_wdt_init(void) { orion_wdt_init(); } @@ -246,7 +245,7 @@ void orion5x_setup_wins(void) int orion5x_tclk; -int __init orion5x_find_tclk(void) +static int __init orion5x_find_tclk(void) { u32 dev, rev; diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index 4b2aefd..dc01c4f 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -202,7 +202,7 @@ __initcall(db88f5281_7seg_init); * PCI ****************************************************************************/ -void __init db88f5281_pci_preinit(void) +static void __init db88f5281_pci_preinit(void) { int pin; diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index 30a192b..9654b0c 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c @@ -16,6 +16,7 @@ #include <mach/bridge-regs.h> #include <plat/orion-gpio.h> #include <plat/irq.h> +#include "common.h" static int __initdata gpio0_irqs[4] = { IRQ_ORION5X_GPIO_0_7, diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 7fab670..87a12d6 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -240,11 +240,11 @@ static int __init pcie_setup(struct pci_sys_data *sys) #define PCI_BAR_SIZE_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc08) : \ ((n) == 1) ? ORION5X_PCI_REG(0xd08) : \ ((n) == 2) ? ORION5X_PCI_REG(0xc0c) : \ - ((n) == 3) ? ORION5X_PCI_REG(0xd0c) : 0) + ((n) == 3) ? ORION5X_PCI_REG(0xd0c) : NULL) #define PCI_BAR_REMAP_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc48) : \ ((n) == 1) ? ORION5X_PCI_REG(0xd48) : \ ((n) == 2) ? ORION5X_PCI_REG(0xc4c) : \ - ((n) == 3) ? ORION5X_PCI_REG(0xd4c) : 0) + ((n) == 3) ? ORION5X_PCI_REG(0xd4c) : NULL) #define PCI_BAR_ENABLE ORION5X_PCI_REG(0xc3c) #define PCI_ADDR_DECODE_CTRL ORION5X_PCI_REG(0xd3c) diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index b1cf684..b576ef5 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -108,7 +108,7 @@ static struct platform_device rd88f5182_gpio_leds = { * PCI ****************************************************************************/ -void __init rd88f5182_pci_preinit(void) +static void __init rd88f5182_pci_preinit(void) { int pin; diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c index 7e90648..6208d12 100644 --- a/arch/arm/mach-orion5x/terastation_pro2-setup.c +++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c @@ -77,7 +77,7 @@ static struct platform_device tsp2_nor_flash = { #define TSP2_PCI_SLOT0_OFFS 7 #define TSP2_PCI_SLOT0_IRQ_PIN 11 -void __init tsp2_pci_preinit(void) +static void __init tsp2_pci_preinit(void) { int pin; diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c index e90c061..9136797 100644 --- a/arch/arm/mach-orion5x/ts209-setup.c +++ b/arch/arm/mach-orion5x/ts209-setup.c @@ -106,7 +106,7 @@ static struct platform_device qnap_ts209_nor_flash = { #define QNAP_TS209_PCI_SLOT0_IRQ_PIN 6 #define QNAP_TS209_PCI_SLOT1_IRQ_PIN 7 -void __init qnap_ts209_pci_preinit(void) +static void __init qnap_ts209_pci_preinit(void) { int pin; diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index e960855..db16dae 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -57,7 +57,7 @@ static struct map_desc ts78xx_io_desc[] __initdata = { }, }; -void __init ts78xx_map_io(void) +static void __init ts78xx_map_io(void) { orion5x_map_io(); iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc)); diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c index 3dbcb1a..e358b07 100644 --- a/arch/arm/mach-prima2/platsmp.c +++ b/arch/arm/mach-prima2/platsmp.c @@ -106,8 +106,7 @@ static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle) * "cpu" is Linux's internal ID. */ pen_release = cpu_logical_map(cpu); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); /* * Send the secondary CPU SEV, thereby causing the boot monitor to read diff --git a/arch/arm/mach-pxa/am200epd.c b/arch/arm/mach-pxa/am200epd.c index ffa6d81..12fb0f4 100644 --- a/arch/arm/mach-pxa/am200epd.c +++ b/arch/arm/mach-pxa/am200epd.c @@ -293,8 +293,7 @@ static int am200_setup_irq(struct fb_info *info) int ret; ret = request_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), am200_handle_irq, - IRQF_DISABLED|IRQF_TRIGGER_FALLING, - "AM200", info->par); + IRQF_TRIGGER_FALLING, "AM200", info->par); if (ret) dev_err(&am200_device->dev, "request_irq failed: %d\n", ret); diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c index 3dfec1e..c9f309a 100644 --- a/arch/arm/mach-pxa/am300epd.c +++ b/arch/arm/mach-pxa/am300epd.c @@ -241,8 +241,7 @@ static int am300_setup_irq(struct fb_info *info) struct broadsheetfb_par *par = info->par; ret = request_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), am300_handle_irq, - IRQF_DISABLED|IRQF_TRIGGER_RISING, - "AM300", par); + IRQF_TRIGGER_RISING, "AM300", par); if (ret) dev_err(&am300_device->dev, "request_irq failed: %d\n", ret); diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 8eb4e23..6915a9f 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -564,8 +564,7 @@ static int em_x270_mci_init(struct device *dev, } err = request_irq(gpio_to_irq(mmc_cd), em_x270_detect_int, - IRQF_DISABLED | IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MMC card detect", data); if (err) { dev_err(dev, "can't request MMC card detect IRQ: %d\n", err); diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index b6cc181..0eecd83 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -235,8 +235,6 @@ static const struct of_device_id intc_ids[] __initconst = { void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)) { struct device_node *node; - const struct of_device_id *of_id; - struct pxa_intc_conf *conf; struct resource res; int n, ret; @@ -245,8 +243,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)) pr_err("Failed to find interrupt controller in arch-pxa\n"); return; } - of_id = of_match_node(intc_ids, node); - conf = of_id->data; ret = of_property_read_u32(node, "marvell,intc-nr-irqs", &pxa_internal_irq_nr); diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index fab30d6..a9761c2 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -634,7 +634,7 @@ static struct platform_device bq24022 = { static int magician_mci_init(struct device *dev, irq_handler_t detect_irq, void *data) { - return request_irq(IRQ_MAGICIAN_SD, detect_irq, IRQF_DISABLED, + return request_irq(IRQ_MAGICIAN_SD, detect_irq, 0, "mmc card detect", data); } diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 08ccc07..78b84c0 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -401,7 +401,7 @@ static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_in */ MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL; - err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, IRQF_DISABLED, + err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, 0, "MMC card detect", data); if (err) printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 9a4e470..2897da2 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -327,7 +327,7 @@ static int pcm990_mci_init(struct device *dev, irq_handler_t mci_detect_int, { int err; - err = request_irq(PCM027_MMCDET_IRQ, mci_detect_int, IRQF_DISABLED, + err = request_irq(PCM027_MMCDET_IRQ, mci_detect_int, 0, "MMC card detect", data); if (err) printk(KERN_ERR "pcm990_mci_init: MMC/SD: can't request MMC " diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 0a36d35..051a655 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -860,18 +860,18 @@ static int sharpsl_pm_probe(struct platform_device *pdev) /* Register interrupt handlers */ irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_acin); - if (request_irq(irq, sharpsl_ac_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) { + if (request_irq(irq, sharpsl_ac_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) { dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq); } irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batlock); - if (request_irq(irq, sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) { + if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) { dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq); } if (sharpsl_pm.machinfo->gpio_fatal) { irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_fatal); - if (request_irq(irq, sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) { + if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) { dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq); } } @@ -879,7 +879,7 @@ static int sharpsl_pm_probe(struct platform_device *pdev) if (sharpsl_pm.machinfo->batfull_irq) { /* Register interrupt handler. */ irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batfull); - if (request_irq(irq, sharpsl_chrg_full_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) { + if (request_irq(irq, sharpsl_chrg_full_isr, IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) { dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq); } } diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 9aa852a..5fdc9c4f 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -137,7 +137,7 @@ static struct clock_event_device ckevt_pxa_osmr0 = { static struct irqaction pxa_ost0_irq = { .name = "ost0", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = pxa_ost0_interrupt, .dev_id = &ckevt_pxa_osmr0, }; diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index c580434..872dcb2 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -332,8 +332,7 @@ static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, int err; err = request_irq(TRIZEPS4_MMC_IRQ, mci_detect_int, - IRQF_DISABLED | IRQF_TRIGGER_RISING, - "MMC card detect", data); + IRQF_TRIGGER_RISING, "MMC card detect", data); if (err) { printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request" "MMC card detect IRQ\n"); diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index 0fa068e..fe071a9 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c @@ -168,7 +168,7 @@ static const struct sh_mmcif_plat_data mmcif0_pdata __initconst = { }; static const struct resource mmcif0_resources[] __initconst = { - DEFINE_RES_MEM_NAMED(0xee200000, 0x100, "MMCIF0"), + DEFINE_RES_MEM(0xee200000, 0x100), DEFINE_RES_IRQ(gic_spi(169)), }; @@ -179,7 +179,7 @@ static const struct sh_mobile_sdhi_info sdhi0_pdata __initconst = { }; static const struct resource sdhi0_resources[] __initconst = { - DEFINE_RES_MEM_NAMED(0xee100000, 0x100, "SDHI0"), + DEFINE_RES_MEM(0xee100000, 0x100), DEFINE_RES_IRQ(gic_spi(165)), }; @@ -191,7 +191,7 @@ static const struct sh_mobile_sdhi_info sdhi1_pdata __initconst = { }; static const struct resource sdhi1_resources[] __initconst = { - DEFINE_RES_MEM_NAMED(0xee120000, 0x100, "SDHI1"), + DEFINE_RES_MEM(0xee120000, 0x100), DEFINE_RES_IRQ(gic_spi(166)), }; diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c index ae88fda..1687df9 100644 --- a/arch/arm/mach-shmobile/board-bockw-reference.c +++ b/arch/arm/mach-shmobile/board-bockw-reference.c @@ -19,7 +19,6 @@ */ #include <linux/of_platform.h> -#include <linux/pinctrl/machine.h> #include <mach/common.h> #include <mach/r8a7778.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index 1a1a4a8..7df9ea0 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c @@ -20,16 +20,15 @@ #include <linux/init.h> #include <linux/of_platform.h> +#include <mach/rcar-gen2.h> #include <mach/r8a7790.h> #include <asm/mach/arch.h> static void __init lager_add_standard_devices(void) { - /* clocks are setup late during boot in the case of DT */ r8a7790_clock_init(); - r8a7790_add_dt_devices(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static const char *lager_boards_compat_dt[] __initdata = { diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index a8d3ce6..78a31b6 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -148,7 +148,7 @@ static const struct sh_mmcif_plat_data mmcif1_pdata __initconst = { }; static const struct resource mmcif1_resources[] __initconst = { - DEFINE_RES_MEM_NAMED(0xee220000, 0x80, "MMCIF1"), + DEFINE_RES_MEM(0xee220000, 0x80), DEFINE_RES_IRQ(gic_spi(170)), }; diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index da1352f..4f9e3ec 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -29,6 +29,7 @@ #include <linux/leds.h> #include <linux/dma-mapping.h> #include <linux/pinctrl/machine.h> +#include <linux/platform_data/camera-rcar.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_data/rcar-du.h> #include <linux/platform_data/usb-rcar-phy.h> @@ -259,10 +260,30 @@ static struct platform_device leds_device = { }, }; +/* VIN */ static struct rcar_vin_platform_data vin_platform_data __initdata = { .flags = RCAR_VIN_BT656, }; +#define MARZEN_VIN(idx) \ +static struct resource vin##idx##_resources[] __initdata = { \ + DEFINE_RES_MEM(0xffc50000 + 0x1000 * (idx), 0x1000), \ + DEFINE_RES_IRQ(gic_iid(0x5f + (idx))), \ +}; \ + \ +static struct platform_device_info vin##idx##_info __initdata = { \ + .parent = &platform_bus, \ + .name = "r8a7779-vin", \ + .id = idx, \ + .res = vin##idx##_resources, \ + .num_res = ARRAY_SIZE(vin##idx##_resources), \ + .dma_mask = DMA_BIT_MASK(32), \ + .data = &vin_platform_data, \ + .size_data = sizeof(vin_platform_data), \ +} +MARZEN_VIN(1); +MARZEN_VIN(3); + #define MARZEN_CAMERA(idx) \ static struct i2c_board_info camera##idx##_info = { \ I2C_BOARD_INFO("adv7180", 0x20 + (idx)), \ @@ -367,8 +388,8 @@ static void __init marzen_init(void) r8a7779_init_irq_extpin(1); /* IRQ1 as individual interrupt */ r8a7779_add_standard_devices(); - r8a7779_add_vin_device(1, &vin_platform_data); - r8a7779_add_vin_device(3, &vin_platform_data); + platform_device_register_full(&vin1_info); + platform_device_register_full(&vin3_info); platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices)); marzen_add_du_device(); } diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c index 4aba20c..0814a50 100644 --- a/arch/arm/mach-shmobile/clock-r7s72100.c +++ b/arch/arm/mach-shmobile/clock-r7s72100.c @@ -170,6 +170,9 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), /* MSTP clocks */ + CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP33]), + + /* ICK */ CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]), CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]), CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]), diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index a64f965..fa1b477 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -77,7 +77,7 @@ static struct sh_clk_ops followparent_clk_ops = { }; static struct clk main_clk = { - /* .parent will be set r8a73a4_clock_init */ + /* .parent will be set r8a7790_clock_init */ .ops = &followparent_clk_ops, }; diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 5390c6b..2848997 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -504,10 +504,6 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]), - CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ @@ -574,6 +570,11 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ CLKDEV_DEV_ID("sh_cmt.2", &mstp_clks[MSTP400]), /* CMT2 */ + /* ICK */ + CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), + CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), CLKDEV_ICK_ID("hdmi", "sh_mobile_lcdc_fb.1", &div6_reparent_clks[DIV6_HDMI]), CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]), diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index c92c023..2aeec46 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -625,12 +625,6 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("sdhi0_clk", &div6_clks[DIV6_SDHI0]), CLKDEV_CON_ID("sdhi1_clk", &div6_clks[DIV6_SDHI1]), CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]), - CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), - CLKDEV_ICK_ID("dsiphy_clk", "sh-mipi-dsi.0", &dsi0phy_clk), - CLKDEV_ICK_ID("dsiphy_clk", "sh-mipi-dsi.1", &dsi1phy_clk), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ @@ -680,6 +674,14 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */ CLKDEV_DEV_ID("e6828000.i2c", &mstp_clks[MSTP410]), /* I2C4 */ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ + + /* ICK */ + CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), + CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), + CLKDEV_ICK_ID("dsiphy_clk", "sh-mipi-dsi.0", &dsi0phy_clk), + CLKDEV_ICK_ID("dsiphy_clk", "sh-mipi-dsi.1", &dsi1phy_clk), }; void __init sh73a0_clock_init(void) diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h index 17af34e..5014145 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7779.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7779.h @@ -3,8 +3,6 @@ #include <linux/sh_clk.h> #include <linux/pm_domain.h> -#include <linux/sh_eth.h> -#include <linux/platform_data/camera-rcar.h> /* HPB-DMA slave IDs */ enum { @@ -40,9 +38,6 @@ extern void r8a7779_earlytimer_init(void); extern void r8a7779_add_early_devices(void); extern void r8a7779_add_standard_devices(void); extern void r8a7779_add_standard_devices_dt(void); -extern void r8a7779_add_ether_device(struct sh_eth_plat_data *pdata); -extern void r8a7779_add_vin_device(int idx, - struct rcar_vin_platform_data *pdata); extern void r8a7779_init_late(void); extern void r8a7779_clock_init(void); extern void r8a7779_pinmux_init(void); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 13049e9..8f94531 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -598,45 +598,6 @@ static struct platform_device ohci1_device = { .resource = ohci1_resources, }; -/* Ether */ -static struct resource ether_resources[] __initdata = { - { - .start = 0xfde00000, - .end = 0xfde003ff, - .flags = IORESOURCE_MEM, - }, { - .start = gic_iid(0xb4), - .flags = IORESOURCE_IRQ, - }, -}; - -#define R8A7779_VIN(idx) \ -static struct resource vin##idx##_resources[] __initdata = { \ - DEFINE_RES_MEM(0xffc50000 + 0x1000 * (idx), 0x1000), \ - DEFINE_RES_IRQ(gic_iid(0x5f + (idx))), \ -}; \ - \ -static struct platform_device_info vin##idx##_info __initdata = { \ - .parent = &platform_bus, \ - .name = "r8a7779-vin", \ - .id = idx, \ - .res = vin##idx##_resources, \ - .num_res = ARRAY_SIZE(vin##idx##_resources), \ - .dma_mask = DMA_BIT_MASK(32), \ -} - -R8A7779_VIN(0); -R8A7779_VIN(1); -R8A7779_VIN(2); -R8A7779_VIN(3); - -static struct platform_device_info *vin_info_table[] __initdata = { - &vin0_info, - &vin1_info, - &vin2_info, - &vin3_info, -}; - /* HPB-DMA */ /* Asynchronous mode register bits */ @@ -825,24 +786,6 @@ void __init r8a7779_add_standard_devices(void) r8a7779_register_hpb_dmae(); } -void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata) -{ - platform_device_register_resndata(&platform_bus, "r8a777x-ether", -1, - ether_resources, - ARRAY_SIZE(ether_resources), - pdata, sizeof(*pdata)); -} - -void __init r8a7779_add_vin_device(int id, struct rcar_vin_platform_data *pdata) -{ - BUG_ON(id < 0 || id > 3); - - vin_info_table[id]->data = pdata; - vin_info_table[id]->size_data = sizeof(*pdata); - - platform_device_register_full(vin_info_table[id]); -} - /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */ void __init __weak r8a7779_register_twd(void) { } diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index c47bcebb..3543c3b 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -34,6 +34,10 @@ static const struct resource pfc_resources[] __initconst = { DEFINE_RES_MEM(0xe6060000, 0x250), }; +#define r8a7790_register_pfc() \ + platform_device_register_simple("pfc-r8a7790", -1, pfc_resources, \ + ARRAY_SIZE(pfc_resources)) + #define R8A7790_GPIO(idx) \ static const struct resource r8a7790_gpio##idx##_resources[] __initconst = { \ DEFINE_RES_MEM(0xe6050000 + 0x1000 * (idx), 0x50), \ @@ -65,8 +69,7 @@ R8A7790_GPIO(5); void __init r8a7790_pinmux_init(void) { - platform_device_register_simple("pfc-r8a7790", -1, pfc_resources, - ARRAY_SIZE(pfc_resources)); + r8a7790_register_pfc(); r8a7790_register_gpio(0); r8a7790_register_gpio(1); r8a7790_register_gpio(2); diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 22de174..65151c4 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -273,7 +273,7 @@ static struct sh_timer_config tmu00_platform_data = { }; static struct resource tmu00_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xfff60008, 0xc, "TMU00"), + [0] = DEFINE_RES_MEM(0xfff60008, 0xc), [1] = { .start = intcs_evt2irq(0x0e80), /* TMU0_TUNI00 */ .flags = IORESOURCE_IRQ, @@ -298,7 +298,7 @@ static struct sh_timer_config tmu01_platform_data = { }; static struct resource tmu01_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xfff60014, 0xc, "TMU00"), + [0] = DEFINE_RES_MEM(0xfff60014, 0xc), [1] = { .start = intcs_evt2irq(0x0ea0), /* TMU0_TUNI01 */ .flags = IORESOURCE_IRQ, @@ -316,7 +316,7 @@ static struct platform_device tmu01_device = { }; static struct resource i2c0_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xe6820000, 0x426, "IIC0"), + [0] = DEFINE_RES_MEM(0xe6820000, 0x426), [1] = { .start = gic_spi(167), .end = gic_spi(170), @@ -325,7 +325,7 @@ static struct resource i2c0_resources[] = { }; static struct resource i2c1_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xe6822000, 0x426, "IIC1"), + [0] = DEFINE_RES_MEM(0xe6822000, 0x426), [1] = { .start = gic_spi(51), .end = gic_spi(54), @@ -334,7 +334,7 @@ static struct resource i2c1_resources[] = { }; static struct resource i2c2_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xe6824000, 0x426, "IIC2"), + [0] = DEFINE_RES_MEM(0xe6824000, 0x426), [1] = { .start = gic_spi(171), .end = gic_spi(174), @@ -343,7 +343,7 @@ static struct resource i2c2_resources[] = { }; static struct resource i2c3_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xe6826000, 0x426, "IIC3"), + [0] = DEFINE_RES_MEM(0xe6826000, 0x426), [1] = { .start = gic_spi(183), .end = gic_spi(186), @@ -352,7 +352,7 @@ static struct resource i2c3_resources[] = { }; static struct resource i2c4_resources[] = { - [0] = DEFINE_RES_MEM_NAMED(0xe6828000, 0x426, "IIC4"), + [0] = DEFINE_RES_MEM(0xe6828000, 0x426), [1] = { .start = gic_spi(187), .end = gic_spi(190), @@ -722,7 +722,7 @@ static struct platform_device pmu_device = { /* an IPMMU module for ICB */ static struct resource ipmmu_resources[] = { - DEFINE_RES_MEM_NAMED(0xfe951000, 0x100, "IPMMU"), + DEFINE_RES_MEM(0xfe951000, 0x100), }; static const char * const ipmmu_dev_names[] = { diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 037100a..aee77f0 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -10,6 +10,7 @@ config ARCH_SOCFPGA select GENERIC_CLOCKEVENTS select GPIO_PL061 if GPIOLIB select HAVE_ARM_SCU + select HAVE_ARM_TWD if SMP select HAVE_SMP select MFD_SYSCON select SPARSE_IRQ diff --git a/arch/arm/mach-sti/platsmp.c b/arch/arm/mach-sti/platsmp.c index dce50d9..fa2c33f 100644 --- a/arch/arm/mach-sti/platsmp.c +++ b/arch/arm/mach-sti/platsmp.c @@ -31,8 +31,7 @@ static void write_pen_release(int val) { pen_release = val; smp_wmb(); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); } static DEFINE_SPINLOCK(boot_lock); diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index d4639c5..9a4e910 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -209,13 +209,3 @@ void __init tegra_init_fuse(void) tegra_sku_id, tegra_cpu_process_id, tegra_core_process_id); } - -unsigned long long tegra_chip_uid(void) -{ - unsigned long long lo, hi; - - lo = tegra_fuse_readl(FUSE_UID_LOW); - hi = tegra_fuse_readl(FUSE_UID_HIGH); - return (hi << 32ull) | lo; -} -EXPORT_SYMBOL(tegra_chip_uid); diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 2e85c1e..12c7e5c 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -140,6 +140,10 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { /* Requires call-back bindings. */ OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata), /* Requires DMA bindings. */ + OF_DEV_AUXDATA("arm,pl18x", 0x80126000, "sdi0", &mop500_sdi0_data), + OF_DEV_AUXDATA("arm,pl18x", 0x80118000, "sdi1", &mop500_sdi1_data), + OF_DEV_AUXDATA("arm,pl18x", 0x80005000, "sdi2", &mop500_sdi2_data), + OF_DEV_AUXDATA("arm,pl18x", 0x80114000, "sdi4", &mop500_sdi4_data), OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80123000, "ux500-msp-i2s.0", &msp0_platform_data), OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80124000, diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 1f296e7..a44967f 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -38,8 +38,7 @@ static void write_pen_release(int val) { pen_release = val; smp_wmb(); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); } static void __iomem *scu_base_addr(void) diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index 033d34d..c26ef5b 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c @@ -53,6 +53,11 @@ #define A15_BX_ADDR0 0x68 #define A7_BX_ADDR0 0x78 +/* SPC CPU/cluster reset statue */ +#define STANDBYWFI_STAT 0x3c +#define STANDBYWFI_STAT_A15_CPU_MASK(cpu) (1 << (cpu)) +#define STANDBYWFI_STAT_A7_CPU_MASK(cpu) (1 << (3 + (cpu))) + /* SPC system config interface registers */ #define SYSCFG_WDATA 0x70 #define SYSCFG_RDATA 0x74 @@ -213,6 +218,41 @@ void ve_spc_powerdown(u32 cluster, bool enable) writel_relaxed(enable, info->baseaddr + pwdrn_reg); } +static u32 standbywfi_cpu_mask(u32 cpu, u32 cluster) +{ + return cluster_is_a15(cluster) ? + STANDBYWFI_STAT_A15_CPU_MASK(cpu) + : STANDBYWFI_STAT_A7_CPU_MASK(cpu); +} + +/** + * ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) + * + * @cpu: mpidr[7:0] bitfield describing CPU affinity level within cluster + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * + * @return: non-zero if and only if the specified CPU is in WFI + * + * Take care when interpreting the result of this function: a CPU might + * be in WFI temporarily due to idle, and is not necessarily safely + * parked. + */ +int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) +{ + int ret; + u32 mask = standbywfi_cpu_mask(cpu, cluster); + + if (cluster >= MAX_CLUSTERS) + return 1; + + ret = readl_relaxed(info->baseaddr + STANDBYWFI_STAT); + + pr_debug("%s: PCFGREG[0x%X] = 0x%08X, mask = 0x%X\n", + __func__, STANDBYWFI_STAT, ret, mask); + + return ret & mask; +} + static int ve_spc_get_performance(int cluster, u32 *freq) { struct ve_spc_opp *opps = info->opps[cluster]; diff --git a/arch/arm/mach-vexpress/spc.h b/arch/arm/mach-vexpress/spc.h index dbd44c3..793d065 100644 --- a/arch/arm/mach-vexpress/spc.h +++ b/arch/arm/mach-vexpress/spc.h @@ -20,5 +20,6 @@ void ve_spc_global_wakeup_irq(bool set); void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); void ve_spc_powerdown(u32 cluster, bool enable); +int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster); #endif diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index 05a364c50..29e7785 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> @@ -32,11 +33,17 @@ #include "spc.h" /* SCC conf registers */ +#define RESET_CTRL 0x018 +#define RESET_A15_NCORERESET(cpu) (1 << (2 + (cpu))) +#define RESET_A7_NCORERESET(cpu) (1 << (16 + (cpu))) + #define A15_CONF 0x400 #define A7_CONF 0x500 #define SYS_INFO 0x700 #define SPC_BASE 0xb00 +static void __iomem *scc; + /* * We can't use regular spinlocks. In the switcher case, it is possible * for an outbound CPU to call power_down() after its inbound counterpart @@ -190,6 +197,55 @@ static void tc2_pm_power_down(void) tc2_pm_down(0); } +static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster) +{ + u32 mask = cluster ? + RESET_A7_NCORERESET(cpu) + : RESET_A15_NCORERESET(cpu); + + return !(readl_relaxed(scc + RESET_CTRL) & mask); +} + +#define POLL_MSEC 10 +#define TIMEOUT_MSEC 1000 + +static int tc2_pm_power_down_finish(unsigned int cpu, unsigned int cluster) +{ + unsigned tries; + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); + + for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) { + /* + * Only examine the hardware state if the target CPU has + * caught up at least as far as tc2_pm_down(): + */ + if (ACCESS_ONCE(tc2_pm_use_count[cpu][cluster]) == 0) { + pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n", + __func__, cpu, cluster, + readl_relaxed(scc + RESET_CTRL)); + + /* + * We need the CPU to reach WFI, but the power + * controller may put the cluster in reset and + * power it off as soon as that happens, before + * we have a chance to see STANDBYWFI. + * + * So we need to check for both conditions: + */ + if (tc2_core_in_reset(cpu, cluster) || + ve_spc_cpu_in_wfi(cpu, cluster)) + return 0; /* success: the CPU is halted */ + } + + /* Otherwise, wait and retry: */ + msleep(POLL_MSEC); + } + + return -ETIMEDOUT; /* timeout */ +} + static void tc2_pm_suspend(u64 residency) { unsigned int mpidr, cpu, cluster; @@ -232,10 +288,11 @@ static void tc2_pm_powered_up(void) } static const struct mcpm_platform_ops tc2_pm_power_ops = { - .power_up = tc2_pm_power_up, - .power_down = tc2_pm_power_down, - .suspend = tc2_pm_suspend, - .powered_up = tc2_pm_powered_up, + .power_up = tc2_pm_power_up, + .power_down = tc2_pm_power_down, + .power_down_finish = tc2_pm_power_down_finish, + .suspend = tc2_pm_suspend, + .powered_up = tc2_pm_powered_up, }; static bool __init tc2_pm_usage_count_init(void) @@ -269,7 +326,6 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) static int __init tc2_pm_init(void) { int ret, irq; - void __iomem *scc; u32 a15_cluster_id, a7_cluster_id, sys_info; struct device_node *np; diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 9a7bd13..1db2a5ca 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -25,6 +25,8 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of.h> +#include <linux/irqchip.h> +#include <linux/irqchip/arm-gic.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -39,11 +41,6 @@ void __iomem *zynq_scu_base; -static struct of_device_id zynq_of_bus_ids[] __initdata = { - { .compatible = "simple-bus", }, - {} -}; - static struct platform_device zynq_cpuidle_device = { .name = "cpuidle-zynq", }; @@ -59,7 +56,7 @@ static void __init zynq_init_machine(void) */ l2x0_of_init(0x02060000, 0xF0F0FFFF); - of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); platform_device_register(&zynq_cpuidle_device); } @@ -97,6 +94,12 @@ static void __init zynq_map_io(void) zynq_scu_map_io(); } +static void __init zynq_irq_init(void) +{ + gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; + irqchip_init(); +} + static void zynq_system_reset(enum reboot_mode mode, const char *cmd) { zynq_slcr_system_reset(); @@ -110,6 +113,7 @@ static const char * const zynq_dt_match[] = { DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .smp = smp_ops(zynq_smp_ops), .map_io = zynq_map_io, + .init_irq = zynq_irq_init, .init_machine = zynq_init_machine, .init_time = zynq_timer_init, .dt_compat = zynq_dt_match, diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 3040d21..c22c92c 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -17,6 +17,8 @@ #ifndef __MACH_ZYNQ_COMMON_H__ #define __MACH_ZYNQ_COMMON_H__ +void zynq_secondary_startup(void); + extern int zynq_slcr_init(void); extern void zynq_slcr_system_reset(void); extern void zynq_slcr_cpu_stop(int cpu); diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S index d4cd5f3..57a3286 100644 --- a/arch/arm/mach-zynq/headsmp.S +++ b/arch/arm/mach-zynq/headsmp.S @@ -18,5 +18,9 @@ zynq_secondary_trampoline_jump: .word /* cpu 1 */ .globl zynq_secondary_trampoline_end zynq_secondary_trampoline_end: - ENDPROC(zynq_secondary_trampoline) + +ENTRY(zynq_secondary_startup) + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(zynq_secondary_startup) diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c index 689fbbc..abc82ef 100644 --- a/arch/arm/mach-zynq/platsmp.c +++ b/arch/arm/mach-zynq/platsmp.c @@ -39,11 +39,6 @@ int zynq_cpun_start(u32 address, int cpu) u32 trampoline_code_size = &zynq_secondary_trampoline_end - &zynq_secondary_trampoline; - if (cpu > ncores) { - pr_warn("CPU No. is not available in the system\n"); - return -1; - } - /* MS: Expectation that SLCR are directly map and accessible */ /* Not possible to jump to non aligned address */ if (!(address & 3) && (!address || (address >= trampoline_code_size))) { @@ -95,7 +90,7 @@ EXPORT_SYMBOL(zynq_cpun_start); static int zynq_boot_secondary(unsigned int cpu, struct task_struct *idle) { - return zynq_cpun_start(virt_to_phys(secondary_startup), cpu); + return zynq_cpun_start(virt_to_phys(zynq_secondary_startup), cpu); } /* @@ -114,23 +109,23 @@ static void __init zynq_smp_init_cpus(void) static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - scu_enable(zynq_scu_base); } +#ifdef CONFIG_HOTPLUG_CPU +static int zynq_cpu_kill(unsigned cpu) +{ + zynq_slcr_cpu_stop(cpu); + return 1; +} +#endif + struct smp_operations zynq_smp_ops __initdata = { .smp_init_cpus = zynq_smp_init_cpus, .smp_prepare_cpus = zynq_smp_prepare_cpus, .smp_boot_secondary = zynq_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = zynq_platform_cpu_die, + .cpu_kill = zynq_cpu_kill, #endif }; diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index fb92abb..2861b15 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -336,8 +336,11 @@ static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) if (timer->posted) return; - if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) + if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) { + timer->posted = OMAP_TIMER_NONPOSTED; + __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0); return; + } __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, OMAP_TIMER_CTRL_POSTED, 0); diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index c66d163..830ff07 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -22,6 +22,7 @@ #include <linux/platform_data/dma-mv_xor.h> #include <linux/platform_data/usb-ehci-orion.h> #include <mach/bridge-regs.h> +#include <plat/common.h> /* Create a clkdev entry for a given device/clk */ void __init orion_clkdev_add(const char *con_id, const char *dev_id, @@ -256,7 +257,7 @@ static __init void ge_complete( /***************************************************************************** * GE00 ****************************************************************************/ -struct mv643xx_eth_shared_platform_data orion_ge00_shared_data; +static struct mv643xx_eth_shared_platform_data orion_ge00_shared_data; static struct resource orion_ge00_shared_resources[] = { { @@ -322,7 +323,7 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, /***************************************************************************** * GE01 ****************************************************************************/ -struct mv643xx_eth_shared_platform_data orion_ge01_shared_data; +static struct mv643xx_eth_shared_platform_data orion_ge01_shared_data; static struct resource orion_ge01_shared_resources[] = { { @@ -373,7 +374,7 @@ void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, /***************************************************************************** * GE10 ****************************************************************************/ -struct mv643xx_eth_shared_platform_data orion_ge10_shared_data; +static struct mv643xx_eth_shared_platform_data orion_ge10_shared_data; static struct resource orion_ge10_shared_resources[] = { { @@ -422,7 +423,7 @@ void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, /***************************************************************************** * GE11 ****************************************************************************/ -struct mv643xx_eth_shared_platform_data orion_ge11_shared_data; +static struct mv643xx_eth_shared_platform_data orion_ge11_shared_data; static struct resource orion_ge11_shared_resources[] = { { diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 9d2b2ac..15921a1 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/sched_clock.h> +#include <plat/time.h> /* * MBus bridge block registers. @@ -174,7 +175,7 @@ static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) static struct irqaction orion_timer_irq = { .name = "orion_tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .handler = orion_timer_interrupt }; diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c index 79ef102..054fc5a 100644 --- a/arch/arm/plat-pxa/dma.c +++ b/arch/arm/plat-pxa/dma.c @@ -377,7 +377,7 @@ int __init pxa_init_dma(int irq, int num_ch) spin_lock_init(&dma_channels[i].lock); } - ret = request_irq(irq, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); + ret = request_irq(irq, dma_irq_handler, 0, "DMA", NULL); if (ret) { printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); kfree(dma_channels); diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c index 39895d8..53feb90 100644 --- a/arch/arm/plat-versatile/platsmp.c +++ b/arch/arm/plat-versatile/platsmp.c @@ -27,8 +27,7 @@ static void write_pen_release(int val) { pen_release = val; smp_wmb(); - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + sync_cache_w(&pen_release); } static DEFINE_SPINLOCK(boot_lock); diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts index 84fcc50..519c4b2 100644 --- a/arch/arm64/boot/dts/foundation-v8.dts +++ b/arch/arm64/boot/dts/foundation-v8.dts @@ -6,6 +6,8 @@ /dts-v1/; +/memreserve/ 0x80000000 0x00010000; + / { model = "Foundation-v8A"; compatible = "arm,foundation-aarch64", "arm,vexpress"; diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index aa11943..b2fcfbc 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -56,6 +56,9 @@ static inline void arch_local_irq_disable(void) #define local_fiq_enable() asm("msr daifclr, #1" : : : "memory") #define local_fiq_disable() asm("msr daifset, #1" : : : "memory") +#define local_async_enable() asm("msr daifclr, #4" : : : "memory") +#define local_async_disable() asm("msr daifset, #4" : : : "memory") + /* * Save the current interrupt enable state. */ diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 17bd3af..7f2b60a 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -25,10 +25,11 @@ * Software defined PTE bits definition. */ #define PTE_VALID (_AT(pteval_t, 1) << 0) -#define PTE_PROT_NONE (_AT(pteval_t, 1) << 2) /* only when !PTE_VALID */ -#define PTE_FILE (_AT(pteval_t, 1) << 3) /* only when !pte_present() */ +#define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ #define PTE_DIRTY (_AT(pteval_t, 1) << 55) #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) + /* bit 57 for PMD_SECT_SPLITTING */ +#define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */ /* * VMALLOC and SPARSEMEM_VMEMMAP ranges. @@ -254,7 +255,7 @@ static inline int has_transparent_hugepage(void) #define pgprot_noncached(prot) \ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE)) #define pgprot_writecombine(prot) \ - __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE)) + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC)) #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC)) #define __HAVE_PHYS_MEM_ACCESS_PROT @@ -357,18 +358,20 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; /* * Encode and decode a swap entry: - * bits 0, 2: present (must both be zero) - * bit 3: PTE_FILE - * bits 4-8: swap type - * bits 9-63: swap offset + * bits 0-1: present (must be zero) + * bit 2: PTE_FILE + * bits 3-8: swap type + * bits 9-57: swap offset */ -#define __SWP_TYPE_SHIFT 4 +#define __SWP_TYPE_SHIFT 3 #define __SWP_TYPE_BITS 6 +#define __SWP_OFFSET_BITS 49 #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) +#define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1) #define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) -#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT) +#define __swp_offset(x) (((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK) #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) @@ -382,15 +385,15 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; /* * Encode and decode a file entry: - * bits 0, 2: present (must both be zero) - * bit 3: PTE_FILE - * bits 4-63: file offset / PAGE_SIZE + * bits 0-1: present (must be zero) + * bit 2: PTE_FILE + * bits 3-57: file offset / PAGE_SIZE */ #define pte_file(pte) (pte_val(pte) & PTE_FILE) -#define pte_to_pgoff(x) (pte_val(x) >> 4) -#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE) +#define pte_to_pgoff(x) (pte_val(x) >> 3) +#define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE) -#define PTE_FILE_MAX_BITS 60 +#define PTE_FILE_MAX_BITS 55 extern int kern_addr_valid(unsigned long addr); diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 6a0a9b1..4ae6857 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -248,7 +248,8 @@ static int brk_handler(unsigned long addr, unsigned int esr, int aarch32_break_handler(struct pt_regs *regs) { siginfo_t info; - unsigned int instr; + u32 arm_instr; + u16 thumb_instr; bool bp = false; void __user *pc = (void __user *)instruction_pointer(regs); @@ -257,18 +258,21 @@ int aarch32_break_handler(struct pt_regs *regs) if (compat_thumb_mode(regs)) { /* get 16-bit Thumb instruction */ - get_user(instr, (u16 __user *)pc); - if (instr == AARCH32_BREAK_THUMB2_LO) { + get_user(thumb_instr, (u16 __user *)pc); + thumb_instr = le16_to_cpu(thumb_instr); + if (thumb_instr == AARCH32_BREAK_THUMB2_LO) { /* get second half of 32-bit Thumb-2 instruction */ - get_user(instr, (u16 __user *)(pc + 2)); - bp = instr == AARCH32_BREAK_THUMB2_HI; + get_user(thumb_instr, (u16 __user *)(pc + 2)); + thumb_instr = le16_to_cpu(thumb_instr); + bp = thumb_instr == AARCH32_BREAK_THUMB2_HI; } else { - bp = instr == AARCH32_BREAK_THUMB; + bp = thumb_instr == AARCH32_BREAK_THUMB; } } else { /* 32-bit ARM instruction */ - get_user(instr, (u32 __user *)pc); - bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM; + get_user(arm_instr, (u32 __user *)pc); + arm_instr = le32_to_cpu(arm_instr); + bp = (arm_instr & ~0xf0000000) == AARCH32_BREAK_ARM; } if (!bp) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index e116614..4d2c6f3 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -309,15 +309,12 @@ el1_irq: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif -#ifdef CONFIG_PREEMPT - get_thread_info tsk - ldr w24, [tsk, #TI_PREEMPT] // get preempt count - add w0, w24, #1 // increment it - str w0, [tsk, #TI_PREEMPT] -#endif + irq_handler + #ifdef CONFIG_PREEMPT - str w24, [tsk, #TI_PREEMPT] // restore preempt count + get_thread_info tsk + ldr w24, [tsk, #TI_PREEMPT] // restore preempt count cbnz w24, 1f // preempt count != 0 ldr x0, [tsk, #TI_FLAGS] // get flags tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? @@ -507,22 +504,10 @@ el0_irq_naked: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif - get_thread_info tsk -#ifdef CONFIG_PREEMPT - ldr w24, [tsk, #TI_PREEMPT] // get preempt count - add w23, w24, #1 // increment it - str w23, [tsk, #TI_PREEMPT] -#endif + irq_handler -#ifdef CONFIG_PREEMPT - ldr w0, [tsk, #TI_PREEMPT] - str w24, [tsk, #TI_PREEMPT] - cmp w0, w23 - b.eq 1f - mov x1, #0 - str x1, [x1] // BUG -1: -#endif + get_thread_info tsk + #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on #endif diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index fecdbf7..6777a21 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -636,28 +636,27 @@ static int compat_gpr_get(struct task_struct *target, for (i = 0; i < num_regs; ++i) { unsigned int idx = start + i; - void *reg; + compat_ulong_t reg; switch (idx) { case 15: - reg = (void *)&task_pt_regs(target)->pc; + reg = task_pt_regs(target)->pc; break; case 16: - reg = (void *)&task_pt_regs(target)->pstate; + reg = task_pt_regs(target)->pstate; break; case 17: - reg = (void *)&task_pt_regs(target)->orig_x0; + reg = task_pt_regs(target)->orig_x0; break; default: - reg = (void *)&task_pt_regs(target)->regs[idx]; + reg = task_pt_regs(target)->regs[idx]; } - ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t)); - + ret = copy_to_user(ubuf, ®, sizeof(reg)); if (ret) break; - else - ubuf += sizeof(compat_ulong_t); + + ubuf += sizeof(reg); } return ret; @@ -685,28 +684,28 @@ static int compat_gpr_set(struct task_struct *target, for (i = 0; i < num_regs; ++i) { unsigned int idx = start + i; - void *reg; + compat_ulong_t reg; + + ret = copy_from_user(®, ubuf, sizeof(reg)); + if (ret) + return ret; + + ubuf += sizeof(reg); switch (idx) { case 15: - reg = (void *)&newregs.pc; + newregs.pc = reg; break; case 16: - reg = (void *)&newregs.pstate; + newregs.pstate = reg; break; case 17: - reg = (void *)&newregs.orig_x0; + newregs.orig_x0 = reg; break; default: - reg = (void *)&newregs.regs[idx]; + newregs.regs[idx] = reg; } - ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t)); - - if (ret) - goto out; - else - ubuf += sizeof(compat_ulong_t); } if (valid_user_regs(&newregs.user_regs)) @@ -714,7 +713,6 @@ static int compat_gpr_set(struct task_struct *target, else ret = -EINVAL; -out: return ret; } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 0bc5e4c..bd9bbd0 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -205,6 +205,11 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; void __init setup_arch(char **cmdline_p) { + /* + * Unmask asynchronous aborts early to catch possible system errors. + */ + local_async_enable(); + setup_processor(); setup_machine_fdt(__fdt_pointer); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a5aeefa..a0c2ca6 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -160,6 +160,7 @@ asmlinkage void secondary_start_kernel(void) local_irq_enable(); local_fiq_enable(); + local_async_enable(); /* * OK, it's off to the idle thread for us diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 8a24636..0f4344e 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -75,8 +75,10 @@ LDEMULATION := lppc GNUTARGET := powerpcle MULTIPLEWORD := -mno-multiple else +ifeq ($(call cc-option-yn,-mbig-endian),y) override CC += -mbig-endian override AS += -mbig-endian +endif override LD += -EB LDEMULATION := ppc GNUTARGET := powerpc @@ -128,7 +130,12 @@ CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5) CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6) CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7) +# Altivec option not allowed with e500mc64 in GCC. +ifeq ($(CONFIG_ALTIVEC),y) +E5500_CPU := -mcpu=powerpc64 +else E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64) +endif CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU) CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU)) diff --git a/arch/powerpc/boot/dts/xcalibur1501.dts b/arch/powerpc/boot/dts/xcalibur1501.dts index cc00f4d..c409cba 100644 --- a/arch/powerpc/boot/dts/xcalibur1501.dts +++ b/arch/powerpc/boot/dts/xcalibur1501.dts @@ -637,14 +637,14 @@ tlu@2f000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x2f000 0x1000>; - interupts = <61 2 >; + interrupts = <61 2>; interrupt-parent = <&mpic>; }; tlu@15000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x15000 0x1000>; - interupts = <75 2>; + interrupts = <75 2>; interrupt-parent = <&mpic>; }; }; diff --git a/arch/powerpc/boot/dts/xpedite5301.dts b/arch/powerpc/boot/dts/xpedite5301.dts index 53c1c6a..04cb410 100644 --- a/arch/powerpc/boot/dts/xpedite5301.dts +++ b/arch/powerpc/boot/dts/xpedite5301.dts @@ -547,14 +547,14 @@ tlu@2f000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x2f000 0x1000>; - interupts = <61 2 >; + interrupts = <61 2>; interrupt-parent = <&mpic>; }; tlu@15000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x15000 0x1000>; - interupts = <75 2>; + interrupts = <75 2>; interrupt-parent = <&mpic>; }; }; diff --git a/arch/powerpc/boot/dts/xpedite5330.dts b/arch/powerpc/boot/dts/xpedite5330.dts index 2152259..73f8620 100644 --- a/arch/powerpc/boot/dts/xpedite5330.dts +++ b/arch/powerpc/boot/dts/xpedite5330.dts @@ -583,14 +583,14 @@ tlu@2f000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x2f000 0x1000>; - interupts = <61 2 >; + interrupts = <61 2>; interrupt-parent = <&mpic>; }; tlu@15000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x15000 0x1000>; - interupts = <75 2>; + interrupts = <75 2>; interrupt-parent = <&mpic>; }; }; diff --git a/arch/powerpc/boot/dts/xpedite5370.dts b/arch/powerpc/boot/dts/xpedite5370.dts index 11dbda1..cd0ea2b 100644 --- a/arch/powerpc/boot/dts/xpedite5370.dts +++ b/arch/powerpc/boot/dts/xpedite5370.dts @@ -545,14 +545,14 @@ tlu@2f000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x2f000 0x1000>; - interupts = <61 2 >; + interrupts = <61 2>; interrupt-parent = <&mpic>; }; tlu@15000 { compatible = "fsl,mpc8572-tlu", "fsl_tlu"; reg = <0x15000 0x1000>; - interupts = <75 2>; + interrupts = <75 2>; interrupt-parent = <&mpic>; }; }; diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S index 5143228..6636b1d 100644 --- a/arch/powerpc/boot/util.S +++ b/arch/powerpc/boot/util.S @@ -71,18 +71,32 @@ udelay: add r4,r4,r5 addi r4,r4,-1 divw r4,r4,r5 /* BUS ticks */ +#ifdef CONFIG_8xx +1: mftbu r5 + mftb r6 + mftbu r7 +#else 1: mfspr r5, SPRN_TBRU mfspr r6, SPRN_TBRL mfspr r7, SPRN_TBRU +#endif cmpw 0,r5,r7 bne 1b /* Get [synced] base time */ addc r9,r6,r4 /* Compute end time */ addze r8,r5 +#ifdef CONFIG_8xx +2: mftbu r5 +#else 2: mfspr r5, SPRN_TBRU +#endif cmpw 0,r5,r8 blt 2b bgt 3f +#ifdef CONFIG_8xx + mftb r6 +#else mfspr r6, SPRN_TBRL +#endif cmpw 0,r6,r9 blt 2b 3: blr diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h index 16cb92d..6940128 100644 --- a/arch/powerpc/include/asm/pgalloc-64.h +++ b/arch/powerpc/include/asm/pgalloc-64.h @@ -16,6 +16,7 @@ struct vmemmap_backing { unsigned long phys; unsigned long virt_addr; }; +extern struct vmemmap_backing *vmemmap_list; /* * Functions that deal with pagetables that could be at any level of diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 3c1acc3..f595b98 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -366,6 +366,8 @@ BEGIN_FTR_SECTION_NESTED(96); \ cmpwi dest,0; \ beq- 90b; \ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) +#elif defined(CONFIG_8xx) +#define MFTB(dest) mftb dest #else #define MFTB(dest) mfspr dest, SPRN_TBRL #endif diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 5c45787..fa8388e 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1174,12 +1174,19 @@ #else /* __powerpc64__ */ +#if defined(CONFIG_8xx) +#define mftbl() ({unsigned long rval; \ + asm volatile("mftbl %0" : "=r" (rval)); rval;}) +#define mftbu() ({unsigned long rval; \ + asm volatile("mftbu %0" : "=r" (rval)); rval;}) +#else #define mftbl() ({unsigned long rval; \ asm volatile("mfspr %0, %1" : "=r" (rval) : \ "i" (SPRN_TBRL)); rval;}) #define mftbu() ({unsigned long rval; \ asm volatile("mfspr %0, %1" : "=r" (rval) : \ "i" (SPRN_TBRU)); rval;}) +#endif #endif /* !__powerpc64__ */ #define mttbl(v) asm volatile("mttbl %0":: "r"(v)) diff --git a/arch/powerpc/include/asm/timex.h b/arch/powerpc/include/asm/timex.h index 18908ca..2cf846e 100644 --- a/arch/powerpc/include/asm/timex.h +++ b/arch/powerpc/include/asm/timex.h @@ -29,7 +29,11 @@ static inline cycles_t get_cycles(void) ret = 0; __asm__ __volatile__( +#ifdef CONFIG_8xx + "97: mftb %0\n" +#else "97: mfspr %0, %2\n" +#endif "99:\n" ".section __ftr_fixup,\"a\"\n" ".align 2\n" @@ -41,7 +45,11 @@ static inline cycles_t get_cycles(void) " .long 0\n" " .long 0\n" ".previous" +#ifdef CONFIG_8xx + : "=r" (ret) : "i" (CPU_FTR_601)); +#else : "=r" (ret) : "i" (CPU_FTR_601), "i" (SPRN_TBRL)); +#endif return ret; #endif } diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index e1ec57e..88a7fb4 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -18,6 +18,7 @@ #include <linux/ftrace.h> #include <asm/machdep.h> +#include <asm/pgalloc.h> #include <asm/prom.h> #include <asm/sections.h> @@ -75,6 +76,17 @@ void arch_crash_save_vmcoreinfo(void) #ifndef CONFIG_NEED_MULTIPLE_NODES VMCOREINFO_SYMBOL(contig_page_data); #endif +#if defined(CONFIG_PPC64) && defined(CONFIG_SPARSEMEM_VMEMMAP) + VMCOREINFO_SYMBOL(vmemmap_list); + VMCOREINFO_SYMBOL(mmu_vmemmap_psize); + VMCOREINFO_SYMBOL(mmu_psize_defs); + VMCOREINFO_STRUCT_SIZE(vmemmap_backing); + VMCOREINFO_OFFSET(vmemmap_backing, list); + VMCOREINFO_OFFSET(vmemmap_backing, phys); + VMCOREINFO_OFFSET(vmemmap_backing, virt_addr); + VMCOREINFO_STRUCT_SIZE(mmu_psize_def); + VMCOREINFO_OFFSET(mmu_psize_def, shift); +#endif } /* diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index fd82c28..28b898e 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -210,7 +210,7 @@ static void __init nvram_print_partitions(char * label) printk(KERN_WARNING "--------%s---------\n", label); printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); list_for_each_entry(tmp_part, &nvram_partitions, partition) { - printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12s\n", + printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12.12s\n", tmp_part->index, tmp_part->header.signature, tmp_part->header.checksum, tmp_part->header.length, tmp_part->header.name); diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 1844298..68027bf 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -445,6 +445,12 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, #endif /* CONFIG_ALTIVEC */ if (copy_fpr_to_user(&frame->mc_fregs, current)) return 1; + + /* + * Clear the MSR VSX bit to indicate there is no valid state attached + * to this context, except in the specific case below where we set it. + */ + msr &= ~MSR_VSX; #ifdef CONFIG_VSX /* * Copy VSR 0-31 upper half from thread_struct to local @@ -457,15 +463,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, if (copy_vsx_to_user(&frame->mc_vsregs, current)) return 1; msr |= MSR_VSX; - } else if (!ctx_has_vsx_region) - /* - * With a small context structure we can't hold the VSX - * registers, hence clear the MSR value to indicate the state - * was not saved. - */ - msr &= ~MSR_VSX; - - + } #endif /* CONFIG_VSX */ #ifdef CONFIG_SPE /* save spe registers */ diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index e66f67b..4299104 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -122,6 +122,12 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, flush_fp_to_thread(current); /* copy fpr regs and fpscr */ err |= copy_fpr_to_user(&sc->fp_regs, current); + + /* + * Clear the MSR VSX bit to indicate there is no valid state attached + * to this context, except in the specific case below where we set it. + */ + msr &= ~MSR_VSX; #ifdef CONFIG_VSX /* * Copy VSX low doubleword to local buffer for formatting, diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S index 6b1f2a6..6b2b696 100644 --- a/arch/powerpc/kernel/vdso32/gettimeofday.S +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S @@ -232,9 +232,15 @@ __do_get_tspec: lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) /* Get a stable TB value */ +#ifdef CONFIG_8xx +2: mftbu r3 + mftbl r4 + mftbu r0 +#else 2: mfspr r3, SPRN_TBRU mfspr r4, SPRN_TBRL mfspr r0, SPRN_TBRU +#endif cmplw cr0,r3,r0 bne- 2b diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 3bc7006..74551b5 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -117,6 +117,5 @@ void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr) struct hstate *hstate = hstate_file(vma->vm_file); unsigned long tsize = huge_page_shift(hstate) - 10; - __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr, tsize, 0); - + __flush_tlb_page(vma->vm_mm, vmaddr, tsize, 0); } diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 41cd68d..358d743 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -305,7 +305,7 @@ void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { #ifdef CONFIG_HUGETLB_PAGE - if (is_vm_hugetlb_page(vma)) + if (vma && is_vm_hugetlb_page(vma)) flush_hugetlb_page(vma, vmaddr); #endif diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 132f872..bca2465 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -404,13 +404,27 @@ config PPC_DOORBELL endmenu -config CPU_LITTLE_ENDIAN - bool "Build little endian kernel" - default n +choice + prompt "Endianness selection" + default CPU_BIG_ENDIAN help This option selects whether a big endian or little endian kernel will be built. +config CPU_BIG_ENDIAN + bool "Build big endian kernel" + help + Build a big endian kernel. + + If unsure, select this option. + +config CPU_LITTLE_ENDIAN + bool "Build little endian kernel" + help + Build a little endian kernel. + Note that if cross compiling a little endian kernel, CROSS_COMPILE must point to a toolchain capable of targeting little endian powerpc. + +endchoice diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 314fced..5877e71 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -101,7 +101,7 @@ config S390 select GENERIC_CPU_DEVICES if !SMP select GENERIC_FIND_FIRST_BIT select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL_OLD + select GENERIC_TIME_VSYSCALL select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 select HAVE_ARCH_SECCOMP_FILTER diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 46cae13..4363528 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -35,7 +35,6 @@ static u8 *ctrblk; static char keylen_flag; struct s390_aes_ctx { - u8 iv[AES_BLOCK_SIZE]; u8 key[AES_MAX_KEY_SIZE]; long enc; long dec; @@ -441,30 +440,36 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, return aes_set_key(tfm, in_key, key_len); } -static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param, +static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, struct blkcipher_walk *walk) { + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes = walk->nbytes; + struct { + u8 iv[AES_BLOCK_SIZE]; + u8 key[AES_MAX_KEY_SIZE]; + } param; if (!nbytes) goto out; - memcpy(param, walk->iv, AES_BLOCK_SIZE); + memcpy(param.iv, walk->iv, AES_BLOCK_SIZE); + memcpy(param.key, sctx->key, sctx->key_len); do { /* only use complete blocks */ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_kmc(func, param, out, in, n); + ret = crypt_s390_kmc(func, ¶m, out, in, n); if (ret < 0 || ret != n) return -EIO; nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, walk, nbytes); } while ((nbytes = walk->nbytes)); - memcpy(walk->iv, param, AES_BLOCK_SIZE); + memcpy(walk->iv, param.iv, AES_BLOCK_SIZE); out: return ret; @@ -481,7 +486,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, return fallback_blk_enc(desc, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk); + return cbc_aes_crypt(desc, sctx->enc, &walk); } static int cbc_aes_decrypt(struct blkcipher_desc *desc, @@ -495,7 +500,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, return fallback_blk_dec(desc, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk); + return cbc_aes_crypt(desc, sctx->dec, &walk); } static struct crypto_alg cbc_aes_alg = { diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 316c850..114258e 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -48,33 +48,21 @@ static inline void clear_page(void *page) : "memory", "cc"); } +/* + * copy_page uses the mvcl instruction with 0xb0 padding byte in order to + * bypass caches when copying a page. Especially when copying huge pages + * this keeps L1 and L2 data caches alive. + */ static inline void copy_page(void *to, void *from) { - if (MACHINE_HAS_MVPG) { - register unsigned long reg0 asm ("0") = 0; - asm volatile( - " mvpg %0,%1" - : : "a" (to), "a" (from), "d" (reg0) - : "memory", "cc"); - } else - asm volatile( - " mvc 0(256,%0),0(%1)\n" - " mvc 256(256,%0),256(%1)\n" - " mvc 512(256,%0),512(%1)\n" - " mvc 768(256,%0),768(%1)\n" - " mvc 1024(256,%0),1024(%1)\n" - " mvc 1280(256,%0),1280(%1)\n" - " mvc 1536(256,%0),1536(%1)\n" - " mvc 1792(256,%0),1792(%1)\n" - " mvc 2048(256,%0),2048(%1)\n" - " mvc 2304(256,%0),2304(%1)\n" - " mvc 2560(256,%0),2560(%1)\n" - " mvc 2816(256,%0),2816(%1)\n" - " mvc 3072(256,%0),3072(%1)\n" - " mvc 3328(256,%0),3328(%1)\n" - " mvc 3584(256,%0),3584(%1)\n" - " mvc 3840(256,%0),3840(%1)\n" - : : "a" (to), "a" (from) : "memory"); + register void *reg2 asm ("2") = to; + register unsigned long reg3 asm ("3") = 0x1000; + register void *reg4 asm ("4") = from; + register unsigned long reg5 asm ("5") = 0xb0001000; + asm volatile( + " mvcl 2,4" + : "+d" (reg2), "+d" (reg3), "+d" (reg4), "+d" (reg5) + : : "memory", "cc"); } #define clear_user_page(page, vaddr, pg) clear_page(page) diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index a73eb2e..bc9746a 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -26,8 +26,9 @@ struct vdso_data { __u64 wtom_clock_nsec; /* 0x28 */ __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ __u32 tz_dsttime; /* Type of dst correction 0x34 */ - __u32 ectg_available; - __u32 ntp_mult; /* NTP adjusted multiplier 0x3C */ + __u32 ectg_available; /* ECTG instruction present 0x38 */ + __u32 tk_mult; /* Mult. used for xtime_nsec 0x3c */ + __u32 tk_shift; /* Shift used for xtime_nsec 0x40 */ }; struct vdso_per_cpu_data { diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 2416138..496116c 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -65,7 +65,8 @@ int main(void) DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available)); - DEFINE(__VDSO_NTP_MULT, offsetof(struct vdso_data, ntp_mult)); + DEFINE(__VDSO_TK_MULT, offsetof(struct vdso_data, tk_mult)); + DEFINE(__VDSO_TK_SHIFT, offsetof(struct vdso_data, tk_shift)); DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base)); DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time)); /* constants used by the vdso */ diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 6e24429..95e7ba0 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -194,7 +194,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) return -EINVAL; /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ - regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | + regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | (__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 | (__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 | (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE); diff --git a/arch/s390/kernel/pgm_check.S b/arch/s390/kernel/pgm_check.S index 4a460c4..813ec72 100644 --- a/arch/s390/kernel/pgm_check.S +++ b/arch/s390/kernel/pgm_check.S @@ -78,7 +78,7 @@ PGM_CHECK_DEFAULT /* 34 */ PGM_CHECK_DEFAULT /* 35 */ PGM_CHECK_DEFAULT /* 36 */ PGM_CHECK_DEFAULT /* 37 */ -PGM_CHECK_DEFAULT /* 38 */ +PGM_CHECK_64BIT(do_dat_exception) /* 38 */ PGM_CHECK_64BIT(do_dat_exception) /* 39 */ PGM_CHECK_64BIT(do_dat_exception) /* 3a */ PGM_CHECK_64BIT(do_dat_exception) /* 3b */ diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index fb53587..d8fd508 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -94,7 +94,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) return -EINVAL; /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ - regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | + regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); /* Check for invalid user address space control. */ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 064c308..dd95f163 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -108,20 +108,10 @@ static void fixup_clock_comparator(unsigned long long delta) set_clock_comparator(S390_lowcore.clock_comparator); } -static int s390_next_ktime(ktime_t expires, +static int s390_next_event(unsigned long delta, struct clock_event_device *evt) { - struct timespec ts; - u64 nsecs; - - ts.tv_sec = ts.tv_nsec = 0; - monotonic_to_bootbased(&ts); - nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires)); - do_div(nsecs, 125); - S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9); - /* Program the maximum value if we have an overflow (== year 2042) */ - if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc)) - S390_lowcore.clock_comparator = -1ULL; + S390_lowcore.clock_comparator = get_tod_clock() + delta; set_clock_comparator(S390_lowcore.clock_comparator); return 0; } @@ -146,15 +136,14 @@ void init_cpu_timer(void) cpu = smp_processor_id(); cd = &per_cpu(comparators, cpu); cd->name = "comparator"; - cd->features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_KTIME; + cd->features = CLOCK_EVT_FEAT_ONESHOT; cd->mult = 16777; cd->shift = 12; cd->min_delta_ns = 1; cd->max_delta_ns = LONG_MAX; cd->rating = 400; cd->cpumask = cpumask_of(cpu); - cd->set_next_ktime = s390_next_ktime; + cd->set_next_event = s390_next_event; cd->set_mode = s390_set_mode; clockevents_register_device(cd); @@ -221,21 +210,30 @@ struct clocksource * __init clocksource_default_clock(void) return &clocksource_tod; } -void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, - struct clocksource *clock, u32 mult) +void update_vsyscall(struct timekeeper *tk) { - if (clock != &clocksource_tod) + u64 nsecps; + + if (tk->clock != &clocksource_tod) return; /* Make userspace gettimeofday spin until we're done. */ ++vdso_data->tb_update_count; smp_wmb(); - vdso_data->xtime_tod_stamp = clock->cycle_last; - vdso_data->xtime_clock_sec = wall_time->tv_sec; - vdso_data->xtime_clock_nsec = wall_time->tv_nsec; - vdso_data->wtom_clock_sec = wtm->tv_sec; - vdso_data->wtom_clock_nsec = wtm->tv_nsec; - vdso_data->ntp_mult = mult; + vdso_data->xtime_tod_stamp = tk->clock->cycle_last; + vdso_data->xtime_clock_sec = tk->xtime_sec; + vdso_data->xtime_clock_nsec = tk->xtime_nsec; + vdso_data->wtom_clock_sec = + tk->xtime_sec + tk->wall_to_monotonic.tv_sec; + vdso_data->wtom_clock_nsec = tk->xtime_nsec + + + (tk->wall_to_monotonic.tv_nsec << tk->shift); + nsecps = (u64) NSEC_PER_SEC << tk->shift; + while (vdso_data->wtom_clock_nsec >= nsecps) { + vdso_data->wtom_clock_nsec -= nsecps; + vdso_data->wtom_clock_sec++; + } + vdso_data->tk_mult = tk->mult; + vdso_data->tk_shift = tk->shift; smp_wmb(); ++vdso_data->tb_update_count; } diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S index b2224e0..5be8e47 100644 --- a/arch/s390/kernel/vdso32/clock_gettime.S +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -38,25 +38,26 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,2f ahi %r0,-1 -2: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ +2: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */ lr %r2,%r0 - l %r0,__VDSO_NTP_MULT(%r5) + l %r0,__VDSO_TK_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 3f - a %r0,__VDSO_NTP_MULT(%r5) + a %r0,__VDSO_TK_MULT(%r5) 3: alr %r0,%r2 - srdl %r0,12 - al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + al %r0,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ al %r1,__VDSO_XTIME_NSEC+4(%r5) brc 12,4f ahi %r0,1 -4: l %r2,__VDSO_XTIME_SEC+4(%r5) - al %r0,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */ +4: al %r0,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic.nsec */ al %r1,__VDSO_WTOM_NSEC+4(%r5) brc 12,5f ahi %r0,1 -5: al %r2,__VDSO_WTOM_SEC+4(%r5) +5: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ + srdl %r0,0(%r2) /* >> tk->shift */ + l %r2,__VDSO_XTIME_SEC+4(%r5) + al %r2,__VDSO_WTOM_SEC+4(%r5) cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ jne 1b basr %r5,0 @@ -86,20 +87,21 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,12f ahi %r0,-1 -12: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ +12: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */ lr %r2,%r0 - l %r0,__VDSO_NTP_MULT(%r5) + l %r0,__VDSO_TK_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 13f - a %r0,__VDSO_NTP_MULT(%r5) + a %r0,__VDSO_TK_MULT(%r5) 13: alr %r0,%r2 - srdl %r0,12 - al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ + al %r0,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ al %r1,__VDSO_XTIME_NSEC+4(%r5) brc 12,14f ahi %r0,1 -14: l %r2,__VDSO_XTIME_SEC+4(%r5) +14: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ + srdl %r0,0(%r2) /* >> tk->shift */ + l %r2,__VDSO_XTIME_SEC+4(%r5) cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ jne 11b basr %r5,0 diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S index 2d36331..fd621a9 100644 --- a/arch/s390/kernel/vdso32/gettimeofday.S +++ b/arch/s390/kernel/vdso32/gettimeofday.S @@ -35,15 +35,14 @@ __kernel_gettimeofday: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,3f ahi %r0,-1 -3: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ +3: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */ st %r0,24(%r15) - l %r0,__VDSO_NTP_MULT(%r5) + l %r0,__VDSO_TK_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 4f - a %r0,__VDSO_NTP_MULT(%r5) + a %r0,__VDSO_TK_MULT(%r5) 4: al %r0,24(%r15) - srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ al %r1,__VDSO_XTIME_NSEC+4(%r5) brc 12,5f @@ -51,6 +50,8 @@ __kernel_gettimeofday: 5: mvc 24(4,%r15),__VDSO_XTIME_SEC+4(%r5) cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ jne 1b + l %r4,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ + srdl %r0,0(%r4) /* >> tk->shift */ l %r4,24(%r15) /* get tv_sec from stack */ basr %r5,0 6: ltr %r0,%r0 diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index d46c95e..0add107 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -34,14 +34,15 @@ __kernel_clock_gettime: tmll %r4,0x0001 /* pending update ? loop */ jnz 0b stck 48(%r15) /* Store TOD clock */ + lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ + lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */ + alg %r0,__VDSO_WTOM_SEC(%r5) /* + wall_to_monotonic.sec */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ - srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ - alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ - lg %r0,__VDSO_XTIME_SEC(%r5) - alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */ - alg %r0,__VDSO_WTOM_SEC(%r5) + msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ + alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic.nsec */ + srlg %r1,%r1,0(%r2) /* >> tk->shift */ clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ jne 0b larl %r5,13f @@ -62,12 +63,13 @@ __kernel_clock_gettime: tmll %r4,0x0001 /* pending update ? loop */ jnz 5b stck 48(%r15) /* Store TOD clock */ + lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ - srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ - alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ - lg %r0,__VDSO_XTIME_SEC(%r5) + msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ + srlg %r1,%r1,0(%r2) /* >> tk->shift */ + lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */ clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ jne 5b larl %r5,13f diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S index 36ee674..d0860d1 100644 --- a/arch/s390/kernel/vdso64/gettimeofday.S +++ b/arch/s390/kernel/vdso64/gettimeofday.S @@ -31,12 +31,13 @@ __kernel_gettimeofday: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ - srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ - alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */ - lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */ + msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ + alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ + lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */ clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */ jne 0b + lgf %r5,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ + srlg %r1,%r1,0(%r5) /* >> tk->shift */ larl %r5,5f 2: clg %r1,0(%r5) jl 3f diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 97e03ca..dbdab3e 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -78,11 +78,14 @@ static size_t copy_in_kernel(size_t count, void __user *to, * contains the (negative) exception code. */ #ifdef CONFIG_64BIT + static unsigned long follow_table(struct mm_struct *mm, unsigned long address, int write) { unsigned long *table = (unsigned long *)__pa(mm->pgd); + if (unlikely(address > mm->context.asce_limit - 1)) + return -0x38UL; switch (mm->context.asce_bits & _ASCE_TYPE_MASK) { case _ASCE_TYPE_REGION1: table = table + ((address >> 53) & 0x7ff); diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 7d6ba9d..e0fc24d 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -3,8 +3,9 @@ # avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no) +avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ + $(comma)4)$(comma)%ymm2,yes,no) -obj-$(CONFIG_CRYPTO_ABLK_HELPER_X86) += ablk_helper.o obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index f80e668..835488b 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -34,7 +34,7 @@ #include <asm/cpu_device_id.h> #include <asm/i387.h> #include <asm/crypto/aes.h> -#include <asm/crypto/ablk_helper.h> +#include <crypto/ablk_helper.h> #include <crypto/scatterwalk.h> #include <crypto/internal/aead.h> #include <linux/workqueue.h> diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c index 414fe5d..4209a76 100644 --- a/arch/x86/crypto/camellia_aesni_avx2_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/ctr.h> #include <crypto/lrw.h> @@ -21,7 +22,6 @@ #include <asm/xcr.h> #include <asm/xsave.h> #include <asm/crypto/camellia.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #define CAMELLIA_AESNI_PARALLEL_BLOCKS 16 diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c index 37fd0c0..87a041a 100644 --- a/arch/x86/crypto/camellia_aesni_avx_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx_glue.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/ctr.h> #include <crypto/lrw.h> @@ -21,7 +22,6 @@ #include <asm/xcr.h> #include <asm/xsave.h> #include <asm/crypto/camellia.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #define CAMELLIA_AESNI_PARALLEL_BLOCKS 16 diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c index c6631813..e6a3700 100644 --- a/arch/x86/crypto/cast5_avx_glue.c +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -26,13 +26,13 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/cast5.h> #include <crypto/cryptd.h> #include <crypto/ctr.h> #include <asm/xcr.h> #include <asm/xsave.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #define CAST5_PARALLEL_BLOCKS 16 diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c index 8d0dfb8..09f3677 100644 --- a/arch/x86/crypto/cast6_avx_glue.c +++ b/arch/x86/crypto/cast6_avx_glue.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/cast6.h> #include <crypto/cryptd.h> @@ -37,7 +38,6 @@ #include <crypto/xts.h> #include <asm/xcr.h> #include <asm/xsave.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #define CAST6_PARALLEL_BLOCKS 8 diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c index 23aabc6..2fae489 100644 --- a/arch/x86/crypto/serpent_avx2_glue.c +++ b/arch/x86/crypto/serpent_avx2_glue.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/ctr.h> #include <crypto/lrw.h> @@ -22,7 +23,6 @@ #include <asm/xcr.h> #include <asm/xsave.h> #include <asm/crypto/serpent-avx.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #define SERPENT_AVX2_PARALLEL_BLOCKS 16 diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c index 9ae83cf..ff48708 100644 --- a/arch/x86/crypto/serpent_avx_glue.c +++ b/arch/x86/crypto/serpent_avx_glue.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/serpent.h> #include <crypto/cryptd.h> @@ -38,7 +39,6 @@ #include <asm/xcr.h> #include <asm/xsave.h> #include <asm/crypto/serpent-avx.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> /* 8-way parallel cipher functions */ diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index 97a356e..8c95f86 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -34,6 +34,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/serpent.h> #include <crypto/cryptd.h> @@ -42,7 +43,6 @@ #include <crypto/lrw.h> #include <crypto/xts.h> #include <asm/crypto/serpent-sse2.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 50226c4..f248546 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -281,7 +281,7 @@ static int __init sha256_ssse3_mod_init(void) /* allow AVX to override SSSE3, it's a little faster */ if (avx_usable()) { #ifdef CONFIG_AS_AVX2 - if (boot_cpu_has(X86_FEATURE_AVX2)) + if (boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_BMI2)) sha256_transform_asm = sha256_transform_rorx; else #endif @@ -319,4 +319,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, Supplemental SSE3 accelerated"); MODULE_ALIAS("sha256"); -MODULE_ALIAS("sha384"); +MODULE_ALIAS("sha224"); diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c index a62ba54..4e3c665 100644 --- a/arch/x86/crypto/twofish_avx_glue.c +++ b/arch/x86/crypto/twofish_avx_glue.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/ablk_helper.h> #include <crypto/algapi.h> #include <crypto/twofish.h> #include <crypto/cryptd.h> @@ -39,7 +40,6 @@ #include <asm/xcr.h> #include <asm/xsave.h> #include <asm/crypto/twofish.h> -#include <asm/crypto/ablk_helper.h> #include <asm/crypto/glue_helper.h> #include <crypto/scatterwalk.h> #include <linux/workqueue.h> diff --git a/arch/x86/include/asm/simd.h b/arch/x86/include/asm/simd.h new file mode 100644 index 0000000..ee80b92 --- /dev/null +++ b/arch/x86/include/asm/simd.h @@ -0,0 +1,11 @@ + +#include <asm/i387.h> + +/* + * may_use_simd - whether it is allowable at this time to issue SIMD + * instructions or access the SIMD register file + */ +static __must_check inline bool may_use_simd(void) +{ + return irq_fpu_usable(); +} diff --git a/crypto/Kconfig b/crypto/Kconfig index 4ae5734..7bcb70d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -174,9 +174,8 @@ config CRYPTO_TEST help Quick & dirty crypto test module. -config CRYPTO_ABLK_HELPER_X86 +config CRYPTO_ABLK_HELPER tristate - depends on X86 select CRYPTO_CRYPTD config CRYPTO_GLUE_HELPER_X86 @@ -695,7 +694,7 @@ config CRYPTO_AES_NI_INTEL select CRYPTO_AES_X86_64 if 64BIT select CRYPTO_AES_586 if !64BIT select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_ALGAPI select CRYPTO_GLUE_HELPER_X86 if 64BIT select CRYPTO_LRW @@ -895,7 +894,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 depends on CRYPTO select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_CAMELLIA_X86_64 select CRYPTO_LRW @@ -917,7 +916,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 depends on CRYPTO select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_CAMELLIA_X86_64 select CRYPTO_CAMELLIA_AESNI_AVX_X86_64 @@ -969,7 +968,7 @@ config CRYPTO_CAST5_AVX_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_CAST_COMMON select CRYPTO_CAST5 help @@ -992,7 +991,7 @@ config CRYPTO_CAST6_AVX_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_CAST_COMMON select CRYPTO_CAST6 @@ -1110,7 +1109,7 @@ config CRYPTO_SERPENT_SSE2_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT select CRYPTO_LRW @@ -1132,7 +1131,7 @@ config CRYPTO_SERPENT_SSE2_586 depends on X86 && !64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT select CRYPTO_LRW @@ -1154,7 +1153,7 @@ config CRYPTO_SERPENT_AVX_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT select CRYPTO_LRW @@ -1176,7 +1175,7 @@ config CRYPTO_SERPENT_AVX2_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT select CRYPTO_SERPENT_AVX_X86_64 @@ -1292,7 +1291,7 @@ config CRYPTO_TWOFISH_AVX_X86_64 depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_ABLK_HELPER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_TWOFISH_COMMON select CRYPTO_TWOFISH_X86_64 diff --git a/crypto/Makefile b/crypto/Makefile index b3a7e80..989c510 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,8 +2,13 @@ # Cryptographic API # +# memneq MUST be built with -Os or -O0 to prevent early-return optimizations +# that will defeat memneq's actual purpose to prevent timing attacks. +CFLAGS_REMOVE_memneq.o := -O1 -O2 -O3 +CFLAGS_memneq.o := -Os + obj-$(CONFIG_CRYPTO) += crypto.o -crypto-y := api.o cipher.o compress.o +crypto-y := api.o cipher.o compress.o memneq.o obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o @@ -105,3 +110,4 @@ obj-$(CONFIG_XOR_BLOCKS) += xor.o obj-$(CONFIG_ASYNC_CORE) += async_tx/ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o +obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o diff --git a/arch/x86/crypto/ablk_helper.c b/crypto/ablk_helper.c index 43282fe..ffe7278 100644 --- a/arch/x86/crypto/ablk_helper.c +++ b/crypto/ablk_helper.c @@ -28,10 +28,11 @@ #include <linux/crypto.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/hardirq.h> #include <crypto/algapi.h> #include <crypto/cryptd.h> -#include <asm/i387.h> -#include <asm/crypto/ablk_helper.h> +#include <crypto/ablk_helper.h> +#include <asm/simd.h> int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) @@ -70,11 +71,11 @@ int ablk_encrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); - if (!irq_fpu_usable()) { + if (!may_use_simd()) { struct ablkcipher_request *cryptd_req = ablkcipher_request_ctx(req); - memcpy(cryptd_req, req, sizeof(*req)); + *cryptd_req = *req; ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); return crypto_ablkcipher_encrypt(cryptd_req); @@ -89,11 +90,11 @@ int ablk_decrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); - if (!irq_fpu_usable()) { + if (!may_use_simd()) { struct ablkcipher_request *cryptd_req = ablkcipher_request_ctx(req); - memcpy(cryptd_req, req, sizeof(*req)); + *cryptd_req = *req; ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); return crypto_ablkcipher_decrypt(cryptd_req); diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 7d4a8d2..40886c4 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -16,9 +16,7 @@ #include <crypto/internal/skcipher.h> #include <linux/cpumask.h> #include <linux/err.h> -#include <linux/init.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/rtnetlink.h> #include <linux/sched.h> #include <linux/slab.h> @@ -30,8 +28,6 @@ #include "internal.h" -static const char *skcipher_default_geniv __read_mostly; - struct ablkcipher_buffer { struct list_head entry; struct scatter_walk dst; @@ -527,8 +523,7 @@ const char *crypto_default_geniv(const struct crypto_alg *alg) alg->cra_blocksize) return "chainiv"; - return alg->cra_flags & CRYPTO_ALG_ASYNC ? - "eseqiv" : skcipher_default_geniv; + return "eseqiv"; } static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask) @@ -709,17 +704,3 @@ err: return ERR_PTR(err); } EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher); - -static int __init skcipher_module_init(void) -{ - skcipher_default_geniv = num_possible_cpus() > 1 ? - "eseqiv" : "chainiv"; - return 0; -} - -static void skcipher_module_exit(void) -{ -} - -module_init(skcipher_module_init); -module_exit(skcipher_module_exit); diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index c0bb377..666f196 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -230,11 +230,11 @@ remainder: */ if (byte_count < DEFAULT_BLK_SZ) { empty_rbuf: - for (; ctx->rand_data_valid < DEFAULT_BLK_SZ; - ctx->rand_data_valid++) { + while (ctx->rand_data_valid < DEFAULT_BLK_SZ) { *ptr = ctx->rand_data[ctx->rand_data_valid]; ptr++; byte_count--; + ctx->rand_data_valid++; if (byte_count == 0) goto done; } diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 90a17f5..459cf97 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <crypto/algapi.h> #include "public_key.h" MODULE_LICENSE("GPL"); @@ -189,12 +190,12 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, } } - if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { + if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) { kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); return -EBADMSG; } - if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { + if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) { kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); return -EKEYREJECTED; } diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index f83300b..382ef0d 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -18,60 +18,12 @@ #include <linux/asn1_decoder.h> #include <keys/asymmetric-subtype.h> #include <keys/asymmetric-parser.h> -#include <keys/system_keyring.h> #include <crypto/hash.h> #include "asymmetric_keys.h" #include "public_key.h" #include "x509_parser.h" /* - * Find a key in the given keyring by issuer and authority. - */ -static struct key *x509_request_asymmetric_key( - struct key *keyring, - const char *signer, size_t signer_len, - const char *authority, size_t auth_len) -{ - key_ref_t key; - char *id; - - /* Construct an identifier. */ - id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); - if (!id) - return ERR_PTR(-ENOMEM); - - memcpy(id, signer, signer_len); - id[signer_len + 0] = ':'; - id[signer_len + 1] = ' '; - memcpy(id + signer_len + 2, authority, auth_len); - id[signer_len + 2 + auth_len] = 0; - - pr_debug("Look up: \"%s\"\n", id); - - key = keyring_search(make_key_ref(keyring, 1), - &key_type_asymmetric, id); - if (IS_ERR(key)) - pr_debug("Request for module key '%s' err %ld\n", - id, PTR_ERR(key)); - kfree(id); - - if (IS_ERR(key)) { - switch (PTR_ERR(key)) { - /* Hide some search errors */ - case -EACCES: - case -ENOTDIR: - case -EAGAIN: - return ERR_PTR(-ENOKEY); - default: - return ERR_CAST(key); - } - } - - pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); - return key_ref_to_ptr(key); -} - -/* * Set up the signature parameters in an X.509 certificate. This involves * digesting the signed data and extracting the signature. */ @@ -151,33 +103,6 @@ int x509_check_signature(const struct public_key *pub, EXPORT_SYMBOL_GPL(x509_check_signature); /* - * Check the new certificate against the ones in the trust keyring. If one of - * those is the signing key and validates the new certificate, then mark the - * new certificate as being trusted. - * - * Return 0 if the new certificate was successfully validated, 1 if we couldn't - * find a matching parent certificate in the trusted list and an error if there - * is a matching certificate but the signature check fails. - */ -static int x509_validate_trust(struct x509_certificate *cert, - struct key *trust_keyring) -{ - const struct public_key *pk; - struct key *key; - int ret = 1; - - key = x509_request_asymmetric_key(trust_keyring, - cert->issuer, strlen(cert->issuer), - cert->authority, - strlen(cert->authority)); - if (!IS_ERR(key)) { - pk = key->payload.data; - ret = x509_check_signature(pk, cert); - } - return ret; -} - -/* * Attempt to parse a data blob for a key as an X509 certificate. */ static int x509_key_preparse(struct key_preparsed_payload *prep) @@ -230,13 +155,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) /* Check the signature on the key if it appears to be self-signed */ if (!cert->authority || strcmp(cert->fingerprint, cert->authority) == 0) { - ret = x509_check_signature(cert->pub, cert); /* self-signed */ + ret = x509_check_signature(cert->pub, cert); if (ret < 0) goto error_free_cert; - } else { - ret = x509_validate_trust(cert, system_trusted_keyring); - if (!ret) - prep->trusted = 1; } /* Propose a description */ diff --git a/crypto/authenc.c b/crypto/authenc.c index ffce19d..1875e70 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -52,40 +52,52 @@ static void authenc_request_complete(struct aead_request *req, int err) aead_request_complete(req, err); } -static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, - unsigned int keylen) +int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key, + unsigned int keylen) { - unsigned int authkeylen; - unsigned int enckeylen; - struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - struct crypto_ahash *auth = ctx->auth; - struct crypto_ablkcipher *enc = ctx->enc; - struct rtattr *rta = (void *)key; + struct rtattr *rta = (struct rtattr *)key; struct crypto_authenc_key_param *param; - int err = -EINVAL; if (!RTA_OK(rta, keylen)) - goto badkey; + return -EINVAL; if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; + return -EINVAL; if (RTA_PAYLOAD(rta) < sizeof(*param)) - goto badkey; + return -EINVAL; param = RTA_DATA(rta); - enckeylen = be32_to_cpu(param->enckeylen); + keys->enckeylen = be32_to_cpu(param->enckeylen); key += RTA_ALIGN(rta->rta_len); keylen -= RTA_ALIGN(rta->rta_len); - if (keylen < enckeylen) - goto badkey; + if (keylen < keys->enckeylen) + return -EINVAL; - authkeylen = keylen - enckeylen; + keys->authkeylen = keylen - keys->enckeylen; + keys->authkey = key; + keys->enckey = key + keys->authkeylen; + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_authenc_extractkeys); + +static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, + unsigned int keylen) +{ + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_ahash *auth = ctx->auth; + struct crypto_ablkcipher *enc = ctx->enc; + struct crypto_authenc_keys keys; + int err = -EINVAL; + + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) + goto badkey; crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) & CRYPTO_TFM_REQ_MASK); - err = crypto_ahash_setkey(auth, key, authkeylen); + err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) & CRYPTO_TFM_RES_MASK); @@ -95,7 +107,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) & CRYPTO_TFM_REQ_MASK); - err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen); + err = crypto_ablkcipher_setkey(enc, keys.enckey, keys.enckeylen); crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) & CRYPTO_TFM_RES_MASK); @@ -188,7 +200,7 @@ static void authenc_verify_ahash_update_done(struct crypto_async_request *areq, scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; + err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0; if (err) goto out; @@ -227,7 +239,7 @@ static void authenc_verify_ahash_done(struct crypto_async_request *areq, scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; + err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0; if (err) goto out; @@ -462,7 +474,7 @@ static int crypto_authenc_verify(struct aead_request *req, ihash = ohash + authsize; scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0; + return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0; } static int crypto_authenc_iverify(struct aead_request *req, u8 *iv, diff --git a/crypto/authencesn.c b/crypto/authencesn.c index ab53762..4be0dd4 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -59,37 +59,19 @@ static void authenc_esn_request_complete(struct aead_request *req, int err) static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key, unsigned int keylen) { - unsigned int authkeylen; - unsigned int enckeylen; struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); struct crypto_ahash *auth = ctx->auth; struct crypto_ablkcipher *enc = ctx->enc; - struct rtattr *rta = (void *)key; - struct crypto_authenc_key_param *param; + struct crypto_authenc_keys keys; int err = -EINVAL; - if (!RTA_OK(rta, keylen)) + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) - goto badkey; - - param = RTA_DATA(rta); - enckeylen = be32_to_cpu(param->enckeylen); - - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - - if (keylen < enckeylen) - goto badkey; - - authkeylen = keylen - enckeylen; crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) & CRYPTO_TFM_REQ_MASK); - err = crypto_ahash_setkey(auth, key, authkeylen); + err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); crypto_aead_set_flags(authenc_esn, crypto_ahash_get_flags(auth) & CRYPTO_TFM_RES_MASK); @@ -99,7 +81,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 * crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) & CRYPTO_TFM_REQ_MASK); - err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen); + err = crypto_ablkcipher_setkey(enc, keys.enckey, keys.enckeylen); crypto_aead_set_flags(authenc_esn, crypto_ablkcipher_get_flags(enc) & CRYPTO_TFM_RES_MASK); @@ -247,7 +229,7 @@ static void authenc_esn_verify_ahash_update_done(struct crypto_async_request *ar scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; + err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0; if (err) goto out; @@ -296,7 +278,7 @@ static void authenc_esn_verify_ahash_update_done2(struct crypto_async_request *a scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; + err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0; if (err) goto out; @@ -336,7 +318,7 @@ static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq, scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0; + err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0; if (err) goto out; @@ -568,7 +550,7 @@ static int crypto_authenc_esn_verify(struct aead_request *req) ihash = ohash + authsize; scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, authsize, 0); - return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0; + return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0; } static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, diff --git a/crypto/ccm.c b/crypto/ccm.c index 499c917..3e05499 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -363,7 +363,7 @@ static void crypto_ccm_decrypt_done(struct crypto_async_request *areq, if (!err) { err = crypto_ccm_auth(req, req->dst, cryptlen); - if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize)) + if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize)) err = -EBADMSG; } aead_request_complete(req, err); @@ -422,7 +422,7 @@ static int crypto_ccm_decrypt(struct aead_request *req) return err; /* verify */ - if (memcmp(authtag, odata, authsize)) + if (crypto_memneq(authtag, odata, authsize)) return -EBADMSG; return err; diff --git a/crypto/gcm.c b/crypto/gcm.c index 43e1fb0..b4f0179 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -582,7 +582,7 @@ static int crypto_gcm_verify(struct aead_request *req, crypto_xor(auth_tag, iauth_tag, 16); scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0); - return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; + return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; } static void gcm_decrypt_done(struct crypto_async_request *areq, int err) diff --git a/crypto/memneq.c b/crypto/memneq.c new file mode 100644 index 0000000..cd01622 --- /dev/null +++ b/crypto/memneq.c @@ -0,0 +1,138 @@ +/* + * Constant-time equality testing of memory regions. + * + * Authors: + * + * James Yonan <james@openvpn.net> + * Daniel Borkmann <dborkman@redhat.com> + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of OpenVPN Technologies nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <crypto/algapi.h> + +#ifndef __HAVE_ARCH_CRYPTO_MEMNEQ + +/* Generic path for arbitrary size */ +static inline unsigned long +__crypto_memneq_generic(const void *a, const void *b, size_t size) +{ + unsigned long neq = 0; + +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + while (size >= sizeof(unsigned long)) { + neq |= *(unsigned long *)a ^ *(unsigned long *)b; + a += sizeof(unsigned long); + b += sizeof(unsigned long); + size -= sizeof(unsigned long); + } +#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + while (size > 0) { + neq |= *(unsigned char *)a ^ *(unsigned char *)b; + a += 1; + b += 1; + size -= 1; + } + return neq; +} + +/* Loop-free fast-path for frequently used 16-byte size */ +static inline unsigned long __crypto_memneq_16(const void *a, const void *b) +{ +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (sizeof(unsigned long) == 8) + return ((*(unsigned long *)(a) ^ *(unsigned long *)(b)) + | (*(unsigned long *)(a+8) ^ *(unsigned long *)(b+8))); + else if (sizeof(unsigned int) == 4) + return ((*(unsigned int *)(a) ^ *(unsigned int *)(b)) + | (*(unsigned int *)(a+4) ^ *(unsigned int *)(b+4)) + | (*(unsigned int *)(a+8) ^ *(unsigned int *)(b+8)) + | (*(unsigned int *)(a+12) ^ *(unsigned int *)(b+12))); + else +#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + return ((*(unsigned char *)(a) ^ *(unsigned char *)(b)) + | (*(unsigned char *)(a+1) ^ *(unsigned char *)(b+1)) + | (*(unsigned char *)(a+2) ^ *(unsigned char *)(b+2)) + | (*(unsigned char *)(a+3) ^ *(unsigned char *)(b+3)) + | (*(unsigned char *)(a+4) ^ *(unsigned char *)(b+4)) + | (*(unsigned char *)(a+5) ^ *(unsigned char *)(b+5)) + | (*(unsigned char *)(a+6) ^ *(unsigned char *)(b+6)) + | (*(unsigned char *)(a+7) ^ *(unsigned char *)(b+7)) + | (*(unsigned char *)(a+8) ^ *(unsigned char *)(b+8)) + | (*(unsigned char *)(a+9) ^ *(unsigned char *)(b+9)) + | (*(unsigned char *)(a+10) ^ *(unsigned char *)(b+10)) + | (*(unsigned char *)(a+11) ^ *(unsigned char *)(b+11)) + | (*(unsigned char *)(a+12) ^ *(unsigned char *)(b+12)) + | (*(unsigned char *)(a+13) ^ *(unsigned char *)(b+13)) + | (*(unsigned char *)(a+14) ^ *(unsigned char *)(b+14)) + | (*(unsigned char *)(a+15) ^ *(unsigned char *)(b+15))); +} + +/* Compare two areas of memory without leaking timing information, + * and with special optimizations for common sizes. Users should + * not call this function directly, but should instead use + * crypto_memneq defined in crypto/algapi.h. + */ +noinline unsigned long __crypto_memneq(const void *a, const void *b, + size_t size) +{ + switch (size) { + case 16: + return __crypto_memneq_16(a, b); + default: + return __crypto_memneq_generic(a, b, size); + } +} +EXPORT_SYMBOL(__crypto_memneq); + +#endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */ diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index f691d0e..ff97430 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -184,7 +184,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, struct acpi_buffer *output_buffer); acpi_status -acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, +acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, struct acpi_buffer *output_buffer); acpi_status @@ -227,8 +227,8 @@ acpi_rs_get_list_length(u8 * aml_buffer, u32 aml_buffer_length, acpi_size * size_needed); acpi_status -acpi_rs_get_aml_length(struct acpi_resource *linked_list_buffer, - acpi_size * size_needed); +acpi_rs_get_aml_length(struct acpi_resource *resource_list, + acpi_size resource_list_size, acpi_size * size_needed); acpi_status acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 2437373..fd1ff54 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -106,6 +106,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) void acpi_ns_delete_node(struct acpi_namespace_node *node) { union acpi_operand_object *obj_desc; + union acpi_operand_object *next_desc; ACPI_FUNCTION_NAME(ns_delete_node); @@ -114,12 +115,13 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) acpi_ns_detach_object(node); /* - * Delete an attached data object if present (an object that was created - * and attached via acpi_attach_data). Note: After any normal object is - * detached above, the only possible remaining object is a data object. + * Delete an attached data object list if present (objects that were + * attached via acpi_attach_data). Note: After any normal object is + * detached above, the only possible remaining object(s) are data + * objects, in a linked list. */ obj_desc = node->object; - if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { + while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { /* Invoke the attached data deletion handler if present */ @@ -127,7 +129,15 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) obj_desc->data.handler(node, obj_desc->data.pointer); } + next_desc = obj_desc->common.next_object; acpi_ut_remove_reference(obj_desc); + obj_desc = next_desc; + } + + /* Special case for the statically allocated root node */ + + if (node == acpi_gbl_root_node) { + return; } /* Now we can delete the node */ diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index cc2fea9..4a0665b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -593,24 +593,26 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) void acpi_ns_terminate(void) { - union acpi_operand_object *obj_desc; + acpi_status status; ACPI_FUNCTION_TRACE(ns_terminate); /* - * 1) Free the entire namespace -- all nodes and objects - * - * Delete all object descriptors attached to namepsace nodes + * Free the entire namespace -- all nodes and all objects + * attached to the nodes */ acpi_ns_delete_namespace_subtree(acpi_gbl_root_node); - /* Detach any objects attached to the root */ + /* Delete any objects attached to the root node */ - obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node); - if (obj_desc) { - acpi_ns_detach_object(acpi_gbl_root_node); + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_VOID; } + acpi_ns_delete_node(acpi_gbl_root_node); + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n")); return_VOID; } diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index b62a0f4..b60c9cf 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -174,6 +174,7 @@ acpi_rs_stream_option_length(u32 resource_length, * FUNCTION: acpi_rs_get_aml_length * * PARAMETERS: resource - Pointer to the resource linked list + * resource_list_size - Size of the resource linked list * size_needed - Where the required size is returned * * RETURN: Status @@ -185,16 +186,20 @@ acpi_rs_stream_option_length(u32 resource_length, ******************************************************************************/ acpi_status -acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) +acpi_rs_get_aml_length(struct acpi_resource *resource, + acpi_size resource_list_size, acpi_size * size_needed) { acpi_size aml_size_needed = 0; + struct acpi_resource *resource_end; acpi_rs_length total_size; ACPI_FUNCTION_TRACE(rs_get_aml_length); /* Traverse entire list of internal resource descriptors */ - while (resource) { + resource_end = + ACPI_ADD_PTR(struct acpi_resource, resource, resource_list_size); + while (resource < resource_end) { /* Validate the descriptor type */ diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 65f3e1c..3a2ace9 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -418,22 +418,21 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, * * FUNCTION: acpi_rs_create_aml_resources * - * PARAMETERS: linked_list_buffer - Pointer to the resource linked list - * output_buffer - Pointer to the user's buffer + * PARAMETERS: resource_list - Pointer to the resource list buffer + * output_buffer - Where the AML buffer is returned * * RETURN: Status AE_OK if okay, else a valid acpi_status code. * If the output_buffer is too small, the error will be * AE_BUFFER_OVERFLOW and output_buffer->Length will point * to the size buffer needed. * - * DESCRIPTION: Takes the linked list of device resources and - * creates a bytestream to be used as input for the - * _SRS control method. + * DESCRIPTION: Converts a list of device resources to an AML bytestream + * to be used as input for the _SRS control method. * ******************************************************************************/ acpi_status -acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, +acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, struct acpi_buffer *output_buffer) { acpi_status status; @@ -441,16 +440,16 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, ACPI_FUNCTION_TRACE(rs_create_aml_resources); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "LinkedListBuffer = %p\n", - linked_list_buffer)); + /* Params already validated, no need to re-validate here */ - /* - * Params already validated, so we don't re-validate here - * - * Pass the linked_list_buffer into a module that calculates - * the buffer size needed for the byte stream. - */ - status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ResourceList Buffer = %p\n", + resource_list->pointer)); + + /* Get the buffer size needed for the AML byte stream */ + + status = acpi_rs_get_aml_length(resource_list->pointer, + resource_list->length, + &aml_size_needed); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", (u32)aml_size_needed, acpi_format_exception(status))); @@ -467,10 +466,9 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, /* Do the conversion */ - status = - acpi_rs_convert_resources_to_aml(linked_list_buffer, - aml_size_needed, - output_buffer->pointer); + status = acpi_rs_convert_resources_to_aml(resource_list->pointer, + aml_size_needed, + output_buffer->pointer); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index aef303d..14a7982 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -753,7 +753,7 @@ acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, * Convert the linked list into a byte stream */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_rs_create_aml_resources(in_buffer->pointer, &buffer); + status = acpi_rs_create_aml_resources(in_buffer, &buffer); if (ACPI_FAILURE(status)) { goto cleanup; } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 1a67b39..03ae8af 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -185,6 +185,7 @@ acpi_debug_print(u32 requested_debug_level, } acpi_gbl_prev_thread_id = thread_id; + acpi_gbl_nesting_level = 0; } /* @@ -193,13 +194,21 @@ acpi_debug_print(u32 requested_debug_level, */ acpi_os_printf("%9s-%04ld ", module_name, line_number); +#ifdef ACPI_EXEC_APP + /* + * For acpi_exec only, emit the thread ID and nesting level. + * Note: nesting level is really only useful during a single-thread + * execution. Otherwise, multiple threads will keep resetting the + * level. + */ if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf("[%u] ", (u32)thread_id); } - acpi_os_printf("[%02ld] %-22.22s: ", - acpi_gbl_nesting_level, - acpi_ut_trim_function_name(function_name)); + acpi_os_printf("[%02ld] ", acpi_gbl_nesting_level); +#endif + + acpi_os_printf("%-22.22s: ", acpi_ut_trim_function_name(function_name)); va_start(args, format); acpi_os_vprintf(format, args); @@ -420,7 +429,9 @@ acpi_ut_exit(u32 line_number, component_id, "%s\n", acpi_gbl_fn_exit_str); } - acpi_gbl_nesting_level--; + if (acpi_gbl_nesting_level) { + acpi_gbl_nesting_level--; + } } ACPI_EXPORT_SYMBOL(acpi_ut_exit) @@ -467,7 +478,9 @@ acpi_ut_status_exit(u32 line_number, } } - acpi_gbl_nesting_level--; + if (acpi_gbl_nesting_level) { + acpi_gbl_nesting_level--; + } } ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) @@ -504,7 +517,9 @@ acpi_ut_value_exit(u32 line_number, ACPI_FORMAT_UINT64(value)); } - acpi_gbl_nesting_level--; + if (acpi_gbl_nesting_level) { + acpi_gbl_nesting_level--; + } } ACPI_EXPORT_SYMBOL(acpi_ut_value_exit) @@ -540,7 +555,9 @@ acpi_ut_ptr_exit(u32 line_number, ptr); } - acpi_gbl_nesting_level--; + if (acpi_gbl_nesting_level) { + acpi_gbl_nesting_level--; + } } #endif diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 266bc58..386a9fe 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/acpi.h> #include <linux/acpi_io.h> -#include <acpi/acpiosxf.h> /* ACPI NVS regions, APEI may use it */ diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0703bff..20360e4 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -65,6 +65,9 @@ static struct acpi_scan_handler pci_root_handler = { .ids = root_device_ids, .attach = acpi_pci_root_add, .detach = acpi_pci_root_remove, + .hotplug = { + .ignore = true, + }, }; static DEFINE_MUTEX(osc_lock); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 15daa21..fd39459 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1772,7 +1772,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type) */ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler) { + if (handler && !handler->hotplug.ignore) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, acpi_hotplug_notify_cb, handler); break; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 14df305..721e949 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -525,7 +525,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) * generate wakeup events. */ if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { - acpi_event_status pwr_btn_status; + acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index db52936..6dbc3ca 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -309,7 +309,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr, sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", table_attr->instance); - table_attr->attr.size = 0; + table_attr->attr.size = table_header->length; table_attr->attr.read = acpi_table_show; table_attr->attr.attr.name = table_attr->name; table_attr->attr.attr.mode = 0400; @@ -354,8 +354,9 @@ static int acpi_tables_sysfs_init(void) { struct acpi_table_attr *table_attr; struct acpi_table_header *table_header = NULL; - int table_index = 0; - int result; + int table_index; + acpi_status status; + int ret; tables_kobj = kobject_create_and_add("tables", acpi_kobj); if (!tables_kobj) @@ -365,33 +366,34 @@ static int acpi_tables_sysfs_init(void) if (!dynamic_tables_kobj) goto err_dynamic_tables; - do { - result = acpi_get_table_by_index(table_index, &table_header); - if (!result) { - table_index++; - table_attr = NULL; - table_attr = - kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); - if (!table_attr) - return -ENOMEM; - - acpi_table_attr_init(table_attr, table_header); - result = - sysfs_create_bin_file(tables_kobj, - &table_attr->attr); - if (result) { - kfree(table_attr); - return result; - } else - list_add_tail(&table_attr->node, - &acpi_table_attr_list); + for (table_index = 0;; table_index++) { + status = acpi_get_table_by_index(table_index, &table_header); + + if (status == AE_BAD_PARAMETER) + break; + + if (ACPI_FAILURE(status)) + continue; + + table_attr = NULL; + table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL); + if (!table_attr) + return -ENOMEM; + + acpi_table_attr_init(table_attr, table_header); + ret = sysfs_create_bin_file(tables_kobj, &table_attr->attr); + if (ret) { + kfree(table_attr); + return ret; } - } while (!result); + list_add_tail(&table_attr->node, &acpi_table_attr_list); + } + kobject_uevent(tables_kobj, KOBJ_ADD); kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); - result = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); + status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); - return result == AE_OK ? 0 : -EINVAL; + return ACPI_FAILURE(status) ? -EINVAL : 0; err_dynamic_tables: kobject_put(tables_kobj); err: diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e2903d0..14f1e95 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -435,6 +435,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), + .driver_data = board_ahci_yes_fbs }, /* Promise */ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index f955431..4b231ba 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -329,6 +329,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); static const struct of_device_id ahci_of_match[] = { { .compatible = "snps,spear-ahci", }, { .compatible = "snps,exynos5440-ahci", }, + { .compatible = "ibm,476gtr-ahci", }, {}, }; MODULE_DEVICE_TABLE(of, ahci_of_match); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 81a94a3..75b9367 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6304,10 +6304,9 @@ static void ata_port_detach(struct ata_port *ap) for (i = 0; i < SATA_PMP_MAX_PORTS; i++) ata_tlink_delete(&ap->pmp_link[i]); } - ata_tport_delete(ap); - /* remove the associated SCSI host */ scsi_remove_host(ap->scsi_host); + ata_tport_delete(ap); } /** diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 68f9e32..88949c6 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -88,15 +88,13 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) static bool odd_can_poweroff(struct ata_device *ata_dev) { acpi_handle handle; - acpi_status status; struct acpi_device *acpi_dev; handle = ata_dev_acpi_handle(ata_dev); if (!handle) return false; - status = acpi_bus_get_device(handle, &acpi_dev); - if (ACPI_FAILURE(status)) + if (acpi_bus_get_device(handle, &acpi_dev)) return false; return acpi_device_can_poweroff(acpi_dev); diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index e88690e..73492dd 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -319,6 +319,7 @@ static int cf_init(struct arasan_cf_dev *acdev) ret = clk_set_rate(acdev->clk, 166000000); if (ret) { dev_warn(acdev->host->dev, "clock set rate failed"); + clk_disable_unprepare(acdev->clk); return ret; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c206de2..2f2b084 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -165,6 +165,19 @@ config HW_RANDOM_OMAP If unsure, say Y. +config HW_RANDOM_OMAP3_ROM + tristate "OMAP3 ROM Random Number Generator support" + depends on HW_RANDOM && ARCH_OMAP3 + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on OMAP34xx processors. + + To compile this driver as a module, choose M here: the + module will be called omap3-rom-rng. + + If unsure, say Y. + config HW_RANDOM_OCTEON tristate "Octeon Random Number Generator support" depends on HW_RANDOM && CAVIUM_OCTEON_SOC @@ -327,3 +340,15 @@ config HW_RANDOM_TPM module will be called tpm-rng. If unsure, say Y. + +config HW_RANDOM_MSM + tristate "Qualcomm MSM Random Number Generator support" + depends on HW_RANDOM && ARCH_MSM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on Qualcomm MSM SoCs. + + To compile this driver as a module, choose M here. the + module will be called msm-rng. + + If unsure, say Y. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index d7d2435..3ae7755 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -15,6 +15,7 @@ n2-rng-y := n2-drv.o n2-asm.o obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o +obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o @@ -28,3 +29,4 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c new file mode 100644 index 0000000..148521e --- /dev/null +++ b/drivers/char/hw_random/msm-rng.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/hw_random.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +/* Device specific register offsets */ +#define PRNG_DATA_OUT 0x0000 +#define PRNG_STATUS 0x0004 +#define PRNG_LFSR_CFG 0x0100 +#define PRNG_CONFIG 0x0104 + +/* Device specific register masks and config values */ +#define PRNG_LFSR_CFG_MASK 0x0000ffff +#define PRNG_LFSR_CFG_CLOCKS 0x0000dddd +#define PRNG_CONFIG_HW_ENABLE BIT(1) +#define PRNG_STATUS_DATA_AVAIL BIT(0) + +#define MAX_HW_FIFO_DEPTH 16 +#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) +#define WORD_SZ 4 + +struct msm_rng { + void __iomem *base; + struct clk *clk; + struct hwrng hwrng; +}; + +#define to_msm_rng(p) container_of(p, struct msm_rng, hwrng) + +static int msm_rng_enable(struct hwrng *hwrng, int enable) +{ + struct msm_rng *rng = to_msm_rng(hwrng); + u32 val; + int ret; + + ret = clk_prepare_enable(rng->clk); + if (ret) + return ret; + + if (enable) { + /* Enable PRNG only if it is not already enabled */ + val = readl_relaxed(rng->base + PRNG_CONFIG); + if (val & PRNG_CONFIG_HW_ENABLE) + goto already_enabled; + + val = readl_relaxed(rng->base + PRNG_LFSR_CFG); + val &= ~PRNG_LFSR_CFG_MASK; + val |= PRNG_LFSR_CFG_CLOCKS; + writel(val, rng->base + PRNG_LFSR_CFG); + + val = readl_relaxed(rng->base + PRNG_CONFIG); + val |= PRNG_CONFIG_HW_ENABLE; + writel(val, rng->base + PRNG_CONFIG); + } else { + val = readl_relaxed(rng->base + PRNG_CONFIG); + val &= ~PRNG_CONFIG_HW_ENABLE; + writel(val, rng->base + PRNG_CONFIG); + } + +already_enabled: + clk_disable_unprepare(rng->clk); + return 0; +} + +static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) +{ + struct msm_rng *rng = to_msm_rng(hwrng); + size_t currsize = 0; + u32 *retdata = data; + size_t maxsize; + int ret; + u32 val; + + /* calculate max size bytes to transfer back to caller */ + maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max); + + /* no room for word data */ + if (maxsize < WORD_SZ) + return 0; + + ret = clk_prepare_enable(rng->clk); + if (ret) + return ret; + + /* read random data from hardware */ + do { + val = readl_relaxed(rng->base + PRNG_STATUS); + if (!(val & PRNG_STATUS_DATA_AVAIL)) + break; + + val = readl_relaxed(rng->base + PRNG_DATA_OUT); + if (!val) + break; + + *retdata++ = val; + currsize += WORD_SZ; + + /* make sure we stay on 32bit boundary */ + if ((maxsize - currsize) < WORD_SZ) + break; + } while (currsize < maxsize); + + clk_disable_unprepare(rng->clk); + + return currsize; +} + +static int msm_rng_init(struct hwrng *hwrng) +{ + return msm_rng_enable(hwrng, 1); +} + +static void msm_rng_cleanup(struct hwrng *hwrng) +{ + msm_rng_enable(hwrng, 0); +} + +static int msm_rng_probe(struct platform_device *pdev) +{ + struct resource *res; + struct msm_rng *rng; + int ret; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng) + return -ENOMEM; + + platform_set_drvdata(pdev, rng); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rng->base)) + return PTR_ERR(rng->base); + + rng->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(rng->clk)) + return PTR_ERR(rng->clk); + + rng->hwrng.name = KBUILD_MODNAME, + rng->hwrng.init = msm_rng_init, + rng->hwrng.cleanup = msm_rng_cleanup, + rng->hwrng.read = msm_rng_read, + + ret = hwrng_register(&rng->hwrng); + if (ret) { + dev_err(&pdev->dev, "failed to register hwrng\n"); + return ret; + } + + return 0; +} + +static int msm_rng_remove(struct platform_device *pdev) +{ + struct msm_rng *rng = platform_get_drvdata(pdev); + + hwrng_unregister(&rng->hwrng); + return 0; +} + +static const struct of_device_id msm_rng_of_match[] = { + { .compatible = "qcom,prng", }, + {} +}; +MODULE_DEVICE_TABLE(of, msm_rng_of_match); + +static struct platform_driver msm_rng_driver = { + .probe = msm_rng_probe, + .remove = msm_rng_remove, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(msm_rng_of_match), + } +}; +module_platform_driver(msm_rng_driver); + +MODULE_ALIAS("platform:" KBUILD_MODNAME); +MODULE_AUTHOR("The Linux Foundation"); +MODULE_DESCRIPTION("Qualcomm MSM random number generator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c new file mode 100644 index 0000000..c853e9e --- /dev/null +++ b/drivers/char/hw_random/omap3-rom-rng.c @@ -0,0 +1,141 @@ +/* + * omap3-rom-rng.c - RNG driver for TI OMAP3 CPU family + * + * Copyright (C) 2009 Nokia Corporation + * Author: Juha Yrjola <juha.yrjola@solidboot.com> + * + * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/random.h> +#include <linux/hw_random.h> +#include <linux/timer.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.h> + +#define RNG_RESET 0x01 +#define RNG_GEN_PRNG_HW_INIT 0x02 +#define RNG_GEN_HW 0x08 + +/* param1: ptr, param2: count, param3: flag */ +static u32 (*omap3_rom_rng_call)(u32, u32, u32); + +static struct timer_list idle_timer; +static int rng_idle; +static struct clk *rng_clk; + +static void omap3_rom_rng_idle(unsigned long data) +{ + int r; + + r = omap3_rom_rng_call(0, 0, RNG_RESET); + if (r != 0) { + pr_err("reset failed: %d\n", r); + return; + } + clk_disable_unprepare(rng_clk); + rng_idle = 1; +} + +static int omap3_rom_rng_get_random(void *buf, unsigned int count) +{ + u32 r; + u32 ptr; + + del_timer_sync(&idle_timer); + if (rng_idle) { + clk_prepare_enable(rng_clk); + r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT); + if (r != 0) { + clk_disable_unprepare(rng_clk); + pr_err("HW init failed: %d\n", r); + return -EIO; + } + rng_idle = 0; + } + + ptr = virt_to_phys(buf); + r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW); + mod_timer(&idle_timer, jiffies + msecs_to_jiffies(500)); + if (r != 0) + return -EINVAL; + return 0; +} + +static int omap3_rom_rng_data_present(struct hwrng *rng, int wait) +{ + return 1; +} + +static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data) +{ + int r; + + r = omap3_rom_rng_get_random(data, 4); + if (r < 0) + return r; + return 4; +} + +static struct hwrng omap3_rom_rng_ops = { + .name = "omap3-rom", + .data_present = omap3_rom_rng_data_present, + .data_read = omap3_rom_rng_data_read, +}; + +static int omap3_rom_rng_probe(struct platform_device *pdev) +{ + pr_info("initializing\n"); + + omap3_rom_rng_call = pdev->dev.platform_data; + if (!omap3_rom_rng_call) { + pr_err("omap3_rom_rng_call is NULL\n"); + return -EINVAL; + } + + setup_timer(&idle_timer, omap3_rom_rng_idle, 0); + rng_clk = clk_get(&pdev->dev, "ick"); + if (IS_ERR(rng_clk)) { + pr_err("unable to get RNG clock\n"); + return PTR_ERR(rng_clk); + } + + /* Leave the RNG in reset state. */ + clk_prepare_enable(rng_clk); + omap3_rom_rng_idle(0); + + return hwrng_register(&omap3_rom_rng_ops); +} + +static int omap3_rom_rng_remove(struct platform_device *pdev) +{ + hwrng_unregister(&omap3_rom_rng_ops); + clk_disable_unprepare(rng_clk); + clk_put(rng_clk); + return 0; +} + +static struct platform_driver omap3_rom_rng_driver = { + .driver = { + .name = "omap3-rom-rng", + .owner = THIS_MODULE, + }, + .probe = omap3_rom_rng_probe, + .remove = omap3_rom_rng_remove, +}; + +module_platform_driver(omap3_rom_rng_driver); + +MODULE_ALIAS("platform:omap3-rom-rng"); +MODULE_AUTHOR("Juha Yrjola"); +MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index b761459a..ab7ffde 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -24,7 +24,6 @@ #include <linux/hw_random.h> #include <asm/vio.h> -#define MODULE_NAME "pseries-rng" static int pseries_rng_data_read(struct hwrng *rng, u32 *data) { @@ -55,7 +54,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev) }; static struct hwrng pseries_rng = { - .name = MODULE_NAME, + .name = KBUILD_MODNAME, .data_read = pseries_rng_data_read, }; @@ -78,7 +77,7 @@ static struct vio_device_id pseries_rng_driver_ids[] = { MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids); static struct vio_driver pseries_rng_driver = { - .name = MODULE_NAME, + .name = KBUILD_MODNAME, .probe = pseries_rng_probe, .remove = pseries_rng_remove, .get_desired_dma = pseries_rng_get_desired_dma, diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index e737772..de5a6dc 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -221,7 +221,7 @@ static void __exit mod_exit(void) module_init(mod_init); module_exit(mod_exit); -static struct x86_cpu_id via_rng_cpu_id[] = { +static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = { X86_FEATURE_MATCH(X86_FEATURE_XSTORE), {} }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7a10bc9..ace7309 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ +obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile new file mode 100644 index 0000000..46c1d3d --- /dev/null +++ b/drivers/clk/at91/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for at91 specific clk +# + +obj-y += pmc.o +obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o +obj-y += clk-system.o clk-peripheral.o clk-programmable.o + +obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o +obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o +obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c new file mode 100644 index 0000000..8e9e8cc --- /dev/null +++ b/drivers/clk/at91/clk-main.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/wait.h> + +#include "pmc.h" + +#define SLOW_CLOCK_FREQ 32768 +#define MAINF_DIV 16 +#define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \ + SLOW_CLOCK_FREQ) +#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ) +#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT + +struct clk_main { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned long rate; + unsigned int irq; + wait_queue_head_t wait; +}; + +#define to_clk_main(hw) container_of(hw, struct clk_main, hw) + +static irqreturn_t clk_main_irq_handler(int irq, void *dev_id) +{ + struct clk_main *clkmain = (struct clk_main *)dev_id; + + wake_up(&clkmain->wait); + disable_irq_nosync(clkmain->irq); + + return IRQ_HANDLED; +} + +static int clk_main_prepare(struct clk_hw *hw) +{ + struct clk_main *clkmain = to_clk_main(hw); + struct at91_pmc *pmc = clkmain->pmc; + unsigned long halt_time, timeout; + u32 tmp; + + while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) { + enable_irq(clkmain->irq); + wait_event(clkmain->wait, + pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); + } + + if (clkmain->rate) + return 0; + + timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); + do { + halt_time = jiffies; + tmp = pmc_read(pmc, AT91_CKGR_MCFR); + if (tmp & AT91_PMC_MAINRDY) + return 0; + usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); + } while (time_before(halt_time, timeout)); + + return 0; +} + +static int clk_main_is_prepared(struct clk_hw *hw) +{ + struct clk_main *clkmain = to_clk_main(hw); + + return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); +} + +static unsigned long clk_main_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 tmp; + struct clk_main *clkmain = to_clk_main(hw); + struct at91_pmc *pmc = clkmain->pmc; + + if (clkmain->rate) + return clkmain->rate; + + tmp = pmc_read(pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINF; + clkmain->rate = (tmp * parent_rate) / MAINF_DIV; + + return clkmain->rate; +} + +static const struct clk_ops main_ops = { + .prepare = clk_main_prepare, + .is_prepared = clk_main_is_prepared, + .recalc_rate = clk_main_recalc_rate, +}; + +static struct clk * __init +at91_clk_register_main(struct at91_pmc *pmc, + unsigned int irq, + const char *name, + const char *parent_name, + unsigned long rate) +{ + int ret; + struct clk_main *clkmain; + struct clk *clk = NULL; + struct clk_init_data init; + + if (!pmc || !irq || !name) + return ERR_PTR(-EINVAL); + + if (!rate && !parent_name) + return ERR_PTR(-EINVAL); + + clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); + if (!clkmain) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &main_ops; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.flags = parent_name ? 0 : CLK_IS_ROOT; + + clkmain->hw.init = &init; + clkmain->rate = rate; + clkmain->pmc = pmc; + clkmain->irq = irq; + init_waitqueue_head(&clkmain->wait); + irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); + ret = request_irq(clkmain->irq, clk_main_irq_handler, + IRQF_TRIGGER_HIGH, "clk-main", clkmain); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &clkmain->hw); + if (IS_ERR(clk)) { + free_irq(clkmain->irq, clkmain); + kfree(clkmain); + } + + return clk; +} + + + +static void __init +of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc) +{ + struct clk *clk; + unsigned int irq; + const char *parent_name; + const char *name = np->name; + u32 rate = 0; + + parent_name = of_clk_get_parent_name(np, 0); + of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "clock-frequency", &rate); + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_main(pmc, irq, name, parent_name, rate); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +void __init of_at91rm9200_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_main_setup(np, pmc); +} diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c new file mode 100644 index 0000000..bd313f7 --- /dev/null +++ b/drivers/clk/at91/clk-master.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include "pmc.h" + +#define MASTER_SOURCE_MAX 4 + +#define MASTER_PRES_MASK 0x7 +#define MASTER_PRES_MAX MASTER_PRES_MASK +#define MASTER_DIV_SHIFT 8 +#define MASTER_DIV_MASK 0x3 + +struct clk_master_characteristics { + struct clk_range output; + u32 divisors[4]; + u8 have_div3_pres; +}; + +struct clk_master_layout { + u32 mask; + u8 pres_shift; +}; + +#define to_clk_master(hw) container_of(hw, struct clk_master, hw) + +struct clk_master { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; + const struct clk_master_layout *layout; + const struct clk_master_characteristics *characteristics; +}; + +static irqreturn_t clk_master_irq_handler(int irq, void *dev_id) +{ + struct clk_master *master = (struct clk_master *)dev_id; + + wake_up(&master->wait); + disable_irq_nosync(master->irq); + + return IRQ_HANDLED; +} +static int clk_master_prepare(struct clk_hw *hw) +{ + struct clk_master *master = to_clk_master(hw); + struct at91_pmc *pmc = master->pmc; + + while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) { + enable_irq(master->irq); + wait_event(master->wait, + pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); + } + + return 0; +} + +static int clk_master_is_prepared(struct clk_hw *hw) +{ + struct clk_master *master = to_clk_master(hw); + + return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); +} + +static unsigned long clk_master_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u8 pres; + u8 div; + unsigned long rate = parent_rate; + struct clk_master *master = to_clk_master(hw); + struct at91_pmc *pmc = master->pmc; + const struct clk_master_layout *layout = master->layout; + const struct clk_master_characteristics *characteristics = + master->characteristics; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask; + pmc_unlock(pmc); + + pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK; + div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; + + if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) + rate /= 3; + else + rate >>= pres; + + rate /= characteristics->divisors[div]; + + if (rate < characteristics->output.min) + pr_warn("master clk is underclocked"); + else if (rate > characteristics->output.max) + pr_warn("master clk is overclocked"); + + return rate; +} + +static u8 clk_master_get_parent(struct clk_hw *hw) +{ + struct clk_master *master = to_clk_master(hw); + struct at91_pmc *pmc = master->pmc; + + return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS; +} + +static const struct clk_ops master_ops = { + .prepare = clk_master_prepare, + .is_prepared = clk_master_is_prepared, + .recalc_rate = clk_master_recalc_rate, + .get_parent = clk_master_get_parent, +}; + +static struct clk * __init +at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, + const char *name, int num_parents, + const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics) +{ + int ret; + struct clk_master *master; + struct clk *clk = NULL; + struct clk_init_data init; + + if (!pmc || !irq || !name || !num_parents || !parent_names) + return ERR_PTR(-EINVAL); + + master = kzalloc(sizeof(*master), GFP_KERNEL); + if (!master) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &master_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = 0; + + master->hw.init = &init; + master->layout = layout; + master->characteristics = characteristics; + master->pmc = pmc; + master->irq = irq; + init_waitqueue_head(&master->wait); + irq_set_status_flags(master->irq, IRQ_NOAUTOEN); + ret = request_irq(master->irq, clk_master_irq_handler, + IRQF_TRIGGER_HIGH, "clk-master", master); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &master->hw); + if (IS_ERR(clk)) + kfree(master); + + return clk; +} + + +static const struct clk_master_layout at91rm9200_master_layout = { + .mask = 0x31F, + .pres_shift = 2, +}; + +static const struct clk_master_layout at91sam9x5_master_layout = { + .mask = 0x373, + .pres_shift = 4, +}; + + +static struct clk_master_characteristics * __init +of_at91_clk_master_get_characteristics(struct device_node *np) +{ + struct clk_master_characteristics *characteristics; + + characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); + if (!characteristics) + return NULL; + + if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output)) + goto out_free_characteristics; + + of_property_read_u32_array(np, "atmel,clk-divisors", + characteristics->divisors, 4); + + characteristics->have_div3_pres = + of_property_read_bool(np, "atmel,master-clk-have-div3-pres"); + + return characteristics; + +out_free_characteristics: + kfree(characteristics); + return NULL; +} + +static void __init +of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, + const struct clk_master_layout *layout) +{ + struct clk *clk; + int num_parents; + int i; + unsigned int irq; + const char *parent_names[MASTER_SOURCE_MAX]; + const char *name = np->name; + struct clk_master_characteristics *characteristics; + + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) + return; + + for (i = 0; i < num_parents; ++i) { + parent_names[i] = of_clk_get_parent_name(np, i); + if (!parent_names[i]) + return; + } + + of_property_read_string(np, "clock-output-names", &name); + + characteristics = of_at91_clk_master_get_characteristics(np); + if (!characteristics) + return; + + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_master(pmc, irq, name, num_parents, + parent_names, layout, + characteristics); + if (IS_ERR(clk)) + goto out_free_characteristics; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; + +out_free_characteristics: + kfree(characteristics); +} + +void __init of_at91rm9200_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout); +} + +void __init of_at91sam9x5_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout); +} diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c new file mode 100644 index 0000000..597fed4 --- /dev/null +++ b/drivers/clk/at91/clk-peripheral.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> + +#include "pmc.h" + +#define PERIPHERAL_MAX 64 + +#define PERIPHERAL_AT91RM9200 0 +#define PERIPHERAL_AT91SAM9X5 1 + +#define PERIPHERAL_ID_MIN 2 +#define PERIPHERAL_ID_MAX 31 +#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) + +#define PERIPHERAL_RSHIFT_MASK 0x3 +#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK) + +#define PERIPHERAL_MAX_SHIFT 4 + +struct clk_peripheral { + struct clk_hw hw; + struct at91_pmc *pmc; + u32 id; +}; + +#define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw) + +struct clk_sam9x5_peripheral { + struct clk_hw hw; + struct at91_pmc *pmc; + struct clk_range range; + u32 id; + u32 div; + bool auto_div; +}; + +#define to_clk_sam9x5_peripheral(hw) \ + container_of(hw, struct clk_sam9x5_peripheral, hw) + +static int clk_peripheral_enable(struct clk_hw *hw) +{ + struct clk_peripheral *periph = to_clk_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCER; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return 0; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCER1; + pmc_write(pmc, offset, PERIPHERAL_MASK(id)); + return 0; +} + +static void clk_peripheral_disable(struct clk_hw *hw) +{ + struct clk_peripheral *periph = to_clk_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCDR; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCDR1; + pmc_write(pmc, offset, PERIPHERAL_MASK(id)); +} + +static int clk_peripheral_is_enabled(struct clk_hw *hw) +{ + struct clk_peripheral *periph = to_clk_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCSR; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return 1; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCSR1; + return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id)); +} + +static const struct clk_ops peripheral_ops = { + .enable = clk_peripheral_enable, + .disable = clk_peripheral_disable, + .is_enabled = clk_peripheral_is_enabled, +}; + +static struct clk * __init +at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name, + const char *parent_name, u32 id) +{ + struct clk_peripheral *periph; + struct clk *clk = NULL; + struct clk_init_data init; + + if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); + if (!periph) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &peripheral_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + init.flags = 0; + + periph->id = id; + periph->hw.init = &init; + periph->pmc = pmc; + + clk = clk_register(NULL, &periph->hw); + if (IS_ERR(clk)) + kfree(periph); + + return clk; +} + +static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph) +{ + struct clk *parent; + unsigned long parent_rate; + int shift = 0; + + if (!periph->auto_div) + return; + + if (periph->range.max) { + parent = clk_get_parent_by_index(periph->hw.clk, 0); + parent_rate = __clk_get_rate(parent); + if (!parent_rate) + return; + + for (; shift < PERIPHERAL_MAX_SHIFT; shift++) { + if (parent_rate >> shift <= periph->range.max) + break; + } + } + + periph->auto_div = false; + periph->div = shift; +} + +static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + + if (periph->id < PERIPHERAL_ID_MIN) + return 0; + + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) | + AT91_PMC_PCR_CMD | + AT91_PMC_PCR_DIV(periph->div) | + AT91_PMC_PCR_EN); + return 0; +} + +static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + + if (periph->id < PERIPHERAL_ID_MIN) + return; + + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) | + AT91_PMC_PCR_CMD); +} + +static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + int ret; + + if (periph->id < PERIPHERAL_ID_MIN) + return 1; + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID)); + ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN); + pmc_unlock(pmc); + + return ret; +} + +static unsigned long +clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + struct at91_pmc *pmc = periph->pmc; + u32 tmp; + + if (periph->id < PERIPHERAL_ID_MIN) + return parent_rate; + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID)); + tmp = pmc_read(pmc, AT91_PMC_PCR); + pmc_unlock(pmc); + + if (tmp & AT91_PMC_PCR_EN) { + periph->div = PERIPHERAL_RSHIFT(tmp); + periph->auto_div = false; + } else { + clk_sam9x5_peripheral_autodiv(periph); + } + + return parent_rate >> periph->div; +} + +static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + int shift = 0; + unsigned long best_rate; + unsigned long best_diff; + unsigned long cur_rate = *parent_rate; + unsigned long cur_diff; + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + + if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) + return *parent_rate; + + if (periph->range.max) { + for (; shift < PERIPHERAL_MAX_SHIFT; shift++) { + cur_rate = *parent_rate >> shift; + if (cur_rate <= periph->range.max) + break; + } + } + + if (rate >= cur_rate) + return cur_rate; + + best_diff = cur_rate - rate; + best_rate = cur_rate; + for (; shift < PERIPHERAL_MAX_SHIFT; shift++) { + cur_rate = *parent_rate >> shift; + if (cur_rate < rate) + cur_diff = rate - cur_rate; + else + cur_diff = cur_rate - rate; + + if (cur_diff < best_diff) { + best_diff = cur_diff; + best_rate = cur_rate; + } + + if (!best_diff || cur_rate < rate) + break; + } + + return best_rate; +} + +static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + int shift; + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); + if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { + if (parent_rate == rate) + return 0; + else + return -EINVAL; + } + + if (periph->range.max && rate > periph->range.max) + return -EINVAL; + + for (shift = 0; shift < PERIPHERAL_MAX_SHIFT; shift++) { + if (parent_rate >> shift == rate) { + periph->auto_div = false; + periph->div = shift; + return 0; + } + } + + return -EINVAL; +} + +static const struct clk_ops sam9x5_peripheral_ops = { + .enable = clk_sam9x5_peripheral_enable, + .disable = clk_sam9x5_peripheral_disable, + .is_enabled = clk_sam9x5_peripheral_is_enabled, + .recalc_rate = clk_sam9x5_peripheral_recalc_rate, + .round_rate = clk_sam9x5_peripheral_round_rate, + .set_rate = clk_sam9x5_peripheral_set_rate, +}; + +static struct clk * __init +at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name, + const char *parent_name, u32 id, + const struct clk_range *range) +{ + struct clk_sam9x5_peripheral *periph; + struct clk *clk = NULL; + struct clk_init_data init; + + if (!pmc || !name || !parent_name) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); + if (!periph) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &sam9x5_peripheral_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + init.flags = 0; + + periph->id = id; + periph->hw.init = &init; + periph->div = 0; + periph->pmc = pmc; + periph->auto_div = true; + periph->range = *range; + + clk = clk_register(NULL, &periph->hw); + if (IS_ERR(clk)) + kfree(periph); + else + clk_sam9x5_peripheral_autodiv(periph); + + return clk; +} + +static void __init +of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) +{ + int num; + u32 id; + struct clk *clk; + const char *parent_name; + const char *name; + struct device_node *periphclknp; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + num = of_get_child_count(np); + if (!num || num > PERIPHERAL_MAX) + return; + + for_each_child_of_node(np, periphclknp) { + if (of_property_read_u32(periphclknp, "reg", &id)) + continue; + + if (id >= PERIPHERAL_MAX) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = periphclknp->name; + + if (type == PERIPHERAL_AT91RM9200) { + clk = at91_clk_register_peripheral(pmc, name, + parent_name, id); + } else { + struct clk_range range = CLK_RANGE(0, 0); + + of_at91_get_clk_range(periphclknp, + "atmel,clk-output-range", + &range); + + clk = at91_clk_register_sam9x5_peripheral(pmc, name, + parent_name, + id, &range); + } + + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk); + } +} + +void __init of_at91rm9200_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200); +} + +void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5); +} diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c new file mode 100644 index 0000000..cf6ed02 --- /dev/null +++ b/drivers/clk/at91/clk-pll.c @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include "pmc.h" + +#define PLL_STATUS_MASK(id) (1 << (1 + (id))) +#define PLL_REG(id) (AT91_CKGR_PLLAR + ((id) * 4)) +#define PLL_DIV_MASK 0xff +#define PLL_DIV_MAX PLL_DIV_MASK +#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) +#define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ + (layout)->mul_mask) +#define PLL_ICPR_SHIFT(id) ((id) * 16) +#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) +#define PLL_MAX_COUNT 0x3ff +#define PLL_COUNT_SHIFT 8 +#define PLL_OUT_SHIFT 14 +#define PLL_MAX_ID 1 + +struct clk_pll_characteristics { + struct clk_range input; + int num_output; + struct clk_range *output; + u16 *icpll; + u8 *out; +}; + +struct clk_pll_layout { + u32 pllr_mask; + u16 mul_mask; + u8 mul_shift; +}; + +#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw) + +struct clk_pll { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; + u8 id; + u8 div; + u8 range; + u16 mul; + const struct clk_pll_layout *layout; + const struct clk_pll_characteristics *characteristics; +}; + +static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id) +{ + struct clk_pll *pll = (struct clk_pll *)dev_id; + + wake_up(&pll->wait); + disable_irq_nosync(pll->irq); + + return IRQ_HANDLED; +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + const struct clk_pll_layout *layout = pll->layout; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + u8 id = pll->id; + u32 mask = PLL_STATUS_MASK(id); + int offset = PLL_REG(id); + u8 out = 0; + u32 pllr, icpr; + u8 div; + u16 mul; + + pllr = pmc_read(pmc, offset); + div = PLL_DIV(pllr); + mul = PLL_MUL(pllr, layout); + + if ((pmc_read(pmc, AT91_PMC_SR) & mask) && + (div == pll->div && mul == pll->mul)) + return 0; + + if (characteristics->out) + out = characteristics->out[pll->range]; + if (characteristics->icpll) { + icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id); + icpr |= (characteristics->icpll[pll->range] << + PLL_ICPR_SHIFT(id)); + pmc_write(pmc, AT91_PMC_PLLICPR, icpr); + } + + pllr &= ~layout->pllr_mask; + pllr |= layout->pllr_mask & + (pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | + (out << PLL_OUT_SHIFT) | + ((pll->mul & layout->mul_mask) << layout->mul_shift)); + pmc_write(pmc, offset, pllr); + + while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { + enable_irq(pll->irq); + wait_event(pll->wait, + pmc_read(pmc, AT91_PMC_SR) & mask); + } + + return 0; +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SR) & + PLL_STATUS_MASK(pll->id)); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + const struct clk_pll_layout *layout = pll->layout; + int offset = PLL_REG(pll->id); + u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask); + + pmc_write(pmc, offset, tmp); +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + const struct clk_pll_layout *layout = pll->layout; + struct at91_pmc *pmc = pll->pmc; + int offset = PLL_REG(pll->id); + u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask; + u8 div = PLL_DIV(tmp); + u16 mul = PLL_MUL(tmp, layout); + if (!div || !mul) + return 0; + + return (parent_rate * (mul + 1)) / div; +} + +static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, + unsigned long parent_rate, + u32 *div, u32 *mul, + u32 *index) { + unsigned long maxrate; + unsigned long minrate; + unsigned long divrate; + unsigned long bestdiv = 1; + unsigned long bestmul; + unsigned long tmpdiv; + unsigned long roundup; + unsigned long rounddown; + unsigned long remainder; + unsigned long bestremainder; + unsigned long maxmul; + unsigned long maxdiv; + unsigned long mindiv; + int i = 0; + const struct clk_pll_layout *layout = pll->layout; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + + /* Minimum divider = 1 */ + /* Maximum multiplier = max_mul */ + maxmul = layout->mul_mask + 1; + maxrate = (parent_rate * maxmul) / 1; + + /* Maximum divider = max_div */ + /* Minimum multiplier = 2 */ + maxdiv = PLL_DIV_MAX; + minrate = (parent_rate * 2) / maxdiv; + + if (parent_rate < characteristics->input.min || + parent_rate < characteristics->input.max) + return -ERANGE; + + if (parent_rate < minrate || parent_rate > maxrate) + return -ERANGE; + + for (i = 0; i < characteristics->num_output; i++) { + if (parent_rate >= characteristics->output[i].min && + parent_rate <= characteristics->output[i].max) + break; + } + + if (i >= characteristics->num_output) + return -ERANGE; + + bestmul = rate / parent_rate; + rounddown = parent_rate % rate; + roundup = rate - rounddown; + bestremainder = roundup < rounddown ? roundup : rounddown; + + if (!bestremainder) { + if (div) + *div = bestdiv; + if (mul) + *mul = bestmul; + if (index) + *index = i; + return rate; + } + + maxdiv = 255 / (bestmul + 1); + if (parent_rate / maxdiv < characteristics->input.min) + maxdiv = parent_rate / characteristics->input.min; + mindiv = parent_rate / characteristics->input.max; + if (parent_rate % characteristics->input.max) + mindiv++; + + for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) { + divrate = parent_rate / tmpdiv; + + rounddown = rate % divrate; + roundup = divrate - rounddown; + remainder = roundup < rounddown ? roundup : rounddown; + + if (remainder < bestremainder) { + bestremainder = remainder; + bestmul = rate / divrate; + bestdiv = tmpdiv; + } + + if (!remainder) + break; + } + + rate = (parent_rate / bestdiv) * bestmul; + + if (div) + *div = bestdiv; + if (mul) + *mul = bestmul; + if (index) + *index = i; + + return rate; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + + return clk_pll_get_best_div_mul(pll, rate, *parent_rate, + NULL, NULL, NULL); +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + long ret; + u32 div; + u32 mul; + u32 index; + + ret = clk_pll_get_best_div_mul(pll, rate, parent_rate, + &div, &mul, &index); + if (ret < 0) + return ret; + + pll->range = index; + pll->div = div; + pll->mul = mul; + + return 0; +} + +static const struct clk_ops pll_ops = { + .prepare = clk_pll_prepare, + .unprepare = clk_pll_unprepare, + .is_prepared = clk_pll_is_prepared, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, +}; + +static struct clk * __init +at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_layout *layout, + const struct clk_pll_characteristics *characteristics) +{ + struct clk_pll *pll; + struct clk *clk = NULL; + struct clk_init_data init; + int ret; + int offset = PLL_REG(id); + u32 tmp; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + pll->id = id; + pll->hw.init = &init; + pll->layout = layout; + pll->characteristics = characteristics; + pll->pmc = pmc; + pll->irq = irq; + tmp = pmc_read(pmc, offset) & layout->pllr_mask; + pll->div = PLL_DIV(tmp); + pll->mul = PLL_MUL(tmp, layout); + init_waitqueue_head(&pll->wait); + irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); + ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, + id ? "clk-pllb" : "clk-plla", pll); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + + +static const struct clk_pll_layout at91rm9200_pll_layout = { + .pllr_mask = 0x7FFFFFF, + .mul_shift = 16, + .mul_mask = 0x7FF, +}; + +static const struct clk_pll_layout at91sam9g45_pll_layout = { + .pllr_mask = 0xFFFFFF, + .mul_shift = 16, + .mul_mask = 0xFF, +}; + +static const struct clk_pll_layout at91sam9g20_pllb_layout = { + .pllr_mask = 0x3FFFFF, + .mul_shift = 16, + .mul_mask = 0x3F, +}; + +static const struct clk_pll_layout sama5d3_pll_layout = { + .pllr_mask = 0x1FFFFFF, + .mul_shift = 18, + .mul_mask = 0x7F, +}; + + +static struct clk_pll_characteristics * __init +of_at91_clk_pll_get_characteristics(struct device_node *np) +{ + int i; + int offset; + u32 tmp; + int num_output; + u32 num_cells; + struct clk_range input; + struct clk_range *output; + u8 *out = NULL; + u16 *icpll = NULL; + struct clk_pll_characteristics *characteristics; + + if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input)) + return NULL; + + if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells", + &num_cells)) + return NULL; + + if (num_cells < 2 || num_cells > 4) + return NULL; + + if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) + return NULL; + num_output = tmp / (sizeof(u32) * num_cells); + + characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); + if (!characteristics) + return NULL; + + output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL); + if (!output) + goto out_free_characteristics; + + if (num_cells > 2) { + out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL); + if (!out) + goto out_free_output; + } + + if (num_cells > 3) { + icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL); + if (!icpll) + goto out_free_output; + } + + for (i = 0; i < num_output; i++) { + offset = i * num_cells; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset, &tmp)) + goto out_free_output; + output[i].min = tmp; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 1, &tmp)) + goto out_free_output; + output[i].max = tmp; + + if (num_cells == 2) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 2, &tmp)) + goto out_free_output; + out[i] = tmp; + + if (num_cells == 3) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 3, &tmp)) + goto out_free_output; + icpll[i] = tmp; + } + + characteristics->input = input; + characteristics->num_output = num_output; + characteristics->output = output; + characteristics->out = out; + characteristics->icpll = icpll; + return characteristics; + +out_free_output: + kfree(icpll); + kfree(out); + kfree(output); +out_free_characteristics: + kfree(characteristics); + return NULL; +} + +static void __init +of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, + const struct clk_pll_layout *layout) +{ + u32 id; + unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; + struct clk_pll_characteristics *characteristics; + + if (of_property_read_u32(np, "reg", &id)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + characteristics = of_at91_clk_pll_get_characteristics(np); + if (!characteristics) + return; + + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout, + characteristics); + if (IS_ERR(clk)) + goto out_free_characteristics; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; + +out_free_characteristics: + kfree(characteristics); +} + +void __init of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout); +} + +void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout); +} + +void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout); +} + +void __init of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout); +} diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c new file mode 100644 index 0000000..ea22656 --- /dev/null +++ b/drivers/clk/at91/clk-plldiv.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> + +#include "pmc.h" + +#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw) + +struct clk_plldiv { + struct clk_hw hw; + struct at91_pmc *pmc; +}; + +static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_plldiv *plldiv = to_clk_plldiv(hw); + struct at91_pmc *pmc = plldiv->pmc; + + if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2) + return parent_rate / 2; + + return parent_rate; +} + +static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long div; + + if (rate > *parent_rate) + return *parent_rate; + div = *parent_rate / 2; + if (rate < div) + return div; + + if (rate - div < *parent_rate - rate) + return div; + + return *parent_rate; +} + +static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_plldiv *plldiv = to_clk_plldiv(hw); + struct at91_pmc *pmc = plldiv->pmc; + u32 tmp; + + if (parent_rate != rate && (parent_rate / 2) != rate) + return -EINVAL; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2; + if ((parent_rate / 2) == rate) + tmp |= AT91_PMC_PLLADIV2; + pmc_write(pmc, AT91_PMC_MCKR, tmp); + pmc_unlock(pmc); + + return 0; +} + +static const struct clk_ops plldiv_ops = { + .recalc_rate = clk_plldiv_recalc_rate, + .round_rate = clk_plldiv_round_rate, + .set_rate = clk_plldiv_set_rate, +}; + +static struct clk * __init +at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, + const char *parent_name) +{ + struct clk_plldiv *plldiv; + struct clk *clk = NULL; + struct clk_init_data init; + + plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL); + if (!plldiv) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &plldiv_ops; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.flags = CLK_SET_RATE_GATE; + + plldiv->hw.init = &init; + plldiv->pmc = pmc; + + clk = clk_register(NULL, &plldiv->hw); + + if (IS_ERR(clk)) + kfree(plldiv); + + return clk; +} + +static void __init +of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc) +{ + struct clk *clk; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91_clk_register_plldiv(pmc, name, parent_name); + + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +} + +void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_plldiv_setup(np, pmc); +} diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c new file mode 100644 index 0000000..fd792b2 --- /dev/null +++ b/drivers/clk/at91/clk-programmable.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include "pmc.h" + +#define PROG_SOURCE_MAX 5 +#define PROG_ID_MAX 7 + +#define PROG_STATUS_MASK(id) (1 << ((id) + 8)) +#define PROG_PRES_MASK 0x7 +#define PROG_MAX_RM9200_CSS 3 + +struct clk_programmable_layout { + u8 pres_shift; + u8 css_mask; + u8 have_slck_mck; +}; + +struct clk_programmable { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; + u8 id; + u8 css; + u8 pres; + u8 slckmck; + const struct clk_programmable_layout *layout; +}; + +#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw) + + +static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id) +{ + struct clk_programmable *prog = (struct clk_programmable *)dev_id; + + wake_up(&prog->wait); + + return IRQ_HANDLED; +} + +static int clk_programmable_prepare(struct clk_hw *hw) +{ + u32 tmp; + struct clk_programmable *prog = to_clk_programmable(hw); + struct at91_pmc *pmc = prog->pmc; + const struct clk_programmable_layout *layout = prog->layout; + u8 id = prog->id; + u32 mask = PROG_STATUS_MASK(id); + + tmp = prog->css | (prog->pres << layout->pres_shift); + if (layout->have_slck_mck && prog->slckmck) + tmp |= AT91_PMC_CSSMCK_MCK; + + pmc_write(pmc, AT91_PMC_PCKR(id), tmp); + + while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) + wait_event(prog->wait, pmc_read(pmc, AT91_PMC_SR) & mask); + + return 0; +} + +static int clk_programmable_is_ready(struct clk_hw *hw) +{ + struct clk_programmable *prog = to_clk_programmable(hw); + struct at91_pmc *pmc = prog->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_PCKR(prog->id)); +} + +static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 tmp; + struct clk_programmable *prog = to_clk_programmable(hw); + struct at91_pmc *pmc = prog->pmc; + const struct clk_programmable_layout *layout = prog->layout; + + tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); + prog->pres = (tmp >> layout->pres_shift) & PROG_PRES_MASK; + + return parent_rate >> prog->pres; +} + +static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long best_rate = *parent_rate; + unsigned long best_diff; + unsigned long new_diff; + unsigned long cur_rate; + int shift = shift; + + if (rate > *parent_rate) + return *parent_rate; + else + best_diff = *parent_rate - rate; + + if (!best_diff) + return best_rate; + + for (shift = 1; shift < PROG_PRES_MASK; shift++) { + cur_rate = *parent_rate >> shift; + + if (cur_rate > rate) + new_diff = cur_rate - rate; + else + new_diff = rate - cur_rate; + + if (!new_diff) + return cur_rate; + + if (new_diff < best_diff) { + best_diff = new_diff; + best_rate = cur_rate; + } + + if (rate > cur_rate) + break; + } + + return best_rate; +} + +static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_programmable *prog = to_clk_programmable(hw); + const struct clk_programmable_layout *layout = prog->layout; + if (index > layout->css_mask) { + if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) { + prog->css = 0; + prog->slckmck = 1; + return 0; + } else { + return -EINVAL; + } + } + + prog->css = index; + return 0; +} + +static u8 clk_programmable_get_parent(struct clk_hw *hw) +{ + u32 tmp; + u8 ret; + struct clk_programmable *prog = to_clk_programmable(hw); + struct at91_pmc *pmc = prog->pmc; + const struct clk_programmable_layout *layout = prog->layout; + + tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); + prog->css = tmp & layout->css_mask; + ret = prog->css; + if (layout->have_slck_mck) { + prog->slckmck = !!(tmp & AT91_PMC_CSSMCK_MCK); + if (prog->slckmck && !ret) + ret = PROG_MAX_RM9200_CSS + 1; + } + + return ret; +} + +static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_programmable *prog = to_clk_programmable(hw); + unsigned long best_rate = parent_rate; + unsigned long best_diff; + unsigned long new_diff; + unsigned long cur_rate; + int shift = 0; + + if (rate > parent_rate) + return parent_rate; + else + best_diff = parent_rate - rate; + + if (!best_diff) { + prog->pres = shift; + return 0; + } + + for (shift = 1; shift < PROG_PRES_MASK; shift++) { + cur_rate = parent_rate >> shift; + + if (cur_rate > rate) + new_diff = cur_rate - rate; + else + new_diff = rate - cur_rate; + + if (!new_diff) + break; + + if (new_diff < best_diff) { + best_diff = new_diff; + best_rate = cur_rate; + } + + if (rate > cur_rate) + break; + } + + prog->pres = shift; + return 0; +} + +static const struct clk_ops programmable_ops = { + .prepare = clk_programmable_prepare, + .is_prepared = clk_programmable_is_ready, + .recalc_rate = clk_programmable_recalc_rate, + .round_rate = clk_programmable_round_rate, + .get_parent = clk_programmable_get_parent, + .set_parent = clk_programmable_set_parent, + .set_rate = clk_programmable_set_rate, +}; + +static struct clk * __init +at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq, + const char *name, const char **parent_names, + u8 num_parents, u8 id, + const struct clk_programmable_layout *layout) +{ + int ret; + struct clk_programmable *prog; + struct clk *clk = NULL; + struct clk_init_data init; + char irq_name[11]; + + if (id > PROG_ID_MAX) + return ERR_PTR(-EINVAL); + + prog = kzalloc(sizeof(*prog), GFP_KERNEL); + if (!prog) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &programmable_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + prog->id = id; + prog->layout = layout; + prog->hw.init = &init; + prog->pmc = pmc; + prog->irq = irq; + init_waitqueue_head(&prog->wait); + irq_set_status_flags(prog->irq, IRQ_NOAUTOEN); + snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id); + ret = request_irq(prog->irq, clk_programmable_irq_handler, + IRQF_TRIGGER_HIGH, irq_name, prog); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &prog->hw); + if (IS_ERR(clk)) + kfree(prog); + + return clk; +} + +static const struct clk_programmable_layout at91rm9200_programmable_layout = { + .pres_shift = 2, + .css_mask = 0x3, + .have_slck_mck = 0, +}; + +static const struct clk_programmable_layout at91sam9g45_programmable_layout = { + .pres_shift = 2, + .css_mask = 0x3, + .have_slck_mck = 1, +}; + +static const struct clk_programmable_layout at91sam9x5_programmable_layout = { + .pres_shift = 4, + .css_mask = 0x7, + .have_slck_mck = 0, +}; + +static void __init +of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, + const struct clk_programmable_layout *layout) +{ + int num; + u32 id; + int i; + unsigned int irq; + struct clk *clk; + int num_parents; + const char *parent_names[PROG_SOURCE_MAX]; + const char *name; + struct device_node *progclknp; + + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) + return; + + for (i = 0; i < num_parents; ++i) { + parent_names[i] = of_clk_get_parent_name(np, i); + if (!parent_names[i]) + return; + } + + num = of_get_child_count(np); + if (!num || num > (PROG_ID_MAX + 1)) + return; + + for_each_child_of_node(np, progclknp) { + if (of_property_read_u32(progclknp, "reg", &id)) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = progclknp->name; + + irq = irq_of_parse_and_map(progclknp, 0); + if (!irq) + continue; + + clk = at91_clk_register_programmable(pmc, irq, name, + parent_names, num_parents, + id, layout); + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(progclknp, of_clk_src_simple_get, clk); + } +} + + +void __init of_at91rm9200_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout); +} + +void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout); +} + +void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout); +} diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c new file mode 100644 index 0000000..144d47e --- /dev/null +++ b/drivers/clk/at91/clk-smd.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> + +#include "pmc.h" + +#define SMD_SOURCE_MAX 2 + +#define SMD_DIV_SHIFT 8 +#define SMD_MAX_DIV 0xf + +struct at91sam9x5_clk_smd { + struct clk_hw hw; + struct at91_pmc *pmc; +}; + +#define to_at91sam9x5_clk_smd(hw) \ + container_of(hw, struct at91sam9x5_clk_smd, hw) + +static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 tmp; + u8 smddiv; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); + struct at91_pmc *pmc = smd->pmc; + + tmp = pmc_read(pmc, AT91_PMC_SMD); + smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT; + return parent_rate / (smddiv + 1); +} + +static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long div; + unsigned long bestrate; + unsigned long tmp; + + if (rate >= *parent_rate) + return *parent_rate; + + div = *parent_rate / rate; + if (div > SMD_MAX_DIV) + return *parent_rate / (SMD_MAX_DIV + 1); + + bestrate = *parent_rate / div; + tmp = *parent_rate / (div + 1); + if (bestrate - rate > rate - tmp) + bestrate = tmp; + + return bestrate; +} + +static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index) +{ + u32 tmp; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); + struct at91_pmc *pmc = smd->pmc; + + if (index > 1) + return -EINVAL; + tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS; + if (index) + tmp |= AT91_PMC_SMDS; + pmc_write(pmc, AT91_PMC_SMD, tmp); + return 0; +} + +static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw) +{ + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); + struct at91_pmc *pmc = smd->pmc; + + return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS; +} + +static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 tmp; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); + struct at91_pmc *pmc = smd->pmc; + unsigned long div = parent_rate / rate; + + if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1)) + return -EINVAL; + tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV; + tmp |= (div - 1) << SMD_DIV_SHIFT; + pmc_write(pmc, AT91_PMC_SMD, tmp); + + return 0; +} + +static const struct clk_ops at91sam9x5_smd_ops = { + .recalc_rate = at91sam9x5_clk_smd_recalc_rate, + .round_rate = at91sam9x5_clk_smd_round_rate, + .get_parent = at91sam9x5_clk_smd_get_parent, + .set_parent = at91sam9x5_clk_smd_set_parent, + .set_rate = at91sam9x5_clk_smd_set_rate, +}; + +static struct clk * __init +at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, + const char **parent_names, u8 num_parents) +{ + struct at91sam9x5_clk_smd *smd; + struct clk *clk = NULL; + struct clk_init_data init; + + smd = kzalloc(sizeof(*smd), GFP_KERNEL); + if (!smd) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &at91sam9x5_smd_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + smd->hw.init = &init; + smd->pmc = pmc; + + clk = clk_register(NULL, &smd->hw); + if (IS_ERR(clk)) + kfree(smd); + + return clk; +} + +void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk *clk; + int i; + int num_parents; + const char *parent_names[SMD_SOURCE_MAX]; + const char *name = np->name; + + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) + return; + + for (i = 0; i < num_parents; i++) { + parent_names[i] = of_clk_get_parent_name(np, i); + if (!parent_names[i]) + return; + } + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91sam9x5_clk_register_smd(pmc, name, parent_names, + num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); +} diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c new file mode 100644 index 0000000..8f7c043 --- /dev/null +++ b/drivers/clk/at91/clk-system.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> + +#include "pmc.h" + +#define SYSTEM_MAX_ID 31 + +#define SYSTEM_MAX_NAME_SZ 32 + +#define to_clk_system(hw) container_of(hw, struct clk_system, hw) +struct clk_system { + struct clk_hw hw; + struct at91_pmc *pmc; + u8 id; +}; + +static int clk_system_enable(struct clk_hw *hw) +{ + struct clk_system *sys = to_clk_system(hw); + struct at91_pmc *pmc = sys->pmc; + + pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id); + return 0; +} + +static void clk_system_disable(struct clk_hw *hw) +{ + struct clk_system *sys = to_clk_system(hw); + struct at91_pmc *pmc = sys->pmc; + + pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id); +} + +static int clk_system_is_enabled(struct clk_hw *hw) +{ + struct clk_system *sys = to_clk_system(hw); + struct at91_pmc *pmc = sys->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)); +} + +static const struct clk_ops system_ops = { + .enable = clk_system_enable, + .disable = clk_system_disable, + .is_enabled = clk_system_is_enabled, +}; + +static struct clk * __init +at91_clk_register_system(struct at91_pmc *pmc, const char *name, + const char *parent_name, u8 id) +{ + struct clk_system *sys; + struct clk *clk = NULL; + struct clk_init_data init; + + if (!parent_name || id > SYSTEM_MAX_ID) + return ERR_PTR(-EINVAL); + + sys = kzalloc(sizeof(*sys), GFP_KERNEL); + if (!sys) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &system_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + /* + * CLK_IGNORE_UNUSED is used to avoid ddrck switch off. + * TODO : we should implement a driver supporting at91 ddr controller + * (see drivers/memory) which would request and enable the ddrck clock. + * When this is done we will be able to remove CLK_IGNORE_UNUSED flag. + */ + init.flags = CLK_IGNORE_UNUSED; + + sys->id = id; + sys->hw.init = &init; + sys->pmc = pmc; + + clk = clk_register(NULL, &sys->hw); + if (IS_ERR(clk)) + kfree(sys); + + return clk; +} + +static void __init +of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc) +{ + int num; + u32 id; + struct clk *clk; + const char *name; + struct device_node *sysclknp; + const char *parent_name; + + num = of_get_child_count(np); + if (num > (SYSTEM_MAX_ID + 1)) + return; + + for_each_child_of_node(np, sysclknp) { + if (of_property_read_u32(sysclknp, "reg", &id)) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = sysclknp->name; + + parent_name = of_clk_get_parent_name(sysclknp, 0); + + clk = at91_clk_register_system(pmc, name, parent_name, id); + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk); + } +} + +void __init of_at91rm9200_clk_sys_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_sys_setup(np, pmc); +} diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c new file mode 100644 index 0000000..7d1d26a --- /dev/null +++ b/drivers/clk/at91/clk-usb.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> + +#include "pmc.h" + +#define USB_SOURCE_MAX 2 + +#define SAM9X5_USB_DIV_SHIFT 8 +#define SAM9X5_USB_MAX_DIV 0xf + +#define RM9200_USB_DIV_SHIFT 28 +#define RM9200_USB_DIV_TAB_SIZE 4 + +struct at91sam9x5_clk_usb { + struct clk_hw hw; + struct at91_pmc *pmc; +}; + +#define to_at91sam9x5_clk_usb(hw) \ + container_of(hw, struct at91sam9x5_clk_usb, hw) + +struct at91rm9200_clk_usb { + struct clk_hw hw; + struct at91_pmc *pmc; + u32 divisors[4]; +}; + +#define to_at91rm9200_clk_usb(hw) \ + container_of(hw, struct at91rm9200_clk_usb, hw) + +static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 tmp; + u8 usbdiv; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + tmp = pmc_read(pmc, AT91_PMC_USB); + usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; + return parent_rate / (usbdiv + 1); +} + +static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long div; + unsigned long bestrate; + unsigned long tmp; + + if (rate >= *parent_rate) + return *parent_rate; + + div = *parent_rate / rate; + if (div >= SAM9X5_USB_MAX_DIV) + return *parent_rate / (SAM9X5_USB_MAX_DIV + 1); + + bestrate = *parent_rate / div; + tmp = *parent_rate / (div + 1); + if (bestrate - rate > rate - tmp) + bestrate = tmp; + + return bestrate; +} + +static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) +{ + u32 tmp; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + if (index > 1) + return -EINVAL; + tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS; + if (index) + tmp |= AT91_PMC_USBS; + pmc_write(pmc, AT91_PMC_USB, tmp); + return 0; +} + +static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) +{ + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS; +} + +static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 tmp; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + unsigned long div = parent_rate / rate; + + if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV) + return -EINVAL; + + tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; + tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT; + pmc_write(pmc, AT91_PMC_USB, tmp); + + return 0; +} + +static const struct clk_ops at91sam9x5_usb_ops = { + .recalc_rate = at91sam9x5_clk_usb_recalc_rate, + .round_rate = at91sam9x5_clk_usb_round_rate, + .get_parent = at91sam9x5_clk_usb_get_parent, + .set_parent = at91sam9x5_clk_usb_set_parent, + .set_rate = at91sam9x5_clk_usb_set_rate, +}; + +static int at91sam9n12_clk_usb_enable(struct clk_hw *hw) +{ + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + pmc_write(pmc, AT91_PMC_USB, + pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS); + return 0; +} + +static void at91sam9n12_clk_usb_disable(struct clk_hw *hw) +{ + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + pmc_write(pmc, AT91_PMC_USB, + pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS); +} + +static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw) +{ + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + + return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS); +} + +static const struct clk_ops at91sam9n12_usb_ops = { + .enable = at91sam9n12_clk_usb_enable, + .disable = at91sam9n12_clk_usb_disable, + .is_enabled = at91sam9n12_clk_usb_is_enabled, + .recalc_rate = at91sam9x5_clk_usb_recalc_rate, + .round_rate = at91sam9x5_clk_usb_round_rate, + .set_rate = at91sam9x5_clk_usb_set_rate, +}; + +static struct clk * __init +at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, + const char **parent_names, u8 num_parents) +{ + struct at91sam9x5_clk_usb *usb; + struct clk *clk = NULL; + struct clk_init_data init; + + usb = kzalloc(sizeof(*usb), GFP_KERNEL); + if (!usb) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &at91sam9x5_usb_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + usb->hw.init = &init; + usb->pmc = pmc; + + clk = clk_register(NULL, &usb->hw); + if (IS_ERR(clk)) + kfree(usb); + + return clk; +} + +static struct clk * __init +at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name, + const char *parent_name) +{ + struct at91sam9x5_clk_usb *usb; + struct clk *clk = NULL; + struct clk_init_data init; + + usb = kzalloc(sizeof(*usb), GFP_KERNEL); + if (!usb) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &at91sam9n12_usb_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + usb->hw.init = &init; + usb->pmc = pmc; + + clk = clk_register(NULL, &usb->hw); + if (IS_ERR(clk)) + kfree(usb); + + return clk; +} + +static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + u32 tmp; + u8 usbdiv; + + tmp = pmc_read(pmc, AT91_CKGR_PLLBR); + usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT; + if (usb->divisors[usbdiv]) + return parent_rate / usb->divisors[usbdiv]; + + return 0; +} + +static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); + unsigned long bestrate = 0; + int bestdiff = -1; + unsigned long tmprate; + int tmpdiff; + int i = 0; + + for (i = 0; i < 4; i++) { + if (!usb->divisors[i]) + continue; + tmprate = *parent_rate / usb->divisors[i]; + if (tmprate < rate) + tmpdiff = rate - tmprate; + else + tmpdiff = tmprate - rate; + + if (bestdiff < 0 || bestdiff > tmpdiff) { + bestrate = tmprate; + bestdiff = tmpdiff; + } + + if (!bestdiff) + break; + } + + return bestrate; +} + +static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 tmp; + int i; + struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); + struct at91_pmc *pmc = usb->pmc; + unsigned long div = parent_rate / rate; + + if (parent_rate % rate) + return -EINVAL; + for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { + if (usb->divisors[i] == div) { + tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & + ~AT91_PMC_USBDIV; + tmp |= i << RM9200_USB_DIV_SHIFT; + pmc_write(pmc, AT91_CKGR_PLLBR, tmp); + return 0; + } + } + + return -EINVAL; +} + +static const struct clk_ops at91rm9200_usb_ops = { + .recalc_rate = at91rm9200_clk_usb_recalc_rate, + .round_rate = at91rm9200_clk_usb_round_rate, + .set_rate = at91rm9200_clk_usb_set_rate, +}; + +static struct clk * __init +at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, + const char *parent_name, const u32 *divisors) +{ + struct at91rm9200_clk_usb *usb; + struct clk *clk = NULL; + struct clk_init_data init; + + usb = kzalloc(sizeof(*usb), GFP_KERNEL); + if (!usb) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &at91rm9200_usb_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + + usb->hw.init = &init; + usb->pmc = pmc; + memcpy(usb->divisors, divisors, sizeof(usb->divisors)); + + clk = clk_register(NULL, &usb->hw); + if (IS_ERR(clk)) + kfree(usb); + + return clk; +} + +void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk *clk; + int i; + int num_parents; + const char *parent_names[USB_SOURCE_MAX]; + const char *name = np->name; + + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) + return; + + for (i = 0; i < num_parents; i++) { + parent_names[i] = of_clk_get_parent_name(np, i); + if (!parent_names[i]) + return; + } + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk *clk; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91sam9n12_clk_register_usb(pmc, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +void __init of_at91rm9200_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk *clk; + const char *parent_name; + const char *name = np->name; + u32 divisors[4] = {0, 0, 0, 0}; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4); + if (!divisors[0]) + return; + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); +} diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c new file mode 100644 index 0000000..ae3263b --- /dev/null +++ b/drivers/clk/at91/clk-utmi.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/sched.h> +#include <linux/wait.h> + +#include "pmc.h" + +#define UTMI_FIXED_MUL 40 + +struct clk_utmi { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; +}; + +#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) + +static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id) +{ + struct clk_utmi *utmi = (struct clk_utmi *)dev_id; + + wake_up(&utmi->wait); + disable_irq_nosync(utmi->irq); + + return IRQ_HANDLED; +} + +static int clk_utmi_prepare(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN | + AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN; + + pmc_write(pmc, AT91_CKGR_UCKR, tmp); + + while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) { + enable_irq(utmi->irq); + wait_event(utmi->wait, + pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); + } + + return 0; +} + +static int clk_utmi_is_prepared(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); +} + +static void clk_utmi_unprepare(struct clk_hw *hw) +{ + struct clk_utmi *utmi = to_clk_utmi(hw); + struct at91_pmc *pmc = utmi->pmc; + u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN; + + pmc_write(pmc, AT91_CKGR_UCKR, tmp); +} + +static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + /* UTMI clk is a fixed clk multiplier */ + return parent_rate * UTMI_FIXED_MUL; +} + +static const struct clk_ops utmi_ops = { + .prepare = clk_utmi_prepare, + .unprepare = clk_utmi_unprepare, + .is_prepared = clk_utmi_is_prepared, + .recalc_rate = clk_utmi_recalc_rate, +}; + +static struct clk * __init +at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, + const char *name, const char *parent_name) +{ + int ret; + struct clk_utmi *utmi; + struct clk *clk = NULL; + struct clk_init_data init; + + utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &utmi_ops; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.flags = CLK_SET_RATE_GATE; + + utmi->hw.init = &init; + utmi->pmc = pmc; + utmi->irq = irq; + init_waitqueue_head(&utmi->wait); + irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); + ret = request_irq(utmi->irq, clk_utmi_irq_handler, + IRQF_TRIGGER_HIGH, "clk-utmi", utmi); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &utmi->hw); + if (IS_ERR(clk)) + kfree(utmi); + + return clk; +} + +static void __init +of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc) +{ + unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_utmi(pmc, irq, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +} + +void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_utmi_setup(np, pmc); +} diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c new file mode 100644 index 0000000..11fceff --- /dev/null +++ b/drivers/clk/at91/pmc.c @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/of_irq.h> + +#include <asm/proc-fns.h> + +#include "pmc.h" + +void __iomem *at91_pmc_base; +EXPORT_SYMBOL_GPL(at91_pmc_base); + +void at91sam9_idle(void) +{ + at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK); + cpu_do_idle(); +} + +int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range) +{ + u32 min, max; + int ret; + + ret = of_property_read_u32_index(np, propname, 0, &min); + if (ret) + return ret; + + ret = of_property_read_u32_index(np, propname, 1, &max); + if (ret) + return ret; + + if (range) { + range->min = min; + range->max = max; + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_at91_get_clk_range); + +static void pmc_irq_mask(struct irq_data *d) +{ + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + + pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq); +} + +static void pmc_irq_unmask(struct irq_data *d) +{ + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + + pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq); +} + +static int pmc_irq_set_type(struct irq_data *d, unsigned type) +{ + if (type != IRQ_TYPE_LEVEL_HIGH) { + pr_warn("PMC: type not supported (support only IRQ_TYPE_LEVEL_HIGH type)\n"); + return -EINVAL; + } + + return 0; +} + +static struct irq_chip pmc_irq = { + .name = "PMC", + .irq_disable = pmc_irq_mask, + .irq_mask = pmc_irq_mask, + .irq_unmask = pmc_irq_unmask, + .irq_set_type = pmc_irq_set_type, +}; + +static struct lock_class_key pmc_lock_class; + +static int pmc_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct at91_pmc *pmc = h->host_data; + + irq_set_lockdep_class(virq, &pmc_lock_class); + + irq_set_chip_and_handler(virq, &pmc_irq, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, pmc); + + return 0; +} + +static int pmc_irq_domain_xlate(struct irq_domain *d, + struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_type) +{ + struct at91_pmc *pmc = d->host_data; + const struct at91_pmc_caps *caps = pmc->caps; + + if (WARN_ON(intsize < 1)) + return -EINVAL; + + *out_hwirq = intspec[0]; + + if (!(caps->available_irqs & (1 << *out_hwirq))) + return -EINVAL; + + *out_type = IRQ_TYPE_LEVEL_HIGH; + + return 0; +} + +static struct irq_domain_ops pmc_irq_ops = { + .map = pmc_irq_map, + .xlate = pmc_irq_domain_xlate, +}; + +static irqreturn_t pmc_irq_handler(int irq, void *data) +{ + struct at91_pmc *pmc = (struct at91_pmc *)data; + unsigned long sr; + int n; + + sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR); + if (!sr) + return IRQ_NONE; + + for_each_set_bit(n, &sr, BITS_PER_LONG) + generic_handle_irq(irq_find_mapping(pmc->irqdomain, n)); + + return IRQ_HANDLED; +} + +static const struct at91_pmc_caps at91rm9200_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | + AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | + AT91_PMC_PCK3RDY, +}; + +static const struct at91_pmc_caps at91sam9260_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | + AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY, +}; + +static const struct at91_pmc_caps at91sam9g45_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | + AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY, +}; + +static const struct at91_pmc_caps at91sam9n12_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | + AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | + AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, +}; + +static const struct at91_pmc_caps at91sam9x5_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | + AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | + AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, +}; + +static const struct at91_pmc_caps sama5d3_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | + AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | + AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | + AT91_PMC_CFDEV, +}; + +static struct at91_pmc *__init at91_pmc_init(struct device_node *np, + void __iomem *regbase, int virq, + const struct at91_pmc_caps *caps) +{ + struct at91_pmc *pmc; + + if (!regbase || !virq || !caps) + return NULL; + + at91_pmc_base = regbase; + + pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); + if (!pmc) + return NULL; + + spin_lock_init(&pmc->lock); + pmc->regbase = regbase; + pmc->virq = virq; + pmc->caps = caps; + + pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc); + + if (!pmc->irqdomain) + goto out_free_pmc; + + pmc_write(pmc, AT91_PMC_IDR, 0xffffffff); + if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc)) + goto out_remove_irqdomain; + + return pmc; + +out_remove_irqdomain: + irq_domain_remove(pmc->irqdomain); +out_free_pmc: + kfree(pmc); + + return NULL; +} + +static const struct of_device_id pmc_clk_ids[] __initdata = { + /* Main clock */ + { + .compatible = "atmel,at91rm9200-clk-main", + .data = of_at91rm9200_clk_main_setup, + }, + /* PLL clocks */ + { + .compatible = "atmel,at91rm9200-clk-pll", + .data = of_at91rm9200_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9g45-clk-pll", + .data = of_at91sam9g45_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9g20-clk-pllb", + .data = of_at91sam9g20_clk_pllb_setup, + }, + { + .compatible = "atmel,sama5d3-clk-pll", + .data = of_sama5d3_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-plldiv", + .data = of_at91sam9x5_clk_plldiv_setup, + }, + /* Master clock */ + { + .compatible = "atmel,at91rm9200-clk-master", + .data = of_at91rm9200_clk_master_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-master", + .data = of_at91sam9x5_clk_master_setup, + }, + /* System clocks */ + { + .compatible = "atmel,at91rm9200-clk-system", + .data = of_at91rm9200_clk_sys_setup, + }, + /* Peripheral clocks */ + { + .compatible = "atmel,at91rm9200-clk-peripheral", + .data = of_at91rm9200_clk_periph_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-peripheral", + .data = of_at91sam9x5_clk_periph_setup, + }, + /* Programmable clocks */ + { + .compatible = "atmel,at91rm9200-clk-programmable", + .data = of_at91rm9200_clk_prog_setup, + }, + { + .compatible = "atmel,at91sam9g45-clk-programmable", + .data = of_at91sam9g45_clk_prog_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-programmable", + .data = of_at91sam9x5_clk_prog_setup, + }, + /* UTMI clock */ +#if defined(CONFIG_HAVE_AT91_UTMI) + { + .compatible = "atmel,at91sam9x5-clk-utmi", + .data = of_at91sam9x5_clk_utmi_setup, + }, +#endif + /* USB clock */ +#if defined(CONFIG_HAVE_AT91_USB_CLK) + { + .compatible = "atmel,at91rm9200-clk-usb", + .data = of_at91rm9200_clk_usb_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-usb", + .data = of_at91sam9x5_clk_usb_setup, + }, + { + .compatible = "atmel,at91sam9n12-clk-usb", + .data = of_at91sam9n12_clk_usb_setup, + }, +#endif + /* SMD clock */ +#if defined(CONFIG_HAVE_AT91_SMD) + { + .compatible = "atmel,at91sam9x5-clk-smd", + .data = of_at91sam9x5_clk_smd_setup, + }, +#endif + { /*sentinel*/ } +}; + +static void __init of_at91_pmc_setup(struct device_node *np, + const struct at91_pmc_caps *caps) +{ + struct at91_pmc *pmc; + struct device_node *childnp; + void (*clk_setup)(struct device_node *, struct at91_pmc *); + const struct of_device_id *clk_id; + void __iomem *regbase = of_iomap(np, 0); + int virq; + + if (!regbase) + return; + + virq = irq_of_parse_and_map(np, 0); + if (!virq) + return; + + pmc = at91_pmc_init(np, regbase, virq, caps); + if (!pmc) + return; + for_each_child_of_node(np, childnp) { + clk_id = of_match_node(pmc_clk_ids, childnp); + if (!clk_id) + continue; + clk_setup = clk_id->data; + clk_setup(childnp, pmc); + } +} + +static void __init of_at91rm9200_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &at91rm9200_caps); +} +CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc", + of_at91rm9200_pmc_setup); + +static void __init of_at91sam9260_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &at91sam9260_caps); +} +CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc", + of_at91sam9260_pmc_setup); + +static void __init of_at91sam9g45_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &at91sam9g45_caps); +} +CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc", + of_at91sam9g45_pmc_setup); + +static void __init of_at91sam9n12_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &at91sam9n12_caps); +} +CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc", + of_at91sam9n12_pmc_setup); + +static void __init of_at91sam9x5_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &at91sam9x5_caps); +} +CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc", + of_at91sam9x5_pmc_setup); + +static void __init of_sama5d3_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &sama5d3_caps); +} +CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc", + of_sama5d3_pmc_setup); diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h new file mode 100644 index 0000000..4413509 --- /dev/null +++ b/drivers/clk/at91/pmc.h @@ -0,0 +1,114 @@ +/* + * drivers/clk/at91/pmc.h + * + * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __PMC_H_ +#define __PMC_H_ + +#include <linux/io.h> +#include <linux/irqdomain.h> +#include <linux/spinlock.h> + +struct clk_range { + unsigned long min; + unsigned long max; +}; + +#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} + +struct at91_pmc_caps { + u32 available_irqs; +}; + +struct at91_pmc { + void __iomem *regbase; + int virq; + spinlock_t lock; + const struct at91_pmc_caps *caps; + struct irq_domain *irqdomain; +}; + +static inline void pmc_lock(struct at91_pmc *pmc) +{ + spin_lock(&pmc->lock); +} + +static inline void pmc_unlock(struct at91_pmc *pmc) +{ + spin_unlock(&pmc->lock); +} + +static inline u32 pmc_read(struct at91_pmc *pmc, int offset) +{ + return readl(pmc->regbase + offset); +} + +static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) +{ + writel(value, pmc->regbase + offset); +} + +int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range); + +extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc); + +extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc); + +extern void __init of_at91rm9200_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); + +extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np, + struct at91_pmc *pmc); + +extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); + +extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); + +#if defined(CONFIG_HAVE_AT91_UTMI) +extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc); +#endif + +#if defined(CONFIG_HAVE_AT91_USB_CLK) +extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +#endif + +#if defined(CONFIG_HAVE_AT91_SMD) +extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, + struct at91_pmc *pmc); +#endif + +#endif /* __PMC_H_ */ diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c index f2c7506..dfd1643 100644 --- a/drivers/cpufreq/exynos4210-cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c @@ -157,4 +157,3 @@ err_moutcore: pr_debug("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos4210_cpufreq_init); diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index 8683304..efad5e6 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -211,4 +211,3 @@ err_moutcore: pr_debug("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos4x12_cpufreq_init); diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c index 9fae466..8feda86 100644 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ b/drivers/cpufreq/exynos5250-cpufreq.c @@ -236,4 +236,3 @@ err_moutcore: pr_err("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos5250_cpufreq_init); diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index f42df7e..b7309c3 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -142,10 +142,8 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index) mutex_lock(&tegra_cpu_lock); - if (is_suspended) { - ret = -EBUSY; + if (is_suspended) goto out; - } freq = freq_table[index].frequency; diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index ca89f6b..e7555ff 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -4,16 +4,29 @@ config CRYPTO_DEV_FSL_CAAM help Enables the driver module for Freescale's Cryptographic Accelerator and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). - This module adds a job ring operation interface, and configures h/w + This module creates job ring devices, and configures h/w to operate as a DPAA component automatically, depending on h/w feature availability. To compile this driver as a module, choose M here: the module will be called caam. +config CRYPTO_DEV_FSL_CAAM_JR + tristate "Freescale CAAM Job Ring driver backend" + depends on CRYPTO_DEV_FSL_CAAM + default y + help + Enables the driver module for Job Rings which are part of + Freescale's Cryptographic Accelerator + and Assurance Module (CAAM). This module adds a job ring operation + interface. + + To compile this driver as a module, choose M here: the module + will be called caam_jr. + config CRYPTO_DEV_FSL_CAAM_RINGSIZE int "Job Ring size" - depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM_JR range 2 9 default "9" help @@ -31,7 +44,7 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE config CRYPTO_DEV_FSL_CAAM_INTC bool "Job Ring interrupt coalescing" - depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM_JR default n help Enable the Job Ring's interrupt coalescing feature. @@ -62,7 +75,7 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD config CRYPTO_DEV_FSL_CAAM_CRYPTO_API tristate "Register algorithm implementations with the Crypto API" - depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_ALGAPI select CRYPTO_AUTHENC @@ -76,7 +89,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API config CRYPTO_DEV_FSL_CAAM_AHASH_API tristate "Register hash algorithm implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_HASH help @@ -88,7 +101,7 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API config CRYPTO_DEV_FSL_CAAM_RNG_API tristate "Register caam device for hwrng API" - depends on CRYPTO_DEV_FSL_CAAM + depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_RNG select HW_RANDOM diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index d56bd0e..550758a 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -6,8 +6,10 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y) endif obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o -caam-objs := ctrl.o jr.o error.o key_gen.o +caam-objs := ctrl.o +caam_jr-objs := jr.o key_gen.o error.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 7c63b72..4f44b71 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -86,6 +86,7 @@ #else #define debug(format, arg...) #endif +static struct list_head alg_list; /* Set DK bit in class 1 operation if shared */ static inline void append_dec_op1(u32 *desc, u32 type) @@ -2057,7 +2058,6 @@ static struct caam_alg_template driver_algs[] = { struct caam_crypto_alg { struct list_head entry; - struct device *ctrldev; int class1_alg_type; int class2_alg_type; int alg_op; @@ -2070,14 +2070,12 @@ static int caam_cra_init(struct crypto_tfm *tfm) struct caam_crypto_alg *caam_alg = container_of(alg, struct caam_crypto_alg, crypto_alg); struct caam_ctx *ctx = crypto_tfm_ctx(tfm); - struct caam_drv_private *priv = dev_get_drvdata(caam_alg->ctrldev); - int tgt_jr = atomic_inc_return(&priv->tfm_count); - /* - * distribute tfms across job rings to ensure in-order - * crypto request processing per tfm - */ - ctx->jrdev = priv->jrdev[(tgt_jr / 2) % priv->total_jobrs]; + ctx->jrdev = caam_jr_alloc(); + if (IS_ERR(ctx->jrdev)) { + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(ctx->jrdev); + } /* copy descriptor header template value */ ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type; @@ -2104,44 +2102,26 @@ static void caam_cra_exit(struct crypto_tfm *tfm) dma_unmap_single(ctx->jrdev, ctx->sh_desc_givenc_dma, desc_bytes(ctx->sh_desc_givenc), DMA_TO_DEVICE); + + caam_jr_free(ctx->jrdev); } static void __exit caam_algapi_exit(void) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; struct caam_crypto_alg *t_alg, *n; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) - return; - - ctrldev = &pdev->dev; - of_node_put(dev_node); - priv = dev_get_drvdata(ctrldev); - - if (!priv->alg_list.next) + if (!alg_list.next) return; - list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { + list_for_each_entry_safe(t_alg, n, &alg_list, entry) { crypto_unregister_alg(&t_alg->crypto_alg); list_del(&t_alg->entry); kfree(t_alg); } } -static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, - struct caam_alg_template +static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template *template) { struct caam_crypto_alg *t_alg; @@ -2149,7 +2129,7 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, t_alg = kzalloc(sizeof(struct caam_crypto_alg), GFP_KERNEL); if (!t_alg) { - dev_err(ctrldev, "failed to allocate t_alg\n"); + pr_err("failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); } @@ -2181,62 +2161,39 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, t_alg->class1_alg_type = template->class1_alg_type; t_alg->class2_alg_type = template->class2_alg_type; t_alg->alg_op = template->alg_op; - t_alg->ctrldev = ctrldev; return t_alg; } static int __init caam_algapi_init(void) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; int i = 0, err = 0; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) - return -ENODEV; - - ctrldev = &pdev->dev; - priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); - - INIT_LIST_HEAD(&priv->alg_list); - - atomic_set(&priv->tfm_count, -1); + INIT_LIST_HEAD(&alg_list); /* register crypto algorithms the device supports */ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { /* TODO: check if h/w supports alg */ struct caam_crypto_alg *t_alg; - t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); + t_alg = caam_alg_alloc(&driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - dev_warn(ctrldev, "%s alg allocation failed\n", - driver_algs[i].driver_name); + pr_warn("%s alg allocation failed\n", + driver_algs[i].driver_name); continue; } err = crypto_register_alg(&t_alg->crypto_alg); if (err) { - dev_warn(ctrldev, "%s alg registration failed\n", + pr_warn("%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); } else - list_add_tail(&t_alg->entry, &priv->alg_list); + list_add_tail(&t_alg->entry, &alg_list); } - if (!list_empty(&priv->alg_list)) - dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", - (char *)of_get_property(dev_node, "compatible", NULL)); + if (!list_empty(&alg_list)) + pr_info("caam algorithms registered in /proc/crypto\n"); return err; } diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index e732bd9..0378328 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -94,6 +94,9 @@ #define debug(format, arg...) #endif + +static struct list_head hash_list; + /* ahash per-session context */ struct caam_hash_ctx { struct device *jrdev; @@ -1653,7 +1656,6 @@ static struct caam_hash_template driver_hash[] = { struct caam_hash_alg { struct list_head entry; - struct device *ctrldev; int alg_type; int alg_op; struct ahash_alg ahash_alg; @@ -1670,7 +1672,6 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) struct caam_hash_alg *caam_hash = container_of(alg, struct caam_hash_alg, ahash_alg); struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); - struct caam_drv_private *priv = dev_get_drvdata(caam_hash->ctrldev); /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */ static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE, HASH_MSG_LEN + SHA1_DIGEST_SIZE, @@ -1678,15 +1679,17 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) HASH_MSG_LEN + SHA256_DIGEST_SIZE, HASH_MSG_LEN + 64, HASH_MSG_LEN + SHA512_DIGEST_SIZE }; - int tgt_jr = atomic_inc_return(&priv->tfm_count); int ret = 0; /* - * distribute tfms across job rings to ensure in-order + * Get a Job ring from Job Ring driver to ensure in-order * crypto request processing per tfm */ - ctx->jrdev = priv->jrdev[tgt_jr % priv->total_jobrs]; - + ctx->jrdev = caam_jr_alloc(); + if (IS_ERR(ctx->jrdev)) { + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(ctx->jrdev); + } /* copy descriptor header template value */ ctx->alg_type = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_hash->alg_op; @@ -1729,35 +1732,18 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) !dma_mapping_error(ctx->jrdev, ctx->sh_desc_finup_dma)) dma_unmap_single(ctx->jrdev, ctx->sh_desc_finup_dma, desc_bytes(ctx->sh_desc_finup), DMA_TO_DEVICE); + + caam_jr_free(ctx->jrdev); } static void __exit caam_algapi_hash_exit(void) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; struct caam_hash_alg *t_alg, *n; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) + if (!hash_list.next) return; - ctrldev = &pdev->dev; - of_node_put(dev_node); - priv = dev_get_drvdata(ctrldev); - - if (!priv->hash_list.next) - return; - - list_for_each_entry_safe(t_alg, n, &priv->hash_list, entry) { + list_for_each_entry_safe(t_alg, n, &hash_list, entry) { crypto_unregister_ahash(&t_alg->ahash_alg); list_del(&t_alg->entry); kfree(t_alg); @@ -1765,7 +1751,7 @@ static void __exit caam_algapi_hash_exit(void) } static struct caam_hash_alg * -caam_hash_alloc(struct device *ctrldev, struct caam_hash_template *template, +caam_hash_alloc(struct caam_hash_template *template, bool keyed) { struct caam_hash_alg *t_alg; @@ -1774,7 +1760,7 @@ caam_hash_alloc(struct device *ctrldev, struct caam_hash_template *template, t_alg = kzalloc(sizeof(struct caam_hash_alg), GFP_KERNEL); if (!t_alg) { - dev_err(ctrldev, "failed to allocate t_alg\n"); + pr_err("failed to allocate t_alg\n"); return ERR_PTR(-ENOMEM); } @@ -1805,37 +1791,15 @@ caam_hash_alloc(struct device *ctrldev, struct caam_hash_template *template, t_alg->alg_type = template->alg_type; t_alg->alg_op = template->alg_op; - t_alg->ctrldev = ctrldev; return t_alg; } static int __init caam_algapi_hash_init(void) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; int i = 0, err = 0; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) - return -ENODEV; - - ctrldev = &pdev->dev; - priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); - - INIT_LIST_HEAD(&priv->hash_list); - - atomic_set(&priv->tfm_count, -1); + INIT_LIST_HEAD(&hash_list); /* register crypto algorithms the device supports */ for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { @@ -1843,38 +1807,38 @@ static int __init caam_algapi_hash_init(void) struct caam_hash_alg *t_alg; /* register hmac version */ - t_alg = caam_hash_alloc(ctrldev, &driver_hash[i], true); + t_alg = caam_hash_alloc(&driver_hash[i], true); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - dev_warn(ctrldev, "%s alg allocation failed\n", - driver_hash[i].driver_name); + pr_warn("%s alg allocation failed\n", + driver_hash[i].driver_name); continue; } err = crypto_register_ahash(&t_alg->ahash_alg); if (err) { - dev_warn(ctrldev, "%s alg registration failed\n", + pr_warn("%s alg registration failed\n", t_alg->ahash_alg.halg.base.cra_driver_name); kfree(t_alg); } else - list_add_tail(&t_alg->entry, &priv->hash_list); + list_add_tail(&t_alg->entry, &hash_list); /* register unkeyed version */ - t_alg = caam_hash_alloc(ctrldev, &driver_hash[i], false); + t_alg = caam_hash_alloc(&driver_hash[i], false); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - dev_warn(ctrldev, "%s alg allocation failed\n", - driver_hash[i].driver_name); + pr_warn("%s alg allocation failed\n", + driver_hash[i].driver_name); continue; } err = crypto_register_ahash(&t_alg->ahash_alg); if (err) { - dev_warn(ctrldev, "%s alg registration failed\n", + pr_warn("%s alg registration failed\n", t_alg->ahash_alg.halg.base.cra_driver_name); kfree(t_alg); } else - list_add_tail(&t_alg->entry, &priv->hash_list); + list_add_tail(&t_alg->entry, &hash_list); } return err; diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index d1939a9..28486b1 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -273,34 +273,23 @@ static struct hwrng caam_rng = { static void __exit caam_rng_exit(void) { + caam_jr_free(rng_ctx.jrdev); hwrng_unregister(&caam_rng); } static int __init caam_rng_init(void) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; - - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) - return -ENODEV; + struct device *dev; - ctrldev = &pdev->dev; - priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); + dev = caam_jr_alloc(); + if (IS_ERR(dev)) { + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(dev); + } - caam_init_rng(&rng_ctx, priv->jrdev[0]); + caam_init_rng(&rng_ctx, dev); - dev_info(priv->jrdev[0], "registering rng-caam\n"); + dev_info(dev, "registering rng-caam\n"); return hwrng_register(&caam_rng); } diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index bc6d820..63fb1af 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -16,82 +16,75 @@ #include "error.h" #include "ctrl.h" -static int caam_remove(struct platform_device *pdev) -{ - struct device *ctrldev; - struct caam_drv_private *ctrlpriv; - struct caam_drv_private_jr *jrpriv; - struct caam_full __iomem *topregs; - int ring, ret = 0; - - ctrldev = &pdev->dev; - ctrlpriv = dev_get_drvdata(ctrldev); - topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; - - /* shut down JobRs */ - for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { - ret |= caam_jr_shutdown(ctrlpriv->jrdev[ring]); - jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); - irq_dispose_mapping(jrpriv->irq); - } - - /* Shut down debug views */ -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(ctrlpriv->dfs_root); -#endif - - /* Unmap controller region */ - iounmap(&topregs->ctrl); - - kfree(ctrlpriv->jrdev); - kfree(ctrlpriv); - - return ret; -} - /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers */ -static void build_instantiation_desc(u32 *desc) +static void build_instantiation_desc(u32 *desc, int handle, int do_sk) { - u32 *jump_cmd; + u32 *jump_cmd, op_flags; init_job_desc(desc, 0); + op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | + (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT; + /* INIT RNG in non-test mode */ - append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - OP_ALG_AS_INIT); + append_operation(desc, op_flags); + + if (!handle && do_sk) { + /* + * For SH0, Secure Keys must be generated as well + */ + + /* wait for done */ + jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); + set_jump_tgt_here(desc, jump_cmd); + + /* + * load 1 to clear written reg: + * resets the done interrrupt and returns the RNG to idle. + */ + append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); + + /* Initialize State Handle */ + append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | + OP_ALG_AAI_RNG4_SK); + } - /* wait for done */ - jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); - set_jump_tgt_here(desc, jump_cmd); + append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); +} - /* - * load 1 to clear written reg: - * resets the done interrupt and returns the RNG to idle. - */ - append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); +/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ +static void build_deinstantiation_desc(u32 *desc, int handle) +{ + init_job_desc(desc, 0); - /* generate secure keys (non-test) */ + /* Uninstantiate State Handle 0 */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - OP_ALG_RNG4_SK); + (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); + + append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); } -static int instantiate_rng(struct device *ctrldev) +/* + * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of + * the software (no JR/QI used). + * @ctrldev - pointer to device + * @status - descriptor status, after being run + * + * Return: - 0 if no error occurred + * - -ENODEV if the DECO couldn't be acquired + * - -EAGAIN if an error occurred while executing the descriptor + */ +static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, + u32 *status) { struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_full __iomem *topregs; unsigned int timeout = 100000; - u32 *desc; - int i, ret = 0; - - desc = kmalloc(CAAM_CMD_SZ * 6, GFP_KERNEL | GFP_DMA); - if (!desc) { - dev_err(ctrldev, "can't allocate RNG init descriptor memory\n"); - return -ENOMEM; - } - build_instantiation_desc(desc); + u32 deco_dbg_reg, flags; + int i; /* Set the bit to request direct access to DECO0 */ topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; @@ -103,36 +96,219 @@ static int instantiate_rng(struct device *ctrldev) if (!timeout) { dev_err(ctrldev, "failed to acquire DECO 0\n"); - ret = -EIO; - goto out; + clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE); + return -ENODEV; } for (i = 0; i < desc_len(desc); i++) - topregs->deco.descbuf[i] = *(desc + i); + wr_reg32(&topregs->deco.descbuf[i], *(desc + i)); + + flags = DECO_JQCR_WHL; + /* + * If the descriptor length is longer than 4 words, then the + * FOUR bit in JRCTRL register must be set. + */ + if (desc_len(desc) >= 4) + flags |= DECO_JQCR_FOUR; - wr_reg32(&topregs->deco.jr_ctl_hi, DECO_JQCR_WHL | DECO_JQCR_FOUR); + /* Instruct the DECO to execute it */ + wr_reg32(&topregs->deco.jr_ctl_hi, flags); timeout = 10000000; - while ((rd_reg32(&topregs->deco.desc_dbg) & DECO_DBG_VALID) && - --timeout) + do { + deco_dbg_reg = rd_reg32(&topregs->deco.desc_dbg); + /* + * If an error occured in the descriptor, then + * the DECO status field will be set to 0x0D + */ + if ((deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) == + DESC_DBG_DECO_STAT_HOST_ERR) + break; cpu_relax(); + } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); - if (!timeout) { - dev_err(ctrldev, "failed to instantiate RNG\n"); - ret = -EIO; - } + *status = rd_reg32(&topregs->deco.op_status_hi) & + DECO_OP_STATUS_HI_ERR_MASK; + /* Mark the DECO as free */ clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE); -out: + + if (!timeout) + return -EAGAIN; + + return 0; +} + +/* + * instantiate_rng - builds and executes a descriptor on DECO0, + * which initializes the RNG block. + * @ctrldev - pointer to device + * @state_handle_mask - bitmask containing the instantiation status + * for the RNG4 state handles which exist in + * the RNG4 block: 1 if it's been instantiated + * by an external entry, 0 otherwise. + * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; + * Caution: this can be done only once; if the keys need to be + * regenerated, a POR is required + * + * Return: - 0 if no error occurred + * - -ENOMEM if there isn't enough memory to allocate the descriptor + * - -ENODEV if DECO0 couldn't be acquired + * - -EAGAIN if an error occurred when executing the descriptor + * f.i. there was a RNG hardware error due to not "good enough" + * entropy being aquired. + */ +static int instantiate_rng(struct device *ctrldev, int state_handle_mask, + int gen_sk) +{ + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); + struct caam_full __iomem *topregs; + struct rng4tst __iomem *r4tst; + u32 *desc, status, rdsta_val; + int ret = 0, sh_idx; + + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + r4tst = &topregs->ctrl.r4tst[0]; + + desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); + if (!desc) + return -ENOMEM; + + for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { + /* + * If the corresponding bit is set, this state handle + * was initialized by somebody else, so it's left alone. + */ + if ((1 << sh_idx) & state_handle_mask) + continue; + + /* Create the descriptor for instantiating RNG State Handle */ + build_instantiation_desc(desc, sh_idx, gen_sk); + + /* Try to run it through DECO0 */ + ret = run_descriptor_deco0(ctrldev, desc, &status); + + /* + * If ret is not 0, or descriptor status is not 0, then + * something went wrong. No need to try the next state + * handle (if available), bail out here. + * Also, if for some reason, the State Handle didn't get + * instantiated although the descriptor has finished + * without any error (HW optimizations for later + * CAAM eras), then try again. + */ + rdsta_val = + rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IFMASK; + if (status || !(rdsta_val & (1 << sh_idx))) + ret = -EAGAIN; + if (ret) + break; + + dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); + /* Clear the contents before recreating the descriptor */ + memset(desc, 0x00, CAAM_CMD_SZ * 7); + } + kfree(desc); + return ret; } /* - * By default, the TRNG runs for 200 clocks per sample; - * 1600 clocks per sample generates better entropy. + * deinstantiate_rng - builds and executes a descriptor on DECO0, + * which deinitializes the RNG block. + * @ctrldev - pointer to device + * @state_handle_mask - bitmask containing the instantiation status + * for the RNG4 state handles which exist in + * the RNG4 block: 1 if it's been instantiated + * + * Return: - 0 if no error occurred + * - -ENOMEM if there isn't enough memory to allocate the descriptor + * - -ENODEV if DECO0 couldn't be acquired + * - -EAGAIN if an error occurred when executing the descriptor */ -static void kick_trng(struct platform_device *pdev) +static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) +{ + u32 *desc, status; + int sh_idx, ret = 0; + + desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); + if (!desc) + return -ENOMEM; + + for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { + /* + * If the corresponding bit is set, then it means the state + * handle was initialized by us, and thus it needs to be + * deintialized as well + */ + if ((1 << sh_idx) & state_handle_mask) { + /* + * Create the descriptor for deinstantating this state + * handle + */ + build_deinstantiation_desc(desc, sh_idx); + + /* Try to run it through DECO0 */ + ret = run_descriptor_deco0(ctrldev, desc, &status); + + if (ret || status) { + dev_err(ctrldev, + "Failed to deinstantiate RNG4 SH%d\n", + sh_idx); + break; + } + dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); + } + } + + kfree(desc); + + return ret; +} + +static int caam_remove(struct platform_device *pdev) +{ + struct device *ctrldev; + struct caam_drv_private *ctrlpriv; + struct caam_full __iomem *topregs; + int ring, ret = 0; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + + /* Remove platform devices for JobRs */ + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + if (ctrlpriv->jrpdev[ring]) + of_device_unregister(ctrlpriv->jrpdev[ring]); + } + + /* De-initialize RNG state handles initialized by this driver. */ + if (ctrlpriv->rng4_sh_init) + deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); + + /* Shut down debug views */ +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(ctrlpriv->dfs_root); +#endif + + /* Unmap controller region */ + iounmap(&topregs->ctrl); + + kfree(ctrlpriv->jrpdev); + kfree(ctrlpriv); + + return ret; +} + +/* + * kick_trng - sets the various parameters for enabling the initialization + * of the RNG4 block in CAAM + * @pdev - pointer to the platform device + * @ent_delay - Defines the length (in system clocks) of each entropy sample. + */ +static void kick_trng(struct platform_device *pdev, int ent_delay) { struct device *ctrldev = &pdev->dev; struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); @@ -145,14 +321,31 @@ static void kick_trng(struct platform_device *pdev) /* put RNG4 into program mode */ setbits32(&r4tst->rtmctl, RTMCTL_PRGM); - /* 1600 clocks per sample */ + + /* + * Performance-wise, it does not make sense to + * set the delay to a value that is lower + * than the last one that worked (i.e. the state handles + * were instantiated properly. Thus, instead of wasting + * time trying to set the values controlling the sample + * frequency, the function simply returns. + */ + val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK) + >> RTSDCTL_ENT_DLY_SHIFT; + if (ent_delay <= val) { + /* put RNG4 into run mode */ + clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); + return; + } + val = rd_reg32(&r4tst->rtsdctl); - val = (val & ~RTSDCTL_ENT_DLY_MASK) | (1600 << RTSDCTL_ENT_DLY_SHIFT); + val = (val & ~RTSDCTL_ENT_DLY_MASK) | + (ent_delay << RTSDCTL_ENT_DLY_SHIFT); wr_reg32(&r4tst->rtsdctl, val); - /* min. freq. count */ - wr_reg32(&r4tst->rtfrqmin, 400); - /* max. freq. count */ - wr_reg32(&r4tst->rtfrqmax, 6400); + /* min. freq. count, equal to 1/4 of the entropy sample length */ + wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2); + /* max. freq. count, equal to 8 times the entropy sample length */ + wr_reg32(&r4tst->rtfrqmax, ent_delay << 3); /* put RNG4 into run mode */ clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); } @@ -193,7 +386,7 @@ EXPORT_SYMBOL(caam_get_era); /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { - int ret, ring, rspec; + int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; u64 caam_id; struct device *dev; struct device_node *nprop, *np; @@ -258,8 +451,9 @@ static int caam_probe(struct platform_device *pdev) rspec++; } - ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL); - if (ctrlpriv->jrdev == NULL) { + ctrlpriv->jrpdev = kzalloc(sizeof(struct platform_device *) * rspec, + GFP_KERNEL); + if (ctrlpriv->jrpdev == NULL) { iounmap(&topregs->ctrl); return -ENOMEM; } @@ -267,13 +461,24 @@ static int caam_probe(struct platform_device *pdev) ring = 0; ctrlpriv->total_jobrs = 0; for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { - caam_jr_probe(pdev, np, ring); + ctrlpriv->jrpdev[ring] = + of_platform_device_create(np, NULL, dev); + if (!ctrlpriv->jrpdev[ring]) { + pr_warn("JR%d Platform device creation error\n", ring); + continue; + } ctrlpriv->total_jobrs++; ring++; } if (!ring) { for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { - caam_jr_probe(pdev, np, ring); + ctrlpriv->jrpdev[ring] = + of_platform_device_create(np, NULL, dev); + if (!ctrlpriv->jrpdev[ring]) { + pr_warn("JR%d Platform device creation error\n", + ring); + continue; + } ctrlpriv->total_jobrs++; ring++; } @@ -299,16 +504,55 @@ static int caam_probe(struct platform_device *pdev) /* * If SEC has RNG version >= 4 and RNG state handle has not been - * already instantiated ,do RNG instantiation + * already instantiated, do RNG instantiation */ - if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4 && - !(rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IF0)) { - kick_trng(pdev); - ret = instantiate_rng(dev); + if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4) { + ctrlpriv->rng4_sh_init = + rd_reg32(&topregs->ctrl.r4tst[0].rdsta); + /* + * If the secure keys (TDKEK, JDKEK, TDSK), were already + * generated, signal this to the function that is instantiating + * the state handles. An error would occur if RNG4 attempts + * to regenerate these keys before the next POR. + */ + gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; + ctrlpriv->rng4_sh_init &= RDSTA_IFMASK; + do { + int inst_handles = + rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & + RDSTA_IFMASK; + /* + * If either SH were instantiated by somebody else + * (e.g. u-boot) then it is assumed that the entropy + * parameters are properly set and thus the function + * setting these (kick_trng(...)) is skipped. + * Also, if a handle was instantiated, do not change + * the TRNG parameters. + */ + if (!(ctrlpriv->rng4_sh_init || inst_handles)) { + kick_trng(pdev, ent_delay); + ent_delay += 400; + } + /* + * if instantiate_rng(...) fails, the loop will rerun + * and the kick_trng(...) function will modfiy the + * upper and lower limits of the entropy sampling + * interval, leading to a sucessful initialization of + * the RNG. + */ + ret = instantiate_rng(dev, inst_handles, + gen_sk); + } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); if (ret) { + dev_err(dev, "failed to instantiate RNG"); caam_remove(pdev); return ret; } + /* + * Set handles init'ed by this module as the complement of the + * already initialized ones + */ + ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK; /* Enable RDB bit so that RNG works faster */ setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE); diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index 53b296f..7e4500f 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -1155,8 +1155,15 @@ struct sec4_sg_entry { /* randomizer AAI set */ #define OP_ALG_AAI_RNG (0x00 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG_NOZERO (0x10 << OP_ALG_AAI_SHIFT) -#define OP_ALG_AAI_RNG_ODD (0x20 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_NZB (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_OBP (0x20 << OP_ALG_AAI_SHIFT) + +/* RNG4 AAI set */ +#define OP_ALG_AAI_RNG4_SH_0 (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG4_SH_1 (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG4_PS (0x40 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG4_AI (0x80 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG4_SK (0x100 << OP_ALG_AAI_SHIFT) /* hmac/smac AAI set */ #define OP_ALG_AAI_HASH (0x00 << OP_ALG_AAI_SHIFT) @@ -1178,12 +1185,6 @@ struct sec4_sg_entry { #define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT) #define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT) -/* RNG4 set */ -#define OP_ALG_RNG4_SHIFT 4 -#define OP_ALG_RNG4_MASK (0x1f3 << OP_ALG_RNG4_SHIFT) - -#define OP_ALG_RNG4_SK (0x100 << OP_ALG_RNG4_SHIFT) - #define OP_ALG_AS_SHIFT 2 #define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT) #define OP_ALG_AS_UPDATE (0 << OP_ALG_AS_SHIFT) diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 34c4b9f..6d85fcc 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -37,13 +37,16 @@ struct caam_jrentry_info { /* Private sub-storage for a single JobR */ struct caam_drv_private_jr { - struct device *parentdev; /* points back to controller dev */ - struct platform_device *jr_pdev;/* points to platform device for JR */ + struct list_head list_node; /* Job Ring device list */ + struct device *dev; int ridx; struct caam_job_ring __iomem *rregs; /* JobR's register space */ struct tasklet_struct irqtask; int irq; /* One per queue */ + /* Number of scatterlist crypt transforms active on the JobR */ + atomic_t tfm_count ____cacheline_aligned; + /* Job ring info */ int ringsize; /* Size of rings (assume input = output) */ struct caam_jrentry_info *entinfo; /* Alloc'ed 1 per ring entry */ @@ -63,7 +66,7 @@ struct caam_drv_private_jr { struct caam_drv_private { struct device *dev; - struct device **jrdev; /* Alloc'ed array per sub-device */ + struct platform_device **jrpdev; /* Alloc'ed array per sub-device */ struct platform_device *pdev; /* Physical-presence section */ @@ -80,12 +83,11 @@ struct caam_drv_private { u8 qi_present; /* Nonzero if QI present in device */ int secvio_irq; /* Security violation interrupt number */ - /* which jr allocated to scatterlist crypto */ - atomic_t tfm_count ____cacheline_aligned; - /* list of registered crypto algorithms (mk generic context handle?) */ - struct list_head alg_list; - /* list of registered hash algorithms (mk generic context handle?) */ - struct list_head hash_list; +#define RNG4_MAX_HANDLES 2 + /* RNG4 block */ + u32 rng4_sh_init; /* This bitmap shows which of the State + Handles of the RNG4 block are initialized + by this driver */ /* * debugfs entries for developer view into driver/device diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index bdb786d..d23356d2 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -13,6 +13,113 @@ #include "desc.h" #include "intern.h" +struct jr_driver_data { + /* List of Physical JobR's with the Driver */ + struct list_head jr_list; + spinlock_t jr_alloc_lock; /* jr_list lock */ +} ____cacheline_aligned; + +static struct jr_driver_data driver_data; + +static int caam_reset_hw_jr(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + unsigned int timeout = 100000; + + /* + * mask interrupts since we are going to poll + * for reset completion status + */ + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + /* initiate flush (required prior to reset) */ + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout) + cpu_relax(); + + if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != + JRINT_ERR_HALT_COMPLETE || timeout == 0) { + dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); + return -EIO; + } + + /* initiate reset */ + timeout = 100000; + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) + cpu_relax(); + + if (timeout == 0) { + dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); + return -EIO; + } + + /* unmask interrupts */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + return 0; +} + +/* + * Shutdown JobR independent of platform property code + */ +int caam_jr_shutdown(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + dma_addr_t inpbusaddr, outbusaddr; + int ret; + + ret = caam_reset_hw_jr(dev); + + tasklet_kill(&jrp->irqtask); + + /* Release interrupt */ + free_irq(jrp->irq, dev); + + /* Free rings */ + inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); + outbusaddr = rd_reg64(&jrp->rregs->outring_base); + dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, + jrp->inpring, inpbusaddr); + dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, + jrp->outring, outbusaddr); + kfree(jrp->entinfo); + + return ret; +} + +static int caam_jr_remove(struct platform_device *pdev) +{ + int ret; + struct device *jrdev; + struct caam_drv_private_jr *jrpriv; + + jrdev = &pdev->dev; + jrpriv = dev_get_drvdata(jrdev); + + /* + * Return EBUSY if job ring already allocated. + */ + if (atomic_read(&jrpriv->tfm_count)) { + dev_err(jrdev, "Device is busy\n"); + return -EBUSY; + } + + /* Remove the node from Physical JobR list maintained by driver */ + spin_lock(&driver_data.jr_alloc_lock); + list_del(&jrpriv->list_node); + spin_unlock(&driver_data.jr_alloc_lock); + + /* Release ring */ + ret = caam_jr_shutdown(jrdev); + if (ret) + dev_err(jrdev, "Failed to shut down job ring\n"); + irq_dispose_mapping(jrpriv->irq); + + return ret; +} + /* Main per-ring interrupt handler */ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) { @@ -128,6 +235,59 @@ static void caam_jr_dequeue(unsigned long devarg) } /** + * caam_jr_alloc() - Alloc a job ring for someone to use as needed. + * + * returns : pointer to the newly allocated physical + * JobR dev can be written to if successful. + **/ +struct device *caam_jr_alloc(void) +{ + struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL; + struct device *dev = NULL; + int min_tfm_cnt = INT_MAX; + int tfm_cnt; + + spin_lock(&driver_data.jr_alloc_lock); + + if (list_empty(&driver_data.jr_list)) { + spin_unlock(&driver_data.jr_alloc_lock); + return ERR_PTR(-ENODEV); + } + + list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) { + tfm_cnt = atomic_read(&jrpriv->tfm_count); + if (tfm_cnt < min_tfm_cnt) { + min_tfm_cnt = tfm_cnt; + min_jrpriv = jrpriv; + } + if (!min_tfm_cnt) + break; + } + + if (min_jrpriv) { + atomic_inc(&min_jrpriv->tfm_count); + dev = min_jrpriv->dev; + } + spin_unlock(&driver_data.jr_alloc_lock); + + return dev; +} +EXPORT_SYMBOL(caam_jr_alloc); + +/** + * caam_jr_free() - Free the Job Ring + * @rdev - points to the dev that identifies the Job ring to + * be released. + **/ +void caam_jr_free(struct device *rdev) +{ + struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev); + + atomic_dec(&jrpriv->tfm_count); +} +EXPORT_SYMBOL(caam_jr_free); + +/** * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, * -EBUSY if the queue is full, -EIO if it cannot map the caller's * descriptor. @@ -207,46 +367,6 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, } EXPORT_SYMBOL(caam_jr_enqueue); -static int caam_reset_hw_jr(struct device *dev) -{ - struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); - unsigned int timeout = 100000; - - /* - * mask interrupts since we are going to poll - * for reset completion status - */ - setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); - - /* initiate flush (required prior to reset) */ - wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == - JRINT_ERR_HALT_INPROGRESS) && --timeout) - cpu_relax(); - - if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != - JRINT_ERR_HALT_COMPLETE || timeout == 0) { - dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); - return -EIO; - } - - /* initiate reset */ - timeout = 100000; - wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); - while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) - cpu_relax(); - - if (timeout == 0) { - dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); - return -EIO; - } - - /* unmask interrupts */ - clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); - - return 0; -} - /* * Init JobR independent of platform property detection */ @@ -262,7 +382,7 @@ static int caam_jr_init(struct device *dev) /* Connect job ring interrupt handler. */ error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, - "caam-jobr", dev); + dev_name(dev), dev); if (error) { dev_err(dev, "can't connect JobR %d interrupt (%d)\n", jrp->ridx, jrp->irq); @@ -318,86 +438,43 @@ static int caam_jr_init(struct device *dev) return 0; } -/* - * Shutdown JobR independent of platform property code - */ -int caam_jr_shutdown(struct device *dev) -{ - struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); - dma_addr_t inpbusaddr, outbusaddr; - int ret; - - ret = caam_reset_hw_jr(dev); - - tasklet_kill(&jrp->irqtask); - - /* Release interrupt */ - free_irq(jrp->irq, dev); - - /* Free rings */ - inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); - outbusaddr = rd_reg64(&jrp->rregs->outring_base); - dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, - jrp->inpring, inpbusaddr); - dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, - jrp->outring, outbusaddr); - kfree(jrp->entinfo); - of_device_unregister(jrp->jr_pdev); - - return ret; -} /* - * Probe routine for each detected JobR subsystem. It assumes that - * property detection was picked up externally. + * Probe routine for each detected JobR subsystem. */ -int caam_jr_probe(struct platform_device *pdev, struct device_node *np, - int ring) +static int caam_jr_probe(struct platform_device *pdev) { - struct device *ctrldev, *jrdev; - struct platform_device *jr_pdev; - struct caam_drv_private *ctrlpriv; + struct device *jrdev; + struct device_node *nprop; + struct caam_job_ring __iomem *ctrl; struct caam_drv_private_jr *jrpriv; - u32 *jroffset; + static int total_jobrs; int error; - ctrldev = &pdev->dev; - ctrlpriv = dev_get_drvdata(ctrldev); - + jrdev = &pdev->dev; jrpriv = kmalloc(sizeof(struct caam_drv_private_jr), GFP_KERNEL); - if (jrpriv == NULL) { - dev_err(ctrldev, "can't alloc private mem for job ring %d\n", - ring); + if (!jrpriv) return -ENOMEM; - } - jrpriv->parentdev = ctrldev; /* point back to parent */ - jrpriv->ridx = ring; /* save ring identity relative to detection */ - /* - * Derive a pointer to the detected JobRs regs - * Driver has already iomapped the entire space, we just - * need to add in the offset to this JobR. Don't know if I - * like this long-term, but it'll run - */ - jroffset = (u32 *)of_get_property(np, "reg", NULL); - jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl - + *jroffset); + dev_set_drvdata(jrdev, jrpriv); - /* Build a local dev for each detected queue */ - jr_pdev = of_platform_device_create(np, NULL, ctrldev); - if (jr_pdev == NULL) { - kfree(jrpriv); - return -EINVAL; + /* save ring identity relative to detection */ + jrpriv->ridx = total_jobrs++; + + nprop = pdev->dev.of_node; + /* Get configuration properties from device tree */ + /* First, get register page */ + ctrl = of_iomap(nprop, 0); + if (!ctrl) { + dev_err(jrdev, "of_iomap() failed\n"); + return -ENOMEM; } - jrpriv->jr_pdev = jr_pdev; - jrdev = &jr_pdev->dev; - dev_set_drvdata(jrdev, jrpriv); - ctrlpriv->jrdev[ring] = jrdev; + jrpriv->rregs = (struct caam_job_ring __force *)ctrl; if (sizeof(dma_addr_t) == sizeof(u64)) - if (of_device_is_compatible(np, "fsl,sec-v5.0-job-ring")) + if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring")) dma_set_mask(jrdev, DMA_BIT_MASK(40)); else dma_set_mask(jrdev, DMA_BIT_MASK(36)); @@ -405,15 +482,61 @@ int caam_jr_probe(struct platform_device *pdev, struct device_node *np, dma_set_mask(jrdev, DMA_BIT_MASK(32)); /* Identify the interrupt */ - jrpriv->irq = irq_of_parse_and_map(np, 0); + jrpriv->irq = irq_of_parse_and_map(nprop, 0); /* Now do the platform independent part */ error = caam_jr_init(jrdev); /* now turn on hardware */ if (error) { - of_device_unregister(jr_pdev); kfree(jrpriv); return error; } - return error; + jrpriv->dev = jrdev; + spin_lock(&driver_data.jr_alloc_lock); + list_add_tail(&jrpriv->list_node, &driver_data.jr_list); + spin_unlock(&driver_data.jr_alloc_lock); + + atomic_set(&jrpriv->tfm_count, 0); + + return 0; +} + +static struct of_device_id caam_jr_match[] = { + { + .compatible = "fsl,sec-v4.0-job-ring", + }, + { + .compatible = "fsl,sec4.0-job-ring", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, caam_jr_match); + +static struct platform_driver caam_jr_driver = { + .driver = { + .name = "caam_jr", + .owner = THIS_MODULE, + .of_match_table = caam_jr_match, + }, + .probe = caam_jr_probe, + .remove = caam_jr_remove, +}; + +static int __init jr_driver_init(void) +{ + spin_lock_init(&driver_data.jr_alloc_lock); + INIT_LIST_HEAD(&driver_data.jr_list); + return platform_driver_register(&caam_jr_driver); +} + +static void __exit jr_driver_exit(void) +{ + platform_driver_unregister(&caam_jr_driver); } + +module_init(jr_driver_init); +module_exit(jr_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM JR request backend"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/jr.h b/drivers/crypto/caam/jr.h index 9d8741a..97113a6 100644 --- a/drivers/crypto/caam/jr.h +++ b/drivers/crypto/caam/jr.h @@ -8,12 +8,11 @@ #define JR_H /* Prototypes for backend-level services exposed to APIs */ +struct device *caam_jr_alloc(void); +void caam_jr_free(struct device *rdev); int caam_jr_enqueue(struct device *dev, u32 *desc, void (*cbk)(struct device *dev, u32 *desc, u32 status, void *areq), void *areq); -extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np, - int ring); -extern int caam_jr_shutdown(struct device *dev); #endif /* JR_H */ diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 4455396..d50174f 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -245,7 +245,7 @@ struct rngtst { /* RNG4 TRNG test registers */ struct rng4tst { -#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ +#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ u32 rtmctl; /* misc. control register */ u32 rtscmisc; /* statistical check misc. register */ u32 rtpkrrng; /* poker range register */ @@ -255,6 +255,8 @@ struct rng4tst { }; #define RTSDCTL_ENT_DLY_SHIFT 16 #define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT) +#define RTSDCTL_ENT_DLY_MIN 1200 +#define RTSDCTL_ENT_DLY_MAX 12800 u32 rtsdctl; /* seed control register */ union { u32 rtsblim; /* PRGM=1: sparse bit limit register */ @@ -266,7 +268,11 @@ struct rng4tst { u32 rtfrqcnt; /* PRGM=0: freq. count register */ }; u32 rsvd1[40]; +#define RDSTA_SKVT 0x80000000 +#define RDSTA_SKVN 0x40000000 #define RDSTA_IF0 0x00000001 +#define RDSTA_IF1 0x00000002 +#define RDSTA_IFMASK (RDSTA_IF1 | RDSTA_IF0) u32 rdsta; u32 rsvd2[15]; }; @@ -692,6 +698,7 @@ struct caam_deco { u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */ u32 jr_ctl_lo; u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */ +#define DECO_OP_STATUS_HI_ERR_MASK 0xF00000FF u32 op_status_hi; /* DxOPSTA - DECO Operation Status */ u32 op_status_lo; u32 rsvd24[2]; @@ -706,12 +713,13 @@ struct caam_deco { u32 rsvd29[48]; u32 descbuf[64]; /* DxDESB - Descriptor buffer */ u32 rscvd30[193]; +#define DESC_DBG_DECO_STAT_HOST_ERR 0x00D00000 +#define DESC_DBG_DECO_STAT_VALID 0x80000000 +#define DESC_DBG_DECO_STAT_MASK 0x00F00000 u32 desc_dbg; /* DxDDR - DECO Debug Register */ u32 rsvd31[126]; }; -/* DECO DBG Register Valid Bit*/ -#define DECO_DBG_VALID 0x80000000 #define DECO_JQCR_WHL 0x20000000 #define DECO_JQCR_FOUR 0x10000000 diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index e0037c8..b12ff85 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -117,6 +117,21 @@ static int dma_unmap_sg_chained(struct device *dev, struct scatterlist *sg, return nents; } +/* Map SG page in kernel virtual address space and copy */ +static inline void sg_map_copy(u8 *dest, struct scatterlist *sg, + int len, int offset) +{ + u8 *mapped_addr; + + /* + * Page here can be user-space pinned using get_user_pages + * Same must be kmapped before use and kunmapped subsequently + */ + mapped_addr = kmap_atomic(sg_page(sg)); + memcpy(dest, mapped_addr + offset, len); + kunmap_atomic(mapped_addr); +} + /* Copy from len bytes of sg to dest, starting from beginning */ static inline void sg_copy(u8 *dest, struct scatterlist *sg, unsigned int len) { @@ -124,15 +139,15 @@ static inline void sg_copy(u8 *dest, struct scatterlist *sg, unsigned int len) int cpy_index = 0, next_cpy_index = current_sg->length; while (next_cpy_index < len) { - memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg), - current_sg->length); + sg_map_copy(dest + cpy_index, current_sg, current_sg->length, + current_sg->offset); current_sg = scatterwalk_sg_next(current_sg); cpy_index = next_cpy_index; next_cpy_index += current_sg->length; } if (cpy_index < len) - memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg), - len - cpy_index); + sg_map_copy(dest + cpy_index, current_sg, len-cpy_index, + current_sg->offset); } /* Copy sg data, from to_skip to end, to dest */ @@ -140,7 +155,7 @@ static inline void sg_copy_part(u8 *dest, struct scatterlist *sg, int to_skip, unsigned int end) { struct scatterlist *current_sg = sg; - int sg_index, cpy_index; + int sg_index, cpy_index, offset; sg_index = current_sg->length; while (sg_index <= to_skip) { @@ -148,9 +163,10 @@ static inline void sg_copy_part(u8 *dest, struct scatterlist *sg, sg_index += current_sg->length; } cpy_index = sg_index - to_skip; - memcpy(dest, (u8 *) sg_virt(current_sg) + - current_sg->length - cpy_index, cpy_index); - current_sg = scatterwalk_sg_next(current_sg); - if (end - sg_index) + offset = current_sg->offset + current_sg->length - cpy_index; + sg_map_copy(dest, current_sg, cpy_index, offset); + if (end - sg_index) { + current_sg = scatterwalk_sg_next(current_sg); sg_copy(dest + cpy_index, current_sg, end - sg_index); + } } diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c index a8a7dd4..247ab80 100644 --- a/drivers/crypto/dcp.c +++ b/drivers/crypto/dcp.c @@ -733,12 +733,9 @@ static int dcp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n"); - return -ENXIO; - } - dev->dcp_regs_base = devm_ioremap(&pdev->dev, r->start, - resource_size(r)); + dev->dcp_regs_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(dev->dcp_regs_base)) + return PTR_ERR(dev->dcp_regs_base); dcp_set(dev, DCP_CTRL_SFRST, DCP_REG_CTRL); udelay(10); @@ -762,7 +759,8 @@ static int dcp_probe(struct platform_device *pdev) return -EIO; } dev->dcp_vmi_irq = r->start; - ret = request_irq(dev->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", dev); + ret = devm_request_irq(&pdev->dev, dev->dcp_vmi_irq, dcp_vmi_irq, 0, + "dcp", dev); if (ret != 0) { dev_err(&pdev->dev, "can't request_irq (0)\n"); return -EIO; @@ -771,15 +769,14 @@ static int dcp_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!r) { dev_err(&pdev->dev, "can't get IRQ resource (1)\n"); - ret = -EIO; - goto err_free_irq0; + return -EIO; } dev->dcp_irq = r->start; - ret = request_irq(dev->dcp_irq, dcp_irq, 0, "dcp", dev); + ret = devm_request_irq(&pdev->dev, dev->dcp_irq, dcp_irq, 0, "dcp", + dev); if (ret != 0) { dev_err(&pdev->dev, "can't request_irq (1)\n"); - ret = -EIO; - goto err_free_irq0; + return -EIO; } dev->hw_pkg[0] = dma_alloc_coherent(&pdev->dev, @@ -788,8 +785,7 @@ static int dcp_probe(struct platform_device *pdev) GFP_KERNEL); if (!dev->hw_pkg[0]) { dev_err(&pdev->dev, "Could not allocate hw descriptors\n"); - ret = -ENOMEM; - goto err_free_irq1; + return -ENOMEM; } for (i = 1; i < DCP_MAX_PKG; i++) { @@ -848,16 +844,14 @@ err_unregister: for (j = 0; j < i; j++) crypto_unregister_alg(&algs[j]); err_free_key_iv: + tasklet_kill(&dev->done_task); + tasklet_kill(&dev->queue_task); dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base, dev->payload_base_dma); err_free_hw_packet: dma_free_coherent(&pdev->dev, DCP_MAX_PKG * sizeof(struct dcp_hw_packet), dev->hw_pkg[0], dev->hw_phys_pkg); -err_free_irq1: - free_irq(dev->dcp_irq, dev); -err_free_irq0: - free_irq(dev->dcp_vmi_irq, dev); return ret; } @@ -868,23 +862,20 @@ static int dcp_remove(struct platform_device *pdev) int j; dev = platform_get_drvdata(pdev); - dma_free_coherent(&pdev->dev, - DCP_MAX_PKG * sizeof(struct dcp_hw_packet), - dev->hw_pkg[0], dev->hw_phys_pkg); - - dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base, - dev->payload_base_dma); + misc_deregister(&dev->dcp_bootstream_misc); - free_irq(dev->dcp_irq, dev); - free_irq(dev->dcp_vmi_irq, dev); + for (j = 0; j < ARRAY_SIZE(algs); j++) + crypto_unregister_alg(&algs[j]); tasklet_kill(&dev->done_task); tasklet_kill(&dev->queue_task); - for (j = 0; j < ARRAY_SIZE(algs); j++) - crypto_unregister_alg(&algs[j]); + dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base, + dev->payload_base_dma); - misc_deregister(&dev->dcp_bootstream_misc); + dma_free_coherent(&pdev->dev, + DCP_MAX_PKG * sizeof(struct dcp_hw_packet), + dev->hw_pkg[0], dev->hw_phys_pkg); return 0; } diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 214357e..9dd6e01 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -1149,32 +1149,24 @@ static int aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { struct ixp_ctx *ctx = crypto_aead_ctx(tfm); - struct rtattr *rta = (struct rtattr *)key; - struct crypto_authenc_key_param *param; + struct crypto_authenc_keys keys; - if (!RTA_OK(rta, keylen)) - goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; - param = RTA_DATA(rta); - ctx->enckey_len = be32_to_cpu(param->enckeylen); - - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); + if (keys.authkeylen > sizeof(ctx->authkey)) + goto badkey; - if (keylen < ctx->enckey_len) + if (keys.enckeylen > sizeof(ctx->enckey)) goto badkey; - ctx->authkey_len = keylen - ctx->enckey_len; - memcpy(ctx->enckey, key + ctx->authkey_len, ctx->enckey_len); - memcpy(ctx->authkey, key, ctx->authkey_len); + memcpy(ctx->authkey, keys.authkey, keys.authkeylen); + memcpy(ctx->enckey, keys.enckey, keys.enckeylen); + ctx->authkey_len = keys.authkeylen; + ctx->enckey_len = keys.enckeylen; return aead_setup(tfm, crypto_aead_authsize(tfm)); badkey: - ctx->enckey_len = 0; crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 3374a3e..8d1e6f8 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -907,7 +907,7 @@ static int mv_cra_hash_hmac_sha1_init(struct crypto_tfm *tfm) return mv_cra_hash_init(tfm, "sha1", COP_HMAC_SHA1, SHA1_BLOCK_SIZE); } -irqreturn_t crypto_int(int irq, void *priv) +static irqreturn_t crypto_int(int irq, void *priv) { u32 val; @@ -928,7 +928,7 @@ irqreturn_t crypto_int(int irq, void *priv) return IRQ_HANDLED; } -struct crypto_alg mv_aes_alg_ecb = { +static struct crypto_alg mv_aes_alg_ecb = { .cra_name = "ecb(aes)", .cra_driver_name = "mv-ecb-aes", .cra_priority = 300, @@ -951,7 +951,7 @@ struct crypto_alg mv_aes_alg_ecb = { }, }; -struct crypto_alg mv_aes_alg_cbc = { +static struct crypto_alg mv_aes_alg_cbc = { .cra_name = "cbc(aes)", .cra_driver_name = "mv-cbc-aes", .cra_priority = 300, @@ -975,7 +975,7 @@ struct crypto_alg mv_aes_alg_cbc = { }, }; -struct ahash_alg mv_sha1_alg = { +static struct ahash_alg mv_sha1_alg = { .init = mv_hash_init, .update = mv_hash_update, .final = mv_hash_final, @@ -999,7 +999,7 @@ struct ahash_alg mv_sha1_alg = { } }; -struct ahash_alg mv_hmac_sha1_alg = { +static struct ahash_alg mv_hmac_sha1_alg = { .init = mv_hash_init, .update = mv_hash_update, .final = mv_hash_final, @@ -1084,7 +1084,7 @@ static int mv_probe(struct platform_device *pdev) goto err_unmap_sram; } - ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), + ret = request_irq(irq, crypto_int, 0, dev_name(&pdev->dev), cp); if (ret) goto err_thread; @@ -1187,7 +1187,7 @@ static struct platform_driver marvell_crypto = { .driver = { .owner = THIS_MODULE, .name = "mv_crypto", - .of_match_table = of_match_ptr(mv_cesa_of_match_table), + .of_match_table = mv_cesa_of_match_table, }, }; MODULE_ALIAS("platform:mv_crypto"); diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index ce791c2..a9ccbf1 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -275,7 +275,7 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd) if (dd->flags & FLAGS_CBC) val |= AES_REG_CTRL_CBC; if (dd->flags & FLAGS_CTR) { - val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_32; + val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_128; mask = AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_MASK; } if (dd->flags & FLAGS_ENCRYPT) @@ -554,7 +554,7 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) return err; } -int omap_aes_check_aligned(struct scatterlist *sg) +static int omap_aes_check_aligned(struct scatterlist *sg) { while (sg) { if (!IS_ALIGNED(sg->offset, 4)) @@ -566,7 +566,7 @@ int omap_aes_check_aligned(struct scatterlist *sg) return 0; } -int omap_aes_copy_sgs(struct omap_aes_dev *dd) +static int omap_aes_copy_sgs(struct omap_aes_dev *dd) { void *buf_in, *buf_out; int pages; diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index e28104b..e45aaaf 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -2033,3 +2033,4 @@ module_platform_driver(omap_sham_driver); MODULE_DESCRIPTION("OMAP SHA1/MD5 hw acceleration support."); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Dmitry Kasatkin"); +MODULE_ALIAS("platform:omap-sham"); diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 888f7f4..a6175ba 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -495,45 +495,29 @@ static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key, { struct spacc_aead_ctx *ctx = crypto_aead_ctx(tfm); struct spacc_alg *alg = to_spacc_alg(tfm->base.__crt_alg); - struct rtattr *rta = (void *)key; - struct crypto_authenc_key_param *param; - unsigned int authkeylen, enckeylen; + struct crypto_authenc_keys keys; int err = -EINVAL; - if (!RTA_OK(rta, keylen)) + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) + if (keys.enckeylen > AES_MAX_KEY_SIZE) goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) - goto badkey; - - param = RTA_DATA(rta); - enckeylen = be32_to_cpu(param->enckeylen); - - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - - if (keylen < enckeylen) - goto badkey; - - authkeylen = keylen - enckeylen; - - if (enckeylen > AES_MAX_KEY_SIZE) + if (keys.authkeylen > sizeof(ctx->hash_ctx)) goto badkey; if ((alg->ctrl_default & SPACC_CRYPTO_ALG_MASK) == SPA_CTRL_CIPH_ALG_AES) - err = spacc_aead_aes_setkey(tfm, key + authkeylen, enckeylen); + err = spacc_aead_aes_setkey(tfm, keys.enckey, keys.enckeylen); else - err = spacc_aead_des_setkey(tfm, key + authkeylen, enckeylen); + err = spacc_aead_des_setkey(tfm, keys.enckey, keys.enckeylen); if (err) goto badkey; - memcpy(ctx->hash_ctx, key, authkeylen); - ctx->hash_key_len = authkeylen; + memcpy(ctx->hash_ctx, keys.authkey, keys.authkeylen); + ctx->hash_key_len = keys.authkeylen; return 0; diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index d7bb8ba..785a9de 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1058,7 +1058,7 @@ static struct platform_driver sahara_driver = { .driver = { .name = SAHARA_NAME, .owner = THIS_MODULE, - .of_match_table = of_match_ptr(sahara_dt_ids), + .of_match_table = sahara_dt_ids, }, .id_table = sahara_platform_ids, }; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 6cd0e60..905de44 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -673,39 +673,20 @@ static int aead_setkey(struct crypto_aead *authenc, const u8 *key, unsigned int keylen) { struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - struct rtattr *rta = (void *)key; - struct crypto_authenc_key_param *param; - unsigned int authkeylen; - unsigned int enckeylen; - - if (!RTA_OK(rta, keylen)) - goto badkey; + struct crypto_authenc_keys keys; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) + if (keys.authkeylen + keys.enckeylen > TALITOS_MAX_KEY_SIZE) goto badkey; - param = RTA_DATA(rta); - enckeylen = be32_to_cpu(param->enckeylen); - - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - - if (keylen < enckeylen) - goto badkey; + memcpy(ctx->key, keys.authkey, keys.authkeylen); + memcpy(&ctx->key[keys.authkeylen], keys.enckey, keys.enckeylen); - authkeylen = keylen - enckeylen; - - if (keylen > TALITOS_MAX_KEY_SIZE) - goto badkey; - - memcpy(&ctx->key, key, keylen); - - ctx->keylen = keylen; - ctx->enckeylen = enckeylen; - ctx->authkeylen = authkeylen; + ctx->keylen = keys.authkeylen + keys.enckeylen; + ctx->enckeylen = keys.enckeylen; + ctx->authkeylen = keys.authkeylen; return 0; diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c index fa05e3c..060eecc 100644 --- a/drivers/crypto/tegra-aes.c +++ b/drivers/crypto/tegra-aes.c @@ -27,6 +27,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> @@ -199,8 +201,6 @@ static void aes_workqueue_handler(struct work_struct *work); static DECLARE_WORK(aes_work, aes_workqueue_handler); static struct workqueue_struct *aes_wq; -extern unsigned long long tegra_chip_uid(void); - static inline u32 aes_readl(struct tegra_aes_dev *dd, u32 offset) { return readl(dd->io_base + offset); @@ -713,13 +713,12 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed, struct tegra_aes_dev *dd = aes_dev; struct tegra_aes_ctx *ctx = &rng_ctx; struct tegra_aes_slot *key_slot; - struct timespec ts; int ret = 0; - u64 nsec, tmp[2]; + u8 tmp[16]; /* 16 bytes = 128 bits of entropy */ u8 *dt; if (!ctx || !dd) { - dev_err(dd->dev, "ctx=0x%x, dd=0x%x\n", + pr_err("ctx=0x%x, dd=0x%x\n", (unsigned int)ctx, (unsigned int)dd); return -EINVAL; } @@ -778,14 +777,8 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed, if (dd->ivlen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) { dt = dd->iv + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128; } else { - getnstimeofday(&ts); - nsec = timespec_to_ns(&ts); - do_div(nsec, 1000); - nsec ^= dd->ctr << 56; - dd->ctr++; - tmp[0] = nsec; - tmp[1] = tegra_chip_uid(); - dt = (u8 *)tmp; + get_random_bytes(tmp, sizeof(tmp)); + dt = tmp; } memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ); @@ -804,7 +797,7 @@ static int tegra_aes_cra_init(struct crypto_tfm *tfm) return 0; } -void tegra_aes_cra_exit(struct crypto_tfm *tfm) +static void tegra_aes_cra_exit(struct crypto_tfm *tfm) { struct tegra_aes_ctx *ctx = crypto_ablkcipher_ctx((struct crypto_ablkcipher *)tfm); @@ -924,7 +917,7 @@ static int tegra_aes_probe(struct platform_device *pdev) } /* Initialize the vde clock */ - dd->aes_clk = clk_get(dev, "vde"); + dd->aes_clk = devm_clk_get(dev, "vde"); if (IS_ERR(dd->aes_clk)) { dev_err(dev, "iclock intialization failed.\n"); err = -ENODEV; @@ -1033,8 +1026,6 @@ out: if (dd->buf_out) dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, dd->buf_out, dd->dma_buf_out); - if (!IS_ERR(dd->aes_clk)) - clk_put(dd->aes_clk); if (aes_wq) destroy_workqueue(aes_wq); spin_lock(&list_lock); @@ -1068,7 +1059,6 @@ static int tegra_aes_remove(struct platform_device *pdev) dd->buf_in, dd->dma_buf_in); dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, dd->buf_out, dd->dma_buf_out); - clk_put(dd->aes_clk); aes_dev = NULL; return 0; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 446687c..af36763 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -289,9 +289,11 @@ config MMP_TDMA bool "MMP Two-Channel DMA support" depends on ARCH_MMP select DMA_ENGINE + select MMP_SRAM help Support the MMP Two-Channel DMA engine. This engine used for MMP Audio DMA and pxa910 SQU. + It needs sram driver under mach-mmp. Say Y here if you enabled MMP ADMA, otherwise say N. diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 72c927d..54c18c2 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -158,7 +158,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ - return !!(val & bit); + return !!(val & BIT(bit)); } static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index f7a0cc4..7b37300 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -102,7 +102,7 @@ struct msm_gpio_dev { DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); struct irq_domain *domain; - unsigned int summary_irq; + int summary_irq; void __iomem *msm_tlmm_base; }; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 3c3321f..db31290 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -79,7 +79,7 @@ struct mvebu_gpio_chip { spinlock_t lock; void __iomem *membase; void __iomem *percpu_membase; - unsigned int irqbase; + int irqbase; struct irq_domain *domain; int soc_variant; }; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index f22f7f3..b4d4211 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -286,11 +286,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (!chip->base) return -ENOMEM; - chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, - irq_base, &pl061_domain_ops, chip); - if (!chip->domain) - return -ENODEV; - spin_lock_init(&chip->lock); chip->gc.request = pl061_gpio_request; @@ -320,6 +315,11 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); + chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, + irq_base, &pl061_domain_ops, chip); + if (!chip->domain) + return -ENODEV; + for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { if (pdata->directions & (1 << i)) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index d3f15ae..fe088a3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -381,7 +381,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) if (!p->irq_domain) { ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); - goto err1; + goto err0; } if (devm_request_irq(&pdev->dev, irq->start, diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 0502b9a..da071dd 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -132,6 +132,7 @@ static int tb10x_gpio_direction_out(struct gpio_chip *chip, int mask = BIT(offset); int val = TB10X_GPIO_DIR_OUT << offset; + tb10x_gpio_set(chip, offset, value); tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val); return 0; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 0c7e891..b97d6a6 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -354,17 +354,18 @@ static void twl_set(struct gpio_chip *chip, unsigned offset, int value) static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + int ret = -EINVAL; mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) - twl4030_set_gpio_dataout(offset, value); + ret = twl4030_set_gpio_direction(offset, 0); priv->direction |= BIT(offset); mutex_unlock(&priv->mutex); twl_set(chip, offset, value); - return 0; + return ret; } static int twl_to_irq(struct gpio_chip *chip, unsigned offset) @@ -435,7 +436,8 @@ static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) static int gpio_twl4030_remove(struct platform_device *pdev); -static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) +static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev, + struct twl4030_gpio_platform_data *pdata) { struct twl4030_gpio_platform_data *omap_twl_info; @@ -443,6 +445,9 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) if (!omap_twl_info) return NULL; + if (pdata) + *omap_twl_info = *pdata; + omap_twl_info->use_leds = of_property_read_bool(dev->of_node, "ti,use-leds"); @@ -500,7 +505,7 @@ no_irqs: mutex_init(&priv->mutex); if (node) - pdata = of_gpio_twl4030(&pdev->dev); + pdata = of_gpio_twl4030(&pdev->dev, pdata); if (pdata == NULL) { dev_err(&pdev->dev, "Platform data is missing\n"); diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 1a605f2a..06fb5cf 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -105,3 +105,4 @@ module_platform_driver(ucb1400_gpio_driver); MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ucb1400_gpio"); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4e10b10..ac53a95 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -14,6 +14,7 @@ #include <linux/idr.h> #include <linux/slab.h> #include <linux/acpi.h> +#include <linux/gpio/driver.h> #define CREATE_TRACE_POINTS #include <trace/events/gpio.h> @@ -1308,6 +1309,18 @@ struct gpio_chip *gpiochip_find(void *data, } EXPORT_SYMBOL_GPL(gpiochip_find); +static int gpiochip_match_name(struct gpio_chip *chip, void *data) +{ + const char *name = data; + + return !strcmp(chip->label, name); +} + +static struct gpio_chip *find_chip_by_name(const char *name) +{ + return gpiochip_find((void *)name, gpiochip_match_name); +} + #ifdef CONFIG_PINCTRL /** @@ -1341,8 +1354,10 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, ret = pinctrl_get_group_pins(pctldev, pin_group, &pin_range->range.pins, &pin_range->range.npins); - if (ret < 0) + if (ret < 0) { + kfree(pin_range); return ret; + } pinctrl_add_gpio_range(pctldev, &pin_range->range); @@ -2260,26 +2275,10 @@ void gpiod_add_table(struct gpiod_lookup *table, size_t size) mutex_unlock(&gpio_lookup_lock); } -/* - * Caller must have a acquired gpio_lookup_lock - */ -static struct gpio_chip *find_chip_by_name(const char *name) -{ - struct gpio_chip *chip = NULL; - - list_for_each_entry(chip, &gpio_lookup_list, list) { - if (chip->label == NULL) - continue; - if (!strcmp(chip->label, name)) - break; - } - - return chip; -} - #ifdef CONFIG_OF static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, unsigned long *flags) + unsigned int idx, + enum gpio_lookup_flags *flags) { char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; @@ -2297,20 +2296,22 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, return desc; if (of_flags & OF_GPIO_ACTIVE_LOW) - *flags |= GPIOF_ACTIVE_LOW; + *flags |= GPIO_ACTIVE_LOW; return desc; } #else static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, unsigned long *flags) + unsigned int idx, + enum gpio_lookup_flags *flags) { return ERR_PTR(-ENODEV); } #endif static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, unsigned long *flags) + unsigned int idx, + enum gpio_lookup_flags *flags) { struct acpi_gpio_info info; struct gpio_desc *desc; @@ -2320,13 +2321,14 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; if (info.gpioint && info.active_low) - *flags |= GPIOF_ACTIVE_LOW; + *flags |= GPIO_ACTIVE_LOW; return desc; } static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, unsigned long *flags) + unsigned int idx, + enum gpio_lookup_flags *flags) { const char *dev_id = dev ? dev_name(dev) : NULL; struct gpio_desc *desc = ERR_PTR(-ENODEV); @@ -2418,7 +2420,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, { struct gpio_desc *desc; int status; - unsigned long flags = 0; + enum gpio_lookup_flags flags = 0; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -2444,8 +2446,12 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, if (status < 0) return ERR_PTR(status); - if (flags & GPIOF_ACTIVE_LOW) + if (flags & GPIO_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (flags & GPIO_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + if (flags & GPIO_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); return desc; } diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index bd2bca3..c22c309 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -516,7 +516,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor_str = "card%d"; minor->kdev = kzalloc(sizeof(*minor->kdev), GFP_KERNEL); - if (!minor->dev) { + if (!minor->kdev) { r = -ENOMEM; goto error; } diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 38a4db5..4aff04f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -630,7 +630,6 @@ error: hwmon->hwmon = NULL; return ret; #else - hwmon->hwmon = NULL; return 0; #endif } diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 0109a96..821ab7b 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -92,6 +92,7 @@ qxl_release_free(struct qxl_device *qdev, - DRM_FILE_OFFSET); qxl_fence_remove_release(&bo->fence, release->id); qxl_bo_unref(&bo); + kfree(entry); } spin_lock(&qdev->release_idr_lock); idr_remove(&qdev->release_idr, release->id); diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 329fbb9..34e2d39 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -460,6 +460,7 @@ config HID_MULTITOUCH - Stantum multitouch panels - Touch International Panels - Unitec Panels + - Wistron optical touch panels - XAT optical touch panels - Xiroku optical touch panels - Zytronic touch panels diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c index a42e6a3..0e6a42d 100644 --- a/drivers/hid/hid-appleir.c +++ b/drivers/hid/hid-appleir.c @@ -297,6 +297,9 @@ static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id) appleir->hid = hid; + /* force input as some remotes bypass the input registration */ + hid->quirks |= HID_QUIRK_HIDINPUT_FORCE; + spin_lock_init(&appleir->lock); setup_timer(&appleir->key_up_timer, key_up_tick, (unsigned long) appleir); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8c10f27..253fe23 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1723,6 +1723,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, @@ -1879,7 +1880,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7655962..f9304cb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -489,6 +489,7 @@ #define USB_VENDOR_ID_KYE 0x0458 #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138 +#define USB_DEVICE_ID_GENIUS_MANTICORE 0x0153 #define USB_DEVICE_ID_GENIUS_GX_IMPERATOR 0x4018 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 #define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 @@ -640,7 +641,6 @@ #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 #define USB_VENDOR_ID_NINTENDO 0x057e -#define USB_VENDOR_ID_NINTENDO2 0x054c #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 #define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330 @@ -902,6 +902,9 @@ #define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802 #define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804 +#define USB_VENDOR_ID_WISTRON 0x0fb8 +#define USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH 0x1109 + #define USB_VENDOR_ID_X_TENSIONS 0x1ae7 #define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001 diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 7384512..ecb5ca6 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -341,6 +341,9 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, case USB_DEVICE_ID_GENIUS_GX_IMPERATOR: rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83, "Genius Gx Imperator Keyboard"); + case USB_DEVICE_ID_GENIUS_MANTICORE: + rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, + "Genius Manticore Keyboard"); break; } return rdesc; @@ -418,6 +421,14 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) goto enabling_err; } break; + case USB_DEVICE_ID_GENIUS_MANTICORE: + /* + * The manticore keyboard needs to have all the interfaces + * opened at least once to be fully functional. + */ + if (hid_hw_open(hdev)) + hid_hw_close(hdev); + break; } return 0; @@ -439,6 +450,8 @@ static const struct hid_device_id kye_devices[] = { USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, + USB_DEVICE_ID_GENIUS_MANTICORE) }, { } }; MODULE_DEVICE_TABLE(hid, kye_devices); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index a2cedb8..d83b1e8b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1335,6 +1335,12 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, + + /* Wistron panels */ + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_WISTRON, + USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH) }, + /* XAT */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XAT, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index da551d1..098af2f8 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -225,6 +225,13 @@ static const unsigned int buzz_keymap[] = { struct sony_sc { unsigned long quirks; +#ifdef CONFIG_SONY_FF + struct work_struct rumble_worker; + struct hid_device *hdev; + __u8 left; + __u8 right; +#endif + void *extra; }; @@ -615,9 +622,9 @@ static void buzz_remove(struct hid_device *hdev) } #ifdef CONFIG_SONY_FF -static int sony_play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) +static void sony_rumble_worker(struct work_struct *work) { + struct sony_sc *sc = container_of(work, struct sony_sc, rumble_worker); unsigned char buf[] = { 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, @@ -628,21 +635,28 @@ static int sony_play_effect(struct input_dev *dev, void *data, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00 }; - __u8 left; - __u8 right; + + buf[3] = sc->right; + buf[5] = sc->left; + + sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf), + HID_OUTPUT_REPORT); +} + +static int sony_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ struct hid_device *hid = input_get_drvdata(dev); + struct sony_sc *sc = hid_get_drvdata(hid); if (effect->type != FF_RUMBLE) return 0; - left = effect->u.rumble.strong_magnitude / 256; - right = effect->u.rumble.weak_magnitude ? 1 : 0; - - buf[3] = right; - buf[5] = left; + sc->left = effect->u.rumble.strong_magnitude / 256; + sc->right = effect->u.rumble.weak_magnitude ? 1 : 0; - return hid->hid_output_raw_report(hid, buf, sizeof(buf), - HID_OUTPUT_REPORT); + schedule_work(&sc->rumble_worker); + return 0; } static int sony_init_ff(struct hid_device *hdev) @@ -650,16 +664,31 @@ static int sony_init_ff(struct hid_device *hdev) struct hid_input *hidinput = list_entry(hdev->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; + struct sony_sc *sc = hid_get_drvdata(hdev); + + sc->hdev = hdev; + INIT_WORK(&sc->rumble_worker, sony_rumble_worker); input_set_capability(input_dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(input_dev, NULL, sony_play_effect); } +static void sony_destroy_ff(struct hid_device *hdev) +{ + struct sony_sc *sc = hid_get_drvdata(hdev); + + cancel_work_sync(&sc->rumble_worker); +} + #else static int sony_init_ff(struct hid_device *hdev) { return 0; } + +static void sony_destroy_ff(struct hid_device *hdev) +{ +} #endif static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -728,6 +757,8 @@ static void sony_remove(struct hid_device *hdev) if (sc->quirks & BUZZ_CONTROLLER) buzz_remove(hdev); + sony_destroy_ff(hdev); + hid_hw_stop(hdev); } diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 1446f52..abb20db 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -834,8 +834,7 @@ static void wiimote_init_set_type(struct wiimote_data *wdata, goto done; } - if (vendor == USB_VENDOR_ID_NINTENDO || - vendor == USB_VENDOR_ID_NINTENDO2) { + if (vendor == USB_VENDOR_ID_NINTENDO) { if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE) { devtype = WIIMOTE_DEV_GEN10; goto done; @@ -1856,8 +1855,6 @@ static void wiimote_hid_remove(struct hid_device *hdev) static const struct hid_device_id wiimote_hid_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2, - USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { } diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 93b00d7..cedc6da 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -287,7 +287,7 @@ static int uhid_event_from_user(const char __user *buffer, size_t len, */ struct uhid_create_req_compat *compat; - compat = kmalloc(sizeof(*compat), GFP_KERNEL); + compat = kzalloc(sizeof(*compat), GFP_KERNEL); if (!compat) return -ENOMEM; diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 1d7ff46..dafc63c 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -18,7 +18,6 @@ #include <linux/err.h> #include <acpi/acpi.h> -#include <acpi/acpixf.h> #include <acpi/acpi_drivers.h> #include <acpi/acpi_bus.h> diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index 036cf03..18a74a6 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -20,7 +20,6 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/clk.h> #include <linux/slab.h> /* Hardware register offsets and field defintions */ @@ -891,7 +890,7 @@ static const struct of_device_id bcm_kona_i2c_of_match[] = { {.compatible = "brcm,kona-i2c",}, {}, }; -MODULE_DEVICE_TABLE(of, kona_i2c_of_match); +MODULE_DEVICE_TABLE(of, bcm_kona_i2c_of_match); static struct platform_driver bcm_kona_i2c_driver = { .driver = { diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d7e8600..77df97b 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -299,6 +299,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name)); adap->algo = &bcm2835_i2c_algo; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index ff05d9f..af0b583 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -125,12 +125,12 @@ static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = { static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev, int reg, u16 val) { - __raw_writew(val, i2c_dev->base + reg); + writew_relaxed(val, i2c_dev->base + reg); } static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) { - return __raw_readw(i2c_dev->base + reg); + return readw_relaxed(i2c_dev->base + reg); } /* Generate a pulse on the i2c clock pin. */ diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index dae3ddfe..721f7eb 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -25,8 +25,6 @@ #define USB_VENDOR_ID_DIOLAN 0x0abf #define USB_DEVICE_ID_DIOLAN_U2C 0x3370 -#define DIOLAN_OUT_EP 0x02 -#define DIOLAN_IN_EP 0x84 /* commands via USB, must match command ids in the firmware */ #define CMD_I2C_READ 0x01 @@ -84,6 +82,7 @@ struct i2c_diolan_u2c { u8 obuffer[DIOLAN_OUTBUF_LEN]; /* output buffer */ u8 ibuffer[DIOLAN_INBUF_LEN]; /* input buffer */ + int ep_in, ep_out; /* Endpoints */ struct usb_device *usb_dev; /* the usb device for this device */ struct usb_interface *interface;/* the interface for this device */ struct i2c_adapter adapter; /* i2c related things */ @@ -109,7 +108,7 @@ static int diolan_usb_transfer(struct i2c_diolan_u2c *dev) return -EINVAL; ret = usb_bulk_msg(dev->usb_dev, - usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP), + usb_sndbulkpipe(dev->usb_dev, dev->ep_out), dev->obuffer, dev->olen, &actual, DIOLAN_USB_TIMEOUT); if (!ret) { @@ -118,7 +117,7 @@ static int diolan_usb_transfer(struct i2c_diolan_u2c *dev) tmpret = usb_bulk_msg(dev->usb_dev, usb_rcvbulkpipe(dev->usb_dev, - DIOLAN_IN_EP), + dev->ep_in), dev->ibuffer, sizeof(dev->ibuffer), &actual, DIOLAN_USB_TIMEOUT); @@ -210,7 +209,7 @@ static void diolan_flush_input(struct i2c_diolan_u2c *dev) int ret; ret = usb_bulk_msg(dev->usb_dev, - usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP), + usb_rcvbulkpipe(dev->usb_dev, dev->ep_in), dev->ibuffer, sizeof(dev->ibuffer), &actual, DIOLAN_USB_TIMEOUT); if (ret < 0 || actual == 0) @@ -445,9 +444,14 @@ static void diolan_u2c_free(struct i2c_diolan_u2c *dev) static int diolan_u2c_probe(struct usb_interface *interface, const struct usb_device_id *id) { + struct usb_host_interface *hostif = interface->cur_altsetting; struct i2c_diolan_u2c *dev; int ret; + if (hostif->desc.bInterfaceNumber != 0 + || hostif->desc.bNumEndpoints < 2) + return -ENODEV; + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { @@ -455,6 +459,8 @@ static int diolan_u2c_probe(struct usb_interface *interface, ret = -ENOMEM; goto error; } + dev->ep_out = hostif->endpoint[0].desc.bEndpointAddress; + dev->ep_in = hostif->endpoint[1].desc.bEndpointAddress; dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a6a891d..90dcc2e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -266,13 +266,13 @@ static const u8 reg_map_ip_v2[] = { static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, int reg, u16 val) { - __raw_writew(val, i2c_dev->base + + writew_relaxed(val, i2c_dev->base + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) { - return __raw_readw(i2c_dev->base + + return readw_relaxed(i2c_dev->base + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } @@ -1037,6 +1037,20 @@ static const struct i2c_algorithm omap_i2c_algo = { }; #ifdef CONFIG_OF +static struct omap_i2c_bus_platform_data omap2420_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_NO_FIFO | + OMAP_I2C_FLAG_SIMPLE_CLOCK | + OMAP_I2C_FLAG_16BIT_DATA_REG | + OMAP_I2C_FLAG_BUS_SHIFT_2, +}; + +static struct omap_i2c_bus_platform_data omap2430_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 | + OMAP_I2C_FLAG_FORCE_19200_INT_CLK, +}; + static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, @@ -1055,6 +1069,14 @@ static const struct of_device_id omap_i2c_of_match[] = { .compatible = "ti,omap3-i2c", .data = &omap3_pdata, }, + { + .compatible = "ti,omap2430-i2c", + .data = &omap2430_pdata, + }, + { + .compatible = "ti,omap2420-i2c", + .data = &omap2420_pdata, + }, { }, }; MODULE_DEVICE_TABLE(of, omap_i2c_of_match); @@ -1140,9 +1162,9 @@ omap_i2c_probe(struct platform_device *pdev) * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset. * Also since the omap_i2c_read_reg uses reg_map_ip_* a - * raw_readw is done. + * readw_relaxed is done. */ - rev = __raw_readw(dev->base + 0x04); + rev = readw_relaxed(dev->base + 0x04); dev->scheme = OMAP_I2C_SCHEME(rev); switch (dev->scheme) { diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index dcda173..1cae4e9 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -350,7 +350,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&accel_state->common_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); error_free_dev_mem: @@ -363,10 +363,11 @@ static int hid_accel_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct accel_3d_state *accel_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&accel_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); kfree(indio_dev->channels); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index d72118d..98ba761 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -112,9 +112,10 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address) mutex_lock(&st->buf_lock); st->tx[0] = KXSD9_READ(address); ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); - if (ret) - return ret; - return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); + if (!ret) + ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); + mutex_unlock(&st->buf_lock); + return ret; } static IIO_CONST_ATTR(accel_scale_available, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 17df749..5b1aa02 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1047,6 +1047,7 @@ static int at91_adc_probe(struct platform_device *pdev) } else { if (!st->caps->has_tsmr) { dev_err(&pdev->dev, "We don't support non-TSMR adc\n"); + ret = -ENODEV; goto error_disable_adc_clk; } diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 1294832..c8c1baa 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -88,10 +88,10 @@ static const int mcp3422_sample_rates[4] = { /* sample rates to sign extension table */ static const int mcp3422_sign_extend[4] = { - [MCP3422_SRATE_240] = 12, - [MCP3422_SRATE_60] = 14, - [MCP3422_SRATE_15] = 16, - [MCP3422_SRATE_3] = 18 }; + [MCP3422_SRATE_240] = 11, + [MCP3422_SRATE_60] = 13, + [MCP3422_SRATE_15] = 15, + [MCP3422_SRATE_3] = 17 }; /* Client data (each client gets its own) */ struct mcp3422 { diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 728411e..d4d7482 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -229,12 +229,15 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev, unsigned long flags, const struct iio_buffer_setup_ops *setup_ops) { + struct iio_buffer *buffer; int ret; - indio_dev->buffer = iio_kfifo_allocate(indio_dev); - if (!indio_dev->buffer) + buffer = iio_kfifo_allocate(indio_dev); + if (!buffer) return -ENOMEM; + iio_device_attach_buffer(indio_dev, buffer); + ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh, flags, indio_dev->name, indio_dev); if (ret) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index b6e77e0..bbd6426 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -55,11 +55,10 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, return 0; } -void hid_sensor_remove_trigger(struct iio_dev *indio_dev) +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb) { - iio_trigger_unregister(indio_dev->trig); - iio_trigger_free(indio_dev->trig); - indio_dev->trig = NULL; + iio_trigger_unregister(attrb->trigger); + iio_trigger_free(attrb->trigger); } EXPORT_SYMBOL(hid_sensor_remove_trigger); @@ -90,7 +89,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, dev_err(&indio_dev->dev, "Trigger Register Failed\n"); goto error_free_trig; } - indio_dev->trig = trig; + indio_dev->trig = attrb->trigger = trig; return ret; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index 9a87314..ca02f78 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -21,6 +21,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, struct hid_sensor_common *attrb); -void hid_sensor_remove_trigger(struct iio_dev *indio_dev); +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb); #endif diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index ea01c6bc..e54f0f4 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -348,7 +348,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&gyro_state->common_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); error_free_dev_mem: @@ -361,10 +361,11 @@ static int hid_gyro_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct gyro_3d_state *gyro_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&gyro_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); kfree(indio_dev->channels); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index f98c2b5..b0d65df 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -81,6 +81,8 @@ config SENSORS_LM3533 config TCS3472 tristate "TAOS TCS3472 color light-to-digital converter" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for the TAOS TCS3472 family of color light-to-digital converters with IR filter. diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index fa6ae8c..8e8b9d7 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -314,7 +314,7 @@ static int hid_als_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&als_state->common_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); error_free_dev_mem: @@ -327,10 +327,11 @@ static int hid_als_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct als_state *als_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&als_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); kfree(indio_dev->channels); diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 0cf0963..d86d226 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -19,6 +19,8 @@ config AK8975 config MAG3110 tristate "Freescale MAG3110 3-Axis Magnetometer" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for the Freescale MAG3110 3-Axis magnetometer. diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 2634920..b26e102 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -351,7 +351,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&magn_state->common_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); error_free_dev_mem: @@ -364,10 +364,11 @@ static int hid_magn_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct magn_3d_state *magn_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&magn_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); kfree(indio_dev->channels); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 783c5b4..becf544 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -250,7 +250,12 @@ done: .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = idx, \ - .scan_type = IIO_ST('s', 16, 16, IIO_BE), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ } static const struct iio_chan_spec mag3110_channels[] = { diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 86b8228..45e0e3e 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -180,7 +180,10 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) if (WARN_ON(down_interruptible(&i8042tregs))) return -1; - if (hp_sdc_enqueue_transaction(&t)) return -1; + if (hp_sdc_enqueue_transaction(&t)) { + up(&i8042tregs); + return -1; + } /* Sleep until results come back. */ if (WARN_ON(down_interruptible(&i8042tregs))) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 00d1e54..961d58d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -906,6 +906,17 @@ config TOUCHSCREEN_STMPE To compile this driver as a module, choose M here: the module will be called stmpe-ts. +config TOUCHSCREEN_SUR40 + tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" + depends on USB + select INPUT_POLLDEV + help + Say Y here if you want support for the Samsung SUR40 touchscreen + (also known as Microsoft Surface 2.0 or Microsoft PixelSense). + + To compile this driver as a module, choose M here: the + module will be called sur40. + config TOUCHSCREEN_TPS6507X tristate "TPS6507x based touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7587883..62801f2 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o +obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 268a35e..279c0e4 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -391,7 +391,7 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int atmel_wm97xx_suspend(struct *dev) +static int atmel_wm97xx_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 42d830e..a035a39 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1246,8 +1246,7 @@ static void cyttsp4_watchdog_timer(unsigned long handle) dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); - if (!work_pending(&cd->watchdog_work)) - schedule_work(&cd->watchdog_work); + schedule_work(&cd->watchdog_work); return; } diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c new file mode 100644 index 0000000..cfd1b7e --- /dev/null +++ b/drivers/input/touchscreen/sur40.c @@ -0,0 +1,466 @@ +/* + * Surface2.0/SUR40/PixelSense input driver + * + * Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org> + * + * Derived from the USB Skeleton driver 1.1, + * Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com) + * + * and from the Apple USB BCM5974 multitouch driver, + * Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se) + * + * and from the generic hid-multitouch driver, + * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/completion.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/printk.h> +#include <linux/input-polldev.h> +#include <linux/input/mt.h> +#include <linux/usb/input.h> + +/* read 512 bytes from endpoint 0x86 -> get header + blobs */ +struct sur40_header { + + __le16 type; /* always 0x0001 */ + __le16 count; /* count of blobs (if 0: continue prev. packet) */ + + __le32 packet_id; /* unique ID for all packets in one frame */ + + __le32 timestamp; /* milliseconds (inc. by 16 or 17 each frame) */ + __le32 unknown; /* "epoch?" always 02/03 00 00 00 */ + +} __packed; + +struct sur40_blob { + + __le16 blob_id; + + u8 action; /* 0x02 = enter/exit, 0x03 = update (?) */ + u8 unknown; /* always 0x01 or 0x02 (no idea what this is?) */ + + __le16 bb_pos_x; /* upper left corner of bounding box */ + __le16 bb_pos_y; + + __le16 bb_size_x; /* size of bounding box */ + __le16 bb_size_y; + + __le16 pos_x; /* finger tip position */ + __le16 pos_y; + + __le16 ctr_x; /* centroid position */ + __le16 ctr_y; + + __le16 axis_x; /* somehow related to major/minor axis, mostly: */ + __le16 axis_y; /* axis_x == bb_size_y && axis_y == bb_size_x */ + + __le32 angle; /* orientation in radians relative to x axis - + actually an IEEE754 float, don't use in kernel */ + + __le32 area; /* size in pixels/pressure (?) */ + + u8 padding[32]; + +} __packed; + +/* combined header/blob data */ +struct sur40_data { + struct sur40_header header; + struct sur40_blob blobs[]; +} __packed; + + +/* version information */ +#define DRIVER_SHORT "sur40" +#define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>" +#define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver" + +/* vendor and device IDs */ +#define ID_MICROSOFT 0x045e +#define ID_SUR40 0x0775 + +/* sensor resolution */ +#define SENSOR_RES_X 1920 +#define SENSOR_RES_Y 1080 + +/* touch data endpoint */ +#define TOUCH_ENDPOINT 0x86 + +/* polling interval (ms) */ +#define POLL_INTERVAL 10 + +/* maximum number of contacts FIXME: this is a guess? */ +#define MAX_CONTACTS 64 + +/* control commands */ +#define SUR40_GET_VERSION 0xb0 /* 12 bytes string */ +#define SUR40_UNKNOWN1 0xb3 /* 5 bytes */ +#define SUR40_UNKNOWN2 0xc1 /* 24 bytes */ + +#define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */ +#define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */ + +/* + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT + * here by mistake which is very likely to have corrupted the firmware EEPROM + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. + * Should you ever run into a similar problem, the background story to this + * incident and instructions on how to fix the corrupted EEPROM are available + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html +*/ + +struct sur40_state { + + struct usb_device *usbdev; + struct device *dev; + struct input_polled_dev *input; + + struct sur40_data *bulk_in_buffer; + size_t bulk_in_size; + u8 bulk_in_epaddr; + + char phys[64]; +}; + +static int sur40_command(struct sur40_state *dev, + u8 command, u16 index, void *buffer, u16 size) +{ + return usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), + command, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, index, buffer, size, 1000); +} + +/* Initialization routine, called from sur40_open */ +static int sur40_init(struct sur40_state *dev) +{ + int result; + u8 buffer[24]; + + /* stupidly replay the original MS driver init sequence */ + result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12); + if (result < 0) + return result; + + result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12); + if (result < 0) + return result; + + result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12); + if (result < 0) + return result; + + result = sur40_command(dev, SUR40_UNKNOWN2, 0x00, buffer, 24); + if (result < 0) + return result; + + result = sur40_command(dev, SUR40_UNKNOWN1, 0x00, buffer, 5); + if (result < 0) + return result; + + result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12); + + /* + * Discard the result buffer - no known data inside except + * some version strings, maybe extract these sometime... + */ + + return result; +} + +/* + * Callback routines from input_polled_dev + */ + +/* Enable the device, polling will now start. */ +static void sur40_open(struct input_polled_dev *polldev) +{ + struct sur40_state *sur40 = polldev->private; + + dev_dbg(sur40->dev, "open\n"); + sur40_init(sur40); +} + +/* Disable device, polling has stopped. */ +static void sur40_close(struct input_polled_dev *polldev) +{ + struct sur40_state *sur40 = polldev->private; + + dev_dbg(sur40->dev, "close\n"); + /* + * There is no known way to stop the device, so we simply + * stop polling. + */ +} + +/* + * This function is called when a whole contact has been processed, + * so that it can assign it to a slot and store the data there. + */ +static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) +{ + int wide, major, minor; + + int bb_size_x = le16_to_cpu(blob->bb_size_x); + int bb_size_y = le16_to_cpu(blob->bb_size_y); + + int pos_x = le16_to_cpu(blob->pos_x); + int pos_y = le16_to_cpu(blob->pos_y); + + int ctr_x = le16_to_cpu(blob->ctr_x); + int ctr_y = le16_to_cpu(blob->ctr_y); + + int slotnum = input_mt_get_slot_by_key(input, blob->blob_id); + if (slotnum < 0 || slotnum >= MAX_CONTACTS) + return; + + input_mt_slot(input, slotnum); + input_mt_report_slot_state(input, MT_TOOL_FINGER, 1); + wide = (bb_size_x > bb_size_y); + major = max(bb_size_x, bb_size_y); + minor = min(bb_size_x, bb_size_y); + + input_report_abs(input, ABS_MT_POSITION_X, pos_x); + input_report_abs(input, ABS_MT_POSITION_Y, pos_y); + input_report_abs(input, ABS_MT_TOOL_X, ctr_x); + input_report_abs(input, ABS_MT_TOOL_Y, ctr_y); + + /* TODO: use a better orientation measure */ + input_report_abs(input, ABS_MT_ORIENTATION, wide); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); + input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); +} + +/* core function: poll for new input data */ +static void sur40_poll(struct input_polled_dev *polldev) +{ + + struct sur40_state *sur40 = polldev->private; + struct input_dev *input = polldev->input; + int result, bulk_read, need_blobs, packet_blobs, i; + u32 packet_id; + + struct sur40_header *header = &sur40->bulk_in_buffer->header; + struct sur40_blob *inblob = &sur40->bulk_in_buffer->blobs[0]; + + dev_dbg(sur40->dev, "poll\n"); + + need_blobs = -1; + + do { + + /* perform a blocking bulk read to get data from the device */ + result = usb_bulk_msg(sur40->usbdev, + usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr), + sur40->bulk_in_buffer, sur40->bulk_in_size, + &bulk_read, 1000); + + dev_dbg(sur40->dev, "received %d bytes\n", bulk_read); + + if (result < 0) { + dev_err(sur40->dev, "error in usb_bulk_read\n"); + return; + } + + result = bulk_read - sizeof(struct sur40_header); + + if (result % sizeof(struct sur40_blob) != 0) { + dev_err(sur40->dev, "transfer size mismatch\n"); + return; + } + + /* first packet? */ + if (need_blobs == -1) { + need_blobs = le16_to_cpu(header->count); + dev_dbg(sur40->dev, "need %d blobs\n", need_blobs); + packet_id = header->packet_id; + } + + /* + * Sanity check. when video data is also being retrieved, the + * packet ID will usually increase in the middle of a series + * instead of at the end. + */ + if (packet_id != header->packet_id) + dev_warn(sur40->dev, "packet ID mismatch\n"); + + packet_blobs = result / sizeof(struct sur40_blob); + dev_dbg(sur40->dev, "received %d blobs\n", packet_blobs); + + /* packets always contain at least 4 blobs, even if empty */ + if (packet_blobs > need_blobs) + packet_blobs = need_blobs; + + for (i = 0; i < packet_blobs; i++) { + need_blobs--; + dev_dbg(sur40->dev, "processing blob\n"); + sur40_report_blob(&(inblob[i]), input); + } + + } while (need_blobs > 0); + + input_mt_sync_frame(input); + input_sync(input); +} + +/* Initialize input device parameters. */ +static void sur40_input_setup(struct input_dev *input_dev) +{ + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, SENSOR_RES_X, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, SENSOR_RES_Y, 0, 0); + + input_set_abs_params(input_dev, ABS_MT_TOOL_X, + 0, SENSOR_RES_X, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOOL_Y, + 0, SENSOR_RES_Y, 0, 0); + + /* max value unknown, but major/minor axis + * can never be larger than screen */ + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, SENSOR_RES_X, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, + 0, SENSOR_RES_Y, 0, 0); + + input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); + + input_mt_init_slots(input_dev, MAX_CONTACTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); +} + +/* Check candidate USB interface. */ +static int sur40_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *usbdev = interface_to_usbdev(interface); + struct sur40_state *sur40; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct input_polled_dev *poll_dev; + int error; + + /* Check if we really have the right interface. */ + iface_desc = &interface->altsetting[0]; + if (iface_desc->desc.bInterfaceClass != 0xFF) + return -ENODEV; + + /* Use endpoint #4 (0x86). */ + endpoint = &iface_desc->endpoint[4].desc; + if (endpoint->bEndpointAddress != TOUCH_ENDPOINT) + return -ENODEV; + + /* Allocate memory for our device state and initialize it. */ + sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL); + if (!sur40) + return -ENOMEM; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + error = -ENOMEM; + goto err_free_dev; + } + + /* Set up polled input device control structure */ + poll_dev->private = sur40; + poll_dev->poll_interval = POLL_INTERVAL; + poll_dev->open = sur40_open; + poll_dev->poll = sur40_poll; + poll_dev->close = sur40_close; + + /* Set up regular input device structure */ + sur40_input_setup(poll_dev->input); + + poll_dev->input->name = "Samsung SUR40"; + usb_to_input_id(usbdev, &poll_dev->input->id); + usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); + strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); + poll_dev->input->phys = sur40->phys; + poll_dev->input->dev.parent = &interface->dev; + + sur40->usbdev = usbdev; + sur40->dev = &interface->dev; + sur40->input = poll_dev; + + /* use the bulk-in endpoint tested above */ + sur40->bulk_in_size = usb_endpoint_maxp(endpoint); + sur40->bulk_in_epaddr = endpoint->bEndpointAddress; + sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL); + if (!sur40->bulk_in_buffer) { + dev_err(&interface->dev, "Unable to allocate input buffer."); + error = -ENOMEM; + goto err_free_polldev; + } + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(&interface->dev, + "Unable to register polled input device."); + goto err_free_buffer; + } + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, sur40); + dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); + + return 0; + +err_free_buffer: + kfree(sur40->bulk_in_buffer); +err_free_polldev: + input_free_polled_device(sur40->input); +err_free_dev: + kfree(sur40); + + return error; +} + +/* Unregister device & clean up. */ +static void sur40_disconnect(struct usb_interface *interface) +{ + struct sur40_state *sur40 = usb_get_intfdata(interface); + + input_unregister_polled_device(sur40->input); + input_free_polled_device(sur40->input); + kfree(sur40->bulk_in_buffer); + kfree(sur40); + + usb_set_intfdata(interface, NULL); + dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); +} + +static const struct usb_device_id sur40_table[] = { + { USB_DEVICE(ID_MICROSOFT, ID_SUR40) }, /* Samsung SUR40 */ + { } /* terminating null entry */ +}; +MODULE_DEVICE_TABLE(usb, sur40_table); + +/* USB-specific object needed to register this driver with the USB subsystem. */ +static struct usb_driver sur40_driver = { + .name = DRIVER_SHORT, + .probe = sur40_probe, + .disconnect = sur40_disconnect, + .id_table = sur40_table, +}; + +module_usb_driver(sur40_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 6753b65..d2f0120 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \ windfarm_ad7417_sensor.o \ windfarm_lm75_sensor.o \ windfarm_lm87_sensor.o \ + windfarm_max6690_sensor.o \ windfarm_pid.o \ windfarm_cpufreq_clamp.o \ windfarm_rm31.o diff --git a/drivers/md/md.c b/drivers/md/md.c index b6b7a28..e60cebf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7777,7 +7777,7 @@ void md_check_recovery(struct mddev *mddev) if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) return; if ( ! ( - (mddev->flags & ~ (1<<MD_CHANGE_PENDING)) || + (mddev->flags & MD_UPDATE_SB_FLAGS & ~ (1<<MD_CHANGE_PENDING)) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || (mddev->external == 0 && mddev->safemode == 1) || diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 47da0af..cc055da 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -678,26 +678,23 @@ get_active_stripe(struct r5conf *conf, sector_t sector, } else init_stripe(sh, sector, previous); } else { + spin_lock(&conf->device_lock); if (atomic_read(&sh->count)) { BUG_ON(!list_empty(&sh->lru) && !test_bit(STRIPE_EXPANDING, &sh->state) && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state) - && !test_bit(STRIPE_ON_RELEASE_LIST, &sh->state)); + ); } else { - spin_lock(&conf->device_lock); if (!test_bit(STRIPE_HANDLE, &sh->state)) atomic_inc(&conf->active_stripes); - if (list_empty(&sh->lru) && - !test_bit(STRIPE_ON_RELEASE_LIST, &sh->state) && - !test_bit(STRIPE_EXPANDING, &sh->state)) - BUG(); + BUG_ON(list_empty(&sh->lru)); list_del_init(&sh->lru); if (sh->group) { sh->group->stripes_cnt--; sh->group = NULL; } - spin_unlock(&conf->device_lock); } + spin_unlock(&conf->device_lock); } } while (sh == NULL); @@ -5471,7 +5468,7 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt, for (i = 0; i < *group_cnt; i++) { struct r5worker_group *group; - group = worker_groups[i]; + group = &(*worker_groups)[i]; INIT_LIST_HEAD(&group->handle_list); group->conf = conf; group->workers = workers + i * cnt; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 0b10a90..98b6b6e 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/timer.h> +#include <linux/of.h> #include <linux/omap-dma.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -90,17 +91,6 @@ #define OMAP_MMC_CMDTYPE_AC 2 #define OMAP_MMC_CMDTYPE_ADTC 3 -#define OMAP_DMA_MMC_TX 21 -#define OMAP_DMA_MMC_RX 22 -#define OMAP_DMA_MMC2_TX 54 -#define OMAP_DMA_MMC2_RX 55 - -#define OMAP24XX_DMA_MMC2_TX 47 -#define OMAP24XX_DMA_MMC2_RX 48 -#define OMAP24XX_DMA_MMC1_TX 61 -#define OMAP24XX_DMA_MMC1_RX 62 - - #define DRIVER_NAME "mmci-omap" /* Specifies how often in millisecs to poll for card status changes @@ -1330,7 +1320,7 @@ static int mmc_omap_probe(struct platform_device *pdev) struct mmc_omap_host *host = NULL; struct resource *res; dma_cap_mask_t mask; - unsigned sig; + unsigned sig = 0; int i, ret = 0; int irq; @@ -1340,7 +1330,7 @@ static int mmc_omap_probe(struct platform_device *pdev) } if (pdata->nr_slots == 0) { dev_err(&pdev->dev, "no slots\n"); - return -ENXIO; + return -EPROBE_DEFER; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1407,19 +1397,20 @@ static int mmc_omap_probe(struct platform_device *pdev) host->dma_tx_burst = -1; host->dma_rx_burst = -1; - if (mmc_omap2()) - sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX; - else - sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX; - host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); + if (res) + sig = res->start; + host->dma_tx = dma_request_slave_channel_compat(mask, + omap_dma_filter_fn, &sig, &pdev->dev, "tx"); if (!host->dma_tx) dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", sig); - if (mmc_omap2()) - sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX; - else - sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX; - host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); + if (res) + sig = res->start; + host->dma_rx = dma_request_slave_channel_compat(mask, + omap_dma_filter_fn, &sig, &pdev->dev, "rx"); if (!host->dma_rx) dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n", sig); @@ -1512,12 +1503,20 @@ static int mmc_omap_remove(struct platform_device *pdev) return 0; } +#if IS_BUILTIN(CONFIG_OF) +static const struct of_device_id mmc_omap_match[] = { + { .compatible = "ti,omap2420-mmc", }, + { }, +}; +#endif + static struct platform_driver mmc_omap_driver = { .probe = mmc_omap_probe, .remove = mmc_omap_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mmc_omap_match), }, }; diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 1cb6e51..170e8e60 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) ndev->event_cb = NULL; } +static void ntb_irq_work(unsigned long data) +{ + struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; + int rc; + + rc = db_cb->callback(db_cb->data, db_cb->db_num); + if (rc) + tasklet_schedule(&db_cb->irq_work); + else { + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + } +} + /** * ntb_register_db_callback() - register a callback for doorbell interrupt * @ndev: pointer to ntb_device instance @@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, void (*func)(void *data, int db_num)) + void *data, int (*func)(void *data, int db_num)) { unsigned long mask; @@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, ndev->db_cb[idx].callback = func; ndev->db_cb[idx].data = data; + ndev->db_cb[idx].ndev = ndev; + + tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, + (unsigned long) &ndev->db_cb[idx]); /* unmask interrupt */ mask = readw(ndev->reg_ofs.ldb_mask); @@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) set_bit(idx * ndev->bits_per_vector, &mask); writew(mask, ndev->reg_ofs.ldb_mask); + tasklet_disable(&ndev->db_cb[idx].irq_work); + ndev->db_cb[idx].callback = NULL; } @@ -678,6 +702,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) return -EINVAL; ndev->limits.max_mw = SNB_ERRATA_MAX_MW; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->reg_ofs.spad_write = ndev->mw[1].vbase + SNB_SPAD_OFFSET; ndev->reg_ofs.rdb = ndev->mw[1].vbase + @@ -688,8 +713,21 @@ static int ntb_xeon_setup(struct ntb_device *ndev) */ writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on the + * driver defaults, but write the Limit registers first + * just in case. + */ } else { ndev->limits.max_mw = SNB_MAX_MW; + + /* HW Errata on bit 14 of b2bdoorbell register. Writes + * will not be mirrored to the remote system. Shrink + * the number of bits by one, since bit 14 is the last + * bit. + */ + ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; ndev->reg_ofs.spad_write = ndev->reg_base + SNB_B2B_SPAD_OFFSET; ndev->reg_ofs.rdb = ndev->reg_base + @@ -699,6 +737,12 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * something silly */ writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on the + * driver defaults, but write the Limit registers first + * just in case. + */ } /* The Xeon errata workaround requires setting SBAR Base @@ -769,6 +813,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * have an equal amount. */ ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; /* Note: The SDOORBELL is the cause of the errata. You REALLY * don't want to touch it. */ @@ -793,6 +838,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * have an equal amount. */ ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; @@ -819,7 +865,6 @@ static int ntb_xeon_setup(struct ntb_device *ndev) ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->limits.msix_cnt = SNB_MSIX_CNT; ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; @@ -934,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data) { struct ntb_db_cb *db_cb = data; struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, db_cb->db_num); - if (db_cb->callback) - db_cb->callback(db_cb->data, db_cb->db_num); + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); /* No need to check for the specific HB irq, any interrupt means * we're connected. @@ -955,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data) { struct ntb_db_cb *db_cb = data; struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, db_cb->db_num); - if (db_cb->callback) - db_cb->callback(db_cb->data, db_cb->db_num); + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); /* On Sandybridge, there are 16 bits in the interrupt register * but only 4 vectors. So, 5 bits are assigned to the first 3 @@ -986,7 +1039,7 @@ static irqreturn_t xeon_event_msix_irq(int irq, void *dev) dev_err(&ndev->pdev->dev, "Error determining link status\n"); /* bit 15 is always the link bit */ - writew(1 << ndev->limits.max_db_bits, ndev->reg_ofs.ldb); + writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); return IRQ_HANDLED; } @@ -1075,6 +1128,10 @@ static int ntb_setup_msix(struct ntb_device *ndev) "Only %d MSI-X vectors. Limiting the number of queues to that number.\n", rc); msix_entries = rc; + + rc = pci_enable_msix(pdev, ndev->msix_entries, msix_entries); + if (rc) + goto err1; } for (i = 0; i < msix_entries; i++) { @@ -1176,9 +1233,10 @@ static int ntb_setup_interrupts(struct ntb_device *ndev) */ if (ndev->hw_type == BWD_HW) writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~(1 << ndev->limits.max_db_bits), - ndev->reg_ofs.ldb_mask); + else { + u16 var = 1 << SNB_LINK_DB; + writew(~var, ndev->reg_ofs.ldb_mask); + } rc = ntb_setup_msix(ndev); if (!rc) @@ -1286,6 +1344,39 @@ static void ntb_free_debugfs(struct ntb_device *ndev) } } +static void ntb_hw_link_up(struct ntb_device *ndev) +{ + if (ndev->conn_type == NTB_CONN_TRANSPARENT) + ntb_link_event(ndev, NTB_LINK_UP); + else { + u32 ntb_cntl; + + /* Let's bring the NTB link up */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); + ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; + ntb_cntl |= NTB_CNTL_P2S_BAR45_SNOOP | NTB_CNTL_S2P_BAR45_SNOOP; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + } +} + +static void ntb_hw_link_down(struct ntb_device *ndev) +{ + u32 ntb_cntl; + + if (ndev->conn_type == NTB_CONN_TRANSPARENT) { + ntb_link_event(ndev, NTB_LINK_DOWN); + return; + } + + /* Bring NTB link down */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR45_SNOOP | NTB_CNTL_S2P_BAR45_SNOOP); + ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); +} + static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ntb_device *ndev; @@ -1374,9 +1465,7 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) goto err6; - /* Let's bring the NTB link up */ - writel(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP, - ndev->reg_ofs.lnk_cntl); + ntb_hw_link_up(ndev); return 0; @@ -1406,12 +1495,8 @@ static void ntb_pci_remove(struct pci_dev *pdev) { struct ntb_device *ndev = pci_get_drvdata(pdev); int i; - u32 ntb_cntl; - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl |= NTB_CNTL_LINK_DISABLE; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + ntb_hw_link_down(ndev); ntb_transport_free(ndev->ntb_transport); diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h index 0a31ced..bbdb7ed 100644 --- a/drivers/ntb/ntb_hw.h +++ b/drivers/ntb/ntb_hw.h @@ -106,10 +106,11 @@ struct ntb_mw { }; struct ntb_db_cb { - void (*callback) (void *data, int db_num); + int (*callback)(void *data, int db_num); unsigned int db_num; void *data; struct ntb_device *ndev; + struct tasklet_struct irq_work; }; struct ntb_device { @@ -228,8 +229,8 @@ struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void ntb_unregister_transport(struct ntb_device *ndev); void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, void (*db_cb_func) (void *data, - int db_num)); + void *data, int (*db_cb_func)(void *data, + int db_num)); void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); int ntb_register_event_callback(struct ntb_device *ndev, void (*event_cb_func) (void *handle, diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h index aa4bdd3..9774506 100644 --- a/drivers/ntb/ntb_regs.h +++ b/drivers/ntb/ntb_regs.h @@ -55,6 +55,7 @@ #define SNB_MAX_COMPAT_SPADS 16 /* Reserve the uppermost bit for link interrupt */ #define SNB_MAX_DB_BITS 15 +#define SNB_LINK_DB 15 #define SNB_DB_BITS_PER_VEC 5 #define SNB_MAX_MW 2 #define SNB_ERRATA_MAX_MW 1 @@ -75,9 +76,6 @@ #define SNB_SBAR2XLAT_OFFSET 0x0030 #define SNB_SBAR4XLAT_OFFSET 0x0038 #define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR2BASE_OFFSET 0x0048 -#define SNB_SBAR4BASE_OFFSET 0x0050 #define SNB_SBAR2BASE_OFFSET 0x0048 #define SNB_SBAR4BASE_OFFSET 0x0050 #define SNB_NTBCNTL_OFFSET 0x0058 @@ -145,11 +143,13 @@ #define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) #define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF -#define NTB_CNTL_CFG_LOCK (1 << 0) -#define NTB_CNTL_LINK_DISABLE (1 << 1) -#define NTB_CNTL_BAR23_SNOOP (1 << 2) -#define NTB_CNTL_BAR45_SNOOP (1 << 6) -#define BWD_CNTL_LINK_DOWN (1 << 16) +#define NTB_CNTL_CFG_LOCK (1 << 0) +#define NTB_CNTL_LINK_DISABLE (1 << 1) +#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) +#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) +#define NTB_CNTL_S2P_BAR45_SNOOP (1 << 6) +#define NTB_CNTL_P2S_BAR45_SNOOP (1 << 8) +#define BWD_CNTL_LINK_DOWN (1 << 16) #define NTB_PPD_OFFSET 0x00D4 #define SNB_PPD_CONN_TYPE 0x0003 diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index d0222f1..3217f39 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -119,7 +119,6 @@ struct ntb_transport_qp { void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data, void *data, int len); - struct tasklet_struct rx_work; struct list_head rx_pend_q; struct list_head rx_free_q; spinlock_t ntb_rx_pend_q_lock; @@ -584,11 +583,8 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size) return 0; } -static void ntb_qp_link_cleanup(struct work_struct *work) +static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) { - struct ntb_transport_qp *qp = container_of(work, - struct ntb_transport_qp, - link_cleanup); struct ntb_transport *nt = qp->transport; struct pci_dev *pdev = ntb_query_pdev(nt->ndev); @@ -602,6 +598,16 @@ static void ntb_qp_link_cleanup(struct work_struct *work) dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); qp->qp_link = NTB_LINK_DOWN; +} + +static void ntb_qp_link_cleanup_work(struct work_struct *work) +{ + struct ntb_transport_qp *qp = container_of(work, + struct ntb_transport_qp, + link_cleanup); + struct ntb_transport *nt = qp->transport; + + ntb_qp_link_cleanup(qp); if (nt->transport_link == NTB_LINK_UP) schedule_delayed_work(&qp->link_work, @@ -613,22 +619,20 @@ static void ntb_qp_link_down(struct ntb_transport_qp *qp) schedule_work(&qp->link_cleanup); } -static void ntb_transport_link_cleanup(struct work_struct *work) +static void ntb_transport_link_cleanup(struct ntb_transport *nt) { - struct ntb_transport *nt = container_of(work, struct ntb_transport, - link_cleanup); int i; + /* Pass along the info to any clients */ + for (i = 0; i < nt->max_qps; i++) + if (!test_bit(i, &nt->qp_bitmap)) + ntb_qp_link_cleanup(&nt->qps[i]); + if (nt->transport_link == NTB_LINK_DOWN) cancel_delayed_work_sync(&nt->link_work); else nt->transport_link = NTB_LINK_DOWN; - /* Pass along the info to any clients */ - for (i = 0; i < nt->max_qps; i++) - if (!test_bit(i, &nt->qp_bitmap)) - ntb_qp_link_down(&nt->qps[i]); - /* The scratchpad registers keep the values if the remote side * goes down, blast them now to give them a sane value the next * time they are accessed @@ -637,6 +641,14 @@ static void ntb_transport_link_cleanup(struct work_struct *work) ntb_write_local_spad(nt->ndev, i, 0); } +static void ntb_transport_link_cleanup_work(struct work_struct *work) +{ + struct ntb_transport *nt = container_of(work, struct ntb_transport, + link_cleanup); + + ntb_transport_link_cleanup(nt); +} + static void ntb_transport_event_callback(void *data, enum ntb_hw_event event) { struct ntb_transport *nt = data; @@ -880,7 +892,7 @@ static int ntb_transport_init_queue(struct ntb_transport *nt, } INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work); - INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup); + INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work); spin_lock_init(&qp->ntb_rx_pend_q_lock); spin_lock_init(&qp->ntb_rx_free_q_lock); @@ -936,7 +948,7 @@ int ntb_transport_init(struct pci_dev *pdev) } INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work); - INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup); + INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work); rc = ntb_register_event_callback(nt->ndev, ntb_transport_event_callback); @@ -972,7 +984,7 @@ void ntb_transport_free(void *transport) struct ntb_device *ndev = nt->ndev; int i; - nt->transport_link = NTB_LINK_DOWN; + ntb_transport_link_cleanup(nt); /* verify that all the qp's are freed */ for (i = 0; i < nt->max_qps; i++) { @@ -1188,11 +1200,14 @@ err: goto out; } -static void ntb_transport_rx(unsigned long data) +static int ntb_transport_rxc_db(void *data, int db_num) { - struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data; + struct ntb_transport_qp *qp = data; int rc, i; + dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", + __func__, db_num); + /* Limit the number of packets processed in a single interrupt to * provide fairness to others */ @@ -1204,16 +1219,8 @@ static void ntb_transport_rx(unsigned long data) if (qp->dma_chan) dma_async_issue_pending(qp->dma_chan); -} - -static void ntb_transport_rxc_db(void *data, int db_num) -{ - struct ntb_transport_qp *qp = data; - - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", - __func__, db_num); - tasklet_schedule(&qp->rx_work); + return i; } static void ntb_tx_copy_callback(void *data) @@ -1432,11 +1439,12 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, qp->tx_handler = handlers->tx_handler; qp->event_handler = handlers->event_handler; + dmaengine_get(); qp->dma_chan = dma_find_channel(DMA_MEMCPY); - if (!qp->dma_chan) + if (!qp->dma_chan) { + dmaengine_put(); dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n"); - else - dmaengine_get(); + } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC); @@ -1458,25 +1466,23 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, &qp->tx_free_q); } - tasklet_init(&qp->rx_work, ntb_transport_rx, (unsigned long) qp); - rc = ntb_register_db_callback(qp->ndev, free_queue, qp, ntb_transport_rxc_db); if (rc) - goto err3; + goto err2; dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num); return qp; -err3: - tasklet_disable(&qp->rx_work); err2: while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); err1: while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) kfree(entry); + if (qp->dma_chan) + dmaengine_put(); set_bit(free_queue, &nt->qp_bitmap); err: return NULL; @@ -1515,7 +1521,6 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) } ntb_unregister_db_callback(qp->ndev, qp->qp_num); - tasklet_disable(&qp->rx_work); cancel_delayed_work_sync(&qp->link_work); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b3b1b9a..3a02717 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -9,10 +9,6 @@ * * Init/reset quirks for USB host controllers should be in the * USB quirks file, where their drivers can access reuse it. - * - * The bridge optimization stuff has been removed. If you really - * have a silly BIOS which is unable to set your host bridge right, - * use the PowerTweak utility (see http://powertweak.sourceforge.net). */ #include <linux/types.h> diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616ae..09fde58 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -5,3 +5,4 @@ if GOLDFISH source "drivers/platform/goldfish/Kconfig" endif +source "drivers/platform/chrome/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 8a44a4c..3656b7b 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ +obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig new file mode 100644 index 0000000..b13303e --- /dev/null +++ b/drivers/platform/chrome/Kconfig @@ -0,0 +1,28 @@ +# +# Platform support for Chrome OS hardware (Chromebooks and Chromeboxes) +# + +menuconfig CHROME_PLATFORMS + bool "Platform support for Chrome hardware" + depends on X86 + ---help--- + Say Y here to get to see options for platform support for + various Chromebooks and Chromeboxes. This option alone does + not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if CHROME_PLATFORMS + +config CHROMEOS_LAPTOP + tristate "Chrome OS Laptop" + depends on I2C + depends on DMI + ---help--- + This driver instantiates i2c and smbus devices such as + light sensors and touchpads. + + If you have a supported Chromebook, choose Y or M here. + The module will be called chromeos_laptop. + +endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile new file mode 100644 index 0000000..015e919 --- /dev/null +++ b/drivers/platform/chrome/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 3e5b4497..3e5b4497 100644 --- a/drivers/platform/x86/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b51a746..d9dcd37 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -79,17 +79,6 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. -config CHROMEOS_LAPTOP - tristate "Chrome OS Laptop" - depends on I2C - depends on DMI - ---help--- - This driver instantiates i2c and smbus devices such as - light sensors and touchpads. - - If you have a supported Chromebook, choose Y or M here. - The module will be called chromeos_laptop. - config DELL_LAPTOP tristate "Dell Laptop Extras" depends on X86 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5dbe1932..f0e6aa4 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o -obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_INTEL_RST) += intel-rst.o obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0e9c169..594323a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1494,10 +1494,9 @@ static int asus_input_init(struct asus_laptop *asus) int error; input = input_allocate_device(); - if (!input) { - pr_warn("Unable to allocate input device\n"); + if (!input) return -ENOMEM; - } + input->name = "Asus Laptop extra buttons"; input->phys = ASUS_LAPTOP_FILE "/input0"; input->id.bustype = BUS_HOST; diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index bb77e18..c608b1d 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -21,6 +21,7 @@ #include <linux/err.h> #include <linux/dmi.h> #include <linux/io.h> +#include <linux/rfkill.h> #include <linux/power_supply.h> #include <linux/acpi.h> #include <linux/mm.h> @@ -89,6 +90,13 @@ static struct platform_driver platform_driver = { static struct platform_device *platform_device; static struct backlight_device *dell_backlight_device; +static struct rfkill *wifi_rfkill; +static struct rfkill *bluetooth_rfkill; +static struct rfkill *wwan_rfkill; +static bool force_rfkill; + +module_param(force_rfkill, bool, 0444); +MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models"); static const struct dmi_system_id dell_device_table[] __initconst = { { @@ -355,6 +363,108 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, return buffer; } +/* Derived from information in DellWirelessCtl.cpp: + Class 17, select 11 is radio control. It returns an array of 32-bit values. + + Input byte 0 = 0: Wireless information + + result[0]: return code + result[1]: + Bit 0: Hardware switch supported + Bit 1: Wifi locator supported + Bit 2: Wifi is supported + Bit 3: Bluetooth is supported + Bit 4: WWAN is supported + Bit 5: Wireless keyboard supported + Bits 6-7: Reserved + Bit 8: Wifi is installed + Bit 9: Bluetooth is installed + Bit 10: WWAN is installed + Bits 11-15: Reserved + Bit 16: Hardware switch is on + Bit 17: Wifi is blocked + Bit 18: Bluetooth is blocked + Bit 19: WWAN is blocked + Bits 20-31: Reserved + result[2]: NVRAM size in bytes + result[3]: NVRAM format version number + + Input byte 0 = 2: Wireless switch configuration + result[0]: return code + result[1]: + Bit 0: Wifi controlled by switch + Bit 1: Bluetooth controlled by switch + Bit 2: WWAN controlled by switch + Bits 3-6: Reserved + Bit 7: Wireless switch config locked + Bit 8: Wifi locator enabled + Bits 9-14: Reserved + Bit 15: Wifi locator setting locked + Bits 16-31: Reserved +*/ + +static int dell_rfkill_set(void *data, bool blocked) +{ + int disable = blocked ? 1 : 0; + unsigned long radio = (unsigned long)data; + int hwswitch_bit = (unsigned long)data - 1; + + get_buffer(); + dell_send_request(buffer, 17, 11); + + /* If the hardware switch controls this radio, and the hardware + switch is disabled, always disable the radio */ + if ((hwswitch_state & BIT(hwswitch_bit)) && + !(buffer->output[1] & BIT(16))) + disable = 1; + + buffer->input[0] = (1 | (radio<<8) | (disable << 16)); + dell_send_request(buffer, 17, 11); + + release_buffer(); + return 0; +} + +/* Must be called with the buffer held */ +static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, + int status) +{ + if (status & BIT(0)) { + /* Has hw-switch, sync sw_state to BIOS */ + int block = rfkill_blocked(rfkill); + buffer->input[0] = (1 | (radio << 8) | (block << 16)); + dell_send_request(buffer, 17, 11); + } else { + /* No hw-switch, sync BIOS state to sw_state */ + rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); + } +} + +static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, + int status) +{ + if (hwswitch_state & (BIT(radio - 1))) + rfkill_set_hw_state(rfkill, !(status & BIT(16))); +} + +static void dell_rfkill_query(struct rfkill *rfkill, void *data) +{ + int status; + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + + dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status); + + release_buffer(); +} + +static const struct rfkill_ops dell_rfkill_ops = { + .set_block = dell_rfkill_set, + .query = dell_rfkill_query, +}; + static struct dentry *dell_laptop_dir; static int dell_debugfs_show(struct seq_file *s, void *data) @@ -424,6 +534,136 @@ static const struct file_operations dell_debugfs_fops = { .release = single_release, }; +static void dell_update_rfkill(struct work_struct *ignored) +{ + int status; + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + + if (wifi_rfkill) { + dell_rfkill_update_hw_state(wifi_rfkill, 1, status); + dell_rfkill_update_sw_state(wifi_rfkill, 1, status); + } + if (bluetooth_rfkill) { + dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status); + dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status); + } + if (wwan_rfkill) { + dell_rfkill_update_hw_state(wwan_rfkill, 3, status); + dell_rfkill_update_sw_state(wwan_rfkill, 3, status); + } + + release_buffer(); +} +static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); + + +static int __init dell_setup_rfkill(void) +{ + int status; + int ret; + const char *product; + + /* + * rfkill causes trouble on various non Latitudes, according to Dell + * actually testing the rfkill functionality is only done on Latitudes. + */ + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!force_rfkill && (!product || strncmp(product, "Latitude", 8))) + return 0; + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + buffer->input[0] = 0x2; + dell_send_request(buffer, 17, 11); + hwswitch_state = buffer->output[1]; + release_buffer(); + + if (!(status & BIT(0))) { + if (force_rfkill) { + /* No hwsitch, clear all hw-controlled bits */ + hwswitch_state &= ~7; + } else { + /* rfkill is only tested on laptops with a hwswitch */ + return 0; + } + } + + if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { + wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, + RFKILL_TYPE_WLAN, + &dell_rfkill_ops, (void *) 1); + if (!wifi_rfkill) { + ret = -ENOMEM; + goto err_wifi; + } + ret = rfkill_register(wifi_rfkill); + if (ret) + goto err_wifi; + } + + if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { + bluetooth_rfkill = rfkill_alloc("dell-bluetooth", + &platform_device->dev, + RFKILL_TYPE_BLUETOOTH, + &dell_rfkill_ops, (void *) 2); + if (!bluetooth_rfkill) { + ret = -ENOMEM; + goto err_bluetooth; + } + ret = rfkill_register(bluetooth_rfkill); + if (ret) + goto err_bluetooth; + } + + if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { + wwan_rfkill = rfkill_alloc("dell-wwan", + &platform_device->dev, + RFKILL_TYPE_WWAN, + &dell_rfkill_ops, (void *) 3); + if (!wwan_rfkill) { + ret = -ENOMEM; + goto err_wwan; + } + ret = rfkill_register(wwan_rfkill); + if (ret) + goto err_wwan; + } + + return 0; +err_wwan: + rfkill_destroy(wwan_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); +err_bluetooth: + rfkill_destroy(bluetooth_rfkill); + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); +err_wifi: + rfkill_destroy(wifi_rfkill); + + return ret; +} + +static void dell_cleanup_rfkill(void) +{ + if (wifi_rfkill) { + rfkill_unregister(wifi_rfkill); + rfkill_destroy(wifi_rfkill); + } + if (bluetooth_rfkill) { + rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); + } + if (wwan_rfkill) { + rfkill_unregister(wwan_rfkill); + rfkill_destroy(wwan_rfkill); + } +} + static int dell_send_intensity(struct backlight_device *bd) { int ret = 0; @@ -515,6 +755,30 @@ static void touchpad_led_exit(void) led_classdev_unregister(&touchpad_led); } +static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + + if (str & 0x20) + return false; + + if (unlikely(data == 0xe0)) { + extended = true; + return false; + } else if (unlikely(extended)) { + switch (data) { + case 0x8: + schedule_delayed_work(&dell_rfkill_work, + round_jiffies_relative(HZ / 4)); + break; + } + extended = false; + } + + return false; +} + static int __init dell_init(void) { int max_intensity = 0; @@ -557,10 +821,26 @@ static int __init dell_init(void) } buffer = page_address(bufferpage); + ret = dell_setup_rfkill(); + + if (ret) { + pr_warn("Unable to setup rfkill\n"); + goto fail_rfkill; + } + + ret = i8042_install_filter(dell_laptop_i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + goto fail_filter; + } + if (quirks && quirks->touchpad_led) touchpad_led_init(&platform_device->dev); dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); + if (dell_laptop_dir != NULL) + debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, + &dell_debugfs_fops); #ifdef CONFIG_ACPI /* In the event of an ACPI backlight being available, don't @@ -603,6 +883,11 @@ static int __init dell_init(void) return 0; fail_backlight: + i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); +fail_filter: + dell_cleanup_rfkill(); +fail_rfkill: free_page((unsigned long)bufferpage); fail_buffer: platform_device_del(platform_device); @@ -620,7 +905,10 @@ static void __exit dell_exit(void) debugfs_remove_recursive(dell_laptop_dir); if (quirks && quirks->touchpad_led) touchpad_led_exit(); + i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); backlight_device_unregister(dell_backlight_device); + dell_cleanup_rfkill(); if (platform_device) { platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fa9a217..60e0900 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -130,7 +130,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = { KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, - KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_MICMUTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -139,8 +140,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_PROG3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3 }; static struct input_dev *dell_wmi_input_dev; diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index aefcc32..dec68e7 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1203,10 +1203,8 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc) int error; input = input_allocate_device(); - if (!input) { - pr_info("Unable to allocate input device\n"); + if (!input) return -ENOMEM; - } input->name = "Asus EeePC extra buttons"; input->phys = EEEPC_LAPTOP_FILE "/input0"; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 1c86fa0..8ba8956 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -54,6 +54,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_HARDWARE_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 #define HPWMI_HOTKEY_QUERY 0xc +#define HPWMI_FEATURE_QUERY 0xd #define HPWMI_WIRELESS2_QUERY 0x1b #define HPWMI_POSTCODEERROR_QUERY 0x2a @@ -292,6 +293,17 @@ static int hp_wmi_tablet_state(void) return (state & 0x4) ? 1 : 0; } +static int hp_wmi_bios_2009_later(void) +{ + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, + sizeof(state), sizeof(state)); + if (ret) + return ret; + + return (state & 0x10) ? 1 : 0; +} + static int hp_wmi_set_block(void *data, bool blocked) { enum hp_wmi_radio r = (enum hp_wmi_radio) data; @@ -871,7 +883,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) gps_rfkill = NULL; rfkill2_count = 0; - if (hp_wmi_rfkill_setup(device)) + if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) hp_wmi_rfkill2_setup(device); err = device_create_file(&device->dev, &dev_attr_display); diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6788acc..19ec951 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -570,10 +570,8 @@ static int ideapad_input_init(struct ideapad_private *priv) int error; inputdev = input_allocate_device(); - if (!inputdev) { - pr_info("Unable to allocate input device\n"); + if (!inputdev) return -ENOMEM; - } inputdev->name = "Ideapad extra buttons"; inputdev->phys = "ideapad/input0"; diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 6b18aba..8d67752 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -66,10 +66,8 @@ static int mfld_pb_probe(struct platform_device *pdev) return -EINVAL; input = input_allocate_device(); - if (!input) { - dev_err(&pdev->dev, "Input device allocation error\n"); + if (!input) return -ENOMEM; - } input->name = pdev->name; input->phys = "power-button/input0"; diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index d654f83..60ea476 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -58,12 +58,56 @@ * message handler is called within firmware. */ -#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ -#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ -#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ -#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ +#define IPC_IOC 0x100 /* IPC command register IOC bit */ + +enum { + SCU_IPC_LINCROFT, + SCU_IPC_PENWELL, + SCU_IPC_CLOVERVIEW, + SCU_IPC_TANGIER, +}; + +/* intel scu ipc driver data*/ +struct intel_scu_ipc_pdata_t { + u32 ipc_base; + u32 i2c_base; + u32 ipc_len; + u32 i2c_len; + u8 irq_mode; +}; + +static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = { + [SCU_IPC_LINCROFT] = { + .ipc_base = 0xff11c000, + .i2c_base = 0xff12b000, + .ipc_len = 0x100, + .i2c_len = 0x10, + .irq_mode = 0, + }, + [SCU_IPC_PENWELL] = { + .ipc_base = 0xff11c000, + .i2c_base = 0xff12b000, + .ipc_len = 0x100, + .i2c_len = 0x10, + .irq_mode = 1, + }, + [SCU_IPC_CLOVERVIEW] = { + .ipc_base = 0xff11c000, + .i2c_base = 0xff12b000, + .ipc_len = 0x100, + .i2c_len = 0x10, + .irq_mode = 1, + }, + [SCU_IPC_TANGIER] = { + .ipc_base = 0xff009000, + .i2c_base = 0xff00d000, + .ipc_len = 0x100, + .i2c_len = 0x10, + .irq_mode = 0, + }, +}; static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); static void ipc_remove(struct pci_dev *pdev); @@ -72,6 +116,8 @@ struct intel_scu_ipc_dev { struct pci_dev *pdev; void __iomem *ipc_base; void __iomem *i2c_base; + struct completion cmd_complete; + u8 irq_mode; }; static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ @@ -98,6 +144,10 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ */ static inline void ipc_command(u32 cmd) /* Send ipc command */ { + if (ipcdev.irq_mode) { + reinit_completion(&ipcdev.cmd_complete); + writel(cmd | IPC_IOC, ipcdev.ipc_base); + } writel(cmd, ipcdev.ipc_base); } @@ -156,6 +206,30 @@ static inline int busy_loop(void) /* Wait till scu status is busy */ return 0; } +/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ +static inline int ipc_wait_for_interrupt(void) +{ + int status; + + if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) { + struct device *dev = &ipcdev.pdev->dev; + dev_err(dev, "IPC timed out\n"); + return -ETIMEDOUT; + } + + status = ipc_read_status(); + + if ((status >> 1) & 1) + return -EIO; + + return 0; +} + +int intel_scu_ipc_check_status(void) +{ + return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop(); +} + /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) { @@ -196,8 +270,8 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) ipc_command(4 << 16 | id << 12 | 0 << 8 | op); } - err = busy_loop(); - if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ + err = intel_scu_ipc_check_status(); + if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ /* Workaround: values are read as 0 without memcpy_fromio */ memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); for (nc = 0; nc < count; nc++) @@ -391,7 +465,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub) return -ENODEV; } ipc_command(sub << 12 | cmd); - err = busy_loop(); + err = intel_scu_ipc_check_status(); mutex_unlock(&ipclock); return err; } @@ -425,10 +499,12 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, ipc_data_writel(*in++, 4 * i); ipc_command((inlen << 16) | (sub << 12) | cmd); - err = busy_loop(); + err = intel_scu_ipc_check_status(); - for (i = 0; i < outlen; i++) - *out++ = ipc_data_readl(4 * i); + if (!err) { + for (i = 0; i < outlen; i++) + *out++ = ipc_data_readl(4 * i); + } mutex_unlock(&ipclock); return err; @@ -491,6 +567,9 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); */ static irqreturn_t ioc(int irq, void *dev_id) { + if (ipcdev.irq_mode) + complete(&ipcdev.cmd_complete); + return IRQ_HANDLED; } @@ -504,13 +583,18 @@ static irqreturn_t ioc(int irq, void *dev_id) */ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int err; + int err, pid; + struct intel_scu_ipc_pdata_t *pdata; resource_size_t pci_resource; if (ipcdev.pdev) /* We support only one SCU */ return -EBUSY; + pid = id->driver_data; + pdata = &intel_scu_ipc_pdata[pid]; + ipcdev.pdev = pci_dev_get(dev); + ipcdev.irq_mode = pdata->irq_mode; err = pci_enable_device(dev); if (err) @@ -524,14 +608,16 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) if (!pci_resource) return -ENOMEM; + init_completion(&ipcdev.cmd_complete); + if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) return -EBUSY; - ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR); + ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len); if (!ipcdev.ipc_base) return -ENOMEM; - ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR); + ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len); if (!ipcdev.i2c_base) { iounmap(ipcdev.ipc_base); return -ENOMEM; @@ -564,7 +650,10 @@ static void ipc_remove(struct pci_dev *pdev) } static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, + {PCI_VDEVICE(INTEL, 0x082a), SCU_IPC_LINCROFT}, + {PCI_VDEVICE(INTEL, 0x080e), SCU_IPC_PENWELL}, + {PCI_VDEVICE(INTEL, 0x08ea), SCU_IPC_CLOVERVIEW}, + {PCI_VDEVICE(INTEL, 0x11a0), SCU_IPC_TANGIER}, { 0,} }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 10d12b2..3008fd2 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -490,11 +490,8 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) int error; input_dev = input_allocate_device(); - if (!input_dev) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Couldn't allocate input device for hotkey")); + if (!input_dev) return -ENOMEM; - } input_dev->name = ACPI_PCC_DRIVER_NAME; input_dev->phys = ACPI_PCC_INPUT_PHYS; diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 47caab0..fb233ae 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -140,12 +140,12 @@ MODULE_PARM_DESC(kbd_backlight_timeout, "on the model (default: no change from current value)"); #ifdef CONFIG_PM_SLEEP -static void sony_nc_kbd_backlight_resume(void); static void sony_nc_thermal_resume(void); #endif static int sony_nc_kbd_backlight_setup(struct platform_device *pd, unsigned int handle); -static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); +static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd, + unsigned int handle); static int sony_nc_battery_care_setup(struct platform_device *pd, unsigned int handle); @@ -304,8 +304,8 @@ static int sony_laptop_input_keycode_map[] = { KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ - KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ - KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ + KEY_FN_1, /* 17 SONYPI_EVENT_FNKEY_1 */ + KEY_FN_2, /* 18 SONYPI_EVENT_FNKEY_2 */ KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ @@ -1444,7 +1444,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd) case 0x014b: case 0x014c: case 0x0163: - sony_nc_kbd_backlight_cleanup(pd); + sony_nc_kbd_backlight_cleanup(pd, handle); break; default: continue; @@ -1486,13 +1486,6 @@ static void sony_nc_function_resume(void) case 0x0135: sony_nc_rfkill_update(); break; - case 0x0137: - case 0x0143: - case 0x014b: - case 0x014c: - case 0x0163: - sony_nc_kbd_backlight_resume(); - break; default: continue; } @@ -1822,6 +1815,12 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd, int result; int ret = 0; + if (kbdbl_ctl) { + pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n", + handle, kbdbl_ctl->handle); + return -EBUSY; + } + /* verify the kbd backlight presence, these handles are not used for * keyboard backlight only */ @@ -1881,9 +1880,10 @@ outkzalloc: return ret; } -static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) +static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd, + unsigned int handle) { - if (kbdbl_ctl) { + if (kbdbl_ctl && handle == kbdbl_ctl->handle) { device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); kfree(kbdbl_ctl); @@ -1891,25 +1891,6 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) } } -#ifdef CONFIG_PM_SLEEP -static void sony_nc_kbd_backlight_resume(void) -{ - int ignore = 0; - - if (!kbdbl_ctl) - return; - - if (kbdbl_ctl->mode == 0) - sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base, - &ignore); - - if (kbdbl_ctl->timeout != 0) - sony_call_snc_handle(kbdbl_ctl->handle, - (kbdbl_ctl->base + 0x200) | - (kbdbl_ctl->timeout << 0x10), &ignore); -} -#endif - struct battery_care_control { struct device_attribute attrs[2]; unsigned int handle; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 05e046a..58b0274 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6438,7 +6438,12 @@ static struct ibm_struct brightness_driver_data = { #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME -static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */ +#if SNDRV_CARDS <= 32 +#define DEFAULT_ALSA_IDX ~((1 << (SNDRV_CARDS - 3)) - 1) +#else +#define DEFAULT_ALSA_IDX ~((1 << (32 - 3)) - 1) +#endif +static int alsa_index = DEFAULT_ALSA_IDX; /* last three slots */ static char *alsa_id = "ThinkPadEC"; static bool alsa_enable = SNDRV_DEFAULT_ENABLE1; @@ -9163,7 +9168,6 @@ static int __init thinkpad_acpi_module_init(void) mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { - pr_err("unable to allocate input device\n"); thinkpad_acpi_module_exit(); return -ENOMEM; } else { diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index 67897c8..e597de0 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -97,10 +97,8 @@ static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) int error; input = input_allocate_device(); - if (!input) { - pr_err("Unable to allocate input device\n"); + if (!input) return -ENOMEM; - } input->name = "Topstar Laptop extra buttons"; input->phys = "topstar/input0"; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0cfadb65..7fce391 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -975,10 +975,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) u32 hci_result; dev->hotkey_dev = input_allocate_device(); - if (!dev->hotkey_dev) { - pr_info("Unable to register input device\n"); + if (!dev->hotkey_dev) return -ENOMEM; - } dev->hotkey_dev->name = "Toshiba input device"; dev->hotkey_dev->phys = "toshiba_acpi/input0"; diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 62e8c22..c2e7b26 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -672,8 +672,10 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, struct wmi_block *wblock; wblock = dev_get_drvdata(dev); - if (!wblock) - return -ENOMEM; + if (!wblock) { + strcat(buf, "\n"); + return strlen(buf); + } wmi_gtoa(wblock->gblock.guid, guid_string); diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 724706a..fd3154d 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -174,6 +174,33 @@ static const struct regulator_desc arizona_micsupp = { .owner = THIS_MODULE, }; +static const struct regulator_linear_range arizona_micsupp_ext_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0, 0x14, 25000), + REGULATOR_LINEAR_RANGE(1500000, 0x15, 0x27, 100000), +}; + +static const struct regulator_desc arizona_micsupp_ext = { + .name = "MICVDD", + .supply_name = "CPVDD", + .type = REGULATOR_VOLTAGE, + .n_voltages = 40, + .ops = &arizona_micsupp_ops, + + .vsel_reg = ARIZONA_LDO2_CONTROL_1, + .vsel_mask = ARIZONA_LDO2_VSEL_MASK, + .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, + .enable_mask = ARIZONA_CPMIC_ENA, + .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1, + .bypass_mask = ARIZONA_CPMIC_BYPASS, + + .linear_ranges = arizona_micsupp_ext_ranges, + .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges), + + .enable_time = 3000, + + .owner = THIS_MODULE, +}; + static const struct regulator_init_data arizona_micsupp_default = { .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS | @@ -186,9 +213,22 @@ static const struct regulator_init_data arizona_micsupp_default = { .num_consumer_supplies = 1, }; +static const struct regulator_init_data arizona_micsupp_ext_default = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_BYPASS, + .min_uV = 900000, + .max_uV = 3300000, + }, + + .num_consumer_supplies = 1, +}; + static int arizona_micsupp_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *desc; struct regulator_config config = { }; struct arizona_micsupp *micsupp; int ret; @@ -207,7 +247,17 @@ static int arizona_micsupp_probe(struct platform_device *pdev) * default init_data for it. This will be overridden with * platform data if provided. */ - micsupp->init_data = arizona_micsupp_default; + switch (arizona->type) { + case WM5110: + desc = &arizona_micsupp_ext; + micsupp->init_data = arizona_micsupp_ext_default; + break; + default: + desc = &arizona_micsupp; + micsupp->init_data = arizona_micsupp_default; + break; + } + micsupp->init_data.consumer_supplies = &micsupp->supply; micsupp->supply.supply = "MICVDD"; micsupp->supply.dev_name = dev_name(arizona->dev); @@ -226,7 +276,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev) ARIZONA_CPMIC_BYPASS, 0); micsupp->regulator = devm_regulator_register(&pdev->dev, - &arizona_micsupp, + desc, &config); if (IS_ERR(micsupp->regulator)) { ret = PTR_ERR(micsupp->regulator); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6382f0a..3fe1313 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2184,6 +2184,9 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) struct regulator_ops *ops = rdev->desc->ops; int ret; + if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) + return rdev->desc->fixed_uV; + if (!ops->list_voltage || selector >= rdev->desc->n_voltages) return -EINVAL; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 04406a91..234960d 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -139,6 +139,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) struct property *prop; const char *regtype; int proplen, gpio, i; + int ret; config = devm_kzalloc(dev, sizeof(struct gpio_regulator_config), @@ -202,7 +203,11 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) } config->nr_states = i; - of_property_read_string(np, "regulator-type", ®type); + ret = of_property_read_string(np, "regulator-type", ®type); + if (ret < 0) { + dev_err(dev, "Missing 'regulator-type' property\n"); + return ERR_PTR(-EINVAL); + } if (!strncmp("voltage", regtype, 7)) config->type = REGULATOR_VOLTAGE; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index ba67b2c..032df37 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -308,9 +308,15 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) if (ret) return ret; - if (value & 0x0f) { - dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); - return -ENODEV; + switch (value & 0x0f) { + /* Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 as ID=8 */ + case 0x8: + dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); + case 0x0: + break; + default: + dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); + return -ENODEV; } ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cee7e27..95e4578 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3224,6 +3224,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, fcx_multitrack = private->features.feature[40] & 0x20; data_size = blk_rq_bytes(req); + if (data_size % blksize) + return ERR_PTR(-EINVAL); /* tpm write request add CBC data on each track boundary */ if (rq_data_dir(req) == WRITE) data_size += (last_trk - first_trk) * 4; diff --git a/drivers/staging/btmtk_usb/btmtk_usb.c b/drivers/staging/btmtk_usb/btmtk_usb.c index 7a9bf3b..9a5ebd6 100644 --- a/drivers/staging/btmtk_usb/btmtk_usb.c +++ b/drivers/staging/btmtk_usb/btmtk_usb.c @@ -1284,9 +1284,8 @@ done: kfree_skb(skb); } -static int btmtk_usb_send_frame(struct sk_buff *skb) +static int btmtk_usb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_dev *hdev = (struct hci_dev *)skb->dev; struct btmtk_usb_data *data = hci_get_drvdata(hdev); struct usb_ctrlrequest *dr; struct urb *urb; diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index d041b714..2baaf1d 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -173,11 +173,11 @@ static int pcl730_do_insn_bits(struct comedi_device *dev, if (mask) { if (mask & 0x00ff) outb(s->state & 0xff, dev->iobase + reg); - if ((mask & 0xff00) & (s->n_chan > 8)) + if ((mask & 0xff00) && (s->n_chan > 8)) outb((s->state >> 8) & 0xff, dev->iobase + reg + 1); - if ((mask & 0xff0000) & (s->n_chan > 16)) + if ((mask & 0xff0000) && (s->n_chan > 16)) outb((s->state >> 16) & 0xff, dev->iobase + reg + 2); - if ((mask & 0xff000000) & (s->n_chan > 24)) + if ((mask & 0xff000000) && (s->n_chan > 24)) outb((s->state >> 24) & 0xff, dev->iobase + reg + 3); } diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 6815cfe..b486099 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -494,7 +494,7 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * Private helper function: Write setpoint to an application DAC channel. */ static void s626_set_dac(struct comedi_device *dev, uint16_t chan, - unsigned short dacdata) + int16_t dacdata) { struct s626_private *devpriv = dev->private; uint16_t signmask; diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 933b01a..0adf3cf 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -465,7 +465,7 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, unsigned char *rx_buf = devpriv->usb_rx_buf; unsigned char *tx_buf = devpriv->usb_tx_buf; int reg, cmd; - int ret; + int ret = 0; if (devpriv->model == VMK8061_MODEL) { reg = VMK8061_DO_REG; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 68ded17..12f333f 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -578,7 +578,7 @@ static int request_code_segment(struct ft1000_usb *ft1000dev, u16 **s_file, u8 **c_file, const u8 *endpoint, bool boot_case) { long word_length; - int status; + int status = 0; /*DEBUG("FT1000:REQUEST_CODE_SEGMENT\n");i*/ word_length = get_request_value(ft1000dev); @@ -1074,4 +1074,3 @@ int scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, return status; } - diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig index a3ea69e..34634da 100644 --- a/drivers/staging/iio/magnetometer/Kconfig +++ b/drivers/staging/iio/magnetometer/Kconfig @@ -6,6 +6,8 @@ menu "Magnetometer sensors" config SENSORS_HMC5843 tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say Y here to add support for the Honeywell HMC5843, HMC5883 and HMC5883L 3-Axis Magnetometer (digital compass). diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 2c3a9e1..8742432 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -8,4 +8,6 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ -obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o ipuv3-plane.o + +imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o +obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 51aa977..6bd015a 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -72,6 +72,7 @@ int imx_drm_crtc_id(struct imx_drm_crtc *crtc) { return crtc->pipe; } +EXPORT_SYMBOL_GPL(imx_drm_crtc_id); static void imx_drm_driver_lastclose(struct drm_device *drm) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index 5dec771..4d340f4 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -409,8 +409,8 @@ int ptlrpc_stop_pinger(void) struct l_wait_info lwi = { 0 }; int rc = 0; - if (!thread_is_init(&pinger_thread) && - !thread_is_stopped(&pinger_thread)) + if (thread_is_init(&pinger_thread) || + thread_is_stopped(&pinger_thread)) return -EALREADY; ptlrpc_pinger_remove_timeouts(); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 58684da..b658c23 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -15,6 +15,8 @@ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -661,7 +663,7 @@ static int go7007_usb_interface_reset(struct go7007 *go) if (usb->board->flags & GO7007_USB_EZUSB) { /* Reset buffer in EZ-USB */ - dev_dbg(go->dev, "resetting EZ-USB buffers\n"); + pr_debug("resetting EZ-USB buffers\n"); if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) return -1; @@ -689,7 +691,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, u16 status_reg = 0; int timeout = 500; - dev_dbg(go->dev, "WriteInterrupt: %04x %04x\n", addr, data); + pr_debug("WriteInterrupt: %04x %04x\n", addr, data); for (i = 0; i < 100; ++i) { r = usb_control_msg(usb->usbdev, @@ -734,7 +736,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, int r; int timeout = 500; - dev_dbg(go->dev, "WriteInterrupt: %04x %04x\n", addr, data); + pr_debug("WriteInterrupt: %04x %04x\n", addr, data); go->usb_buf[0] = data & 0xff; go->usb_buf[1] = data >> 8; @@ -771,7 +773,7 @@ static void go7007_usb_readinterrupt_complete(struct urb *urb) go->interrupt_available = 1; go->interrupt_data = __le16_to_cpu(regs[0]); go->interrupt_value = __le16_to_cpu(regs[1]); - dev_dbg(go->dev, "ReadInterrupt: %04x %04x\n", + pr_debug("ReadInterrupt: %04x %04x\n", go->interrupt_value, go->interrupt_data); } @@ -891,7 +893,7 @@ static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) int transferred, pipe; int timeout = 500; - dev_dbg(go->dev, "DownloadBuffer sending %d bytes\n", len); + pr_debug("DownloadBuffer sending %d bytes\n", len); if (usb->board->flags & GO7007_USB_EZUSB) pipe = usb_sndbulkpipe(usb->usbdev, 2); @@ -977,7 +979,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, !(msgs[i].flags & I2C_M_RD) && (msgs[i + 1].flags & I2C_M_RD)) { #ifdef GO7007_I2C_DEBUG - dev_dbg(go->dev, "i2c write/read %d/%d bytes on %02x\n", + pr_debug("i2c write/read %d/%d bytes on %02x\n", msgs[i].len, msgs[i + 1].len, msgs[i].addr); #endif buf[0] = 0x01; @@ -988,7 +990,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, buf[buf_len++] = msgs[++i].len; } else if (msgs[i].flags & I2C_M_RD) { #ifdef GO7007_I2C_DEBUG - dev_dbg(go->dev, "i2c read %d bytes on %02x\n", + pr_debug("i2c read %d bytes on %02x\n", msgs[i].len, msgs[i].addr); #endif buf[0] = 0x01; @@ -998,7 +1000,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, buf_len = 4; } else { #ifdef GO7007_I2C_DEBUG - dev_dbg(go->dev, "i2c write %d bytes on %02x\n", + pr_debug("i2c write %d bytes on %02x\n", msgs[i].len, msgs[i].addr); #endif buf[0] = 0x00; @@ -1057,7 +1059,7 @@ static int go7007_usb_probe(struct usb_interface *intf, char *name; int video_pipe, i, v_urb_len; - dev_dbg(go->dev, "probing new GO7007 USB board\n"); + pr_debug("probing new GO7007 USB board\n"); switch (id->driver_info) { case GO7007_BOARDID_MATRIX_II: @@ -1097,13 +1099,13 @@ static int go7007_usb_probe(struct usb_interface *intf, board = &board_px_tv402u; break; case GO7007_BOARDID_LIFEVIEW_LR192: - dev_err(go->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n"); + dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n"); return -ENODEV; name = "Lifeview TV Walker Ultra"; board = &board_lifeview_lr192; break; case GO7007_BOARDID_SENSORAY_2250: - dev_info(go->dev, "Sensoray 2250 found\n"); + dev_info(&intf->dev, "Sensoray 2250 found\n"); name = "Sensoray 2250/2251"; board = &board_sensoray_2250; break; @@ -1112,7 +1114,7 @@ static int go7007_usb_probe(struct usb_interface *intf, board = &board_ads_usbav_709; break; default: - dev_err(go->dev, "unknown board ID %d!\n", + dev_err(&intf->dev, "unknown board ID %d!\n", (unsigned int)id->driver_info); return -ENODEV; } @@ -1247,7 +1249,7 @@ static int go7007_usb_probe(struct usb_interface *intf, sizeof(go->name)); break; default: - dev_dbg(go->dev, "unable to detect tuner type!\n"); + pr_debug("unable to detect tuner type!\n"); break; } /* Configure tuner mode selection inputs connected diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 3066ee2..49ea76b 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -681,7 +681,8 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) dev_err(nvec->dev, "RX buffer overflow on %p: " "Trying to write byte %u of %u\n", - nvec->rx, nvec->rx->pos, NVEC_MSG_SIZE); + nvec->rx, nvec->rx ? nvec->rx->pos : 0, + NVEC_MSG_SIZE); break; default: nvec->state = 0; diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 2c678f4..2f548eb 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -1115,6 +1115,9 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) return _FAIL; } + /* fix bug of flush_cam_entry at STOP AP mode */ + psta->state |= WIFI_AP_STATE; + rtw_indicate_connect(padapter); pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */ return ret; } diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig index 165b918..1b6d581 100644 --- a/drivers/staging/tidspbridge/Kconfig +++ b/drivers/staging/tidspbridge/Kconfig @@ -4,7 +4,7 @@ menuconfig TIDSPBRIDGE tristate "DSP Bridge driver" - depends on ARCH_OMAP3 && !ARCH_MULTIPLATFORM + depends on ARCH_OMAP3 && !ARCH_MULTIPLATFORM && BROKEN select MAILBOX select OMAP2PLUS_MBOX help diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c index aab0012..ab8b2ba 100644 --- a/drivers/staging/vt6655/hostap.c +++ b/drivers/staging/vt6655/hostap.c @@ -143,7 +143,8 @@ static int hostap_disable_hostapd(PSDevice pDevice, int rtnl_locked) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n", pDevice->dev->name, pDevice->apdev->name); } - free_netdev(pDevice->apdev); + if (pDevice->apdev) + free_netdev(pDevice->apdev); pDevice->apdev = NULL; pDevice->bEnable8021x = false; pDevice->bEnableHostWEP = false; diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c index 1e8b841..4aa5ef5 100644 --- a/drivers/staging/vt6656/baseband.c +++ b/drivers/staging/vt6656/baseband.c @@ -939,6 +939,7 @@ int BBbVT3184Init(struct vnt_private *pDevice) u8 * pbyAgc; u16 wLengthAgc; u8 abyArray[256]; + u8 data; ntStatus = CONTROLnsRequestIn(pDevice, MESSAGE_TYPE_READ, @@ -1104,6 +1105,16 @@ else { ControlvWriteByte(pDevice,MESSAGE_REQUEST_BBREG,0x0D,0x01); RFbRFTableDownload(pDevice); + + /* Fix for TX USB resets from vendors driver */ + CONTROLnsRequestIn(pDevice, MESSAGE_TYPE_READ, USB_REG4, + MESSAGE_REQUEST_MEM, sizeof(data), &data); + + data |= 0x2; + + CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_WRITE, USB_REG4, + MESSAGE_REQUEST_MEM, sizeof(data), &data); + return true;//ntStatus; } diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c index ae1676d..67ba48b 100644 --- a/drivers/staging/vt6656/hostap.c +++ b/drivers/staging/vt6656/hostap.c @@ -133,7 +133,8 @@ static int hostap_disable_hostapd(struct vnt_private *pDevice, int rtnl_locked) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n", pDevice->dev->name, pDevice->apdev->name); } - free_netdev(pDevice->apdev); + if (pDevice->apdev) + free_netdev(pDevice->apdev); pDevice->apdev = NULL; pDevice->bEnable8021x = false; pDevice->bEnableHostWEP = false; diff --git a/drivers/staging/vt6656/rndis.h b/drivers/staging/vt6656/rndis.h index 5e07306..5cf5e73 100644 --- a/drivers/staging/vt6656/rndis.h +++ b/drivers/staging/vt6656/rndis.h @@ -66,6 +66,8 @@ #define VIAUSB20_PACKET_HEADER 0x04 +#define USB_REG4 0x604 + typedef struct _CMD_MESSAGE { u8 byData[256]; diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 79ce363..3277d98 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -652,21 +652,30 @@ static ssize_t reset_store(struct device *dev, return -ENOMEM; /* Do not reset an active device! */ - if (bdev->bd_holders) - return -EBUSY; + if (bdev->bd_holders) { + ret = -EBUSY; + goto out; + } ret = kstrtou16(buf, 10, &do_reset); if (ret) - return ret; + goto out; - if (!do_reset) - return -EINVAL; + if (!do_reset) { + ret = -EINVAL; + goto out; + } /* Make sure all pending I/O is finished */ fsync_bdev(bdev); + bdput(bdev); zram_reset_device(zram, true); return len; + +out: + bdput(bdev); + return ret; } static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c index 1a67537..3b950e5 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/drivers/staging/zsmalloc/zsmalloc-main.c @@ -430,7 +430,12 @@ static struct page *get_next_page(struct page *page) return next; } -/* Encode <page, obj_idx> as a single handle value */ +/* + * Encode <page, obj_idx> as a single handle value. + * On hardware platforms with physical memory starting at 0x0 the pfn + * could be 0 so we ensure that the handle will never be 0 by adjusting the + * encoded obj_idx value before encoding. + */ static void *obj_location_to_handle(struct page *page, unsigned long obj_idx) { unsigned long handle; @@ -441,17 +446,21 @@ static void *obj_location_to_handle(struct page *page, unsigned long obj_idx) } handle = page_to_pfn(page) << OBJ_INDEX_BITS; - handle |= (obj_idx & OBJ_INDEX_MASK); + handle |= ((obj_idx + 1) & OBJ_INDEX_MASK); return (void *)handle; } -/* Decode <page, obj_idx> pair from the given object handle */ +/* + * Decode <page, obj_idx> pair from the given object handle. We adjust the + * decoded obj_idx back to its original value since it was adjusted in + * obj_location_to_handle(). + */ static void obj_handle_to_location(unsigned long handle, struct page **page, unsigned long *obj_idx) { *page = pfn_to_page(handle >> OBJ_INDEX_BITS); - *obj_idx = handle & OBJ_INDEX_MASK; + *obj_idx = (handle & OBJ_INDEX_MASK) - 1; } static unsigned long obj_idx_to_offset(struct page *page, diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 2b86f8e..71630a2 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1855,6 +1855,9 @@ static struct console sercons = { */ static int __init amiserial_console_init(void) { + if (!MACH_IS_AMIGA) + return -ENODEV; + register_console(&sercons); return 0; } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7cdd1eb..0f74945 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -768,7 +768,7 @@ static size_t __process_echoes(struct tty_struct *tty) * data at the tail to prevent a subsequent overrun */ while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { if (echo_buf(ldata, tail) == ECHO_OP_START) { - if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB) + if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) tail += 3; else tail += 2; @@ -1998,7 +1998,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, found = 1; size = N_TTY_BUF_SIZE - tail; - n = (found + eol + size) & (N_TTY_BUF_SIZE - 1); + n = eol - tail; + if (n > 4096) + n += 4096; + n += found; c = n; if (found && read_buf(ldata, eol) == __DISABLED_CHAR) { @@ -2243,18 +2246,19 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, if (time) timeout = time; } - mutex_unlock(&ldata->atomic_read_lock); - remove_wait_queue(&tty->read_wait, &wait); + n_tty_set_room(tty); + up_read(&tty->termios_rwsem); + remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) ldata->minimum_to_wake = minimum; + mutex_unlock(&ldata->atomic_read_lock); + __set_current_state(TASK_RUNNING); if (b - buf) retval = b - buf; - n_tty_set_room(tty); - up_read(&tty->termios_rwsem); return retval; } diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f3b306e..2332991 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -41,7 +41,7 @@ config SERIAL_8250_DEPRECATED_OPTIONS accept kernel parameters in both forms like 8250_core.nr_uarts=4 and 8250.nr_uarts=4. We now renamed the module back to 8250, but if anybody noticed in 3.7 and changed their userspace we still have to - keep the 8350_core.* options around until they revert the changes + keep the 8250_core.* options around until they revert the changes they already did. If 8250 is built as a module, this adds 8250_core alias instead. diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 481b781..e9d420f 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -2052,6 +2052,9 @@ static int __init pmz_console_init(void) /* Probe ports */ pmz_probe(); + if (pmz_ports_count == 0) + return -ENODEV; + /* TODO: Autoprobe console based on OF */ /* pmz_console.index = i; */ register_console(&pmz_console); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 3a1a01a..c74a00a 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2086,6 +2086,7 @@ retry_open: filp->f_op = &tty_fops; goto retry_open; } + clear_bit(TTY_HUPPED, &tty->flags); tty_unlock(tty); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2cb52e0..9f71d9f 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc) #if defined(CONFIG_ARCH_AT91SAM9RL) -#include <mach/at91_pmc.h> +#include <linux/clk/at91_pmc.h> static void toggle_bias(int is_on) { diff --git a/fs/affs/Changes b/fs/affs/Changes index a29409c..b41c2c9 100644 --- a/fs/affs/Changes +++ b/fs/affs/Changes @@ -91,7 +91,7 @@ more 2.4 fixes: [Roman Zippel] Version 3.11 ------------ -- Converted to use 2.3.x page cache [Dave Jones <dave@powertweak.com>] +- Converted to use 2.3.x page cache [Dave Jones] - Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>] Version 3.10 diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 6df8bd4..1e561c0 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -216,7 +216,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) } SetPageUptodate(page); - if (err == 0) + if (err >= 0) ceph_readpage_to_fscache(inode, page); out: diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c index 7db2e6c..8c44fdd 100644 --- a/fs/ceph/cache.c +++ b/fs/ceph/cache.c @@ -324,6 +324,9 @@ void ceph_invalidate_fscache_page(struct inode* inode, struct page *page) { struct ceph_inode_info *ci = ceph_inode(inode); + if (!PageFsCache(page)) + return; + fscache_wait_on_page_write(ci->fscache, page); fscache_uncache_page(ci->fscache, page); } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 13976c3..3c0a4bd 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -897,7 +897,7 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci) * caller should hold i_ceph_lock. * caller will not hold session s_mutex if called from destroy_inode. */ -void __ceph_remove_cap(struct ceph_cap *cap) +void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) { struct ceph_mds_session *session = cap->session; struct ceph_inode_info *ci = cap->ci; @@ -909,6 +909,16 @@ void __ceph_remove_cap(struct ceph_cap *cap) /* remove from session list */ spin_lock(&session->s_cap_lock); + /* + * s_cap_reconnect is protected by s_cap_lock. no one changes + * s_cap_gen while session is in the reconnect state. + */ + if (queue_release && + (!session->s_cap_reconnect || + cap->cap_gen == session->s_cap_gen)) + __queue_cap_release(session, ci->i_vino.ino, cap->cap_id, + cap->mseq, cap->issue_seq); + if (session->s_cap_iterator == cap) { /* not yet, we are iterating over this very cap */ dout("__ceph_remove_cap delaying %p removal from session %p\n", @@ -1023,7 +1033,6 @@ void __queue_cap_release(struct ceph_mds_session *session, struct ceph_mds_cap_release *head; struct ceph_mds_cap_item *item; - spin_lock(&session->s_cap_lock); BUG_ON(!session->s_num_cap_releases); msg = list_first_entry(&session->s_cap_releases, struct ceph_msg, list_head); @@ -1052,7 +1061,6 @@ void __queue_cap_release(struct ceph_mds_session *session, (int)CEPH_CAPS_PER_RELEASE, (int)msg->front.iov_len); } - spin_unlock(&session->s_cap_lock); } /* @@ -1067,12 +1075,8 @@ void ceph_queue_caps_release(struct inode *inode) p = rb_first(&ci->i_caps); while (p) { struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); - struct ceph_mds_session *session = cap->session; - - __queue_cap_release(session, ceph_ino(inode), cap->cap_id, - cap->mseq, cap->issue_seq); p = rb_next(p); - __ceph_remove_cap(cap); + __ceph_remove_cap(cap, true); } } @@ -2791,7 +2795,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, } spin_unlock(&mdsc->cap_dirty_lock); } - __ceph_remove_cap(cap); + __ceph_remove_cap(cap, false); } /* else, we already released it */ @@ -2931,9 +2935,12 @@ void ceph_handle_caps(struct ceph_mds_session *session, if (!inode) { dout(" i don't have ino %llx\n", vino.ino); - if (op == CEPH_CAP_OP_IMPORT) + if (op == CEPH_CAP_OP_IMPORT) { + spin_lock(&session->s_cap_lock); __queue_cap_release(session, vino.ino, cap_id, mseq, seq); + spin_unlock(&session->s_cap_lock); + } goto flush_cap_releases; } diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 868b61d..2a0bcae 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -352,8 +352,18 @@ more: } /* note next offset and last dentry name */ + rinfo = &req->r_reply_info; + if (le32_to_cpu(rinfo->dir_dir->frag) != frag) { + frag = le32_to_cpu(rinfo->dir_dir->frag); + if (ceph_frag_is_leftmost(frag)) + fi->next_offset = 2; + else + fi->next_offset = 0; + off = fi->next_offset; + } fi->offset = fi->next_offset; fi->last_readdir = req; + fi->frag = frag; if (req->r_reply_info.dir_end) { kfree(fi->last_name); @@ -363,7 +373,6 @@ more: else fi->next_offset = 0; } else { - rinfo = &req->r_reply_info; err = note_last_dentry(fi, rinfo->dir_dname[rinfo->dir_nr-1], rinfo->dir_dname_len[rinfo->dir_nr-1]); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8549a48..9a8e396 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -577,6 +577,8 @@ static int fill_inode(struct inode *inode, int issued = 0, implemented; struct timespec mtime, atime, ctime; u32 nsplits; + struct ceph_inode_frag *frag; + struct rb_node *rb_node; struct ceph_buffer *xattr_blob = NULL; int err = 0; int queue_trunc = 0; @@ -751,15 +753,38 @@ no_change: /* FIXME: move me up, if/when version reflects fragtree changes */ nsplits = le32_to_cpu(info->fragtree.nsplits); mutex_lock(&ci->i_fragtree_mutex); + rb_node = rb_first(&ci->i_fragtree); for (i = 0; i < nsplits; i++) { u32 id = le32_to_cpu(info->fragtree.splits[i].frag); - struct ceph_inode_frag *frag = __get_or_create_frag(ci, id); - - if (IS_ERR(frag)) - continue; + frag = NULL; + while (rb_node) { + frag = rb_entry(rb_node, struct ceph_inode_frag, node); + if (ceph_frag_compare(frag->frag, id) >= 0) { + if (frag->frag != id) + frag = NULL; + else + rb_node = rb_next(rb_node); + break; + } + rb_node = rb_next(rb_node); + rb_erase(&frag->node, &ci->i_fragtree); + kfree(frag); + frag = NULL; + } + if (!frag) { + frag = __get_or_create_frag(ci, id); + if (IS_ERR(frag)) + continue; + } frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); dout(" frag %x split by %d\n", frag->frag, frag->split_by); } + while (rb_node) { + frag = rb_entry(rb_node, struct ceph_inode_frag, node); + rb_node = rb_next(rb_node); + rb_erase(&frag->node, &ci->i_fragtree); + kfree(frag); + } mutex_unlock(&ci->i_fragtree_mutex); /* were we issued a capability? */ @@ -1250,8 +1275,20 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, int err = 0, i; struct inode *snapdir = NULL; struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; - u64 frag = le32_to_cpu(rhead->args.readdir.frag); struct ceph_dentry_info *di; + u64 r_readdir_offset = req->r_readdir_offset; + u32 frag = le32_to_cpu(rhead->args.readdir.frag); + + if (rinfo->dir_dir && + le32_to_cpu(rinfo->dir_dir->frag) != frag) { + dout("readdir_prepopulate got new frag %x -> %x\n", + frag, le32_to_cpu(rinfo->dir_dir->frag)); + frag = le32_to_cpu(rinfo->dir_dir->frag); + if (ceph_frag_is_leftmost(frag)) + r_readdir_offset = 2; + else + r_readdir_offset = 0; + } if (req->r_aborted) return readdir_prepopulate_inodes_only(req, session); @@ -1315,7 +1352,7 @@ retry_lookup: } di = dn->d_fsdata; - di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset); + di->offset = ceph_make_fpos(frag, i + r_readdir_offset); /* inode */ if (dn->d_inode) { diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b7bda5d..d90861f 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -43,6 +43,7 @@ */ struct ceph_reconnect_state { + int nr_caps; struct ceph_pagelist *pagelist; bool flock; }; @@ -443,6 +444,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, INIT_LIST_HEAD(&s->s_waiting); INIT_LIST_HEAD(&s->s_unsafe); s->s_num_cap_releases = 0; + s->s_cap_reconnect = 0; s->s_cap_iterator = NULL; INIT_LIST_HEAD(&s->s_cap_releases); INIT_LIST_HEAD(&s->s_cap_releases_done); @@ -642,6 +644,8 @@ static void __unregister_request(struct ceph_mds_client *mdsc, req->r_unsafe_dir = NULL; } + complete_all(&req->r_safe_completion); + ceph_mdsc_put_request(req); } @@ -986,7 +990,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, dout("removing cap %p, ci is %p, inode is %p\n", cap, ci, &ci->vfs_inode); spin_lock(&ci->i_ceph_lock); - __ceph_remove_cap(cap); + __ceph_remove_cap(cap, false); if (!__ceph_is_any_real_caps(ci)) { struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; @@ -1231,9 +1235,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) session->s_trim_caps--; if (oissued) { /* we aren't the only cap.. just remove us */ - __queue_cap_release(session, ceph_ino(inode), cap->cap_id, - cap->mseq, cap->issue_seq); - __ceph_remove_cap(cap); + __ceph_remove_cap(cap, true); } else { /* try to drop referring dentries */ spin_unlock(&ci->i_ceph_lock); @@ -1416,7 +1418,6 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, unsigned num; dout("discard_cap_releases mds%d\n", session->s_mds); - spin_lock(&session->s_cap_lock); /* zero out the in-progress message */ msg = list_first_entry(&session->s_cap_releases, @@ -1443,8 +1444,6 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, msg->front.iov_len = sizeof(*head); list_add(&msg->list_head, &session->s_cap_releases); } - - spin_unlock(&session->s_cap_lock); } /* @@ -1875,8 +1874,11 @@ static int __do_request(struct ceph_mds_client *mdsc, int mds = -1; int err = -EAGAIN; - if (req->r_err || req->r_got_result) + if (req->r_err || req->r_got_result) { + if (req->r_aborted) + __unregister_request(mdsc, req); goto out; + } if (req->r_timeout && time_after_eq(jiffies, req->r_started + req->r_timeout)) { @@ -2186,7 +2188,6 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) if (head->safe) { req->r_got_safe = true; __unregister_request(mdsc, req); - complete_all(&req->r_safe_completion); if (req->r_got_unsafe) { /* @@ -2238,8 +2239,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); if (err == 0) { if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR || - req->r_op == CEPH_MDS_OP_LSSNAP) && - rinfo->dir_nr) + req->r_op == CEPH_MDS_OP_LSSNAP)) ceph_readdir_prepopulate(req, req->r_session); ceph_unreserve_caps(mdsc, &req->r_caps_reservation); } @@ -2490,6 +2490,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, cap->seq = 0; /* reset cap seq */ cap->issue_seq = 0; /* and issue_seq */ cap->mseq = 0; /* and migrate_seq */ + cap->cap_gen = cap->session->s_cap_gen; if (recon_state->flock) { rec.v2.cap_id = cpu_to_le64(cap->cap_id); @@ -2552,6 +2553,8 @@ encode_again: } else { err = ceph_pagelist_append(pagelist, &rec, reclen); } + + recon_state->nr_caps++; out_free: kfree(path); out_dput: @@ -2579,6 +2582,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, struct rb_node *p; int mds = session->s_mds; int err = -ENOMEM; + int s_nr_caps; struct ceph_pagelist *pagelist; struct ceph_reconnect_state recon_state; @@ -2610,20 +2614,38 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, dout("session %p state %s\n", session, session_state_name(session->s_state)); + spin_lock(&session->s_gen_ttl_lock); + session->s_cap_gen++; + spin_unlock(&session->s_gen_ttl_lock); + + spin_lock(&session->s_cap_lock); + /* + * notify __ceph_remove_cap() that we are composing cap reconnect. + * If a cap get released before being added to the cap reconnect, + * __ceph_remove_cap() should skip queuing cap release. + */ + session->s_cap_reconnect = 1; /* drop old cap expires; we're about to reestablish that state */ discard_cap_releases(mdsc, session); + spin_unlock(&session->s_cap_lock); /* traverse this session's caps */ - err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps); + s_nr_caps = session->s_nr_caps; + err = ceph_pagelist_encode_32(pagelist, s_nr_caps); if (err) goto fail; + recon_state.nr_caps = 0; recon_state.pagelist = pagelist; recon_state.flock = session->s_con.peer_features & CEPH_FEATURE_FLOCK; err = iterate_session_caps(session, encode_caps_cb, &recon_state); if (err < 0) goto fail; + spin_lock(&session->s_cap_lock); + session->s_cap_reconnect = 0; + spin_unlock(&session->s_cap_lock); + /* * snaprealms. we provide mds with the ino, seq (version), and * parent for all of our realms. If the mds has any newer info, @@ -2646,11 +2668,18 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, if (recon_state.flock) reply->hdr.version = cpu_to_le16(2); - if (pagelist->length) { - /* set up outbound data if we have any */ - reply->hdr.data_len = cpu_to_le32(pagelist->length); - ceph_msg_data_add_pagelist(reply, pagelist); + + /* raced with cap release? */ + if (s_nr_caps != recon_state.nr_caps) { + struct page *page = list_first_entry(&pagelist->head, + struct page, lru); + __le32 *addr = kmap_atomic(page); + *addr = cpu_to_le32(recon_state.nr_caps); + kunmap_atomic(addr); } + + reply->hdr.data_len = cpu_to_le32(pagelist->length); + ceph_msg_data_add_pagelist(reply, pagelist); ceph_con_send(&session->s_con, reply); mutex_unlock(&session->s_mutex); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index c2a19fb..4c053d0 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -132,6 +132,7 @@ struct ceph_mds_session { struct list_head s_caps; /* all caps issued by this session */ int s_nr_caps, s_trim_caps; int s_num_cap_releases; + int s_cap_reconnect; struct list_head s_cap_releases; /* waiting cap_release messages */ struct list_head s_cap_releases_done; /* ready to send */ struct ceph_cap *s_cap_iterator; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 6014b0a..ef4ac38 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -741,13 +741,7 @@ extern int ceph_add_cap(struct inode *inode, int fmode, unsigned issued, unsigned wanted, unsigned cap, unsigned seq, u64 realmino, int flags, struct ceph_cap_reservation *caps_reservation); -extern void __ceph_remove_cap(struct ceph_cap *cap); -static inline void ceph_remove_cap(struct ceph_cap *cap) -{ - spin_lock(&cap->ci->i_ceph_lock); - __ceph_remove_cap(cap); - spin_unlock(&cap->ci->i_ceph_lock); -} +extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); extern void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d9ea7ad..f918a99 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -384,6 +384,7 @@ struct smb_version_operations { int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, struct cifsFileInfo *target_file, u64 src_off, u64 len, u64 dest_off); + int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); }; struct smb_version_values { diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 409b45e..7749230 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -26,13 +26,15 @@ #include <linux/mount.h> #include <linux/mm.h> #include <linux/pagemap.h> -#include <linux/btrfs.h> #include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" #include "cifsfs.h" +#define CIFS_IOCTL_MAGIC 0xCF +#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) + static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, unsigned long srcfd, u64 off, u64 len, u64 destoff) { @@ -213,7 +215,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) cifs_dbg(FYI, "set compress flag rc %d\n", rc); } break; - case BTRFS_IOC_CLONE: + case CIFS_IOC_COPYCHUNK_FILE: rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0); break; default: diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 11dde4b..757da3e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -532,7 +532,10 @@ smb2_clone_range(const unsigned int xid, int rc; unsigned int ret_data_len; struct copychunk_ioctl *pcchunk; - char *retbuf = NULL; + struct copychunk_ioctl_rsp *retbuf = NULL; + struct cifs_tcon *tcon; + int chunks_copied = 0; + bool chunk_sizes_updated = false; pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); @@ -547,27 +550,96 @@ smb2_clone_range(const unsigned int xid, /* Note: request_res_key sets res_key null only if rc !=0 */ if (rc) - return rc; + goto cchunk_out; /* For now array only one chunk long, will make more flexible later */ pcchunk->ChunkCount = __constant_cpu_to_le32(1); pcchunk->Reserved = 0; - pcchunk->SourceOffset = cpu_to_le64(src_off); - pcchunk->TargetOffset = cpu_to_le64(dest_off); - pcchunk->Length = cpu_to_le32(len); pcchunk->Reserved2 = 0; - /* Request that server copy to target from src file identified by key */ - rc = SMB2_ioctl(xid, tlink_tcon(trgtfile->tlink), - trgtfile->fid.persistent_fid, - trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, - true /* is_fsctl */, (char *)pcchunk, - sizeof(struct copychunk_ioctl), &retbuf, &ret_data_len); + tcon = tlink_tcon(trgtfile->tlink); - /* BB need to special case rc = EINVAL to alter chunk size */ + while (len > 0) { + pcchunk->SourceOffset = cpu_to_le64(src_off); + pcchunk->TargetOffset = cpu_to_le64(dest_off); + pcchunk->Length = + cpu_to_le32(min_t(u32, len, tcon->max_bytes_chunk)); - cifs_dbg(FYI, "rc %d data length out %d\n", rc, ret_data_len); + /* Request server copy to target from src identified by key */ + rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, + trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, + true /* is_fsctl */, (char *)pcchunk, + sizeof(struct copychunk_ioctl), (char **)&retbuf, + &ret_data_len); + if (rc == 0) { + if (ret_data_len != + sizeof(struct copychunk_ioctl_rsp)) { + cifs_dbg(VFS, "invalid cchunk response size\n"); + rc = -EIO; + goto cchunk_out; + } + if (retbuf->TotalBytesWritten == 0) { + cifs_dbg(FYI, "no bytes copied\n"); + rc = -EIO; + goto cchunk_out; + } + /* + * Check if server claimed to write more than we asked + */ + if (le32_to_cpu(retbuf->TotalBytesWritten) > + le32_to_cpu(pcchunk->Length)) { + cifs_dbg(VFS, "invalid copy chunk response\n"); + rc = -EIO; + goto cchunk_out; + } + if (le32_to_cpu(retbuf->ChunksWritten) != 1) { + cifs_dbg(VFS, "invalid num chunks written\n"); + rc = -EIO; + goto cchunk_out; + } + chunks_copied++; + + src_off += le32_to_cpu(retbuf->TotalBytesWritten); + dest_off += le32_to_cpu(retbuf->TotalBytesWritten); + len -= le32_to_cpu(retbuf->TotalBytesWritten); + + cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %d\n", + le32_to_cpu(retbuf->ChunksWritten), + le32_to_cpu(retbuf->ChunkBytesWritten), + le32_to_cpu(retbuf->TotalBytesWritten)); + } else if (rc == -EINVAL) { + if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) + goto cchunk_out; + + cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n", + le32_to_cpu(retbuf->ChunksWritten), + le32_to_cpu(retbuf->ChunkBytesWritten), + le32_to_cpu(retbuf->TotalBytesWritten)); + + /* + * Check if this is the first request using these sizes, + * (ie check if copy succeed once with original sizes + * and check if the server gave us different sizes after + * we already updated max sizes on previous request). + * if not then why is the server returning an error now + */ + if ((chunks_copied != 0) || chunk_sizes_updated) + goto cchunk_out; + + /* Check that server is not asking us to grow size */ + if (le32_to_cpu(retbuf->ChunkBytesWritten) < + tcon->max_bytes_chunk) + tcon->max_bytes_chunk = + le32_to_cpu(retbuf->ChunkBytesWritten); + else + goto cchunk_out; /* server gave us bogus size */ + + /* No need to change MaxChunks since already set to 1 */ + chunk_sizes_updated = true; + } + } +cchunk_out: kfree(pcchunk); return rc; } @@ -1247,6 +1319,7 @@ struct smb_version_operations smb30_operations = { .create_lease_buf = smb3_create_lease_buf, .parse_lease_buf = smb3_parse_lease_buf, .clone_range = smb2_clone_range, + .validate_negotiate = smb3_validate_negotiate, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index d65270c..2013234 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -454,6 +454,81 @@ neg_exit: return rc; } +int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) +{ + int rc = 0; + struct validate_negotiate_info_req vneg_inbuf; + struct validate_negotiate_info_rsp *pneg_rsp; + u32 rsplen; + + cifs_dbg(FYI, "validate negotiate\n"); + + /* + * validation ioctl must be signed, so no point sending this if we + * can not sign it. We could eventually change this to selectively + * sign just this, the first and only signed request on a connection. + * This is good enough for now since a user who wants better security + * would also enable signing on the mount. Having validation of + * negotiate info for signed connections helps reduce attack vectors + */ + if (tcon->ses->server->sign == false) + return 0; /* validation requires signing */ + + vneg_inbuf.Capabilities = + cpu_to_le32(tcon->ses->server->vals->req_capabilities); + memcpy(vneg_inbuf.Guid, cifs_client_guid, SMB2_CLIENT_GUID_SIZE); + + if (tcon->ses->sign) + vneg_inbuf.SecurityMode = + cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); + else if (global_secflags & CIFSSEC_MAY_SIGN) + vneg_inbuf.SecurityMode = + cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED); + else + vneg_inbuf.SecurityMode = 0; + + vneg_inbuf.DialectCount = cpu_to_le16(1); + vneg_inbuf.Dialects[0] = + cpu_to_le16(tcon->ses->server->vals->protocol_id); + + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, + (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), + (char **)&pneg_rsp, &rsplen); + + if (rc != 0) { + cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); + return -EIO; + } + + if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { + cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); + return -EIO; + } + + /* check validate negotiate info response matches what we got earlier */ + if (pneg_rsp->Dialect != + cpu_to_le16(tcon->ses->server->vals->protocol_id)) + goto vneg_out; + + if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode)) + goto vneg_out; + + /* do not validate server guid because not saved at negprot time yet */ + + if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND | + SMB2_LARGE_FILES) != tcon->ses->server->capabilities) + goto vneg_out; + + /* validate negotiate successful */ + cifs_dbg(FYI, "validate negotiate info successful\n"); + return 0; + +vneg_out: + cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n"); + return -EIO; +} + int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp) @@ -829,6 +904,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); init_copy_chunk_defaults(tcon); + if (tcon->ses->server->ops->validate_negotiate) + rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); tcon_exit: free_rsp_buf(resp_buftype, rsp); kfree(unc_path); @@ -1214,10 +1291,17 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; - if (rc != 0) { + if ((rc != 0) && (rc != -EINVAL)) { if (tcon) cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; + } else if (rc == -EINVAL) { + if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) && + (opcode != FSCTL_SRV_COPYCHUNK)) { + if (tcon) + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); + goto ioctl_exit; + } } /* check if caller wants to look at return data or just return rc */ @@ -2154,11 +2238,9 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0); rsp = (struct smb2_set_info_rsp *)iov[0].iov_base; - if (rc != 0) { + if (rc != 0) cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE); - goto out; - } -out: + free_rsp_buf(resp_buftype, rsp); kfree(iov); return rc; diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f88320b..2022c54 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -577,13 +577,19 @@ struct copychunk_ioctl_rsp { __le32 TotalBytesWritten; } __packed; -/* Response and Request are the same format */ -struct validate_negotiate_info { +struct validate_negotiate_info_req { __le32 Capabilities; __u8 Guid[SMB2_CLIENT_GUID_SIZE]; __le16 SecurityMode; __le16 DialectCount; - __le16 Dialect[1]; + __le16 Dialects[1]; /* dialect (someday maybe list) client asked for */ +} __packed; + +struct validate_negotiate_info_rsp { + __le32 Capabilities; + __u8 Guid[SMB2_CLIENT_GUID_SIZE]; + __le16 SecurityMode; + __le16 Dialect; /* Dialect in use for the connection */ } __packed; #define RSS_CAPABLE 0x00000001 diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index b4eea10..93adc64 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -162,5 +162,6 @@ extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, struct smb2_lock_element *buf); extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, __u8 *lease_key, const __le32 lease_state); +extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); #endif /* _SMB2PROTO_H */ diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index a4b2391f..0e538b5 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h @@ -90,7 +90,7 @@ #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ -#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */ +#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* Perform server-side data movement */ #define FSCTL_SRV_COPYCHUNK 0x001440F2 #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 @@ -513,8 +513,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) if (!lockref_get_not_dead(&parent->d_lockref)) { nd->path.dentry = NULL; - rcu_read_unlock(); - return -ECHILD; + goto out; } /* diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 79b5da2..b94f936 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -609,7 +609,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_open_file *of; - bool has_read, has_write; + bool has_read, has_write, has_mmap; int error = -EACCES; /* need attr_sd for attr and ops, its parent for kobj */ @@ -621,6 +621,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) has_read = battr->read || battr->mmap; has_write = battr->write || battr->mmap; + has_mmap = battr->mmap; } else { const struct sysfs_ops *ops = sysfs_file_ops(attr_sd); @@ -632,6 +633,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) has_read = ops->show; has_write = ops->store; + has_mmap = false; } /* check perms and supported operations */ @@ -649,7 +651,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) if (!of) goto err_out; - mutex_init(&of->mutex); + /* + * The following is done to give a different lockdep key to + * @of->mutex for files which implement mmap. This is a rather + * crude way to avoid false positive lockdep warning around + * mm->mmap_sem - mmap nests @of->mutex under mm->mmap_sem and + * reading /sys/block/sda/trace/act_mask grabs sr_mutex, under + * which mm->mmap_sem nests, while holding @of->mutex. As each + * open file has a separate mutex, it's okay as long as those don't + * happen on the same file. At this point, we can't easily give + * each file a separate locking class. Let's differentiate on + * whether the file has mmap or not for now. + */ + if (has_mmap) + mutex_init(&of->mutex); + else + mutex_init(&of->mutex); + of->sd = attr_sd; of->file = file; diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index d98c670..3ea214c 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -83,7 +83,9 @@ * Should the subsystem abort the loading of an ACPI table if the * table checksum is incorrect? */ +#ifndef ACPI_CHECKSUM_ABORT #define ACPI_CHECKSUM_ABORT FALSE +#endif /* * Generate a version of ACPICA that only supports "reduced hardware" diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7b2de02..c602c77 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -100,6 +100,7 @@ enum acpi_hotplug_mode { struct acpi_hotplug_profile { struct kobject kobj; bool enabled:1; + bool ignore:1; enum acpi_hotplug_mode mode; }; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d8f9457..4278aba9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20130927 +#define ACPI_CA_VERSION 0x20131115 #include <acpi/acconfig.h> #include <acpi/actypes.h> diff --git a/include/asm-generic/simd.h b/include/asm-generic/simd.h new file mode 100644 index 0000000..f57eb7b --- /dev/null +++ b/include/asm-generic/simd.h @@ -0,0 +1,14 @@ + +#include <linux/hardirq.h> + +/* + * may_use_simd - whether it is allowable at this time to issue SIMD + * instructions or access the SIMD register file + * + * As architectures typically don't preserve the SIMD register file when + * taking an interrupt, !in_interrupt() should be a reasonable default. + */ +static __must_check inline bool may_use_simd(void) +{ + return !in_interrupt(); +} diff --git a/arch/x86/include/asm/crypto/ablk_helper.h b/include/crypto/ablk_helper.h index 4f93df5..4f93df5 100644 --- a/arch/x86/include/asm/crypto/ablk_helper.h +++ b/include/crypto/ablk_helper.h diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 418d270..e73c19e 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -386,5 +386,21 @@ static inline int crypto_requires_sync(u32 type, u32 mask) return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC; } -#endif /* _CRYPTO_ALGAPI_H */ +noinline unsigned long __crypto_memneq(const void *a, const void *b, size_t size); + +/** + * crypto_memneq - Compare two areas of memory without leaking + * timing information. + * + * @a: One area of memory + * @b: Another area of memory + * @size: The size of the area. + * + * Returns 0 when data is equal, 1 otherwise. + */ +static inline int crypto_memneq(const void *a, const void *b, size_t size) +{ + return __crypto_memneq(a, b, size) != 0UL ? 1 : 0; +} +#endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/crypto/authenc.h b/include/crypto/authenc.h index e47b044..6775059 100644 --- a/include/crypto/authenc.h +++ b/include/crypto/authenc.h @@ -23,5 +23,15 @@ struct crypto_authenc_key_param { __be32 enckeylen; }; -#endif /* _CRYPTO_AUTHENC_H */ +struct crypto_authenc_keys { + const u8 *authkey; + const u8 *enckey; + + unsigned int authkeylen; + unsigned int enckeylen; +}; +int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key, + unsigned int keylen); + +#endif /* _CRYPTO_AUTHENC_H */ diff --git a/include/dt-bindings/clk/at91.h b/include/dt-bindings/clk/at91.h new file mode 100644 index 0000000..0b4cb99 --- /dev/null +++ b/include/dt-bindings/clk/at91.h @@ -0,0 +1,22 @@ +/* + * This header provides constants for AT91 pmc status. + * + * The constants defined in this header are being used in dts. + * + * Licensed under GPLv2 or later. + */ + +#ifndef _DT_BINDINGS_CLK_AT91_H +#define _DT_BINDINGS_CLK_AT91_H + +#define AT91_PMC_MOSCS 0 /* MOSCS Flag */ +#define AT91_PMC_LOCKA 1 /* PLLA Lock */ +#define AT91_PMC_LOCKB 2 /* PLLB Lock */ +#define AT91_PMC_MCKRDY 3 /* Master Clock */ +#define AT91_PMC_LOCKU 6 /* UPLL Lock */ +#define AT91_PMC_PCKRDY(id) (8 + (id)) /* Programmable Clock */ +#define AT91_PMC_MOSCSELS 16 /* Main Oscillator Selection */ +#define AT91_PMC_MOSCRCS 17 /* Main On-Chip RC */ +#define AT91_PMC_CFDEV 18 /* Clock Failure Detector Event */ + +#endif diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/include/linux/clk/at91_pmc.h index c604cc6..a6911eb 100644 --- a/arch/arm/mach-at91/include/mach/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-at91/include/mach/at91_pmc.h + * include/linux/clk/at91_pmc.h * * Copyright (C) 2005 Ivan Kokshaysky * Copyright (C) SAN People @@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ #define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ +#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */ + #define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ #define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ #define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 656a27e..82eac61 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -125,6 +125,13 @@ extern struct gpio_chip *gpiochip_find(void *data, int gpiod_lock_as_irq(struct gpio_desc *desc); void gpiod_unlock_as_irq(struct gpio_desc *desc); +enum gpio_lookup_flags { + GPIO_ACTIVE_HIGH = (0 << 0), + GPIO_ACTIVE_LOW = (1 << 0), + GPIO_OPEN_DRAIN = (1 << 1), + GPIO_OPEN_SOURCE = (1 << 2), +}; + /** * Lookup table for associating GPIOs to specific devices and functions using * platform data. @@ -152,9 +159,9 @@ struct gpiod_lookup { */ unsigned int idx; /* - * mask of GPIOF_* values + * mask of GPIO_* values */ - unsigned long flags; + enum gpio_lookup_flags flags; }; /* diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index a265af2..206a2af 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -21,6 +21,8 @@ #include <linux/hid.h> #include <linux/hid-sensor-ids.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> /** * struct hid_sensor_hub_attribute_info - Attribute info @@ -184,6 +186,7 @@ struct hid_sensor_common { struct platform_device *pdev; unsigned usage_id; bool data_ready; + struct iio_trigger *trigger; struct hid_sensor_hub_attribute_info poll; struct hid_sensor_hub_attribute_info report_state; struct hid_sensor_hub_attribute_info power_state; diff --git a/include/linux/padata.h b/include/linux/padata.h index 86292be..4386946 100644 --- a/include/linux/padata.h +++ b/include/linux/padata.h @@ -129,10 +129,9 @@ struct parallel_data { struct padata_serial_queue __percpu *squeue; atomic_t reorder_objects; atomic_t refcnt; + atomic_t seq_nr; struct padata_cpumask cpumask; spinlock_t lock ____cacheline_aligned; - spinlock_t seq_lock; - unsigned int seq_nr; unsigned int processed; struct timer_list timer; }; diff --git a/include/linux/slab.h b/include/linux/slab.h index c2bba24..1e2f4fe 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -388,10 +388,55 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags) /** * kmalloc - allocate memory * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kcalloc). + * @flags: the type of memory to allocate. * * kmalloc is the normal method of allocating memory * for objects smaller than page size in the kernel. + * + * The @flags argument may be one of: + * + * %GFP_USER - Allocate memory on behalf of user. May sleep. + * + * %GFP_KERNEL - Allocate normal kernel ram. May sleep. + * + * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. + * For example, use this inside interrupt handlers. + * + * %GFP_HIGHUSER - Allocate pages from high memory. + * + * %GFP_NOIO - Do not do any I/O at all while trying to get memory. + * + * %GFP_NOFS - Do not make any fs calls while trying to get memory. + * + * %GFP_NOWAIT - Allocation will not sleep. + * + * %GFP_THISNODE - Allocate node-local memory only. + * + * %GFP_DMA - Allocation suitable for DMA. + * Should only be used for kmalloc() caches. Otherwise, use a + * slab created with SLAB_DMA. + * + * Also it is possible to set different flags by OR'ing + * in one or more of the following additional @flags: + * + * %__GFP_COLD - Request cache-cold pages instead of + * trying to return cache-warm pages. + * + * %__GFP_HIGH - This allocation has high priority and may use emergency pools. + * + * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail + * (think twice before using). + * + * %__GFP_NORETRY - If memory is not immediately available, + * then give up at once. + * + * %__GFP_NOWARN - If allocation fails, don't issue any warnings. + * + * %__GFP_REPEAT - If allocation fails initially, try once more before failing. + * + * There are other flags available as well, but these are not intended + * for general use, and so are not documented here. For a full list of + * potential flags, always refer to linux/gfp.h. */ static __always_inline void *kmalloc(size_t size, gfp_t flags) { @@ -502,61 +547,6 @@ int cache_show(struct kmem_cache *s, struct seq_file *m); void print_slabinfo_header(struct seq_file *m); /** - * kmalloc - allocate memory - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. - * For example, use this inside interrupt handlers. - * - * %GFP_HIGHUSER - Allocate pages from high memory. - * - * %GFP_NOIO - Do not do any I/O at all while trying to get memory. - * - * %GFP_NOFS - Do not make any fs calls while trying to get memory. - * - * %GFP_NOWAIT - Allocation will not sleep. - * - * %GFP_THISNODE - Allocate node-local memory only. - * - * %GFP_DMA - Allocation suitable for DMA. - * Should only be used for kmalloc() caches. Otherwise, use a - * slab created with SLAB_DMA. - * - * Also it is possible to set different flags by OR'ing - * in one or more of the following additional @flags: - * - * %__GFP_COLD - Request cache-cold pages instead of - * trying to return cache-warm pages. - * - * %__GFP_HIGH - This allocation has high priority and may use emergency pools. - * - * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail - * (think twice before using). - * - * %__GFP_NORETRY - If memory is not immediately available, - * then give up at once. - * - * %__GFP_NOWARN - If allocation fails, don't issue any warnings. - * - * %__GFP_REPEAT - If allocation fails initially, try once more before failing. - * - * There are other flags available as well, but these are not intended - * for general use, and so are not documented here. For a full list of - * potential flags, always refer to linux/gfp.h. - * - * kmalloc is the normal method of allocating memory - * in the kernel. - */ -static __always_inline void *kmalloc(size_t size, gfp_t flags); - -/** * kmalloc_array - allocate memory for an array. * @n: number of elements. * @size: element size. diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index c98cfa4..fd44983 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -45,6 +45,7 @@ struct clk; #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D +#ifdef CONFIG_ARCH_TEGRA int tegra_powergate_is_powered(int id); int tegra_powergate_power_on(int id); int tegra_powergate_power_off(int id); @@ -52,5 +53,31 @@ int tegra_powergate_remove_clamping(int id); /* Must be called with clk disabled, and returns with clk enabled */ int tegra_powergate_sequence_power_up(int id, struct clk *clk); +#else +static inline int tegra_powergate_is_powered(int id) +{ + return -ENOSYS; +} + +static inline int tegra_powergate_power_on(int id) +{ + return -ENOSYS; +} + +static inline int tegra_powergate_power_off(int id) +{ + return -ENOSYS; +} + +static inline int tegra_powergate_remove_clamping(int id) +{ + return -ENOSYS; +} + +static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk) +{ + return -ENOSYS; +} +#endif #endif /* _MACH_TEGRA_POWERGATE_H_ */ diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 52594b2..d17a35c 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -372,7 +372,8 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ __data_size += (len) * sizeof(type); #undef __string -#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1) +#define __string(item, src) __dynamic_array(char, item, \ + strlen((src) ? (const char *)(src) : "(null)") + 1) #undef DECLARE_EVENT_CLASS #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ @@ -501,7 +502,7 @@ static inline notrace int ftrace_get_offsets_##call( \ #undef __assign_str #define __assign_str(dst, src) \ - strcpy(__get_str(dst), src); + strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)"); #undef TP_fast_assign #define TP_fast_assign(args...) args diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 4c62513..8b729c2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -90,6 +90,14 @@ static DEFINE_MUTEX(cgroup_mutex); static DEFINE_MUTEX(cgroup_root_mutex); /* + * cgroup destruction makes heavy use of work items and there can be a lot + * of concurrent destructions. Use a separate workqueue so that cgroup + * destruction work items don't end up filling up max_active of system_wq + * which may lead to deadlock. + */ +static struct workqueue_struct *cgroup_destroy_wq; + +/* * Generate an array of cgroup subsystem pointers. At boot time, this is * populated with the built in subsystems, and modular subsystems are * registered after that. The mutable section of this array is protected by @@ -191,6 +199,7 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp); static int cgroup_destroy_locked(struct cgroup *cgrp); static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], bool is_add); +static int cgroup_file_release(struct inode *inode, struct file *file); /** * cgroup_css - obtain a cgroup's css for the specified subsystem @@ -871,7 +880,7 @@ static void cgroup_free_rcu(struct rcu_head *head) struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head); INIT_WORK(&cgrp->destroy_work, cgroup_free_fn); - schedule_work(&cgrp->destroy_work); + queue_work(cgroup_destroy_wq, &cgrp->destroy_work); } static void cgroup_diput(struct dentry *dentry, struct inode *inode) @@ -2421,7 +2430,7 @@ static const struct file_operations cgroup_seqfile_operations = { .read = seq_read, .write = cgroup_file_write, .llseek = seq_lseek, - .release = single_release, + .release = cgroup_file_release, }; static int cgroup_file_open(struct inode *inode, struct file *file) @@ -2482,6 +2491,8 @@ static int cgroup_file_release(struct inode *inode, struct file *file) ret = cft->release(inode, file); if (css->ss) css_put(css); + if (file->f_op == &cgroup_seqfile_operations) + single_release(inode, file); return ret; } @@ -4249,7 +4260,7 @@ static void css_free_rcu_fn(struct rcu_head *rcu_head) * css_put(). dput() requires process context which we don't have. */ INIT_WORK(&css->destroy_work, css_free_work_fn); - schedule_work(&css->destroy_work); + queue_work(cgroup_destroy_wq, &css->destroy_work); } static void css_release(struct percpu_ref *ref) @@ -4539,7 +4550,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) container_of(ref, struct cgroup_subsys_state, refcnt); INIT_WORK(&css->destroy_work, css_killed_work_fn); - schedule_work(&css->destroy_work); + queue_work(cgroup_destroy_wq, &css->destroy_work); } /** @@ -5063,6 +5074,22 @@ out: return err; } +static int __init cgroup_wq_init(void) +{ + /* + * There isn't much point in executing destruction path in + * parallel. Good chunk is serialized with cgroup_mutex anyway. + * Use 1 for @max_active. + * + * We would prefer to do this in cgroup_init() above, but that + * is called before init_workqueues(): so leave this until after. + */ + cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1); + BUG_ON(!cgroup_destroy_wq); + return 0; +} +core_initcall(cgroup_wq_init); + /* * proc_cgroup_show() * - Print task's cgroup paths into seq_file, one line for each hierarchy diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6bf981e..4772034 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1033,8 +1033,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk, need_loop = task_has_mempolicy(tsk) || !nodes_intersects(*newmems, tsk->mems_allowed); - if (need_loop) + if (need_loop) { + local_irq_disable(); write_seqcount_begin(&tsk->mems_allowed_seq); + } nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems); mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1); @@ -1042,8 +1044,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk, mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2); tsk->mems_allowed = *newmems; - if (need_loop) + if (need_loop) { write_seqcount_end(&tsk->mems_allowed_seq); + local_irq_enable(); + } task_unlock(tsk); } diff --git a/kernel/extable.c b/kernel/extable.c index 832cb28..763faf0 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -61,7 +61,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) static inline int init_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_sinittext && - addr <= (unsigned long)_einittext) + addr < (unsigned long)_einittext) return 1; return 0; } @@ -69,7 +69,7 @@ static inline int init_kernel_text(unsigned long addr) int core_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_stext && - addr <= (unsigned long)_etext) + addr < (unsigned long)_etext) return 1; if (system_state == SYSTEM_BOOTING && diff --git a/kernel/padata.c b/kernel/padata.c index 07af2c9..2abd25d 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -46,6 +46,7 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) static int padata_cpu_hash(struct parallel_data *pd) { + unsigned int seq_nr; int cpu_index; /* @@ -53,10 +54,8 @@ static int padata_cpu_hash(struct parallel_data *pd) * seq_nr mod. number of cpus in use. */ - spin_lock(&pd->seq_lock); - cpu_index = pd->seq_nr % cpumask_weight(pd->cpumask.pcpu); - pd->seq_nr++; - spin_unlock(&pd->seq_lock); + seq_nr = atomic_inc_return(&pd->seq_nr); + cpu_index = seq_nr % cpumask_weight(pd->cpumask.pcpu); return padata_index_to_cpu(pd, cpu_index); } @@ -429,7 +428,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst, padata_init_pqueues(pd); padata_init_squeues(pd); setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd); - pd->seq_nr = 0; + atomic_set(&pd->seq_nr, -1); atomic_set(&pd->reorder_objects, 0); atomic_set(&pd->refcnt, 0); pd->pinst = pinst; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 22fa556..0e9f9ea 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -367,9 +367,6 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list, static int __register_ftrace_function(struct ftrace_ops *ops) { - if (unlikely(ftrace_disabled)) - return -ENODEV; - if (FTRACE_WARN_ON(ops == &global_ops)) return -EINVAL; @@ -428,9 +425,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) { int ret; - if (ftrace_disabled) - return -ENODEV; - if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) return -EBUSY; @@ -2088,10 +2082,15 @@ static void ftrace_startup_enable(int command) static int ftrace_startup(struct ftrace_ops *ops, int command) { bool hash_enable = true; + int ret; if (unlikely(ftrace_disabled)) return -ENODEV; + ret = __register_ftrace_function(ops); + if (ret) + return ret; + ftrace_start_up++; command |= FTRACE_UPDATE_CALLS; @@ -2113,12 +2112,17 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) return 0; } -static void ftrace_shutdown(struct ftrace_ops *ops, int command) +static int ftrace_shutdown(struct ftrace_ops *ops, int command) { bool hash_disable = true; + int ret; if (unlikely(ftrace_disabled)) - return; + return -ENODEV; + + ret = __unregister_ftrace_function(ops); + if (ret) + return ret; ftrace_start_up--; /* @@ -2153,9 +2157,10 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) } if (!command || !ftrace_enabled) - return; + return 0; ftrace_run_update_code(command); + return 0; } static void ftrace_startup_sysctl(void) @@ -3060,16 +3065,13 @@ static void __enable_ftrace_function_probe(void) if (i == FTRACE_FUNC_HASHSIZE) return; - ret = __register_ftrace_function(&trace_probe_ops); - if (!ret) - ret = ftrace_startup(&trace_probe_ops, 0); + ret = ftrace_startup(&trace_probe_ops, 0); ftrace_probe_registered = 1; } static void __disable_ftrace_function_probe(void) { - int ret; int i; if (!ftrace_probe_registered) @@ -3082,9 +3084,7 @@ static void __disable_ftrace_function_probe(void) } /* no more funcs left */ - ret = __unregister_ftrace_function(&trace_probe_ops); - if (!ret) - ftrace_shutdown(&trace_probe_ops, 0); + ftrace_shutdown(&trace_probe_ops, 0); ftrace_probe_registered = 0; } @@ -4366,12 +4366,15 @@ core_initcall(ftrace_nodyn_init); static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } static inline void ftrace_startup_enable(int command) { } /* Keep as macros so we do not need to define the commands */ -# define ftrace_startup(ops, command) \ - ({ \ - (ops)->flags |= FTRACE_OPS_FL_ENABLED; \ - 0; \ +# define ftrace_startup(ops, command) \ + ({ \ + int ___ret = __register_ftrace_function(ops); \ + if (!___ret) \ + (ops)->flags |= FTRACE_OPS_FL_ENABLED; \ + ___ret; \ }) -# define ftrace_shutdown(ops, command) do { } while (0) +# define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops) + # define ftrace_startup_sysctl() do { } while (0) # define ftrace_shutdown_sysctl() do { } while (0) @@ -4780,9 +4783,7 @@ int register_ftrace_function(struct ftrace_ops *ops) mutex_lock(&ftrace_lock); - ret = __register_ftrace_function(ops); - if (!ret) - ret = ftrace_startup(ops, 0); + ret = ftrace_startup(ops, 0); mutex_unlock(&ftrace_lock); @@ -4801,9 +4802,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops) int ret; mutex_lock(&ftrace_lock); - ret = __unregister_ftrace_function(ops); - if (!ret) - ftrace_shutdown(ops, 0); + ret = ftrace_shutdown(ops, 0); mutex_unlock(&ftrace_lock); return ret; @@ -4997,6 +4996,13 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state, return NOTIFY_DONE; } +/* Just a place holder for function graph */ +static struct ftrace_ops fgraph_ops __read_mostly = { + .func = ftrace_stub, + .flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL | + FTRACE_OPS_FL_RECURSION_SAFE, +}; + int register_ftrace_graph(trace_func_graph_ret_t retfunc, trace_func_graph_ent_t entryfunc) { @@ -5023,7 +5029,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, ftrace_graph_return = retfunc; ftrace_graph_entry = entryfunc; - ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); + ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET); out: mutex_unlock(&ftrace_lock); @@ -5040,7 +5046,7 @@ void unregister_ftrace_graph(void) ftrace_graph_active--; ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; ftrace_graph_entry = ftrace_graph_entry_stub; - ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET); + ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET); unregister_pm_notifier(&ftrace_suspend_notifier); unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 987293d..c66912be 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -305,6 +305,9 @@ static DEFINE_HASHTABLE(unbound_pool_hash, UNBOUND_POOL_HASH_ORDER); /* I: attributes used when instantiating standard unbound pools on demand */ static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS]; +/* I: attributes used when instantiating ordered pools on demand */ +static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS]; + struct workqueue_struct *system_wq __read_mostly; EXPORT_SYMBOL(system_wq); struct workqueue_struct *system_highpri_wq __read_mostly; @@ -518,14 +521,21 @@ static inline void debug_work_activate(struct work_struct *work) { } static inline void debug_work_deactivate(struct work_struct *work) { } #endif -/* allocate ID and assign it to @pool */ +/** + * worker_pool_assign_id - allocate ID and assing it to @pool + * @pool: the pool pointer of interest + * + * Returns 0 if ID in [0, WORK_OFFQ_POOL_NONE) is allocated and assigned + * successfully, -errno on failure. + */ static int worker_pool_assign_id(struct worker_pool *pool) { int ret; lockdep_assert_held(&wq_pool_mutex); - ret = idr_alloc(&worker_pool_idr, pool, 0, 0, GFP_KERNEL); + ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE, + GFP_KERNEL); if (ret >= 0) { pool->id = ret; return 0; @@ -1320,7 +1330,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, debug_work_activate(work); - /* if dying, only works from the same workqueue are allowed */ + /* if draining, only works from the same workqueue are allowed */ if (unlikely(wq->flags & __WQ_DRAINING) && WARN_ON_ONCE(!is_chained_work(wq))) return; @@ -1736,16 +1746,17 @@ static struct worker *create_worker(struct worker_pool *pool) if (IS_ERR(worker->task)) goto fail; + set_user_nice(worker->task, pool->attrs->nice); + + /* prevent userland from meddling with cpumask of workqueue workers */ + worker->task->flags |= PF_NO_SETAFFINITY; + /* * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any * online CPUs. It'll be re-applied when any of the CPUs come up. */ - set_user_nice(worker->task, pool->attrs->nice); set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask); - /* prevent userland from meddling with cpumask of workqueue workers */ - worker->task->flags |= PF_NO_SETAFFINITY; - /* * The caller is responsible for ensuring %POOL_DISASSOCIATED * remains stable across this function. See the comments above the @@ -4106,7 +4117,7 @@ out_unlock: static int alloc_and_link_pwqs(struct workqueue_struct *wq) { bool highpri = wq->flags & WQ_HIGHPRI; - int cpu; + int cpu, ret; if (!(wq->flags & WQ_UNBOUND)) { wq->cpu_pwqs = alloc_percpu(struct pool_workqueue); @@ -4126,6 +4137,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) mutex_unlock(&wq->mutex); } return 0; + } else if (wq->flags & __WQ_ORDERED) { + ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]); + /* there should only be single pwq for ordering guarantee */ + WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node || + wq->pwqs.prev != &wq->dfl_pwq->pwqs_node), + "ordering guarantee broken for workqueue %s\n", wq->name); + return ret; } else { return apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]); } @@ -5009,10 +5027,6 @@ static int __init init_workqueues(void) int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; int i, cpu; - /* make sure we have enough bits for OFFQ pool ID */ - BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT)) < - WORK_CPU_END * NR_STD_WORKER_POOLS); - WARN_ON(__alignof__(struct pool_workqueue) < __alignof__(long long)); pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); @@ -5051,13 +5065,23 @@ static int __init init_workqueues(void) } } - /* create default unbound wq attrs */ + /* create default unbound and ordered wq attrs */ for (i = 0; i < NR_STD_WORKER_POOLS; i++) { struct workqueue_attrs *attrs; BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); attrs->nice = std_nice[i]; unbound_std_wq_attrs[i] = attrs; + + /* + * An ordered wq should have only one pwq as ordering is + * guaranteed by max_active which is enforced by pwqs. + * Turn off NUMA so that dfl_pwq is used for all nodes. + */ + BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); + attrs->nice = std_nice[i]; + attrs->no_numa = true; + ordered_wq_attrs[i] = attrs; } system_wq = alloc_workqueue("events", 0, 0); diff --git a/lib/lockref.c b/lib/lockref.c index d2b123f..f07a40d 100644 --- a/lib/lockref.c +++ b/lib/lockref.c @@ -1,5 +1,6 @@ #include <linux/export.h> #include <linux/lockref.h> +#include <linux/mutex.h> #if USE_CMPXCHG_LOCKREF @@ -12,14 +13,6 @@ #endif /* - * Allow architectures to override the default cpu_relax() within CMPXCHG_LOOP. - * This is useful for architectures with an expensive cpu_relax(). - */ -#ifndef arch_mutex_cpu_relax -# define arch_mutex_cpu_relax() cpu_relax() -#endif - -/* * Note that the "cmpxchg()" reloads the "old" value for the * failure case. */ diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 77ca965..b4af4eb 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -13,9 +13,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/err.h> -#include <linux/sched.h> #include <linux/rbtree.h> -#include <linux/cred.h> #include <linux/key-type.h> #include <linux/digsig.h> @@ -23,19 +21,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; -#ifdef CONFIG_IMA_TRUSTED_KEYRING -static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { - ".evm", - ".module", - ".ima", -}; -#else static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { "_evm", "_module", "_ima", }; -#endif int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, const char *digest, int digestlen) @@ -45,7 +35,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, if (!keyring[id]) { keyring[id] = - request_key(&key_type_keyring, keyring_name[id], NULL); + request_key(&key_type_keyring, keyring_name[id], NULL); if (IS_ERR(keyring[id])) { int err = PTR_ERR(keyring[id]); pr_err("no %s keyring: %d\n", keyring_name[id], err); @@ -66,21 +56,3 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, return -EOPNOTSUPP; } - -int integrity_init_keyring(const unsigned int id) -{ - const struct cred *cred = current_cred(); - const struct user_struct *user = cred->user; - - keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), - KGIDT_INIT(0), cred, - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), - KEY_ALLOC_NOT_IN_QUOTA, user->uid_keyring); - if (!IS_ERR(keyring[id])) - set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); - else - pr_info("Can't allocate %s keyring (%ld)\n", - keyring_name[id], PTR_ERR(keyring[id])); - return 0; -} diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index dad8d4c..81a2797 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -123,11 +123,3 @@ config IMA_APPRAISE For more information on integrity appraisal refer to: <http://linux-ima.sourceforge.net> If unsure, say N. - -config IMA_TRUSTED_KEYRING - bool "Require all keys on the _ima keyring be signed" - depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING - default y - help - This option requires that all keys added to the _ima - keyring be signed by a key on the system trusted keyring. diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index bf03c6a..9636e17 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -26,7 +26,8 @@ #include "../integrity.h" -enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII }; +enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, + IMA_SHOW_ASCII }; enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; /* digest size for IMA, fits SHA1 or MD5 */ @@ -97,7 +98,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); -int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, +int ima_calc_field_array_hash(struct ima_field_data *field_data, + struct ima_template_desc *desc, int num_fields, struct ima_digest_data *hash); int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); void ima_add_violation(struct file *file, const unsigned char *filename, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 0e75408..8037484 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -94,6 +94,7 @@ int ima_store_template(struct ima_template_entry *entry, /* this function uses default algo */ hash.hdr.algo = HASH_ALGO_SHA1; result = ima_calc_field_array_hash(&entry->template_data[0], + entry->template_desc, num_fields, &hash.hdr); if (result < 0) { integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 46353ee..734e946 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -381,14 +381,3 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) } return result; } - -#ifdef CONFIG_IMA_TRUSTED_KEYRING -static int __init init_ima_keyring(void) -{ - int ret; - - ret = integrity_init_keyring(INTEGRITY_KEYRING_IMA); - return 0; -} -late_initcall(init_ima_keyring); -#endif diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 676e029..fdf60de 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -140,6 +140,7 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) * Calculate the hash of template data */ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, + struct ima_template_desc *td, int num_fields, struct ima_digest_data *hash, struct crypto_shash *tfm) @@ -160,9 +161,13 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, return rc; for (i = 0; i < num_fields; i++) { - rc = crypto_shash_update(&desc.shash, - (const u8 *) &field_data[i].len, - sizeof(field_data[i].len)); + if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { + rc = crypto_shash_update(&desc.shash, + (const u8 *) &field_data[i].len, + sizeof(field_data[i].len)); + if (rc) + break; + } rc = crypto_shash_update(&desc.shash, field_data[i].data, field_data[i].len); if (rc) @@ -175,7 +180,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, return rc; } -int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, +int ima_calc_field_array_hash(struct ima_field_data *field_data, + struct ima_template_desc *desc, int num_fields, struct ima_digest_data *hash) { struct crypto_shash *tfm; @@ -185,7 +191,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, if (IS_ERR(tfm)) return PTR_ERR(tfm); - rc = ima_calc_field_array_hash_tfm(field_data, num_fields, hash, tfm); + rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields, + hash, tfm); ima_free_tfm(tfm); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index d47a7c8..db01125 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -120,6 +120,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) struct ima_template_entry *e; int namelen; u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; + bool is_ima_template = false; int i; /* get entry */ @@ -145,14 +146,21 @@ static int ima_measurements_show(struct seq_file *m, void *v) ima_putc(m, e->template_desc->name, namelen); /* 5th: template length (except for 'ima' template) */ - if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) + if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) + is_ima_template = true; + + if (!is_ima_template) ima_putc(m, &e->template_data_len, sizeof(e->template_data_len)); /* 6th: template specific data */ for (i = 0; i < e->template_desc->num_fields; i++) { - e->template_desc->fields[i]->field_show(m, IMA_SHOW_BINARY, - &e->template_data[i]); + enum ima_show_type show = IMA_SHOW_BINARY; + struct ima_template_field *field = e->template_desc->fields[i]; + + if (is_ima_template && strcmp(field->field_id, "d") == 0) + show = IMA_SHOW_BINARY_NO_FIELD_LEN; + field->field_show(m, show, &e->template_data[i]); } return 0; } diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 4e5da99..913e192 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -90,7 +90,7 @@ static struct ima_template_field *lookup_template_field(const char *field_id) return NULL; } -static int template_fmt_size(char *template_fmt) +static int template_fmt_size(const char *template_fmt) { char c; int template_fmt_len = strlen(template_fmt); @@ -106,23 +106,28 @@ static int template_fmt_size(char *template_fmt) return j + 1; } -static int template_desc_init_fields(char *template_fmt, +static int template_desc_init_fields(const char *template_fmt, struct ima_template_field ***fields, int *num_fields) { - char *c, *template_fmt_ptr = template_fmt; + char *c, *template_fmt_copy; int template_num_fields = template_fmt_size(template_fmt); int i, result = 0; if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) return -EINVAL; + /* copying is needed as strsep() modifies the original buffer */ + template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL); + if (template_fmt_copy == NULL) + return -ENOMEM; + *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); if (*fields == NULL) { result = -ENOMEM; goto out; } - for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && + for (i = 0; (c = strsep(&template_fmt_copy, "|")) != NULL && i < template_num_fields; i++) { struct ima_template_field *f = lookup_template_field(c); @@ -133,10 +138,12 @@ static int template_desc_init_fields(char *template_fmt, (*fields)[i] = f; } *num_fields = i; - return 0; out: - kfree(*fields); - *fields = NULL; + if (result < 0) { + kfree(*fields); + *fields = NULL; + } + kfree(template_fmt_copy); return result; } diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 6d66ad6..c38adcc 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -109,9 +109,12 @@ static void ima_show_template_data_binary(struct seq_file *m, enum data_formats datafmt, struct ima_field_data *field_data) { - ima_putc(m, &field_data->len, sizeof(u32)); + if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) + ima_putc(m, &field_data->len, sizeof(u32)); + if (!field_data->len) return; + ima_putc(m, field_data->data, field_data->len); } @@ -125,6 +128,7 @@ static void ima_show_template_field_data(struct seq_file *m, ima_show_template_data_ascii(m, show, datafmt, field_data); break; case IMA_SHOW_BINARY: + case IMA_SHOW_BINARY_NO_FIELD_LEN: ima_show_template_data_binary(m, show, datafmt, field_data); break; default: diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index b9e7c13..2fb5e53 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -137,19 +137,12 @@ static inline int integrity_digsig_verify(const unsigned int id, #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS int asymmetric_verify(struct key *keyring, const char *sig, int siglen, const char *data, int datalen); - -int integrity_init_keyring(const unsigned int id); #else static inline int asymmetric_verify(struct key *keyring, const char *sig, int siglen, const char *data, int datalen) { return -EOPNOTSUPP; } - -static int integrity_init_keyring(const unsigned int id) -{ - return 0; -} #endif #ifdef CONFIG_INTEGRITY_AUDIT diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index d322689..9048777 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -434,17 +434,14 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) return; index = s->packet_index; + /* this module generate empty packet for 'no data' */ syt = calculate_syt(s, cycle); - if (!(s->flags & CIP_BLOCKING)) { + if (!(s->flags & CIP_BLOCKING)) data_blocks = calculate_data_blocks(s); - } else { - if (syt != 0xffff) { - data_blocks = s->syt_interval; - } else { - data_blocks = 0; - syt = 0xffffff; - } - } + else if (syt != 0xffff) + data_blocks = s->syt_interval; + else + data_blocks = 0; buffer = s->buffer.packets[index].buffer; buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 77db694..7aa9870 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -698,7 +698,6 @@ struct hda_bus { unsigned int in_reset:1; /* during reset operation */ unsigned int power_keep_link_on:1; /* don't power off HDA link */ unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ - unsigned int avoid_link_reset:1; /* don't reset link at runtime PM */ int primary_dig_out_type; /* primary digital out PCM type */ }; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 3067ed4..c4671d0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -2506,12 +2506,8 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins, for (i = 0; i < num_pins; i++) { hda_nid_t pin = pins[i]; - if (pin == spec->hp_mic_pin) { - int ret = create_hp_mic_jack_mode(codec, pin); - if (ret < 0) - return ret; + if (pin == spec->hp_mic_pin) continue; - } if (get_out_jack_num_items(codec, pin) > 1) { struct snd_kcontrol_new *knew; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; @@ -2764,7 +2760,7 @@ static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, val &= ~(AC_PINCTL_VREFEN | PIN_HP); val |= get_vref_idx(vref_caps, idx) | PIN_IN; } else - val = snd_hda_get_default_vref(codec, nid); + val = snd_hda_get_default_vref(codec, nid) | PIN_IN; } snd_hda_set_pin_ctl_cache(codec, nid, val); call_hp_automute(codec, NULL); @@ -2784,9 +2780,6 @@ static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) struct hda_gen_spec *spec = codec->spec; struct snd_kcontrol_new *knew; - if (get_out_jack_num_items(codec, pin) <= 1 && - get_in_jack_num_items(codec, pin) <= 1) - return 0; /* no need */ knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", &hp_mic_jack_mode_enum); if (!knew) @@ -2815,6 +2808,42 @@ static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) return 0; } +/* return true if either a volume or a mute amp is found for the given + * aamix path; the amp has to be either in the mixer node or its direct leaf + */ +static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid, + hda_nid_t pin, unsigned int *mix_val, + unsigned int *mute_val) +{ + int idx, num_conns; + const hda_nid_t *list; + hda_nid_t nid; + + idx = snd_hda_get_conn_index(codec, mix_nid, pin, true); + if (idx < 0) + return false; + + *mix_val = *mute_val = 0; + if (nid_has_volume(codec, mix_nid, HDA_INPUT)) + *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + if (nid_has_mute(codec, mix_nid, HDA_INPUT)) + *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + if (*mix_val && *mute_val) + return true; + + /* check leaf node */ + num_conns = snd_hda_get_conn_list(codec, mix_nid, &list); + if (num_conns < idx) + return false; + nid = list[idx]; + if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT)) + *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT)) + *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + + return *mix_val || *mute_val; +} + /* create input playback/capture controls for the given pin */ static int new_analog_input(struct hda_codec *codec, int input_idx, hda_nid_t pin, const char *ctlname, int ctlidx, @@ -2822,12 +2851,11 @@ static int new_analog_input(struct hda_codec *codec, int input_idx, { struct hda_gen_spec *spec = codec->spec; struct nid_path *path; - unsigned int val; + unsigned int mix_val, mute_val; int err, idx; - if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && - !nid_has_mute(codec, mix_nid, HDA_INPUT)) - return 0; /* no need for analog loopback */ + if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val)) + return 0; path = snd_hda_add_new_path(codec, pin, mix_nid, 0); if (!path) @@ -2836,20 +2864,18 @@ static int new_analog_input(struct hda_codec *codec, int input_idx, spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); idx = path->idx[path->depth - 1]; - if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { - val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); - err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); + if (mix_val) { + err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val); if (err < 0) return err; - path->ctls[NID_PATH_VOL_CTL] = val; + path->ctls[NID_PATH_VOL_CTL] = mix_val; } - if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { - val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); - err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); + if (mute_val) { + err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val); if (err < 0) return err; - path->ctls[NID_PATH_MUTE_CTL] = val; + path->ctls[NID_PATH_MUTE_CTL] = mute_val; } path->active = true; @@ -4383,6 +4409,17 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (err < 0) return err; + /* create "Headphone Mic Jack Mode" if no input selection is + * available (or user specifies add_jack_modes hint) + */ + if (spec->hp_mic_pin && + (spec->auto_mic || spec->input_mux.num_items == 1 || + spec->add_jack_modes)) { + err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin); + if (err < 0) + return err; + } + if (spec->add_jack_modes) { if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { err = create_out_jack_modes(codec, cfg->line_outs, diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7a09404..c6d2301 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2994,8 +2994,7 @@ static int azx_runtime_suspend(struct device *dev) STATESTS_INT_MASK); azx_stop_chip(chip); - if (!chip->bus->avoid_link_reset) - azx_enter_link_reset(chip); + azx_enter_link_reset(chip); azx_clear_irq_pending(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) hda_display_power(false); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c205bb1..1f2717f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3244,9 +3244,29 @@ enum { #if IS_ENABLED(CONFIG_THINKPAD_ACPI) #include <linux/thinkpad_acpi.h> +#include <acpi/acpi.h> static int (*led_set_func)(int, bool); +static acpi_status acpi_check_cb(acpi_handle handle, u32 lvl, void *context, + void **rv) +{ + bool *found = context; + *found = true; + return AE_OK; +} + +static bool is_thinkpad(struct hda_codec *codec) +{ + bool found = false; + if (codec->subsystem_id >> 16 != 0x17aa) + return false; + if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found) + return true; + found = false; + return ACPI_SUCCESS(acpi_get_devices("IBM0068", acpi_check_cb, &found, NULL)) && found; +} + static void update_tpacpi_mute_led(void *private_data, int enabled) { struct hda_codec *codec = private_data; @@ -3279,6 +3299,8 @@ static void cxt_fixup_thinkpad_acpi(struct hda_codec *codec, bool removefunc = false; if (action == HDA_FIXUP_ACT_PROBE) { + if (!is_thinkpad(codec)) + return; if (!led_set_func) led_set_func = symbol_request(tpacpi_led_set); if (!led_set_func) { @@ -3494,6 +3516,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), {} diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5e42059..c770bdb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1782,6 +1782,8 @@ enum { ALC889_FIXUP_IMAC91_VREF, ALC882_FIXUP_INV_DMIC, ALC882_FIXUP_NO_PRIMARY_HP, + ALC887_FIXUP_ASUS_BASS, + ALC887_FIXUP_BASS_CHMAP, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -1915,6 +1917,9 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, } } +static void alc_fixup_bass_chmap(struct hda_codec *codec, + const struct hda_fixup *fix, int action); + static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = HDA_FIXUP_PINS, @@ -2105,6 +2110,19 @@ static const struct hda_fixup alc882_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc882_fixup_no_primary_hp, }, + [ALC887_FIXUP_ASUS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x99130130}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC887_FIXUP_BASS_CHMAP, + }, + [ALC887_FIXUP_BASS_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2138,6 +2156,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), + SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), @@ -3798,6 +3817,7 @@ enum { ALC271_FIXUP_HP_GATE_MIC_JACK, ALC269_FIXUP_ACER_AC700, ALC269_FIXUP_LIMIT_INT_MIC_BOOST, + ALC269VB_FIXUP_ASUS_ZENBOOK, ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED, ALC269VB_FIXUP_ORDISSIMO_EVE2, ALC283_FIXUP_CHROME_BOOK, @@ -4075,6 +4095,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, + [ALC269VB_FIXUP_ASUS_ZENBOOK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269VB_FIXUP_DMIC, + }, [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_limit_int_mic_boost, @@ -4189,8 +4215,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), - SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC), + SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), + SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), @@ -4715,7 +4741,7 @@ static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = { }; /* override the 2.1 chmap */ -static void alc662_fixup_bass_chmap(struct hda_codec *codec, +static void alc_fixup_bass_chmap(struct hda_codec *codec, const struct hda_fixup *fix, int action) { if (action == HDA_FIXUP_ACT_BUILD) { @@ -4923,7 +4949,7 @@ static const struct hda_fixup alc662_fixups[] = { }, [ALC662_FIXUP_BASS_CHMAP] = { .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_bass_chmap, + .v.func = alc_fixup_bass_chmap, .chained = true, .chain_id = ALC662_FIXUP_ASUS_MODE4 }, @@ -4936,7 +4962,7 @@ static const struct hda_fixup alc662_fixups[] = { }, [ALC662_FIXUP_BASS_1A_CHMAP] = { .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_bass_chmap, + .v.func = alc_fixup_bass_chmap, .chained = true, .chain_id = ALC662_FIXUP_BASS_1A, }, @@ -5118,6 +5144,7 @@ static int patch_alc662(struct hda_codec *codec) case 0x10ec0272: case 0x10ec0663: case 0x10ec0665: + case 0x10ec0668: set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); break; case 0x10ec0273: @@ -5175,6 +5202,7 @@ static int patch_alc680(struct hda_codec *codec) */ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, + { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 }, { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 }, { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 }, { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d2cc004..088a5af 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2094,7 +2094,8 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ - codec->bus->avoid_link_reset = 1; + /* resetting controller clears GPIO, so we need to keep on */ + codec->bus->power_keep_link_on = 1; } } diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e48d38a..e634eb7 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -25,7 +25,7 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS + depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index b9ba0fc..83aabea2 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -636,8 +636,22 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, if (usb_pipein(ep->pipe) || snd_usb_endpoint_implicit_feedback_sink(ep)) { + urb_packs = packs_per_ms; + /* + * Wireless devices can poll at a max rate of once per 4ms. + * For dataintervals less than 5, increase the packet count to + * allow the host controller to use bursting to fill in the + * gaps. + */ + if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { + int interval = ep->datainterval; + while (interval < 5) { + urb_packs <<= 1; + ++interval; + } + } /* make capture URBs <= 1 ms and smaller than a period */ - urb_packs = min(max_packs_per_urb, packs_per_ms); + urb_packs = min(max_packs_per_urb, urb_packs); while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) urb_packs >>= 1; ep->nurbs = MAX_URBS; diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 index 4178eff..7b3646a 100644 --- a/tools/power/cpupower/man/cpupower-idle-info.1 +++ b/tools/power/cpupower/man/cpupower-idle-info.1 @@ -87,4 +87,5 @@ Thomas Renninger <trenn@suse.de> .fi .SH "SEE ALSO" .LP -cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1) +cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1), +cpupower\-idle\-set(1) diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1 new file mode 100644 index 0000000..6b16072 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-idle-set.1 @@ -0,0 +1,71 @@ +.TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" +.SH "NAME" +.LP +cpupower idle\-set \- Utility to set cpu idle state specific kernel options +.SH "SYNTAX" +.LP +cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] +.SH "DESCRIPTION" +.LP +The cpupower idle\-set subcommand allows to set cpu idle, also called cpu +sleep state, specific options offered by the kernel. One example is disabling +sleep states. This can be handy for power vs performance tuning. +.SH "OPTIONS" +.LP +.TP +\fB\-d\fR \fB\-\-disable\fR +Disable a specific processor sleep state. +.TP +\fB\-e\fR \fB\-\-enable\fR +Enable a specific processor sleep state. + +.SH "REMARKS" +.LP +Cpuidle Governors Policy on Disabling Sleep States + +.RS 4 +Depending on the used cpuidle governor, implementing the kernel policy +how to choose sleep states, subsequent sleep states on this core, might get +disabled as well. + +There are two cpuidle governors ladder and menu. While the ladder +governor is always available, if CONFIG_CPU_IDLE is selected, the +menu governor additionally requires CONFIG_NO_HZ. + +The behavior and the effect of the disable variable depends on the +implementation of a particular governor. In the ladder governor, for +example, it is not coherent, i.e. if one is disabling a light state, +then all deeper states are disabled as well. Likewise, if one enables a +deep state but a lighter state still is disabled, then this has no effect. +.RE +.LP +Disabling the Lightest Sleep State may not have any Affect + +.RS 4 +If criteria are not met to enter deeper sleep states and the lightest sleep +state is chosen when idle, the kernel may still enter this sleep state, +irrespective of whether it is disabled or not. This is also reflected in +the usage count of the disabled sleep state when using the cpupower idle-info +command. +.RE +.LP +Selecting specific CPU Cores + +.RS 4 +By default processor sleep states of all CPU cores are set. Please refer +to the cpupower(1) manpage in the \-\-cpu option section how to disable +C-states of specific cores. +.RE +.SH "FILES" +.nf +\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP +\fI/sys/devices/system/cpu/cpuidle/*\fP +.fi +.SH "AUTHORS" +.nf +Thomas Renninger <trenn@suse.de> +.fi +.SH "SEE ALSO" +.LP +cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1), +cpupower\-idle\-info(1) diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 5cdc600..851c7a1 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -278,7 +278,7 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu, int sysfs_is_idlestate_disabled(unsigned int cpu, unsigned int idlestate) { - if (sysfs_get_idlestate_count(cpu) < idlestate) + if (sysfs_get_idlestate_count(cpu) <= idlestate) return -1; if (!sysfs_idlestate_file_exists(cpu, idlestate, @@ -303,7 +303,7 @@ int sysfs_idlestate_disable(unsigned int cpu, char value[SYSFS_PATH_MAX]; int bytes_written; - if (sysfs_get_idlestate_count(cpu) < idlestate) + if (sysfs_get_idlestate_count(cpu) <= idlestate) return -1; if (!sysfs_idlestate_file_exists(cpu, idlestate, |