--- /dev/null
+_DSD Device Properties Related to GPIO
+--------------------------------------
+
+With the release of ACPI 5.1 and the _DSD configuration objecte names
+can finally be given to GPIOs (and other things as well) returned by
+_CRS. Previously, we were only able to use an integer index to find
+the corresponding GPIO, which is pretty error prone (it depends on
+the _CRS output ordering, for example).
+
+With _DSD we can now query GPIOs using a name instead of an integer
+index, like the ASL example below shows:
+
+ // Bluetooth device with reset and shutdown GPIOs
+ Device (BTH)
+ {
+ Name (_HID, ...)
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {15}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
+ })
+
+ Name (_DSD, Package ()
+ {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
+ Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
+ }
+ })
+ }
+
+The format of the supported GPIO property is:
+
+ Package () { "name", Package () { ref, index, pin, active_low }}
+
+ ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
+ typically this is the device itself (BTH in our case).
+ index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
+ pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
+ active_low - If 1 the GPIO is marked as active_low.
+
+Since ACPI GpioIo() resource does not have a field saying whether it is
+active low or high, the "active_low" argument can be used here. Setting
+it to 1 marks the GPIO as active low.
+
+In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
+resource, second pin in that resource with the GPIO number of 31.
+
+ACPI GPIO Mappings Provided by Drivers
+--------------------------------------
+
+There are systems in which the ACPI tables do not contain _DSD but provide _CRS
+with GpioIo()/GpioInt() resources and device drivers still need to work with
+them.
+
+In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
+available to the driver can be used to identify the device and that is supposed
+to be sufficient to determine the meaning and purpose of all of the GPIO lines
+listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
+the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
+once it has identified the device. Having done that, it can simply assign names
+to the GPIO lines it is going to use and provide the GPIO subsystem with a
+mapping between those names and the ACPI GPIO resources corresponding to them.
+
+To do that, the driver needs to define a mapping table as a NULL-terminated
+array of struct acpi_gpio_mapping objects that each contain a name, a pointer
+to an array of line data (struct acpi_gpio_params) objects and the size of that
+array. Each struct acpi_gpio_params object consists of three fields,
+crs_entry_index, line_index, active_low, representing the index of the target
+GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
+line in that resource starting from zero, and the active-low flag for that line,
+respectively, in analogy with the _DSD GPIO property format specified above.
+
+For the example Bluetooth device discussed previously the data structures in
+question would look like this:
+
+static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
+static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
+
+static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
+ { "reset-gpio", &reset_gpio, 1 },
+ { "shutdown-gpio", &shutdown_gpio, 1 },
+ { },
+};
+
+Next, the mapping table needs to be passed as the second argument to
+acpi_dev_add_driver_gpios() that will register it with the ACPI device object
+pointed to by its first argument. That should be done in the driver's .probe()
+routine. On removal, the driver should unregister its GPIO mapping table by
+calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
+table was previously registered.
Example:
interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
-A device node may contain either "interrupts" or "interrupts-extended", but not
-both. If both properties are present, then the operating system should log an
-error and use only the data in "interrupts".
-
2) Interrupt controller nodes
-----------------------------
Open Firmware Recommended Practice: Interrupt Mapping
http://www.openfirmware.org/1275/practice/imap/imap0_9d.pdf
+
+Additionally to the properties specified in the above standards a host bridge
+driver implementation may support the following properties:
+
+- linux,pci-domain:
+ If present this property assigns a fixed PCI domain number to a host bridge,
+ otherwise an unstable (across boots) unique number will be assigned.
+ It is required to either not set this property at all or set it for all
+ host bridges in the system, otherwise potentially conflicting domain numbers
+ may be assigned to root buses behind different host bridges. The domain
+ number for each host bridge in the system must be unique.
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-TZ1090-PDC's pin configuration nodes act as a container for an abitrary number
+TZ1090-PDC's pin configuration nodes act as a container for an arbitrary number
of subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-TZ1090's pin configuration nodes act as a container for an abitrary number of
+TZ1090's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Lantiq's pin configuration nodes act as a container for an abitrary number of
+Lantiq's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those group(s), and two pin configuration parameters:
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Lantiq's pin configuration nodes act as a container for an abitrary number of
+Lantiq's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those group(s), and two pin configuration parameters:
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Tegra's pin configuration nodes act as a container for an abitrary number of
+Tegra's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
Please refer to pinctrl-bindings.txt in this directory for details of the common
pinctrl bindings used by client devices.
-SiRFprimaII's pinmux nodes act as a container for an abitrary number of subnodes.
+SiRFprimaII's pinmux nodes act as a container for an arbitrary number of subnodes.
Each of these subnodes represents some desired configuration for a group of pins.
Required subnode-properties:
Please refer to pinctrl-bindings.txt in this directory for details of the common
pinctrl bindings used by client devices.
-SPEAr's pinmux nodes act as a container for an abitrary number of subnodes. Each
+SPEAr's pinmux nodes act as a container for an arbitrary number of subnodes. Each
of these subnodes represents muxing for a pin, a group, or a list of pins or
groups.
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-The pin configuration nodes act as a container for an abitrary number of
+The pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-The pin configuration nodes act as a container for an abitrary number of
+The pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's pin configuration nodes act as a container for an arbitrary number of
subnodes. Each of these subnodes represents some desired configuration for a
pin, a group, or a list of pins or groups. This configuration can include the
mux function to select on those pin(s)/group(s), and various pin configuration
chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd.
cirrus Cirrus Logic, Inc.
+cnm Chips&Media, Inc.
cortina Cortina Systems, Inc.
crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
mediatek MediaTek Inc.
micrel Micrel Inc.
microchip Microchip Technology Inc.
+micron Micron Technology Inc.
mitsubishi Mitsubishi Electric Corporation
mosaixtech Mosaix Technologies, Inc.
moxa Moxa
ricoh Ricoh Co. Ltd.
rockchip Fuzhou Rockchip Electronics Co., Ltd
samsung Samsung Semiconductor
+sandisk Sandisk Corporation
sbs Smart Battery System
schindler Schindler
seagate Seagate Technology PLC
sirf SiRF Technology, Inc.
sitronix Sitronix Technology Corporation
smsc Standard Microsystems Corporation
-snps Synopsys, Inc.
+snps Synopsys, Inc.
solidrun SolidRun
sony Sony Corporation
spansion Spansion Inc.
At mount time, the two directories given as mount options "lowerdir" and
"upperdir" are combined into a merged directory:
- mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper,\
+ mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\
workdir=/work /merged
The "workdir" needs to be an empty directory on the same filesystem
capabilities.
+GPIOs and ACPI
+==============
+
+On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
+the _CRS configuration objects of devices. Those resources do not provide
+connection IDs (names) for GPIOs, so it is necessary to use an additional
+mechanism for this purpose.
+
+Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
+which, among other things, may be used to provide connection IDs for specific
+GPIOs described by the GpioIo()/GpioInt() resources in _CRS. If that is the
+case, it will be handled by the GPIO subsystem automatically. However, if the
+_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
+connection IDs need to be provided by device drivers.
+
+For details refer to Documentation/acpi/gpio-properties.txt
+
+
Interacting With the Legacy GPIO Subsystem
==========================================
Many kernel subsystems still handle GPIOs using the legacy integer-based
This option is implemented only for transmit timestamps. There, the
timestamp is always looped along with a struct sock_extended_err.
- The option modifies field ee_info to pass an id that is unique
+ The option modifies field ee_data to pass an id that is unique
among all possibly concurrently outstanding timestamp requests for
that socket. In practice, it is a monotonically increasing u32
(that wraps).
F: net/ax25/
AZ6007 DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: fs/btrfs/
BTTV VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: include/media/cx2341x*
CX88 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
EDAC-CORE
M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Supported
F: drivers/edac/e7xxx_edac.c
EDAC-GHES
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I7300
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7300_edac.c
EDAC-I7CORE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/net/ethernet/ibm/ehea/
EM28XX VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/radio-maxiradio*
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
P: LinuxTV.org Project
L: linux-media@vger.kernel.org
W: http://linuxtv.org
F: include/scsi/osd_*
F: fs/exofs/
-OVERLAYFS FILESYSTEM
+OVERLAY FILESYSTEM
M: Miklos Szeredi <miklos@szeredi.hu>
-L: linux-fsdevel@vger.kernel.org
+L: linux-unionfs@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
S: Supported
-F: fs/overlayfs/*
+F: fs/overlayfs/
F: Documentation/filesystems/overlayfs.txt
P54 WIRELESS DRIVER
F: drivers/media/i2c/saa6588*
SAA7134 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/si4713/radio-usb-si4713.c
SIANO DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/leds/leds-net48xx.c
SOFTLOGIC 6x10 MPEG CODEC
-M: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
+M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
+M: Andrey Utkin <andrey.utkin@corp.bluecherry.net>
+M: Andrey Utkin <andrey.krieger.utkin@gmail.com>
L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/pci/solo6x10/
F: drivers/media/i2c/tda9840*
TEA5761 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/tuners/tea5761.*
TEA5767 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: mm/shmem.c
TM6000 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: arch/x86/kernel/cpu/mcheck/*
XC2028/3028 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION =
NAME = Diseased Newt
# *DOCUMENTATION*
num-cs = <1>;
};
+&usbdrd_dwc3 {
+ dr_mode = "host";
+};
+
#include "cros-ec-keyboard.dtsi"
#size-cells = <1>;
ranges;
- dwc3 {
+ usbdrd_dwc3: dwc3 {
compatible = "synopsys,dwc3";
reg = <0x12000000 0x10000>;
interrupts = <0 72 0>;
clocks = <&cpg_clocks R8A7740_CLK_S>,
<&cpg_clocks R8A7740_CLK_S>, <&sub_clk>,
<&cpg_clocks R8A7740_CLK_B>,
- <&sub_clk>, <&sub_clk>,
+ <&cpg_clocks R8A7740_CLK_HPP>, <&sub_clk>,
<&cpg_clocks R8A7740_CLK_B>;
#clock-cells = <1>;
renesas,clock-indices = <
#clock-cells = <0>;
clock-output-names = "sd2";
};
- sd3_clk: sd3_clk@e615007c {
+ sd3_clk: sd3_clk@e615026c {
compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock";
- reg = <0 0xe615007c 0 4>;
+ reg = <0 0xe615026c 0 4>;
clocks = <&pll1_div2_clk>;
#clock-cells = <0>;
clock-output-names = "sd3";
clocks = <&ahb1_gates 6>;
resets = <&ahb1_rst 6>;
#dma-cells = <1>;
+
+ /* DMA controller requires AHB1 clocked from PLL6 */
+ assigned-clocks = <&ahb1_mux>;
+ assigned-clock-parents = <&pll6>;
};
mmc0: mmc@01c0f000 {
aliases {
rtc0 = "/i2c@7000d000/tps65913@58";
rtc1 = "/rtc@7000e000";
+ serial0 = &uartd;
};
memory {
linux,initrd-end = <0x82800000>;
};
+ aliases {
+ serial0 = &uartd;
+ };
+
firmware {
trusted-foundations {
compatible = "tlm,trusted-foundations";
regulator-name = "vddio-sdmmc3";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
};
ldousb {
sdhci@78000400 {
status = "okay";
bus-width = <4>;
- vmmc-supply = <&vddio_sdmmc3>;
+ vqmmc-supply = <&vddio_sdmmc3>;
cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
power-gpios = <&gpio TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
};
sdhci@78000600 {
status = "okay";
bus-width = <8>;
- vmmc-supply = <&vdd_1v8>;
non-removable;
};
linux,initrd-end = <0x82800000>;
};
+ aliases {
+ serial0 = &uartd;
+ };
+
firmware {
trusted-foundations {
compatible = "tlm,trusted-foundations";
sdhci@78000600 {
status = "okay";
bus-width = <8>;
- vmmc-supply = <&vdd_1v8>;
non-removable;
};
compatible = "nvidia,tegra114";
interrupt-parent = <&gic>;
- aliases {
- serial0 = &uarta;
- serial1 = &uartb;
- serial2 = &uartc;
- serial3 = &uartd;
- };
-
host1x@50000000 {
compatible = "nvidia,tegra114-host1x", "simple-bus";
reg = <0x50000000 0x00028000>;
aliases {
rtc0 = "/i2c@0,7000d000/pmic@40";
rtc1 = "/rtc@0,7000e000";
+ serial0 = &uartd;
};
memory {
aliases {
rtc0 = "/i2c@0,7000d000/pmic@40";
rtc1 = "/rtc@0,7000e000";
+ serial0 = &uarta;
};
memory {
aliases {
rtc0 = "/i2c@0,7000d000/pmic@40";
rtc1 = "/rtc@0,7000e000";
+ serial0 = &uarta;
};
memory {
* the APB DMA based serial driver, the comptible is
* "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart".
*/
- serial@0,70006000 {
+ uarta: serial@0,70006000 {
compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
reg = <0x0 0x70006000 0x0 0x40>;
reg-shift = <2>;
status = "disabled";
};
- serial@0,70006040 {
+ uartb: serial@0,70006040 {
compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
reg = <0x0 0x70006040 0x0 0x40>;
reg-shift = <2>;
status = "disabled";
};
- serial@0,70006200 {
+ uartc: serial@0,70006200 {
compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
reg = <0x0 0x70006200 0x0 0x40>;
reg-shift = <2>;
status = "disabled";
};
- serial@0,70006300 {
+ uartd: serial@0,70006300 {
compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
reg = <0x0 0x70006300 0x0 0x40>;
reg-shift = <2>;
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc1 = "/rtc@7000e000";
+ serial0 = &uartd;
};
memory {
model = "Toradex Colibri T20 512MB on Iris";
compatible = "toradex,iris", "toradex,colibri_t20-512", "nvidia,tegra20";
+ aliases {
+ serial0 = &uarta;
+ serial1 = &uartd;
+ };
+
host1x@50000000 {
hdmi@54280000 {
status = "okay";
model = "Avionic Design Medcom-Wide board";
compatible = "ad,medcom-wide", "ad,tamonten", "nvidia,tegra20";
+ aliases {
+ serial0 = &uartd;
+ };
+
pwm@7000a000 {
status = "okay";
};
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc1 = "/rtc@7000e000";
+ serial0 = &uarta;
+ serial1 = &uartc;
};
memory {
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc1 = "/rtc@7000e000";
+ serial0 = &uartd;
};
memory {
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc1 = "/rtc@7000e000";
+ serial0 = &uartd;
};
memory {
aliases {
rtc0 = "/i2c@7000c500/rtc@56";
rtc1 = "/rtc@7000e000";
+ serial0 = &uarta;
};
memory {
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc1 = "/rtc@7000e000";
+ serial0 = &uartd;
};
memory {
aliases {
rtc0 = "/i2c@7000d000/max8907@3c";
rtc1 = "/rtc@7000e000";
+ serial0 = &uarta;
};
memory {
compatible = "nvidia,tegra20";
interrupt-parent = <&intc>;
- aliases {
- serial0 = &uarta;
- serial1 = &uartb;
- serial2 = &uartc;
- serial3 = &uartd;
- serial4 = &uarte;
- };
-
host1x@50000000 {
compatible = "nvidia,tegra20-host1x", "simple-bus";
reg = <0x50000000 0x00024000>;
rtc0 = "/i2c@7000c000/rtc@68";
rtc1 = "/i2c@7000d000/tps65911@2d";
rtc2 = "/rtc@7000e000";
+ serial0 = &uarta;
+ serial1 = &uartb;
+ serial2 = &uartc;
+ serial3 = &uartd;
};
pcie-controller@00003000 {
aliases {
rtc0 = "/i2c@7000d000/tps65911@2d";
rtc1 = "/rtc@7000e000";
+ serial0 = &uarta;
};
memory {
aliases {
rtc0 = "/i2c@7000d000/tps65911@2d";
rtc1 = "/rtc@7000e000";
+ serial0 = &uarta;
+ serial1 = &uartc;
};
memory {
rtc0 = "/i2c@7000c000/rtc@68";
rtc1 = "/i2c@7000d000/tps65911@2d";
rtc2 = "/rtc@7000e000";
+ serial0 = &uarta;
+ serial1 = &uartb;
+ serial2 = &uartd;
};
host1x@50000000 {
compatible = "nvidia,tegra30";
interrupt-parent = <&intc>;
- aliases {
- serial0 = &uarta;
- serial1 = &uartb;
- serial2 = &uartc;
- serial3 = &uartd;
- serial4 = &uarte;
- };
-
pcie-controller@00003000 {
compatible = "nvidia,tegra30-pcie";
device_type = "pci";
CONFIG_MMC_DW_EXYNOS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_MAX77802=y
CONFIG_RTC_DRV_S5M=y
CONFIG_RTC_DRV_S3C=y
CONFIG_DMADEVICES=y
CONFIG_PL330_DMA=y
CONFIG_COMMON_CLK_MAX77686=y
+CONFIG_COMMON_CLK_MAX77802=y
CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_EXYNOS_IOMMU=y
CONFIG_IIO=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_EXYNOS5=y
CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_S3C2410=y
CONFIG_I2C_SIRF=y
CONFIG_I2C_TEGRA=y
CONFIG_I2C_ST=y
__u32 extra[2]; /* Xscale 'acc' register, etc */
};
-struct arm_restart_block {
- union {
- /* For user cache flushing */
- struct {
- unsigned long start;
- unsigned long end;
- } cache;
- };
-};
-
/*
* low level task data that entry.S needs immediate access to.
* __switch_to() assumes cpu_context follows immediately after cpu_domain.
unsigned long thumbee_state; /* ThumbEE Handler Base register */
#endif
struct restart_block restart_block;
- struct arm_restart_block arm_restart_block;
};
#define INIT_THREAD_INFO(tsk) \
return regs->ARM_r0;
}
-static long do_cache_op_restart(struct restart_block *);
-
static inline int
__do_cache_op(unsigned long start, unsigned long end)
{
do {
unsigned long chunk = min(PAGE_SIZE, end - start);
- if (signal_pending(current)) {
- struct thread_info *ti = current_thread_info();
-
- ti->restart_block = (struct restart_block) {
- .fn = do_cache_op_restart,
- };
-
- ti->arm_restart_block = (struct arm_restart_block) {
- {
- .cache = {
- .start = start,
- .end = end,
- },
- },
- };
-
- return -ERESTART_RESTARTBLOCK;
- }
+ if (fatal_signal_pending(current))
+ return 0;
ret = flush_cache_user_range(start, start + chunk);
if (ret)
return 0;
}
-static long do_cache_op_restart(struct restart_block *unused)
-{
- struct arm_restart_block *restart_block;
-
- restart_block = ¤t_thread_info()->arm_restart_block;
- return __do_cache_op(restart_block->cache.start,
- restart_block->cache.end);
-}
-
static inline int
do_cache_op(unsigned long start, unsigned long end, int flags)
{
pgd = pgdp + pgd_index(addr);
do {
next = kvm_pgd_addr_end(addr, end);
- unmap_puds(kvm, pgd, addr, next);
+ if (!pgd_none(*pgd))
+ unmap_puds(kvm, pgd, addr, next);
} while (pgd++, addr = next, addr != end);
}
return kvm_vcpu_dabt_iswrite(vcpu);
}
+static bool kvm_is_device_pfn(unsigned long pfn)
+{
+ return !pfn_valid(pfn);
+}
+
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm_memory_slot *memslot, unsigned long hva,
unsigned long fault_status)
if (is_error_pfn(pfn))
return -EFAULT;
- if (kvm_is_mmio_pfn(pfn))
+ if (kvm_is_device_pfn(pfn))
mem_type = PAGE_S2_DEVICE;
spin_lock(&kvm->mmu_lock);
type == COHERENCY_FABRIC_TYPE_ARMADA_380)
armada_375_380_coherency_init(np);
+ of_node_put(np);
+
return 0;
}
mdelay(10);
gpio_set_value(S3C2410_GPH(1), 0);
- h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
+ h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL);
}
else {
gpio_set_value(S3C2410_GPH(1), 1);
mdelay(10);
gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
- h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
+ h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
}
}
#define H1940_SUSPEND_RESUMEAT (0x30081000)
#define H1940_SUSPEND_CHECK (0x30080000)
+struct gpio_desc;
+
extern void h1940_pm_return(void);
-extern int h1940_led_blink_set(unsigned gpio, int state,
+extern int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
static DEFINE_SPINLOCK(h1940_blink_spin);
-int h1940_led_blink_set(unsigned gpio, int state,
+int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
int blink_gpio, check_gpio1, check_gpio2;
+ int gpio = desc ? desc_to_gpio(desc) : -EINVAL;
switch (gpio) {
case H1940_LATCH_LED_GREEN:
static DEFINE_SPINLOCK(rx1950_blink_spin);
-static int rx1950_led_blink_set(unsigned gpio, int state,
+static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
+ int gpio = desc_to_gpio(desc);
int blink_gpio, check_gpio;
switch (gpio) {
MSTP128, MSTP127, MSTP125,
MSTP116, MSTP111, MSTP100, MSTP117,
- MSTP230,
+ MSTP230, MSTP229,
MSTP222,
MSTP218, MSTP217, MSTP216, MSTP214,
MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
[MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S], SMSTPCR1, 27, 0), /* CEU20 */
[MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
[MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
- [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+ [MSTP116] = SH_CLK_MSTP32(&div4_clks[DIV4_HPP], SMSTPCR1, 16, 0), /* IIC0 */
[MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 11, 0), /* TMU1 */
[MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
[MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */
+ [MSTP229] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 29, 0), /* INTCA */
[MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */
[MSTP218] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */
[MSTP217] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]),
CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP222]),
CLKDEV_DEV_ID("e6cd0000.serial", &mstp_clks[MSTP222]),
+ CLKDEV_DEV_ID("renesas_intc_irqpin.0", &mstp_clks[MSTP229]),
+ CLKDEV_DEV_ID("renesas_intc_irqpin.1", &mstp_clks[MSTP229]),
+ CLKDEV_DEV_ID("renesas_intc_irqpin.2", &mstp_clks[MSTP229]),
+ CLKDEV_DEV_ID("renesas_intc_irqpin.3", &mstp_clks[MSTP229]),
CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]),
CLKDEV_DEV_ID("e6cc0000.serial", &mstp_clks[MSTP230]),
#define SDCKCR 0xE6150074
#define SD2CKCR 0xE6150078
-#define SD3CKCR 0xE615007C
+#define SD3CKCR 0xE615026C
#define MMC0CKCR 0xE6150240
#define MMC1CKCR 0xE6150244
#define SSPCKCR 0xE6150248
{
struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
+ genpd->flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(genpd, NULL, false);
- genpd->dev_ops.stop = pm_clk_suspend;
- genpd->dev_ops.start = pm_clk_resume;
genpd->dev_ops.active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
struct generic_pm_domain *genpd = &rmobile_pd->genpd;
struct dev_power_governor *gov = rmobile_pd->gov;
+ genpd->flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
- genpd->dev_ops.stop = pm_clk_suspend;
- genpd->dev_ops.start = pm_clk_resume;
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
genpd->power_off = rmobile_pd_power_down;
genpd->power_on = rmobile_pd_power_up;
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/i2c/i2c-sh_mobile.h>
#include <linux/io.h>
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
},
};
+static struct i2c_sh_mobile_platform_data i2c_platform_data = {
+ .clks_per_count = 2,
+};
+
static struct platform_device i2c0_device = {
.name = "i2c-sh_mobile",
.id = 0,
.resource = i2c0_resources,
.num_resources = ARRAY_SIZE(i2c0_resources),
+ .dev = {
+ .platform_data = &i2c_platform_data,
+ },
};
static struct platform_device i2c1_device = {
.id = 1,
.resource = i2c1_resources,
.num_resources = ARRAY_SIZE(i2c1_resources),
+ .dev = {
+ .platform_data = &i2c_platform_data,
+ },
};
static struct platform_device i2c2_device = {
.id = 2,
.resource = i2c2_resources,
.num_resources = ARRAY_SIZE(i2c2_resources),
+ .dev = {
+ .platform_data = &i2c_platform_data,
+ },
};
static struct platform_device i2c3_device = {
.id = 3,
.resource = i2c3_resources,
.num_resources = ARRAY_SIZE(i2c3_resources),
+ .dev = {
+ .platform_data = &i2c_platform_data,
+ },
};
static struct platform_device i2c4_device = {
.id = 4,
.resource = i2c4_resources,
.num_resources = ARRAY_SIZE(i2c4_resources),
+ .dev = {
+ .platform_data = &i2c_platform_data,
+ },
};
static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
static void tegra_mask(struct irq_data *d)
{
- if (d->irq < FIRST_LEGACY_IRQ)
+ if (d->hwirq < FIRST_LEGACY_IRQ)
return;
- tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR);
+ tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR);
}
static void tegra_unmask(struct irq_data *d)
{
- if (d->irq < FIRST_LEGACY_IRQ)
+ if (d->hwirq < FIRST_LEGACY_IRQ)
return;
- tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET);
+ tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET);
}
static void tegra_ack(struct irq_data *d)
{
- if (d->irq < FIRST_LEGACY_IRQ)
+ if (d->hwirq < FIRST_LEGACY_IRQ)
return;
- tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
+ tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
}
static void tegra_eoi(struct irq_data *d)
{
- if (d->irq < FIRST_LEGACY_IRQ)
+ if (d->hwirq < FIRST_LEGACY_IRQ)
return;
- tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
+ tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
}
static int tegra_retrigger(struct irq_data *d)
{
- if (d->irq < FIRST_LEGACY_IRQ)
+ if (d->hwirq < FIRST_LEGACY_IRQ)
return 0;
- tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET);
+ tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET);
return 1;
}
#ifdef CONFIG_PM_SLEEP
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
{
- u32 irq = d->irq;
+ u32 irq = d->hwirq;
u32 index, mask;
if (irq < FIRST_LEGACY_IRQ ||
/* Auxiliary Debug Modes Control 1 Register */
#define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */
#define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */
-#define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */
#define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */
/* Auxiliary Debug Modes Control 2 Register */
/* Auxiliary Debug Modes Control 1 Register */
mrc p15, 1, r0, c15, c1, 1
orr r0, r0, #PJ4B_CLEAN_LINE
- orr r0, r0, #PJ4B_BCK_OFF_STREX
orr r0, r0, #PJ4B_INTER_PARITY
bic r0, r0, #PJ4B_STATIC_BP
mcr p15, 1, r0, c15, c1, 1
mrc p15, 0, r5, c15, c1, 0 @ CP access reg
mrc p15, 0, r6, c13, c0, 0 @ PID
mrc p15, 0, r7, c3, c0, 0 @ domain ID
- mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
mrc p15, 0, r9, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
stmia r0, {r4 - r9} @ store cp regs
mcr p15, 0, r6, c13, c0, 0 @ PID
mcr p15, 0, r7, c3, c0, 0 @ domain ID
mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
mov r0, r9 @ control register
b cpu_resume_mmu
ENDPROC(cpu_xscale_do_resume)
#define ORION_BLINK_HALF_PERIOD 100 /* ms */
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
+ unsigned gpio = desc_to_gpio(desc);
if (delay_on && delay_off && !*delay_on && !*delay_off)
*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
#include <linux/init.h>
#include <linux/types.h>
#include <linux/irqdomain.h>
+
+struct gpio_desc;
+
/*
* Orion-specific GPIO API extensions.
*/
void orion_gpio_set_unused(unsigned pin);
void orion_gpio_set_blink(unsigned pin, int blink);
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
#define GPIO_INPUT_OK (1 << 0)
/* VBAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
NULL, reset_val, VBAR_EL1, 0 },
+
+ /* ICC_SRE_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101),
+ trap_raz_wi },
+
/* CONTEXTIDR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
{ Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
{ Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
+
+ /* ICC_SRE */
+ { Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi },
+
{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
};
for (i = 0; i < npages; i++) {
pfn = gfn_to_pfn(kvm, base_gfn + i);
- if (!kvm_is_mmio_pfn(pfn)) {
+ if (!kvm_is_reserved_pfn(pfn)) {
kvm_set_pmt_entry(kvm, base_gfn + i,
pfn << PAGE_SHIFT,
_PAGE_AR_RWX | _PAGE_MA_WB);
config ARCH_PHYS_ADDR_T_64BIT
def_bool 64BIT_PHYS_ADDR
+choice
+ prompt "SmartMIPS or microMIPS ASE support"
+
+config CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS
+ bool "None"
+ help
+ Select this if you want neither microMIPS nor SmartMIPS support
+
config CPU_HAS_SMARTMIPS
depends on SYS_SUPPORTS_SMARTMIPS
- bool "Support for the SmartMIPS ASE"
+ bool "SmartMIPS"
help
SmartMIPS is a extension of the MIPS32 architecture aimed at
increased security at both hardware and software level for
config CPU_MICROMIPS
depends on SYS_SUPPORTS_MICROMIPS
- bool "Build kernel using microMIPS ISA"
+ bool "microMIPS"
help
When this option is enabled the kernel will be built using the
microMIPS ISA
+endchoice
+
config CPU_HAS_MSA
bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)"
depends on CPU_SUPPORTS_MSA
#define WORD_INSN ".word"
#endif
+#ifdef CONFIG_CPU_MICROMIPS
+#define NOP_INSN "nop32"
+#else
+#define NOP_INSN "nop"
+#endif
+
static __always_inline bool arch_static_branch(struct static_key *key)
{
- asm_volatile_goto("1:\tnop\n\t"
+ asm_volatile_goto("1:\t" NOP_INSN "\n\t"
"nop\n\t"
".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t"
#define cpu_has_mcheck 0
#define cpu_has_mdmx 0
#define cpu_has_mips16 0
-#define cpu_has_mips32r1 0
#define cpu_has_mips32r2 0
#define cpu_has_mips3d 0
-#define cpu_has_mips64r1 0
#define cpu_has_mips64r2 0
#define cpu_has_mipsmt 0
#define cpu_has_prefetch 0
#define MIPS_CONF6_SYND (_ULCAST_(1) << 13)
/* proAptiv FTLB on/off bit */
#define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15)
+/* FTLB probability bits */
+#define MIPS_CONF6_FTLBP_SHIFT (16)
#define MIPS_CONF7_WII (_ULCAST_(1) << 31)
*/
static inline void protected_writeback_dcache_line(unsigned long addr)
{
+#ifdef CONFIG_EVA
+ protected_cachee_op(Hit_Writeback_Inv_D, addr);
+#else
protected_cache_op(Hit_Writeback_Inv_D, addr);
+#endif
}
static inline void protected_writeback_scache_line(unsigned long addr)
__get_kernel_common((x), size, __gu_ptr); \
else \
__get_user_common((x), size, __gu_ptr); \
- } \
+ } else \
+ (x) = 0; \
\
__gu_err; \
})
" .insn \n" \
" .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \
+ " move %1, $0 \n" \
" j 2b \n" \
" .previous \n" \
" .section __ex_table,\"a\" \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \
+ " move %1, $0 \n" \
" j 2b \n" \
" .previous \n" \
" .section __ex_table,\"a\" \n" \
"jal\t" #destination "\n\t"
#endif
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-#define DADDI_SCRATCH "$0"
-#else
+#if defined(CONFIG_CPU_DADDI_WORKAROUNDS) || (defined(CONFIG_EVA) && \
+ defined(CONFIG_CPU_HAS_PREFETCH))
#define DADDI_SCRATCH "$3"
+#else
+#define DADDI_SCRATCH "$0"
#endif
extern size_t __copy_user(void *__to, const void *__from, size_t __n);
}
/*
- * strlen_user: - Get the size of a string in user space.
+ * strnlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
* Context: User context only. This function may sleep.
*
* Returns the size of the string INCLUDING the terminating NUL.
* On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
+ * If the string is too long, returns a value greater than @n.
*/
static inline long strnlen_user(const char __user *s, long n)
{
#define __NR_seccomp (__NR_Linux + 316)
#define __NR_getrandom (__NR_Linux + 317)
#define __NR_memfd_create (__NR_Linux + 318)
-#define __NR_memfd_create (__NR_Linux + 319)
+#define __NR_bpf (__NR_Linux + 319)
/*
* Offset of the last N32 flavoured syscall
END(bmips_reset_nmi_vec)
.set pop
- .previous
/***********************************************************************
* CPU1 warm restart vector (used for second and subsequent boots).
jr ra
END(bmips_enable_xks01)
-
- .previous
nop
.set push
+ .set mips32r2
.set mt
/* Only allow 1 TC per VPE to execute... */
nop
.set push
+ .set mips32r2
.set mt
1: /* Enter VPE configuration state */
static char unknown_isa[] = KERN_ERR \
"Unsupported ISA type, c0.config0: %d.";
+static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c)
+{
+
+ unsigned int probability = c->tlbsize / c->tlbsizevtlb;
+
+ /*
+ * 0 = All TLBWR instructions go to FTLB
+ * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the
+ * FTLB and 1 goes to the VTLB.
+ * 2 = 7:1: As above with 7:1 ratio.
+ * 3 = 3:1: As above with 3:1 ratio.
+ *
+ * Use the linear midpoint as the probability threshold.
+ */
+ if (probability >= 12)
+ return 1;
+ else if (probability >= 6)
+ return 2;
+ else
+ /*
+ * So FTLB is less than 4 times bigger than VTLB.
+ * A 3:1 ratio can still be useful though.
+ */
+ return 3;
+}
+
static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
{
unsigned int config6;
case CPU_P5600:
/* proAptiv & related cores use Config6 to enable the FTLB */
config6 = read_c0_config6();
+ /* Clear the old probability value */
+ config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT);
if (enable)
/* Enable FTLB */
- write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
+ write_c0_config6(config6 |
+ (calculate_ftlb_probability(c)
+ << MIPS_CONF6_FTLBP_SHIFT)
+ | MIPS_CONF6_FTLBEN);
else
/* Disable FTLB */
write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
c->cputype = CPU_LOONGSON2;
__cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2e");
+ set_isa(c, MIPS_CPU_ISA_III);
break;
case PRID_REV_LOONGSON2F:
c->cputype = CPU_LOONGSON2;
__cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2f");
+ set_isa(c, MIPS_CPU_ISA_III);
break;
case PRID_REV_LOONGSON3A:
c->cputype = CPU_LOONGSON3;
- c->writecombine = _CACHE_UNCACHED_ACCELERATED;
__cpu_name[cpu] = "ICT Loongson-3";
set_elf_platform(cpu, "loongson3a");
+ set_isa(c, MIPS_CPU_ISA_M64R1);
break;
case PRID_REV_LOONGSON3B_R1:
case PRID_REV_LOONGSON3B_R2:
c->cputype = CPU_LOONGSON3;
__cpu_name[cpu] = "ICT Loongson-3";
set_elf_platform(cpu, "loongson3b");
+ set_isa(c, MIPS_CPU_ISA_M64R1);
break;
}
- set_isa(c, MIPS_CPU_ISA_III);
c->options = R4K_OPTS |
MIPS_CPU_FPU | MIPS_CPU_LLSC |
MIPS_CPU_32FPR;
c->tlbsize = 64;
+ c->writecombine = _CACHE_UNCACHED_ACCELERATED;
break;
case PRID_IMP_LOONGSON_32: /* Loongson-1 */
decode_configs(c);
#ifdef HAVE_JUMP_LABEL
-#define J_RANGE_MASK ((1ul << 28) - 1)
+/*
+ * Define parameters for the standard MIPS and the microMIPS jump
+ * instruction encoding respectively:
+ *
+ * - the ISA bit of the target, either 0 or 1 respectively,
+ *
+ * - the amount the jump target address is shifted right to fit in the
+ * immediate field of the machine instruction, either 2 or 1,
+ *
+ * - the mask determining the size of the jump region relative to the
+ * delay-slot instruction, either 256MB or 128MB,
+ *
+ * - the jump target alignment, either 4 or 2 bytes.
+ */
+#define J_ISA_BIT IS_ENABLED(CONFIG_CPU_MICROMIPS)
+#define J_RANGE_SHIFT (2 - J_ISA_BIT)
+#define J_RANGE_MASK ((1ul << (26 + J_RANGE_SHIFT)) - 1)
+#define J_ALIGN_MASK ((1ul << J_RANGE_SHIFT) - 1)
void arch_jump_label_transform(struct jump_entry *e,
enum jump_label_type type)
{
+ union mips_instruction *insn_p;
union mips_instruction insn;
- union mips_instruction *insn_p =
- (union mips_instruction *)(unsigned long)e->code;
- /* Jump only works within a 256MB aligned region. */
- BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
+ insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
+
+ /* Jump only works within an aligned region its delay slot is in. */
+ BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
- /* Target must have 4 byte alignment. */
- BUG_ON((e->target & 3) != 0);
+ /* Target must have the right alignment and ISA must be preserved. */
+ BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
if (type == JUMP_LABEL_ENABLE) {
- insn.j_format.opcode = j_op;
- insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
+ insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
+ insn.j_format.target = e->target >> J_RANGE_SHIFT;
} else {
insn.word = 0; /* nop */
}
get_online_cpus();
mutex_lock(&text_mutex);
- *insn_p = insn;
+ if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
+ insn_p->halfword[0] = insn.word >> 16;
+ insn_p->halfword[1] = insn.word;
+ } else
+ *insn_p = insn;
flush_icache_range((unsigned long)insn_p,
(unsigned long)insn_p + sizeof(*insn_p));
int ret = 0;
if (index >= RTLX_CHANNELS) {
- pr_debug(KERN_DEBUG "rtlx_open index out of range\n");
+ pr_debug("rtlx_open index out of range\n");
return -ENOSYS;
}
if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
- pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
+ pr_debug("rtlx_open channel %d already opened\n", index);
ret = -EBUSY;
goto out_fail;
}
* NOTE: historically plat_mem_setup did the entire platform initialization.
* This was rather impractical because it meant plat_mem_setup had to
* get away without any kind of memory allocator. To keep old code from
- * breaking plat_setup was just renamed to plat_setup and a second platform
+ * breaking plat_setup was just renamed to plat_mem_setup and a second platform
* initialization hook for anything else was introduced.
*/
static int __init early_parse_mem(char *p)
{
- unsigned long start, size;
+ phys_t start, size;
/*
* If a user specifies memory size, we
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
} else {
- save_fp_context = copy_fp_from_sigcontext;
- restore_fp_context = copy_fp_to_sigcontext;
+ save_fp_context = copy_fp_to_sigcontext;
+ restore_fp_context = copy_fp_from_sigcontext;
}
#endif /* CONFIG_SMP */
#else
- save_fp_context = copy_fp_from_sigcontext;;
- restore_fp_context = copy_fp_to_sigcontext;
+ save_fp_context = copy_fp_to_sigcontext;
+ restore_fp_context = copy_fp_from_sigcontext;
#endif
return 0;
STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
.Ldone\@:
jr ra
+ nop
.if __memcpy == 1
END(memcpy)
.set __memcpy, 0
# Serial port support
#
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_SERIAL_8250) += serial.o
+loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
+obj-y += $(loongson-serial-m) $(loongson-serial-y)
obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
static struct node_data prealloc__node_data[MAX_NUMNODES];
unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
+EXPORT_SYMBOL(__node_distances);
struct node_data *__node_data[MAX_NUMNODES];
EXPORT_SYMBOL(__node_data);
local_irq_save(flags);
+ htw_stop();
pid = read_c0_entryhi() & ASID_MASK;
address &= (PAGE_MASK << 1);
write_c0_entryhi(address | pid);
tlb_write_indexed();
}
tlbw_use_hazard();
+ htw_start();
flush_itlb_vm(vma);
local_irq_restore(flags);
}
local_irq_save(flags);
/* Save old context and create impossible VPN2 value */
+ htw_stop();
old_ctx = read_c0_entryhi();
old_pagemask = read_c0_pagemask();
wired = read_c0_wired();
write_c0_entryhi(old_ctx);
write_c0_pagemask(old_pagemask);
+ htw_start();
out:
local_irq_restore(flags);
return ret;
uasm_l_smp_pgtable_change(l, *p);
#endif
iPTE_LW(p, wr.r1, wr.r2); /* get even pte */
- if (!m4kc_tlbp_war())
+ if (!m4kc_tlbp_war()) {
build_tlb_probe_entry(p);
+ if (cpu_has_htw) {
+ /* race condition happens, leaving */
+ uasm_i_ehb(p);
+ uasm_i_mfc0(p, wr.r3, C0_INDEX);
+ uasm_il_bltz(p, r, wr.r3, label_leave);
+ uasm_i_nop(p);
+ }
+ }
return wr;
}
*
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
return platform_device_register(&fled_device);
}
-module_init(led_init);
-
-MODULE_AUTHOR("Chris Dearman <chris@mips.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("LED probe driver for SEAD-3");
+device_initcall(led_init);
obj-y += setup.o nlm_hal.o cop2-ex.o dt.o
obj-$(CONFIG_SMP) += wakeup.o
-obj-$(CONFIG_USB) += usb-init.o
-obj-$(CONFIG_USB) += usb-init-xlp2.o
-obj-$(CONFIG_SATA_AHCI) += ahci-init.o
-obj-$(CONFIG_SATA_AHCI) += ahci-init-xlp2.o
+ifdef CONFIG_USB
+obj-y += usb-init.o
+obj-y += usb-init-xlp2.o
+endif
+ifdef CONFIG_SATA_AHCI
+obj-y += ahci-init.o
+obj-y += ahci-init-xlp2.o
+endif
/* This marks the end of the previous function,
which means we overran. */
break;
- stack_size = (unsigned) stack_adjustment;
+ stack_size = (unsigned long) stack_adjustment;
} else if (is_ra_save_ins(&ip)) {
int ra_slot = ip.i_format.simmediate;
if (ra_slot < 0)
}
unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
+EXPORT_SYMBOL(__node_distances);
static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
{
int pci_ext_config_space; /* for pci devices */
- bool force_32bit_msi;
-
struct pci_dev *pcidev; /* back-pointer to the pci device */
#ifdef CONFIG_EEH
struct eeh_dev *edev; /* eeh device */
return -ENODEV;
state = eeh_ops->get_state(edev->pe, NULL);
- return sprintf(buf, "%0x08x %0x08x\n",
+ return sprintf(buf, "0x%08x 0x%08x\n",
state, edev->pe->state);
}
}
EXPORT_SYMBOL(pcibus_to_node);
#endif
-
-static void quirk_radeon_32bit_msi(struct pci_dev *dev)
-{
- struct pci_dn *pdn = pci_get_pdn(dev);
-
- if (pdn)
- pdn->force_32bit_msi = true;
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon_32bit_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon_32bit_msi);
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
mfspr r5,SPRN_SPRG_VDSO_READ
- cmpdi cr0,r3,0
- cmpdi cr1,r4,0
+ cmpwi cr0,r3,0
+ cmpwi cr1,r4,0
clrlwi r6,r5,16
rlwinm r7,r5,16,31-15,31-0
beq cr0,1f
};
/* Print things out */
- if (hmi_evt->version != OpalHMIEvt_V1) {
+ if (hmi_evt->version < OpalHMIEvt_V1) {
pr_err("HMI Interrupt, Unknown event version %d !\n",
hmi_evt->version);
return;
unsigned int is_64, struct msi_msg *msg)
{
struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
- struct pci_dn *pdn = pci_get_pdn(dev);
unsigned int xive_num = hwirq - phb->msi_base;
__be32 data;
int rc;
return -ENXIO;
/* Force 32-bit MSI on some broken devices */
- if (pdn && pdn->force_32bit_msi)
+ if (dev->no_64bit_msi)
is_64 = 0;
/* Assign XIVE to PE */
if (is_kdump_kernel()) {
pr_info(" Issue PHB reset ...\n");
ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
- ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
+ ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE);
}
/* Configure M64 window */
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
- struct pci_dn *pdn = pci_get_pdn(pdev);
struct msi_desc *entry;
struct msi_msg msg;
int hwirq;
if (WARN_ON(!phb) || !phb->msi_bmp.bitmap)
return -ENODEV;
- if (pdn && pdn->force_32bit_msi && !phb->msi32_support)
+ if (pdev->no_64bit_msi && !phb->msi32_support)
return -ENODEV;
list_for_each_entry(entry, &pdev->msi_list, list) {
*/
again:
if (type == PCI_CAP_ID_MSI) {
- if (pdn->force_32bit_msi) {
+ if (pdev->no_64bit_msi) {
rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec);
if (rc < 0) {
/*
cascade_data->virq = virt_msir;
msi->cascade_array[irq_index] = cascade_data;
- ret = request_irq(virt_msir, fsl_msi_cascade, 0,
+ ret = request_irq(virt_msir, fsl_msi_cascade, IRQF_NO_THREAD,
"fsl-msi-cascade", cascade_data);
if (ret) {
dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n",
args.token = rtas_token("set-indicator");
if (args.token == RTAS_UNKNOWN_SERVICE)
return;
- args.nargs = 3;
- args.nret = 1;
+ args.nargs = cpu_to_be32(3);
+ args.nret = cpu_to_be32(1);
args.rets = &args.args[3];
- args.args[0] = SURVEILLANCE_TOKEN;
+ args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN);
args.args[1] = 0;
args.args[2] = 0;
enter_rtas(__pa(&args));
*/
local_irq_save(flags);
local_mcck_disable();
- /*
- * Ummm... Does this make sense at all? Copying the percpu struct
- * and then zapping it one statement later?
- */
- memcpy(&mcck, this_cpu_ptr(&cpu_mcck), sizeof(mcck));
- memset(&mcck, 0, sizeof(struct mcck_struct));
+ mcck = *this_cpu_ptr(&cpu_mcck);
+ memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck));
clear_cpu_flag(CIF_MCCK_PENDING);
local_mcck_enable();
local_irq_restore(flags);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ /* Since dma_{alloc,free}_noncoherent() allocated coherent memory, this
+ * routine can be a nop.
+ */
+}
+
extern struct dma_map_ops *dma_ops;
extern struct dma_map_ops *leon_dma_ops;
extern struct dma_map_ops pci32_dma_ops;
config PERF_EVENTS_INTEL_UNCORE
def_bool y
- depends on PERF_EVENTS && SUP_SUP_INTEL && PCI
+ depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
config OUTPUT_FORMAT
string
suffix-$(CONFIG_KERNEL_LZO) := lzo
suffix-$(CONFIG_KERNEL_LZ4) := lz4
-RUN_SIZE = $(shell objdump -h vmlinux | \
+RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \
perl $(srctree)/arch/x86/tools/calc_run_size.pl)
quiet_cmd_mkpiggy = MKPIGGY $@
cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
#define THREAD_SIZE_ORDER 1
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
-#define STACKFAULT_STACK 0
#define DOUBLEFAULT_STACK 1
#define NMI_STACK 0
#define DEBUG_STACK 0
#define IRQ_STACK_ORDER 2
#define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
-#define STACKFAULT_STACK 1
-#define DOUBLEFAULT_STACK 2
-#define NMI_STACK 3
-#define DEBUG_STACK 4
-#define MCE_STACK 5
-#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 2
+#define DEBUG_STACK 3
+#define MCE_STACK 4
+#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */
#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
/* Only used for 64 bit */
#define _TIF_DO_NOTIFY_MASK \
(_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \
- _TIF_USER_RETURN_NOTIFY)
+ _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE)
/* flags to check in __switch_to() */
#define _TIF_WORK_CTXSW \
#ifdef CONFIG_TRACING
asmlinkage void trace_page_fault(void);
+#define trace_stack_segment stack_segment
#define trace_divide_error divide_error
#define trace_bounds bounds
#define trace_invalid_op invalid_op
static int __init x86_xsave_setup(char *s)
{
+ if (strlen(s))
+ return 0;
setup_clear_cpu_cap(X86_FEATURE_XSAVE);
setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
setup_clear_cpu_cap(X86_FEATURE_XSAVES);
if (uci->valid && uci->mc)
microcode_ops->apply_microcode(cpu);
+#ifdef CONFIG_X86_64
+ else if (!uci->mc)
+ /*
+ * We might resume and not have applied late microcode but still
+ * have a newer patch stashed from the early loader. We don't
+ * have it in uci->mc so we have to load it the same way we're
+ * applying patches early on the APs.
+ */
+ load_ucode_ap();
+#endif
}
static struct syscore_ops mc_syscore_ops = {
.attrs = snbep_uncore_qpi_formats_attr,
};
-#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \
- .init_box = snbep_uncore_msr_init_box, \
+#define __SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \
.disable_box = snbep_uncore_msr_disable_box, \
.enable_box = snbep_uncore_msr_enable_box, \
.disable_event = snbep_uncore_msr_disable_event, \
.enable_event = snbep_uncore_msr_enable_event, \
.read_counter = uncore_msr_read_counter
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \
+ __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), \
+ .init_box = snbep_uncore_msr_init_box \
+
static struct intel_uncore_ops snbep_uncore_msr_ops = {
SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
};
.format_group = &hswep_uncore_cbox_format_group,
};
+/*
+ * Write SBOX Initialization register bit by bit to avoid spurious #GPs
+ */
+static void hswep_uncore_sbox_msr_init_box(struct intel_uncore_box *box)
+{
+ unsigned msr = uncore_msr_box_ctl(box);
+
+ if (msr) {
+ u64 init = SNBEP_PMON_BOX_CTL_INT;
+ u64 flags = 0;
+ int i;
+
+ for_each_set_bit(i, (unsigned long *)&init, 64) {
+ flags |= (1ULL << i);
+ wrmsrl(msr, flags);
+ }
+ }
+}
+
+static struct intel_uncore_ops hswep_uncore_sbox_msr_ops = {
+ __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+ .init_box = hswep_uncore_sbox_msr_init_box
+};
+
static struct attribute *hswep_uncore_sbox_formats_attr[] = {
&format_attr_event.attr,
&format_attr_umask.attr,
.event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
.box_ctl = HSWEP_S0_MSR_PMON_BOX_CTL,
.msr_offset = HSWEP_SBOX_MSR_OFFSET,
- .ops = &snbep_uncore_msr_ops,
+ .ops = &hswep_uncore_sbox_msr_ops,
.format_group = &hswep_uncore_sbox_format_group,
};
SNBEP_UNCORE_PCI_COMMON_INIT(),
};
+static unsigned hswep_uncore_irp_ctrs[] = {0xa0, 0xa8, 0xb0, 0xb8};
+
+static u64 hswep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct pci_dev *pdev = box->pci_dev;
+ struct hw_perf_event *hwc = &event->hw;
+ u64 count = 0;
+
+ pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+ pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+ return count;
+}
+
static struct intel_uncore_ops hswep_uncore_irp_ops = {
.init_box = snbep_uncore_pci_init_box,
.disable_box = snbep_uncore_pci_disable_box,
.enable_box = snbep_uncore_pci_enable_box,
.disable_event = ivbep_uncore_irp_disable_event,
.enable_event = ivbep_uncore_irp_enable_event,
- .read_counter = ivbep_uncore_irp_read_counter,
+ .read_counter = hswep_uncore_irp_read_counter,
};
static struct intel_uncore_type hswep_uncore_irp = {
[ DEBUG_STACK-1 ] = "#DB",
[ NMI_STACK-1 ] = "NMI",
[ DOUBLEFAULT_STACK-1 ] = "#DF",
- [ STACKFAULT_STACK-1 ] = "#SS",
[ MCE_STACK-1 ] = "#MC",
#if DEBUG_STKSZ > EXCEPTION_STKSZ
[ N_EXCEPTION_STACKS ...
jnz native_irq_return_ldt
#endif
+.global native_irq_return_iret
native_irq_return_iret:
+ /*
+ * This may fault. Non-paranoid faults on return to userspace are
+ * handled by fixup_bad_iret. These include #SS, #GP, and #NP.
+ * Double-faults due to espfix64 are handled in do_double_fault.
+ * Other faults here are fatal.
+ */
iretq
- _ASM_EXTABLE(native_irq_return_iret, bad_iret)
#ifdef CONFIG_X86_ESPFIX64
native_irq_return_ldt:
jmp native_irq_return_iret
#endif
- .section .fixup,"ax"
-bad_iret:
- /*
- * The iret traps when the %cs or %ss being restored is bogus.
- * We've lost the original trap vector and error code.
- * #GPF is the most likely one to get for an invalid selector.
- * So pretend we completed the iret and took the #GPF in user mode.
- *
- * We are now running with the kernel GS after exception recovery.
- * But error_entry expects us to have user GS to match the user %cs,
- * so swap back.
- */
- pushq $0
-
- SWAPGS
- jmp general_protection
-
- .previous
-
/* edi: workmask, edx: work */
retint_careful:
CFI_RESTORE_STATE
CFI_ENDPROC
END(common_interrupt)
- /*
- * If IRET takes a fault on the espfix stack, then we
- * end up promoting it to a doublefault. In that case,
- * modify the stack to make it look like we just entered
- * the #GP handler from user space, similar to bad_iret.
- */
-#ifdef CONFIG_X86_ESPFIX64
- ALIGN
-__do_double_fault:
- XCPT_FRAME 1 RDI+8
- movq RSP(%rdi),%rax /* Trap on the espfix stack? */
- sarq $PGDIR_SHIFT,%rax
- cmpl $ESPFIX_PGD_ENTRY,%eax
- jne do_double_fault /* No, just deliver the fault */
- cmpl $__KERNEL_CS,CS(%rdi)
- jne do_double_fault
- movq RIP(%rdi),%rax
- cmpq $native_irq_return_iret,%rax
- jne do_double_fault /* This shouldn't happen... */
- movq PER_CPU_VAR(kernel_stack),%rax
- subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */
- movq %rax,RSP(%rdi)
- movq $0,(%rax) /* Missing (lost) #GP error code */
- movq $general_protection,RIP(%rdi)
- retq
- CFI_ENDPROC
-END(__do_double_fault)
-#else
-# define __do_double_fault do_double_fault
-#endif
-
/*
* APIC interrupts.
*/
idtentry bounds do_bounds has_error_code=0
idtentry invalid_op do_invalid_op has_error_code=0
idtentry device_not_available do_device_not_available has_error_code=0
-idtentry double_fault __do_double_fault has_error_code=1 paranoid=1
+idtentry double_fault do_double_fault has_error_code=1 paranoid=1
idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0
idtentry invalid_TSS do_invalid_TSS has_error_code=1
idtentry segment_not_present do_segment_not_present has_error_code=1
idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1
+idtentry stack_segment do_stack_segment has_error_code=1
#ifdef CONFIG_XEN
idtentry xen_debug do_debug has_error_code=0
idtentry xen_int3 do_int3 has_error_code=0
/*
* There are two places in the kernel that can potentially fault with
- * usergs. Handle them here. The exception handlers after iret run with
- * kernel gs again, so don't set the user space flag. B stepping K8s
- * sometimes report an truncated RIP for IRET exceptions returning to
- * compat mode. Check for these here too.
+ * usergs. Handle them here. B stepping K8s sometimes report a
+ * truncated RIP for IRET exceptions returning to compat mode. Check
+ * for these here too.
*/
error_kernelspace:
CFI_REL_OFFSET rcx, RCX+8
incl %ebx
leaq native_irq_return_iret(%rip),%rcx
cmpq %rcx,RIP+8(%rsp)
- je error_swapgs
+ je error_bad_iret
movl %ecx,%eax /* zero extend */
cmpq %rax,RIP+8(%rsp)
je bstep_iret
bstep_iret:
/* Fix truncated RIP */
movq %rcx,RIP+8(%rsp)
- jmp error_swapgs
+ /* fall through */
+
+error_bad_iret:
+ SWAPGS
+ mov %rsp,%rdi
+ call fixup_bad_iret
+ mov %rax,%rsp
+ decl %ebx /* Return to usergs */
+ jmp error_sti
CFI_ENDPROC
END(error_entry)
*/
if (work & _TIF_NOHZ) {
user_exit();
- work &= ~TIF_NOHZ;
+ work &= ~_TIF_NOHZ;
}
#ifdef CONFIG_SECCOMP
DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun)
DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present)
-#ifdef CONFIG_X86_32
DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment)
-#endif
DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check)
#ifdef CONFIG_X86_64
/* Runs on IST stack */
-dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
- enum ctx_state prev_state;
-
- prev_state = exception_enter();
- if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
- X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
- preempt_conditional_sti(regs);
- do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
- preempt_conditional_cli(regs);
- }
- exception_exit(prev_state);
-}
-
dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
{
static const char str[] = "double fault";
struct task_struct *tsk = current;
+#ifdef CONFIG_X86_ESPFIX64
+ extern unsigned char native_irq_return_iret[];
+
+ /*
+ * If IRET takes a non-IST fault on the espfix64 stack, then we
+ * end up promoting it to a doublefault. In that case, modify
+ * the stack to make it look like we just entered the #GP
+ * handler from user space, similar to bad_iret.
+ */
+ if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
+ regs->cs == __KERNEL_CS &&
+ regs->ip == (unsigned long)native_irq_return_iret)
+ {
+ struct pt_regs *normal_regs = task_pt_regs(current);
+
+ /* Fake a #GP(0) from userspace. */
+ memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
+ normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */
+ regs->ip = (unsigned long)general_protection;
+ regs->sp = (unsigned long)&normal_regs->orig_ax;
+ return;
+ }
+#endif
+
exception_enter();
/* Return not checked because double check cannot be ignored */
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
return regs;
}
NOKPROBE_SYMBOL(sync_regs);
+
+struct bad_iret_stack {
+ void *error_entry_ret;
+ struct pt_regs regs;
+};
+
+asmlinkage __visible
+struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
+{
+ /*
+ * This is called from entry_64.S early in handling a fault
+ * caused by a bad iret to user mode. To handle the fault
+ * correctly, we want move our stack frame to task_pt_regs
+ * and we want to pretend that the exception came from the
+ * iret target.
+ */
+ struct bad_iret_stack *new_stack =
+ container_of(task_pt_regs(current),
+ struct bad_iret_stack, regs);
+
+ /* Copy the IRET target to the new stack. */
+ memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8);
+
+ /* Copy the remainder of the stack from the current stack. */
+ memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip));
+
+ BUG_ON(!user_mode_vm(&new_stack->regs));
+ return new_stack;
+}
#endif
/*
set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun);
set_intr_gate(X86_TRAP_TS, invalid_TSS);
set_intr_gate(X86_TRAP_NP, segment_not_present);
- set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
+ set_intr_gate(X86_TRAP_SS, stack_segment);
set_intr_gate(X86_TRAP_GP, general_protection);
set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug);
set_intr_gate(X86_TRAP_MF, coprocessor_error);
* kvm mmu, before reclaiming the page, we should
* unmap it from mmu first.
*/
- WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn)));
+ WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn)));
if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
kvm_set_pfn_accessed(pfn);
spte |= PT_PAGE_SIZE_MASK;
if (tdp_enabled)
spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
- kvm_is_mmio_pfn(pfn));
+ kvm_is_reserved_pfn(pfn));
if (host_writable)
spte |= SPTE_HOST_WRITEABLE;
* PT_PAGE_TABLE_LEVEL and there would be no adjustment done
* here.
*/
- if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn) &&
+ if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
level == PT_PAGE_TABLE_LEVEL &&
PageTransCompound(pfn_to_page(pfn)) &&
!has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) {
unsigned long end = (unsigned long) &__end_rodata_hpage_align;
unsigned long text_end = PFN_ALIGN(&__stop___ex_table);
unsigned long rodata_end = PFN_ALIGN(&__end_rodata);
- unsigned long all_end = PFN_ALIGN(&_end);
+ unsigned long all_end;
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
/*
* The rodata/data/bss/brk section (but not the kernel text!)
* should also be not-executable.
+ *
+ * We align all_end to PMD_SIZE because the existing mapping
+ * is a full PMD. If we would align _brk_end to PAGE_SIZE we
+ * split the PMD and the reminder between _brk_end and the end
+ * of the PMD will remain mapped executable.
+ *
+ * Any PMD which was setup after the one which covers _brk_end
+ * has been zapped already via cleanup_highmem().
*/
+ all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT);
rodata_test();
if ($file_offset == 0) {
$file_offset = $offset;
} elsif ($file_offset != $offset) {
- die ".bss and .brk lack common file offset\n";
+ # BFD linker shows the same file offset in ELF.
+ # Gold linker shows them as consecutive.
+ next if ($file_offset + $mem_size == $offset + $size);
+
+ printf STDERR "file_offset: 0x%lx\n", $file_offset;
+ printf STDERR "mem_size: 0x%lx\n", $mem_size;
+ printf STDERR "offset: 0x%lx\n", $offset;
+ printf STDERR "size: 0x%lx\n", $size;
+
+ die ".bss and .brk are non-contiguous\n";
}
}
}
{
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
struct blk_integrity_iter iter;
- struct bio_vec *bv;
+ struct bvec_iter bviter;
+ struct bio_vec bv;
struct bio_integrity_payload *bip = bio_integrity(bio);
- unsigned int i, ret = 0;
+ unsigned int ret = 0;
void *prot_buf = page_address(bip->bip_vec->bv_page) +
bip->bip_vec->bv_offset;
iter.seed = bip_get_seed(bip);
iter.prot_buf = prot_buf;
- bio_for_each_segment_all(bv, bio, i) {
- void *kaddr = kmap_atomic(bv->bv_page);
+ bio_for_each_segment(bv, bio, bviter) {
+ void *kaddr = kmap_atomic(bv.bv_page);
- iter.data_buf = kaddr + bv->bv_offset;
- iter.data_size = bv->bv_len;
+ iter.data_buf = kaddr + bv.bv_offset;
+ iter.data_size = bv.bv_len;
ret = proc_fn(&iter);
if (ret) {
config ACPI_REDUCED_HARDWARE_ONLY
bool "Hardware-reduced ACPI support only" if EXPERT
def_bool n
- depends on ACPI
help
- This config item changes the way the ACPI code is built. When this
- option is selected, the kernel will use a specialized version of
- ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
- resulting kernel will be smaller but it will also be restricted to
- running in ACPI reduced hardware mode ONLY.
+ This config item changes the way the ACPI code is built. When this
+ option is selected, the kernel will use a specialized version of
+ ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
+ resulting kernel will be smaller but it will also be restricted to
+ running in ACPI reduced hardware mode ONLY.
- If you are unsure what to do, do not enable this option.
+ If you are unsure what to do, do not enable this option.
source "drivers/acpi/apei/Kconfig"
driver adds support for that functionality with corresponding
tracepoint which carries that information to userspace.
+menuconfig PMIC_OPREGION
+ bool "PMIC (Power Management Integrated Circuit) operation region support"
+ help
+ Select this option to enable support for ACPI operation
+ region of the PMIC chip. The operation region can be used
+ to control power rails and sensor reading/writing on the
+ PMIC chip.
+
+if PMIC_OPREGION
+config CRC_PMIC_OPREGION
+ bool "ACPI operation region support for CrystalCove PMIC"
+ depends on INTEL_SOC_PMIC
+ help
+ This config adds ACPI operation region support for CrystalCove PMIC.
+
+config XPOWER_PMIC_OPREGION
+ bool "ACPI operation region support for XPower AXP288 PMIC"
+ depends on AXP288_ADC = y
+ help
+ This config adds ACPI operation region support for XPower AXP288 PMIC.
+
+endif
+
endif # ACPI
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_APEI) += apei/
obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
+
+obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o
+obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
+obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
/*
* ACPI support for Intel Lynxpoint LPSS.
*
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2014, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
#define LPSS_CLK_DIVIDER BIT(2)
#define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4)
+#define LPSS_DEV_PROXY BIT(5)
+#define LPSS_PROXY_REQ BIT(6)
struct lpss_private_data;
void (*setup)(struct lpss_private_data *pdata);
};
+static struct device *proxy_device;
+
static struct lpss_device_desc lpss_dma_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_PROXY_REQ,
};
struct lpss_private_data {
};
static struct lpss_device_desc byt_uart_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};
static struct lpss_device_desc byt_spi_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x400,
};
static struct lpss_device_desc byt_sdio_dev_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_DEV_PROXY,
};
static struct lpss_device_desc byt_i2c_dev_desc = {
- .flags = LPSS_CLK | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
};
adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) {
+ if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY)
+ proxy_device = &pdev->dev;
return 1;
}
/**
* acpi_lpss_save_ctx() - Save the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Most LPSS devices have private registers which may loose their context when
* the device is powered down. acpi_lpss_save_ctx() saves those registers into
* prv_reg_ctx array.
*/
-static void acpi_lpss_save_ctx(struct device *dev)
+static void acpi_lpss_save_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
/**
* acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Restores the registers that were previously stored with acpi_lpss_save_ctx().
*/
-static void acpi_lpss_restore_ctx(struct device *dev)
+static void acpi_lpss_restore_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
/*
#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
{
- int ret = pm_generic_suspend_late(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = pm_generic_suspend_late(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
return acpi_dev_suspend_late(dev);
}
static int acpi_lpss_resume_early(struct device *dev)
{
- int ret = acpi_dev_resume_early(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = acpi_dev_resume_early(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_resume_early(dev);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
static int acpi_lpss_runtime_suspend(struct device *dev)
{
- int ret = pm_generic_runtime_suspend(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = pm_generic_runtime_suspend(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
- return acpi_dev_runtime_suspend(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
+ ret = acpi_dev_runtime_suspend(dev);
+ if (ret)
+ return ret;
+
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
+ return pm_runtime_put_sync_suspend(proxy_device);
+
+ return 0;
}
static int acpi_lpss_runtime_resume(struct device *dev)
{
- int ret = acpi_dev_runtime_resume(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) {
+ ret = pm_runtime_get_sync(proxy_device);
+ if (ret)
+ return ret;
+ }
+ ret = acpi_dev_runtime_resume(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_runtime_resume(dev);
}
#endif /* CONFIG_PM_RUNTIME */
return 0;
pdata = acpi_driver_data(adev);
- if (!pdata || !pdata->mmio_base)
+ if (!pdata)
return 0;
- if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
+ if (pdata->mmio_base &&
+ pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
return 0;
}
switch (action) {
- case BUS_NOTIFY_BOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = &acpi_lpss_pm_domain;
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = NULL;
- break;
case BUS_NOTIFY_ADD_DEVICE:
+ pdev->dev.pm_domain = &acpi_lpss_pm_domain;
if (pdata->dev_desc->flags & LPSS_LTR)
return sysfs_create_group(&pdev->dev.kobj,
&lpss_attr_group);
+ break;
case BUS_NOTIFY_DEL_DEVICE:
if (pdata->dev_desc->flags & LPSS_LTR)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+ pdev->dev.pm_domain = NULL;
+ break;
default:
break;
}
ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */
+ u8 enable_mask; /* Current mask of enabled GPEs */
};
/*
ACPI_DISASM_ONLY_MEMBERS (\
u8 disasm_flags; /* Used during AML disassembly */\
u8 disasm_opcode; /* Subtype used for disassembly */\
+ char *operator_symbol;/* Used for C-style operator name strings */\
char aml_op_name[16]) /* Op name (debug only) */
/* Flags for disasm_flags field above */
#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
#define ACPI_PARSEOP_PREDEF_CHECKED 0x08
#define ACPI_PARSEOP_SPECIAL 0x10
+#define ACPI_PARSEOP_COMPOUND 0x20
+#define ACPI_PARSEOP_ASSIGNMENT 0x40
/*****************************************************************************
*
/* Enable the requested GPE */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE_SAVE);
return_ACPI_STATUS(status);
}
if (ACPI_SUCCESS(status)) {
status =
acpi_hw_low_set_gpe(gpe_event_info,
- ACPI_GPE_DISABLE);
+ ACPI_GPE_DISABLE_SAVE);
}
if (ACPI_FAILURE(status)) {
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
+ acpi_cpu_flags flags;
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
(void)acpi_ev_finish_gpe(gpe_event_info);
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
ACPI_FREE(gpe_event_info);
return;
/*
* Enable this GPE, conditionally. This means that the GPE will
- * only be physically enabled if the enable_for_run bit is set
+ * only be physically enabled if the enable_mask bit is set
* in the event_info.
*/
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
/* Set or clear just the bit that corresponds to this GPE */
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
- switch (action) {
+ switch (action & ~ACPI_GPE_SAVE_MASK) {
case ACPI_GPE_CONDITIONAL_ENABLE:
- /* Only enable if the enable_for_run bit is set */
+ /* Only enable if the corresponding enable_mask bit is set */
- if (!(register_bit & gpe_register_info->enable_for_run)) {
+ if (!(register_bit & gpe_register_info->enable_mask)) {
return (AE_BAD_PARAMETER);
}
/* Write the updated enable mask */
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
return (status);
}
return (AE_OK);
}
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_gpe_enable_write
+ *
+ * PARAMETERS: enable_mask - Bit mask to write to the GPE register
+ * gpe_register_info - Gpe Register info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write the enable mask byte to the given GPE register.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_gpe_enable_write(u8 enable_mask,
+ struct acpi_gpe_register_info *gpe_register_info)
+{
+ acpi_status status;
+
+ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
+ return (status);
+}
+
/******************************************************************************
*
* FUNCTION: acpi_hw_disable_gpe_block
/* Disable all GPEs in this register */
status =
- acpi_hw_write(0x00,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(0x00,
+ &gpe_block->register_info[i]);
if (ACPI_FAILURE(status)) {
return (status);
}
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* NOTE: assumes that all GPEs are currently disabled */
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
- if (!gpe_block->register_info[i].enable_for_run) {
+ gpe_register_info = &gpe_block->register_info[i];
+ if (!gpe_register_info->enable_for_run) {
continue;
}
/* Enable all "runtime" GPEs in this register */
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_run,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+ gpe_register_info = &gpe_block->register_info[i];
/*
* Enable all "wake" GPEs in this register and disable the
*/
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
/* UART serial bus stop bits */
const char *acpi_gbl_sb_decode[] = {
- "StopBitsNone",
+ "StopBitsZero",
"StopBitsOne",
"StopBitsOnePlusHalf",
"StopBitsTwo"
ACPI_MOVE_32_TO_32(&dword, &buffer[0]);
pld_info->revision = ACPI_PLD_GET_REVISION(&dword);
pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword);
- pld_info->color = ACPI_PLD_GET_COLOR(&dword);
+ pld_info->red = ACPI_PLD_GET_RED(&dword);
+ pld_info->green = ACPI_PLD_GET_GREEN(&dword);
+ pld_info->blue = ACPI_PLD_GET_BLUE(&dword);
/* Second 32-bit DWord */
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxfinit")
+/* For acpi_exec only */
+void ae_do_object_overrides(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
* called, so any early initialization belongs here.
*
******************************************************************************/
+
acpi_status __init acpi_initialize_subsystem(void)
{
acpi_status status;
return_ACPI_STATUS(status);
}
}
+#ifdef ACPI_EXEC_APP
+ /*
+ * This call implements the "initialization file" option for acpi_exec.
+ * This is the precise point that we want to perform the overrides.
+ */
+ ae_do_object_overrides();
+#endif
/*
* Execute any module-level code that was detected during the table load
if (!device)
return -EINVAL;
+
+ if (device->dep_unmet)
+ return -EPROBE_DEFER;
+
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return -ENOMEM;
* Transition Power
* ----------------
* In accordance with the ACPI specification first apply power (via
- * power resources) and then evalute _PSx.
+ * power resources) and then evaluate _PSx.
*/
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
return 0;
target_state = acpi_target_system_state();
- wakeup = device_may_wakeup(dev);
+ wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
error = acpi_device_wakeup(adev, target_state, wakeup);
if (wakeup && error)
return error;
bool acpi_osi_is_win8(void);
#endif
+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
static void acpi_os_map_cleanup(struct acpi_ioremap *map)
{
if (!map->refcount) {
- synchronize_rcu();
+ synchronize_rcu_expedited();
acpi_unmap(map->phys, map->virt);
kfree(map);
}
void acpi_os_wait_events_complete(void)
{
+ /*
+ * Make sure the GPE handler or the fixed event handler is not used
+ * on another CPU after removal.
+ */
+ if (acpi_irq_handler)
+ synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
--- /dev/null
+/*
+ * intel_pmic.c - Intel PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. 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 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/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+#define PMIC_POWER_OPREGION_ID 0x8d
+#define PMIC_THERMAL_OPREGION_ID 0x8c
+
+struct acpi_lpat {
+ int temp;
+ int raw;
+};
+
+struct intel_pmic_opregion {
+ struct mutex lock;
+ struct acpi_lpat *lpat;
+ int lpat_count;
+ struct regmap *regmap;
+ struct intel_pmic_opregion_data *data;
+};
+
+static int pmic_get_reg_bit(int address, struct pmic_table *table,
+ int count, int *reg, int *bit)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (table[i].address == address) {
+ *reg = table[i].reg;
+ if (bit)
+ *bit = table[i].bit;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * raw_to_temp(): Return temperature from raw value through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @raw: the raw value, used as a key to get the temerature from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
+{
+ int i, delta_temp, delta_raw, temp;
+
+ for (i = 0; i < count - 1; i++) {
+ if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
+ (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
+
+ return temp;
+}
+
+/**
+ * temp_to_raw(): Return raw value from temperature through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @temp: the temperature, used as a key to get the raw value from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
+{
+ int i, delta_temp, delta_raw, raw;
+
+ for (i = 0; i < count - 1; i++) {
+ if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
+
+ return raw;
+}
+
+static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
+ acpi_handle handle, struct device *dev)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj_p, *obj_e;
+ int *lpat, i;
+ acpi_status status;
+
+ status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return;
+
+ obj_p = (union acpi_object *)buffer.pointer;
+ if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
+ (obj_p->package.count % 2) || (obj_p->package.count < 4))
+ goto out;
+
+ lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
+ GFP_KERNEL);
+ if (!lpat)
+ goto out;
+
+ for (i = 0; i < obj_p->package.count; i++) {
+ obj_e = &obj_p->package.elements[i];
+ if (obj_e->type != ACPI_TYPE_INTEGER) {
+ devm_kfree(dev, lpat);
+ goto out;
+ }
+ lpat[i] = (s64)obj_e->integer.value;
+ }
+
+ opregion->lpat = (struct acpi_lpat *)lpat;
+ opregion->lpat_count = obj_p->package.count / 2;
+
+out:
+ kfree(buffer.pointer);
+}
+
+static acpi_status intel_pmic_power_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct regmap *regmap = opregion->regmap;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, bit, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->power_table,
+ d->power_table_count, ®, &bit);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ result = function == ACPI_READ ?
+ d->get_power(regmap, reg, bit, value64) :
+ d->update_power(regmap, reg, bit, *value64 == 1);
+
+ mutex_unlock(&opregion->lock);
+
+ return result ? AE_ERROR : AE_OK;
+}
+
+static int pmic_read_temp(struct intel_pmic_opregion *opregion,
+ int reg, u64 *value)
+{
+ int raw_temp, temp;
+
+ if (!opregion->data->get_raw_temp)
+ return -ENXIO;
+
+ raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
+ if (raw_temp < 0)
+ return raw_temp;
+
+ if (!opregion->lpat) {
+ *value = raw_temp;
+ return 0;
+ }
+
+ temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
+ if (temp < 0)
+ return temp;
+
+ *value = temp;
+ return 0;
+}
+
+static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ return function == ACPI_READ ?
+ pmic_read_temp(opregion, reg, value) : -EINVAL;
+}
+
+static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ int raw_temp;
+
+ if (function == ACPI_READ)
+ return pmic_read_temp(opregion, reg, value);
+
+ if (!opregion->data->update_aux)
+ return -ENXIO;
+
+ if (opregion->lpat) {
+ raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
+ *value);
+ if (raw_temp < 0)
+ return raw_temp;
+ } else {
+ raw_temp = *value;
+ }
+
+ return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
+}
+
+static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ struct intel_pmic_opregion_data *d = opregion->data;
+ struct regmap *regmap = opregion->regmap;
+
+ if (!d->get_policy || !d->update_policy)
+ return -ENXIO;
+
+ if (function == ACPI_READ)
+ return d->get_policy(regmap, reg, value);
+
+ if (*value != 0 && *value != 1)
+ return -EINVAL;
+
+ return d->update_policy(regmap, reg, *value);
+}
+
+static bool pmic_thermal_is_temp(int address)
+{
+ return (address <= 0x3c) && !(address % 12);
+}
+
+static bool pmic_thermal_is_aux(int address)
+{
+ return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
+ (address >= 8 && address <= 0x44 && !((address - 8) % 12));
+}
+
+static bool pmic_thermal_is_pen(int address)
+{
+ return address >= 0x48 && address <= 0x5c;
+}
+
+static acpi_status intel_pmic_thermal_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->thermal_table,
+ d->thermal_table_count, ®, NULL);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ if (pmic_thermal_is_temp(address))
+ result = pmic_thermal_temp(opregion, reg, function, value64);
+ else if (pmic_thermal_is_aux(address))
+ result = pmic_thermal_aux(opregion, reg, function, value64);
+ else if (pmic_thermal_is_pen(address))
+ result = pmic_thermal_pen(opregion, reg, function, value64);
+ else
+ result = -EINVAL;
+
+ mutex_unlock(&opregion->lock);
+
+ if (result < 0) {
+ if (result == -EINVAL)
+ return AE_BAD_PARAMETER;
+ else
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
+ struct regmap *regmap,
+ struct intel_pmic_opregion_data *d)
+{
+ acpi_status status;
+ struct intel_pmic_opregion *opregion;
+
+ if (!dev || !regmap || !d)
+ return -EINVAL;
+
+ if (!handle)
+ return -ENODEV;
+
+ opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+ if (!opregion)
+ return -ENOMEM;
+
+ mutex_init(&opregion->lock);
+ opregion->regmap = regmap;
+ pmic_thermal_lpat(opregion, handle, dev);
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_THERMAL_OPREGION_ID,
+ intel_pmic_thermal_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler);
+ return -ENODEV;
+ }
+
+ opregion->data = d;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef __INTEL_PMIC_H
+#define __INTEL_PMIC_H
+
+struct pmic_table {
+ int address; /* operation region address */
+ int reg; /* corresponding thermal register */
+ int bit; /* control bit for power */
+};
+
+struct intel_pmic_opregion_data {
+ int (*get_power)(struct regmap *r, int reg, int bit, u64 *value);
+ int (*update_power)(struct regmap *r, int reg, int bit, bool on);
+ int (*get_raw_temp)(struct regmap *r, int reg);
+ int (*update_aux)(struct regmap *r, int reg, int raw_temp);
+ int (*get_policy)(struct regmap *r, int reg, u64 *value);
+ int (*update_policy)(struct regmap *r, int reg, int enable);
+ struct pmic_table *power_table;
+ int power_table_count;
+ struct pmic_table *thermal_table;
+ int thermal_table_count;
+};
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d);
+
+#endif
--- /dev/null
+/*
+ * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. 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 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/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include "intel_pmic.h"
+
+#define PWR_SOURCE_SELECT BIT(1)
+
+#define PMIC_A0LOCK_REG 0xc5
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x24,
+ .reg = 0x66,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x5d,
+ .bit = 0x00,
+ },
+};
+
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x75
+ },
+ {
+ .address = 0x04,
+ .reg = 0x95
+ },
+ {
+ .address = 0x08,
+ .reg = 0x97
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x77
+ },
+ {
+ .address = 0x10,
+ .reg = 0x9a
+ },
+ {
+ .address = 0x14,
+ .reg = 0x9c
+ },
+ {
+ .address = 0x18,
+ .reg = 0x79
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x9f
+ },
+ {
+ .address = 0x20,
+ .reg = 0xa1
+ },
+ {
+ .address = 0x48,
+ .reg = 0x94
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x99
+ },
+ {
+ .address = 0x50,
+ .reg = 0x9e
+ },
+};
+
+static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on) {
+ data |= PWR_SOURCE_SELECT | BIT(bit);
+ } else {
+ data &= ~BIT(bit);
+ data |= PWR_SOURCE_SELECT;
+ }
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+ return 0;
+}
+
+static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ int temp_l, temp_h;
+
+ /*
+ * Raw temperature value is 10bits: 8bits in reg
+ * and 2bits in reg-1: bit0,1
+ */
+ if (regmap_read(regmap, reg, &temp_l) ||
+ regmap_read(regmap, reg - 1, &temp_h))
+ return -EIO;
+
+ return temp_l | (temp_h & 0x3) << 8;
+}
+
+static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
+{
+ return regmap_write(regmap, reg, raw) ||
+ regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;
+}
+
+static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value)
+{
+ int pen;
+
+ if (regmap_read(regmap, reg, &pen))
+ return -EIO;
+ *value = pen >> 7;
+ return 0;
+}
+
+static int intel_crc_pmic_update_policy(struct regmap *regmap,
+ int reg, int enable)
+{
+ int alert0;
+
+ /* Update to policy enable bit requires unlocking a0lock */
+ if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, reg, 0x80, enable << 7))
+ return -EIO;
+
+ /* restore alert0 */
+ if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))
+ return -EIO;
+
+ return 0;
+}
+
+static struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {
+ .get_power = intel_crc_pmic_get_power,
+ .update_power = intel_crc_pmic_update_power,
+ .get_raw_temp = intel_crc_pmic_get_raw_temp,
+ .update_aux = intel_crc_pmic_update_aux,
+ .get_policy = intel_crc_pmic_get_policy,
+ .update_policy = intel_crc_pmic_update_policy,
+ .power_table = power_table,
+ .power_table_count= ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+ return intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
+ &intel_crc_pmic_opregion_data);
+}
+
+static struct platform_driver intel_crc_pmic_opregion_driver = {
+ .probe = intel_crc_pmic_opregion_probe,
+ .driver = {
+ .name = "crystal_cove_pmic",
+ },
+};
+
+static int __init intel_crc_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_crc_pmic_opregion_driver);
+}
+module_init(intel_crc_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("CrystalCove ACPI opration region driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. 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 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/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/iio/consumer.h>
+#include "intel_pmic.h"
+
+#define XPOWER_GPADC_LOW 0x5b
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x13,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x04,
+ .reg = 0x13,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x08,
+ .reg = 0x13,
+ .bit = 0x07,
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x12,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x10,
+ .reg = 0x12,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x14,
+ .reg = 0x12,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x18,
+ .reg = 0x12,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x12,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x20,
+ .reg = 0x12,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x24,
+ .reg = 0x12,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x28,
+ .reg = 0x13,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x2c,
+ .reg = 0x13,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x30,
+ .reg = 0x13,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x38,
+ .reg = 0x10,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x3c,
+ .reg = 0x10,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x40,
+ .reg = 0x10,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x44,
+ .reg = 0x10,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x10,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x10,
+ .bit = 0x00
+ },
+};
+
+/* TMP0 - TMP5 are the same, all from GPADC */
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x0c,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x18,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x24,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x30,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x3c,
+ .reg = XPOWER_GPADC_LOW
+ },
+};
+
+static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on)
+ data |= BIT(bit);
+ else
+ data &= ~BIT(bit);
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
+ *
+ * @regmap: regmap of the PMIC device
+ * @reg: register to get the reading
+ *
+ * We could get the sensor value by manipulating the HW regs here, but since
+ * the axp288 IIO driver may also access the same regs at the same time, the
+ * APIs provided by IIO subsystem are used here instead to avoid problems. As
+ * a result, the two passed in params are of no actual use.
+ *
+ * Return a positive value on success, errno on failure.
+ */
+static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ struct iio_channel *gpadc_chan;
+ int ret, val;
+
+ gpadc_chan = iio_channel_get(NULL, "axp288-system-temp");
+ if (IS_ERR_OR_NULL(gpadc_chan))
+ return -EACCES;
+
+ ret = iio_read_channel_raw(gpadc_chan, &val);
+ if (ret < 0)
+ val = ret;
+
+ iio_channel_release(gpadc_chan);
+ return val;
+}
+
+static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
+ .get_power = intel_xpower_pmic_get_power,
+ .update_power = intel_xpower_pmic_update_power,
+ .get_raw_temp = intel_xpower_pmic_get_raw_temp,
+ .power_table = power_table,
+ .power_table_count = ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
+ acpi_physical_address address, u32 bit_width, u64 *value,
+ void *handler_context, void *region_context)
+{
+ return AE_OK;
+}
+
+static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct device *parent = pdev->dev.parent;
+ struct axp20x_dev *axp20x = dev_get_drvdata(parent);
+ acpi_status status;
+ int result;
+
+ status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ result = intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(parent), axp20x->regmap,
+ &intel_xpower_pmic_opregion_data);
+ if (result)
+ acpi_remove_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO,
+ intel_xpower_pmic_gpio_handler);
+
+ return result;
+}
+
+static struct platform_driver intel_xpower_pmic_opregion_driver = {
+ .probe = intel_xpower_pmic_opregion_probe,
+ .driver = {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
+static int __init intel_xpower_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_xpower_pmic_opregion_driver);
+}
+module_init(intel_xpower_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("XPower AXP288 ACPI operation region driver");
+MODULE_LICENSE("GPL");
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
u64 count;
int current_count;
- int i;
+ int i, ret = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
printk(KERN_ERR PREFIX "not enough elements in _CST\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
/* Validate number of power states discovered */
if (current_count < 2)
- status = -EFAULT;
+ ret = -EFAULT;
end:
kfree(buffer.pointer);
- return status;
+ return ret;
}
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
int acpi_processor_power_init(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
int retval;
struct cpuidle_device *dev;
static int first_run;
--- /dev/null
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Darren Hart <dvhart@linux.intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return true;
+
+ case ACPI_TYPE_PACKAGE:
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ continue;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+ int ret;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible);
+ if (ret) {
+ ret = acpi_dev_get_property(adev, "compatible",
+ ACPI_TYPE_STRING, &of_compatible);
+ if (ret) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+ }
+ adev->data.of_compatible = of_compatible;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
+ return;
+ }
+
+ fail:
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ * doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev. If the reference includes arguments, store
+ * them in the @args->args[] array.
+ *
+ * If there's more than one reference in the property value package, @index is
+ * used to select the one to return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ * references followed by number of ints as follows:
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ if (val && nval == 1) {
+ ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
+ if (!ret)
+ return ret;
+ }
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+ else if (nval <= 0)
+ return -EINVAL;
+
+ if (nval > obj->package.count)
+ return -EOVERFLOW;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
static const char *dummy_hid = "device";
+static LIST_HEAD(acpi_dep_list);
+static DEFINE_MUTEX(acpi_dep_list_lock);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
LIST_HEAD(acpi_wakeup_device_list);
static DEFINE_MUTEX(acpi_hp_context_lock);
+struct acpi_dep_data {
+ struct list_head node;
+ acpi_handle master;
+ acpi_handle slave;
+};
+
struct acpi_device_bus_id{
char bus_id[15];
unsigned int instance_no;
if (list_empty(&acpi_dev->pnp.ids))
return 0;
- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ int i, nval;
+ char *c;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ for (i = 0; i < nval; i++, obj++) {
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}
modalias[len] = '\0';
}
EXPORT_SYMBOL(acpi_match_device_ids);
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible, *obj;
+ struct acpi_device *adev;
+ int i, nval;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < nval; i++, obj++) {
+ const struct of_device_id *id;
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
return result;
}
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
}
}
+static void acpi_device_dep_initialize(struct acpi_device *adev)
+{
+ struct acpi_dep_data *dep;
+ struct acpi_handle_list dep_devices;
+ acpi_status status;
+ int i;
+
+ if (!acpi_has_method(adev->handle, "_DEP"))
+ return;
+
+ status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+ &dep_devices);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Failed to evaluate _DEP.\n");
+ return;
+ }
+
+ for (i = 0; i < dep_devices.count; i++) {
+ struct acpi_device_info *info;
+ int skip;
+
+ status = acpi_get_object_info(dep_devices.handles[i], &info);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Error reading device info\n");
+ continue;
+ }
+
+ /*
+ * Skip the dependency of Windows System Power
+ * Management Controller
+ */
+ skip = info->valid & ACPI_VALID_HID &&
+ !strcmp(info->hardware_id.string, "INT3396");
+
+ kfree(info);
+
+ if (skip)
+ continue;
+
+ dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
+ if (!dep)
+ return;
+
+ dep->master = dep_devices.handles[i];
+ dep->slave = adev->handle;
+ adev->dep_unmet++;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_add_tail(&dep->node , &acpi_dep_list);
+ mutex_unlock(&acpi_dep_list_lock);
+ }
+}
+
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
return AE_CTRL_DEPTH;
acpi_scan_init_hotplug(device);
+ acpi_device_dep_initialize(device);
out:
if (!*return_value)
device->handler->hotplug.notify_online(device);
}
+void acpi_walk_dep_device_list(acpi_handle handle)
+{
+ struct acpi_dep_data *dep, *tmp;
+ struct acpi_device *adev;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+ if (dep->master == handle) {
+ acpi_bus_get_device(dep->slave, &adev);
+ if (!adev)
+ continue;
+
+ adev->dep_unmet--;
+ if (!adev->dep_unmet)
+ acpi_bus_attach(adev);
+ list_del(&dep->node);
+ kfree(dep);
+ }
+ }
+ mutex_unlock(&acpi_dep_list_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+
/**
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
* @handle: Root of the namespace scope to scan.
static int acpi_freeze_prepare(void)
{
acpi_enable_all_wakeup_gpes();
+ acpi_os_wait_events_complete();
enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
return 0;
}
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
acpi_disable_all_gpes();
+ acpi_os_wait_events_complete();
}
static void acpi_power_off(void)
}
}
-
int __init
-acpi_table_parse_entries(char *id,
- unsigned long table_size,
- int entry_id,
- acpi_tbl_entry_handler handler,
- unsigned int max_entries)
+acpi_parse_entries(char *id, unsigned long table_size,
+ acpi_tbl_entry_handler handler,
+ struct acpi_table_header *table_header,
+ int entry_id, unsigned int max_entries)
{
- struct acpi_table_header *table_header = NULL;
struct acpi_subtable_header *entry;
- unsigned int count = 0;
+ int count = 0;
unsigned long table_end;
- acpi_size tbl_size;
if (acpi_disabled)
return -ENODEV;
- if (!handler)
+ if (!id || !handler)
return -EINVAL;
- if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
- acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
- else
- acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
+ if (!table_size)
+ return -EINVAL;
if (!table_header) {
pr_warn("%4.4s not present\n", id);
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
table_end) {
if (entry->type == entry_id
- && (!max_entries || count++ < max_entries))
+ && (!max_entries || count < max_entries)) {
if (handler(entry, table_end))
- goto err;
+ return -EINVAL;
+
+ count++;
+ }
/*
* If entry->length is 0, break from this loop to avoid
*/
if (entry->length == 0) {
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
- goto err;
+ return -EINVAL;
}
entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
+
if (max_entries && count > max_entries) {
pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
id, entry_id, count - max_entries, count);
}
- early_acpi_os_unmap_memory((char *)table_header, tbl_size);
return count;
-err:
+}
+
+int __init
+acpi_table_parse_entries(char *id,
+ unsigned long table_size,
+ int entry_id,
+ acpi_tbl_entry_handler handler,
+ unsigned int max_entries)
+{
+ struct acpi_table_header *table_header = NULL;
+ acpi_size tbl_size;
+ int count;
+ u32 instance = 0;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!id || !handler)
+ return -EINVAL;
+
+ if (!strncmp(id, ACPI_SIG_MADT, 4))
+ instance = acpi_apic_instance;
+
+ acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+ if (!table_header) {
+ pr_warn("%4.4s not present\n", id);
+ return -ENODEV;
+ }
+
+ count = acpi_parse_entries(id, table_size, handler, table_header,
+ entry_id, max_entries);
+
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
- return -EINVAL;
+ return count;
}
int __init
break;
case 'B':
size_required +=
- sizeof(u8 *) +
- (element->buffer.length * sizeof(u8));
+ sizeof(u8 *) + element->buffer.length;
tail_offset += sizeof(u8 *);
break;
default:
memcpy(tail, element->buffer.pointer,
element->buffer.length);
head += sizeof(u8 *);
- tail += element->buffer.length * sizeof(u8);
+ tail += element->buffer.length;
break;
default:
/* Should never get here */
return true;
for (i = 0; i < video->attached_count; i++) {
- if (video->attached_array[i].bind_info == device)
+ if ((video->attached_array[i].value.int_val & 0xfff) ==
+ (device->device_id & 0xfff))
return true;
}
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
+static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
+{
+ struct acpi_video_device *dev;
+ union acpi_object *levels;
+
+ mutex_lock(&video->device_list_lock);
+ list_for_each_entry(dev, &video->video_device_list, entry) {
+ if (!acpi_video_device_lcd_query_levels(dev, &levels))
+ kfree(levels);
+ }
+ mutex_unlock(&video->device_list_lock);
+}
+
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
if (video->backlight_registered)
return 0;
+ acpi_video_run_bcl_for_osi(video);
+
if (!acpi_video_verify_backlight_support())
return 0;
{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+ { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
* enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731
*/
{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
+ { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
/* Enmotus */
{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
host_priv->csr_base = csr_base;
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
- if (irq < 0) {
+ if (!irq) {
dev_err(&ofdev->dev, "invalid irq from platform\n");
goto error_exit_with_cleanup;
}
card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE);
if (!card->config_regs) {
dev_warn(&dev->dev, "Failed to ioremap config registers\n");
+ err = -ENOMEM;
goto out_release_regions;
}
card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE);
if (!card->buffers) {
dev_warn(&dev->dev, "Failed to ioremap data buffers\n");
+ err = -ENOMEM;
goto out_unmap_config;
}
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o
+ topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
#include <linux/pm.h>
#include <linux/pm_clock.h>
#include <linux/clk.h>
+#include <linux/clkdev.h>
#include <linux/slab.h>
#include <linux/err.h>
/**
* pm_clk_enable - Enable a clock, reporting any errors
* @dev: The device for the given clock
- * @clk: The clock being enabled.
+ * @ce: PM clock entry corresponding to the clock.
*/
-static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
+static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
{
- int ret = clk_enable(clk);
- if (ret)
- dev_err(dev, "%s: failed to enable clk %p, error %d\n",
- __func__, clk, ret);
+ int ret;
+
+ if (ce->status < PCE_STATUS_ERROR) {
+ ret = clk_enable(ce->clk);
+ if (!ret)
+ ce->status = PCE_STATUS_ENABLED;
+ else
+ dev_err(dev, "%s: failed to enable clk %p, error %d\n",
+ __func__, ce->clk, ret);
+ }
return ret;
}
*/
static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
{
- ce->clk = clk_get(dev, ce->con_id);
+ if (!ce->clk)
+ ce->clk = clk_get(dev, ce->con_id);
if (IS_ERR(ce->clk)) {
ce->status = PCE_STATUS_ERROR;
} else {
}
}
-/**
- * pm_clk_add - Start using a device clock for power management.
- * @dev: Device whose clock is going to be used for power management.
- * @con_id: Connection ID of the clock.
- *
- * Add the clock represented by @con_id to the list of clocks used for
- * the power management of @dev.
- */
-int pm_clk_add(struct device *dev, const char *con_id)
+static int __pm_clk_add(struct device *dev, const char *con_id,
+ struct clk *clk)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
kfree(ce);
return -ENOMEM;
}
+ } else {
+ if (IS_ERR(ce->clk) || !__clk_get(clk)) {
+ kfree(ce);
+ return -ENOENT;
+ }
+ ce->clk = clk;
}
pm_clk_acquire(dev, ce);
return 0;
}
+/**
+ * pm_clk_add - Start using a device clock for power management.
+ * @dev: Device whose clock is going to be used for power management.
+ * @con_id: Connection ID of the clock.
+ *
+ * Add the clock represented by @con_id to the list of clocks used for
+ * the power management of @dev.
+ */
+int pm_clk_add(struct device *dev, const char *con_id)
+{
+ return __pm_clk_add(dev, con_id, NULL);
+}
+
+/**
+ * pm_clk_add_clk - Start using a device clock for power management.
+ * @dev: Device whose clock is going to be used for power management.
+ * @clk: Clock pointer
+ *
+ * Add the clock to the list of clocks used for the power management of @dev.
+ * It will increment refcount on clock pointer, use clk_put() on it when done.
+ */
+int pm_clk_add_clk(struct device *dev, struct clk *clk)
+{
+ return __pm_clk_add(dev, NULL, clk);
+}
+
/**
* __pm_clk_remove - Destroy PM clock entry.
* @ce: PM clock entry to destroy.
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
unsigned long flags;
- int ret;
dev_dbg(dev, "%s()\n", __func__);
spin_lock_irqsave(&psd->lock, flags);
- list_for_each_entry(ce, &psd->clock_list, node) {
- if (ce->status < PCE_STATUS_ERROR) {
- ret = __pm_clk_enable(dev, ce->clk);
- if (!ret)
- ce->status = PCE_STATUS_ENABLED;
- }
- }
+ list_for_each_entry(ce, &psd->clock_list, node)
+ __pm_clk_enable(dev, ce);
spin_unlock_irqrestore(&psd->lock, flags);
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
unsigned long flags;
- int ret;
dev_dbg(dev, "%s()\n", __func__);
spin_lock_irqsave(&psd->lock, flags);
- list_for_each_entry(ce, &psd->clock_list, node) {
- if (ce->status < PCE_STATUS_ERROR) {
- ret = __pm_clk_enable(dev, ce->clk);
- if (!ret)
- ce->status = PCE_STATUS_ENABLED;
- }
- }
+ list_for_each_entry(ce, &psd->clock_list, node)
+ __pm_clk_enable(dev, ce);
spin_unlock_irqrestore(&psd->lock, flags);
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
+#include <linux/pm_clock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sched.h>
genpd->cpuidle_data->idle_state->exit_latency = usecs64;
}
+static int genpd_power_on(struct generic_pm_domain *genpd)
+{
+ ktime_t time_start;
+ s64 elapsed_ns;
+ int ret;
+
+ if (!genpd->power_on)
+ return 0;
+
+ time_start = ktime_get();
+ ret = genpd->power_on(genpd);
+ if (ret)
+ return ret;
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns <= genpd->power_on_latency_ns)
+ return ret;
+
+ genpd->power_on_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
+ genpd_recalc_cpu_exit_latency(genpd);
+ pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "on", elapsed_ns);
+
+ return ret;
+}
+
+static int genpd_power_off(struct generic_pm_domain *genpd)
+{
+ ktime_t time_start;
+ s64 elapsed_ns;
+ int ret;
+
+ if (!genpd->power_off)
+ return 0;
+
+ time_start = ktime_get();
+ ret = genpd->power_off(genpd);
+ if (ret == -EBUSY)
+ return ret;
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns <= genpd->power_off_latency_ns)
+ return ret;
+
+ genpd->power_off_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
+ pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "off", elapsed_ns);
+
+ return ret;
+}
+
/**
* __pm_genpd_poweron - Restore power to a given PM domain and its masters.
* @genpd: PM domain to power up.
}
}
- if (genpd->power_on) {
- ktime_t time_start = ktime_get();
- s64 elapsed_ns;
-
- ret = genpd->power_on(genpd);
- if (ret)
- goto err;
-
- elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns > genpd->power_on_latency_ns) {
- genpd->power_on_latency_ns = elapsed_ns;
- genpd->max_off_time_changed = true;
- genpd_recalc_cpu_exit_latency(genpd);
- if (genpd->name)
- pr_warning("%s: Power-on latency exceeded, "
- "new value %lld ns\n", genpd->name,
- elapsed_ns);
- }
- }
+ ret = genpd_power_on(genpd);
+ if (ret)
+ goto err;
out:
genpd_set_active(genpd);
}
if (genpd->power_off) {
- ktime_t time_start;
- s64 elapsed_ns;
-
if (atomic_read(&genpd->sd_count) > 0) {
ret = -EBUSY;
goto out;
}
- time_start = ktime_get();
-
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call pm_genpd_poweron() for the master yet after
* the pm_genpd_poweron() restore power for us (this shouldn't
* happen very often).
*/
- ret = genpd->power_off(genpd);
+ ret = genpd_power_off(genpd);
if (ret == -EBUSY) {
genpd_set_active(genpd);
goto out;
}
-
- elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns > genpd->power_off_latency_ns) {
- genpd->power_off_latency_ns = elapsed_ns;
- genpd->max_off_time_changed = true;
- if (genpd->name)
- pr_warning("%s: Power-off latency exceeded, "
- "new value %lld ns\n", genpd->name,
- elapsed_ns);
- }
}
genpd->status = GPD_STATE_POWER_OFF;
* pm_genpd_present - Check if the given PM domain has been initialized.
* @genpd: PM domain to check.
*/
-static bool pm_genpd_present(struct generic_pm_domain *genpd)
+static bool pm_genpd_present(const struct generic_pm_domain *genpd)
{
- struct generic_pm_domain *gpd;
+ const struct generic_pm_domain *gpd;
if (IS_ERR_OR_NULL(genpd))
return false;
|| atomic_read(&genpd->sd_count) > 0)
return;
- if (genpd->power_off)
- genpd->power_off(genpd);
+ genpd_power_off(genpd);
genpd->status = GPD_STATE_POWER_OFF;
genpd_sd_counter_inc(link->master);
}
- if (genpd->power_on)
- genpd->power_on(genpd);
+ genpd_power_on(genpd);
genpd->status = GPD_STATE_ACTIVE;
}
* If the domain was off before the hibernation, make
* sure it will be off going forward.
*/
- if (genpd->power_off)
- genpd->power_off(genpd);
+ genpd_power_off(genpd);
return 0;
}
genpd->domain.ops.complete = pm_genpd_complete;
genpd->dev_ops.save_state = pm_genpd_default_save_state;
genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
+
+ if (genpd->flags & GENPD_FLAG_PM_CLK) {
+ genpd->dev_ops.stop = pm_clk_suspend;
+ genpd->dev_ops.start = pm_clk_resume;
+ }
+
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
}
dev->pm_domain->detach = genpd_dev_pm_detach;
+ pm_genpd_poweron(pd);
return 0;
}
* are protected by the dev_opp_list_lock for integrity.
* IMPORTANT: the opp nodes should be maintained in increasing
* order.
+ * @dynamic: not-created from static DT entries.
* @available: true/false - marks if this OPP as available or not
* @rate: Frequency in hertz
* @u_volt: Nominal voltage in microvolts corresponding to this OPP
* @dev_opp: points back to the device_opp struct this opp belongs to
- * @head: RCU callback head used for deferred freeing
+ * @rcu_head: RCU callback head used for deferred freeing
*
* This structure stores the OPP information for a given device.
*/
struct list_head node;
bool available;
+ bool dynamic;
unsigned long rate;
unsigned long u_volt;
struct device_opp *dev_opp;
- struct rcu_head head;
+ struct rcu_head rcu_head;
};
/**
* RCU usage: nodes are not modified in the list of device_opp,
* however addition is possible and is secured by dev_opp_list_lock
* @dev: device pointer
- * @head: notifier head to notify the OPP availability changes.
+ * @srcu_head: notifier head to notify the OPP availability changes.
+ * @rcu_head: RCU callback head used for deferred freeing
* @opp_list: list of opps
*
* This is an internal data structure maintaining the link to opps attached to
struct list_head node;
struct device *dev;
- struct srcu_notifier_head head;
+ struct srcu_notifier_head srcu_head;
+ struct rcu_head rcu_head;
struct list_head opp_list;
};
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
-/**
- * dev_pm_opp_add() - Add an OPP table from a table definitions
- * @dev: device for which we do this operation
- * @freq: Frequency in Hz for this OPP
- * @u_volt: Voltage in uVolts for this OPP
- *
- * This function adds an opp definition to the opp list and returns status.
- * The opp is made available by default and it can be controlled using
- * dev_pm_opp_enable/disable functions.
- *
- * Locking: The internal device_opp and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
- * Return:
- * 0: On success OR
- * Duplicate OPPs (both freq and volt are same) and opp->available
- * -EEXIST: Freq are same and volt are different OR
- * Duplicate OPPs (both freq and volt are same) and !opp->available
- * -ENOMEM: Memory allocation failure
- */
-int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
+ unsigned long u_volt, bool dynamic)
{
struct device_opp *dev_opp = NULL;
struct dev_pm_opp *opp, *new_opp;
/* Hold our list modification lock here */
mutex_lock(&dev_opp_list_lock);
+ /* populate the opp table */
+ new_opp->dev_opp = dev_opp;
+ new_opp->rate = freq;
+ new_opp->u_volt = u_volt;
+ new_opp->available = true;
+ new_opp->dynamic = dynamic;
+
/* Check for existing list for 'dev' */
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
}
dev_opp->dev = dev;
- srcu_init_notifier_head(&dev_opp->head);
+ srcu_init_notifier_head(&dev_opp->srcu_head);
INIT_LIST_HEAD(&dev_opp->opp_list);
/* Secure the device list modification */
list_add_rcu(&dev_opp->node, &dev_opp_list);
+ head = &dev_opp->opp_list;
+ goto list_add;
}
- /* populate the opp table */
- new_opp->dev_opp = dev_opp;
- new_opp->rate = freq;
- new_opp->u_volt = u_volt;
- new_opp->available = true;
-
/*
* Insert new OPP in order of increasing frequency
* and discard if already present
return ret;
}
+list_add:
list_add_rcu(&new_opp->node, head);
mutex_unlock(&dev_opp_list_lock);
* Notify the changes in the availability of the operable
* frequency/voltage list.
*/
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
return 0;
}
+
+/**
+ * dev_pm_opp_add() - Add an OPP table from a table definitions
+ * @dev: device for which we do this operation
+ * @freq: Frequency in Hz for this OPP
+ * @u_volt: Voltage in uVolts for this OPP
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ * The opp is made available by default and it can be controlled using
+ * dev_pm_opp_enable/disable functions.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ *
+ * Return:
+ * 0: On success OR
+ * Duplicate OPPs (both freq and volt are same) and opp->available
+ * -EEXIST: Freq are same and volt are different OR
+ * Duplicate OPPs (both freq and volt are same) and !opp->available
+ * -ENOMEM: Memory allocation failure
+ */
+int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+{
+ return dev_pm_opp_add_dynamic(dev, freq, u_volt, true);
+}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
+static void kfree_opp_rcu(struct rcu_head *head)
+{
+ struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
+
+ kfree_rcu(opp, rcu_head);
+}
+
+static void kfree_device_rcu(struct rcu_head *head)
+{
+ struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
+
+ kfree(device_opp);
+}
+
+void __dev_pm_opp_remove(struct device_opp *dev_opp, struct dev_pm_opp *opp)
+{
+ /*
+ * Notify the changes in the availability of the operable
+ * frequency/voltage list.
+ */
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
+ list_del_rcu(&opp->node);
+ call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
+
+ if (list_empty(&dev_opp->opp_list)) {
+ list_del_rcu(&dev_opp->node);
+ call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
+ kfree_device_rcu);
+ }
+}
+
+/**
+ * dev_pm_opp_remove() - Remove an OPP from OPP list
+ * @dev: device for which we do this operation
+ * @freq: OPP to remove with matching 'freq'
+ *
+ * This function removes an opp from the opp list.
+ */
+void dev_pm_opp_remove(struct device *dev, unsigned long freq)
+{
+ struct dev_pm_opp *opp;
+ struct device_opp *dev_opp;
+ bool found = false;
+
+ /* Hold our list modification lock here */
+ mutex_lock(&dev_opp_list_lock);
+
+ dev_opp = find_device_opp(dev);
+ if (IS_ERR(dev_opp))
+ goto unlock;
+
+ list_for_each_entry(opp, &dev_opp->opp_list, node) {
+ if (opp->rate == freq) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
+ __func__, freq);
+ goto unlock;
+ }
+
+ __dev_pm_opp_remove(dev_opp, opp);
+unlock:
+ mutex_unlock(&dev_opp_list_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
+
/**
* opp_set_availability() - helper to set the availability of an opp
* @dev: device for which we do this operation
list_replace_rcu(&opp->node, &new_opp->node);
mutex_unlock(&dev_opp_list_lock);
- kfree_rcu(opp, head);
+ call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
/* Notify the change of the OPP availability */
if (availability_req)
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE,
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
new_opp);
else
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
new_opp);
return 0;
if (IS_ERR(dev_opp))
return ERR_CAST(dev_opp); /* matching type */
- return &dev_opp->head;
+ return &dev_opp->srcu_head;
}
#ifdef CONFIG_OF
unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++);
- if (dev_pm_opp_add(dev, freq, volt))
+ if (dev_pm_opp_add_dynamic(dev, freq, volt, false))
dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq);
nr -= 2;
return 0;
}
EXPORT_SYMBOL_GPL(of_init_opp_table);
+
+/**
+ * of_free_opp_table() - Free OPP table entries created from static DT entries
+ * @dev: device pointer used to lookup device OPPs.
+ *
+ * Free OPPs created using static entries present in DT.
+ */
+void of_free_opp_table(struct device *dev)
+{
+ struct device_opp *dev_opp = find_device_opp(dev);
+ struct dev_pm_opp *opp, *tmp;
+
+ /* Check for existing list for 'dev' */
+ dev_opp = find_device_opp(dev);
+ if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev),
+ PTR_ERR(dev_opp)))
+ return;
+
+ /* Hold our list modification lock here */
+ mutex_lock(&dev_opp_list_lock);
+
+ /* Free static OPPs */
+ list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
+ if (!opp->dynamic)
+ __dev_pm_opp_remove(dev_opp, opp);
+ }
+
+ mutex_unlock(&dev_opp_list_lock);
+}
+EXPORT_SYMBOL_GPL(of_free_opp_table);
#endif
--- /dev/null
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ * Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+ * @propname: Name of the property
+ *
+ * Check if property @propname is present in the device firmware description.
+ */
+bool device_property_present(struct device *dev, const char *propname)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_bool(dev->of_node, propname);
+
+ return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+}
+EXPORT_SYMBOL_GPL(device_property_present);
+
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+ * @propname: Name of the property
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
+#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
+ IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
+ (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
+ _val_, _nval_)) : \
+ acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
+ _proptype_, _val_, _nval_)
+
+/**
+ * device_property_read_u8_array - return a u8 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u8 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8_array);
+
+/**
+ * device_property_read_u16_array - return a u16 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u16 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
+/**
+ * device_property_read_u32_array - return a u32 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u32 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
+/**
+ * device_property_read_u64_array - return a u64 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u64 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
+/**
+ * device_property_read_string_array - return a string array property of device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of string properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_string_array(struct device *dev, const char *propname,
+ const char **val, size_t nval)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ of_property_read_string_array(dev->of_node, propname, val, nval) :
+ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+/**
+ * device_property_read_string - return a string property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not a string.
+ */
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ of_property_read_string(dev->of_node, propname, val) :
+ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, 1);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string);
+
+#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+({ \
+ int _ret_; \
+ if (is_of_node(_fwnode_)) \
+ _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \
+ _type_, _val_, _nval_); \
+ else if (is_acpi_node(_fwnode_)) \
+ _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
+ _proptype_, _val_, _nval_); \
+ else \
+ _ret_ = -ENXIO; \
+ _ret_; \
+})
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u8 properties with @propname from @fwnode and stores them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u16 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u32 properties with @propname from @fwnode store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u64 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an string list property @propname from the given firmware node and store
+ * them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, const char **val,
+ size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string_array(of_node(fwnode), propname,
+ val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string(of_node(fwnode),propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, 1);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ struct device_node *node;
+
+ node = of_get_next_available_child(dev->of_node, of_node(child));
+ if (node)
+ return &node->fwnode;
+ } else if (IS_ENABLED(CONFIG_ACPI)) {
+ struct acpi_device *node;
+
+ node = acpi_get_next_child(dev, acpi_node(child));
+ if (node)
+ return acpi_fwnode_handle(node);
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ * @fwnode: Pointer to the device node to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+ if (is_of_node(fwnode))
+ of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
tmp = pmc_read(pmc, AT91_PMC_USB);
usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
- return parent_rate / (usbdiv + 1);
+
+ return DIV_ROUND_CLOSEST(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)
+ return -EINVAL;
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;
+ div = DIV_ROUND_CLOSEST(*parent_rate, rate);
+ if (div > SAM9X5_USB_MAX_DIV + 1)
+ div = SAM9X5_USB_MAX_DIV + 1;
- return bestrate;
+ return DIV_ROUND_CLOSEST(*parent_rate, div);
}
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;
- unsigned long div = parent_rate / rate;
+ unsigned long div;
+
+ if (!rate)
+ return -EINVAL;
- if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV)
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
tmp_parent_rate = rate * usb->divisors[i];
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
- tmprate = tmp_parent_rate / usb->divisors[i];
+ tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
if (tmprate < rate)
tmpdiff = rate - tmprate;
else
struct at91_pmc *pmc = usb->pmc;
unsigned long div;
- if (!rate || parent_rate % rate)
+ if (!rate)
return -EINVAL;
- div = parent_rate / rate;
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) {
if (!rate)
rate = 1;
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv &= div_mask(divider);
+ bestdiv = _get_div(divider, bestdiv);
+ return bestdiv;
+ }
+
maxdiv = _get_maxdiv(divider);
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
};
EXPORT_SYMBOL_GPL(clk_divider_ops);
-const struct clk_ops clk_divider_ro_ops = {
- .recalc_rate = clk_divider_recalc_rate,
-};
-EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
-
static struct clk *_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
}
init.name = name;
- if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
- init.ops = &clk_divider_ro_ops;
- else
- init.ops = &clk_divider_ops;
+ init.ops = &clk_divider_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
unsigned long ccsr = CCSR;
osc_forced = ccsr & (1 << CCCR_CPDIS_BIT);
- a = cccr & CCCR_A_BIT;
+ a = cccr & (1 << CCCR_A_BIT);
l = ccsr & CCSR_L_MASK;
if (osc_forced || a)
unsigned long ccsr = CCSR;
osc_forced = ccsr & (1 << CCCR_CPDIS_BIT);
- a = cccr & CCCR_A_BIT;
+ a = cccr & (1 << CCCR_A_BIT);
if (osc_forced)
return PXA_MEM_13Mhz;
if (a)
[ESC1_CLK_SRC] = &esc1_clk_src.clkr,
[HDMI_CLK_SRC] = &hdmi_clk_src.clkr,
[VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
- [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
+ [MMSS_RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
[RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
[MAPLE_CLK_SRC] = &maple_clk_src.clkr,
[VDP_CLK_SRC] = &vdp_clk_src.clkr,
div->width = div_width;
div->lock = lock;
div->table = div_table;
- div_ops = (div_flags & CLK_DIVIDER_READ_ONLY)
- ? &clk_divider_ro_ops
- : &clk_divider_ops;
+ div_ops = &clk_divider_ops;
}
clk = clk_register_composite(NULL, name, parent_names, num_parents,
/* Make sure timer is stopped before playing with interrupts */
sun4i_clkevt_time_stop(0);
+ sun4i_clockevent.cpumask = cpu_possible_mask;
+ sun4i_clockevent.irq = irq;
+
+ clockevents_config_and_register(&sun4i_clockevent, rate,
+ TIMER_SYNC_TICKS, 0xffffffff);
+
ret = setup_irq(irq, &sun4i_timer_irq);
if (ret)
pr_warn("failed to setup irq %d\n", irq);
/* Enable timer0 interrupt */
val = readl(timer_base + TIMER_IRQ_EN_REG);
writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
-
- sun4i_clockevent.cpumask = cpu_possible_mask;
- sun4i_clockevent.irq = irq;
-
- clockevents_config_and_register(&sun4i_clockevent, rate,
- TIMER_SYNC_TICKS, 0xffffffff);
}
CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
sun4i_timer_init);
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include "../dmaengine.h"
#include "internal.h"
dw->regs = chip->regs;
chip->dw = dw;
+ pm_runtime_enable(chip->dev);
+ pm_runtime_get_sync(chip->dev);
+
dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
autocfg = dw_params >> DW_PARAMS_EN & 0x1;
dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
nr_channels);
+ pm_runtime_put_sync_suspend(chip->dev);
+
return 0;
err_dma_register:
free_irq(chip->irq, dw);
err_pdata:
+ pm_runtime_put_sync_suspend(chip->dev);
return err;
}
EXPORT_SYMBOL_GPL(dw_dma_probe);
struct dw_dma *dw = chip->dw;
struct dw_dma_chan *dwc, *_dwc;
+ pm_runtime_get_sync(chip->dev);
+
dw_dma_off(dw);
dma_async_device_unregister(&dw->dma);
channel_clear_bit(dw, CH_EN, dwc->mask);
}
+ pm_runtime_put_sync_suspend(chip->dev);
+ pm_runtime_disable(chip->dev);
return 0;
}
EXPORT_SYMBOL_GPL(dw_dma_remove);
#define DMAC_MODE_NS (1 << 0)
unsigned int mode;
unsigned int data_bus_width:10; /* In number of bits */
- unsigned int data_buf_dep:10;
+ unsigned int data_buf_dep:11;
unsigned int num_chan:4;
unsigned int num_peri:6;
u32 peri_ns;
int burst_len;
burst_len = pl330->pcfg.data_bus_width / 8;
- burst_len *= pl330->pcfg.data_buf_dep;
+ burst_len *= pl330->pcfg.data_buf_dep / pl330->pcfg.num_chan;
burst_len >>= desc->rqcfg.brst_size;
/* src/dst_burst_len can't be more than 16 */
/* Select max possible burst size */
burst = pl330->pcfg.data_bus_width / 8;
- while (burst > 1) {
- if (!(len % burst))
- break;
+ /*
+ * Make sure we use a burst size that aligns with all the memcpy
+ * parameters because our DMA programming algorithm doesn't cope with
+ * transfers which straddle an entry in the DMA device's MFIFO.
+ */
+ while ((src | dst | len) & (burst - 1))
burst /= 2;
- }
desc->rqcfg.brst_size = 0;
while (burst != (1 << desc->rqcfg.brst_size))
desc->rqcfg.brst_size++;
+ /*
+ * If burst size is smaller than bus width then make sure we only
+ * transfer one at a time to avoid a burst stradling an MFIFO entry.
+ */
+ if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width)
+ desc->rqcfg.brst_len = 1;
+
desc->rqcfg.brst_len = get_burst_len(desc, len);
desc->txd.flags = flags;
dev_info(&adev->dev,
- "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
+ "Loaded driver for PL330 DMAC-%x\n", adev->periphid);
dev_info(&adev->dev,
"\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
readl(pchan->base + DMA_CHAN_CUR_PARA));
}
-static inline int convert_burst(u32 maxburst, u8 *burst)
+static inline s8 convert_burst(u32 maxburst)
{
switch (maxburst) {
case 1:
- *burst = 0;
- break;
+ return 0;
case 8:
- *burst = 2;
- break;
+ return 2;
default:
return -EINVAL;
}
-
- return 0;
}
-static inline int convert_buswidth(enum dma_slave_buswidth addr_width, u8 *width)
+static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
{
if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) ||
(addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES))
return -EINVAL;
- *width = addr_width >> 1;
- return 0;
+ return addr_width >> 1;
}
static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
struct dma_slave_config *config)
{
u8 src_width, dst_width, src_burst, dst_burst;
- int ret;
if (!config)
return -EINVAL;
- ret = convert_burst(config->src_maxburst, &src_burst);
- if (ret)
- return ret;
+ src_burst = convert_burst(config->src_maxburst);
+ if (src_burst)
+ return src_burst;
- ret = convert_burst(config->dst_maxburst, &dst_burst);
- if (ret)
- return ret;
+ dst_burst = convert_burst(config->dst_maxburst);
+ if (dst_burst)
+ return dst_burst;
- ret = convert_buswidth(config->src_addr_width, &src_width);
- if (ret)
- return ret;
+ src_width = convert_buswidth(config->src_addr_width);
+ if (src_width)
+ return src_width;
- ret = convert_buswidth(config->dst_addr_width, &dst_width);
- if (ret)
- return ret;
+ dst_width = convert_buswidth(config->dst_addr_width);
+ if (dst_width)
+ return dst_width;
lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
DMA_CHAN_CFG_SRC_WIDTH(src_width) |
{
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
- struct dma_slave_config *sconfig = &vchan->cfg;
struct sun6i_dma_lli *v_lli;
struct sun6i_desc *txd;
dma_addr_t p_lli;
- int ret;
+ s8 burst, width;
dev_dbg(chan2dev(chan),
"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
goto err_txd_free;
}
- ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig);
- if (ret)
- goto err_dma_free;
+ v_lli->src = src;
+ v_lli->dst = dest;
+ v_lli->len = len;
+ v_lli->para = NORMAL_WAIT;
+ burst = convert_burst(8);
+ width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_LINEAR_MODE;
+ DMA_CHAN_CFG_SRC_LINEAR_MODE |
+ DMA_CHAN_CFG_SRC_BURST(burst) |
+ DMA_CHAN_CFG_SRC_WIDTH(width) |
+ DMA_CHAN_CFG_DST_BURST(burst) |
+ DMA_CHAN_CFG_DST_WIDTH(width);
sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
-err_dma_free:
- dma_pool_free(sdev->pool, v_lli, p_lli);
err_txd_free:
kfree(txd);
return NULL;
sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
sdc->slave.device_control = sun6i_dma_control;
sdc->slave.chancnt = NR_MAX_VCHANS;
+ sdc->slave.copy_align = 4;
sdc->slave.dev = &pdev->dev;
}
EXPORT_SYMBOL(__devm_gpiod_get_index);
+/**
+ * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
+ * @dev: GPIO consumer
+ * @child: firmware node (child of @dev)
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = fwnode_get_named_gpiod(child, "gpios");
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_get_gpiod_from_child);
+
/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
* @dev: GPIO consumer
#include <linux/gpio.h>
-static DEFINE_SPINLOCK(gpio_lock);
-
-#define CGEN (0x00)
-#define CGIO (0x04)
-#define CGLV (0x08)
-
-#define RGEN (0x20)
-#define RGIO (0x24)
-#define RGLV (0x28)
-
-static unsigned short gpio_ba;
-
-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
-{
- u8 curr_dirs;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
-
- if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+#define GEN 0x00
+#define GIO 0x04
+#define GLV 0x08
+
+struct sch_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ unsigned short iobase;
+ unsigned short core_base;
+ unsigned short resume_base;
+};
- spin_unlock(&gpio_lock);
- return 0;
-}
+#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)
-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+ unsigned reg)
{
- int res;
- unsigned short offset, bit;
+ unsigned base = 0;
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ if (gpio >= sch->resume_base) {
+ gpio -= sch->resume_base;
+ base += 0x20;
+ }
- res = !!(inb(gpio_ba + offset) & (1 << bit));
- return res;
+ return base + reg + gpio / 8;
}
-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_vals;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_vals = inb(gpio_ba + offset);
-
- if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
- else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
- spin_unlock(&gpio_lock);
+ if (gpio >= sch->resume_base)
+ gpio -= sch->resume_base;
+ return gpio % 8;
}
-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_dirs;
unsigned short offset, bit;
+ u8 enable;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
- if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ offset = sch_gpio_offset(sch, gpio, GEN);
+ bit = sch_gpio_bit(sch, gpio);
- spin_unlock(&gpio_lock);
+ enable = inb(sch->iobase + offset);
+ if (!(enable & (1 << bit)))
+ outb(enable | (1 << bit), sch->iobase + offset);
- /*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_core_set(gc, gpio_num, val);
- return 0;
+ spin_unlock(&sch->lock);
}
-static struct gpio_chip sch_gpio_core = {
- .label = "sch_gpio_core",
- .owner = THIS_MODULE,
- .direction_input = sch_gpio_core_direction_in,
- .get = sch_gpio_core_get,
- .direction_output = sch_gpio_core_direction_out,
- .set = sch_gpio_core_set,
-};
-
-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
- unsigned gpio_num)
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ outb(curr_dirs | (1 << bit), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
return 0;
}
-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
+ int res;
unsigned short offset, bit;
- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
+
+ res = !!(inb(sch->iobase + offset) & (1 << bit));
- return !!(inb(gpio_ba + offset) & (1 << bit));
+ return res;
}
-static void sch_gpio_resume_set(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_vals;
unsigned short offset, bit;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_vals = inb(gpio_ba + offset);
+ curr_vals = inb(sch->iobase + offset);
if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
+ outb(curr_vals | (1 << bit), sch->iobase + offset);
else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+ outb((curr_vals & ~(1 << bit)), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
}
-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;
- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ spin_lock(&sch->lock);
- spin_lock(&gpio_lock);
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ outb(curr_dirs & ~(1 << bit), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
/*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_resume_set(gc, gpio_num, val);
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_set(gc, gpio_num, val);
return 0;
}
-static struct gpio_chip sch_gpio_resume = {
- .label = "sch_gpio_resume",
+static struct gpio_chip sch_gpio_chip = {
+ .label = "sch_gpio",
.owner = THIS_MODULE,
- .direction_input = sch_gpio_resume_direction_in,
- .get = sch_gpio_resume_get,
- .direction_output = sch_gpio_resume_direction_out,
- .set = sch_gpio_resume_set,
+ .direction_input = sch_gpio_direction_in,
+ .get = sch_gpio_get,
+ .direction_output = sch_gpio_direction_out,
+ .set = sch_gpio_set,
};
static int sch_gpio_probe(struct platform_device *pdev)
{
+ struct sch_gpio *sch;
struct resource *res;
- int err, id;
- id = pdev->id;
- if (!id)
- return -ENODEV;
+ sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+ if (!sch)
+ return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EBUSY;
- if (!request_region(res->start, resource_size(res), pdev->name))
+ if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
+ pdev->name))
return -EBUSY;
- gpio_ba = res->start;
+ spin_lock_init(&sch->lock);
+ sch->iobase = res->start;
+ sch->chip = sch_gpio_chip;
+ sch->chip.label = dev_name(&pdev->dev);
+ sch->chip.dev = &pdev->dev;
- switch (id) {
+ switch (pdev->id) {
case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
+ sch->core_base = 0;
+ sch->resume_base = 10;
+ sch->chip.ngpio = 14;
+
/*
* GPIO[6:0] enabled by default
* GPIO7 is configured by the CMC as SLPIOVR
* Enable GPIO[9:8] core powered gpios explicitly
*/
- outb(0x3, gpio_ba + CGEN + 1);
+ sch_gpio_enable(sch, 8);
+ sch_gpio_enable(sch, 9);
/*
* SUS_GPIO[2:0] enabled by default
* Enable SUS_GPIO3 resume powered gpio explicitly
*/
- outb(0x8, gpio_ba + RGEN);
+ sch_gpio_enable(sch, 13);
break;
case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 5;
+ sch->chip.ngpio = 14;
break;
case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 21;
+ sch->chip.ngpio = 30;
break;
default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ return -ENODEV;
}
- sch_gpio_core.dev = &pdev->dev;
- sch_gpio_resume.dev = &pdev->dev;
-
- err = gpiochip_add(&sch_gpio_core);
- if (err < 0)
- goto err_sch_gpio_core;
+ platform_set_drvdata(pdev, sch);
- err = gpiochip_add(&sch_gpio_resume);
- if (err < 0)
- goto err_sch_gpio_resume;
-
- return 0;
-
-err_sch_gpio_resume:
- gpiochip_remove(&sch_gpio_core);
-
-err_sch_gpio_core:
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
-
- return err;
+ return gpiochip_add(&sch->chip);
}
static int sch_gpio_remove(struct platform_device *pdev)
{
- struct resource *res;
- if (gpio_ba) {
-
- gpiochip_remove(&sch_gpio_core);
- gpiochip_remove(&sch_gpio_resume);
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
- }
+ struct sch_gpio *sch = platform_get_drvdata(pdev);
+ gpiochip_remove(&sch->chip);
return 0;
}
}
}
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios)
+{
+ if (adev && gpios) {
+ adev->driver_gpios = gpios;
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
+
+static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
+ const char *name, int index,
+ struct acpi_reference_args *args)
+{
+ const struct acpi_gpio_mapping *gm;
+
+ if (!adev->driver_gpios)
+ return false;
+
+ for (gm = adev->driver_gpios; gm->name; gm++)
+ if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
+ const struct acpi_gpio_params *par = gm->data + index;
+
+ args->adev = adev;
+ args->args[0] = par->crs_entry_index;
+ args->args[1] = par->line_index;
+ args->args[2] = par->active_low;
+ args->nargs = 3;
+ return true;
+ }
+
+ return false;
+}
+
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}
return 1;
/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
- * @dev: pointer to a device to get GPIO from
+ * @adev: pointer to a ACPI device to get GPIO from
+ * @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
- * Function goes through ACPI resources for @dev and based on @index looks
+ * Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * If @propname is specified the GPIO is looked using device property. In
+ * that case @index is used to select the GPIO entry in the property value
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;
- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname,
+ index, &args);
+ if (ret) {
+ bool found = acpi_get_driver_gpio_data(adev, propname,
+ index, &args);
+ if (!found)
+ return ERR_PTR(ret);
+ }
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
acpi_dev_free_resource_list(&resource_list);
- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
+ char propname[32];
+ int i;
- desc = acpi_get_gpiod_by_index(dev, idx, &info);
- if (IS_ERR(desc))
- return desc;
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios")) {
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, suffixes[i]);
+ } else {
+ snprintf(propname, sizeof(propname), "%s",
+ suffixes[i]);
+ }
+
+ desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
- if (info.gpioint && info.active_low)
+ /* Then from plain _CRS GPIOs */
+ if (IS_ERR(desc)) {
+ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+ }
+
+ if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;
return desc;
}
EXPORT_SYMBOL_GPL(__gpiod_get_index);
+/**
+ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
+ * @fwnode: handle of the firmware node
+ * @propname: name of the firmware property representing the GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware.
+ *
+ * Function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ bool active_low = false;
+ int ret;
+
+ if (!fwnode)
+ return ERR_PTR(-EINVAL);
+
+ if (is_of_node(fwnode)) {
+ enum of_gpio_flags flags;
+
+ desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
+ &flags);
+ if (!IS_ERR(desc))
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+ } else if (is_acpi_node(fwnode)) {
+ struct acpi_gpio_info info;
+
+ desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
+ &info);
+ if (!IS_ERR(desc))
+ active_low = info.active_low;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ ret = gpiod_request(desc, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Only value flag can be set from both DT and ACPI is active_low */
+ if (active_low)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
/**
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
* function
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
- struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+ int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
goto out_regs;
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = i915_kick_out_vgacon(dev_priv);
+ /* WARNING: Apparently we must kick fbdev drivers before vgacon,
+ * otherwise the vga fbdev driver falls over. */
+ ret = i915_kick_out_firmware_fb(dev_priv);
if (ret) {
- DRM_ERROR("failed to remove conflicting VGA console\n");
+ DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
goto out_gtt;
}
- ret = i915_kick_out_firmware_fb(dev_priv);
+ ret = i915_kick_out_vgacon(dev_priv);
if (ret) {
- DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
+ DRM_ERROR("failed to remove conflicting VGA console\n");
goto out_gtt;
}
}
ironlake_fdi_disable(crtc);
ironlake_disable_pch_transcoder(dev_priv, pipe);
- intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
if (HAS_PCH_CPT(dev)) {
/* disable TRANS_DP_CTL */
if (intel_crtc->config.has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
- intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
intel_ddi_fdi_disable(crtc);
}
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ if (i915_reset_in_progress(&dev_priv->gpu_error) ||
+ crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter))
+ return true;
+
/*
* The relevant registers doen't exist on pre-ctg.
* As the flip done interrupt doesn't trigger for mmio
* vdd might still be enabled do to the delayed vdd off.
* Make sure vdd is actually turned off here.
*/
+ cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
pps_lock(intel_dp);
edp_panel_vdd_off_sync(intel_dp);
pps_unlock(intel_dp);
int pipe;
u8 pin;
+ /*
+ * Unlock registers and just leave them unlocked. Do this before
+ * checking quirk lists to avoid bogus WARNINGs.
+ */
+ if (HAS_PCH_SPLIT(dev)) {
+ I915_WRITE(PCH_PP_CONTROL,
+ I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+ } else {
+ I915_WRITE(PP_CONTROL,
+ I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+ }
if (!intel_lvds_supported(dev))
return;
lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
LVDS_A3_POWER_MASK;
- /*
- * Unlock registers and just
- * leave them unlocked
- */
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(PCH_PP_CONTROL,
- I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
- } else {
- I915_WRITE(PP_CONTROL,
- I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
- }
lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
DRM_DEBUG_KMS("lid notifier registration failed\n");
I915_WRITE(_3D_CHICKEN,
_MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB));
- /* WaSetupGtModeTdRowDispatch:snb */
- if (IS_SNB_GT1(dev))
- I915_WRITE(GEN6_GT_MODE,
- _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
-
/* WaDisable_RenderCache_OperationalFlush:snb */
I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
break;
}
if (status & 0x40000000) {
- nouveau_fifo_uevent(&priv->base);
nv_wr32(priv, 0x002100, 0x40000000);
+ nouveau_fifo_uevent(&priv->base);
status &= ~0x40000000;
}
}
u32 inte = nv_rd32(priv, 0x002628);
u32 unkn;
+ nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
+
for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) {
nv_mask(priv, 0x002628, ints, 0);
}
}
-
- nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
}
static void
}
if (stat & 0x80000000) {
- nve0_fifo_intr_engine(priv);
nv_wr32(priv, 0x002100, 0x80000000);
+ nve0_fifo_intr_engine(priv);
stat &= ~0x80000000;
}
pci_save_state(pdev);
pci_disable_device(pdev);
- pci_ignore_hotplug(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
ret = nouveau_do_suspend(drm_dev, true);
pci_save_state(pdev);
pci_disable_device(pdev);
+ pci_ignore_hotplug(pdev);
pci_set_power_state(pdev, PCI_D3cold);
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
return ret;
return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
}
-static void
+static int
nouveau_fence_signal(struct nouveau_fence *fence)
{
+ int drop = 0;
+
fence_signal_locked(&fence->base);
list_del(&fence->head);
+ rcu_assign_pointer(fence->channel, NULL);
if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
if (!--fctx->notify_ref)
- nvif_notify_put(&fctx->notify);
+ drop = 1;
}
fence_put(&fence->base);
+ return drop;
}
static struct nouveau_fence *
{
struct nouveau_fence *fence;
- nvif_notify_fini(&fctx->notify);
-
spin_lock_irq(&fctx->lock);
while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);
- nouveau_fence_signal(fence);
- fence->channel = NULL;
+ if (nouveau_fence_signal(fence))
+ nvif_notify_put(&fctx->notify);
}
spin_unlock_irq(&fctx->lock);
+
+ nvif_notify_fini(&fctx->notify);
+ fctx->dead = 1;
+
+ /*
+ * Ensure that all accesses to fence->channel complete before freeing
+ * the channel.
+ */
+ synchronize_rcu();
}
static void
kref_put(&fctx->fence_ref, nouveau_fence_context_put);
}
-static void
+static int
nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
{
struct nouveau_fence *fence;
-
+ int drop = 0;
u32 seq = fctx->read(chan);
while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);
if ((int)(seq - fence->base.seqno) < 0)
- return;
+ break;
- nouveau_fence_signal(fence);
+ drop |= nouveau_fence_signal(fence);
}
+
+ return drop;
}
static int
struct nouveau_fence_chan *fctx =
container_of(notify, typeof(*fctx), notify);
unsigned long flags;
+ int ret = NVIF_NOTIFY_KEEP;
spin_lock_irqsave(&fctx->lock, flags);
if (!list_empty(&fctx->pending)) {
struct nouveau_fence *fence;
+ struct nouveau_channel *chan;
fence = list_entry(fctx->pending.next, typeof(*fence), head);
- nouveau_fence_update(fence->channel, fctx);
+ chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
+ if (nouveau_fence_update(fence->channel, fctx))
+ ret = NVIF_NOTIFY_DROP;
}
spin_unlock_irqrestore(&fctx->lock, flags);
- /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */
- return NVIF_NOTIFY_KEEP;
+ return ret;
}
void
if (!ret) {
fence_get(&fence->base);
spin_lock_irq(&fctx->lock);
- nouveau_fence_update(chan, fctx);
+
+ if (nouveau_fence_update(chan, fctx))
+ nvif_notify_put(&fctx->notify);
+
list_add_tail(&fence->head, &fctx->pending);
spin_unlock_irq(&fctx->lock);
}
if (fence->base.ops == &nouveau_fence_ops_legacy ||
fence->base.ops == &nouveau_fence_ops_uevent) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+ struct nouveau_channel *chan;
unsigned long flags;
if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
return true;
spin_lock_irqsave(&fctx->lock, flags);
- nouveau_fence_update(fence->channel, fctx);
+ chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
+ if (chan && nouveau_fence_update(chan, fctx))
+ nvif_notify_put(&fctx->notify);
spin_unlock_irqrestore(&fctx->lock, flags);
}
return fence_is_signaled(&fence->base);
if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
struct nouveau_channel *prev = NULL;
+ bool must_wait = true;
f = nouveau_local_fence(fence, chan->drm);
- if (f)
- prev = f->channel;
+ if (f) {
+ rcu_read_lock();
+ prev = rcu_dereference(f->channel);
+ if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
+ must_wait = false;
+ rcu_read_unlock();
+ }
- if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+ if (must_wait)
ret = fence_wait(fence, intr);
return ret;
for (i = 0; i < fobj->shared_count && !ret; ++i) {
struct nouveau_channel *prev = NULL;
+ bool must_wait = true;
fence = rcu_dereference_protected(fobj->shared[i],
reservation_object_held(resv));
f = nouveau_local_fence(fence, chan->drm);
- if (f)
- prev = f->channel;
+ if (f) {
+ rcu_read_lock();
+ prev = rcu_dereference(f->channel);
+ if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
+ must_wait = false;
+ rcu_read_unlock();
+ }
- if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+ if (must_wait)
ret = fence_wait(fence, intr);
-
- if (ret)
- break;
}
return ret;
struct nouveau_fence *fence = from_fence(f);
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
- return fence->channel ? fctx->name : "dead channel";
+ return !fctx->dead ? fctx->name : "dead channel";
}
/*
{
struct nouveau_fence *fence = from_fence(f);
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
- struct nouveau_channel *chan = fence->channel;
+ struct nouveau_channel *chan;
+ bool ret = false;
+
+ rcu_read_lock();
+ chan = rcu_dereference(fence->channel);
+ if (chan)
+ ret = (int)(fctx->read(chan) - fence->base.seqno) >= 0;
+ rcu_read_unlock();
- return (int)(fctx->read(chan) - fence->base.seqno) >= 0;
+ return ret;
}
static bool nouveau_fence_no_signaling(struct fence *f)
bool sysmem;
- struct nouveau_channel *channel;
+ struct nouveau_channel __rcu *channel;
unsigned long timeout;
};
char name[32];
struct nvif_notify notify;
- int notify_ref;
+ int notify_ref, dead;
};
struct nouveau_fence_priv {
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
rdev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
- ppt->usMaximumPowerDeliveryLimit;
+ le16_to_cpu(ppt->usMaximumPowerDeliveryLimit);
pt = &ppt->power_tune_table;
} else {
ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
}
if (!radeon_connector->edid) {
+ /* don't fetch the edid from the vbios if ddc fails and runpm is
+ * enabled so we report disconnected.
+ */
+ if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+ return;
+
if (rdev->is_atom_bios) {
/* some laptops provide a hardcoded edid in rom for LCDs */
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
static enum drm_connector_status
radeon_lvds_detect(struct drm_connector *connector, bool force)
{
+ struct drm_device *dev = connector->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
enum drm_connector_status ret = connector_status_disconnected;
/* check if panel is valid */
if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
ret = connector_status_connected;
-
+ /* don't fetch the edid from the vbios if ddc fails and runpm is
+ * enabled so we report disconnected.
+ */
+ if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+ ret = connector_status_disconnected;
}
/* check for edid as well */
/* check if panel is valid */
if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
ret = connector_status_connected;
+ /* don't fetch the edid from the vbios if ddc fails and runpm is
+ * enabled so we report disconnected.
+ */
+ if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+ ret = connector_status_disconnected;
}
/* eDP is always DP */
radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
{
- int i, r = 0;
+ struct radeon_cs_reloc *reloc;
+ int r;
- for (i = 0; i < p->nrelocs; i++) {
+ list_for_each_entry(reloc, &p->validated, tv.head) {
struct reservation_object *resv;
- if (!p->relocs[i].robj)
- continue;
-
- resv = p->relocs[i].robj->tbo.resv;
+ resv = reloc->robj->tbo.resv;
r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv,
- p->relocs[i].tv.shared);
-
+ reloc->tv.shared);
if (r)
- break;
+ return r;
}
- return r;
+ return 0;
}
/* XXX: note that this is called from the legacy UMS CS ioctl as well */
(rdev->pdev->subsystem_vendor == 0x1734) &&
(rdev->pdev->subsystem_device == 0x1107))
use_bl = false;
+ /* disable native backlight control on older asics */
+ else if (rdev->family < CHIP_R600)
+ use_bl = false;
else
use_bl = true;
}
if (rdev->flags & RADEON_IS_AGP)
return false;
+ /*
+ * Older chips have a HW limitation, they can only generate 40 bits
+ * of address for "64-bit" MSIs which breaks on some platforms, notably
+ * IBM POWER servers, so we limit them
+ */
+ if (rdev->family < CHIP_BONAIRE) {
+ dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n");
+ rdev->pdev->no_64bit_msi = 1;
+ }
+
/* force MSI on */
if (radeon_msi == 1)
return true;
/* Get associated drm_crtc: */
drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
+ if (!drmcrtc)
+ return -EINVAL;
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
if (!(rdev->flags & RADEON_IS_PCIE))
bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+#ifdef CONFIG_X86_32
+ /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
+ * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
+ */
+ bo->flags &= ~RADEON_GEM_GTT_WC;
+#endif
+
radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */
down_read(&rdev->pm.mclk_lock);
if (ret)
goto clock_dis;
- data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- client->name,
- data,
- g762_groups);
+ data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+ data, g762_groups);
if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
goto clock_dis;
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
+#define CDNS_I2C_TIMEOUT_MAX 0xFF
+
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
goto err_clk_dis;
}
+ /*
+ * Cadence I2C controller has a bug wherein it generates
+ * invalid read transaction after HW timeout in master receiver mode.
+ * HW timeout is not used by this driver and the interrupt is disabled.
+ * But the feature itself cannot be disabled. Hence maximum value
+ * is written to this register to reduce the chances of error.
+ */
+ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return msg->len;
- if (stop) {
- w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
- w |= DAVINCI_I2C_MDR_STP;
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
- }
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
return -EREMOTEIO;
}
return -EIO;
}
/* Configure Tx/Rx FIFO threshold levels */
- dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+ dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
/* configure the i2c master */
if (stat & OMAP_I2C_STAT_NACK) {
err |= OMAP_I2C_STAT_NACK;
omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
- break;
}
if (stat & OMAP_I2C_STAT_AL) {
dev_err(dev->dev, "Arbitration lost\n");
err |= OMAP_I2C_STAT_AL;
omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
- break;
}
/*
if (dev->fifo_size)
num_bytes = dev->buf_len;
- omap_i2c_receive_data(dev, num_bytes, true);
-
- if (dev->errata & I2C_OMAP_ERRATA_I207)
+ if (dev->errata & I2C_OMAP_ERRATA_I207) {
i2c_omap_errata_i207(dev, stat);
+ num_bytes = (omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F;
+ }
+ omap_i2c_receive_data(dev, num_bytes, true);
omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
continue;
}
return -ENOMEM;
}
+ acpi_walk_dep_device_list(handle);
return 0;
}
#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B
#define BMC150_ACCEL_ANY_MOTION_MASK 0x07
+#define BMC150_ACCEL_ANY_MOTION_BIT_X BIT(0)
+#define BMC150_ACCEL_ANY_MOTION_BIT_Y BIT(1)
+#define BMC150_ACCEL_ANY_MOTION_BIT_Z BIT(2)
#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3)
#define BMC150_ACCEL_REG_PMU_LPW 0x11
#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF
/* Slope duration in terms of number of samples */
-#define BMC150_ACCEL_DEF_SLOPE_DURATION 2
+#define BMC150_ACCEL_DEF_SLOPE_DURATION 1
/* in terms of multiples of g's/LSB, based on range */
-#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 5
+#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 1
#define BMC150_ACCEL_REG_XOUT_L 0x02
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: bmc150_accel_set_power_state for %d\n", on);
+ if (on)
+ pm_runtime_put_noidle(&data->client->dev);
+
return ret;
}
ret = bmc150_accel_setup_any_motion_interrupt(data, state);
if (ret < 0) {
+ bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
static const struct iio_event_spec bmc150_accel_event = {
.type = IIO_EV_TYPE_ROC,
- .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
+ .dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE) |
BIT(IIO_EV_INFO_PERIOD)
else
ret = bmc150_accel_setup_new_data_interrupt(data, state);
if (ret < 0) {
+ bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
else
dir = IIO_EV_DIR_RISING;
- if (ret & BMC150_ACCEL_ANY_MOTION_MASK)
+ if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_X,
+ IIO_EV_TYPE_ROC,
+ dir),
+ data->timestamp);
+ if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
- IIO_MOD_X_OR_Y_OR_Z,
+ IIO_MOD_Y,
IIO_EV_TYPE_ROC,
- IIO_EV_DIR_EITHER),
+ dir),
+ data->timestamp);
+ if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_Z,
+ IIO_EV_TYPE_ROC,
+ dir),
data->timestamp);
ack_intr_status:
if (!data->dready_trigger_on)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct bmc150_accel_data *data = iio_priv(indio_dev);
+ int ret;
dev_dbg(&data->client->dev, __func__);
+ ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
+ if (ret < 0)
+ return -EAGAIN;
- return bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
+ return 0;
}
static int bmc150_accel_runtime_resume(struct device *dev)
return ret;
}
+ ret &= ~(KXCJK1013_REG_CTRL1_BIT_GSEL0 |
+ KXCJK1013_REG_CTRL1_BIT_GSEL1);
ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
help
Say yes here to build support for Atmel AT91 ADC.
+config AXP288_ADC
+ tristate "X-Powers AXP288 ADC driver"
+ depends on MFD_AXP20X
+ help
+ Say yes here to have support for X-Powers power management IC (PMIC) ADC
+ device. Depending on platform configuration, this general purpose ADC can
+ be used for sampling sensors such as thermal resistors.
+
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
--- /dev/null
+/*
+ * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/platform_device.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define AXP288_ADC_EN_MASK 0xF1
+#define AXP288_ADC_TS_PIN_GPADC 0xF2
+#define AXP288_ADC_TS_PIN_ON 0xF3
+
+enum axp288_adc_id {
+ AXP288_ADC_TS,
+ AXP288_ADC_PMIC,
+ AXP288_ADC_GP,
+ AXP288_ADC_BATT_CHRG_I,
+ AXP288_ADC_BATT_DISCHRG_I,
+ AXP288_ADC_BATT_V,
+ AXP288_ADC_NR_CHAN,
+};
+
+struct axp288_adc_info {
+ int irq;
+ struct regmap *regmap;
+};
+
+static const struct iio_chan_spec const axp288_adc_channels[] = {
+ {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 0,
+ .address = AXP288_TS_ADC_H,
+ .datasheet_name = "TS_PIN",
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 1,
+ .address = AXP288_PMIC_ADC_H,
+ .datasheet_name = "PMIC_TEMP",
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 2,
+ .address = AXP288_GP_ADC_H,
+ .datasheet_name = "GPADC",
+ }, {
+ .indexed = 1,
+ .type = IIO_CURRENT,
+ .channel = 3,
+ .address = AXP20X_BATT_CHRG_I_H,
+ .datasheet_name = "BATT_CHG_I",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .indexed = 1,
+ .type = IIO_CURRENT,
+ .channel = 4,
+ .address = AXP20X_BATT_DISCHRG_I_H,
+ .datasheet_name = "BATT_DISCHRG_I",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .indexed = 1,
+ .type = IIO_VOLTAGE,
+ .channel = 5,
+ .address = AXP20X_BATT_V_H,
+ .datasheet_name = "BATT_V",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+};
+
+#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
+ _consumer_channel) \
+ { \
+ .adc_channel_label = _adc_channel_label, \
+ .consumer_dev_name = _consumer_dev_name, \
+ .consumer_channel = _consumer_channel, \
+ }
+
+/* for consumer drivers */
+static struct iio_map axp288_adc_default_maps[] = {
+ AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
+ AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
+ AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
+ AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
+ AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
+ AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
+ {},
+};
+
+static int axp288_adc_read_channel(int *val, unsigned long address,
+ struct regmap *regmap)
+{
+ u8 buf[2];
+
+ if (regmap_bulk_read(regmap, address, buf, 2))
+ return -EIO;
+ *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
+
+ return IIO_VAL_INT;
+}
+
+static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
+ unsigned long address)
+{
+ /* channels other than GPADC do not need to switch TS pin */
+ if (address != AXP288_GP_ADC_H)
+ return 0;
+
+ return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
+}
+
+static int axp288_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+ struct axp288_adc_info *info = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
+ chan->address)) {
+ dev_err(&indio_dev->dev, "GPADC mode\n");
+ ret = -EINVAL;
+ break;
+ }
+ ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+ if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
+ chan->address))
+ dev_err(&indio_dev->dev, "TS pin restore\n");
+ break;
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static int axp288_adc_set_state(struct regmap *regmap)
+{
+ /* ADC should be always enabled for internal FG to function */
+ if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
+ return -EIO;
+
+ return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
+}
+
+static const struct iio_info axp288_adc_iio_info = {
+ .read_raw = &axp288_adc_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int axp288_adc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct axp288_adc_info *info;
+ struct iio_dev *indio_dev;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return info->irq;
+ }
+ platform_set_drvdata(pdev, indio_dev);
+ info->regmap = axp20x->regmap;
+ /*
+ * Set ADC to enabled state at all time, including system suspend.
+ * otherwise internal fuel gauge functionality may be affected.
+ */
+ ret = axp288_adc_set_state(axp20x->regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable ADC device\n");
+ return ret;
+ }
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->name = pdev->name;
+ indio_dev->channels = axp288_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
+ indio_dev->info = &axp288_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
+ if (ret < 0)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register iio device\n");
+ goto err_array_unregister;
+ }
+ return 0;
+
+err_array_unregister:
+ iio_map_array_unregister(indio_dev);
+
+ return ret;
+}
+
+static int axp288_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+ iio_map_array_unregister(indio_dev);
+
+ return 0;
+}
+
+static struct platform_device_id axp288_adc_id_table[] = {
+ { .name = "axp288_adc" },
+ {},
+};
+
+static struct platform_driver axp288_adc_driver = {
+ .probe = axp288_adc_probe,
+ .remove = axp288_adc_remove,
+ .id_table = axp288_adc_id_table,
+ .driver = {
+ .name = "axp288_adc",
+ },
+};
+
+MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
+
+module_platform_driver(axp288_adc_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
+MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
+MODULE_LICENSE("GPL");
static const struct mcb_device_id men_z188_ids[] = {
{ .device = 0xbc },
+ { }
};
MODULE_DEVICE_TABLE(mcb, men_z188_ids);
#define BMG160_REG_INT_EN_0 0x15
#define BMG160_DATA_ENABLE_INT BIT(7)
+#define BMG160_REG_INT_EN_1 0x16
+#define BMG160_INT1_BIT_OD BIT(1)
+
#define BMG160_REG_XOUT_L 0x02
#define BMG160_AXIS_TO_REG(axis) (BMG160_REG_XOUT_L + (axis * 2))
#define BMG160_REG_INT_STATUS_2 0x0B
#define BMG160_ANY_MOTION_MASK 0x07
+#define BMG160_ANY_MOTION_BIT_X BIT(0)
+#define BMG160_ANY_MOTION_BIT_Y BIT(1)
+#define BMG160_ANY_MOTION_BIT_Z BIT(2)
#define BMG160_REG_TEMP 0x08
#define BMG160_TEMP_CENTER_VAL 23
data->slope_thres = ret;
/* Set default interrupt mode */
+ ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_int_en_1\n");
+ return ret;
+ }
+ ret &= ~BMG160_INT1_BIT_OD;
+ ret = i2c_smbus_write_byte_data(data->client,
+ BMG160_REG_INT_EN_1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
+ return ret;
+ }
+
ret = i2c_smbus_write_byte_data(data->client,
BMG160_REG_INT_RST_LATCH,
BMG160_INT_MODE_LATCH_INT |
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: bmg160_set_power_state for %d\n", on);
+ if (on)
+ pm_runtime_put_noidle(&data->client->dev);
+
return ret;
}
#endif
ret = bmg160_setup_any_motion_interrupt(data, state);
if (ret < 0) {
+ bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
static const struct iio_event_spec bmg160_event = {
.type = IIO_EV_TYPE_ROC,
- .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
+ .dir = IIO_EV_DIR_EITHER,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE)
};
else
ret = bmg160_setup_new_data_interrupt(data, state);
if (ret < 0) {
+ bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
else
dir = IIO_EV_DIR_FALLING;
- if (ret & BMG160_ANY_MOTION_MASK)
+ if (ret & BMG160_ANY_MOTION_BIT_X)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
- IIO_MOD_X_OR_Y_OR_Z,
+ IIO_MOD_X,
+ IIO_EV_TYPE_ROC,
+ dir),
+ data->timestamp);
+ if (ret & BMG160_ANY_MOTION_BIT_Y)
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
+ 0,
+ IIO_MOD_Y,
+ IIO_EV_TYPE_ROC,
+ dir),
+ data->timestamp);
+ if (ret & BMG160_ANY_MOTION_BIT_Z)
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
+ 0,
+ IIO_MOD_Z,
IIO_EV_TYPE_ROC,
dir),
data->timestamp);
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct bmg160_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "set mode failed\n");
+ return -EAGAIN;
+ }
- return bmg160_set_mode(data, BMG160_MODE_SUSPEND);
+ return 0;
}
static int bmg160_runtime_resume(struct device *dev)
attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS;
/*
* FIXME: Use devattr.max_sge - 2 for max_send_sge as
- * work-around for RDMA_READ..
+ * work-around for RDMA_READs with ConnectX-2.
+ *
+ * Also, still make sure to have at least two SGEs for
+ * outgoing control PDU responses.
*/
- attr.cap.max_send_sge = device->dev_attr.max_sge - 2;
+ attr.cap.max_send_sge = max(2, device->dev_attr.max_sge - 2);
isert_conn->max_sge = attr.cap.max_send_sge;
attr.cap.max_recv_sge = 1;
struct isert_cq_desc *cq_desc;
struct ib_device_attr *dev_attr;
int ret = 0, i, j;
+ int max_rx_cqe, max_tx_cqe;
dev_attr = &device->dev_attr;
ret = isert_query_device(ib_dev, dev_attr);
if (ret)
return ret;
+ max_rx_cqe = min(ISER_MAX_RX_CQ_LEN, dev_attr->max_cqe);
+ max_tx_cqe = min(ISER_MAX_TX_CQ_LEN, dev_attr->max_cqe);
+
/* asign function handlers */
if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS &&
dev_attr->device_cap_flags & IB_DEVICE_SIGNATURE_HANDOVER) {
isert_cq_rx_callback,
isert_cq_event_callback,
(void *)&cq_desc[i],
- ISER_MAX_RX_CQ_LEN, i);
+ max_rx_cqe, i);
if (IS_ERR(device->dev_rx_cq[i])) {
ret = PTR_ERR(device->dev_rx_cq[i]);
device->dev_rx_cq[i] = NULL;
isert_cq_tx_callback,
isert_cq_event_callback,
(void *)&cq_desc[i],
- ISER_MAX_TX_CQ_LEN, i);
+ max_tx_cqe, i);
if (IS_ERR(device->dev_tx_cq[i])) {
ret = PTR_ERR(device->dev_tx_cq[i]);
device->dev_tx_cq[i] = NULL;
complete(&isert_conn->conn_wait);
}
-static void
+static int
isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect)
{
- struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
+ struct isert_conn *isert_conn;
+
+ if (!cma_id->qp) {
+ struct isert_np *isert_np = cma_id->context;
+
+ isert_np->np_cm_id = NULL;
+ return -1;
+ }
+
+ isert_conn = (struct isert_conn *)cma_id->context;
isert_conn->disconnect = disconnect;
INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
schedule_work(&isert_conn->conn_logout_work);
+
+ return 0;
}
static int
switch (event->event) {
case RDMA_CM_EVENT_CONNECT_REQUEST:
ret = isert_connect_request(cma_id, event);
+ if (ret)
+ pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n",
+ event->event, ret);
break;
case RDMA_CM_EVENT_ESTABLISHED:
isert_connected_handler(cma_id);
case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */
disconnect = true;
case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */
- isert_disconnected_handler(cma_id, disconnect);
+ ret = isert_disconnected_handler(cma_id, disconnect);
break;
case RDMA_CM_EVENT_CONNECT_ERROR:
default:
break;
}
- if (ret != 0) {
- pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n",
- event->event, ret);
- dump_stack();
- }
-
return ret;
}
{
struct isert_np *isert_np = (struct isert_np *)np->np_context;
- rdma_destroy_id(isert_np->np_cm_id);
+ if (isert_np->np_cm_id)
+ rdma_destroy_id(isert_np->np_cm_id);
np->np_context = NULL;
kfree(isert_np);
if (!qp_init)
goto out;
+retry:
ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch,
ch->rq_size + srp_sq_size, 0);
if (IS_ERR(ch->cq)) {
ch->qp = ib_create_qp(sdev->pd, qp_init);
if (IS_ERR(ch->qp)) {
ret = PTR_ERR(ch->qp);
+ if (ret == -ENOMEM) {
+ srp_sq_size /= 2;
+ if (srp_sq_size >= MIN_SRPT_SQ_SIZE) {
+ ib_destroy_cq(ch->cq);
+ goto retry;
+ }
+ }
printk(KERN_ERR "failed to create_qp ret= %d\n", ret);
goto err_destroy_cq;
}
err_free_client:
evdev_detach_client(evdev, client);
- kfree(client);
+ kvfree(client);
return error;
}
}
ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
- usb_fill_bulk_urb(xpad->bulk_out, udev,
- usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
- xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
+ if (usb_endpoint_is_bulk_out(ep_irq_in)) {
+ usb_fill_bulk_urb(xpad->bulk_out, udev,
+ usb_sndbulkpipe(udev,
+ ep_irq_in->bEndpointAddress),
+ xpad->bdata, XPAD_PKT_LEN,
+ xpad_bulk_out, xpad);
+ } else {
+ usb_fill_int_urb(xpad->bulk_out, udev,
+ usb_sndintpipe(udev,
+ ep_irq_in->bEndpointAddress),
+ xpad->bdata, XPAD_PKT_LEN,
+ xpad_bulk_out, xpad, 0);
+ }
/*
* Submit the int URB immediately rather than waiting for open
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
#define DRV_NAME "gpio-keys-polled"
int state;
if (bdata->can_sleep)
- state = !!gpio_get_value_cansleep(button->gpio);
+ state = !!gpiod_get_value_cansleep(button->gpiod);
else
- state = !!gpio_get_value(button->gpio);
+ state = !!gpiod_get_value(button->gpiod);
if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;
- input_event(input, type, button->code,
- !!(state ^ button->active_low));
+ input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
pdata->disable(bdev->dev);
}
-#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
+ struct fwnode_handle *child;
int error;
int nbuttons;
- int i;
-
- node = dev->of_node;
- if (!node)
- return NULL;
- nbuttons = of_get_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;
- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
- of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+ pdata->rep = device_property_present(dev, "autorepeat");
+ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
- i = 0;
- for_each_child_of_node(node, pp) {
- int gpio;
- enum of_gpio_flags flags;
+ device_for_each_child_node(dev, child) {
+ struct gpio_desc *desc;
- if (!of_find_property(pp, "gpios", NULL)) {
- pdata->nbuttons--;
- dev_warn(dev, "Found button without gpios\n");
- continue;
- }
-
- gpio = of_get_gpio_flags(pp, 0, &flags);
- if (gpio < 0) {
- error = gpio;
+ desc = devm_get_gpiod_from_child(dev, child);
+ if (IS_ERR(desc)) {
+ error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
+ fwnode_handle_put(child);
return ERR_PTR(error);
}
- button = &pdata->buttons[i++];
-
- button->gpio = gpio;
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ button = &pdata->buttons[pdata->nbuttons++];
+ button->gpiod = desc;
- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
+ dev_err(dev, "Button without keycode: %d\n",
+ pdata->nbuttons - 1);
+ fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
- button->desc = of_get_property(pp, "label", NULL);
+ fwnode_property_read_string(child, "label", &button->desc);
- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &button->type))
button->type = EV_KEY;
- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+ button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
- if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ if (fwnode_property_read_u32(child, "debounce-interval",
+ &button->debounce_interval))
button->debounce_interval = 5;
}
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
- unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
return -EINVAL;
}
- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
- button->desc ? : DRV_NAME);
- if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
- gpio, error);
- return error;
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
+ if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ unsigned flags = 0;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ error = devm_gpio_request_one(&pdev->dev, button->gpio,
+ flags, button->desc ? : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ button->gpio, error);
+ return error;
+ }
+
+ button->gpiod = gpio_to_desc(button->gpio);
}
- bdata->can_sleep = gpio_cansleep(gpio);
+ if (IS_ERR(button->gpiod))
+ return PTR_ERR(button->gpiod);
+
+ bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+ .of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
int x, y;
u32 t;
- if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev,
- !tp_dev,
- psmouse_fmt("Unexpected trackpoint message\n"))) {
- if (etd->debug == 1)
- elantech_packet_dump(psmouse);
- return;
- }
-
t = get_unaligned_le32(&packet[0]);
switch (t & ~7U) {
unsigned char packet_type = packet[3] & 0x03;
bool sanity_check;
- if ((packet[3] & 0x0f) == 0x06)
+ if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
return PACKET_TRACKPOINT;
/*
(const char * const []){"LEN2001", NULL},
1024, 5022, 2508, 4832
},
+ {
+ (const char * const []){"LEN2006", NULL},
+ 1264, 5675, 1171, 4688
+ },
{ }
};
}
ret = irq_alloc_domain_generic_chips(domain, 32, 1, name,
- handle_level_irq, 0, 0,
- IRQCHIP_SKIP_SET_WAKE);
+ handle_fasteoi_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE |
+ IRQ_NOAUTOEN, 0, 0);
if (ret)
goto err_domain_remove;
gc->unused = 0;
gc->wake_enabled = ~0;
gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK;
- gc->chip_types[0].handler = handle_fasteoi_irq;
gc->chip_types[0].chip.irq_eoi = irq_gc_eoi;
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown;
int parent_irq;
parent_irq = irq_of_parse_and_map(dn, irq);
- if (parent_irq < 0) {
+ if (!parent_irq) {
pr_err("failed to map interrupt %d\n", irq);
- return parent_irq;
+ return -EINVAL;
}
data->irq_map_mask |= be32_to_cpup(map_mask + irq);
__raw_writel(0xffffffff, data->base + CPU_CLEAR);
data->parent_irq = irq_of_parse_and_map(np, 0);
- if (data->parent_irq < 0) {
+ if (!data->parent_irq) {
pr_err("failed to find parent interrupt\n");
- ret = data->parent_irq;
+ ret = -EINVAL;
goto out_unmap;
}
*/
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
- unsigned gpio;
+ struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
- u8 active_low;
u8 blinking;
- int (*platform_gpio_blink_set)(unsigned gpio, int state,
+ int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio,
- led_dat->new_level,
- NULL, NULL);
+ led_dat->platform_gpio_blink_set(led_dat->gpiod,
+ led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
- if (led_dat->active_low)
- level = !level;
-
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio, level,
+ led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value(led_dat->gpio, level);
+ gpiod_set_value(led_dat->gpiod, level);
}
}
container_of(led_cdev, struct gpio_led_data, cdev);
led_dat->blinking = 1;
- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+ return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
delay_on, delay_off);
}
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
+ int (*blink_set)(struct gpio_desc *, int, unsigned long *,
+ unsigned long *))
{
int ret, state;
- led_dat->gpio = -1;
+ led_dat->gpiod = template->gpiod;
+ if (!led_dat->gpiod) {
+ /*
+ * This is the legacy code path for platform code that
+ * still uses GPIO numbers. Ultimately we would like to get
+ * rid of this block completely.
+ */
+ unsigned long flags = 0;
+
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ return 0;
+ }
- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
- }
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
- ret = devm_gpio_request(parent, template->gpio, template->name);
- if (ret < 0)
- return ret;
+ ret = devm_gpio_request_one(parent, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->gpiod = gpio_to_desc(template->gpio);
+ if (IS_ERR(led_dat->gpiod))
+ return PTR_ERR(led_dat->gpiod);
+ }
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
- led_dat->gpio = template->gpio;
- led_dat->can_sleep = gpio_cansleep(template->gpio);
- led_dat->active_low = template->active_low;
+ led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, gpio_led_work);
- ret = led_classdev_register(parent, &led_dat->cdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return led_classdev_register(parent, &led_dat->cdev);
}
static void delete_gpio_led(struct gpio_led_data *led)
{
- if (!gpio_is_valid(led->gpio))
- return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
(sizeof(struct gpio_led_data) * num_leds);
}
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
+ struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;
+ struct device_node *np;
- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
-
- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ const char *state = NULL;
+
+ led.gpiod = devm_get_gpiod_from_child(dev, child);
+ if (IS_ERR(led.gpiod)) {
+ fwnode_handle_put(child);
+ goto err;
+ }
+
+ np = of_node(child);
+
+ if (fwnode_property_present(child, "label")) {
+ fwnode_property_read_string(child, "label", &led.name);
+ } else {
+ if (IS_ENABLED(CONFIG_OF) && !led.name && np)
+ led.name = np->name;
+ if (!led.name)
+ return ERR_PTR(-EINVAL);
+ }
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!fwnode_property_read_string(child, "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ fwnode_handle_put(child);
goto err;
}
}
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
static int gpio_led_probe(struct platform_device *pdev)
{
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
ret = smiapp_set_compose(subdev, fh, sel);
break;
default:
- BUG();
+ ret = -EINVAL;
}
mutex_unlock(&sensor->mutex);
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (lpi && line > 0 && !(line % lpi))
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg)-offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++) = cpu_to_le32(sg_dma_address(sg));
if (!status)
return IRQ_NONE;
- if (status & ~solo_dev->irq_mask) {
- solo_reg_write(solo_dev, SOLO_IRQ_STAT,
- status & ~solo_dev->irq_mask);
- status &= solo_dev->irq_mask;
- }
+ /* Acknowledge all interrupts immediately */
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
if (status & SOLO_IRQ_PCI_ERR)
solo_p2m_error_isr(solo_dev);
if (status & SOLO_IRQ_G723)
solo_g723_isr(solo_dev);
- /* Clear all interrupts handled */
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
-
return IRQ_HANDLED;
}
case 32:
if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
protocol = RC_TYPE_RC6_MCE;
- scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
} else {
protocol = RC_BIT_RC6_6A_32;
toggle = 0;
break;
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_MJPEG:
- buf->vb.v4l2_buf.length = jpgsize;
+ vb2_set_plane_payload(&buf->vb, 0, jpgsize);
memcpy(vbuf, tmpbuf, jpgsize);
break;
case V4L2_PIX_FMT_YUV422P:
select REGMAP_IRQ
depends on I2C=y
help
- If you say Y here you get support for the X-Powers AXP202 and AXP209.
+ If you say Y here you get support for the X-Powers AXP202, AXP209 and
+ AXP288 power management IC (PMIC).
This driver include only the core APIs. You have to select individual
components like regulators or the PEK (Power Enable Key) under the
corresponding menus.
/*
- * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ * axp20x.c - MFD core driver for the X-Powers' Power Management ICs
*
- * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
- * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
- * as well as 4 configurable GPIOs.
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
*
* Author: Carlo Caione <carlo@caione.org>
*
#include <linux/mfd/core.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/acpi.h>
#define AXP20X_OFF 0x80
+static const char const *axp20x_model_names[] = {
+ "AXP202",
+ "AXP209",
+ "AXP288",
+};
+
static const struct regmap_range axp20x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
+static const struct regmap_range axp288_writeable_ranges[] = {
+ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
+};
+
+static const struct regmap_range axp288_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
+};
+
+static const struct regmap_access_table axp288_writeable_table = {
+ .yes_ranges = axp288_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges),
+};
+
+static const struct regmap_access_table axp288_volatile_table = {
+ .yes_ranges = axp288_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
+};
+
static struct resource axp20x_pek_resources[] = {
{
.name = "PEK_DBR",
},
};
+static struct resource axp288_battery_resources[] = {
+ {
+ .start = AXP288_IRQ_QWBTU,
+ .end = AXP288_IRQ_QWBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WBTU,
+ .end = AXP288_IRQ_WBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QWBTO,
+ .end = AXP288_IRQ_QWBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WBTO,
+ .end = AXP288_IRQ_WBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WL2,
+ .end = AXP288_IRQ_WL2,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WL1,
+ .end = AXP288_IRQ_WL1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static const struct regmap_config axp20x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
};
-#define AXP20X_IRQ(_irq, _off, _mask) \
- [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+static const struct regmap_config axp288_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp288_writeable_table,
+ .volatile_table = &axp288_volatile_table,
+ .max_register = AXP288_FG_TUNE5,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
+ [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
static const struct regmap_irq axp20x_regmap_irqs[] = {
- AXP20X_IRQ(ACIN_OVER_V, 0, 7),
- AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
- AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
- AXP20X_IRQ(VBUS_OVER_V, 0, 4),
- AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
- AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
- AXP20X_IRQ(VBUS_V_LOW, 0, 1),
- AXP20X_IRQ(BATT_PLUGIN, 1, 7),
- AXP20X_IRQ(BATT_REMOVAL, 1, 6),
- AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
- AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
- AXP20X_IRQ(CHARG, 1, 3),
- AXP20X_IRQ(CHARG_DONE, 1, 2),
- AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
- AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
- AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
- AXP20X_IRQ(CHARG_I_LOW, 2, 6),
- AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
- AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
- AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
- AXP20X_IRQ(PEK_SHORT, 2, 1),
- AXP20X_IRQ(PEK_LONG, 2, 0),
- AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
- AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
- AXP20X_IRQ(VBUS_VALID, 3, 5),
- AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
- AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
- AXP20X_IRQ(VBUS_SESS_END, 3, 2),
- AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
- AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
- AXP20X_IRQ(TIMER, 4, 7),
- AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
- AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
- AXP20X_IRQ(GPIO3_INPUT, 4, 3),
- AXP20X_IRQ(GPIO2_INPUT, 4, 2),
- AXP20X_IRQ(GPIO1_INPUT, 4, 1),
- AXP20X_IRQ(GPIO0_INPUT, 4, 0),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
+ INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
+ INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5),
+ INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4),
+ INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
+ INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1),
+ INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7),
+ INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6),
+ INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5),
+ INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4),
+ INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3),
+ INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1),
+ INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0),
+ INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7),
+ INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2),
+ INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
+ INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6),
+ INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5),
+ INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3),
+ INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2),
+ INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1),
+ INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
+};
+
+/* some IRQs are compatible with axp20x models */
+static const struct regmap_irq axp288_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2),
+ INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3),
+ INIT_REGMAP_IRQ(AXP288, OV, 0, 4),
+
+ INIT_REGMAP_IRQ(AXP288, DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
+ INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
+ INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
+ INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6),
+ INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7),
+
+ INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0),
+ INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1),
+ INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2),
+ INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3),
+ INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4),
+ INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5),
+ INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6),
+ INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7),
+
+ INIT_REGMAP_IRQ(AXP288, WL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP288, WL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2),
+ INIT_REGMAP_IRQ(AXP288, OT, 3, 7),
+
+ INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0),
+ INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1),
+ INIT_REGMAP_IRQ(AXP288, POKO, 4, 2),
+ INIT_REGMAP_IRQ(AXP288, POKL, 4, 3),
+ INIT_REGMAP_IRQ(AXP288, POKS, 4, 4),
+ INIT_REGMAP_IRQ(AXP288, POKN, 4, 5),
+ INIT_REGMAP_IRQ(AXP288, POKP, 4, 6),
+ INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7),
+
+ INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0),
+ INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
static const struct of_device_id axp20x_of_match[] = {
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
+static struct acpi_device_id axp20x_acpi_match[] = {
+ {
+ .id = "INT33F4",
+ .driver_data = AXP288_ID,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
+
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
.name = "axp20x_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
.ack_base = AXP20X_IRQ1_STATE,
.mask_base = AXP20X_IRQ1_EN,
- .num_regs = 5,
+ .mask_invert = true,
+ .init_ack_masked = true,
.irqs = axp20x_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
+ .num_regs = 5,
+
+};
+
+static const struct regmap_irq_chip axp288_regmap_irq_chip = {
+ .name = "axp288_irq_chip",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
.mask_invert = true,
.init_ack_masked = true,
+ .irqs = axp288_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp288_regmap_irqs),
+ .num_regs = 6,
+
};
static struct mfd_cell axp20x_cells[] = {
},
};
+static struct resource axp288_adc_resources[] = {
+ {
+ .name = "GPADC",
+ .start = AXP288_IRQ_GPADC,
+ .end = AXP288_IRQ_GPADC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource axp288_charger_resources[] = {
+ {
+ .start = AXP288_IRQ_OV,
+ .end = AXP288_IRQ_OV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_DONE,
+ .end = AXP288_IRQ_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CHARGING,
+ .end = AXP288_IRQ_CHARGING,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_SAFE_QUIT,
+ .end = AXP288_IRQ_SAFE_QUIT,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_SAFE_ENTER,
+ .end = AXP288_IRQ_SAFE_ENTER,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QCBTU,
+ .end = AXP288_IRQ_QCBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CBTU,
+ .end = AXP288_IRQ_CBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QCBTO,
+ .end = AXP288_IRQ_QCBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CBTO,
+ .end = AXP288_IRQ_CBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell axp288_cells[] = {
+ {
+ .name = "axp288_adc",
+ .num_resources = ARRAY_SIZE(axp288_adc_resources),
+ .resources = axp288_adc_resources,
+ },
+ {
+ .name = "axp288_charger",
+ .num_resources = ARRAY_SIZE(axp288_charger_resources),
+ .resources = axp288_charger_resources,
+ },
+ {
+ .name = "axp288_battery",
+ .num_resources = ARRAY_SIZE(axp288_battery_resources),
+ .resources = axp288_battery_resources,
+ },
+ {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
static struct axp20x_dev *axp20x_pm_power_off;
static void axp20x_power_off(void)
{
+ if (axp20x_pm_power_off->variant == AXP288_ID)
+ return;
+
regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
AXP20X_OFF);
}
+static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
+{
+ const struct acpi_device_id *acpi_id;
+ const struct of_device_id *of_id;
+
+ if (dev->of_node) {
+ of_id = of_match_device(axp20x_of_match, dev);
+ if (!of_id) {
+ dev_err(dev, "Unable to match OF ID\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long) of_id->data;
+ } else {
+ acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!acpi_id || !acpi_id->driver_data) {
+ dev_err(dev, "Unable to match ACPI ID and data\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long) acpi_id->driver_data;
+ }
+
+ switch (axp20x->variant) {
+ case AXP202_ID:
+ case AXP209_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
+ axp20x->cells = axp20x_cells;
+ axp20x->regmap_cfg = &axp20x_regmap_config;
+ axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
+ break;
+ case AXP288_ID:
+ axp20x->cells = axp288_cells;
+ axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
+ break;
+ default:
+ dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
+ return -EINVAL;
+ }
+ dev_info(dev, "AXP20x variant %s found\n",
+ axp20x_model_names[axp20x->variant]);
+
+ return 0;
+}
+
static int axp20x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct axp20x_dev *axp20x;
- const struct of_device_id *of_id;
int ret;
axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
if (!axp20x)
return -ENOMEM;
- of_id = of_match_device(axp20x_of_match, &i2c->dev);
- if (!of_id) {
- dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
- return -ENODEV;
- }
- axp20x->variant = (long) of_id->data;
+ ret = axp20x_match_device(axp20x, &i2c->dev);
+ if (ret)
+ return ret;
axp20x->i2c_client = i2c;
axp20x->dev = &i2c->dev;
dev_set_drvdata(axp20x->dev, axp20x);
- axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
+ axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
if (IS_ERR(axp20x->regmap)) {
ret = PTR_ERR(axp20x->regmap);
dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
IRQF_ONESHOT | IRQF_SHARED, -1,
- &axp20x_regmap_irq_chip,
+ axp20x->regmap_irq_chip,
&axp20x->regmap_irqc);
if (ret) {
dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
return ret;
}
- ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
- ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+ ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
+ axp20x->nr_cells, NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
.name = "axp20x",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(axp20x_of_match),
+ .acpi_match_table = ACPI_PTR(axp20x_acpi_match),
},
.probe = axp20x_i2c_probe,
.remove = axp20x_i2c_remove,
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = gpio_resources,
},
+ {
+ .name = "crystal_cove_pmic",
+ },
};
static struct regmap_config crystal_cove_regmap_config = {
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <linux/of.h>
+#include <linux/property.h>
/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
/*-------------------------------------------------------------------------*/
-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));
- if (of_property_read_u32(np, "size", &val) == 0 ||
- of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+ if (device_property_read_u32(dev, "size", &val) == 0 ||
+ device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
chip->byte_len = val;
} else {
dev_err(dev, "Error: missing \"size\" property\n");
return -ENODEV;
}
- if (of_property_read_u32(np, "pagesize", &val) == 0 ||
- of_property_read_u32(np, "at25,page-size", &val) == 0) {
+ if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
+ device_property_read_u32(dev, "at25,page-size", &val) == 0) {
chip->page_size = (u16)val;
} else {
dev_err(dev, "Error: missing \"pagesize\" property\n");
return -ENODEV;
}
- if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+ if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
chip->flags = (u16)val;
} else {
- if (of_property_read_u32(np, "address-width", &val)) {
+ if (device_property_read_u32(dev, "address-width", &val)) {
dev_err(dev,
"Error: missing \"address-width\" property\n");
return -ENODEV;
val);
return -ENODEV;
}
- if (of_find_property(np, "read-only", NULL))
+ if (device_property_present(dev, "read-only"))
chip->flags |= EE_READONLY;
}
return 0;
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
- struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;
/* Chip description */
if (!spi->dev.platform_data) {
- if (np) {
- err = at25_np_to_chip(&spi->dev, np, &chip);
- if (err)
- return err;
- } else {
- dev_err(&spi->dev, "Error: no chip description\n");
- return -ENODEV;
- }
+ err = at25_fw_to_chip(&spi->dev, &chip);
+ if (err)
+ return err;
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
bond_slave_state_change(bond);
if (BOND_MODE(bond) == BOND_MODE_XOR)
bond_update_slave_arr(bond, NULL);
- } else if (do_failover) {
+ }
+ if (do_failover) {
block_netpoll_tx();
bond_select_active_slave(bond);
unblock_netpoll_tx();
bond_option_arp_ip_targets_clear(bond);
nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
- __be32 target = nla_get_be32(attr);
+ __be32 target;
+
+ if (nla_len(attr) < sizeof(target))
+ return -EINVAL;
+
+ target = nla_get_be32(attr);
bond_opt_initval(&newval, (__force u64)target);
err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
long rate;
u64 v64;
- /* Use CIA recommended sample points */
+ /* Use CiA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
} else {
BUG_ON(idx >= priv->echo_skb_max);
if (priv->echo_skb[idx]) {
- kfree_skb(priv->echo_skb[idx]);
+ dev_kfree_skb_any(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
}
}
config CAN_M_CAN
+ depends on HAS_IOMEM
tristate "Bosch M_CAN devices"
---help---
Say Y here if you want to support for Bosch M_CAN controller.
MRAM_CFG_NUM,
};
+/* Fast Bit Timing & Prescaler Register (FBTP) */
+#define FBTR_FBRP_MASK 0x1f
+#define FBTR_FBRP_SHIFT 16
+#define FBTR_FTSEG1_SHIFT 8
+#define FBTR_FTSEG1_MASK (0xf << FBTR_FTSEG1_SHIFT)
+#define FBTR_FTSEG2_SHIFT 4
+#define FBTR_FTSEG2_MASK (0x7 << FBTR_FTSEG2_SHIFT)
+#define FBTR_FSJW_SHIFT 0
+#define FBTR_FSJW_MASK 0x3
+
/* Test Register (TEST) */
#define TEST_LBCK BIT(4)
/* CC Control Register(CCCR) */
-#define CCCR_TEST BIT(7)
-#define CCCR_MON BIT(5)
-#define CCCR_CCE BIT(1)
-#define CCCR_INIT BIT(0)
+#define CCCR_TEST BIT(7)
+#define CCCR_CMR_MASK 0x3
+#define CCCR_CMR_SHIFT 10
+#define CCCR_CMR_CANFD 0x1
+#define CCCR_CMR_CANFD_BRS 0x2
+#define CCCR_CMR_CAN 0x3
+#define CCCR_CME_MASK 0x3
+#define CCCR_CME_SHIFT 8
+#define CCCR_CME_CAN 0
+#define CCCR_CME_CANFD 0x1
+#define CCCR_CME_CANFD_BRS 0x2
+#define CCCR_TEST BIT(7)
+#define CCCR_MON BIT(5)
+#define CCCR_CCE BIT(1)
+#define CCCR_INIT BIT(0)
+#define CCCR_CANFD 0x10
/* Bit Timing & Prescaler Register (BTP) */
#define BTR_BRP_MASK 0x3ff
/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
#define M_CAN_RXESC_8BYTES 0x0
+#define M_CAN_RXESC_64BYTES 0x777
/* Tx Buffer Configuration(TXBC) */
#define TXBC_NDTB_OFF 16
/* Tx Buffer Element Size Configuration(TXESC) */
#define TXESC_TBDS_8BYTES 0x0
+#define TXESC_TBDS_64BYTES 0x7
/* Tx Event FIFO Con.guration (TXEFC) */
#define TXEFC_EFS_OFF 16
/* Message RAM Configuration (in bytes) */
#define SIDF_ELEMENT_SIZE 4
#define XIDF_ELEMENT_SIZE 8
-#define RXF0_ELEMENT_SIZE 16
-#define RXF1_ELEMENT_SIZE 16
+#define RXF0_ELEMENT_SIZE 72
+#define RXF1_ELEMENT_SIZE 72
#define RXB_ELEMENT_SIZE 16
#define TXE_ELEMENT_SIZE 8
-#define TXB_ELEMENT_SIZE 16
+#define TXB_ELEMENT_SIZE 72
/* Message RAM Elements */
#define M_CAN_FIFO_ID 0x0
#define M_CAN_FIFO_DATA(n) (0x8 + ((n) << 2))
/* Rx Buffer Element */
+/* R0 */
#define RX_BUF_ESI BIT(31)
#define RX_BUF_XTD BIT(30)
#define RX_BUF_RTR BIT(29)
+/* R1 */
+#define RX_BUF_ANMF BIT(31)
+#define RX_BUF_EDL BIT(21)
+#define RX_BUF_BRS BIT(20)
/* Tx Buffer Element */
+/* R0 */
#define TX_BUF_XTD BIT(30)
#define TX_BUF_RTR BIT(29)
if (enable) {
/* enable m_can configuration */
m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT);
+ udelay(5);
/* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
} else {
m_can_write(priv, M_CAN_ILE, 0x0);
}
-static void m_can_read_fifo(const struct net_device *dev, struct can_frame *cf,
- u32 rxfs)
+static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
{
+ struct net_device_stats *stats = &dev->stats;
struct m_can_priv *priv = netdev_priv(dev);
- u32 id, fgi;
+ struct canfd_frame *cf;
+ struct sk_buff *skb;
+ u32 id, fgi, dlc;
+ int i;
/* calculate the fifo get index for where to read data */
fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF;
+ dlc = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
+ if (dlc & RX_BUF_EDL)
+ skb = alloc_canfd_skb(dev, &cf);
+ else
+ skb = alloc_can_skb(dev, (struct can_frame **)&cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ if (dlc & RX_BUF_EDL)
+ cf->len = can_dlc2len((dlc >> 16) & 0x0F);
+ else
+ cf->len = get_can_dlc((dlc >> 16) & 0x0F);
+
id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_ID);
if (id & RX_BUF_XTD)
cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = (id >> 18) & CAN_SFF_MASK;
- if (id & RX_BUF_RTR) {
+ if (id & RX_BUF_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(dev, "ESI Error\n");
+ }
+
+ if (!(dlc & RX_BUF_EDL) && (id & RX_BUF_RTR)) {
cf->can_id |= CAN_RTR_FLAG;
} else {
- id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
- cf->can_dlc = get_can_dlc((id >> 16) & 0x0F);
- *(u32 *)(cf->data + 0) = m_can_fifo_read(priv, fgi,
- M_CAN_FIFO_DATA(0));
- *(u32 *)(cf->data + 4) = m_can_fifo_read(priv, fgi,
- M_CAN_FIFO_DATA(1));
+ if (dlc & RX_BUF_BRS)
+ cf->flags |= CANFD_BRS;
+
+ for (i = 0; i < cf->len; i += 4)
+ *(u32 *)(cf->data + i) =
+ m_can_fifo_read(priv, fgi,
+ M_CAN_FIFO_DATA(i / 4));
}
/* acknowledge rx fifo 0 */
m_can_write(priv, M_CAN_RXF0A, fgi);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+
+ netif_receive_skb(skb);
}
static int m_can_do_rx_poll(struct net_device *dev, int quota)
{
struct m_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
- struct can_frame *frame;
u32 pkts = 0;
u32 rxfs;
if (rxfs & RXFS_RFL)
netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
- skb = alloc_can_skb(dev, &frame);
- if (!skb) {
- stats->rx_dropped++;
- return pkts;
- }
-
- m_can_read_fifo(dev, frame, rxfs);
-
- stats->rx_packets++;
- stats->rx_bytes += frame->can_dlc;
-
- netif_receive_skb(skb);
+ m_can_read_fifo(dev, rxfs);
quota--;
pkts++;
return 1;
}
+static int __m_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct m_can_priv *priv = netdev_priv(dev);
+ unsigned int ecr;
+
+ ecr = m_can_read(priv, M_CAN_ECR);
+ bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
+ bec->txerr = ecr & ECR_TEC_MASK;
+
+ return 0;
+}
+
static int m_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct m_can_priv *priv = netdev_priv(dev);
- unsigned int ecr;
int err;
err = clk_prepare_enable(priv->hclk);
return err;
}
- ecr = m_can_read(priv, M_CAN_ECR);
- bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
- bec->txerr = ecr & ECR_TEC_MASK;
+ __m_can_get_berr_counter(dev, bec);
clk_disable_unprepare(priv->cclk);
clk_disable_unprepare(priv->hclk);
if (unlikely(!skb))
return 0;
- m_can_get_berr_counter(dev, &bec);
+ __m_can_get_berr_counter(dev, &bec);
switch (new_state) {
case CAN_STATE_ERROR_ACTIVE:
if ((psr & PSR_EP) &&
(priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
- netdev_dbg(dev, "entered error warning state\n");
+ netdev_dbg(dev, "entered error passive state\n");
work_done += m_can_handle_state_change(dev,
CAN_STATE_ERROR_PASSIVE);
}
if ((psr & PSR_BO) &&
(priv->can.state != CAN_STATE_BUS_OFF)) {
- netdev_dbg(dev, "entered error warning state\n");
+ netdev_dbg(dev, "entered error bus off state\n");
work_done += m_can_handle_state_change(dev,
CAN_STATE_BUS_OFF);
}
{
if (irqstatus & IR_WDI)
netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
- if (irqstatus & IR_BEU)
+ if (irqstatus & IR_ELO)
netdev_err(dev, "Error Logging Overflow\n");
if (irqstatus & IR_BEU)
netdev_err(dev, "Bit Error Uncorrected\n");
.brp_inc = 1,
};
+static const struct can_bittiming_const m_can_data_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 32,
+ .brp_inc = 1,
+};
+
static int m_can_set_bittiming(struct net_device *dev)
{
struct m_can_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
+ const struct can_bittiming *dbt = &priv->can.data_bittiming;
u16 brp, sjw, tseg1, tseg2;
u32 reg_btp;
reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) |
(tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT);
m_can_write(priv, M_CAN_BTP, reg_btp);
- netdev_dbg(dev, "setting BTP 0x%x\n", reg_btp);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
+ reg_btp = (brp << FBTR_FBRP_SHIFT) | (sjw << FBTR_FSJW_SHIFT) |
+ (tseg1 << FBTR_FTSEG1_SHIFT) |
+ (tseg2 << FBTR_FTSEG2_SHIFT);
+ m_can_write(priv, M_CAN_FBTP, reg_btp);
+ }
return 0;
}
m_can_config_endisable(priv, true);
- /* RX Buffer/FIFO Element Size 8 bytes data field */
- m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_8BYTES);
+ /* RX Buffer/FIFO Element Size 64 bytes data field */
+ m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_64BYTES);
/* Accept Non-matching Frames Into FIFO 0 */
m_can_write(priv, M_CAN_GFC, 0x0);
m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) |
priv->mcfg[MRAM_TXB].off);
- /* only support 8 bytes firstly */
- m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_8BYTES);
+ /* support 64 bytes payload */
+ m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_64BYTES);
m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) |
priv->mcfg[MRAM_TXE].off);
RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off);
cccr = m_can_read(priv, M_CAN_CCCR);
- cccr &= ~(CCCR_TEST | CCCR_MON);
+ cccr &= ~(CCCR_TEST | CCCR_MON | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
+ (CCCR_CME_MASK << CCCR_CME_SHIFT));
test = m_can_read(priv, M_CAN_TEST);
test &= ~TEST_LBCK;
test |= TEST_LBCK;
}
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
+
m_can_write(priv, M_CAN_CCCR, cccr);
m_can_write(priv, M_CAN_TEST, test);
priv->dev = dev;
priv->can.bittiming_const = &m_can_bittiming_const;
+ priv->can.data_bittiming_const = &m_can_data_bittiming_const;
priv->can.do_set_mode = m_can_set_mode;
priv->can.do_get_berr_counter = m_can_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY |
- CAN_CTRLMODE_BERR_REPORTING;
+ CAN_CTRLMODE_BERR_REPORTING |
+ CAN_CTRLMODE_FD;
return dev;
}
struct net_device *dev)
{
struct m_can_priv *priv = netdev_priv(dev);
- struct can_frame *cf = (struct can_frame *)skb->data;
- u32 id;
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ u32 id, cccr;
+ int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
/* message ram configuration */
m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, cf->can_dlc << 16);
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(0), *(u32 *)(cf->data + 0));
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(1), *(u32 *)(cf->data + 4));
+ m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, can_len2dlc(cf->len) << 16);
+
+ for (i = 0; i < cf->len; i += 4)
+ m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(i / 4),
+ *(u32 *)(cf->data + i));
+
can_put_echo_skb(skb, dev, 0);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ cccr = m_can_read(priv, M_CAN_CCCR);
+ cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
+ if (can_is_canfd_skb(skb)) {
+ if (cf->flags & CANFD_BRS)
+ cccr |= CCCR_CMR_CANFD_BRS << CCCR_CMR_SHIFT;
+ else
+ cccr |= CCCR_CMR_CANFD << CCCR_CMR_SHIFT;
+ } else {
+ cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
+ }
+ m_can_write(priv, M_CAN_CCCR, cccr);
+ }
+
/* enable first TX buffer to start transfer */
m_can_write(priv, M_CAN_TXBTIE, 0x1);
m_can_write(priv, M_CAN_TXBAR, 0x1);
.ndo_open = m_can_open,
.ndo_stop = m_can_close,
.ndo_start_xmit = m_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int register_m_can_dev(struct net_device *dev)
struct resource *res;
void __iomem *addr;
u32 out_val[MRAM_CFG_LEN];
- int ret;
+ int i, start, end, ret;
/* message ram could be shared */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
+ /* initialize the entire Message RAM in use to avoid possible
+ * ECC/parity checksum errors when reading an uninitialized buffer
+ */
+ start = priv->mcfg[MRAM_SIDF].off;
+ end = priv->mcfg[MRAM_TXB].off +
+ priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
+ for (i = start; i < end; i += 4)
+ writel(0x0, priv->mram_base + i);
+
return 0;
}
.ndo_open = rcar_can_open,
.ndo_stop = rcar_can_close,
.ndo_start_xmit = rcar_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
struct net_device *dev;
struct sja1000_priv *priv;
struct kvaser_pci *board;
- int err, init_step;
+ int err;
dev = alloc_sja1000dev(sizeof(struct kvaser_pci));
if (dev == NULL)
if (channel == 0) {
board->xilinx_ver =
ioread8(board->res_addr + XILINX_VERINT) >> 4;
- init_step = 2;
/* Assert PTADR# - we're in passive mode so the other bits are
not important */
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
- init_step = 4;
-
dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n",
priv->reg_base, board->conf_addr, dev->irq);
if (urb->actual_length > CPC_HEADER_SIZE) {
struct ems_cpc_msg *msg;
u8 *ibuf = urb->transfer_buffer;
- u8 msg_count, again, start;
+ u8 msg_count, start;
msg_count = ibuf[0] & ~0x80;
- again = ibuf[0] & 0x80;
start = CPC_HEADER_SIZE;
{
struct esd_tx_urb_context *context = urb->context;
struct esd_usb2_net_priv *priv;
- struct esd_usb2 *dev;
struct net_device *netdev;
size_t size = sizeof(struct esd_usb2_msg);
priv = context->priv;
netdev = priv->netdev;
- dev = priv->usb2;
/* free up our allocated buffer */
usb_free_coherent(urb->dev, size,
}
}
unlink_all_urbs(dev);
+ kfree(dev);
}
}
.ndo_open = gs_can_open,
.ndo_stop = gs_can_close,
.ndo_start_xmit = gs_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf)
static int xcan_chip_start(struct net_device *ndev)
{
struct xcan_priv *priv = netdev_priv(ndev);
- u32 err, reg_msr, reg_sr_mask;
+ u32 reg_msr, reg_sr_mask;
+ int err;
unsigned long timeout;
/* Check if it is in reset mode */
.ndo_open = xcan_open,
.ndo_stop = xcan_close,
.ndo_start_xmit = xcan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
/**
return IRQ_HANDLED;
}
+static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
+{
+ unsigned int timeout = 1000;
+ u32 reg;
+
+ reg = core_readl(priv, CORE_WATCHDOG_CTRL);
+ reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
+ core_writel(priv, reg, CORE_WATCHDOG_CTRL);
+
+ do {
+ reg = core_readl(priv, CORE_WATCHDOG_CTRL);
+ if (!(reg & SOFTWARE_RESET))
+ break;
+
+ usleep_range(1000, 2000);
+ } while (timeout-- > 0);
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
*base = of_iomap(dn, i);
if (*base == NULL) {
pr_err("unable to find register: %s\n", reg_names[i]);
- return -ENODEV;
+ ret = -ENOMEM;
+ goto out_unmap;
}
base++;
}
+ ret = bcm_sf2_sw_rst(priv);
+ if (ret) {
+ pr_err("unable to software reset switch: %d\n", ret);
+ goto out_unmap;
+ }
+
/* Disable all interrupts and request them */
intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
out_unmap:
base = &priv->core;
for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
- iounmap(*base);
+ if (*base)
+ iounmap(*base);
base++;
}
return ret;
return 0;
}
-static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
-{
- unsigned int timeout = 1000;
- u32 reg;
-
- reg = core_readl(priv, CORE_WATCHDOG_CTRL);
- reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
- core_writel(priv, reg, CORE_WATCHDOG_CTRL);
-
- do {
- reg = core_readl(priv, CORE_WATCHDOG_CTRL);
- if (!(reg & SOFTWARE_RESET))
- break;
-
- usleep_range(1000, 2000);
- } while (timeout-- > 0);
-
- if (timeout == 0)
- return -ETIMEDOUT;
-
- return 0;
-}
-
static int bcm_sf2_sw_resume(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
if (tnapi->rx_rcb)
memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
- if (tg3_rx_prodring_alloc(tp, &tnapi->prodring)) {
+ if (tnapi->prodring.rx_std &&
+ tg3_rx_prodring_alloc(tp, &tnapi->prodring)) {
tg3_free_rings(tp);
return -ENOMEM;
}
pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
- pg->prio_pg[i] = (pgid >> (i * 4)) & 0xF;
+ pg->prio_pg[7 - i] = (pgid >> (i * 4)) & 0xF;
INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full |
SUPPORTED_10000baseKX4_Full;
else if (type == FW_PORT_TYPE_FIBER_XFI ||
- type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
+ type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) {
v |= SUPPORTED_FIBRE;
- else if (type == FW_PORT_TYPE_BP40_BA)
+ if (caps & FW_PORT_CAP_SPEED_1G)
+ v |= SUPPORTED_1000baseT_Full;
+ if (caps & FW_PORT_CAP_SPEED_10G)
+ v |= SUPPORTED_10000baseT_Full;
+ } else if (type == FW_PORT_TYPE_BP40_BA)
v |= SUPPORTED_40000baseSR4_Full;
if (caps & FW_PORT_CAP_ANEG)
return -EOPNOTSUPP;
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+ if (!br_spec)
+ return -EINVAL;
nla_for_each_nested(attr, br_spec, rem) {
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
+ if (nla_len(attr) < sizeof(mode))
+ return -EINVAL;
+
mode = nla_get_u16(attr);
if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
return -EINVAL;
"Disabled VxLAN offloads for UDP port %d\n",
be16_to_cpu(port));
}
+
+static bool be_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+ return vxlan_gso_check(skb);
+}
#endif
static const struct net_device_ops be_netdev_ops = {
#ifdef CONFIG_BE2NET_VXLAN
.ndo_add_vxlan_port = be_add_vxlan_port,
.ndo_del_vxlan_port = be_del_vxlan_port,
+ .ndo_gso_check = be_gso_check,
#endif
};
/* igb_get_stats64() might access the rings on this vector,
* we must wait a grace period before freeing it.
*/
- kfree_rcu(q_vector, rcu);
+ if (q_vector)
+ kfree_rcu(q_vector, rcu);
}
/**
adapter->flags &= ~IGB_FLAG_NEED_LINK_UPDATE;
for (i = 0; i < adapter->num_q_vectors; i++) {
- napi_synchronize(&(adapter->q_vector[i]->napi));
- napi_disable(&(adapter->q_vector[i]->napi));
+ if (adapter->q_vector[i]) {
+ napi_synchronize(&adapter->q_vector[i]->napi);
+ napi_disable(&adapter->q_vector[i]->napi);
+ }
}
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- igb_free_tx_resources(adapter->tx_ring[i]);
+ if (adapter->tx_ring[i])
+ igb_free_tx_resources(adapter->tx_ring[i]);
}
void igb_unmap_and_free_tx_resource(struct igb_ring *ring,
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- igb_clean_tx_ring(adapter->tx_ring[i]);
+ if (adapter->tx_ring[i])
+ igb_clean_tx_ring(adapter->tx_ring[i]);
}
/**
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- igb_free_rx_resources(adapter->rx_ring[i]);
+ if (adapter->rx_ring[i])
+ igb_free_rx_resources(adapter->rx_ring[i]);
}
/**
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- igb_clean_rx_ring(adapter->rx_ring[i]);
+ if (adapter->rx_ring[i])
+ igb_clean_rx_ring(adapter->rx_ring[i]);
}
/**
pci_restore_state(pdev);
pci_save_state(pdev);
+ if (!pci_device_is_present(pdev))
+ return -ENODEV;
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev,
* if SR-IOV and VMDQ are disabled - otherwise ensure
* that hardware VLAN filters remain enabled.
*/
- if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
- IXGBE_FLAG_SRIOV_ENABLED)))
+ if (adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
+ IXGBE_FLAG_SRIOV_ENABLED))
vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
} else {
if (netdev->flags & IFF_ALLMULTI) {
return -EOPNOTSUPP;
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+ if (!br_spec)
+ return -EINVAL;
nla_for_each_nested(attr, br_spec, rem) {
__u16 mode;
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
+ if (nla_len(attr) < sizeof(mode))
+ return -EINVAL;
+
mode = nla_get_u16(attr);
if (mode == BRIDGE_MODE_VEPA) {
reg = 0;
int i, err, pci_using_dac, expected_gts;
unsigned int indices = MAX_TX_QUEUES;
u8 part_str[IXGBE_PBANUM_LENGTH];
+ bool disable_dev = false;
#ifdef IXGBE_FCOE
u16 device_caps;
#endif
iounmap(adapter->io_addr);
kfree(adapter->mac_table);
err_ioremap:
+ disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
free_netdev(netdev);
err_alloc_etherdev:
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
- if (!adapter || !test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ if (!adapter || disable_dev)
pci_disable_device(pdev);
return err;
}
{
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
+ bool disable_dev;
ixgbe_dbg_adapter_exit(adapter);
e_dev_info("complete\n");
kfree(adapter->mac_table);
+ disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
free_netdev(netdev);
pci_disable_pcie_error_reporting(pdev);
- if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ if (disable_dev)
pci_disable_device(pdev);
}
mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
#ifdef CONFIG_MLX4_EN_VXLAN
- if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
+ if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
vxlan_get_rx_port(dev);
#endif
priv->port_up = true;
queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
}
+
+static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+ return vxlan_gso_check(skb);
+}
#endif
static const struct net_device_ops mlx4_netdev_ops = {
#ifdef CONFIG_MLX4_EN_VXLAN
.ndo_add_vxlan_port = mlx4_en_add_vxlan_port,
.ndo_del_vxlan_port = mlx4_en_del_vxlan_port,
+ .ndo_gso_check = mlx4_en_gso_check,
#endif
};
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
#endif
.ndo_get_phys_port_id = mlx4_en_get_phys_port_id,
+#ifdef CONFIG_MLX4_EN_VXLAN
+ .ndo_add_vxlan_port = mlx4_en_add_vxlan_port,
+ .ndo_del_vxlan_port = mlx4_en_del_vxlan_port,
+ .ndo_gso_check = mlx4_en_gso_check,
+#endif
};
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
switch (op) {
case RES_OP_RESERVE:
- count = get_param_l(&in_param);
+ count = get_param_l(&in_param) & 0xffffff;
align = get_param_h(&in_param);
err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
if (err)
adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
}
+
+static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+ return vxlan_gso_check(skb);
+}
#endif
static const struct net_device_ops qlcnic_netdev_ops = {
#ifdef CONFIG_QLCNIC_VXLAN
.ndo_add_vxlan_port = qlcnic_add_vxlan_port,
.ndo_del_vxlan_port = qlcnic_del_vxlan_port,
+ .ndo_gso_check = qlcnic_gso_check,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
return ret;
}
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
static void sh_eth_set_receive_align(struct sk_buff *skb)
{
- int reserve;
+ uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1);
- reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1));
if (reserve)
- skb_reserve(skb, reserve);
+ skb_reserve(skb, SH_ETH_RX_ALIGN - reserve);
}
-#else
-static void sh_eth_set_receive_align(struct sk_buff *skb)
-{
- skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN);
-}
-#endif
/* CPU <-> EDMAC endian convert */
struct sh_eth_txdesc *txdesc = NULL;
int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring;
int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
+ int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
mdp->cur_rx = 0;
mdp->cur_tx = 0;
for (i = 0; i < mdp->num_rx_ring; i++) {
/* skb */
mdp->rx_skbuff[i] = NULL;
- skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz);
+ skb = netdev_alloc_skb(ndev, skbuff_size);
mdp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
- dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz,
- DMA_FROM_DEVICE);
sh_eth_set_receive_align(skb);
/* RX descriptor */
rxdesc = &mdp->rx_ring[i];
+ /* The size of the buffer is a multiple of 16 bytes. */
+ rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
+ dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
+ DMA_FROM_DEVICE);
rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
- /* The size of the buffer is 16 byte boundary. */
- rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
/* Rx descriptor address set */
if (i == 0) {
sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
struct sk_buff *skb;
u16 pkt_len = 0;
u32 desc_status;
+ int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
rxdesc = &mdp->rx_ring[entry];
while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
if (mdp->cd->rpadir)
skb_reserve(skb, NET_IP_ALIGN);
dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr,
- mdp->rx_buf_sz,
+ ALIGN(mdp->rx_buf_sz, 16),
DMA_FROM_DEVICE);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, ndev);
rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
if (mdp->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz);
+ skb = netdev_alloc_skb(ndev, skbuff_size);
mdp->rx_skbuff[entry] = skb;
if (skb == NULL)
break; /* Better luck next round. */
- dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz,
- DMA_FROM_DEVICE);
sh_eth_set_receive_align(skb);
+ dma_map_single(&ndev->dev, skb->data,
+ rxdesc->buffer_length, DMA_FROM_DEVICE);
skb_checksum_none_assert(skb);
rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
if (ret)
goto out_free_irq;
+ mdp->is_opened = 1;
+
return ret;
out_free_irq:
return NETDEV_TX_OK;
}
+static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ if (sh_eth_is_rz_fast_ether(mdp))
+ return &ndev->stats;
+
+ if (!mdp->is_opened)
+ return &ndev->stats;
+
+ ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
+ sh_eth_write(ndev, 0, TROCR); /* (write clear) */
+ ndev->stats.collisions += sh_eth_read(ndev, CDCR);
+ sh_eth_write(ndev, 0, CDCR); /* (write clear) */
+ ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
+ sh_eth_write(ndev, 0, LCCR); /* (write clear) */
+
+ if (sh_eth_is_gether(mdp)) {
+ ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);
+ sh_eth_write(ndev, 0, CERCR); /* (write clear) */
+ ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);
+ sh_eth_write(ndev, 0, CEECR); /* (write clear) */
+ } else {
+ ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
+ sh_eth_write(ndev, 0, CNDCR); /* (write clear) */
+ }
+
+ return &ndev->stats;
+}
+
/* device close function */
static int sh_eth_close(struct net_device *ndev)
{
sh_eth_write(ndev, 0, EDTRR);
sh_eth_write(ndev, 0, EDRRR);
+ sh_eth_get_stats(ndev);
/* PHY Disconnect */
if (mdp->phydev) {
phy_stop(mdp->phydev);
pm_runtime_put_sync(&mdp->pdev->dev);
- return 0;
-}
-
-static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (sh_eth_is_rz_fast_ether(mdp))
- return &ndev->stats;
+ mdp->is_opened = 0;
- pm_runtime_get_sync(&mdp->pdev->dev);
-
- ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
- sh_eth_write(ndev, 0, TROCR); /* (write clear) */
- ndev->stats.collisions += sh_eth_read(ndev, CDCR);
- sh_eth_write(ndev, 0, CDCR); /* (write clear) */
- ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
- sh_eth_write(ndev, 0, LCCR); /* (write clear) */
- if (sh_eth_is_gether(mdp)) {
- ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);
- sh_eth_write(ndev, 0, CERCR); /* (write clear) */
- ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);
- sh_eth_write(ndev, 0, CEECR); /* (write clear) */
- } else {
- ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
- sh_eth_write(ndev, 0, CNDCR); /* (write clear) */
- }
- pm_runtime_put_sync(&mdp->pdev->dev);
-
- return &ndev->stats;
+ return 0;
}
/* ioctl to device function */
/* Driver's parameters */
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
-#define SH4_SKB_RX_ALIGN 32
+#define SH_ETH_RX_ALIGN 32
#else
-#define SH2_SH3_SKB_RX_ALIGN 2
+#define SH_ETH_RX_ALIGN 2
#endif
/* Register's bits
unsigned no_ether_link:1;
unsigned ether_link_active_low:1;
+ unsigned is_opened:1;
};
static inline void sh_eth_soft_swap(char *src, int len)
*/
plat->maxmtu = JUMBO_LEN;
- /* Set default value for multicast hash bins */
- plat->multicast_filter_bins = HASH_TABLE_SIZE;
-
- /* Set default value for unicast filter entries */
- plat->unicast_filter_entries = 1;
-
/*
* Currently only the properties needed on SPEAr600
* are provided. All other properties should be added
return PTR_ERR(addr);
plat_dat = dev_get_platdata(&pdev->dev);
- if (pdev->dev.of_node) {
- if (!plat_dat)
- plat_dat = devm_kzalloc(&pdev->dev,
+
+ if (!plat_dat)
+ plat_dat = devm_kzalloc(&pdev->dev,
sizeof(struct plat_stmmacenet_data),
GFP_KERNEL);
- if (!plat_dat) {
- pr_err("%s: ERROR: no memory", __func__);
- return -ENOMEM;
- }
+ if (!plat_dat) {
+ pr_err("%s: ERROR: no memory", __func__);
+ return -ENOMEM;
+ }
+
+ /* Set default value for multicast hash bins */
+ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
+ /* Set default value for unicast filter entries */
+ plat_dat->unicast_filter_entries = 1;
+
+ if (pdev->dev.of_node) {
ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
if (ret) {
pr_err("%s: main dt probe failed", __func__);
#define CPSW_VLAN_AWARE BIT(1)
#define CPSW_ALE_VLAN_AWARE 1
-#define CPSW_FIFO_NORMAL_MODE (0 << 15)
-#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
-#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
+#define CPSW_FIFO_NORMAL_MODE (0 << 16)
+#define CPSW_FIFO_DUAL_MAC_MODE (1 << 16)
+#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 16)
#define CPSW_INTPACEEN (0x3f << 16)
#define CPSW_INTPRESCALE_MASK (0x7FF << 0)
err = wpan_phy_register(phy);
if (err)
- goto out;
+ goto err_phy_reg;
err = register_netdev(dev);
- if (err < 0)
- goto out;
+ if (err)
+ goto err_netdev_reg;
dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
return 0;
-out:
- unregister_netdev(dev);
+err_netdev_reg:
+ wpan_phy_unregister(phy);
+err_phy_reg:
+ free_netdev(dev);
+ wpan_phy_free(phy);
return err;
}
int len = sizeof(struct sockaddr_pppox);
struct sockaddr_pppox sp;
- sp.sa_family = AF_PPPOX;
+ memset(&sp.sa_addr, 0, sizeof(sp.sa_addr));
+
+ sp.sa_family = AF_PPPOX;
sp.sa_protocol = PX_PROTO_PPTP;
sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
{QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
};
#endif
+static bool virtnet_fail_on_feature(struct virtio_device *vdev,
+ unsigned int fbit,
+ const char *fname, const char *dname)
+{
+ if (!virtio_has_feature(vdev, fbit))
+ return false;
+
+ dev_err(&vdev->dev, "device advertises feature %s but not %s",
+ fname, dname);
+
+ return true;
+}
+
+#define VIRTNET_FAIL_ON(vdev, fbit, dbit) \
+ virtnet_fail_on_feature(vdev, fbit, #fbit, dbit)
+
+static bool virtnet_validate_features(struct virtio_device *vdev)
+{
+ if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) &&
+ (VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_RX,
+ "VIRTIO_NET_F_CTRL_VQ") ||
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_VLAN,
+ "VIRTIO_NET_F_CTRL_VQ") ||
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE,
+ "VIRTIO_NET_F_CTRL_VQ") ||
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
+ "VIRTIO_NET_F_CTRL_VQ"))) {
+ return false;
+ }
+
+ return true;
+}
+
static int virtnet_probe(struct virtio_device *vdev)
{
int i, err;
struct virtnet_info *vi;
u16 max_queue_pairs;
+ if (!virtnet_validate_features(vdev))
+ return -EINVAL;
+
/* Find if host supports multiqueue virtio_net device */
err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
struct virtio_net_config,
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
-/* VXLAN protocol header */
-struct vxlanhdr {
- __be32 vx_flags;
- __be32 vx_vni;
-};
-
/* UDP port for VXLAN traffic.
* The IANA assigned port is 4789, but the Linux default is 8472
* for compatibility with early adopters.
if (ipv6) {
udp_conf.family = AF_INET6;
udp_conf.use_udp6_tx_checksums =
- !!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
+ !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
udp_conf.use_udp6_rx_checksums =
- !!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
+ !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
} else {
udp_conf.family = AF_INET;
udp_conf.local_ip.s_addr = INADDR_ANY;
ah->enabled_cals |= TX_CL_CAL;
else
ah->enabled_cals &= ~TX_CL_CAL;
+
+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ if (ah->is_clk_25mhz) {
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
+ } else {
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
+ }
+ udelay(100);
+ }
}
static void ar9003_hw_prog_ini(struct ath_hw *ah,
udelay(RTC_PLL_SETTLE_DELAY);
REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
-
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
- if (ah->is_clk_25mhz) {
- REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
- REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
- REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
- } else {
- REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
- REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
- REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
- }
- udelay(100);
- }
}
static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
struct ath_vif *avp;
/*
- * Pick the MAC address of the first interface as the new hardware
- * MAC address. The hardware will use it together with the BSSID mask
- * when matching addresses.
+ * The hardware will use primary station addr together with the
+ * BSSID mask when matching addresses.
*/
memset(iter_data, 0, sizeof(*iter_data));
memset(&iter_data->mask, 0xff, ETH_ALEN);
list_add_tail(&avp->list, &avp->chanctx->vifs);
}
+ ath9k_calculate_summary_state(sc, avp->chanctx);
+
ath9k_assign_hw_queues(hw, vif);
an->sc = sc;
ath_tx_node_cleanup(sc, &avp->mcast_node);
+ ath9k_calculate_summary_state(sc, avp->chanctx);
+
mutex_unlock(&sc->mutex);
}
void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
{
- assert_mac_suspended(dev);
- dev->phy.ops->phy_write(dev, destreg,
- dev->phy.ops->phy_read(dev, srcreg));
+ b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg));
}
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
return;
irq = irq_of_parse_and_map(np, 0);
- if (irq < 0) {
- brcmf_err("interrupt could not be mapped: err=%d\n", irq);
+ if (!irq) {
+ brcmf_err("interrupt could not be mapped\n");
devm_kfree(dev, sdiodev->pdata);
return;
}
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <linux/unaligned/access_ok.h>
#include <linux/interrupt.h>
#include <linux/bcma/bcma.h>
#include <linux/sched.h>
+#include <asm/unaligned.h>
#include <soc.h>
#include <chipcommon.h>
goto finalize;
}
- if (!brcmf_usb_ioctl_resp_wait(devinfo))
+ if (!brcmf_usb_ioctl_resp_wait(devinfo)) {
+ usb_kill_urb(devinfo->ctl_urb);
ret = -ETIMEDOUT;
- else
+ } else {
memcpy(buffer, tmpbuf, buflen);
+ }
finalize:
kfree(tmpbuf);
primary_offset = ch->center_freq1 - ch->chan->center_freq;
switch (ch->width) {
case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_20_NOHT:
ch_inf.bw = BRCMU_CHAN_BW_20;
WARN_ON(primary_offset != 0);
break;
ch_inf.sb = BRCMU_CHAN_SB_LU;
}
break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
default:
WARN_ON_ONCE(1);
}
case IEEE80211_BAND_5GHZ:
ch_inf.band = BRCMU_CHAN_BAND_5G;
break;
+ case IEEE80211_BAND_60GHZ:
default:
WARN_ON_ONCE(1);
}
* @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
* @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
* which also implies support for the scheduler configuration command
+ * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
*/
enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10),
IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11),
IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
};
/* The default calibrate table size if not specified by firmware file */
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- /* Use aux roc framework (HS20) */
- ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
- vif, duration);
+ if (mvm->fw->ucode_capa.capa[0] &
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) {
+ /* Use aux roc framework (HS20) */
+ ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
+ vif, duration);
+ goto out_unlock;
+ }
+ IWL_ERR(mvm, "hotspot not supported\n");
+ ret = -EINVAL;
goto out_unlock;
case NL80211_IFTYPE_P2P_DEVICE:
/* handle below */
SCAN_COMPLETE_NOTIFICATION };
int ret;
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return 0;
-
- if (iwl_mvm_is_radio_killed(mvm)) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- return 0;
- }
-
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
scan_abort_notif,
ARRAY_SIZE(scan_abort_notif),
int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
{
+ if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+ return 0;
+
+ if (iwl_mvm_is_radio_killed(mvm)) {
+ ieee80211_scan_completed(mvm->hw, true);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+ return 0;
+ }
+
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
return iwl_mvm_scan_offload_stop(mvm, true);
return iwl_mvm_cancel_regular_scan(mvm);
int reg;
__le32 *val;
- prph_len += sizeof(*data) + sizeof(*prph) +
- num_bytes_in_chunk;
+ prph_len += sizeof(**data) + sizeof(*prph) + num_bytes_in_chunk;
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
(*data)->len = cpu_to_le32(sizeof(*prph) +
skb_trim(skb, frame_length);
}
-void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
+/*
+ * H/W needs L2 padding between the header and the paylod if header size
+ * is not 4 bytes aligned.
+ */
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len)
{
- unsigned int payload_length = skb->len - header_length;
- unsigned int header_align = ALIGN_SIZE(skb, 0);
- unsigned int payload_align = ALIGN_SIZE(skb, header_length);
- unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
+ unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
- /*
- * Adjust the header alignment if the payload needs to be moved more
- * than the header.
- */
- if (payload_align > header_align)
- header_align += 4;
-
- /* There is nothing to do if no alignment is needed */
- if (!header_align)
+ if (!l2pad)
return;
- /* Reserve the amount of space needed in front of the frame */
- skb_push(skb, header_align);
-
- /*
- * Move the header.
- */
- memmove(skb->data, skb->data + header_align, header_length);
-
- /* Move the payload, if present and if required */
- if (payload_length && payload_align)
- memmove(skb->data + header_length + l2pad,
- skb->data + header_length + l2pad + payload_align,
- payload_length);
-
- /* Trim the skb to the correct size */
- skb_trim(skb, header_length + l2pad + payload_length);
+ skb_push(skb, l2pad);
+ memmove(skb->data, skb->data + l2pad, hdr_len);
}
-void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len)
{
- /*
- * L2 padding is only present if the skb contains more than just the
- * IEEE 802.11 header.
- */
- unsigned int l2pad = (skb->len > header_length) ?
- L2PAD_SIZE(header_length) : 0;
+ unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
if (!l2pad)
return;
- memmove(skb->data + l2pad, skb->data, header_length);
+ memmove(skb->data + l2pad, skb->data, hdr_len);
skb_pull(skb, l2pad);
}
break;
}
/* handle command packet here */
- if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
+ if (rtlpriv->cfg->ops->rx_command_packet &&
+ rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
dev_kfree_skb_any(skb);
goto end;
}
__skb_queue_tail(&ring->queue, pskb);
- rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
- &temp_one);
-
+ if (rtlpriv->use_new_trx_flow) {
+ temp_one = 4;
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pbuffer_desc, true,
+ HW_DESC_OWN, (u8 *)&temp_one);
+ } else {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
+ &temp_one);
+ }
return;
}
ring->desc = NULL;
if (rtlpriv->use_new_trx_flow) {
pci_free_consistent(rtlpci->pdev,
- sizeof(*ring->desc) * ring->entries,
+ sizeof(*ring->buffer_desc) * ring->entries,
ring->buffer_desc, ring->buffer_desc_dma);
- ring->desc = NULL;
+ ring->buffer_desc = NULL;
}
}
true,
HW_DESC_TXBUFF_ADDR),
skb->len, PCI_DMA_TODEVICE);
- ring->idx = (ring->idx + 1) % ring->entries;
kfree_skb(skb);
ring->idx = (ring->idx + 1) % ring->entries;
}
/*like read eeprom and so on */
rtlpriv->cfg->ops->read_eeprom_info(hw);
+ if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
+ err = -ENODEV;
+ goto fail3;
+ }
+ rtlpriv->cfg->ops->init_sw_leds(hw);
+
+ /*aspm */
+ rtl_pci_init_aspm(hw);
+
/* Init mac80211 sw */
err = rtl_init_core(hw);
if (err) {
goto fail3;
}
- if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
- err = -ENODEV;
- goto fail3;
- }
- rtlpriv->cfg->ops->init_sw_leds(hw);
-
- /*aspm */
- rtl_pci_init_aspm(hw);
-
err = ieee80211_register_hw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
}
+ if (type != NL80211_IFTYPE_AP &&
+ rtlpriv->mac80211.link_state < MAC80211_LINKED)
+ bt_msr = rtl_read_byte(rtlpriv, MSR) & ~MSR_LINK_MASK;
rtl_write_byte(rtlpriv, (MSR), bt_msr);
temp = rtl_read_dword(rtlpriv, TCR);
rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
/* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
+ rtlpci->irq_enabled = true;
}
void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
rtlpci = rtl_pcidev(rtl_pcipriv(hw));
rtl_write_dword(rtlpriv, INTA_MASK, 0);
rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
-
- synchronize_irq(rtlpci->pdev->irq);
+ rtlpci->irq_enabled = false;
}
static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
case 2:
currentcmd = &postcommoncmd[*step];
break;
+ default:
+ return true;
}
if (currentcmd->cmdid == CMDID_END) {
}
}
+static bool rtl92se_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue,
+ u16 index)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+ u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+ u8 own = (u8)rtl92se_get_desc(entry, true, HW_DESC_OWN);
+
+ if (own)
+ return false;
+ return true;
+}
+
static struct rtl_hal_ops rtl8192se_hal_ops = {
.init_sw_vars = rtl92s_init_sw_vars,
.deinit_sw_vars = rtl92s_deinit_sw_vars,
.led_control = rtl92se_led_control,
.set_desc = rtl92se_set_desc,
.get_desc = rtl92se_get_desc,
+ .is_tx_desc_closed = rtl92se_is_tx_desc_closed,
.tx_polling = rtl92se_tx_polling,
.enable_hw_sec = rtl92se_enable_hw_security_config,
.set_key = rtl92se_set_key,
.maps[MAC_RCR_ACRC32] = RCR_ACRC32,
.maps[MAC_RCR_ACF] = RCR_ACF,
.maps[MAC_RCR_AAP] = RCR_AAP,
+ .maps[MAC_HIMR] = INTA_MASK,
+ .maps[MAC_HIMRE] = INTA_MASK + 4,
.maps[EFUSE_TEST] = REG_EFUSE_TEST,
.maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
mac->opmode == NL80211_IFTYPE_ADHOC)
macid = sta->aid + 1;
if (wirelessmode == WIRELESS_MODE_N_5G ||
- wirelessmode == WIRELESS_MODE_AC_5G)
- ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ];
+ wirelessmode == WIRELESS_MODE_AC_5G ||
+ wirelessmode == WIRELESS_MODE_A)
+ ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ] << 4;
else
ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ];
static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
static void connect(struct backend_info *be);
static int read_xenbus_vif_flags(struct backend_info *be);
-static void backend_create_xenvif(struct backend_info *be);
+static int backend_create_xenvif(struct backend_info *be);
static void unregister_hotplug_status_watch(struct backend_info *be);
static void set_backend_state(struct backend_info *be,
enum xenbus_state state);
be->state = XenbusStateInitWait;
/* This kicks hotplug scripts, so do it immediately. */
- backend_create_xenvif(be);
+ err = backend_create_xenvif(be);
+ if (err)
+ goto fail;
return 0;
}
-static void backend_create_xenvif(struct backend_info *be)
+static int backend_create_xenvif(struct backend_info *be)
{
int err;
long handle;
struct xenbus_device *dev = be->dev;
if (be->vif != NULL)
- return;
+ return 0;
err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
if (err != 1) {
xenbus_dev_fatal(dev, err, "reading handle");
- return;
+ return (err < 0) ? err : -EINVAL;
}
be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
err = PTR_ERR(be->vif);
be->vif = NULL;
xenbus_dev_fatal(dev, err, "creating interface");
- return;
+ return err;
}
kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+ return 0;
}
static void backend_disconnect(struct backend_info *be)
len = skb_frag_size(frag);
offset = frag->page_offset;
- /* Data must not cross a page boundary. */
- BUG_ON(len + offset > PAGE_SIZE<<compound_order(page));
-
/* Skip unused frames from start of page */
page += offset >> PAGE_SHIFT;
offset &= ~PAGE_MASK;
while (len > 0) {
unsigned long bytes;
- BUG_ON(offset >= PAGE_SIZE);
-
bytes = PAGE_SIZE - offset;
if (bytes > len)
bytes = len;
return NULL;
}
+static int of_empty_ranges_quirk(void)
+{
+ if (IS_ENABLED(CONFIG_PPC)) {
+ /* To save cycles, we cache the result */
+ static int quirk_state = -1;
+
+ if (quirk_state < 0)
+ quirk_state =
+ of_machine_is_compatible("Power Macintosh") ||
+ of_machine_is_compatible("MacRISC");
+ return quirk_state;
+ }
+ return false;
+}
+
static int of_translate_one(struct device_node *parent, struct of_bus *bus,
struct of_bus *pbus, __be32 *addr,
int na, int ns, int pna, const char *rprop)
* This code is only enabled on powerpc. --gcl
*/
ranges = of_get_property(parent, rprop, &rlen);
-#if !defined(CONFIG_PPC)
- if (ranges == NULL) {
+ if (ranges == NULL && !of_empty_ranges_quirk()) {
pr_err("OF: no ranges; cannot translate\n");
return 1;
}
-#endif /* !defined(CONFIG_PPC) */
if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
}
EXPORT_SYMBOL_GPL(of_property_read_u64);
+/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ }
+ return 0;
+}
+
/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @allocflags: Allocation flags (typically pass GFP_KERNEL)
*
* Copy a property by dynamically allocating the memory of both the
- * property stucture and the property name & contents. The property's
+ * property structure and the property name & contents. The property's
* flags have the OF_DYNAMIC bit set so that we can differentiate between
* dynamically allocated properties and not.
* Returns the newly allocated property or NULL on out of memory error.
if (offset < 0)
return -ENODEV;
- while (match->compatible) {
+ while (match->compatible[0]) {
unsigned long addr;
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
match++;
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
- if (memblock_is_region_reserved(base, size))
- return -EBUSY;
if (nomap)
return memblock_remove(base, size);
return memblock_reserve(base, size);
return;
}
- while (last_node_index >= 0) {
+ while (last_node_index-- > 0) {
if (nodes[last_node_index]) {
np = of_find_node_by_path(nodes[last_node_index]->full_name);
- if (strcmp(np->full_name, "/aliases") != 0) {
+ if (np == nodes[last_node_index]) {
+ if (of_aliases == np) {
+ of_node_put(of_aliases);
+ of_aliases = NULL;
+ }
detach_node_and_children(np);
} else {
for_each_property_of_node(np, prop) {
}
}
}
- last_node_index--;
}
}
res = selftest_data_add();
if (res)
return res;
+ if (!of_aliases)
+ of_aliases = of_find_node_by_path("/aliases");
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
if (!np) {
return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
}
-static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
+bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
{
int type = pci_pcie_type(dev);
struct resource all;
struct resource io;
+ struct resource pio;
struct resource mem;
struct resource prefetch;
struct resource busn;
{
struct tegra_pcie *pcie = sys_to_pcie(sys);
int err;
- phys_addr_t io_start;
err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
if (err < 0)
if (err)
return err;
- io_start = pci_pio_to_address(pcie->io.start);
-
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource_offset(&sys->resources, &pcie->prefetch,
sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn);
- pci_ioremap_io(nr * SZ_64K, io_start);
+ pci_ioremap_io(pcie->pio.start, pcie->io.start);
return 1;
}
static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
{
u32 fpci_bar, size, axi_address;
- phys_addr_t io_start = pci_pio_to_address(pcie->io.start);
/* Bar 0: type 1 extended configuration space */
fpci_bar = 0xfe100000;
/* Bar 1: downstream IO bar */
fpci_bar = 0xfdfc0000;
size = resource_size(&pcie->io);
- axi_address = io_start;
+ axi_address = pcie->io.start;
afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
switch (res.flags & IORESOURCE_TYPE_BITS) {
case IORESOURCE_IO:
- memcpy(&pcie->io, &res, sizeof(res));
- pcie->io.name = np->full_name;
+ memcpy(&pcie->pio, &res, sizeof(res));
+ pcie->pio.name = np->full_name;
+
+ /*
+ * The Tegra PCIe host bridge uses this to program the
+ * mapping of the I/O space to the physical address,
+ * so we override the .start and .end fields here that
+ * of_pci_range_to_resource() converted to I/O space.
+ * We also set the IORESOURCE_MEM type to clarify that
+ * the resource is in the physical memory space.
+ */
+ pcie->io.start = range.cpu_addr;
+ pcie->io.end = range.cpu_addr + range.size - 1;
+ pcie->io.flags = IORESOURCE_MEM;
+ pcie->io.name = "I/O";
+
+ memcpy(&res, &pcie->io, sizeof(res));
break;
case IORESOURCE_MEM:
if (ret)
return ret;
- bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res);
+ bus = pci_create_root_bus(&pdev->dev, 0,
+ &xgene_pcie_ops, port, &res);
if (!bus)
return -ENOMEM;
+ pci_scan_child_bus(bus);
+ pci_assign_unassigned_bus_resources(bus);
+ pci_bus_add_devices(bus);
+
platform_set_drvdata(pdev, port);
return 0;
}
return entry;
}
+static int msi_verify_entries(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (!dev->no_64bit_msi || !entry->msg.address_hi)
+ continue;
+ dev_err(&dev->dev, "Device has broken 64-bit MSI but arch"
+ " tried to assign one above 4G\n");
+ return -EIO;
+ }
+ return 0;
+}
+
/**
* msi_capability_init - configure device's MSI capability structure
* @dev: pointer to the pci_dev data structure of MSI device function
return ret;
}
+ ret = msi_verify_entries(dev);
+ if (ret) {
+ msi_mask_irq(entry, mask, ~mask);
+ free_msi_irqs(dev);
+ return ret;
+ }
+
ret = populate_msi_sysfs(dev);
if (ret) {
msi_mask_irq(entry, mask, ~mask);
if (ret)
goto out_avail;
+ /* Check if all MSI entries honor device restrictions */
+ ret = msi_verify_entries(dev);
+ if (ret)
+ goto out_free;
+
/*
* Some devices require MSI-X to be enabled before we can touch the
* MSI-X registers. We need to mask all the vectors to prevent
extern const unsigned char pcie_link_speed[];
+bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
+
/* Functions internal to the PCI core code */
int pci_create_sysfs_dev_files(struct pci_dev *pdev);
{
struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
- unsigned long base, limit;
+ u64 base64, limit64;
+ dma_addr_t base, limit;
struct pci_bus_region region;
struct resource *res;
res = child->resource[2];
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
- base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
- limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+ base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+ limit64 = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
u32 mem_base_hi, mem_limit_hi;
* this, just assume they are not being used.
*/
if (mem_base_hi <= mem_limit_hi) {
-#if BITS_PER_LONG == 64
- base |= ((unsigned long) mem_base_hi) << 32;
- limit |= ((unsigned long) mem_limit_hi) << 32;
-#else
- if (mem_base_hi || mem_limit_hi) {
- dev_err(&dev->dev, "can't handle 64-bit address space for bridge\n");
- return;
- }
-#endif
+ base64 |= (u64) mem_base_hi << 32;
+ limit64 |= (u64) mem_limit_hi << 32;
}
}
+
+ base = (dma_addr_t) base64;
+ limit = (dma_addr_t) limit64;
+
+ if (base != base64) {
+ dev_err(&dev->dev, "can't handle bridge window above 4GB (bus address %#010llx)\n",
+ (unsigned long long) base64);
+ return;
+ }
+
if (base <= limit) {
res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
IORESOURCE_MEM | IORESOURCE_PREFETCH;
~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
/* Initialize Link Control Register */
- if (dev->subordinate)
+ if (pcie_cap_has_lnkctl(dev))
pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
# Client driver configurations go here.
config INTEL_RAPL
tristate "Intel RAPL Support"
- depends on X86
+ depends on X86 && IOSF_MBI
default n
---help---
This enables support for the Intel Running Average Power Limit (RAPL)
#include <linux/sysfs.h>
#include <linux/cpu.h>
#include <linux/powercap.h>
+#include <asm/iosf_mbi.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>
#define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */
#define RAPL_PRIMITIVE_DUMMY BIT(2)
-/* scale RAPL units to avoid floating point math inside kernel */
-#define POWER_UNIT_SCALE (1000000)
-#define ENERGY_UNIT_SCALE (1000000)
-#define TIME_UNIT_SCALE (1000000)
-
#define TIME_WINDOW_MAX_MSEC 40000
#define TIME_WINDOW_MIN_MSEC 250
unsigned int id; /* physical package/socket id */
unsigned int nr_domains;
unsigned long domain_map; /* bit map of active domains */
- unsigned int power_unit_divisor;
- unsigned int energy_unit_divisor;
- unsigned int time_unit_divisor;
+ unsigned int power_unit;
+ unsigned int energy_unit;
+ unsigned int time_unit;
struct rapl_domain *domains; /* array of domains, sized at runtime */
struct powercap_zone *power_zone; /* keep track of parent zone */
int nr_cpus; /* active cpus on the package, topology info is lost during
*/
struct list_head plist;
};
+
+struct rapl_defaults {
+ int (*check_unit)(struct rapl_package *rp, int cpu);
+ void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
+ u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
+ bool to_raw);
+};
+static struct rapl_defaults *rapl_defaults;
+
+/* Sideband MBI registers */
+#define IOSF_CPU_POWER_BUDGET_CTL (0x2)
+
#define PACKAGE_PLN_INT_SAVED BIT(0)
#define MAX_PRIM_NAME (32)
static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
{
struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
- int nr_powerlimit;
if (rd->state & DOMAIN_STATE_BIOS_LOCKED)
return -EACCES;
+
get_online_cpus();
- nr_powerlimit = find_nr_power_limit(rd);
- /* here we activate/deactivate the hardware for power limiting */
rapl_write_data_raw(rd, PL1_ENABLE, mode);
- /* always enable clamp such that p-state can go below OS requested
- * range. power capping priority over guranteed frequency.
- */
- rapl_write_data_raw(rd, PL1_CLAMP, mode);
- /* some domains have pl2 */
- if (nr_powerlimit > 1) {
- rapl_write_data_raw(rd, PL2_ENABLE, mode);
- rapl_write_data_raw(rd, PL2_CLAMP, mode);
- }
+ rapl_defaults->set_floor_freq(rd, mode);
put_online_cpus();
return 0;
static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
int to_raw)
{
- u64 divisor = 1;
- int scale = 1; /* scale to user friendly data without floating point */
- u64 f, y; /* fraction and exp. used for time unit */
+ u64 units = 1;
struct rapl_package *rp;
rp = find_package_by_id(package);
switch (type) {
case POWER_UNIT:
- divisor = rp->power_unit_divisor;
- scale = POWER_UNIT_SCALE;
+ units = rp->power_unit;
break;
case ENERGY_UNIT:
- scale = ENERGY_UNIT_SCALE;
- divisor = rp->energy_unit_divisor;
+ units = rp->energy_unit;
break;
case TIME_UNIT:
- divisor = rp->time_unit_divisor;
- scale = TIME_UNIT_SCALE;
- /* special processing based on 2^Y*(1+F)/4 = val/divisor, refer
- * to Intel Software Developer's manual Vol. 3a, CH 14.7.4.
- */
- if (!to_raw) {
- f = (value & 0x60) >> 5;
- y = value & 0x1f;
- value = (1 << y) * (4 + f) * scale / 4;
- return div64_u64(value, divisor);
- } else {
- do_div(value, scale);
- value *= divisor;
- y = ilog2(value);
- f = div64_u64(4 * (value - (1 << y)), 1 << y);
- value = (y & 0x1f) | ((f & 0x3) << 5);
- return value;
- }
- break;
+ return rapl_defaults->compute_time_window(rp, value, to_raw);
case ARBITRARY_UNIT:
default:
return value;
};
if (to_raw)
- return div64_u64(value * divisor, scale);
- else
- return div64_u64(value * scale, divisor);
+ return div64_u64(value, units);
+
+ value *= units;
+
+ return value;
}
/* in the order of enum rapl_primitives */
return 0;
}
-static const struct x86_cpu_id energy_unit_quirk_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
- {}
-};
-
-static int rapl_check_unit(struct rapl_package *rp, int cpu)
+/*
+ * Raw RAPL data stored in MSRs are in certain scales. We need to
+ * convert them into standard units based on the units reported in
+ * the RAPL unit MSRs. This is specific to CPUs as the method to
+ * calculate units differ on different CPUs.
+ * We convert the units to below format based on CPUs.
+ * i.e.
+ * energy unit: microJoules : Represented in microJoules by default
+ * power unit : microWatts : Represented in milliWatts by default
+ * time unit : microseconds: Represented in seconds by default
+ */
+static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
{
u64 msr_val;
u32 value;
return -ENODEV;
}
- /* Raw RAPL data stored in MSRs are in certain scales. We need to
- * convert them into standard units based on the divisors reported in
- * the RAPL unit MSRs.
- * i.e.
- * energy unit: 1/enery_unit_divisor Joules
- * power unit: 1/power_unit_divisor Watts
- * time unit: 1/time_unit_divisor Seconds
- */
value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
- /* some CPUs have different way to calculate energy unit */
- if (x86_match_cpu(energy_unit_quirk_ids))
- rp->energy_unit_divisor = 1000000 / (1 << value);
- else
- rp->energy_unit_divisor = 1 << value;
+ rp->energy_unit = 1000000 / (1 << value);
value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
- rp->power_unit_divisor = 1 << value;
+ rp->power_unit = 1000000 / (1 << value);
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
- rp->time_unit_divisor = 1 << value;
+ rp->time_unit = 1000000 / (1 << value);
- pr_debug("Physical package %d units: energy=%d, time=%d, power=%d\n",
- rp->id,
- rp->energy_unit_divisor,
- rp->time_unit_divisor,
- rp->power_unit_divisor);
+ pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+ rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
return 0;
}
+static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
+{
+ u64 msr_val;
+ u32 value;
+
+ if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
+ pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
+ MSR_RAPL_POWER_UNIT, cpu);
+ return -ENODEV;
+ }
+ value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+ rp->energy_unit = 1 << value;
+
+ value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+ rp->power_unit = (1 << value) * 1000;
+
+ value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+ rp->time_unit = 1000000 / (1 << value);
+
+ pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+ rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
+
+ return 0;
+}
+
+
/* REVISIT:
* When package power limit is set artificially low by RAPL, LVT
* thermal interrupt for package power limit should be ignored
wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
}
+static void set_floor_freq_default(struct rapl_domain *rd, bool mode)
+{
+ int nr_powerlimit = find_nr_power_limit(rd);
+
+ /* always enable clamp such that p-state can go below OS requested
+ * range. power capping priority over guranteed frequency.
+ */
+ rapl_write_data_raw(rd, PL1_CLAMP, mode);
+
+ /* some domains have pl2 */
+ if (nr_powerlimit > 1) {
+ rapl_write_data_raw(rd, PL2_ENABLE, mode);
+ rapl_write_data_raw(rd, PL2_CLAMP, mode);
+ }
+}
+
+static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
+{
+ static u32 power_ctrl_orig_val;
+ u32 mdata;
+
+ if (!power_ctrl_orig_val)
+ iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_PMC_READ,
+ IOSF_CPU_POWER_BUDGET_CTL, &power_ctrl_orig_val);
+ mdata = power_ctrl_orig_val;
+ if (enable) {
+ mdata &= ~(0x7f << 8);
+ mdata |= 1 << 8;
+ }
+ iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_PMC_WRITE,
+ IOSF_CPU_POWER_BUDGET_CTL, mdata);
+}
+
+static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
+ bool to_raw)
+{
+ u64 f, y; /* fraction and exp. used for time unit */
+
+ /*
+ * Special processing based on 2^Y*(1+F/4), refer
+ * to Intel Software Developer's manual Vol.3B: CH 14.9.3.
+ */
+ if (!to_raw) {
+ f = (value & 0x60) >> 5;
+ y = value & 0x1f;
+ value = (1 << y) * (4 + f) * rp->time_unit / 4;
+ } else {
+ do_div(value, rp->time_unit);
+ y = ilog2(value);
+ f = div64_u64(4 * (value - (1 << y)), 1 << y);
+ value = (y & 0x1f) | ((f & 0x3) << 5);
+ }
+ return value;
+}
+
+static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
+ bool to_raw)
+{
+ /*
+ * Atom time unit encoding is straight forward val * time_unit,
+ * where time_unit is default to 1 sec. Never 0.
+ */
+ if (!to_raw)
+ return (value) ? value *= rp->time_unit : rp->time_unit;
+ else
+ value = div64_u64(value, rp->time_unit);
+
+ return value;
+}
+
+static const struct rapl_defaults rapl_defaults_core = {
+ .check_unit = rapl_check_unit_core,
+ .set_floor_freq = set_floor_freq_default,
+ .compute_time_window = rapl_compute_time_window_core,
+};
+
+static const struct rapl_defaults rapl_defaults_atom = {
+ .check_unit = rapl_check_unit_atom,
+ .set_floor_freq = set_floor_freq_atom,
+ .compute_time_window = rapl_compute_time_window_atom,
+};
+
+#define RAPL_CPU(_model, _ops) { \
+ .vendor = X86_VENDOR_INTEL, \
+ .family = 6, \
+ .model = _model, \
+ .driver_data = (kernel_ulong_t)&_ops, \
+ }
+
static const struct x86_cpu_id rapl_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */
- { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
- { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
- { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
- { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */
- { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */
- { X86_VENDOR_INTEL, 6, 0x3f},/* Haswell */
- { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */
- /* TODO: Add more CPU IDs after testing */
+ RAPL_CPU(0x2a, rapl_defaults_core),/* Sandy Bridge */
+ RAPL_CPU(0x2d, rapl_defaults_core),/* Sandy Bridge EP */
+ RAPL_CPU(0x37, rapl_defaults_atom),/* Valleyview */
+ RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
+ RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
+ RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
+ RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+ RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
+ RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
+ RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
+ RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */
{}
};
MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
/* check if the package contains valid domains */
if (rapl_detect_domains(new_package, i) ||
- rapl_check_unit(new_package, i)) {
+ rapl_defaults->check_unit(new_package, i)) {
kfree(new_package->domains);
kfree(new_package);
/* free up the packages already initialized */
rp->nr_cpus = 1;
/* check if the package contains valid domains */
if (rapl_detect_domains(rp, cpu) ||
- rapl_check_unit(rp, cpu)) {
+ rapl_defaults->check_unit(rp, cpu)) {
ret = -ENODEV;
goto err_free_package;
}
static int __init rapl_init(void)
{
int ret = 0;
+ const struct x86_cpu_id *id;
- if (!x86_match_cpu(rapl_ids)) {
+ id = x86_match_cpu(rapl_ids);
+ if (!id) {
pr_err("driver does not support CPU family %d model %d\n",
boot_cpu_data.x86, boot_cpu_data.x86_model);
return -ENODEV;
}
+ rapl_defaults = (struct rapl_defaults *)id->driver_data;
+
cpu_notifier_register_begin();
/* prevent CPU hotplug during detection */
struct fc_frame_header *fh;
struct fcoe_rcv_info *fr;
struct fcoe_percpu_s *bg;
+ struct sk_buff *tmp_skb;
unsigned short oxid;
interface = container_of(ptype, struct bnx2fc_interface,
goto err;
}
+ tmp_skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!tmp_skb)
+ goto err;
+
+ skb = tmp_skb;
+
if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n");
goto err;
if (status == CPL_ERR_RTX_NEG_ADVICE)
goto rel_skb;
+ module_put(THIS_MODULE);
+
if (status && status != CPL_ERR_TCAM_FULL &&
status != CPL_ERR_CONN_EXIST &&
status != CPL_ERR_ARP_MISS)
read_lock_bh(&csk->callback_lock);
if (csk->user_data)
iscsi_conn_failure(csk->user_data,
- ISCSI_ERR_CONN_FAILED);
+ ISCSI_ERR_TCP_CONN_CLOSE);
read_unlock_bh(&csk->callback_lock);
}
}
{"IOMEGA", "Io20S *F", NULL, BLIST_KEY},
{"INSITE", "Floptical F*8I", NULL, BLIST_KEY},
{"INSITE", "I325VM", NULL, BLIST_KEY},
+ {"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
GFP_KERNEL);
if (!clkfreq) {
- dev_err(dev, "%s: no memory\n", "freq-table-hz");
ret = -ENOMEM;
goto out;
}
if (ret && (ret != -EINVAL)) {
dev_err(dev, "%s: error reading array %d\n",
"freq-table-hz", ret);
- goto free_clkfreq;
+ return ret;
}
for (i = 0; i < sz; i += 2) {
ret = of_property_read_string_index(np,
"clock-names", i/2, (const char **)&name);
if (ret)
- goto free_clkfreq;
+ goto out;
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
- goto free_clkfreq;
+ goto out;
}
clki->min_freq = clkfreq[i];
clki->min_freq, clki->max_freq, clki->name);
list_add_tail(&clki->list, &hba->clk_list_head);
}
-free_clkfreq:
- kfree(clkfreq);
out:
return ret;
}
}
vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
- if (!vreg) {
- dev_err(dev, "No memory for %s regulator\n", name);
- goto out;
- }
+ if (!vreg)
+ return -ENOMEM;
vreg->name = kstrdup(name, GFP_KERNEL);
if (!ufshcd_is_clkgating_allowed(hba))
return;
device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
+ cancel_work_sync(&hba->clk_gating.ungate_work);
+ cancel_delayed_work_sync(&hba->clk_gating.gate_work);
}
/* Must be called with host lock acquired */
return ret;
}
+ /**
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
+ * values in hba power info
+ * @hba: per-adapter instance
+ */
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
+{
+ hba->pwr_info.gear_rx = UFS_PWM_G1;
+ hba->pwr_info.gear_tx = UFS_PWM_G1;
+ hba->pwr_info.lane_rx = 1;
+ hba->pwr_info.lane_tx = 1;
+ hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
+ hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
+ hba->pwr_info.hs_rate = 0;
+}
+
/**
* ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
* @hba: per-adapter instance
hba = shost_priv(sdev->host);
scsi_deactivate_tcq(sdev, hba->nutrs);
/* Drop the reference as it won't be needed anymore */
- if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN)
+ if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
hba->sdev_ufs_device = NULL;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ }
}
/**
static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
{
int ret = 0;
+ struct scsi_device *sdev_rpmb;
+ struct scsi_device *sdev_boot;
hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
hba->sdev_ufs_device = NULL;
goto out;
}
+ scsi_device_put(hba->sdev_ufs_device);
- hba->sdev_boot = __scsi_add_device(hba->host, 0, 0,
+ sdev_boot = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
- if (IS_ERR(hba->sdev_boot)) {
- ret = PTR_ERR(hba->sdev_boot);
- hba->sdev_boot = NULL;
+ if (IS_ERR(sdev_boot)) {
+ ret = PTR_ERR(sdev_boot);
goto remove_sdev_ufs_device;
}
+ scsi_device_put(sdev_boot);
- hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
+ sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
- if (IS_ERR(hba->sdev_rpmb)) {
- ret = PTR_ERR(hba->sdev_rpmb);
- hba->sdev_rpmb = NULL;
+ if (IS_ERR(sdev_rpmb)) {
+ ret = PTR_ERR(sdev_rpmb);
goto remove_sdev_boot;
}
+ scsi_device_put(sdev_rpmb);
goto out;
remove_sdev_boot:
- scsi_remove_device(hba->sdev_boot);
+ scsi_remove_device(sdev_boot);
remove_sdev_ufs_device:
scsi_remove_device(hba->sdev_ufs_device);
out:
return ret;
}
-/**
- * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
- * ufshcd_scsi_add_wlus()
- * @hba: per-adapter instance
- *
- */
-static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
-{
- if (hba->sdev_ufs_device) {
- scsi_remove_device(hba->sdev_ufs_device);
- hba->sdev_ufs_device = NULL;
- }
-
- if (hba->sdev_boot) {
- scsi_remove_device(hba->sdev_boot);
- hba->sdev_boot = NULL;
- }
-
- if (hba->sdev_rpmb) {
- scsi_remove_device(hba->sdev_rpmb);
- hba->sdev_rpmb = NULL;
- }
-}
-
/**
* ufshcd_probe_hba - probe hba to detect device and initialize
* @hba: per-adapter instance
if (ret)
goto out;
+ ufshcd_init_pwr_info(hba);
+
/* UniPro link is active now */
ufshcd_set_link_active(hba);
static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
struct ufs_vreg *vreg)
{
+ if (!vreg)
+ return 0;
+
return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
}
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
struct ufs_vreg *vreg)
{
+ if (!vreg)
+ return 0;
+
return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
}
if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
clk_disable_unprepare(clki->clk);
}
- } else if (!ret && on) {
+ } else if (on) {
spin_lock_irqsave(hba->host->host_lock, flags);
hba->clk_gating.state = CLKS_ON;
spin_unlock_irqrestore(hba->host->host_lock, flags);
{
unsigned char cmd[6] = { START_STOP };
struct scsi_sense_hdr sshdr;
- struct scsi_device *sdp = hba->sdev_ufs_device;
+ struct scsi_device *sdp;
+ unsigned long flags;
int ret;
- if (!sdp || !scsi_device_online(sdp))
- return -ENODEV;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ sdp = hba->sdev_ufs_device;
+ if (sdp) {
+ ret = scsi_device_get(sdp);
+ if (!ret && !scsi_device_online(sdp)) {
+ ret = -ENODEV;
+ scsi_device_put(sdp);
+ }
+ } else {
+ ret = -ENODEV;
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (ret)
+ return ret;
/*
* If scsi commands fail, the scsi mid-layer schedules scsi error-
if (!ret)
hba->curr_dev_pwr_mode = pwr_mode;
out:
+ scsi_device_put(sdp);
hba->host->eh_noresume = 0;
return ret;
}
int ret = 0;
if (!hba || !hba->is_powered)
- goto out;
+ return 0;
if (pm_runtime_suspended(hba->dev)) {
if (hba->rpm_lvl == hba->spm_lvl)
void ufshcd_remove(struct ufs_hba *hba)
{
scsi_remove_host(hba->host);
- ufshcd_scsi_remove_wlus(hba);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
* "UFS device" W-LU.
*/
struct scsi_device *sdev_ufs_device;
- struct scsi_device *sdev_rpmb;
- struct scsi_device *sdev_boot;
enum ufs_dev_pwr_mode curr_dev_pwr_mode;
enum uic_link_state uic_link_state;
chip = dws->cur_chip;
spi = message->spi;
- if (unlikely(!chip->clk_div))
- chip->clk_div = dws->max_freq / chip->speed_hz;
-
if (message->state == ERROR_STATE) {
message->status = -EIO;
goto early_exit;
if (transfer->speed_hz) {
speed = chip->speed_hz;
- if (transfer->speed_hz != speed) {
+ if ((transfer->speed_hz != speed) || (!chip->clk_div)) {
speed = transfer->speed_hz;
/* clk_div doesn't support odd number */
dev_err(&spi->dev, "No max speed HZ parameter\n");
return -EINVAL;
}
- chip->speed_hz = spi->max_speed_hz;
chip->tmode = 0; /* Tx & Rx */
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- sspi->word_width;
+ (sspi->word_width >> 1);
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- sspi->word_width;
+ (sspi->word_width >> 1);
if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
sg_free_table(sgt);
return -ENOMEM;
}
- sg_buf = page_address(vm_page) +
- ((size_t)buf & ~PAGE_MASK);
+ sg_set_page(&sgt->sgl[i], vm_page,
+ min, offset_in_page(buf));
} else {
sg_buf = buf;
+ sg_set_buf(&sgt->sgl[i], sg_buf, min);
}
- sg_set_buf(&sgt->sgl[i], sg_buf, min);
buf += min;
len -= min;
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ph2c == NULL)
return _FAIL;
- psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL);
+ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
if (psurveyPara == NULL) {
kfree(ph2c);
return _FAIL;
else
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
- pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (pcmd == NULL) {
res = _FAIL;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ph2c == NULL) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
if (pdrvextra_cmd_parm == NULL) {
kfree(ph2c);
res = _FAIL;
u8 res = _SUCCESS;
if (enqueue) {
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ph2c == NULL) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
if (pdrvextra_cmd_parm == NULL) {
kfree(ph2c);
res = _FAIL;
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ph2c == NULL) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
if (pdrvextra_cmd_parm == NULL) {
kfree(ph2c);
res = _FAIL;
u8 res = _SUCCESS;
- ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ppscmd == NULL) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
if (pdrvextra_cmd_parm == NULL) {
kfree(ppscmd);
res = _FAIL;
pcmdpriv = &padapter->cmdpriv;
- pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (pcmd_obj == NULL)
return;
cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
- pevtcmd = kzalloc(cmdsz, GFP_KERNEL);
+ pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
if (pevtcmd == NULL) {
kfree(pcmd_obj);
return;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (pcmd_obj == NULL)
return;
cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
- pevtcmd = kzalloc(cmdsz, GFP_KERNEL);
+ pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
if (pevtcmd == NULL) {
kfree(pcmd_obj);
return;
pmlmeext->scan_abort = false;/* reset */
}
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
if (ph2c == NULL)
goto exit_survey_timer_hdl;
- psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL);
+ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
if (psurveyPara == NULL) {
kfree(ph2c);
goto exit_survey_timer_hdl;
return true;
}
- bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_KERNEL);
+ bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
subtype = GetFrameSubType(pframe) >> 4;
{USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
{USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
{USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
+ {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
{USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
{} /* Terminating entry */
};
len = sprintf(buf, "TargetAddress="
"%s:%hu,%hu",
inaddr_any ? conn->local_ip : np->np_ip,
- inaddr_any ? conn->local_port : np->np_port,
+ np->np_port,
tpg->tpgt);
len += 1;
struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
u32 pr_res_mapped_lun = 0;
- int all_reg = 0, calling_it_nexus = 0, released_regs = 0;
+ int all_reg = 0, calling_it_nexus = 0;
+ bool sa_res_key_unmatched = sa_res_key != 0;
int prh_type = 0, prh_scope = 0;
if (!se_sess)
if (!all_reg) {
if (pr_reg->pr_res_key != sa_res_key)
continue;
+ sa_res_key_unmatched = false;
calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
pr_reg_nacl = pr_reg->pr_reg_nacl;
__core_scsi3_free_registration(dev, pr_reg,
(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
NULL, calling_it_nexus);
- released_regs++;
} else {
/*
* Case for any existing all registrants type
if ((sa_res_key) &&
(pr_reg->pr_res_key != sa_res_key))
continue;
+ sa_res_key_unmatched = false;
calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
if (calling_it_nexus)
__core_scsi3_free_registration(dev, pr_reg,
(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
NULL, 0);
- released_regs++;
}
if (!calling_it_nexus)
core_scsi3_ua_allocate(pr_reg_nacl,
* registered reservation key, then the device server shall
* complete the command with RESERVATION CONFLICT status.
*/
- if (!released_regs) {
+ if (sa_res_key_unmatched) {
spin_unlock(&dev->dev_reservation_lock);
core_scsi3_put_pr_reg(pr_reg_n);
return TCM_RESERVATION_CONFLICT;
* and let it call back once the write buffers are ready.
*/
target_add_to_state_list(cmd);
- if (cmd->data_direction != DMA_TO_DEVICE) {
+ if (cmd->data_direction != DMA_TO_DEVICE || cmd->data_length == 0) {
target_execute_cmd(cmd);
return 0;
}
unsigned int cpufreq_state;
unsigned int cpufreq_val;
struct cpumask allowed_cpus;
+ struct list_head node;
};
static DEFINE_IDR(cpufreq_idr);
static DEFINE_MUTEX(cooling_cpufreq_lock);
static unsigned int cpufreq_dev_count;
-/* notify_table passes value to the CPUFREQ_ADJUST callback function. */
-#define NOTIFY_INVALID NULL
-static struct cpufreq_cooling_device *notify_device;
+static LIST_HEAD(cpufreq_dev_list);
/**
* get_idr - function to get a unique id.
cpufreq_device->cpufreq_state = cooling_state;
cpufreq_device->cpufreq_val = clip_freq;
- notify_device = cpufreq_device;
for_each_cpu(cpuid, mask) {
if (is_cpufreq_valid(cpuid))
cpufreq_update_policy(cpuid);
}
- notify_device = NOTIFY_INVALID;
-
return 0;
}
{
struct cpufreq_policy *policy = data;
unsigned long max_freq = 0;
+ struct cpufreq_cooling_device *cpufreq_dev;
- if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID)
+ if (event != CPUFREQ_ADJUST)
return 0;
- if (cpumask_test_cpu(policy->cpu, ¬ify_device->allowed_cpus))
- max_freq = notify_device->cpufreq_val;
- else
- return 0;
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+ if (!cpumask_test_cpu(policy->cpu,
+ &cpufreq_dev->allowed_cpus))
+ continue;
+
+ if (!cpufreq_dev->cpufreq_val)
+ cpufreq_dev->cpufreq_val = get_cpu_frequency(
+ cpumask_any(&cpufreq_dev->allowed_cpus),
+ cpufreq_dev->cpufreq_state);
- /* Never exceed user_policy.max */
- if (max_freq > policy->user_policy.max)
- max_freq = policy->user_policy.max;
+ max_freq = cpufreq_dev->cpufreq_val;
- if (policy->max != max_freq)
- cpufreq_verify_within_limits(policy, 0, max_freq);
+ if (policy->max != max_freq)
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
return 0;
}
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
cpufreq_dev_count++;
+ list_add(&cpufreq_dev->node, &cpufreq_dev_list);
mutex_unlock(&cooling_cpufreq_lock);
cpufreq_dev = cdev->devdata;
mutex_lock(&cooling_cpufreq_lock);
+ list_del(&cpufreq_dev->node);
cpufreq_dev_count--;
/* Unregister the notifier for the last cpufreq cooling device */
th_zone = sensor_conf->pzone_data;
- if (th_zone->therm_dev)
- thermal_zone_device_unregister(th_zone->therm_dev);
+ thermal_zone_device_unregister(th_zone->therm_dev);
- for (i = 0; i < th_zone->cool_dev_size; i++) {
- if (th_zone->cool_dev[i])
- cpufreq_cooling_unregister(th_zone->cool_dev[i]);
- }
+ for (i = 0; i < th_zone->cool_dev_size; ++i)
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
dev_info(sensor_conf->dev,
"Exynos: Kernel Thermal management unregistered\n");
}
EXPORT_SYMBOL_GPL(st_thermal_unregister);
+#ifdef CONFIG_PM_SLEEP
static int st_thermal_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
return 0;
}
+#endif
+
SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int of_serial_suspend(struct device *dev)
-{
- struct of_serial_info *info = dev_get_drvdata(dev);
-
- serial8250_suspend_port(info->line);
- if (info->clk)
- clk_disable_unprepare(info->clk);
-
- return 0;
-}
-
-static int of_serial_resume(struct device *dev)
-{
- struct of_serial_info *info = dev_get_drvdata(dev);
-
- if (info->clk)
- clk_prepare_enable(info->clk);
-
- serial8250_resume_port(info->line);
-
- return 0;
-}
-#endif
-static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume);
-
/*
* A few common types, add more as needed.
*/
.name = "of_serial",
.owner = THIS_MODULE,
.of_match_table = of_platform_serial_table,
- .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Microsoft Wireless Laser Mouse 6000 Receiver */
+ { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* Microsoft LifeCam-VX700 v2.0 */
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
trb = dwc->ep0_trb;
+ r = next_request(&ep0->request_list);
+ if (!r)
+ return;
+
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING) {
dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
return;
}
- r = next_request(&ep0->request_list);
- if (!r)
- return;
-
ur = &r->request;
length = trb->size & DWC3_TRB_SIZE_MASK;
#include <linux/slab.h>
-#include <linux/device.h>
#include <asm/unaligned.h>
#include "xhci.h"
* including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
* is enabled, so also enable remote wake here.
*/
- if (hcd->self.root_hub->do_remote_wakeup
- && device_may_wakeup(hcd->self.controller)) {
-
+ if (hcd->self.root_hub->do_remote_wakeup) {
if (t1 & PORT_CONNECT) {
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
t2 &= ~PORT_WKCONN_E;
if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
pdev->no_d3cold = true;
- return xhci_suspend(xhci);
+ return xhci_suspend(xhci, do_wakeup);
}
static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- return xhci_suspend(xhci);
+ /*
+ * xhci_suspend() needs `do_wakeup` to know whether host is allowed
+ * to do wakeup during suspend. Since xhci_plat_suspend is currently
+ * only designed for system suspend, device_may_wakeup() is enough
+ * to dertermine whether host is allowed to do wakeup. Need to
+ * reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
+ * also applies to runtime suspend.
+ */
+ return xhci_suspend(xhci, device_may_wakeup(dev));
}
static int xhci_plat_resume(struct device *dev)
false);
xhci_ring_cmd_db(xhci);
} else {
- /* Clear our internal halted state and restart the ring(s) */
+ /* Clear our internal halted state */
xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
- ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
}
ep->stopped_td = td;
return 0;
} else {
- if (trb_comp_code == COMP_STALL) {
- /* The transfer is completed from the driver's
- * perspective, but we need to issue a set dequeue
- * command for this stalled endpoint to move the dequeue
- * pointer past the TD. We can't do that here because
- * the halt condition must be cleared first. Let the
- * USB class driver clear the stall later.
- */
- ep->stopped_td = td;
- ep->stopped_stream = ep_ring->stream_id;
- } else if (xhci_requires_manual_halt_cleanup(xhci,
- ep_ctx, trb_comp_code)) {
- /* Other types of errors halt the endpoint, but the
- * class driver doesn't call usb_reset_endpoint() unless
- * the error is -EPIPE. Clear the halted status in the
- * xHCI hardware manually.
+ if (trb_comp_code == COMP_STALL ||
+ xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
+ trb_comp_code)) {
+ /* Issue a reset endpoint command to clear the host side
+ * halt, followed by a set dequeue command to move the
+ * dequeue pointer past the TD.
+ * The class driver clears the device side halt later.
*/
xhci_cleanup_halted_endpoint(xhci,
slot_id, ep_index, ep_ring->stream_id,
else
td->urb->actual_length = 0;
- xhci_cleanup_halted_endpoint(xhci,
- slot_id, ep_index, 0, td, event_trb);
- return finish_td(xhci, td, event_trb, event, ep, status, true);
+ return finish_td(xhci, td, event_trb, event, ep, status, false);
}
/*
* Did we transfer any data, despite the errors that might have
if (ret) {
urb = td->urb;
urb_priv = urb->hcpriv;
- /* Leave the TD around for the reset endpoint function
- * to use(but only if it's not a control endpoint,
- * since we already queued the Set TR dequeue pointer
- * command for stalled control endpoints).
- */
- if (usb_endpoint_xfer_control(&urb->ep->desc) ||
- (trb_comp_code != COMP_STALL &&
- trb_comp_code != COMP_BABBLE))
- xhci_urb_free_priv(xhci, urb_priv);
- else
- kfree(urb_priv);
+
+ xhci_urb_free_priv(xhci, urb_priv);
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
if ((urb->actual_length != urb->transfer_buffer_length &&
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
+#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
+
/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
static int link_quirk;
module_param(link_quirk, int, S_IRUGO | S_IWUSR);
xhci_set_cmd_ring_deq(xhci);
}
+static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
+{
+ int port_index;
+ __le32 __iomem **port_array;
+ unsigned long flags;
+ u32 t1, t2;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* disble usb3 ports Wake bits*/
+ port_index = xhci->num_usb3_ports;
+ port_array = xhci->usb3_ports;
+ while (port_index--) {
+ t1 = readl(port_array[port_index]);
+ t1 = xhci_port_state_to_neutral(t1);
+ t2 = t1 & ~PORT_WAKE_BITS;
+ if (t1 != t2)
+ writel(t2, port_array[port_index]);
+ }
+
+ /* disble usb2 ports Wake bits*/
+ port_index = xhci->num_usb2_ports;
+ port_array = xhci->usb2_ports;
+ while (port_index--) {
+ t1 = readl(port_array[port_index]);
+ t1 = xhci_port_state_to_neutral(t1);
+ t2 = t1 & ~PORT_WAKE_BITS;
+ if (t1 != t2)
+ writel(t2, port_array[port_index]);
+ }
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
/*
* Stop HC (not bus-specific)
*
* This is called when the machine transition into S3/S4 mode.
*
*/
-int xhci_suspend(struct xhci_hcd *xhci)
+int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
{
int rc = 0;
unsigned int delay = XHCI_MAX_HALT_USEC;
xhci->shared_hcd->state != HC_STATE_SUSPENDED)
return -EINVAL;
+ /* Clear root port wake on bits if wakeup not allowed. */
+ if (!do_wakeup)
+ xhci_disable_port_wake_on_bits(xhci);
+
/* Don't poll the roothubs on bus suspend. */
xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
}
}
-/* Deal with stalled endpoints. The core should have sent the control message
- * to clear the halt condition. However, we need to make the xHCI hardware
- * reset its sequence number, since a device will expect a sequence number of
- * zero after the halt condition is cleared.
+/* Called when clearing halted device. The core should have sent the control
+ * message to clear the device halt condition. The host side of the halt should
+ * already be cleared with a reset endpoint command issued when the STALL tx
+ * event was received.
+ *
* Context: in_interrupt
*/
+
void xhci_endpoint_reset(struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
- struct usb_device *udev;
- unsigned int ep_index;
- unsigned long flags;
- int ret;
- struct xhci_virt_ep *virt_ep;
- struct xhci_command *command;
xhci = hcd_to_xhci(hcd);
- udev = (struct usb_device *) ep->hcpriv;
- /* Called with a root hub endpoint (or an endpoint that wasn't added
- * with xhci_add_endpoint()
- */
- if (!ep->hcpriv)
- return;
- ep_index = xhci_get_endpoint_index(&ep->desc);
- virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
- if (!virt_ep->stopped_td) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
- "Endpoint 0x%x not halted, refusing to reset.",
- ep->desc.bEndpointAddress);
- return;
- }
- if (usb_endpoint_xfer_control(&ep->desc)) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
- "Control endpoint stall already handled.");
- return;
- }
- command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
- if (!command)
- return;
-
- xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
- "Queueing reset endpoint command");
- spin_lock_irqsave(&xhci->lock, flags);
- ret = xhci_queue_reset_ep(xhci, command, udev->slot_id, ep_index);
/*
- * Can't change the ring dequeue pointer until it's transitioned to the
- * stopped state, which is only upon a successful reset endpoint
- * command. Better hope that last command worked!
+ * We might need to implement the config ep cmd in xhci 4.8.1 note:
+ * The Reset Endpoint Command may only be issued to endpoints in the
+ * Halted state. If software wishes reset the Data Toggle or Sequence
+ * Number of an endpoint that isn't in the Halted state, then software
+ * may issue a Configure Endpoint Command with the Drop and Add bits set
+ * for the target endpoint. that is in the Stopped state.
*/
- if (!ret) {
- xhci_cleanup_stalled_ring(xhci, udev, ep_index);
- kfree(virt_ep->stopped_td);
- xhci_ring_cmd_db(xhci);
- }
- virt_ep->stopped_td = NULL;
- virt_ep->stopped_stream = 0;
- spin_unlock_irqrestore(&xhci->lock, flags);
- if (ret)
- xhci_warn(xhci, "FIXME allocate a new ring segment\n");
+ /* For now just print debug to follow the situation */
+ xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n",
+ ep->desc.bEndpointAddress);
}
static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *));
#ifdef CONFIG_PM
-int xhci_suspend(struct xhci_hcd *xhci);
+int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
#else
#define xhci_suspend NULL
{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
+ { USB_DEVICE(0x10C4, 0x8875) }, /* CEL MeshConnect USB Stick */
{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
{ USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
{ USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_4701_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9300_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9301_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9302_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9303_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9304_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9305_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9306_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9307_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9308_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9309_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930A_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930B_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930C_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930D_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930E_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930F_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9310_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9311_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9312_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9313_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9314_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9315_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9316_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9317_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9318_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9319_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931A_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931B_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931C_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931D_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931E_PID) },
+ { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
#define BAYER_CONTOUR_CABLE_PID 0x6001
/*
- * The following are the values for the Matrix Orbital FTDI Range
- * Anything in this range will use an FT232RL.
+ * Matrix Orbital Intelligent USB displays.
+ * http://www.matrixorbital.com
*/
#define MTXORB_VID 0x1B3D
#define MTXORB_FTDI_RANGE_0100_PID 0x0100
#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
-
-
+#define MTXORB_FTDI_RANGE_4701_PID 0x4701
+#define MTXORB_FTDI_RANGE_9300_PID 0x9300
+#define MTXORB_FTDI_RANGE_9301_PID 0x9301
+#define MTXORB_FTDI_RANGE_9302_PID 0x9302
+#define MTXORB_FTDI_RANGE_9303_PID 0x9303
+#define MTXORB_FTDI_RANGE_9304_PID 0x9304
+#define MTXORB_FTDI_RANGE_9305_PID 0x9305
+#define MTXORB_FTDI_RANGE_9306_PID 0x9306
+#define MTXORB_FTDI_RANGE_9307_PID 0x9307
+#define MTXORB_FTDI_RANGE_9308_PID 0x9308
+#define MTXORB_FTDI_RANGE_9309_PID 0x9309
+#define MTXORB_FTDI_RANGE_930A_PID 0x930A
+#define MTXORB_FTDI_RANGE_930B_PID 0x930B
+#define MTXORB_FTDI_RANGE_930C_PID 0x930C
+#define MTXORB_FTDI_RANGE_930D_PID 0x930D
+#define MTXORB_FTDI_RANGE_930E_PID 0x930E
+#define MTXORB_FTDI_RANGE_930F_PID 0x930F
+#define MTXORB_FTDI_RANGE_9310_PID 0x9310
+#define MTXORB_FTDI_RANGE_9311_PID 0x9311
+#define MTXORB_FTDI_RANGE_9312_PID 0x9312
+#define MTXORB_FTDI_RANGE_9313_PID 0x9313
+#define MTXORB_FTDI_RANGE_9314_PID 0x9314
+#define MTXORB_FTDI_RANGE_9315_PID 0x9315
+#define MTXORB_FTDI_RANGE_9316_PID 0x9316
+#define MTXORB_FTDI_RANGE_9317_PID 0x9317
+#define MTXORB_FTDI_RANGE_9318_PID 0x9318
+#define MTXORB_FTDI_RANGE_9319_PID 0x9319
+#define MTXORB_FTDI_RANGE_931A_PID 0x931A
+#define MTXORB_FTDI_RANGE_931B_PID 0x931B
+#define MTXORB_FTDI_RANGE_931C_PID 0x931C
+#define MTXORB_FTDI_RANGE_931D_PID 0x931D
+#define MTXORB_FTDI_RANGE_931E_PID 0x931E
+#define MTXORB_FTDI_RANGE_931F_PID 0x931F
/*
* The Mobility Lab (TML)
if ((data[0] & 0x80) == 0) {
/* no errors on individual bytes, only
possible overrun err */
- if (data[0] & RXERROR_OVERRUN)
- err = TTY_OVERRUN;
- else
- err = 0;
+ if (data[0] & RXERROR_OVERRUN) {
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
+ }
for (i = 1; i < urb->actual_length ; ++i)
- tty_insert_flip_char(&port->port, data[i], err);
+ tty_insert_flip_char(&port->port, data[i],
+ TTY_NORMAL);
} else {
/* some bytes had errors, every byte has status */
dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
for (i = 0; i + 1 < urb->actual_length; i += 2) {
- int stat = data[i], flag = 0;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
+ int stat = data[i];
+ int flag = TTY_NORMAL;
+
+ if (stat & RXERROR_OVERRUN) {
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
+ }
/* XXX should handle break (0x10) */
+ if (stat & RXERROR_PARITY)
+ flag = TTY_PARITY;
+ else if (stat & RXERROR_FRAMING)
+ flag = TTY_FRAME;
+
tty_insert_flip_char(&port->port, data[i+1],
flag);
}
} else {
/* some bytes had errors, every byte has status */
for (i = 0; i + 1 < urb->actual_length; i += 2) {
- int stat = data[i], flag = 0;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
+ int stat = data[i];
+ int flag = TTY_NORMAL;
+
+ if (stat & RXERROR_OVERRUN) {
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
+ }
/* XXX should handle break (0x10) */
+ if (stat & RXERROR_PARITY)
+ flag = TTY_PARITY;
+ else if (stat & RXERROR_FRAMING)
+ flag = TTY_FRAME;
+
tty_insert_flip_char(&port->port, data[i+1],
flag);
}
*/
for (x = 0; x + 1 < len &&
i + 1 < urb->actual_length; x += 2) {
- int stat = data[i], flag = 0;
+ int stat = data[i];
+ int flag = TTY_NORMAL;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
+ if (stat & RXERROR_OVERRUN) {
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
+ }
/* XXX should handle break (0x10) */
+ if (stat & RXERROR_PARITY)
+ flag = TTY_PARITY;
+ else if (stat & RXERROR_FRAMING)
+ flag = TTY_FRAME;
+
tty_insert_flip_char(&port->port, data[i+1],
flag);
i += 2;
if ((data[0] & 0x80) == 0) {
/* no errors on individual bytes, only
possible overrun err*/
- if (data[0] & RXERROR_OVERRUN)
- err = TTY_OVERRUN;
- else
- err = 0;
+ if (data[0] & RXERROR_OVERRUN) {
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
+ }
for (i = 1; i < urb->actual_length ; ++i)
tty_insert_flip_char(&port->port,
- data[i], err);
+ data[i], TTY_NORMAL);
} else {
/* some bytes had errors, every byte has status */
dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
for (i = 0; i + 1 < urb->actual_length; i += 2) {
- int stat = data[i], flag = 0;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
+ int stat = data[i];
+ int flag = TTY_NORMAL;
+
+ if (stat & RXERROR_OVERRUN) {
+ tty_insert_flip_char(
+ &port->port, 0,
+ TTY_OVERRUN);
+ }
/* XXX should handle break (0x10) */
+ if (stat & RXERROR_PARITY)
+ flag = TTY_PARITY;
+ else if (stat & RXERROR_FRAMING)
+ flag = TTY_FRAME;
+
tty_insert_flip_char(&port->port,
data[i+1], flag);
}
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_FRAME;
}
- if (lsr & UART_LSR_OE){
+ if (lsr & UART_LSR_OE) {
port->icount.overrun++;
- if (*tty_flag == TTY_NORMAL)
- *tty_flag = TTY_OVERRUN;
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
}
if ((len >= 4) &&
(packet[0] == 0x1b) && (packet[1] == 0x1b) &&
((packet[2] == 0x00) || (packet[2] == 0x01))) {
- if (packet[2] == 0x00) {
+ if (packet[2] == 0x00)
ssu100_update_lsr(port, packet[3], &flag);
- if (flag == TTY_OVERRUN)
- tty_insert_flip_char(&port->port, 0,
- TTY_OVERRUN);
- }
if (packet[2] == 0x01)
ssu100_update_msr(port, packet[3]);
"VL711",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_ATA_1X),
+
+/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
+ "Hitachi",
+ "External HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_UAS),
vhost_scsi_set_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
+ struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg;
struct tcm_vhost_tpg **vs_tpg;
ret = -EEXIST;
goto out;
}
+ /*
+ * In order to ensure individual vhost-scsi configfs
+ * groups cannot be removed while in use by vhost ioctl,
+ * go ahead and take an explicit se_tpg->tpg_group.cg_item
+ * dependency now.
+ */
+ se_tpg = &tpg->se_tpg;
+ ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
+ if (ret) {
+ pr_warn("configfs_depend_item() failed: %d\n", ret);
+ kfree(vs_tpg);
+ mutex_unlock(&tpg->tv_tpg_mutex);
+ goto out;
+ }
tpg->tv_tpg_vhost_count++;
tpg->vhost_scsi = vs;
vs_tpg[tpg->tport_tpgt] = tpg;
vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
+ struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg;
struct vhost_virtqueue *vq;
vs->vs_tpg[target] = NULL;
match = true;
mutex_unlock(&tpg->tv_tpg_mutex);
+ /*
+ * Release se_tpg->tpg_group.cg_item configfs dependency now
+ * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur.
+ */
+ se_tpg = &tpg->se_tpg;
+ configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
}
if (match) {
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
static const struct s3c2410_wdt_variant drv_data_exynos7 = {
.disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
.mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
- .mask_bit = 0,
+ .mask_bit = 23,
.rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
.rst_stat_bit = 23, /* A57 WDTRESET */
.quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
obj-$(CONFIG_AUTOFS4_FS) += autofs4/
obj-$(CONFIG_ADFS_FS) += adfs/
obj-$(CONFIG_FUSE_FS) += fuse/
-obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/
+obj-$(CONFIG_OVERLAY_FS) += overlayfs/
obj-$(CONFIG_UDF_FS) += udf/
obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
obj-$(CONFIG_OMFS_FS) += omfs/
static const struct file_operations aio_ring_fops;
static const struct address_space_operations aio_ctx_aops;
+/* Backing dev info for aio fs.
+ * -no dirty page accounting or writeback happens
+ */
+static struct backing_dev_info aio_fs_backing_dev_info = {
+ .name = "aiofs",
+ .state = 0,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_MAP_COPY,
+};
+
static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
{
struct qstr this = QSTR_INIT("[aio]", 5);
inode->i_mapping->a_ops = &aio_ctx_aops;
inode->i_mapping->private_data = ctx;
+ inode->i_mapping->backing_dev_info = &aio_fs_backing_dev_info;
inode->i_size = PAGE_SIZE * nr_pages;
path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this);
if (IS_ERR(aio_mnt))
panic("Failed to create aio fs mount.");
+ if (bdi_init(&aio_fs_backing_dev_info))
+ panic("Failed to init aio fs backing dev info.");
+
kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
.mmap = aio_ring_mmap,
};
-static int aio_set_page_dirty(struct page *page)
-{
- return 0;
-}
-
#if IS_ENABLED(CONFIG_MIGRATION)
static int aio_migratepage(struct address_space *mapping, struct page *new,
struct page *old, enum migrate_mode mode)
#endif
static const struct address_space_operations aio_ctx_aops = {
- .set_page_dirty = aio_set_page_dirty,
+ .set_page_dirty = __set_page_dirty_no_writeback,
#if IS_ENABLED(CONFIG_MIGRATION)
.migratepage = aio_migratepage,
#endif
pr_debug("pid(%d) page[%d]->count=%d\n",
current->pid, i, page_count(page));
SetPageUptodate(page);
- SetPageDirty(page);
unlock_page(page);
ctx->ring_pages[i] = page;
bytes = min(bytes, working_bytes);
kaddr = kmap_atomic(page_out);
memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
- if (*pg_index == (vcnt - 1) && *pg_offset == 0)
- memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
kunmap_atomic(kaddr);
flush_dcache_page(page_out);
return 1;
}
+
+/*
+ * When uncompressing data, we need to make sure and zero any parts of
+ * the biovec that were not filled in by the decompression code. pg_index
+ * and pg_offset indicate the last page and the last offset of that page
+ * that have been filled in. This will zero everything remaining in the
+ * biovec.
+ */
+void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt,
+ unsigned long pg_index,
+ unsigned long pg_offset)
+{
+ while (pg_index < vcnt) {
+ struct page *page = bvec[pg_index].bv_page;
+ unsigned long off = bvec[pg_index].bv_offset;
+ unsigned long len = bvec[pg_index].bv_len;
+
+ if (pg_offset < off)
+ pg_offset = off;
+ if (pg_offset < off + len) {
+ unsigned long bytes = off + len - pg_offset;
+ char *kaddr;
+
+ kaddr = kmap_atomic(page);
+ memset(kaddr + pg_offset, 0, bytes);
+ kunmap_atomic(kaddr);
+ }
+ pg_index++;
+ pg_offset = 0;
+ }
+}
unsigned long nr_pages);
int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
int mirror_num, unsigned long bio_flags);
-
+void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt,
+ unsigned long pg_index,
+ unsigned long pg_offset);
struct btrfs_compress_op {
struct list_head *(*alloc_workspace)(void);
{
int i;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
- /* lockdep really cares that we take all of these spinlocks
- * in the right order. If any of the locks in the path are not
- * currently blocking, it is going to complain. So, make really
- * really sure by forcing the path to blocking before we clear
- * the path blocking.
- */
if (held) {
btrfs_set_lock_blocking_rw(held, held_rw);
if (held_rw == BTRFS_WRITE_LOCK)
held_rw = BTRFS_READ_LOCK_BLOCKING;
}
btrfs_set_path_blocking(p);
-#endif
for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
if (p->nodes[i] && p->locks[i]) {
}
}
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
if (held)
btrfs_clear_lock_blocking_rw(held, held_rw);
-#endif
}
/* this also releases the path */
}
p->locks[level] = BTRFS_WRITE_LOCK;
} else {
- err = btrfs_try_tree_read_lock(b);
+ err = btrfs_tree_read_lock_atomic(b);
if (!err) {
btrfs_set_path_blocking(p);
btrfs_tree_read_lock(b);
}
level = btrfs_header_level(b);
- err = btrfs_try_tree_read_lock(b);
+ err = btrfs_tree_read_lock_atomic(b);
if (!err) {
btrfs_set_path_blocking(p);
btrfs_tree_read_lock(b);
atomic_inc(&eb->spinning_readers);
}
+/*
+ * take a spinning read lock.
+ * returns 1 if we get the read lock and 0 if we don't
+ * this won't wait for blocking writers
+ */
+int btrfs_tree_read_lock_atomic(struct extent_buffer *eb)
+{
+ if (atomic_read(&eb->blocking_writers))
+ return 0;
+
+ read_lock(&eb->lock);
+ if (atomic_read(&eb->blocking_writers)) {
+ read_unlock(&eb->lock);
+ return 0;
+ }
+ atomic_inc(&eb->read_locks);
+ atomic_inc(&eb->spinning_readers);
+ return 1;
+}
+
/*
* returns 1 if we get the read lock and 0 if we don't
* this won't wait for blocking writers
atomic_read(&eb->blocking_readers))
return 0;
- if (!write_trylock(&eb->lock))
- return 0;
-
+ write_lock(&eb->lock);
if (atomic_read(&eb->blocking_writers) ||
atomic_read(&eb->blocking_readers)) {
write_unlock(&eb->lock);
void btrfs_assert_tree_locked(struct extent_buffer *eb);
int btrfs_try_tree_read_lock(struct extent_buffer *eb);
int btrfs_try_tree_write_lock(struct extent_buffer *eb);
+int btrfs_tree_read_lock_atomic(struct extent_buffer *eb);
+
static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw)
{
}
done:
kunmap(pages_in[page_in_index]);
+ if (!ret)
+ btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
return ret;
}
goto out;
}
+ /*
+ * the caller is already checking against PAGE_SIZE, but lets
+ * move this check closer to the memcpy/memset
+ */
+ destlen = min_t(unsigned long, destlen, PAGE_SIZE);
bytes = min_t(unsigned long, destlen, out_len - start_byte);
kaddr = kmap_atomic(dest_page);
memcpy(kaddr, workspace->buf + start_byte, bytes);
+
+ /*
+ * btrfs_getblock is doing a zero on the tail of the page too,
+ * but this will cover anything missing from the decompressed
+ * data.
+ */
+ if (bytes < destlen)
+ memset(kaddr+bytes, 0, destlen-bytes);
kunmap_atomic(kaddr);
out:
return ret;
zlib_inflateEnd(&workspace->strm);
if (data_in)
kunmap(pages_in[page_in_index]);
+ if (!ret)
+ btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
return ret;
}
struct workspace *workspace = list_entry(ws, struct workspace, list);
int ret = 0;
int wbits = MAX_WBITS;
- unsigned long bytes_left = destlen;
+ unsigned long bytes_left;
unsigned long total_out = 0;
+ unsigned long pg_offset = 0;
char *kaddr;
+ destlen = min_t(unsigned long, destlen, PAGE_SIZE);
+ bytes_left = destlen;
+
workspace->strm.next_in = data_in;
workspace->strm.avail_in = srclen;
workspace->strm.total_in = 0;
unsigned long buf_start;
unsigned long buf_offset;
unsigned long bytes;
- unsigned long pg_offset = 0;
ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
ret = 0;
zlib_inflateEnd(&workspace->strm);
+
+ /*
+ * this should only happen if zlib returned fewer bytes than we
+ * expected. btrfs_get_block is responsible for zeroing from the
+ * end of the inline extent (destlen) to the end of the page
+ */
+ if (pg_offset < destlen) {
+ kaddr = kmap_atomic(dest_page);
+ memset(kaddr + pg_offset, 0, destlen - pg_offset);
+ kunmap_atomic(kaddr);
+ }
return ret;
}
struct dentry *parent = lock_parent(dentry);
if (likely(!dentry->d_lockref.count)) {
__dentry_kill(dentry);
+ dput(parent);
goto restart;
}
if (parent)
}
alias = d_find_alias(inode);
- if (alias && !vfat_d_anon_disconn(alias)) {
+ /*
+ * Checking "alias->d_parent == dentry->d_parent" to make sure
+ * FS is not corrupted (especially double linked dir).
+ */
+ if (alias && alias->d_parent == dentry->d_parent &&
+ !vfat_d_anon_disconn(alias)) {
/*
* This inode has non anonymous-DCACHE_DISCONNECTED
* dentry. This means, the user did ->lookup() by an
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
- dentry->d_time = dentry->d_parent->d_inode->i_version;
- dentry = d_splice_alias(inode, dentry);
- if (dentry)
- dentry->d_time = dentry->d_parent->d_inode->i_version;
- return dentry;
-
+ if (!inode)
+ dentry->d_time = dir->i_version;
+ return d_splice_alias(inode, dentry);
error:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
return ERR_PTR(err);
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
- dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
+ dentry->d_time = dir->i_version;
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
+ dentry->d_time = dir->i_version;
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
- dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
mutex_unlock(&MSDOS_SB(sb)->s_lock);
s32 sbsector;
};
-/*
- * Compute the hash for the isofs name corresponding to the dentry.
- */
-static int
-isofs_hash_common(struct qstr *qstr, int ms)
-{
- const char *name;
- int len;
-
- len = qstr->len;
- name = qstr->name;
- if (ms) {
- while (len && name[len-1] == '.')
- len--;
- }
-
- qstr->hash = full_name_hash(name, len);
-
- return 0;
-}
-
/*
* Compute the hash for the isofs name corresponding to the dentry.
*/
}
#ifdef CONFIG_JOLIET
+/*
+ * Compute the hash for the isofs name corresponding to the dentry.
+ */
+static int
+isofs_hash_common(struct qstr *qstr, int ms)
+{
+ const char *name;
+ int len;
+
+ len = qstr->len;
+ name = qstr->name;
+ if (ms) {
+ while (len && name[len-1] == '.')
+ len--;
+ }
+
+ qstr->hash = full_name_hash(name, len);
+
+ return 0;
+}
+
static int
isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
{
journal->j_chksum_driver = NULL;
return 0;
}
- }
- /* Precompute checksum seed for all metadata */
- if (jbd2_journal_has_csum_v2or3(journal))
+ /* Precompute checksum seed for all metadata */
journal->j_csum_seed = jbd2_chksum(journal, ~0,
sb->s_uuid,
sizeof(sb->s_uuid));
+ }
}
/* If enabling v1 checksums, downgrade superblock */
{
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
- dprintk("%s slot is busy\n", __func__);
- return false;
+ /* Race breaker */
+ if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
+ dprintk("%s slot is busy\n", __func__);
+ return false;
+ }
+ rpc_wake_up_queued_task(&clp->cl_cb_waitq, task);
}
return true;
}
(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
- (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL)
+#define NFSD4_2_SECURITY_ATTRS FATTR4_WORD2_SECURITY_LABEL
#else
-#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
+#define NFSD4_2_SECURITY_ATTRS 0
#endif
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
+ (NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
+ NFSD4_2_SECURITY_ATTRS)
+
static inline u32 nfsd_suppattrs0(u32 minorversion)
{
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
-config OVERLAYFS_FS
+config OVERLAY_FS
tristate "Overlay filesystem support"
help
An overlay filesystem combines two filesystems - an 'upper' filesystem
# Makefile for the overlay filesystem.
#
-obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o
+obj-$(CONFIG_OVERLAY_FS) += overlay.o
-overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o
+overlay-objs := super.o inode.o dir.o readdir.o copy_up.o
return ERR_PTR(err);
}
-static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
- enum ovl_path_type type)
+static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
{
int err;
struct dentry *ret = NULL;
err = ovl_check_empty_dir(dentry, &list);
if (err)
ret = ERR_PTR(err);
- else if (type == OVL_PATH_MERGE)
- ret = ovl_clear_empty(dentry, &list);
+ else {
+ /*
+ * If no upperdentry then skip clearing whiteouts.
+ *
+ * Can race with copy-up, since we don't hold the upperdir
+ * mutex. Doesn't matter, since copy-up can't create a
+ * non-empty directory from an empty one.
+ */
+ if (ovl_dentry_upper(dentry))
+ ret = ovl_clear_empty(dentry, &list);
+ }
ovl_cache_free(&list);
return err;
}
-static int ovl_remove_and_whiteout(struct dentry *dentry,
- enum ovl_path_type type, bool is_dir)
+static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
{
struct dentry *workdir = ovl_workdir(dentry);
struct inode *wdir = workdir->d_inode;
int err;
if (is_dir) {
- opaquedir = ovl_check_empty_and_clear(dentry, type);
+ opaquedir = ovl_check_empty_and_clear(dentry);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out;
if (IS_ERR(whiteout))
goto out_unlock;
- if (type == OVL_PATH_LOWER) {
+ upper = ovl_dentry_upper(dentry);
+ if (!upper) {
upper = lookup_one_len(dentry->d_name.name, upperdir,
- dentry->d_name.len);
+ dentry->d_name.len);
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto kill_whiteout;
} else {
int flags = 0;
- upper = ovl_dentry_upper(dentry);
if (opaquedir)
upper = opaquedir;
err = -ESTALE;
cap_raise(override_cred->cap_effective, CAP_CHOWN);
old_cred = override_creds(override_cred);
- err = ovl_remove_and_whiteout(dentry, type, is_dir);
+ err = ovl_remove_and_whiteout(dentry, is_dir);
revert_creds(old_cred);
put_cred(override_cred);
}
if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) {
- opaquedir = ovl_check_empty_and_clear(new, new_type);
+ opaquedir = ovl_check_empty_and_clear(new);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir)) {
opaquedir = NULL;
return err;
}
+static bool ovl_need_xattr_filter(struct dentry *dentry,
+ enum ovl_path_type type)
+{
+ return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
+}
+
ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
void *value, size_t size)
{
- if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
- ovl_is_private_xattr(name))
+ struct path realpath;
+ enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+
+ if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
return -ENODATA;
- return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
+ return vfs_getxattr(realpath.dentry, name, value, size);
}
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{
+ struct path realpath;
+ enum ovl_path_type type = ovl_path_real(dentry, &realpath);
ssize_t res;
int off;
- res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
+ res = vfs_listxattr(realpath.dentry, list, size);
if (res <= 0 || size == 0)
return res;
- if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
+ if (!ovl_need_xattr_filter(dentry, type))
return res;
/* filter out private xattrs */
{
int err;
struct path realpath;
- enum ovl_path_type type;
+ enum ovl_path_type type = ovl_path_real(dentry, &realpath);
err = ovl_want_write(dentry);
if (err)
goto out;
- if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
- ovl_is_private_xattr(name))
+ err = -ENODATA;
+ if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
goto out_drop_write;
- type = ovl_path_real(dentry, &realpath);
if (type == OVL_PATH_LOWER) {
err = vfs_getxattr(realpath.dentry, name, NULL, 0);
if (err < 0)
return 0;
}
-static inline int ovl_dir_read_merged(struct path *upperpath,
- struct path *lowerpath,
- struct list_head *list)
+static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
{
int err;
+ struct path lowerpath;
+ struct path upperpath;
struct ovl_readdir_data rdd = {
.ctx.actor = ovl_fill_merge,
.list = list,
.is_merge = false,
};
- if (upperpath->dentry) {
- err = ovl_dir_read(upperpath, &rdd);
+ ovl_path_lower(dentry, &lowerpath);
+ ovl_path_upper(dentry, &upperpath);
+
+ if (upperpath.dentry) {
+ err = ovl_dir_read(&upperpath, &rdd);
if (err)
goto out;
- if (lowerpath->dentry) {
- err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd);
+ if (lowerpath.dentry) {
+ err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
if (err)
goto out;
}
}
- if (lowerpath->dentry) {
+ if (lowerpath.dentry) {
/*
* Insert lowerpath entries before upperpath ones, this allows
* offsets to be reasonably constant
*/
list_add(&rdd.middle, rdd.list);
rdd.is_merge = true;
- err = ovl_dir_read(lowerpath, &rdd);
+ err = ovl_dir_read(&lowerpath, &rdd);
list_del(&rdd.middle);
}
out:
static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
{
int res;
- struct path lowerpath;
- struct path upperpath;
struct ovl_dir_cache *cache;
cache = ovl_dir_cache(dentry);
cache->refcount = 1;
INIT_LIST_HEAD(&cache->entries);
- ovl_path_lower(dentry, &lowerpath);
- ovl_path_upper(dentry, &upperpath);
-
- res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries);
+ res = ovl_dir_read_merged(dentry, &cache->entries);
if (res) {
ovl_cache_free(&cache->entries);
kfree(cache);
/*
* Need to check if we started out being a lower dir, but got copied up
*/
- if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) {
+ if (!od->is_upper && ovl_path_type(dentry) != OVL_PATH_LOWER) {
struct inode *inode = file_inode(file);
- realfile =lockless_dereference(od->upperfile);
+ realfile = lockless_dereference(od->upperfile);
if (!realfile) {
struct path upperpath;
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
{
int err;
- struct path lowerpath;
- struct path upperpath;
struct ovl_cache_entry *p;
- ovl_path_upper(dentry, &upperpath);
- ovl_path_lower(dentry, &lowerpath);
-
- err = ovl_dir_read_merged(&upperpath, &lowerpath, list);
+ err = ovl_dir_read_merged(dentry, list);
if (err)
return err;
MODULE_DESCRIPTION("Overlay filesystem");
MODULE_LICENSE("GPL");
-#define OVERLAYFS_SUPER_MAGIC 0x794c764f
+#define OVERLAYFS_SUPER_MAGIC 0x794c7630
struct ovl_config {
char *lowerdir;
static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe)
{
- struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry);
- /*
- * Make sure to order reads to upperdentry wrt ovl_dentry_update()
- */
- smp_read_barrier_depends();
- return upperdentry;
+ return lockless_dereference(oe->__upperdentry);
}
void ovl_path_upper(struct dentry *dentry, struct path *path)
{OPT_ERR, NULL}
};
+static char *ovl_next_opt(char **s)
+{
+ char *sbegin = *s;
+ char *p;
+
+ if (sbegin == NULL)
+ return NULL;
+
+ for (p = sbegin; *p; p++) {
+ if (*p == '\\') {
+ p++;
+ if (!*p)
+ break;
+ } else if (*p == ',') {
+ *p = '\0';
+ *s = p + 1;
+ return sbegin;
+ }
+ }
+ *s = NULL;
+ return sbegin;
+}
+
static int ovl_parse_opt(char *opt, struct ovl_config *config)
{
char *p;
- while ((p = strsep(&opt, ",")) != NULL) {
+ while ((p = ovl_next_opt(&opt)) != NULL) {
int token;
substring_t args[MAX_OPT_ARGS];
goto out_unlock;
}
+static void ovl_unescape(char *s)
+{
+ char *d = s;
+
+ for (;; s++, d++) {
+ if (*s == '\\')
+ s++;
+ *d = *s;
+ if (!*s)
+ break;
+ }
+}
+
static int ovl_mount_dir(const char *name, struct path *path)
{
int err;
+ char *tmp = kstrdup(name, GFP_KERNEL);
+
+ if (!tmp)
+ return -ENOMEM;
- err = kern_path(name, LOOKUP_FOLLOW, path);
+ ovl_unescape(tmp);
+ err = kern_path(tmp, LOOKUP_FOLLOW, path);
if (err) {
- pr_err("overlayfs: failed to resolve '%s': %i\n", name, err);
+ pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err);
err = -EINVAL;
}
+ kfree(tmp);
return err;
}
static struct file_system_type ovl_fs_type = {
.owner = THIS_MODULE,
- .name = "overlayfs",
+ .name = "overlay",
.mount = ovl_mount,
.kill_sb = kill_anon_super,
};
-MODULE_ALIAS_FS("overlayfs");
+MODULE_ALIAS_FS("overlay");
static int __init ovl_init(void)
{
struct acpi_pld_info {
u8 revision;
u8 ignore_color;
- u32 color;
+ u8 red;
+ u8 green;
+ u8 blue;
u16 width;
u16 height;
u8 user_visible;
#define ACPI_PLD_GET_IGNORE_COLOR(dword) ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK)
#define ACPI_PLD_SET_IGNORE_COLOR(dword,value) ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value) /* Offset 7, Len 1 */
-#define ACPI_PLD_GET_COLOR(dword) ACPI_GET_BITS (dword, 8, ACPI_24BIT_MASK)
-#define ACPI_PLD_SET_COLOR(dword,value) ACPI_SET_BITS (dword, 8, ACPI_24BIT_MASK, value) /* Offset 8, Len 24 */
+#define ACPI_PLD_GET_RED(dword) ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_RED(dword,value) ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value) /* Offset 8, Len 8 */
+
+#define ACPI_PLD_GET_GREEN(dword) ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_GREEN(dword,value) ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value) /* Offset 16, Len 8 */
+
+#define ACPI_PLD_GET_BLUE(dword) ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_BLUE(dword,value) ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value) /* Offset 24, Len 8 */
/* Second 32-bit dword, bits 33:63 */
#define __ACPI_BUS_H__
#include <linux/device.h>
+#include <linux/property.h>
/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
bool put_online:1;
};
+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+ const union acpi_object *pointer;
+ const union acpi_object *properties;
+ const union acpi_object *of_compatible;
+};
+
+struct acpi_gpio_mapping;
+
/* Device */
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
+ const struct acpi_gpio_mapping *driver_gpios;
void *driver_data;
struct device dev;
unsigned int physical_node_count;
+ unsigned int dep_unmet;
struct list_head physical_node_list;
struct mutex physical_node_lock;
void (*remove)(struct acpi_device *);
};
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return &adev->fwnode;
+}
+
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20140926
+#define ACPI_CA_VERSION 0x20141107
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
#define ACPI_GPE_ENABLE 0
#define ACPI_GPE_DISABLE 1
#define ACPI_GPE_CONDITIONAL_ENABLE 2
+#define ACPI_GPE_SAVE_MASK 4
+
+#define ACPI_GPE_ENABLE_SAVE (ACPI_GPE_ENABLE | ACPI_GPE_SAVE_MASK)
+#define ACPI_GPE_DISABLE_SAVE (ACPI_GPE_DISABLE | ACPI_GPE_SAVE_MASK)
/*
* GPE info flags - Per GPE
};
struct acpi_processor_power {
- struct acpi_processor_cx *state;
- unsigned long bm_check_timestamp;
- u32 default_state;
int count;
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
int timer_broadcast_on_state;
#endif /* CONFIG_CPU_FREQ */
/* in processor_core.c */
-void acpi_processor_set_pdc(acpi_handle handle);
int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
int acpi_map_cpuid(int apic_id, u32 acpi_id);
int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
+/* in processor_pdc.c */
+void acpi_processor_set_pdc(acpi_handle handle);
+
/* in processor_throttling.c */
int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
int acpi_processor_get_throttling_info(struct acpi_processor *pr);
#define ESC1_CLK_SRC 43
#define HDMI_CLK_SRC 44
#define VSYNC_CLK_SRC 45
-#define RBCPR_CLK_SRC 46
+#define MMSS_RBCPR_CLK_SRC 46
#define RBBMTIMER_CLK_SRC 47
#define MAPLE_CLK_SRC 48
#define VDP_CLK_SRC 49
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
+#include <linux/property.h>
#ifndef _LINUX
#define _LINUX
int acpi_table_init (void);
int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
+int __init acpi_parse_entries(char *id, unsigned long table_size,
+ acpi_tbl_entry_handler handler,
+ struct acpi_table_header *table_header,
+ int entry_id, unsigned int max_entries);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);
-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
+void acpi_walk_dep_device_list(acpi_handle handle);
struct platform_device *acpi_create_platform_device(struct acpi_device *);
#define ACPI_PTR(_ptr) (_ptr)
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)
+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return NULL;
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
#endif
#endif
+struct acpi_gpio_params {
+ unsigned int crs_entry_index;
+ unsigned int line_index;
+ bool active_low;
+};
+
+struct acpi_gpio_mapping {
+ const char *name;
+ const struct acpi_gpio_params *data;
+ unsigned int size;
+};
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios);
+
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
+ if (adev)
+ adev->driver_gpios = NULL;
+}
+#else
+static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios)
+{
+ return -ENXIO;
+}
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
+#endif
+
+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS 8
+struct acpi_reference_args {
+ struct acpi_device *adev;
+ size_t nargs;
+ u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, size_t index,
+ struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr);
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, const char *cells_name,
+ size_t index, struct acpi_reference_args *args)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+ const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
+
+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
+
+#endif
+
#endif /*_LINUX_ACPI_H*/
* position @h. For example
* GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
*/
-#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l))
-#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l))
+#define GENMASK(h, l) \
+ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+#define GENMASK_ULL(h, l) \
+ (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
extern unsigned int __sw_hweight8(unsigned int w);
extern unsigned int __sw_hweight16(unsigned int w);
return 1;
}
+static inline bool can_is_canfd_skb(const struct sk_buff *skb)
+{
+ /* the CAN specific type of skb is identified by its data length */
+ return skb->len == CANFD_MTU;
+}
+
/* get data length from can_dlc with sanitized can_dlc */
u8 can_dlc2len(u8 can_dlc);
#define CLK_DIVIDER_READ_ONLY BIT(5)
extern const struct clk_ops clk_divider_ops;
-extern const struct clk_ops clk_divider_ro_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);
+/* Child properties interface */
+struct fwnode_handle;
+
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname);
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */
static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
#define _GPIO_KEYS_H
struct device;
+struct gpio_desc;
/**
* struct gpio_keys_button - configuration parameters
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
+ * @gpiod: GPIO descriptor
*/
struct gpio_keys_button {
unsigned int code;
bool can_disable;
int value;
unsigned int irq;
+ struct gpio_desc *gpiod;
};
/**
#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
-#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF)
+#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F)
#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
static __inline__ __be32 inet_make_mask(int logmask)
{
if (logmask)
- return htonl(~((1<<(32-logmask))-1));
+ return htonl(~((1U<<(32-logmask))-1));
return 0;
}
return kstat_cpu(cpu).irqs_sum;
}
-/*
- * Lock/unlock the current runqueue - to extract task statistics:
- */
-extern unsigned long long task_delta_exec(struct task_struct *);
-
extern void account_user_time(struct task_struct *, cputime_t, cputime_t);
extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t);
extern void account_steal_time(cputime_t);
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
-bool kvm_is_mmio_pfn(pfn_t pfn);
+bool kvm_is_reserved_pfn(pfn_t pfn);
struct kvm_irq_ack_notifier {
struct hlist_node link;
unsigned retain_state_suspended : 1;
unsigned default_state : 2;
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
+ struct gpio_desc *gpiod;
};
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Please, blink */
- int (*gpio_blink_set)(unsigned gpio, int state,
+ int (*gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
};
enum {
AXP202_ID = 0,
AXP209_ID,
+ AXP288_ID,
+ NR_AXP20X_VARIANTS,
};
#define AXP20X_DATACACHE(m) (0x04 + (m))
#define AXP20X_IRQ3_EN 0x42
#define AXP20X_IRQ4_EN 0x43
#define AXP20X_IRQ5_EN 0x44
+#define AXP20X_IRQ6_EN 0x45
#define AXP20X_IRQ1_STATE 0x48
#define AXP20X_IRQ2_STATE 0x49
#define AXP20X_IRQ3_STATE 0x4a
#define AXP20X_IRQ4_STATE 0x4b
#define AXP20X_IRQ5_STATE 0x4c
+#define AXP20X_IRQ6_STATE 0x4d
/* ADC */
#define AXP20X_ACIN_V_ADC_H 0x56
#define AXP20X_CC_CTRL 0xb8
#define AXP20X_FG_RES 0xb9
+/* AXP288 specific registers */
+#define AXP288_PMIC_ADC_H 0x56
+#define AXP288_PMIC_ADC_L 0x57
+#define AXP288_ADC_TS_PIN_CTRL 0x84
+
+#define AXP288_PMIC_ADC_EN 0x84
+#define AXP288_FG_TUNE5 0xed
+
+
/* Regulators IDs */
enum {
AXP20X_LDO1 = 0,
AXP20X_IRQ_GPIO0_INPUT,
};
+enum axp288_irqs {
+ AXP288_IRQ_VBUS_FALL = 2,
+ AXP288_IRQ_VBUS_RISE,
+ AXP288_IRQ_OV,
+ AXP288_IRQ_FALLING_ALT,
+ AXP288_IRQ_RISING_ALT,
+ AXP288_IRQ_OV_ALT,
+ AXP288_IRQ_DONE = 10,
+ AXP288_IRQ_CHARGING,
+ AXP288_IRQ_SAFE_QUIT,
+ AXP288_IRQ_SAFE_ENTER,
+ AXP288_IRQ_ABSENT,
+ AXP288_IRQ_APPEND,
+ AXP288_IRQ_QWBTU,
+ AXP288_IRQ_WBTU,
+ AXP288_IRQ_QWBTO,
+ AXP288_IRQ_WBTO,
+ AXP288_IRQ_QCBTU,
+ AXP288_IRQ_CBTU,
+ AXP288_IRQ_QCBTO,
+ AXP288_IRQ_CBTO,
+ AXP288_IRQ_WL2,
+ AXP288_IRQ_WL1,
+ AXP288_IRQ_GPADC,
+ AXP288_IRQ_OT = 31,
+ AXP288_IRQ_GPIO0,
+ AXP288_IRQ_GPIO1,
+ AXP288_IRQ_POKO,
+ AXP288_IRQ_POKL,
+ AXP288_IRQ_POKS,
+ AXP288_IRQ_POKN,
+ AXP288_IRQ_POKP,
+ AXP288_IRQ_TIMER,
+ AXP288_IRQ_MV_CHNG,
+ AXP288_IRQ_BC_USB_CHNG,
+};
+
+#define AXP288_TS_ADC_H 0x58
+#define AXP288_TS_ADC_L 0x59
+#define AXP288_GP_ADC_H 0x5a
+#define AXP288_GP_ADC_L 0x5b
+
struct axp20x_dev {
struct device *dev;
struct i2c_client *i2c_client;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irqc;
long variant;
+ int nr_cells;
+ struct mfd_cell *cells;
+ const struct regmap_config *regmap_cfg;
+ const struct regmap_irq_chip *regmap_irq_chip;
};
#endif /* __LINUX_MFD_AXP20X_H */
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/property.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
const char *type;
phandle phandle;
const char *full_name;
+ struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
}
/* true when node is initialized */
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
static inline bool of_have_populated_dt(void)
{
return of_allnodes != NULL;
size_t sz);
extern int of_property_read_u64(const struct device_node *np,
const char *propname, u64 *out_value);
+extern int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values,
+ size_t sz);
extern int of_property_read_string(struct device_node *np,
const char *propname,
#else /* CONFIG_OF */
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
return -ENOSYS;
}
+static inline int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values, size_t sz)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
unsigned int is_added:1;
unsigned int is_busmaster:1; /* device is busmaster */
unsigned int no_msi:1; /* device may not use msi */
+ unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */
unsigned int block_cfg_access:1; /* config space access is blocked */
unsigned int broken_parity_status:1; /* Device generates false positive parity */
unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */
/* paired with smp_store_release() in percpu_ref_reinit() */
smp_read_barrier_depends();
- if (unlikely(percpu_ptr & __PERCPU_REF_ATOMIC))
+ /*
+ * Theoretically, the following could test just ATOMIC; however,
+ * then we'd have to mask off DEAD separately as DEAD may be
+ * visible without ATOMIC if we race with percpu_ref_kill(). DEAD
+ * implies ATOMIC anyway. Test them together.
+ */
+ if (unlikely(percpu_ptr & __PERCPU_REF_ATOMIC_DEAD))
return false;
*percpu_countp = (unsigned long __percpu *)percpu_ptr;
};
struct wakeup_source;
-
-struct pm_domain_data {
- struct list_head list_node;
- struct device *dev;
-};
+struct pm_domain_data;
struct pm_subsys_data {
spinlock_t lock;
char *con_ids[];
};
+struct clk;
+
#ifdef CONFIG_PM_CLK
static inline bool pm_clk_no_clocks(struct device *dev)
{
extern int pm_clk_create(struct device *dev);
extern void pm_clk_destroy(struct device *dev);
extern int pm_clk_add(struct device *dev, const char *con_id);
+extern int pm_clk_add_clk(struct device *dev, struct clk *clk);
extern void pm_clk_remove(struct device *dev, const char *con_id);
extern int pm_clk_suspend(struct device *dev);
extern int pm_clk_resume(struct device *dev);
{
return -EINVAL;
}
+
+static inline int pm_clk_add_clk(struct device *dev, struct clk *clk)
+{
+ return -EINVAL;
+}
static inline void pm_clk_remove(struct device *dev, const char *con_id)
{
}
#include <linux/notifier.h>
#include <linux/cpuidle.h>
+/* Defines used for the flags field in the struct generic_pm_domain */
+#define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */
+
enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */
GPD_STATE_WAIT_MASTER, /* PM domain's master is being waited for */
struct device *dev);
void (*detach_dev)(struct generic_pm_domain *domain,
struct device *dev);
+ unsigned int flags; /* Bit field of configs for genpd */
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
bool cached_stop_ok;
};
+struct pm_domain_data {
+ struct list_head list_node;
+ struct device *dev;
+};
+
struct generic_pm_domain_data {
struct pm_domain_data base;
struct gpd_timing_data td;
struct device;
enum dev_pm_opp_event {
- OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
+ OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
};
#if defined(CONFIG_PM_OPP)
int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt);
+void dev_pm_opp_remove(struct device *dev, unsigned long freq);
int dev_pm_opp_enable(struct device *dev, unsigned long freq);
return -EINVAL;
}
+static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq)
+{
+}
+
static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
return 0;
#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
int of_init_opp_table(struct device *dev);
+void of_free_opp_table(struct device *dev);
#else
static inline int of_init_opp_table(struct device *dev)
{
return -EINVAL;
}
+
+static inline void of_free_opp_table(struct device *dev)
+{
+}
#endif
#endif /* __LINUX_OPP_H__ */
--- /dev/null
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ * Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+ DEV_PROP_U8,
+ DEV_PROP_U16,
+ DEV_PROP_U32,
+ DEV_PROP_U64,
+ DEV_PROP_STRING,
+ DEV_PROP_MAX,
+};
+
+bool device_property_present(struct device *dev, const char *propname);
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval);
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval);
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval);
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval);
+int device_property_read_string_array(struct device *dev, const char *propname,
+ const char **val, size_t nval);
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val);
+
+enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+ FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+ enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
+ size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val,
+ size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val,
+ size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val,
+ size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, const char **val,
+ size_t nval);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
+static inline bool device_property_read_bool(struct device *dev,
+ const char *propname)
+{
+ return device_property_present(dev, propname);
+}
+
+static inline int device_property_read_u8(struct device *dev,
+ const char *propname, u8 *val)
+{
+ return device_property_read_u8_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u16(struct device *dev,
+ const char *propname, u16 *val)
+{
+ return device_property_read_u16_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u32(struct device *dev,
+ const char *propname, u32 *val)
+{
+ return device_property_read_u32_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u64(struct device *dev,
+ const char *propname, u64 *val)
+{
+ return device_property_read_u64_array(dev, propname, val, 1);
+}
+
+static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ return fwnode_property_present(fwnode, propname);
+}
+
+static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val)
+{
+ return fwnode_property_read_u8_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val)
+{
+ return fwnode_property_read_u16_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val)
+{
+ return fwnode_property_read_u32_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val)
+{
+ return fwnode_property_read_u64_array(fwnode, propname, val, 1);
+}
+
+#endif /* _LINUX_PROPERTY_H_ */
int inet_ctl_sock_create(struct sock **sk, unsigned short family,
unsigned short type, unsigned char protocol,
struct net *net);
+int inet_recv_error(struct sock *sk, struct msghdr *msg, int len,
+ int *addr_len);
static inline void inet_ctl_sock_destroy(struct sock *sk)
{
/**
* struct nft_trans - nf_tables object update in transaction
*
- * @rcu_head: rcu head to defer release of transaction data
* @list: used internally
* @msg_type: message type
* @ctx: transaction context
* @data: internal information related to the transaction
*/
struct nft_trans {
- struct rcu_head rcu_head;
struct list_head list;
int msg_type;
struct nft_ctx ctx;
#define VNI_HASH_BITS 10
#define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
+/* VXLAN protocol header */
+struct vxlanhdr {
+ __be32 vx_flags;
+ __be32 vx_vni;
+};
+
struct vxlan_sock;
typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
__be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
__be16 src_port, __be16 dst_port, __be32 vni, bool xnet);
+static inline bool vxlan_gso_check(struct sk_buff *skb)
+{
+ if ((skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) &&
+ (skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
+ skb->inner_protocol != htons(ETH_P_TEB) ||
+ (skb_inner_mac_header(skb) - skb_transport_header(skb) !=
+ sizeof(struct udphdr) + sizeof(struct vxlanhdr))))
+ return false;
+
+ return true;
+}
+
/* IP header + UDP + VXLAN + Ethernet header */
#define VXLAN_HEADROOM (20 + 8 + 8 + 14)
/* IPv6 header + UDP + VXLAN + Ethernet header */
#define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8)
#define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE)
#define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U16_BE _SNDRV_PCM_FMTBIT(DSD_U16_BE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_BE _SNDRV_PCM_FMTBIT(DSD_U32_BE)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
/* state and update */
enum snd_soc_dpcm_update runtime_update;
enum snd_soc_dpcm_state state;
+
+ int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
};
/* can this BE stop and free */
header-y += virtio_pci.h
header-y += virtio_ring.h
header-y += virtio_rng.h
-header=y += vm_sockets.h
+header-y += vm_sockets.h
header-y += vt.h
header-y += wait.h
header-y += wanrouter.h
#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
-#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_LE
+#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */
+#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
return retval;
}
- id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
- if (id < 0) {
- ipc_rcu_putref(sma, sem_rcu_free);
- return id;
- }
- ns->used_sems += nsems;
-
sma->sem_base = (struct sem *) &sma[1];
for (i = 0; i < nsems; i++) {
INIT_LIST_HEAD(&sma->list_id);
sma->sem_nsems = nsems;
sma->sem_ctime = get_seconds();
+
+ id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+ if (id < 0) {
+ ipc_rcu_putref(sma, sem_rcu_free);
+ return id;
+ }
+ ns->used_sems += nsems;
+
sem_unlock(sma, -1);
rcu_read_unlock();
if (!task) {
/*
- * Per cpu events are removed via an smp call and
- * the removal is always successful.
+ * Per cpu events are removed via an smp call. The removal can
+ * fail if the CPU is currently offline, but in that case we
+ * already called __perf_remove_from_context from
+ * perf_event_exit_cpu.
*/
cpu_function_call(event->cpu, __perf_remove_from_context, &re);
return;
static void __perf_event_exit_context(void *__info)
{
- struct remove_event re = { .detach_group = false };
+ struct remove_event re = { .detach_group = true };
struct perf_event_context *ctx = __info;
perf_pmu_rotate_stop(ctx->pmu);
if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) {
utask->state = UTASK_SSTEP_TRAPPED;
set_tsk_thread_flag(t, TIF_UPROBE);
- set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
}
}
config CPU_PM
bool
- depends on SUSPEND || CPU_IDLE
#include <linux/syscore_ops.h>
#include <linux/ctype.h>
#include <linux/genhd.h>
+#include <linux/ktime.h>
#include <trace/events/power.h>
#include "power.h"
* @nr_pages: Number of memory pages processed between @start and @stop.
* @msg: Additional diagnostic message to print.
*/
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
- unsigned nr_pages, char *msg)
+void swsusp_show_speed(ktime_t start, ktime_t stop,
+ unsigned nr_pages, char *msg)
{
+ ktime_t diff;
u64 elapsed_centisecs64;
unsigned int centisecs;
unsigned int k;
unsigned int kps;
- elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
- /*
- * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time,
- * it is obvious enough for what went wrong.
- */
- do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
+ diff = ktime_sub(stop, start);
+ elapsed_centisecs64 = ktime_divns(diff, 10*NSEC_PER_MSEC);
centisecs = elapsed_centisecs64;
if (centisecs == 0)
centisecs = 1; /* avoid div-by-zero */
struct timeval;
/* kernel/power/swsusp.c */
-extern void swsusp_show_speed(struct timeval *, struct timeval *,
- unsigned int, char *);
+extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *);
#ifdef CONFIG_SUSPEND
/* kernel/power/suspend.c */
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/compiler.h>
+#include <linux/ktime.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
struct zone *zone;
unsigned long saveable, size, max_size, count, highmem, pages = 0;
unsigned long alloc, save_highmem, pages_highmem, avail_normal;
- struct timeval start, stop;
+ ktime_t start, stop;
int error;
printk(KERN_INFO "PM: Preallocating image memory... ");
- do_gettimeofday(&start);
+ start = ktime_get();
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
if (error)
free_unnecessary_pages();
out:
- do_gettimeofday(&stop);
+ stop = ktime_get();
printk(KERN_CONT "done (allocated %lu pages)\n", pages);
- swsusp_show_speed(&start, &stop, pages, "Allocated");
+ swsusp_show_speed(start, stop, pages, "Allocated");
return 0;
#include <linux/atomic.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
+#include <linux/ktime.h>
#include "power.h"
int nr_pages;
int err2;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
nr_to_write);
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
while (1) {
ret = snapshot_read_next(snapshot);
if (ret <= 0)
nr_pages++;
}
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
printk(KERN_INFO "PM: Image saving done.\n");
- swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+ swsusp_show_speed(start, stop, nr_to_write, "Wrote");
return ret;
}
int nr_pages;
int err2;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
size_t off;
unsigned thr, run_threads, nr_threads;
unsigned char *page = NULL;
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
for (;;) {
for (thr = 0; thr < nr_threads; thr++) {
for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
out_finish:
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
printk(KERN_INFO "PM: Image saving done.\n");
- swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+ swsusp_show_speed(start, stop, nr_to_write, "Wrote");
out_clean:
if (crc) {
if (crc->thr)
{
unsigned int m;
int ret = 0;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
struct bio *bio;
int err2;
unsigned nr_pages;
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
for ( ; ; ) {
ret = snapshot_write_next(snapshot);
if (ret <= 0)
nr_pages++;
}
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret) {
if (!snapshot_image_loaded(snapshot))
ret = -ENODATA;
}
- swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+ swsusp_show_speed(start, stop, nr_to_read, "Read");
return ret;
}
int ret = 0;
int eof = 0;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
unsigned nr_pages;
size_t off;
unsigned i, thr, run_threads, nr_threads;
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
ret = snapshot_write_next(snapshot);
if (ret <= 0)
wait_event(crc->done, atomic_read(&crc->stop));
atomic_set(&crc->stop, 0);
}
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret) {
printk(KERN_INFO "PM: Image loading done.\n");
snapshot_write_finalize(snapshot);
}
}
}
- swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+ swsusp_show_speed(start, stop, nr_to_read, "Read");
out_clean:
for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]);
kthread_stop(data[thr].thr);
vfree(data);
}
- if (page) vfree(page);
+ vfree(page);
return ret;
}
EXPORT_PER_CPU_SYMBOL(kstat);
EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
-/*
- * Return any ns on the sched_clock that have not yet been accounted in
- * @p in case that task is currently running.
- *
- * Called with task_rq_lock() held on @rq.
- */
-static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
-{
- u64 ns = 0;
-
- /*
- * Must be ->curr _and_ ->on_rq. If dequeued, we would
- * project cycles that may never be accounted to this
- * thread, breaking clock_gettime().
- */
- if (task_current(rq, p) && task_on_rq_queued(p)) {
- update_rq_clock(rq);
- ns = rq_clock_task(rq) - p->se.exec_start;
- if ((s64)ns < 0)
- ns = 0;
- }
-
- return ns;
-}
-
-unsigned long long task_delta_exec(struct task_struct *p)
-{
- unsigned long flags;
- struct rq *rq;
- u64 ns = 0;
-
- rq = task_rq_lock(p, &flags);
- ns = do_task_delta_exec(p, rq);
- task_rq_unlock(rq, p, &flags);
-
- return ns;
-}
-
/*
* Return accounted runtime for the task.
* In case the task is currently running, return the runtime plus current's
{
unsigned long flags;
struct rq *rq;
- u64 ns = 0;
+ u64 ns;
#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
/*
#endif
rq = task_rq_lock(p, &flags);
- ns = p->se.sum_exec_runtime + do_task_delta_exec(p, rq);
+ /*
+ * Must be ->curr _and_ ->on_rq. If dequeued, we would
+ * project cycles that may never be accounted to this
+ * thread, breaking clock_gettime().
+ */
+ if (task_current(rq, p) && task_on_rq_queued(p)) {
+ update_rq_clock(rq);
+ p->sched_class->update_curr(rq);
+ }
+ ns = p->se.sum_exec_runtime;
task_rq_unlock(rq, p, &flags);
return ns;
* or we have been woken up remotely but the IPI has not yet arrived,
* we haven't yet exited the RCU idle mode. Do it here manually until
* we find a better solution.
+ *
+ * NB: There are buggy callers of this function. Ideally we
+ * should warn if prev_state != IN_USER, but that will trigger
+ * too frequently to make sense yet.
*/
- user_exit();
+ enum ctx_state prev_state = exception_enter();
schedule();
- user_enter();
+ exception_exit(prev_state);
}
#endif
if (!sched_debug())
break;
}
+
+ if (!level)
+ return;
+
/*
* 'level' contains the number of unique distances, excluding the
* identity distance node_distance(i,i).
if (unlikely(running))
put_prev_task(rq, tsk);
- tg = container_of(task_css_check(tsk, cpu_cgrp_id,
- lockdep_is_held(&tsk->sighand->siglock)),
+ /*
+ * All callers are synchronized by task_rq_lock(); we do not use RCU
+ * which is pointless here. Thus, we pass "true" to task_css_check()
+ * to prevent lockdep warnings.
+ */
+ tg = container_of(task_css_check(tsk, cpu_cgrp_id, true),
struct task_group, css);
tg = autogroup_task_group(tsk, tg);
tsk->sched_task_group = tg;
.prio_changed = prio_changed_dl,
.switched_from = switched_from_dl,
.switched_to = switched_to_dl,
+
+ .update_curr = update_curr_dl,
};
account_cfs_rq_runtime(cfs_rq, delta_exec);
}
+static void update_curr_fair(struct rq *rq)
+{
+ update_curr(cfs_rq_of(&rq->curr->se));
+}
+
static inline void
update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
cur = NULL;
raw_spin_unlock_irq(&dst_rq->lock);
+ /*
+ * Because we have preemption enabled we can get migrated around and
+ * end try selecting ourselves (current == env->p) as a swap candidate.
+ */
+ if (cur == env->p)
+ goto unlock;
+
/*
* "imp" is the fault differential for the source task between the
* source and destination node. Calculate the total differential for
.get_rr_interval = get_rr_interval_fair,
+ .update_curr = update_curr_fair,
+
#ifdef CONFIG_FAIR_GROUP_SCHED
.task_move_group = task_move_group_fair,
#endif
return 0;
}
+static void update_curr_idle(struct rq *rq)
+{
+}
+
/*
* Simple, special scheduling class for the per-CPU idle tasks:
*/
.prio_changed = prio_changed_idle,
.switched_to = switched_to_idle,
+ .update_curr = update_curr_idle,
};
.prio_changed = prio_changed_rt,
.switched_to = switched_to_rt,
+
+ .update_curr = update_curr_rt,
};
#ifdef CONFIG_SCHED_DEBUG
unsigned int (*get_rr_interval) (struct rq *rq,
struct task_struct *task);
+ void (*update_curr) (struct rq *rq);
+
#ifdef CONFIG_FAIR_GROUP_SCHED
void (*task_move_group) (struct task_struct *p, int on_rq);
#endif
return 0;
}
+static void update_curr_stop(struct rq *rq)
+{
+}
+
/*
* Simple, special scheduling class for the per-CPU stop tasks:
*/
.prio_changed = prio_changed_stop,
.switched_to = switched_to_stop,
+ .update_curr = update_curr_stop,
};
*sample = cputime_to_expires(cputime.utime);
break;
case CPUCLOCK_SCHED:
- *sample = cputime.sum_exec_runtime + task_delta_exec(p);
+ *sample = cputime.sum_exec_runtime;
break;
}
return 0;
lib-y := ctype.o string.o vsprintf.o cmdline.o \
rbtree.o radix-tree.o dump_stack.o timerqueue.o\
idr.o int_sqrt.o extable.o \
- sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
+ sha1.o md5.o irq_regs.o argv_split.o \
proportions.o flex_proportions.o ratelimit.o show_mem.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
earlycpio.o
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
- percpu-refcount.o percpu_ida.o hash.o rhashtable.o
+ percpu-refcount.o percpu_ida.o hash.o rhashtable.o reciprocal_div.o
obj-y += string_helpers.o
obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
obj-y += kstrtox.o
return pool;
}
+EXPORT_SYMBOL(devm_gen_pool_create);
/**
* dev_get_gen_pool - Obtain the gen_pool (if any) for a device
continue;
total += zone->present_pages;
- reserved = zone->present_pages - zone->managed_pages;
+ reserved += zone->present_pages - zone->managed_pages;
if (is_highmem_idx(zoneid))
highmem += zone->present_pages;
the (older) page from frontswap
*/
inc_frontswap_failed_stores();
- if (dup)
+ if (dup) {
__frontswap_clear(sis, offset);
+ frontswap_ops->invalidate_page(type, offset);
+ }
}
if (frontswap_writethrough_enabled)
/* report failure so swap also writes to swap device */
if (!pte_file(pte)) {
swp_entry_t entry = pte_to_swp_entry(pte);
- if (swap_duplicate(entry) < 0)
- return entry.val;
-
- /* make sure dst_mm is on swapoff's mmlist. */
- if (unlikely(list_empty(&dst_mm->mmlist))) {
- spin_lock(&mmlist_lock);
- if (list_empty(&dst_mm->mmlist))
- list_add(&dst_mm->mmlist,
- &src_mm->mmlist);
- spin_unlock(&mmlist_lock);
- }
- if (likely(!non_swap_entry(entry)))
+ if (likely(!non_swap_entry(entry))) {
+ if (swap_duplicate(entry) < 0)
+ return entry.val;
+
+ /* make sure dst_mm is on swapoff's mmlist. */
+ if (unlikely(list_empty(&dst_mm->mmlist))) {
+ spin_lock(&mmlist_lock);
+ if (list_empty(&dst_mm->mmlist))
+ list_add(&dst_mm->mmlist,
+ &src_mm->mmlist);
+ spin_unlock(&mmlist_lock);
+ }
rss[MM_SWAPENTS]++;
- else if (is_migration_entry(entry)) {
+ } else if (is_migration_entry(entry)) {
page = migration_entry_to_page(entry);
if (PageAnon(page))
* shrinking vma had, to cover any anon pages imported.
*/
if (exporter && exporter->anon_vma && !importer->anon_vma) {
- if (anon_vma_clone(importer, exporter))
- return -ENOMEM;
+ int error;
+
+ error = anon_vma_clone(importer, exporter);
+ if (error)
+ return error;
importer->anon_vma = exporter->anon_vma;
}
}
if (err)
goto out_free_vma;
- if (anon_vma_clone(new, vma))
+ err = anon_vma_clone(new, vma);
+ if (err)
goto out_free_mpol;
if (new->vm_file)
{
struct anon_vma_chain *avc;
struct anon_vma *anon_vma;
+ int error;
/* Don't bother if the parent process has no anon_vma here. */
if (!pvma->anon_vma)
* First, attach the new VMA to the parent VMA's anon_vmas,
* so rmap can find non-COWed pages in child processes.
*/
- if (anon_vma_clone(vma, pvma))
- return -ENOMEM;
+ error = anon_vma_clone(vma, pvma);
+ if (error)
+ return error;
/* Then add our own anon_vma. */
anon_vma = anon_vma_alloc();
void *obj;
int x;
- VM_BUG_ON(nodeid > num_online_nodes());
+ VM_BUG_ON(nodeid < 0 || nodeid >= MAX_NUMNODES);
n = get_node(cachep, nodeid);
BUG_ON(!n);
unsigned long scanned;
unsigned long reclaimed;
+ spin_lock(&vmpr->sr_lock);
/*
* Several contexts might be calling vmpressure(), so it is
* possible that the work was rescheduled again before the old
* here. No need for any locks here since we don't care if
* vmpr->reclaimed is in sync.
*/
- if (!vmpr->scanned)
+ scanned = vmpr->scanned;
+ if (!scanned) {
+ spin_unlock(&vmpr->sr_lock);
return;
+ }
- spin_lock(&vmpr->sr_lock);
- scanned = vmpr->scanned;
reclaimed = vmpr->reclaimed;
vmpr->scanned = 0;
vmpr->reclaimed = 0;
return;
if (port) {
- __skb_push(skb, sizeof(struct ethhdr));
skb->dev = port->dev;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
- dev_queue_xmit);
+ br_dev_queue_push_xmit);
} else {
br_multicast_select_own_querier(br, ip, skb);
netif_rx(skb);
[IFLA_BRPORT_MODE] = { .type = NLA_U8 },
[IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
+ [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
};
goto errout;
}
if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
+ put_net(net);
err = -EPERM;
goto errout;
}
int idx = 0;
u32 portid = NETLINK_CB(cb->skb).portid;
u32 seq = cb->nlh->nlmsg_seq;
- struct nlattr *extfilt;
u32 filter_mask = 0;
- extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg),
- IFLA_EXT_MASK);
- if (extfilt)
- filter_mask = nla_get_u32(extfilt);
+ if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
+ struct nlattr *extfilt;
+
+ extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg),
+ IFLA_EXT_MASK);
+ if (extfilt) {
+ if (nla_len(extfilt) < sizeof(filter_mask))
+ return -EINVAL;
+
+ filter_mask = nla_get_u32(extfilt);
+ }
+ }
rcu_read_lock();
for_each_netdev_rcu(net, dev) {
if (br_spec) {
nla_for_each_nested(attr, br_spec, rem) {
if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
+ if (nla_len(attr) < sizeof(flags))
+ return -EINVAL;
+
have_flags = true;
flags = nla_get_u16(attr);
break;
if (br_spec) {
nla_for_each_nested(attr, br_spec, rem) {
if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
+ if (nla_len(attr) < sizeof(flags))
+ return -EINVAL;
+
have_flags = true;
flags = nla_get_u16(attr);
break;
case SKB_FCLONE_CLONE:
fclones = container_of(skb, struct sk_buff_fclones, skb2);
- /* Warning : We must perform the atomic_dec_and_test() before
- * setting skb->fclone back to SKB_FCLONE_FREE, otherwise
- * skb_clone() could set clone_ref to 2 before our decrement.
- * Anyway, if we are going to free the structure, no need to
- * rewrite skb->fclone.
+ /* The clone portion is available for
+ * fast-cloning again.
*/
- if (atomic_dec_and_test(&fclones->fclone_ref)) {
+ skb->fclone = SKB_FCLONE_FREE;
+
+ if (atomic_dec_and_test(&fclones->fclone_ref))
kmem_cache_free(skbuff_fclone_cache, fclones);
- } else {
- /* The clone portion is available for
- * fast-cloning again.
- */
- skb->fclone = SKB_FCLONE_FREE;
- }
break;
}
}
if (skb->fclone == SKB_FCLONE_ORIG &&
n->fclone == SKB_FCLONE_FREE) {
n->fclone = SKB_FCLONE_CLONE;
- /* As our fastclone was free, clone_ref must be 1 at this point.
- * We could use atomic_inc() here, but it is faster
- * to set the final value.
- */
- atomic_set(&fclones->fclone_ref, 2);
+ atomic_inc(&fclones->fclone_ref);
} else {
if (skb_pfmemalloc(skb))
gfp_mask |= __GFP_MEMALLOC;
if (!app)
return -EMSGSIZE;
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->ifindex == netdev->ifindex) {
err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
&itr->app);
if (err) {
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
return -EMSGSIZE;
}
}
else
dcbx = -EOPNOTSUPP;
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
nla_nest_end(skb, app);
/* get peer info if available */
}
/* local app */
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
if (!app)
goto dcb_unlock;
else
dcbx = -EOPNOTSUPP;
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
/* features flags */
if (ops->getfeatcfg) {
return 0;
dcb_unlock:
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
nla_put_failure:
return err;
}
struct dcb_app_type *itr;
u8 prio = 0;
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
prio = itr->app.priority;
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
return prio;
}
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
/* Search for existing match and replace */
if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) {
if (new->priority)
if (new->priority)
err = dcb_app_add(new, dev->ifindex);
out:
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
struct dcb_app_type *itr;
u8 prio = 0;
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
prio |= 1 << itr->app.priority;
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
return prio;
}
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
/* Search for existing match and abort if found */
if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
err = -EEXIST;
err = dcb_app_add(new, dev->ifindex);
out:
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
/* Search for existing match and remove it. */
if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
list_del(&itr->list);
err = 0;
}
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
struct dcb_app_type *app;
struct dcb_app_type *tmp;
- spin_lock(&dcb_lock);
+ spin_lock_bh(&dcb_lock);
list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
list_del(&app->list);
kfree(app);
}
- spin_unlock(&dcb_lock);
+ spin_unlock_bh(&dcb_lock);
}
static int __init dcbnl_init(void)
return pp;
}
+int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+{
+ if (sk->sk_family == AF_INET)
+ return ip_recv_error(sk, msg, len, addr_len);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6)
+ return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len);
+#endif
+ return -EINVAL;
+}
+
static int inet_gro_complete(struct sk_buff *skb, int nhoff)
{
__be16 newlen = htons(skb->len - nhoff);
else
res->tclassid = 0;
#endif
+
+ if (err == -ESRCH)
+ err = -ENETUNREACH;
+
return err;
}
EXPORT_SYMBOL_GPL(__fib_lookup);
return scount;
}
-#define igmp_skb_size(skb) (*(unsigned int *)((skb)->cb))
-
-static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
+static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
{
struct sk_buff *skb;
struct rtable *rt;
struct flowi4 fl4;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
+ unsigned int size = mtu;
while (1) {
skb = alloc_skb(size + hlen + tlen,
return NULL;
}
skb->priority = TC_PRIO_CONTROL;
- igmp_skb_size(skb) = size;
rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
0, 0,
skb_dst_set(skb, &rt->dst);
skb->dev = dev;
+ skb->reserved_tailroom = skb_end_offset(skb) -
+ min(mtu, skb_end_offset(skb));
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
return skb;
}
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? igmp_skb_size(skb) - (skb)->len : \
- skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
int type, int gdeleted, int sdeleted)
.validate = vti_tunnel_validate,
.newlink = vti_newlink,
.changelink = vti_changelink,
+ .dellink = ip_tunnel_dellink,
.get_size = vti_get_size,
.fill_info = vti_fill_info,
};
struct nf_nat_range range;
unsigned int verdict;
+ memset(&range, 0, sizeof(range));
range.flags = priv->flags;
verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
&ipv6_hdr(skb)->daddr))
continue;
#endif
+ } else {
+ continue;
}
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
if (flags & MSG_OOB)
goto out;
- if (flags & MSG_ERRQUEUE) {
- if (family == AF_INET) {
- return ip_recv_error(sk, msg, len, addr_len);
-#if IS_ENABLED(CONFIG_IPV6)
- } else if (family == AF_INET6) {
- return pingv6_ops.ipv6_recv_error(sk, msg, len,
- addr_len);
-#endif
- }
- }
+ if (flags & MSG_ERRQUEUE)
+ return inet_recv_error(sk, msg, len, addr_len);
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
u32 urg_hole = 0;
if (unlikely(flags & MSG_ERRQUEUE))
- return ip_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len, addr_len);
if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) &&
(sk->sk_state == TCP_ESTABLISHED))
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
goto csum_error;
- if (!th->ack && !th->rst)
+ if (!th->ack && !th->rst && !th->syn)
goto discard;
/*
goto discard;
}
- if (!th->ack && !th->rst)
+ if (!th->ack && !th->rst && !th->syn)
goto discard;
if (!tcp_validate_incoming(sk, skb, th, 0))
if (th->rst)
return;
- if (skb_rtable(skb)->rt_type != RTN_LOCAL)
+ /* If sk not NULL, it means we did a successful lookup and incoming
+ * route had to be correct. prequeue might have dropped our dst.
+ */
+ if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL)
return;
/* Swap the send and the receive. */
skb->protocol = gre_proto;
/* WCCP version 1 and 2 protocol decoding.
- * - Change protocol to IP
+ * - Change protocol to IPv6
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
*/
if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
- skb->protocol = htons(ETH_P_IP);
+ skb->protocol = htons(ETH_P_IPV6);
if ((*(h + offset) & 0xF0) != 0x40)
offset += 4;
}
int nhoff;
if (unlikely(skb_shinfo(skb)->gso_type &
- ~(SKB_GSO_UDP |
+ ~(SKB_GSO_TCPV4 |
+ SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_GRE |
uh->source = src_port;
uh->len = htons(skb->len);
- uh->check = 0;
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
| IPSKB_REROUTED);
skb_dst_set(skb, dst);
- udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr,
- &sk->sk_v6_daddr, skb->len);
+ udp6_set_csum(udp_get_no_check6_tx(sk), skb, saddr, daddr, skb->len);
__skb_push(skb, sizeof(*ip6h));
skb_reset_network_header(skb);
return vti6_tnl_create2(dev);
}
+static void vti6_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct net *net = dev_net(dev);
+ struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+
+ if (dev != ip6n->fb_tnl_dev)
+ unregister_netdevice_queue(dev, head);
+}
+
static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
.setup = vti6_dev_setup,
.validate = vti6_validate,
.newlink = vti6_newlink,
+ .dellink = vti6_dellink,
.changelink = vti6_changelink,
.get_size = vti6_get_size,
.fill_info = vti6_fill_info,
if (!ip6n->fb_tnl_dev)
goto err_alloc_dev;
dev_net_set(ip6n->fb_tnl_dev, net);
+ ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops;
err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
if (err < 0)
void ip6_mr_cleanup(void)
{
+ rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
+#ifdef CONFIG_IPV6_PIMSM_V2
+ inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
+#endif
unregister_netdevice_notifier(&ip6_mr_notifier);
unregister_pernet_subsys(&ip6mr_net_ops);
kmem_cache_destroy(mrt_cachep);
hdr->daddr = *daddr;
}
-static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
+static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
{
struct net_device *dev = idev->dev;
struct net *net = dev_net(dev);
const struct in6_addr *saddr;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
+ unsigned int size = mtu + hlen + tlen;
int err;
u8 ra[8] = { IPPROTO_ICMPV6, 0,
IPV6_TLV_ROUTERALERT, 2, 0, 0,
IPV6_TLV_PADN, 0 };
/* we assume size > sizeof(ra) here */
- size += hlen + tlen;
/* limit our allocations to order-0 page */
size = min_t(int, size, SKB_MAX_ORDER(0, 0));
skb = sock_alloc_send_skb(sk, size, 1, &err);
return NULL;
skb->priority = TC_PRIO_CONTROL;
+ skb->reserved_tailroom = skb_end_offset(skb) -
+ min(mtu, skb_end_offset(skb));
skb_reserve(skb, hlen);
if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
return skb;
}
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
- skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
int type, int gdeleted, int sdeleted, int crsend)
struct nf_nat_range range;
unsigned int verdict;
+ memset(&range, 0, sizeof(range));
range.flags = priv->flags;
verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
if (th->rst)
return;
- if (!ipv6_unicast_destination(skb))
+ /* If sk not NULL, it means we did a successful lookup and incoming
+ * route had to be correct. prequeue might have dropped our dst.
+ */
+ if (!sk && !ipv6_unicast_destination(skb))
return;
#ifdef CONFIG_TCP_MD5SIG
struct ipxhdr *ipx = NULL;
struct sk_buff *skb;
int copied, rc;
+ bool locked = true;
lock_sock(sk);
/* put the autobinding in */
if (sock_flag(sk, SOCK_ZAPPED))
goto out;
+ release_sock(sk);
+ locked = false;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &rc);
if (!skb) {
out_free:
skb_free_datagram(sk, skb);
out:
- release_sock(sk);
+ if (locked)
+ release_sock(sk);
return rc;
}
__aligned(__alignof__(struct aead_request));
struct aead_request *aead_req = (void *) aead_req_data;
+ if (data_len == 0)
+ return -EINVAL;
+
memset(aead_req, 0, sizeof(aead_req_data));
sg_init_one(&pt, data, data_len);
cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
cur_prob = mi->groups[cur_group].rates[cur_idx].probability;
- tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
- tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
- tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
-
- while (j > 0 && (cur_thr > tmp_thr ||
- (cur_thr == tmp_thr && cur_prob > tmp_prob))) {
- j--;
+ do {
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
- }
+ if (cur_thr < tmp_thr ||
+ (cur_thr == tmp_thr && cur_prob <= tmp_prob))
+ break;
+ j--;
+ } while (j > 0);
if (j < MAX_THR_RATES - 1) {
memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) *
if (*op < IP_SET_OP_VERSION) {
/* Check the version at the beginning of operations */
struct ip_set_req_version *req_version = data;
+
+ if (*len < sizeof(struct ip_set_req_version)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
if (req_version->version != IPSET_PROTOCOL) {
ret = -EPROTO;
goto done;
new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb)
goto error;
+ if (skb->sk)
+ skb_set_owner_w(new_skb, skb->sk);
consume_skb(skb);
skb = new_skb;
}
}
}
-/* Schedule objects for release via rcu to make sure no packets are accesing
- * removed rules.
- */
-static void nf_tables_commit_release_rcu(struct rcu_head *rt)
+static void nf_tables_commit_release(struct nft_trans *trans)
{
- struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
-
switch (trans->msg_type) {
case NFT_MSG_DELTABLE:
nf_tables_table_destroy(&trans->ctx);
}
}
+ synchronize_rcu();
+
list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
list_del(&trans->list);
- trans->ctx.nla = NULL;
- call_rcu(&trans->rcu_head, nf_tables_commit_release_rcu);
+ nf_tables_commit_release(trans);
}
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
return 0;
}
-/* Schedule objects for release via rcu to make sure no packets are accesing
- * aborted rules.
- */
-static void nf_tables_abort_release_rcu(struct rcu_head *rt)
+static void nf_tables_abort_release(struct nft_trans *trans)
{
- struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
-
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
nf_tables_table_destroy(&trans->ctx);
}
}
+ synchronize_rcu();
+
list_for_each_entry_safe_reverse(trans, next,
&net->nft.commit_list, list) {
list_del(&trans->list);
- trans->ctx.nla = NULL;
- call_rcu(&trans->rcu_head, nf_tables_abort_release_rcu);
+ nf_tables_abort_release(trans);
}
return 0;
[NFNLGRP_CONNTRACK_EXP_NEW] = NFNL_SUBSYS_CTNETLINK_EXP,
[NFNLGRP_CONNTRACK_EXP_UPDATE] = NFNL_SUBSYS_CTNETLINK_EXP,
[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
+ [NFNLGRP_NFTABLES] = NFNL_SUBSYS_NFTABLES,
+ [NFNLGRP_ACCT_QUOTA] = NFNL_SUBSYS_ACCT,
};
void nfnl_lock(__u8 subsys_id)
static int nfnetlink_bind(int group)
{
const struct nfnetlink_subsystem *ss;
- int type = nfnl_group2type[group];
+ int type;
+
+ if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
+ return -EINVAL;
+
+ type = nfnl_group2type[group];
rcu_read_lock();
ss = nfnetlink_get_subsys(type);
{
int i;
+ for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++)
+ BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
+
for (i=0; i<NFNL_SUBSYS_COUNT; i++)
mutex_init(&table[i].mutex);
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/netfilter/nf_tables.h>
-static const struct {
- const char *name;
- u8 type;
-} table_to_chaintype[] = {
- { "filter", NFT_CHAIN_T_DEFAULT },
- { "raw", NFT_CHAIN_T_DEFAULT },
- { "security", NFT_CHAIN_T_DEFAULT },
- { "mangle", NFT_CHAIN_T_ROUTE },
- { "nat", NFT_CHAIN_T_NAT },
- { },
-};
-
-static int nft_compat_table_to_chaintype(const char *table)
-{
- int i;
-
- for (i = 0; table_to_chaintype[i].name != NULL; i++) {
- if (strcmp(table_to_chaintype[i].name, table) == 0)
- return table_to_chaintype[i].type;
- }
-
- return -1;
-}
-
static int nft_compat_chain_validate_dependency(const char *tablename,
const struct nft_chain *chain)
{
- enum nft_chain_type type;
const struct nft_base_chain *basechain;
if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
return 0;
- type = nft_compat_table_to_chaintype(tablename);
- if (type < 0)
- return -EINVAL;
-
basechain = nft_base_chain(chain);
- if (basechain->type->type != type)
+ if (strcmp(tablename, "nat") == 0 &&
+ basechain->type->type != NFT_CHAIN_T_NAT)
return -EINVAL;
return 0;
struct xt_target *target, void *info,
union nft_entry *entry, u8 proto, bool inv)
{
- par->net = &init_net;
+ par->net = ctx->net;
par->table = ctx->table->name;
switch (ctx->afi->family) {
case AF_INET:
struct xt_match *match, void *info,
union nft_entry *entry, u8 proto, bool inv)
{
- par->net = &init_net;
+ par->net = ctx->net;
par->table = ctx->table->name;
switch (ctx->afi->family) {
case AF_INET:
union nft_entry e = {};
int ret;
- ret = nft_compat_chain_validate_dependency(match->name, ctx->chain);
+ ret = nft_compat_chain_validate_dependency(match->table, ctx->chain);
if (ret < 0)
goto err;
if (!(hook_mask & match->hooks))
return -EINVAL;
- ret = nft_compat_chain_validate_dependency(match->name,
+ ret = nft_compat_chain_validate_dependency(match->table,
ctx->chain);
if (ret < 0)
return ret;
{
int transport_len = skb->len - skb_transport_offset(skb);
- if (l4_proto == IPPROTO_TCP) {
+ if (l4_proto == NEXTHDR_TCP) {
if (likely(transport_len >= sizeof(struct tcphdr)))
inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
addr, new_addr, 1);
- } else if (l4_proto == IPPROTO_UDP) {
+ } else if (l4_proto == NEXTHDR_UDP) {
if (likely(transport_len >= sizeof(struct udphdr))) {
struct udphdr *uh = udp_hdr(skb);
uh->check = CSUM_MANGLED_0;
}
}
+ } else if (l4_proto == NEXTHDR_ICMP) {
+ if (likely(transport_len >= sizeof(struct icmp6hdr)))
+ inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
+ skb, addr, new_addr, 1);
}
}
case OVS_ACTION_ATTR_SAMPLE:
err = sample(dp, skb, key, a);
- if (unlikely(err)) /* skb already freed. */
- return err;
break;
}
return msgsize;
}
-/* Called with ovs_mutex or RCU read lock. */
+/* Called with ovs_mutex. */
static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd)
{
if (!reply)
return -ENOMEM;
- rcu_read_lock();
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
if (IS_ERR(dp)) {
err = PTR_ERR(dp);
err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
info->snd_seq, 0, OVS_DP_CMD_NEW);
BUG_ON(err < 0);
- rcu_read_unlock();
+ ovs_unlock();
return genlmsg_reply(reply, info);
err_unlock_free:
- rcu_read_unlock();
+ ovs_unlock();
kfree_skb(reply);
return err;
}
int skip = cb->args[0];
int i = 0;
- rcu_read_lock();
- list_for_each_entry_rcu(dp, &ovs_net->dps, list_node) {
+ ovs_lock();
+ list_for_each_entry(dp, &ovs_net->dps, list_node) {
if (i >= skip &&
ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
break;
i++;
}
- rcu_read_unlock();
+ ovs_unlock();
cb->args[0] = i;
if (match->key->eth.type == htons(ETH_P_ARP)
|| match->key->eth.type == htons(ETH_P_RARP)) {
key_expected |= 1 << OVS_KEY_ATTR_ARP;
- if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
+ if (match->mask && (match->mask->key.tp.src == htons(0xff)))
mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
}
ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
return -EINVAL;
}
+
+ if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
+ OVS_NLERR("IPv6 flow label %x is out of range (max=%x).\n",
+ ntohl(ipv6_key->ipv6_label), (1 << 20) - 1);
+ return -EINVAL;
+ }
+
SW_FLOW_KEY_PUT(match, ipv6.label,
ipv6_key->ipv6_label, is_mask);
SW_FLOW_KEY_PUT(match, ip.proto,
__unregister_prot_hook(sk, sync);
}
-static inline __pure struct page *pgv_to_page(void *addr)
+static inline struct page * __pure pgv_to_page(void *addr)
{
if (is_vmalloc_addr(addr))
return vmalloc_to_page(addr);
.set_block = rfkill_gpio_set_power,
};
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
+ { "reset-gpios", &reset_gpios, 1 },
+ { "shutdown-gpios", &shutdown_gpios, 1 },
+ { },
+};
+
static int rfkill_gpio_acpi_probe(struct device *dev,
struct rfkill_gpio_data *rfkill)
{
rfkill->name = dev_name(dev);
rfkill->type = (unsigned)id->driver_data;
- return 0;
+ return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
+ acpi_rfkill_default_gpios);
}
static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
- gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0);
+ gpio = devm_gpiod_get(&pdev->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
rfkill->reset_gpio = gpio;
}
- gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1);
+ gpio = devm_gpiod_get(&pdev->dev, "shutdown");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
rfkill_unregister(rfkill->rfkill_dev);
rfkill_destroy(rfkill->rfkill_dev);
+ acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
+
return 0;
}
xid = *p++;
calldir = *p;
- if (bc_xprt)
- req = xprt_lookup_rqst(bc_xprt, xid);
-
- if (!req) {
- printk(KERN_NOTICE
- "%s: Got unrecognized reply: "
- "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
- __func__, ntohl(calldir),
- bc_xprt, ntohl(xid));
+ if (!bc_xprt)
return -EAGAIN;
- }
+ spin_lock_bh(&bc_xprt->transport_lock);
+ req = xprt_lookup_rqst(bc_xprt, xid);
+ if (!req)
+ goto unlock_notfound;
memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
/*
dst = &req->rq_private_buf.head[0];
src = &rqstp->rq_arg.head[0];
if (dst->iov_len < src->iov_len)
- return -EAGAIN; /* whatever; just giving up. */
+ goto unlock_eagain; /* whatever; just giving up. */
memcpy(dst->iov_base, src->iov_base, src->iov_len);
xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len);
rqstp->rq_arg.len = 0;
+ spin_unlock_bh(&bc_xprt->transport_lock);
return 0;
+unlock_notfound:
+ printk(KERN_NOTICE
+ "%s: Got unrecognized reply: "
+ "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
+ __func__, ntohl(calldir),
+ bc_xprt, ntohl(xid));
+unlock_eagain:
+ spin_unlock_bh(&bc_xprt->transport_lock);
+ return -EAGAIN;
}
static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
#define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */
#define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */
#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */
+#define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */
int (*iterator)(const void *object, void *iterator_data);
#include <asm/uaccess.h>
#include "internal.h"
+#define KEY_MAX_DESC_SIZE 4096
+
static int key_get_type_from_user(char *type,
const char __user *_type,
unsigned len)
description = NULL;
if (_description) {
- description = strndup_user(_description, PAGE_SIZE);
+ description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) {
ret = PTR_ERR(description);
goto error;
goto error;
/* pull the description into kernel space */
- description = strndup_user(_description, PAGE_SIZE);
+ description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) {
ret = PTR_ERR(description);
goto error;
/* fetch the name from userspace */
name = NULL;
if (_name) {
- name = strndup_user(_name, PAGE_SIZE);
+ name = strndup_user(_name, KEY_MAX_DESC_SIZE);
if (IS_ERR(name)) {
ret = PTR_ERR(name);
goto error;
{
struct key *key, *instkey;
key_ref_t key_ref;
- char *tmpbuf;
+ char *infobuf;
long ret;
+ int desclen, infolen;
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
if (IS_ERR(key_ref)) {
}
okay:
- /* calculate how much description we're going to return */
- ret = -ENOMEM;
- tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!tmpbuf)
- goto error2;
-
key = key_ref_to_ptr(key_ref);
+ desclen = strlen(key->description);
- ret = snprintf(tmpbuf, PAGE_SIZE - 1,
- "%s;%d;%d;%08x;%s",
- key->type->name,
- from_kuid_munged(current_user_ns(), key->uid),
- from_kgid_munged(current_user_ns(), key->gid),
- key->perm,
- key->description ?: "");
-
- /* include a NUL char at the end of the data */
- if (ret > PAGE_SIZE - 1)
- ret = PAGE_SIZE - 1;
- tmpbuf[ret] = 0;
- ret++;
+ /* calculate how much information we're going to return */
+ ret = -ENOMEM;
+ infobuf = kasprintf(GFP_KERNEL,
+ "%s;%d;%d;%08x;",
+ key->type->name,
+ from_kuid_munged(current_user_ns(), key->uid),
+ from_kgid_munged(current_user_ns(), key->gid),
+ key->perm);
+ if (!infobuf)
+ goto error2;
+ infolen = strlen(infobuf);
+ ret = infolen + desclen + 1;
/* consider returning the data */
- if (buffer && buflen > 0) {
- if (buflen > ret)
- buflen = ret;
-
- if (copy_to_user(buffer, tmpbuf, buflen) != 0)
+ if (buffer && buflen >= ret) {
+ if (copy_to_user(buffer, infobuf, infolen) != 0 ||
+ copy_to_user(buffer + infolen, key->description,
+ desclen + 1) != 0)
ret = -EFAULT;
}
- kfree(tmpbuf);
+ kfree(infobuf);
error2:
key_ref_put(key_ref);
error:
if (ret < 0)
goto error;
- description = strndup_user(_description, PAGE_SIZE);
+ description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) {
ret = PTR_ERR(description);
goto error;
}
if (key->expiry && ctx->now.tv_sec >= key->expiry) {
- ctx->result = ERR_PTR(-EKEYEXPIRED);
+ if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
+ ctx->result = ERR_PTR(-EKEYEXPIRED);
kleave(" = %d [expire]", ctx->skipped_ret);
goto skipped;
}
ctx->index_key.type->name,
ctx->index_key.description);
+#define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK)
+ BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
+ (ctx->flags & STATE_CHECKS) == STATE_CHECKS);
+
if (ctx->index_key.description)
ctx->index_key.desc_len = strlen(ctx->index_key.description);
if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
keyring_compare_object(keyring, &ctx->index_key)) {
ctx->skipped_ret = 2;
- ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) {
case 1:
goto found;
}
ctx->skipped_ret = 0;
- if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)
- ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK;
/* Start processing a new keyring */
descend_to_keyring:
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = (KEYRING_SEARCH_DO_STATE_CHECK |
+ KEYRING_SEARCH_SKIP_EXPIRED),
};
struct key *key;
key_ref_t key_ref;
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_DO_STATE_CHECK,
};
struct key *authkey;
key_ref_t authkey_ref;
FORMAT(DSD_U8),
FORMAT(DSD_U16_LE),
FORMAT(DSD_U32_LE),
+ FORMAT(DSD_U16_BE),
+ FORMAT(DSD_U32_BE),
};
const char *snd_pcm_format_name(snd_pcm_format_t format)
.width = 32, .phys = 32, .le = 1, .signd = 0,
.silence = { 0x69, 0x69, 0x69, 0x69 },
},
+ [SNDRV_PCM_FORMAT_DSD_U16_BE] = {
+ .width = 16, .phys = 16, .le = 0, .signd = 0,
+ .silence = { 0x69, 0x69 },
+ },
+ [SNDRV_PCM_FORMAT_DSD_U32_BE] = {
+ .width = 32, .phys = 32, .le = 0, .signd = 0,
+ .silence = { 0x69, 0x69, 0x69, 0x69 },
+ },
/* FIXME: the following three formats are not defined properly yet */
[SNDRV_PCM_FORMAT_MPEG] = {
.le = -1, .signd = -1,
/* quirks for ATI/AMD HDMI */
#define AZX_DCAPS_PRESET_ATI_HDMI \
- (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\
+ AZX_DCAPS_NO_MSI64)
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
struct snd_card *card = chip->card;
int err;
unsigned short gcap;
+ unsigned int dma_bits = 64;
#if BITS_PER_LONG != 64
/* Fix up base address on ULI M5461 */
return -ENXIO;
}
- if (chip->msi)
+ if (chip->msi) {
+ if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
+ dev_dbg(card->dev, "Disabling 64bit MSI\n");
+ pci->no_64bit_msi = true;
+ }
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
+ }
if (azx_acquire_irq(chip, 0) < 0)
return -EBUSY;
gcap = azx_readw(chip, GCAP);
dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
+ /* AMD devices support 40 or 48bit DMA, take the safe one */
+ if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+ dma_bits = 40;
+
/* disable SB600 64bit support for safety */
if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
struct pci_dev *p_smbus;
+ dma_bits = 40;
p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
PCI_DEVICE_ID_ATI_SBX00_SMBUS,
NULL);
}
/* allow 64bit DMA address if supported by H/W */
- if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
- else {
+ if (!(gcap & AZX_GCAP_64OK))
+ dma_bits = 32;
+ if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) {
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits));
+ } else {
pci_set_dma_mask(pci, DMA_BIT_MASK(32));
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
}
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
+#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
/* HD Audio class code */
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
[ALC269_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
},
[ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
.type = HDA_FIXUP_FUNC,
[ALC255_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc255,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
},
[ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
.type = HDA_FIXUP_FUNC,
[ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_dell_wmi,
- .chained_before = true,
- .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
},
[ALC282_FIXUP_ASPIRE_V5_PINS] = {
.type = HDA_FIXUP_PINS,
SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
- SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
- SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
.driver = {
.name = "cs42l51",
.owner = THIS_MODULE,
+ .of_match_table = cs42l51_of_match,
},
.probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
}
EXPORT_SYMBOL_GPL(cs42l51_probe);
-static const struct of_device_id cs42l51_of_match[] = {
+const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }
};
MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+EXPORT_SYMBOL_GPL(cs42l51_of_match);
+
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
extern const struct regmap_config cs42l51_regmap;
int cs42l51_probe(struct device *dev, struct regmap *regmap);
+extern const struct of_device_id cs42l51_of_match[];
#define CS42L51_CHIP_ID 0x1B
#define CS42L51_CHIP_REV_A 0x00
#include "es8328.h"
static const struct i2c_device_id es8328_id[] = {
- { "everest,es8328", 0 },
+ { "es8328", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8328_id);
* 0x02 (when master clk is 20MHz to 40MHz)..
* 0x03 (when master clk is 40MHz to 60MHz)..
*/
- if ((freq >= 10000000) && (freq < 20000000)) {
+ if ((freq >= 10000000) && (freq <= 20000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV1);
- } else if ((freq >= 20000000) && (freq < 40000000)) {
+ } else if ((freq > 20000000) && (freq <= 40000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV2);
- } else if ((freq >= 40000000) && (freq < 60000000)) {
+ } else if ((freq > 40000000) && (freq <= 60000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV4);
} else {
{ 0x76, 0x000a },
{ 0x77, 0x0c00 },
{ 0x78, 0x0000 },
+ { 0x79, 0x0123 },
{ 0x80, 0x0000 },
{ 0x81, 0x0000 },
{ 0x82, 0x0000 },
case RT5645_DMIC_CTRL2:
case RT5645_TDM_CTRL_1:
case RT5645_TDM_CTRL_2:
+ case RT5645_TDM_CTRL_3:
case RT5645_GLB_CLK:
case RT5645_PLL_CTRL1:
case RT5645_PLL_CTRL2:
{ 0x4c, 0x5380 },
{ 0x4f, 0x0073 },
{ 0x52, 0x00d3 },
- { 0x53, 0xf0f0 },
+ { 0x53, 0xf000 },
{ 0x61, 0x0000 },
{ 0x62, 0x0001 },
{ 0x63, 0x00c3 },
{ 0x64, 0x0000 },
- { 0x65, 0x0000 },
+ { 0x65, 0x0001 },
{ 0x66, 0x0000 },
{ 0x6f, 0x8000 },
{ 0x70, 0x8000 },
{ 0x71, 0x8000 },
{ 0x72, 0x8000 },
- { 0x73, 0x1110 },
+ { 0x73, 0x7770 },
{ 0x74, 0x0e00 },
{ 0x75, 0x1505 },
{ 0x76, 0x0015 },
{ 0x83, 0x0000 },
{ 0x84, 0x0000 },
{ 0x85, 0x0000 },
- { 0x86, 0x0008 },
+ { 0x86, 0x0004 },
{ 0x87, 0x0000 },
{ 0x88, 0x0000 },
{ 0x89, 0x0000 },
{ 0x8a, 0x0000 },
{ 0x8b, 0x0000 },
- { 0x8c, 0x0007 },
+ { 0x8c, 0x0003 },
{ 0x8d, 0x0000 },
{ 0x8e, 0x0004 },
{ 0x8f, 0x1100 },
{ 0x90, 0x0646 },
{ 0x91, 0x0c06 },
{ 0x93, 0x0000 },
- { 0x94, 0x0000 },
- { 0x95, 0x0000 },
+ { 0x94, 0x1270 },
+ { 0x95, 0x1000 },
{ 0x97, 0x0000 },
{ 0x98, 0x0000 },
{ 0x99, 0x0000 },
{ 0x9e, 0x0400 },
{ 0xae, 0x7000 },
{ 0xaf, 0x0000 },
- { 0xb0, 0x6000 },
+ { 0xb0, 0x7000 },
{ 0xb1, 0x0000 },
{ 0xb2, 0x0000 },
{ 0xb3, 0x001f },
- { 0xb4, 0x2206 },
+ { 0xb4, 0x220c },
{ 0xb5, 0x1f00 },
{ 0xb6, 0x0000 },
{ 0xb7, 0x0000 },
{ 0xcf, 0x1813 },
{ 0xd0, 0x0690 },
{ 0xd1, 0x1c17 },
- { 0xd3, 0xb320 },
+ { 0xd3, 0xa220 },
{ 0xd4, 0x0000 },
{ 0xd6, 0x0400 },
{ 0xd9, 0x0809 },
{ 0xda, 0x0000 },
{ 0xdb, 0x0001 },
{ 0xdc, 0x0049 },
- { 0xdd, 0x0009 },
+ { 0xdd, 0x0024 },
{ 0xe6, 0x8000 },
{ 0xe7, 0x0000 },
- { 0xec, 0xb300 },
+ { 0xec, 0xa200 },
{ 0xed, 0x0000 },
- { 0xee, 0xb300 },
+ { 0xee, 0xa200 },
{ 0xef, 0x0000 },
{ 0xf8, 0x0000 },
{ 0xf9, 0x0000 },
{ 0xfa, 0x8010 },
{ 0xfb, 0x0033 },
- { 0xfc, 0x0080 },
+ { 0xfc, 0x0100 },
};
static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
{ "DAC1 MIXR", NULL, "DAC Stereo1 Filter" },
+ { "DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll },
+ { "DAC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll },
+ { "DAC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
{ "DAC MIX", NULL, "DAC1 MIXL" },
{ "DAC MIX", NULL, "DAC1 MIXR" },
{ "DAC L1", NULL, "DAC L1 Power" },
{ "DAC L1", NULL, "Stereo DAC MIXL" },
- { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC R1", NULL, "DAC R1 Power" },
{ "DAC R1", NULL, "Stereo DAC MIXR" },
- { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC L2", NULL, "Mono DAC MIXL" },
- { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC R2", NULL, "Mono DAC MIXR" },
- { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
{ "OUT MIXL", "BST1 Switch", "BST1" },
{ "OUT MIXL", "INL Switch", "INL VOL" },
/* enable small pop, introduce 400ms delay in turning off */
snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
- SGTL5000_SMALL_POP,
- SGTL5000_SMALL_POP);
+ SGTL5000_SMALL_POP, 1);
/* disable short cut detector */
snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0);
#define SGTL5000_BIAS_CTRL_MASK 0x000e
#define SGTL5000_BIAS_CTRL_SHIFT 1
#define SGTL5000_BIAS_CTRL_WIDTH 3
-#define SGTL5000_SMALL_POP 0x0001
+#define SGTL5000_SMALL_POP 0
/*
* SGTL5000_CHIP_MIC_CTRL
file, blocks, pos - firmware->size);
out_fw:
+ regmap_async_complete(regmap);
release_firmware(firmware);
wm_adsp_buf_free(&buf_list);
out:
}
}
+static struct reg_default fsl_asrc_reg[] = {
+ { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 },
+ { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 },
+ { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 },
+ { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 },
+ { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 },
+ { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 },
+ { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 },
+ { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 },
+ { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 },
+ { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 },
+ { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 },
+ { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 },
+ { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 },
+ { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 },
+ { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 },
+ { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 },
+ { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 },
+ { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 },
+ { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 },
+ { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 },
+ { REG_ASRMCR1C, 0x0000 },
+};
+
static const struct regmap_config fsl_asrc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = REG_ASRMCR1C,
+ .reg_defaults = fsl_asrc_reg,
+ .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg),
.readable_reg = fsl_asrc_readable_reg,
.volatile_reg = fsl_asrc_volatile_reg,
.writeable_reg = fsl_asrc_writeable_reg,
while (val) {
regmap_read(i2s->regmap, I2S_CLR, &val);
retry--;
- if (!retry)
+ if (!retry) {
dev_warn(i2s->dev, "fail to clear\n");
+ break;
+ }
}
}
}
{ .compatible = "google,snow-audio-max98095", },
{},
};
+MODULE_DEVICE_TABLE(of, snow_of_match);
static struct platform_driver snow_driver = {
.driver = {
static struct snd_pcm_hardware fsi_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE,
+ SNDRV_PCM_INFO_MMAP_VALID,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8192,
static struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE,
+ SNDRV_PCM_INFO_MMAP_VALID,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8192,
list_for_each_entry(component, &component_list, list) {
if (dlc->of_node && component->dev->of_node != dlc->of_node)
continue;
- if (dlc->name && strcmp(dev_name(component->dev), dlc->name))
+ if (dlc->name && strcmp(component->name, dlc->name))
continue;
list_for_each_entry(dai, &component->dai_list, list) {
if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
}
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
+
+/* Set FE's runtime_update state; the state is protected via PCM stream lock
+ * for avoiding the race with trigger callback.
+ * If the state is unset and a trigger is pending while the previous operation,
+ * process the pending trigger action here.
+ */
+static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
+ int stream, enum snd_soc_dpcm_update state)
+{
+ struct snd_pcm_substream *substream =
+ snd_soc_dpcm_get_substream(fe, stream);
+
+ snd_pcm_stream_lock_irq(substream);
+ if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
+ dpcm_fe_dai_do_trigger(substream,
+ fe->dpcm[stream].trigger_pending - 1);
+ fe->dpcm[stream].trigger_pending = 0;
+ }
+ fe->dpcm[stream].runtime_update = state;
+ snd_pcm_stream_unlock_irq(substream);
+}
+
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
{
struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
struct snd_pcm_runtime *runtime = fe_substream->runtime;
int stream = fe_substream->stream, ret = 0;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
ret = dpcm_be_dai_startup(fe, fe_substream->stream);
if (ret < 0) {
dpcm_set_fe_runtime(fe_substream);
snd_pcm_limit_hw_rates(runtime);
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return 0;
unwind:
dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
be_err:
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return ret;
}
struct snd_soc_pcm_runtime *fe = substream->private_data;
int stream = substream->stream;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
/* shutdown the BEs */
dpcm_be_dai_shutdown(fe, substream->stream);
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return 0;
}
int err, stream = substream->stream;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
err = dpcm_be_dai_hw_free(fe, stream);
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
mutex_unlock(&fe->card->mutex);
return 0;
int ret, stream = substream->stream;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
memcpy(&fe->dpcm[substream->stream].hw_params, params,
sizeof(struct snd_pcm_hw_params));
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
out:
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
mutex_unlock(&fe->card->mutex);
return ret;
}
}
EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
-static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *fe = substream->private_data;
int stream = substream->stream, ret;
return ret;
}
+static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int stream = substream->stream;
+
+ /* if FE's runtime_update is already set, we're in race;
+ * process this trigger later at exit
+ */
+ if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
+ fe->dpcm[stream].trigger_pending = cmd + 1;
+ return 0; /* delayed, assuming it's successful */
+ }
+
+ /* we're alone, let's trigger */
+ return dpcm_fe_dai_do_trigger(substream, cmd);
+}
+
int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
/* there is no point preparing this FE if there are no BEs */
if (list_empty(&fe->dpcm[stream].be_clients)) {
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
out:
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
mutex_unlock(&fe->card->mutex);
return ret;
{
int ret;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
ret = dpcm_run_update_startup(fe, stream);
if (ret < 0)
dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return ret;
}
{
int ret;
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
ret = dpcm_run_update_shutdown(fe, stream);
if (ret < 0)
dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return ret;
}
cval->res = 1;
cval->initialized = 1;
- if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
- cval->control = UAC2_CX_CLOCK_SELECTOR;
- else
+ if (state->mixer->protocol == UAC_VERSION_1)
cval->control = 0;
+ else /* UAC_VERSION_2 */
+ cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ?
+ UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR;
namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
if (!namelist) {
if (mixer->chip->shutdown)
ret = -ENODEV;
else
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0, wIndex,
- &tmp, sizeof(tmp), 1000);
+ &tmp, sizeof(tmp));
up_read(&mixer->chip->shutdown_rwsem);
if (ret < 0) {
if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
+
+ /* Marantz/Denon devices with USB DAC functionality need a delay
+ * after each class compliant request
+ */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) &&
+ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
+
+ switch (le16_to_cpu(dev->descriptor.idProduct)) {
+ case 0x3005: /* Marantz HD-DAC1 */
+ case 0x3006: /* Marantz SA-14S1 */
+ mdelay(20);
+ break;
+ }
+ }
}
/*
/* iFi Audio micro/nano iDSD */
case USB_ID(0x20b1, 0x3008):
if (fp->altsetting == 2)
- return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
/* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
case USB_ID(0x20b1, 0x2009):
if (fp->altsetting == 3)
- return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
default:
break;
static void cpuidle_cpu_output(unsigned int cpu, int verbose)
{
- unsigned int idlestates, idlestate;
+ int idlestates, idlestate;
char *tmp;
printf(_ ("Analyzing CPU %d:\n"), cpu);
idlestates = sysfs_get_idlestate_count(cpu);
- if (idlestates == 0) {
+ if (idlestates < 1) {
printf(_("CPU %u: No idle states\n"), cpu);
return;
}
static void proc_cpuidle_cpu_output(unsigned int cpu)
{
long max_allowed_cstate = 2000000000;
- unsigned int cstate, cstates;
+ int cstate, cstates;
cstates = sysfs_get_idlestate_count(cpu);
- if (cstates == 0) {
+ if (cstates < 1) {
printf(_("CPU %u: No C-states info\n"), cpu);
return;
}
int kvm_vgic_create(struct kvm *kvm)
{
- int i, vcpu_lock_idx = -1, ret = 0;
+ int i, vcpu_lock_idx = -1, ret;
struct kvm_vcpu *vcpu;
mutex_lock(&kvm->lock);
* vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure
* that no other VCPUs are run while we create the vgic.
*/
+ ret = -EBUSY;
kvm_for_each_vcpu(i, vcpu, kvm) {
if (!mutex_trylock(&vcpu->mutex))
goto out_unlock;
}
kvm_for_each_vcpu(i, vcpu, kvm) {
- if (vcpu->arch.has_run_once) {
- ret = -EBUSY;
+ if (vcpu->arch.has_run_once)
goto out_unlock;
- }
}
+ ret = 0;
spin_lock_init(&kvm->arch.vgic.lock);
kvm->arch.vgic.in_kernel = true;
static bool largepages_enabled = true;
-bool kvm_is_mmio_pfn(pfn_t pfn)
+bool kvm_is_reserved_pfn(pfn_t pfn)
{
if (pfn_valid(pfn))
- return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
+ return PageReserved(pfn_to_page(pfn));
return true;
}
else if ((vma->vm_flags & VM_PFNMAP)) {
pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) +
vma->vm_pgoff;
- BUG_ON(!kvm_is_mmio_pfn(pfn));
+ BUG_ON(!kvm_is_reserved_pfn(pfn));
} else {
if (async && vma_is_valid(vma, write_fault))
*async = true;
if (is_error_noslot_pfn(pfn))
return KVM_ERR_PTR_BAD_PAGE;
- if (kvm_is_mmio_pfn(pfn)) {
+ if (kvm_is_reserved_pfn(pfn)) {
WARN_ON(1);
return KVM_ERR_PTR_BAD_PAGE;
}
void kvm_release_pfn_clean(pfn_t pfn)
{
- if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn))
+ if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn))
put_page(pfn_to_page(pfn));
}
EXPORT_SYMBOL_GPL(kvm_release_pfn_clean);
void kvm_set_pfn_dirty(pfn_t pfn)
{
- if (!kvm_is_mmio_pfn(pfn)) {
+ if (!kvm_is_reserved_pfn(pfn)) {
struct page *page = pfn_to_page(pfn);
if (!PageReserved(page))
SetPageDirty(page);
void kvm_set_pfn_accessed(pfn_t pfn)
{
- if (!kvm_is_mmio_pfn(pfn))
+ if (!kvm_is_reserved_pfn(pfn))
mark_page_accessed(pfn_to_page(pfn));
}
EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed);
void kvm_get_pfn(pfn_t pfn)
{
- if (!kvm_is_mmio_pfn(pfn))
+ if (!kvm_is_reserved_pfn(pfn))
get_page(pfn_to_page(pfn));
}
EXPORT_SYMBOL_GPL(kvm_get_pfn);