]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge tag 'wireless-drivers-for-davem-2017-11-22' of git://git.kernel.org/pub/scm...
authorDavid S. Miller <davem@davemloft.net>
Thu, 23 Nov 2017 18:06:42 +0000 (03:06 +0900)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Nov 2017 18:06:42 +0000 (03:06 +0900)
Kalle Valo says:

====================
wireless-drivers fixes for 4.15

First set of fixes for 4.15. Most important here is the iwlwifi fix
for scan command firmware interface change.

ath10k

* fix CCMP-256, GCMP and GCMP-256 in raw mode, it was never working

wcn36xx

* fix device tree node search

iwlwifi

* fix a regression with firmware API change of scan cmd (introduced in
  firmware version 34)

* add a bunch of PCI IDs and fix configuration structs for A000 devices

* fix the exported firmware name strings for 9000 and A000 devices
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
206 files changed:
Documentation/ABI/testing/dell-smbios-wmi [new file with mode: 0644]
Documentation/ABI/testing/sysfs-platform-dell-smbios [new file with mode: 0644]
Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt [new file with mode: 0644]
Documentation/admin-guide/thunderbolt.rst
Documentation/devicetree/bindings/display/google,goldfish-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/trivial-devices.txt
Documentation/devicetree/bindings/usb/usb-device.txt
Documentation/switchtec.txt
MAINTAINERS
drivers/block/rbd.c
drivers/ide/ide-pnp.c
drivers/net/dsa/bcm_sf2.c
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40evf_client.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/netronome/nfp/bpf/offload.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/phy/cortina.c
drivers/net/tap.c
drivers/net/tun.c
drivers/net/usb/qmi_wwan.c
drivers/net/wireless/mac80211_hwsim.c
drivers/ntb/hw/Kconfig
drivers/ntb/hw/Makefile
drivers/ntb/hw/idt/ntb_hw_idt.c
drivers/ntb/hw/intel/ntb_hw_intel.c
drivers/ntb/hw/mscc/Kconfig [new file with mode: 0644]
drivers/ntb/hw/mscc/Makefile [new file with mode: 0644]
drivers/ntb/hw/mscc/ntb_hw_switchtec.c [new file with mode: 0644]
drivers/ntb/ntb_transport.c
drivers/ntb/test/ntb_perf.c
drivers/ntb/test/ntb_tool.c
drivers/of/base.c
drivers/of/of_pci.c
drivers/of/unittest-data/Makefile
drivers/of/unittest-data/testcases.dts
drivers/pci/switch/switchtec.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-smbios-smm.c [new file with mode: 0644]
drivers/platform/x86/dell-smbios-wmi.c [new file with mode: 0644]
drivers/platform/x86/dell-smbios.c
drivers/platform/x86/dell-smbios.h
drivers/platform/x86/dell-smo8800.c
drivers/platform/x86/dell-wmi-descriptor.c [new file with mode: 0644]
drivers/platform/x86/dell-wmi-descriptor.h [new file with mode: 0644]
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel-hid.c
drivers/platform/x86/intel-wmi-thunderbolt.c [new file with mode: 0644]
drivers/platform/x86/intel_cht_int33fe.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_ips.h
drivers/platform/x86/intel_punit_ipc.c
drivers/platform/x86/intel_telemetry_core.c
drivers/platform/x86/intel_telemetry_debugfs.c
drivers/platform/x86/intel_telemetry_pltdrv.c
drivers/platform/x86/intel_turbo_max_3.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/peaq-wmi.c
drivers/platform/x86/silead_dmi.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/wmi.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/aty/radeon_base.c
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/au1200fb.c
drivers/video/fbdev/cirrusfb.c
drivers/video/fbdev/controlfb.h
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/dnfb.c
drivers/video/fbdev/goldfishfb.c
drivers/video/fbdev/igafb.c [deleted file]
drivers/video/fbdev/intelfb/intelfbhw.c
drivers/video/fbdev/matrox/matroxfb_base.c
drivers/video/fbdev/mxsfb.c
drivers/video/fbdev/omap/hwa742.c
drivers/video/fbdev/omap2/omapfb/dss/dsi.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/sa1100fb.h
drivers/video/fbdev/sis/init301.c
drivers/video/fbdev/sis/sis_main.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/udlfb.c
fs/ceph/caps.c
fs/ceph/inode.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/super.h
fs/lockd/svc.c
fs/nfs_common/grace.c
fs/nfsd/fault_inject.c
fs/nfsd/netns.h
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/xdr4.h
fs/orangefs/acl.c
fs/orangefs/dir.c
fs/orangefs/file.c
fs/orangefs/inode.c
fs/orangefs/namei.c
fs/orangefs/orangefs-debug.h
fs/orangefs/orangefs-kernel.h
fs/orangefs/orangefs-utils.c
fs/orangefs/super.c
fs/orangefs/symlink.c
include/linux/bpf.h
include/linux/bpf_verifier.h
include/linux/fs.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/ntb.h
include/linux/printk.h
include/linux/skbuff.h
include/linux/sunrpc/svc.h
include/linux/switchtec.h [new file with mode: 0644]
include/linux/virtio_net.h
include/linux/wmi.h
include/net/ipv6.h
include/trace/events/sunrpc.h
include/uapi/linux/bpf.h
include/uapi/linux/wmi.h [new file with mode: 0644]
include/video/iga.h [deleted file]
kernel/bpf/offload.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/printk/printk.c
kernel/printk/printk_safe.c
kernel/trace/bpf_trace.c
net/ceph/ceph_hash.c
net/ceph/crypto.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/core/dev.c
net/core/filter.c
net/ipv4/af_inet.c
net/ipv4/udp_offload.c
net/ipv6/output_core.c
net/ipv6/route.c
net/ipv6/udp_offload.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/led.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/ocb.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/sched/act_csum.c
net/sched/cls_api.c
net/sched/cls_bpf.c
net/smc/smc_core.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/tipc/group.c
net/wireless/nl80211.c
net/wireless/reg.c
security/integrity/ima/ima_appraise.c
tools/Makefile
tools/bpf/bpftool/prog.c
tools/include/uapi/linux/bpf.h
tools/testing/selftests/bpf/test_verifier.c
tools/wmi/Makefile [new file with mode: 0644]
tools/wmi/dell-smbios-example.c [new file with mode: 0644]

diff --git a/Documentation/ABI/testing/dell-smbios-wmi b/Documentation/ABI/testing/dell-smbios-wmi
new file mode 100644 (file)
index 0000000..fc919ce
--- /dev/null
@@ -0,0 +1,41 @@
+What:          /dev/wmi/dell-smbios
+Date:          November 2017
+KernelVersion: 4.15
+Contact:       "Mario Limonciello" <mario.limonciello@dell.com>
+Description:
+               Perform SMBIOS calls on supported Dell machines.
+               through the Dell ACPI-WMI interface.
+
+               IOCTL's and buffer formats are defined in:
+               <uapi/linux/wmi.h>
+
+               1) To perform an SMBIOS call from userspace, you'll need to
+               first determine the minimum size of the calling interface
+               buffer for your machine.
+               Platforms that contain larger buffers can return larger
+               objects from the system firmware.
+               Commonly this size is either 4k or 32k.
+
+               To determine the size of the buffer read() a u64 dword from
+               the WMI character device /dev/wmi/dell-smbios.
+
+               2) After you've determined the minimum size of the calling
+               interface buffer, you can allocate a structure that represents
+               the structure documented above.
+
+               3) In the 'length' object store the size of the buffer you
+               determined above and allocated.
+
+               4) In this buffer object, prepare as necessary for the SMBIOS
+               call you're interested in.  Typically SMBIOS buffers have
+               "class", "select", and "input" defined to values that coincide
+               with the data you are interested in.
+               Documenting class/select/input values is outside of the scope
+               of this documentation. Check with the libsmbios project for
+               further documentation on these values.
+
+               6) Run the call by using ioctl() as described in the header.
+
+               7) The output will be returned in the buffer object.
+
+               8) Be sure to free up your allocated object.
diff --git a/Documentation/ABI/testing/sysfs-platform-dell-smbios b/Documentation/ABI/testing/sysfs-platform-dell-smbios
new file mode 100644 (file)
index 0000000..205d3b6
--- /dev/null
@@ -0,0 +1,21 @@
+What:          /sys/devices/platform/<platform>/tokens/*
+Date:          November 2017
+KernelVersion: 4.15
+Contact:       "Mario Limonciello" <mario.limonciello@dell.com>
+Description:
+               A read-only description of Dell platform tokens
+               available on the machine.
+
+               Each token attribute is available as a pair of
+               sysfs attributes readable by a process with
+               CAP_SYS_ADMIN.
+
+               For example the token ID "5" would be available
+               as the following attributes:
+
+               0005_location
+               0005_value
+
+               Tokens will vary from machine to machine, and
+               only tokens available on that machine will be
+               displayed.
diff --git a/Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt b/Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt
new file mode 100644 (file)
index 0000000..8af6505
--- /dev/null
@@ -0,0 +1,11 @@
+What:          /sys/devices/platform/<platform>/force_power
+Date:          September 2017
+KernelVersion: 4.15
+Contact:       "Mario Limonciello" <mario.limonciello@dell.com>
+Description:
+               Modify the platform force power state, influencing
+               Thunderbolt controllers to turn on or off when no
+               devices are connected (write-only)
+               There are two available states:
+                   * 0 -> Force power disabled
+                   * 1 -> Force power enabled
index 5c62d11d77e86f1709591ba4f3b2abd0e5530a32..de50a8561774249351515662404e2a1f8328aba6 100644 (file)
@@ -221,3 +221,18 @@ The driver will create one virtual ethernet interface per Thunderbolt
 port which are named like ``thunderbolt0`` and so on. From this point
 you can either use standard userspace tools like ``ifconfig`` to
 configure the interface or let your GUI to handle it automatically.
+
+Forcing power
+-------------
+Many OEMs include a method that can be used to force the power of a
+thunderbolt controller to an "On" state even if nothing is connected.
+If supported by your machine this will be exposed by the WMI bus with
+a sysfs attribute called "force_power".
+
+For example the intel-wmi-thunderbolt driver exposes this attribute in:
+  /sys/devices/platform/PNP0C14:00/wmi_bus/wmi_bus-PNP0C14:00/86CCFD48-205E-4A77-9C48-2021CBEDE341/force_power
+
+  To force the power to on, write 1 to this attribute file.
+  To disable force power, write 0 to this attribute file.
+
+Note: it's currently not possible to query the force power state of a platform.
diff --git a/Documentation/devicetree/bindings/display/google,goldfish-fb.txt b/Documentation/devicetree/bindings/display/google,goldfish-fb.txt
new file mode 100644 (file)
index 0000000..751fa9f
--- /dev/null
@@ -0,0 +1,17 @@
+Android Goldfish framebuffer
+
+Android Goldfish framebuffer device used by Android emulator.
+
+Required properties:
+
+- compatible : should contain "google,goldfish-fb"
+- reg        : <registers mapping>
+- interrupts : <interrupt mapping>
+
+Example:
+
+       display-controller@1f008000 {
+               compatible = "google,goldfish-fb";
+               interrupts = <0x10>;
+               reg = <0x1f008000 0x100>;
+       };
index 27dce08edd733b0a4c85cb2ac71baa90edb043b5..678039d4d5e57f96eacd9c9b5a0e8ce72a1d4dd4 100644 (file)
@@ -55,7 +55,6 @@ epson,rx8010          I2C-BUS INTERFACE REAL TIME CLOCK MODULE
 epson,rx8581           I2C-BUS INTERFACE REAL TIME CLOCK MODULE
 emmicro,em3027         EM Microelectronic EM3027 Real-time Clock
 fsl,mag3110            MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
-fsl,mc13892            MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
 fsl,mma7660            MMA7660FC: 3-Axis Orientation/Motion Detection Sensor
 fsl,mma8450            MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
 fsl,mpl3115            MPL3115: Absolute Digital Pressure Sensor
index ce02cebac26afdc80d99600725b3aaec24cb01e9..1b27cebb47f4286f8fac429f1361e6cba240d469 100644 (file)
@@ -4,24 +4,35 @@ Usually, we only use device tree for hard wired USB device.
 The reference binding doc is from:
 http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps
 
+
 Required properties:
-- compatible: usbVID,PID. The textual representation of VID, PID shall
-  be in lower case hexadecimal with leading zeroes suppressed. The
-  other compatible strings from the above standard binding could also
-  be used, but a device adhering to this binding may leave out all except
-  for usbVID,PID.
-- reg: the port number which this device is connecting to, the range
-  is 1-31.
+- compatible: "usbVID,PID", where VID is the vendor id and PID the product id.
+  The textual representation of VID and PID shall be in lower case hexadecimal
+  with leading zeroes suppressed. The other compatible strings from the above
+  standard binding could also be used, but a device adhering to this binding
+  may leave out all except for "usbVID,PID".
+- reg: the number of the USB hub port or the USB host-controller port to which
+  this device is attached. The range is 1-255.
+
+
+Required properties for hub nodes with device nodes:
+- #address-cells: shall be 1
+- #size-cells: shall be 0
 
-Example:
 
-&usb1 {
+Required properties for host-controller nodes with device nodes:
+- #address-cells: shall be 1
+- #size-cells: shall be 0
+
+
+Example:
 
+&usb1 {        /* host controller */
        #address-cells = <1>;
        #size-cells = <0>;
 
-       hub: genesys@1 {
+       hub@1 { /* hub connected to port 1 */
                compatible = "usb5e3,608";
                reg = <1>;
        };
-}
+};
index a0a9c7b3d4d546cc79cdbc39c6555371a4843675..f788264921ffa21415169997225ff40a70469bd7 100644 (file)
@@ -78,3 +78,15 @@ The following IOCTLs are also supported by the device:
   between PCI Function Framework number (used by the event system)
   and Switchtec Logic Port ID and Partition number (which is more
   user friendly).
+
+
+Non-Transparent Bridge (NTB) Driver
+===================================
+
+An NTB driver is provided for the switchtec hardware in switchtec_ntb.
+Currently, it only supports switches configured with exactly 2
+partitions. It also requires the following configuration settings:
+
+* Both partitions must be able to access each other's GAS spaces.
+  Thus, the bits in the GAS Access Vector under Management Settings
+  must be set to support this.
index 16137acd7f2fdb856951e0873273c180580cd2b0..44512c346206708bfc9b90e14e8e733a8aa81018 100644 (file)
@@ -384,6 +384,7 @@ ACPI WMI DRIVER
 L:     platform-driver-x86@vger.kernel.org
 S:     Orphan
 F:     drivers/platform/x86/wmi.c
+F:     include/uapi/linux/wmi.h
 
 AD1889 ALSA SOUND DRIVER
 M:     Thibaut Varene <T-Bone@parisc-linux.org>
@@ -4030,6 +4031,26 @@ M:       "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
 F:     drivers/net/fddi/defxx.*
 
+DELL SMBIOS DRIVER
+M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Mario Limonciello <mario.limonciello@dell.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/dell-smbios.*
+
+DELL SMBIOS SMM DRIVER
+M:     Mario Limonciello <mario.limonciello@dell.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/dell-smbios-smm.c
+
+DELL SMBIOS WMI DRIVER
+M:     Mario Limonciello <mario.limonciello@dell.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/dell-smbios-wmi.c
+F:     tools/wmi/dell-smbios-example.c
+
 DELL LAPTOP DRIVER
 M:     Matthew Garrett <mjg59@srcf.ucam.org>
 M:     Pali Rohár <pali.rohar@gmail.com>
@@ -4059,12 +4080,17 @@ S:      Maintained
 F:     Documentation/dcdbas.txt
 F:     drivers/firmware/dcdbas.*
 
-DELL WMI EXTRAS DRIVER
+DELL WMI NOTIFICATIONS DRIVER
 M:     Matthew Garrett <mjg59@srcf.ucam.org>
 M:     Pali Rohár <pali.rohar@gmail.com>
 S:     Maintained
 F:     drivers/platform/x86/dell-wmi.c
 
+DELL WMI DESCRIPTOR DRIVER
+M:     Mario Limonciello <mario.limonciello@dell.com>
+S:     Maintained
+F:     drivers/platform/x86/dell-wmi-descriptor.c
+
 DELTA ST MEDIA DRIVER
 M:     Hugues Fruchet <hugues.fruchet@st.com>
 L:     linux-media@vger.kernel.org
@@ -7181,6 +7207,11 @@ F:       Documentation/wimax/README.i2400m
 F:     drivers/net/wimax/i2400m/
 F:     include/uapi/linux/wimax/i2400m.h
 
+INTEL WMI THUNDERBOLT FORCE POWER DRIVER
+M:     Mario Limonciello <mario.limonciello@dell.com>
+S:     Maintained
+F:     drivers/platform/x86/intel-wmi-thunderbolt.c
+
 INTEL(R) TRACE HUB
 M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
 S:     Supported
@@ -7442,7 +7473,7 @@ JFS FILESYSTEM
 M:     Dave Kleikamp <shaggy@kernel.org>
 L:     jfs-discussion@lists.sourceforge.net
 W:     http://jfs.sourceforge.net/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
+T:     git git://github.com/kleikamp/linux-shaggy.git
 S:     Maintained
 F:     Documentation/filesystems/jfs.txt
 F:     fs/jfs/
@@ -9695,12 +9726,11 @@ S:      Supported
 F:     drivers/ntb/hw/idt/
 
 NTB INTEL DRIVER
-M:     Jon Mason <jdmason@kudzu.us>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-ntb@googlegroups.com
 S:     Supported
-W:     https://github.com/jonmason/ntb/wiki
-T:     git git://github.com/jonmason/ntb.git
+W:     https://github.com/davejiang/linux/wiki
+T:     git https://github.com/davejiang/linux.git
 F:     drivers/ntb/hw/intel/
 
 NTFS FILESYSTEM
@@ -10412,6 +10442,8 @@ F:      Documentation/switchtec.txt
 F:     Documentation/ABI/testing/sysfs-class-switchtec
 F:     drivers/pci/switch/switchtec*
 F:     include/uapi/linux/switchtec_ioctl.h
+F:     include/linux/switchtec.h
+F:     drivers/ntb/hw/mscc/
 
 PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
 M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
@@ -10630,6 +10662,12 @@ S:     Maintained
 F:     crypto/pcrypt.c
 F:     include/crypto/pcrypt.h
 
+PEAQ WMI HOTKEYS DRIVER
+M:     Hans de Goede <hdegoede@redhat.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/peaq-wmi.c
+
 PER-CPU MEMORY ALLOCATOR
 M:     Tejun Heo <tj@kernel.org>
 M:     Christoph Lameter <cl@linux.com>
index adc877dfef5c2c65ff572e864ef2ef19ad5f5f24..38fc5f397fdede04ebaf4f3f9c2e89118ee6b235 100644 (file)
@@ -348,7 +348,6 @@ struct rbd_client_id {
 struct rbd_mapping {
        u64                     size;
        u64                     features;
-       bool                    read_only;
 };
 
 /*
@@ -450,12 +449,11 @@ static DEFINE_IDA(rbd_dev_id_ida);
 static struct workqueue_struct *rbd_wq;
 
 /*
- * Default to false for now, as single-major requires >= 0.75 version of
- * userspace rbd utility.
+ * single-major requires >= 0.75 version of userspace rbd utility.
  */
-static bool single_major = false;
+static bool single_major = true;
 module_param(single_major, bool, S_IRUGO);
-MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: false)");
+MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: true)");
 
 static int rbd_img_request_submit(struct rbd_img_request *img_request);
 
@@ -608,9 +606,6 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
        struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
        bool removing = false;
 
-       if ((mode & FMODE_WRITE) && rbd_dev->mapping.read_only)
-               return -EROFS;
-
        spin_lock_irq(&rbd_dev->lock);
        if (test_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags))
                removing = true;
@@ -640,46 +635,24 @@ static void rbd_release(struct gendisk *disk, fmode_t mode)
 
 static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg)
 {
-       int ret = 0;
-       int val;
-       bool ro;
-       bool ro_changed = false;
+       int ro;
 
-       /* get_user() may sleep, so call it before taking rbd_dev->lock */
-       if (get_user(val, (int __user *)(arg)))
+       if (get_user(ro, (int __user *)arg))
                return -EFAULT;
 
-       ro = val ? true : false;
-       /* Snapshot doesn't allow to write*/
+       /* Snapshots can't be marked read-write */
        if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro)
                return -EROFS;
 
-       spin_lock_irq(&rbd_dev->lock);
-       /* prevent others open this device */
-       if (rbd_dev->open_count > 1) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (rbd_dev->mapping.read_only != ro) {
-               rbd_dev->mapping.read_only = ro;
-               ro_changed = true;
-       }
-
-out:
-       spin_unlock_irq(&rbd_dev->lock);
-       /* set_disk_ro() may sleep, so call it after releasing rbd_dev->lock */
-       if (ret == 0 && ro_changed)
-               set_disk_ro(rbd_dev->disk, ro ? 1 : 0);
-
-       return ret;
+       /* Let blkdev_roset() handle it */
+       return -ENOTTY;
 }
 
 static int rbd_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long arg)
 {
        struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
-       int ret = 0;
+       int ret;
 
        switch (cmd) {
        case BLKROSET:
@@ -4050,15 +4023,8 @@ static void rbd_queue_workfn(struct work_struct *work)
                goto err_rq;
        }
 
-       /* Only reads are allowed to a read-only device */
-
-       if (op_type != OBJ_OP_READ) {
-               if (rbd_dev->mapping.read_only) {
-                       result = -EROFS;
-                       goto err_rq;
-               }
-               rbd_assert(rbd_dev->spec->snap_id == CEPH_NOSNAP);
-       }
+       rbd_assert(op_type == OBJ_OP_READ ||
+                  rbd_dev->spec->snap_id == CEPH_NOSNAP);
 
        /*
         * Quit early if the mapped snapshot no longer exists.  It's
@@ -4423,7 +4389,6 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        /* enable the discard support */
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
        q->limits.discard_granularity = segment_size;
-       q->limits.discard_alignment = segment_size;
        blk_queue_max_discard_sectors(q, segment_size / SECTOR_SIZE);
        blk_queue_max_write_zeroes_sectors(q, segment_size / SECTOR_SIZE);
 
@@ -5994,7 +5959,7 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
                goto err_out_disk;
 
        set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
-       set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only);
+       set_disk_ro(rbd_dev->disk, rbd_dev->opts->read_only);
 
        ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
        if (ret)
@@ -6145,7 +6110,6 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        struct rbd_options *rbd_opts = NULL;
        struct rbd_spec *spec = NULL;
        struct rbd_client *rbdc;
-       bool read_only;
        int rc;
 
        if (!try_module_get(THIS_MODULE))
@@ -6194,11 +6158,8 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        }
 
        /* If we are mapping a snapshot it must be marked read-only */
-
-       read_only = rbd_dev->opts->read_only;
        if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
-               read_only = true;
-       rbd_dev->mapping.read_only = read_only;
+               rbd_dev->opts->read_only = true;
 
        rc = rbd_dev_device_setup(rbd_dev);
        if (rc)
index f5f2b62471da919e4ffd859b8a96ae738d38cea8..859ddab9448fe690a16f2c2d6fad9e243a3ea1ee 100644 (file)
@@ -22,7 +22,7 @@
 #define DRV_NAME "ide-pnp"
 
 /* Add your devices here :)) */
-static struct pnp_device_id idepnp_devices[] = {
+static const struct pnp_device_id idepnp_devices[] = {
        /* Generic ESDI/IDE/ATA compatible hard disk controller */
        {.id = "PNP0600", .driver_data = 0},
        {.id = ""}
index 93faa1fed6f266017415753fbe383227f22e4a96..ea01f24f15e77f4b9765d3bed76ce71527e39dad 100644 (file)
@@ -95,7 +95,7 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
        reg = reg_readl(priv, REG_SPHY_CNTRL);
        if (enable) {
                reg |= PHY_RESET;
-               reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS);
+               reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | IDDQ_GLOBAL_PWR | CK25_DIS);
                reg_writel(priv, reg, REG_SPHY_CNTRL);
                udelay(21);
                reg = reg_readl(priv, REG_SPHY_CNTRL);
index dbd69310f263ea5e4815a020bd1ec8a6113a85e5..538b42d5c1874870f865b7b217a328fb04e2b252 100644 (file)
@@ -1231,7 +1231,7 @@ static bool fm10k_clean_tx_irq(struct fm10k_q_vector *q_vector,
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->flags & FM10K_TXD_FLAG_DONE))
index 5829715fa34222ccfe4cbdb2c9366fa6f379cad2..e019baa905c569de929c5b67bb984d8a600f75dc 100644 (file)
@@ -90,7 +90,6 @@
 #define I40E_AQ_LEN                    256
 #define I40E_AQ_WORK_LIMIT             66 /* max number of VFs + a little */
 #define I40E_MAX_USER_PRIORITY         8
-#define I40E_MAX_QUEUES_PER_CH         64
 #define I40E_DEFAULT_TRAFFIC_CLASS     BIT(0)
 #define I40E_DEFAULT_MSG_ENABLE                4
 #define I40E_QUEUE_WAIT_RETRY_LIMIT    10
index 9dcb2a961197b1f5c8919959d9661c432f03ad13..9af74253c3f7203bb00caac106e99b798f7b658b 100644 (file)
@@ -613,6 +613,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
                hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
        }
 
+       /* Newer versions of firmware require lock when reading the NVM */
+       if (hw->aq.api_maj_ver > 1 ||
+           (hw->aq.api_maj_ver == 1 &&
+            hw->aq.api_min_ver >= 5))
+               hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
+
        /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */
        if (hw->aq.api_maj_ver > 1 ||
            (hw->aq.api_maj_ver == 1 &&
index 0203665cb53c105329fbe56d86b6ea16273b26e3..095965f268bd3508169a631ef5c3b1e88916c48d 100644 (file)
@@ -948,7 +948,8 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw)
                hw->pf_id = (u8)(func_rid & 0x7);
 
        if (hw->mac.type == I40E_MAC_X722)
-               hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE;
+               hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE |
+                            I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
 
        status = i40e_init_nvm(hw);
        return status;
@@ -1268,6 +1269,7 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
         * we don't need to do the PF Reset
         */
        if (!cnt) {
+               u32 reg2 = 0;
                if (hw->revision_id == 0)
                        cnt = I40E_PF_RESET_WAIT_COUNT_A0;
                else
@@ -1279,6 +1281,12 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
                        reg = rd32(hw, I40E_PFGEN_CTRL);
                        if (!(reg & I40E_PFGEN_CTRL_PFSWR_MASK))
                                break;
+                       reg2 = rd32(hw, I40E_GLGEN_RSTAT);
+                       if (reg2 & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
+                               hw_dbg(hw, "Core reset upcoming. Skipping PF reset request.\n");
+                               hw_dbg(hw, "I40E_GLGEN_RSTAT = 0x%x\n", reg2);
+                               return I40E_ERR_NOT_READY;
+                       }
                        usleep_range(1000, 2000);
                }
                if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
index 4a964d6e4a9ebcdb7b55b157bb9b6006a5fd2aa8..4c08cc86463e3608baa2490c775c9e34f96e941c 100644 (file)
@@ -2166,6 +2166,73 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
        return aq_ret;
 }
 
+/**
+ * i40e_set_promiscuous - set promiscuous mode
+ * @pf: board private structure
+ * @promisc: promisc on or off
+ *
+ * There are different ways of setting promiscuous mode on a PF depending on
+ * what state/environment we're in.  This identifies and sets it appropriately.
+ * Returns 0 on success.
+ **/
+static int i40e_set_promiscuous(struct i40e_pf *pf, bool promisc)
+{
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status aq_ret;
+
+       if (vsi->type == I40E_VSI_MAIN &&
+           pf->lan_veb != I40E_NO_VEB &&
+           !(pf->flags & I40E_FLAG_MFP_ENABLED)) {
+               /* set defport ON for Main VSI instead of true promisc
+                * this way we will get all unicast/multicast and VLAN
+                * promisc behavior but will not get VF or VMDq traffic
+                * replicated on the Main VSI.
+                */
+               if (promisc)
+                       aq_ret = i40e_aq_set_default_vsi(hw,
+                                                        vsi->seid,
+                                                        NULL);
+               else
+                       aq_ret = i40e_aq_clear_default_vsi(hw,
+                                                          vsi->seid,
+                                                          NULL);
+               if (aq_ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Set default VSI failed, err %s, aq_err %s\n",
+                                i40e_stat_str(hw, aq_ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+               }
+       } else {
+               aq_ret = i40e_aq_set_vsi_unicast_promiscuous(
+                                                 hw,
+                                                 vsi->seid,
+                                                 promisc, NULL,
+                                                 true);
+               if (aq_ret) {
+                       dev_info(&pf->pdev->dev,
+                                "set unicast promisc failed, err %s, aq_err %s\n",
+                                i40e_stat_str(hw, aq_ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+               }
+               aq_ret = i40e_aq_set_vsi_multicast_promiscuous(
+                                                 hw,
+                                                 vsi->seid,
+                                                 promisc, NULL);
+               if (aq_ret) {
+                       dev_info(&pf->pdev->dev,
+                                "set multicast promisc failed, err %s, aq_err %s\n",
+                                i40e_stat_str(hw, aq_ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+               }
+       }
+
+       if (!aq_ret)
+               pf->cur_promisc = promisc;
+
+       return aq_ret;
+}
+
 /**
  * i40e_sync_vsi_filters - Update the VSI filter list to the HW
  * @vsi: ptr to the VSI
@@ -2467,81 +2534,16 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
                               test_bit(__I40E_VSI_OVERFLOW_PROMISC,
                                        vsi->state));
-               if ((vsi->type == I40E_VSI_MAIN) &&
-                   (pf->lan_veb != I40E_NO_VEB) &&
-                   !(pf->flags & I40E_FLAG_MFP_ENABLED)) {
-                       /* set defport ON for Main VSI instead of true promisc
-                        * this way we will get all unicast/multicast and VLAN
-                        * promisc behavior but will not get VF or VMDq traffic
-                        * replicated on the Main VSI.
-                        */
-                       if (pf->cur_promisc != cur_promisc) {
-                               pf->cur_promisc = cur_promisc;
-                               if (cur_promisc)
-                                       aq_ret =
-                                             i40e_aq_set_default_vsi(hw,
-                                                                     vsi->seid,
-                                                                     NULL);
-                               else
-                                       aq_ret =
-                                           i40e_aq_clear_default_vsi(hw,
-                                                                     vsi->seid,
-                                                                     NULL);
-                               if (aq_ret) {
-                                       retval = i40e_aq_rc_to_posix(aq_ret,
-                                                       hw->aq.asq_last_status);
-                                       dev_info(&pf->pdev->dev,
-                                                "Set default VSI failed on %s, err %s, aq_err %s\n",
-                                                vsi_name,
-                                                i40e_stat_str(hw, aq_ret),
-                                                i40e_aq_str(hw,
-                                                    hw->aq.asq_last_status));
-                               }
-                       }
-               } else {
-                       aq_ret = i40e_aq_set_vsi_unicast_promiscuous(
-                                                         hw,
-                                                         vsi->seid,
-                                                         cur_promisc, NULL,
-                                                         true);
-                       if (aq_ret) {
-                               retval =
-                               i40e_aq_rc_to_posix(aq_ret,
-                                                   hw->aq.asq_last_status);
-                               dev_info(&pf->pdev->dev,
-                                        "set unicast promisc failed on %s, err %s, aq_err %s\n",
-                                        vsi_name,
-                                        i40e_stat_str(hw, aq_ret),
-                                        i40e_aq_str(hw,
-                                                    hw->aq.asq_last_status));
-                       }
-                       aq_ret = i40e_aq_set_vsi_multicast_promiscuous(
-                                                         hw,
-                                                         vsi->seid,
-                                                         cur_promisc, NULL);
-                       if (aq_ret) {
-                               retval =
-                               i40e_aq_rc_to_posix(aq_ret,
-                                                   hw->aq.asq_last_status);
-                               dev_info(&pf->pdev->dev,
-                                        "set multicast promisc failed on %s, err %s, aq_err %s\n",
-                                        vsi_name,
-                                        i40e_stat_str(hw, aq_ret),
-                                        i40e_aq_str(hw,
-                                                    hw->aq.asq_last_status));
-                       }
-               }
-               aq_ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw,
-                                                  vsi->seid,
-                                                  cur_promisc, NULL);
+               aq_ret = i40e_set_promiscuous(pf, cur_promisc);
                if (aq_ret) {
                        retval = i40e_aq_rc_to_posix(aq_ret,
-                                                    pf->hw.aq.asq_last_status);
+                                                    hw->aq.asq_last_status);
                        dev_info(&pf->pdev->dev,
-                                "set brdcast promisc failed, err %s, aq_err %s\n",
-                                        i40e_stat_str(hw, aq_ret),
-                                        i40e_aq_str(hw,
-                                                    hw->aq.asq_last_status));
+                                "Setting promiscuous %s failed on %s, err %s aq_err %s\n",
+                                cur_promisc ? "on" : "off",
+                                vsi_name,
+                                i40e_stat_str(hw, aq_ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
                }
        }
 out:
@@ -3964,7 +3966,7 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget)
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if the descriptor isn't done, no work yet to do */
                if (!(eop_desc->cmd_type_offset_bsz &
@@ -5629,14 +5631,6 @@ static int i40e_validate_num_queues(struct i40e_pf *pf, int num_queues,
                return -EINVAL;
 
        *reconfig_rss = false;
-
-       if (num_queues > I40E_MAX_QUEUES_PER_CH) {
-               dev_err(&pf->pdev->dev,
-                       "Failed to create VMDq VSI. User requested num_queues (%d) > I40E_MAX_QUEUES_PER_VSI (%u)\n",
-                       num_queues, I40E_MAX_QUEUES_PER_CH);
-               return -EINVAL;
-       }
-
        if (vsi->current_rss_size) {
                if (num_queues > vsi->current_rss_size) {
                        dev_dbg(&pf->pdev->dev,
@@ -9429,6 +9423,15 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
        if (!lock_acquired)
                rtnl_unlock();
 
+       /* Restore promiscuous settings */
+       ret = i40e_set_promiscuous(pf, pf->cur_promisc);
+       if (ret)
+               dev_warn(&pf->pdev->dev,
+                        "Failed to restore promiscuous setting: %s, err %s aq_err %s\n",
+                        pf->cur_promisc ? "on" : "off",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+
        i40e_reset_all_vfs(pf, true);
 
        /* tell the firmware that we're starting */
index 0ccab0a5d717564d5773fb303d7c7f04ddcc0809..7689c2ee0d463650a4c4757c1210751767cad1aa 100644 (file)
@@ -328,15 +328,17 @@ static i40e_status __i40e_read_nvm_word(struct i40e_hw *hw,
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                               u16 *data)
 {
-       i40e_status ret_code;
+       i40e_status ret_code = 0;
 
-       ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
+               ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
        if (ret_code)
                return ret_code;
 
        ret_code = __i40e_read_nvm_word(hw, offset, data);
 
-       i40e_release_nvm(hw);
+       if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
+               i40e_release_nvm(hw);
 
        return ret_code;
 }
index d6d352a6e6ead2ad7f228d7906a24337ad023f76..4566d66ffc7c95a72c4135075a19d5ac8bcd2689 100644 (file)
@@ -759,7 +759,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf);
                /* we have caught up to head, no work left to do */
index 00d4833e992515b026c87c6dcf9dad91b1f84a46..0e8568719b4e65f924ead244da35b7e4a6a07b1e 100644 (file)
@@ -629,6 +629,7 @@ struct i40e_hw {
 #define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0)
 #define I40E_HW_FLAG_802_1AD_CAPABLE        BIT_ULL(1)
 #define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
+#define I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK BIT_ULL(3)
        u64 flags;
 
        /* Used in set switch config AQ command */
index f8a794b72462873d2942dcaddac36ddad9db66e8..a3dc9b93294651064eabcadd469763bd3f93f1cc 100644 (file)
@@ -2218,18 +2218,19 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
                struct i40e_mac_filter *f;
 
                f = i40e_find_mac(vsi, al->list[i].addr);
-               if (!f)
+               if (!f) {
                        f = i40e_add_mac_filter(vsi, al->list[i].addr);
 
-               if (!f) {
-                       dev_err(&pf->pdev->dev,
-                               "Unable to add MAC filter %pM for VF %d\n",
-                                al->list[i].addr, vf->vf_id);
-                       ret = I40E_ERR_PARAM;
-                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-                       goto error_param;
-               } else {
-                       vf->num_mac++;
+                       if (!f) {
+                               dev_err(&pf->pdev->dev,
+                                       "Unable to add MAC filter %pM for VF %d\n",
+                                       al->list[i].addr, vf->vf_id);
+                               ret = I40E_ERR_PARAM;
+                               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                               goto error_param;
+                       } else {
+                               vf->num_mac++;
+                       }
                }
        }
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
index fe817e2b6fef4468e2ed33a50de7190b08f3c282..50864f99446d3a9f22c83c984eaec4f25caa6015 100644 (file)
@@ -179,7 +179,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf);
                /* if the descriptor isn't done, no work yet to do */
index d8131139565ea0ae48c628d1b7219d35bacd3a7f..da60ce12b33d31660c6c00c0425b6ce5919dadd2 100644 (file)
@@ -25,6 +25,26 @@ static struct i40e_ops i40evf_lan_ops = {
        .setup_qvlist = i40evf_client_setup_qvlist,
 };
 
+/**
+ * i40evf_client_get_params - retrieve relevant client parameters
+ * @vsi: VSI with parameters
+ * @params: client param struct
+ **/
+static
+void i40evf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
+{
+       int i;
+
+       memset(params, 0, sizeof(struct i40e_params));
+       params->mtu = vsi->netdev->mtu;
+       params->link_up = vsi->back->link_up;
+
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+               params->qos.prio_qos[i].tc = 0;
+               params->qos.prio_qos[i].qs_handle = vsi->qs_handle;
+       }
+}
+
 /**
  * i40evf_notify_client_message - call the client message receive callback
  * @vsi: the VSI associated with this client
@@ -66,10 +86,6 @@ void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
                return;
 
        cinst = vsi->back->cinst;
-       memset(&params, 0, sizeof(params));
-       params.mtu = vsi->netdev->mtu;
-       params.link_up = vsi->back->link_up;
-       params.qos.prio_qos[0].qs_handle = vsi->qs_handle;
 
        if (!cinst || !cinst->client || !cinst->client->ops ||
            !cinst->client->ops->l2_param_change) {
@@ -77,6 +93,8 @@ void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
                        "Cannot locate client instance l2_param_change function\n");
                return;
        }
+       i40evf_client_get_params(vsi, &params);
+       cinst->lan_info.params = params;
        cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client,
                                            &params);
 }
@@ -166,9 +184,9 @@ static struct i40e_client_instance *
 i40evf_client_add_instance(struct i40evf_adapter *adapter)
 {
        struct i40e_client_instance *cinst = NULL;
-       struct netdev_hw_addr *mac = NULL;
        struct i40e_vsi *vsi = &adapter->vsi;
-       int i;
+       struct netdev_hw_addr *mac = NULL;
+       struct i40e_params params;
 
        if (!vf_registered_client)
                goto out;
@@ -192,18 +210,14 @@ i40evf_client_add_instance(struct i40evf_adapter *adapter)
        cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR;
        cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR;
        cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD;
+       i40evf_client_get_params(vsi, &params);
+       cinst->lan_info.params = params;
        set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
 
        cinst->lan_info.msix_count = adapter->num_iwarp_msix;
        cinst->lan_info.msix_entries =
                        &adapter->msix_entries[adapter->iwarp_base_vector];
 
-       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-               cinst->lan_info.params.qos.prio_qos[i].tc = 0;
-               cinst->lan_info.params.qos.prio_qos[i].qs_handle =
-                                                               vsi->qs_handle;
-       }
-
        mac = list_first_entry(&cinst->lan_info.netdev->dev_addrs.list,
                               struct netdev_hw_addr, list);
        if (mac)
index ca2ebdbd24d7c9ce832af711942671ac622d4a15..7b2a4eba92e23b7f5757d813219edcca1f69426a 100644 (file)
@@ -2110,6 +2110,11 @@ static void i40evf_client_task(struct work_struct *work)
                adapter->flags &= ~I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
                goto out;
        }
+       if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) {
+               i40evf_notify_client_l2_params(&adapter->vsi);
+               adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS;
+               goto out;
+       }
        if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_CLOSE) {
                i40evf_notify_client_close(&adapter->vsi, false);
                adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_CLOSE;
@@ -2118,11 +2123,6 @@ static void i40evf_client_task(struct work_struct *work)
        if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_OPEN) {
                i40evf_notify_client_open(&adapter->vsi);
                adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_OPEN;
-               goto out;
-       }
-       if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) {
-               i40evf_notify_client_l2_params(&adapter->vsi);
-               adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS;
        }
 out:
        clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
index e94d3c256667637c8186fd83299b64ea2de53c72..c208753ff5b7cec52259e15b5c545b5af4b51c6f 100644 (file)
@@ -7317,7 +7317,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector, int napi_budget)
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
index 713e8df23744a46ea30824a014f875bd28d29fc5..4214c1519a879c9cb70cd1791b361657a5615d1e 100644 (file)
@@ -810,7 +810,7 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring)
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
index ca06c3cc2ca841fc395c957efe64cf717b36670f..62a18914f00f4fe1f608b208da86ddf616c752e1 100644 (file)
@@ -1192,7 +1192,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
index feed11bc9ddffdf7b779abab19a7e3e678909ecd..1f4a69134adeb58a14d13998e3be39feba5134f0 100644 (file)
@@ -326,7 +326,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               read_barrier_depends();
+               smp_rmb();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
index 2d46ec84ebdffbea5032a1f670befab4f585b22c..2d0897b7d86035286666e38ad4e41ab63fb4746b 100644 (file)
@@ -3142,13 +3142,17 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
        if (!mlxsw_sp->ports)
                return -ENOMEM;
 
-       mlxsw_sp->port_to_module = kcalloc(max_ports, sizeof(u8), GFP_KERNEL);
+       mlxsw_sp->port_to_module = kmalloc_array(max_ports, sizeof(int),
+                                                GFP_KERNEL);
        if (!mlxsw_sp->port_to_module) {
                err = -ENOMEM;
                goto err_port_to_module_alloc;
        }
 
        for (i = 1; i < max_ports; i++) {
+               /* Mark as invalid */
+               mlxsw_sp->port_to_module[i] = -1;
+
                err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &module,
                                                    &width, &lane);
                if (err)
@@ -3216,6 +3220,8 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
 
        for (i = 0; i < count; i++) {
                local_port = base_port + i * 2;
+               if (mlxsw_sp->port_to_module[local_port] < 0)
+                       continue;
                module = mlxsw_sp->port_to_module[local_port];
 
                mlxsw_sp_port_create(mlxsw_sp, local_port, false, module,
index 58cf222fb98576426a9dd654a31d7f033a11daa4..432ab9b12b7f59ded586a663f0a686741740463d 100644 (file)
@@ -152,7 +152,7 @@ struct mlxsw_sp {
        const struct mlxsw_bus_info *bus_info;
        unsigned char base_mac[ETH_ALEN];
        struct mlxsw_sp_upper *lags;
-       u8 *port_to_module;
+       int *port_to_module;
        struct mlxsw_sp_sb *sb;
        struct mlxsw_sp_bridge *bridge;
        struct mlxsw_sp_router *router;
index b6cee71f49d3d4a0b68afeda4d879f2cd12de5f6..bc879aeb62d4ee95a42654a78ae9329145d22b3f 100644 (file)
@@ -214,8 +214,14 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog,
 {
        int err;
 
-       if (prog && !prog->aux->offload)
-               return -EINVAL;
+       if (prog) {
+               struct bpf_dev_offload *offload = prog->aux->offload;
+
+               if (!offload)
+                       return -EINVAL;
+               if (offload->netdev != nn->dp.netdev)
+                       return -EINVAL;
+       }
 
        if (prog && old_prog) {
                u8 cap;
index f5d73b83dcc2132e80bc400b77cde31b4fe30897..553f94f55dce64ba9cdb661ff9bdb04faf41acac 100644 (file)
@@ -315,6 +315,7 @@ err_free_flow:
  * @app:       Pointer to the APP handle
  * @netdev:    netdev structure.
  * @flow:      TC flower classifier offload structure.
+ * @egress:    NFP netdev is the egress.
  *
  * Adds a new flow to the repeated hash structure and action payload.
  *
index 2cb3622c4acc93ad669f1f09b92e816e4d86a095..fc0d5fa65ad4c1ca02073e2d1d1554df68443e86 100644 (file)
@@ -2030,21 +2030,6 @@ out:
        return ret;
 }
 
-static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct rtl8169_private *tp = netdev_priv(dev);
-       int ret;
-
-       del_timer_sync(&tp->timer);
-
-       rtl_lock_work(tp);
-       ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
-                               cmd->duplex, cmd->advertising);
-       rtl_unlock_work(tp);
-
-       return ret;
-}
-
 static netdev_features_t rtl8169_fix_features(struct net_device *dev,
        netdev_features_t features)
 {
@@ -2171,6 +2156,27 @@ static int rtl8169_get_link_ksettings(struct net_device *dev,
        return rc;
 }
 
+static int rtl8169_set_link_ksettings(struct net_device *dev,
+                                     const struct ethtool_link_ksettings *cmd)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       int rc;
+       u32 advertising;
+
+       if (!ethtool_convert_link_mode_to_legacy_u32(&advertising,
+           cmd->link_modes.advertising))
+               return -EINVAL;
+
+       del_timer_sync(&tp->timer);
+
+       rtl_lock_work(tp);
+       rc = rtl8169_set_speed(dev, cmd->base.autoneg, cmd->base.speed,
+                              cmd->base.duplex, advertising);
+       rtl_unlock_work(tp);
+
+       return rc;
+}
+
 static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
                             void *p)
 {
@@ -2591,7 +2597,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_coalesce           = rtl_get_coalesce,
        .set_coalesce           = rtl_set_coalesce,
-       .set_settings           = rtl8169_set_settings,
        .get_msglevel           = rtl8169_get_msglevel,
        .set_msglevel           = rtl8169_set_msglevel,
        .get_regs               = rtl8169_get_regs,
@@ -2603,6 +2608,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
        .get_ts_info            = ethtool_op_get_ts_info,
        .nway_reset             = rtl8169_nway_reset,
        .get_link_ksettings     = rtl8169_get_link_ksettings,
+       .set_link_ksettings     = rtl8169_set_link_ksettings,
 };
 
 static void rtl8169_get_mac_version(struct rtl8169_private *tp,
index 72f4228a63bb0a9fb0f3baa993fa85fc8ad6f823..9442db2218348713e87faf91ccc25f4a8444526a 100644 (file)
@@ -116,3 +116,7 @@ static struct mdio_device_id __maybe_unused cortina_tbl[] = {
 };
 
 MODULE_DEVICE_TABLE(mdio, cortina_tbl);
+
+MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver");
+MODULE_AUTHOR("NXP");
+MODULE_LICENSE("GPL");
index b13890953ebb92515b3924f511714942a912b120..e9489b88407ce1677385fe480592958b57d02c8d 100644 (file)
@@ -1077,7 +1077,7 @@ static long tap_ioctl(struct file *file, unsigned int cmd,
        case TUNSETOFFLOAD:
                /* let the user check for future flags */
                if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
-                           TUN_F_TSO_ECN))
+                           TUN_F_TSO_ECN | TUN_F_UFO))
                        return -EINVAL;
 
                rtnl_lock();
index 5a2ea78a008f9d22440452e014ca5f4a1dd5968a..6a7bde9bc4b292e349dd92830de494185f7fdc39 100644 (file)
@@ -2370,6 +2370,8 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
                                features |= NETIF_F_TSO6;
                        arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
                }
+
+               arg &= ~TUN_F_UFO;
        }
 
        /* This gives the user a way to test for new features in future by
index 720a3a248070ccd9db305d3c26349392448f0027..c750cf7c042b004ecfbbce64aefb3d0f1d512c82 100644 (file)
@@ -1239,6 +1239,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},    /* SIMCom 7230E */
        {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0  Mini PCIe */
        {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */
+       {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},    /* Quectel BG96 */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 7c3600643c7fdb540e71696e928acedaee3ccccf..10b075a46b266218c53d1e5674c1789e1e0f3d80 100644 (file)
@@ -3108,6 +3108,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
        struct hwsim_new_radio_params param = { 0 };
        const char *hwname = NULL;
+       int ret;
 
        param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
        param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
@@ -3147,7 +3148,9 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
                param.regd = hwsim_world_regdom_custom[idx];
        }
 
-       return mac80211_hwsim_new_radio(info, &param);
+       ret = mac80211_hwsim_new_radio(info, &param);
+       kfree(hwname);
+       return ret;
 }
 
 static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
index a89243c9fdd33acf6a583b0004513bbf45474001..e51b581fd102e8db1f0b0a0ed597f789a4ba9929 100644 (file)
@@ -1,3 +1,4 @@
 source "drivers/ntb/hw/amd/Kconfig"
 source "drivers/ntb/hw/idt/Kconfig"
 source "drivers/ntb/hw/intel/Kconfig"
+source "drivers/ntb/hw/mscc/Kconfig"
index 87332c3905f075dedd86ae7b86ea6ffd5dcb8d23..923c442db750a16caa3e1bad74cc168ecb9fcfc0 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_NTB_AMD)  += amd/
 obj-$(CONFIG_NTB_IDT)  += idt/
 obj-$(CONFIG_NTB_INTEL)        += intel/
+obj-$(CONFIG_NTB_SWITCHTEC) += mscc/
index d44d7ef38fe88fef82b7ff5420e117cd73d43edd..0cd79f367f7cc51d962679a236cfe56beec66ff9 100644 (file)
@@ -2628,35 +2628,35 @@ static void idt_pci_remove(struct pci_dev *pdev)
 /*
  * IDT PCIe-switch models ports configuration structures
  */
-static struct idt_89hpes_cfg idt_89hpes24nt6ag2_config = {
+static const struct idt_89hpes_cfg idt_89hpes24nt6ag2_config = {
        .name = "89HPES24NT6AG2",
        .port_cnt = 6, .ports = {0, 2, 4, 6, 8, 12}
 };
-static struct idt_89hpes_cfg idt_89hpes32nt8ag2_config = {
+static const struct idt_89hpes_cfg idt_89hpes32nt8ag2_config = {
        .name = "89HPES32NT8AG2",
        .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
 };
-static struct idt_89hpes_cfg idt_89hpes32nt8bg2_config = {
+static const struct idt_89hpes_cfg idt_89hpes32nt8bg2_config = {
        .name = "89HPES32NT8BG2",
        .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
 };
-static struct idt_89hpes_cfg idt_89hpes12nt12g2_config = {
+static const struct idt_89hpes_cfg idt_89hpes12nt12g2_config = {
        .name = "89HPES12NT12G2",
        .port_cnt = 3, .ports = {0, 8, 16}
 };
-static struct idt_89hpes_cfg idt_89hpes16nt16g2_config = {
+static const struct idt_89hpes_cfg idt_89hpes16nt16g2_config = {
        .name = "89HPES16NT16G2",
        .port_cnt = 4, .ports = {0, 8, 12, 16}
 };
-static struct idt_89hpes_cfg idt_89hpes24nt24g2_config = {
+static const struct idt_89hpes_cfg idt_89hpes24nt24g2_config = {
        .name = "89HPES24NT24G2",
        .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
 };
-static struct idt_89hpes_cfg idt_89hpes32nt24ag2_config = {
+static const struct idt_89hpes_cfg idt_89hpes32nt24ag2_config = {
        .name = "89HPES32NT24AG2",
        .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
 };
-static struct idt_89hpes_cfg idt_89hpes32nt24bg2_config = {
+static const struct idt_89hpes_cfg idt_89hpes32nt24bg2_config = {
        .name = "89HPES32NT24BG2",
        .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
 };
index 2557e2c05b90c8ca770d176f0cde26162b9a2df5..4de074a86073604abc59353fb509c55f5ef0b4cf 100644 (file)
@@ -1742,89 +1742,18 @@ static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
 {
        struct pci_dev *pdev;
        void __iomem *mmio;
-       resource_size_t bar_size;
        phys_addr_t bar_addr;
-       int b2b_bar;
-       u8 bar_sz;
 
        pdev = ndev->ntb.pdev;
        mmio = ndev->self_mmio;
 
-       if (ndev->b2b_idx == UINT_MAX) {
-               dev_dbg(&pdev->dev, "not using b2b mw\n");
-               b2b_bar = 0;
-               ndev->b2b_off = 0;
-       } else {
-               b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx);
-               if (b2b_bar < 0)
-                       return -EIO;
-
-               dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar);
-
-               bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
-
-               dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size);
-
-               if (b2b_mw_share && ((bar_size >> 1) >= XEON_B2B_MIN_SIZE)) {
-                       dev_dbg(&pdev->dev, "b2b using first half of bar\n");
-                       ndev->b2b_off = bar_size >> 1;
-               } else if (bar_size >= XEON_B2B_MIN_SIZE) {
-                       dev_dbg(&pdev->dev, "b2b using whole bar\n");
-                       ndev->b2b_off = 0;
-                       --ndev->mw_count;
-               } else {
-                       dev_dbg(&pdev->dev, "b2b bar size is too small\n");
-                       return -EIO;
-               }
-       }
-
-       /*
-        * Reset the secondary bar sizes to match the primary bar sizes,
-        * except disable or halve the size of the b2b secondary bar.
-        */
-       pci_read_config_byte(pdev, SKX_IMBAR1SZ_OFFSET, &bar_sz);
-       dev_dbg(&pdev->dev, "IMBAR1SZ %#x\n", bar_sz);
-       if (b2b_bar == 1) {
-               if (ndev->b2b_off)
-                       bar_sz -= 1;
-               else
-                       bar_sz = 0;
-       }
-
-       pci_write_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, bar_sz);
-       pci_read_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, &bar_sz);
-       dev_dbg(&pdev->dev, "EMBAR1SZ %#x\n", bar_sz);
-
-       pci_read_config_byte(pdev, SKX_IMBAR2SZ_OFFSET, &bar_sz);
-       dev_dbg(&pdev->dev, "IMBAR2SZ %#x\n", bar_sz);
-       if (b2b_bar == 2) {
-               if (ndev->b2b_off)
-                       bar_sz -= 1;
-               else
-                       bar_sz = 0;
-       }
-
-       pci_write_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, bar_sz);
-       pci_read_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, &bar_sz);
-       dev_dbg(&pdev->dev, "EMBAR2SZ %#x\n", bar_sz);
-
-       /* SBAR01 hit by first part of the b2b bar */
-       if (b2b_bar == 0)
-               bar_addr = addr->bar0_addr;
-       else if (b2b_bar == 1)
-               bar_addr = addr->bar2_addr64;
-       else if (b2b_bar == 2)
-               bar_addr = addr->bar4_addr64;
-       else
-               return -EIO;
-
        /* setup incoming bar limits == base addrs (zero length windows) */
-       bar_addr = addr->bar2_addr64 + (b2b_bar == 1 ? ndev->b2b_off : 0);
+       bar_addr = addr->bar2_addr64;
        iowrite64(bar_addr, mmio + SKX_IMBAR1XLMT_OFFSET);
        bar_addr = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET);
        dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr);
 
-       bar_addr = addr->bar4_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
+       bar_addr = addr->bar4_addr64;
        iowrite64(bar_addr, mmio + SKX_IMBAR2XLMT_OFFSET);
        bar_addr = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET);
        dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr);
diff --git a/drivers/ntb/hw/mscc/Kconfig b/drivers/ntb/hw/mscc/Kconfig
new file mode 100644 (file)
index 0000000..013ed67
--- /dev/null
@@ -0,0 +1,9 @@
+config NTB_SWITCHTEC
+       tristate "MicroSemi Switchtec Non-Transparent Bridge Support"
+       select PCI_SW_SWITCHTEC
+       help
+        Enables NTB support for Switchtec PCI switches. This also
+        selects the Switchtec management driver as they share the same
+        hardware interface.
+
+        If unsure, say N.
diff --git a/drivers/ntb/hw/mscc/Makefile b/drivers/ntb/hw/mscc/Makefile
new file mode 100644 (file)
index 0000000..064686e
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_NTB_SWITCHTEC) += ntb_hw_switchtec.o
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
new file mode 100644 (file)
index 0000000..afe8ed6
--- /dev/null
@@ -0,0 +1,1216 @@
+/*
+ * Microsemi Switchtec(tm) PCIe Management Driver
+ * Copyright (c) 2017, Microsemi Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/switchtec.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/ntb.h>
+
+MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Microsemi Corporation");
+
+static ulong max_mw_size = SZ_2M;
+module_param(max_mw_size, ulong, 0644);
+MODULE_PARM_DESC(max_mw_size,
+       "Max memory window size reported to the upper layer");
+
+static bool use_lut_mws;
+module_param(use_lut_mws, bool, 0644);
+MODULE_PARM_DESC(use_lut_mws,
+                "Enable the use of the LUT based memory windows");
+
+#ifndef ioread64
+#ifdef readq
+#define ioread64 readq
+#else
+#define ioread64 _ioread64
+static inline u64 _ioread64(void __iomem *mmio)
+{
+       u64 low, high;
+
+       low = ioread32(mmio);
+       high = ioread32(mmio + sizeof(u32));
+       return low | (high << 32);
+}
+#endif
+#endif
+
+#ifndef iowrite64
+#ifdef writeq
+#define iowrite64 writeq
+#else
+#define iowrite64 _iowrite64
+static inline void _iowrite64(u64 val, void __iomem *mmio)
+{
+       iowrite32(val, mmio);
+       iowrite32(val >> 32, mmio + sizeof(u32));
+}
+#endif
+#endif
+
+#define SWITCHTEC_NTB_MAGIC 0x45CC0001
+#define MAX_MWS     128
+
+struct shared_mw {
+       u32 magic;
+       u32 link_sta;
+       u32 partition_id;
+       u64 mw_sizes[MAX_MWS];
+       u32 spad[128];
+};
+
+#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry)
+#define LUT_SIZE SZ_64K
+
+struct switchtec_ntb {
+       struct ntb_dev ntb;
+       struct switchtec_dev *stdev;
+
+       int self_partition;
+       int peer_partition;
+
+       int doorbell_irq;
+       int message_irq;
+
+       struct ntb_info_regs __iomem *mmio_ntb;
+       struct ntb_ctrl_regs __iomem *mmio_ctrl;
+       struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
+       struct ntb_ctrl_regs __iomem *mmio_self_ctrl;
+       struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
+       struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg;
+
+       struct shared_mw *self_shared;
+       struct shared_mw __iomem *peer_shared;
+       dma_addr_t self_shared_dma;
+
+       u64 db_mask;
+       u64 db_valid_mask;
+       int db_shift;
+       int db_peer_shift;
+
+       /* synchronize rmw access of db_mask and hw reg */
+       spinlock_t db_mask_lock;
+
+       int nr_direct_mw;
+       int nr_lut_mw;
+       int direct_mw_to_bar[MAX_DIRECT_MW];
+
+       int peer_nr_direct_mw;
+       int peer_nr_lut_mw;
+       int peer_direct_mw_to_bar[MAX_DIRECT_MW];
+
+       bool link_is_up;
+       enum ntb_speed link_speed;
+       enum ntb_width link_width;
+};
+
+static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
+{
+       return container_of(ntb, struct switchtec_ntb, ntb);
+}
+
+static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
+                                struct ntb_ctrl_regs __iomem *ctl,
+                                u32 op, int wait_status)
+{
+       static const char * const op_text[] = {
+               [NTB_CTRL_PART_OP_LOCK] = "lock",
+               [NTB_CTRL_PART_OP_CFG] = "configure",
+               [NTB_CTRL_PART_OP_RESET] = "reset",
+       };
+
+       int i;
+       u32 ps;
+       int status;
+
+       switch (op) {
+       case NTB_CTRL_PART_OP_LOCK:
+               status = NTB_CTRL_PART_STATUS_LOCKING;
+               break;
+       case NTB_CTRL_PART_OP_CFG:
+               status = NTB_CTRL_PART_STATUS_CONFIGURING;
+               break;
+       case NTB_CTRL_PART_OP_RESET:
+               status = NTB_CTRL_PART_STATUS_RESETTING;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       iowrite32(op, &ctl->partition_op);
+
+       for (i = 0; i < 1000; i++) {
+               if (msleep_interruptible(50) != 0) {
+                       iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op);
+                       return -EINTR;
+               }
+
+               ps = ioread32(&ctl->partition_status) & 0xFFFF;
+
+               if (ps != status)
+                       break;
+       }
+
+       if (ps == wait_status)
+               return 0;
+
+       if (ps == status) {
+               dev_err(&sndev->stdev->dev,
+                       "Timed out while peforming %s (%d). (%08x)",
+                       op_text[op], op,
+                       ioread32(&ctl->partition_status));
+
+               return -ETIMEDOUT;
+       }
+
+       return -EIO;
+}
+
+static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx,
+                                 u32 val)
+{
+       if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg))
+               return -EINVAL;
+
+       iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg);
+
+       return 0;
+}
+
+static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+       int nr_direct_mw = sndev->peer_nr_direct_mw;
+       int nr_lut_mw = sndev->peer_nr_lut_mw - 1;
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       if (!use_lut_mws)
+               nr_lut_mw = 0;
+
+       return nr_direct_mw + nr_lut_mw;
+}
+
+static int lut_index(struct switchtec_ntb *sndev, int mw_idx)
+{
+       return mw_idx - sndev->nr_direct_mw + 1;
+}
+
+static int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx)
+{
+       return mw_idx - sndev->peer_nr_direct_mw + 1;
+}
+
+static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx,
+                                     int widx, resource_size_t *addr_align,
+                                     resource_size_t *size_align,
+                                     resource_size_t *size_max)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+       int lut;
+       resource_size_t size;
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       lut = widx >= sndev->peer_nr_direct_mw;
+       size = ioread64(&sndev->peer_shared->mw_sizes[widx]);
+
+       if (size == 0)
+               return -EINVAL;
+
+       if (addr_align)
+               *addr_align = lut ? size : SZ_4K;
+
+       if (size_align)
+               *size_align = lut ? size : SZ_4K;
+
+       if (size_max)
+               *size_max = size;
+
+       return 0;
+}
+
+static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx)
+{
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+       int bar = sndev->peer_direct_mw_to_bar[idx];
+       u32 ctl_val;
+
+       ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
+       ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN;
+       iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
+       iowrite32(0, &ctl->bar_entry[bar].win_size);
+       iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr);
+}
+
+static void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx)
+{
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+
+       iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]);
+}
+
+static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx,
+                                       dma_addr_t addr, resource_size_t size)
+{
+       int xlate_pos = ilog2(size);
+       int bar = sndev->peer_direct_mw_to_bar[idx];
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+       u32 ctl_val;
+
+       ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
+       ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN;
+
+       iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
+       iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size);
+       iowrite64(sndev->self_partition | addr,
+                 &ctl->bar_entry[bar].xlate_addr);
+}
+
+static void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx,
+                                    dma_addr_t addr, resource_size_t size)
+{
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+
+       iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr),
+                 &ctl->lut_entry[peer_lut_index(sndev, idx)]);
+}
+
+static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
+                                     dma_addr_t addr, resource_size_t size)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+       int xlate_pos = ilog2(size);
+       int nr_direct_mw = sndev->peer_nr_direct_mw;
+       int rc;
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap",
+               widx, pidx, &addr, &size);
+
+       if (widx >= switchtec_ntb_mw_count(ntb, pidx))
+               return -EINVAL;
+
+       if (xlate_pos < 12)
+               return -EINVAL;
+
+       rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
+                                  NTB_CTRL_PART_STATUS_LOCKED);
+       if (rc)
+               return rc;
+
+       if (addr == 0 || size == 0) {
+               if (widx < nr_direct_mw)
+                       switchtec_ntb_mw_clr_direct(sndev, widx);
+               else
+                       switchtec_ntb_mw_clr_lut(sndev, widx);
+       } else {
+               if (widx < nr_direct_mw)
+                       switchtec_ntb_mw_set_direct(sndev, widx, addr, size);
+               else
+                       switchtec_ntb_mw_set_lut(sndev, widx, addr, size);
+       }
+
+       rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
+                                  NTB_CTRL_PART_STATUS_NORMAL);
+
+       if (rc == -EIO) {
+               dev_err(&sndev->stdev->dev,
+                       "Hardware reported an error configuring mw %d: %08x",
+                       widx, ioread32(&ctl->bar_error));
+
+               if (widx < nr_direct_mw)
+                       switchtec_ntb_mw_clr_direct(sndev, widx);
+               else
+                       switchtec_ntb_mw_clr_lut(sndev, widx);
+
+               switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
+                                     NTB_CTRL_PART_STATUS_NORMAL);
+       }
+
+       return rc;
+}
+
+static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       return sndev->nr_direct_mw + (use_lut_mws ? sndev->nr_lut_mw - 1 : 0);
+}
+
+static int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev,
+                                        int idx, phys_addr_t *base,
+                                        resource_size_t *size)
+{
+       int bar = sndev->direct_mw_to_bar[idx];
+       size_t offset = 0;
+
+       if (bar < 0)
+               return -EINVAL;
+
+       if (idx == 0) {
+               /*
+                * This is the direct BAR shared with the LUTs
+                * which means the actual window will be offset
+                * by the size of all the LUT entries.
+                */
+
+               offset = LUT_SIZE * sndev->nr_lut_mw;
+       }
+
+       if (base)
+               *base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
+
+       if (size) {
+               *size = pci_resource_len(sndev->ntb.pdev, bar) - offset;
+               if (offset && *size > offset)
+                       *size = offset;
+
+               if (*size > max_mw_size)
+                       *size = max_mw_size;
+       }
+
+       return 0;
+}
+
+static int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev,
+                                     int idx, phys_addr_t *base,
+                                     resource_size_t *size)
+{
+       int bar = sndev->direct_mw_to_bar[0];
+       int offset;
+
+       offset = LUT_SIZE * lut_index(sndev, idx);
+
+       if (base)
+               *base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
+
+       if (size)
+               *size = LUT_SIZE;
+
+       return 0;
+}
+
+static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+                                         phys_addr_t *base,
+                                         resource_size_t *size)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (idx < sndev->nr_direct_mw)
+               return switchtec_ntb_direct_get_addr(sndev, idx, base, size);
+       else if (idx < switchtec_ntb_peer_mw_count(ntb))
+               return switchtec_ntb_lut_get_addr(sndev, idx, base, size);
+       else
+               return -EINVAL;
+}
+
+static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,
+                                         int partition,
+                                         enum ntb_speed *speed,
+                                         enum ntb_width *width)
+{
+       struct switchtec_dev *stdev = sndev->stdev;
+
+       u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id);
+       u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);
+
+       if (speed)
+               *speed = (linksta >> 16) & 0xF;
+
+       if (width)
+               *width = (linksta >> 20) & 0x3F;
+}
+
+static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev)
+{
+       enum ntb_speed self_speed, peer_speed;
+       enum ntb_width self_width, peer_width;
+
+       if (!sndev->link_is_up) {
+               sndev->link_speed = NTB_SPEED_NONE;
+               sndev->link_width = NTB_WIDTH_NONE;
+               return;
+       }
+
+       switchtec_ntb_part_link_speed(sndev, sndev->self_partition,
+                                     &self_speed, &self_width);
+       switchtec_ntb_part_link_speed(sndev, sndev->peer_partition,
+                                     &peer_speed, &peer_width);
+
+       sndev->link_speed = min(self_speed, peer_speed);
+       sndev->link_width = min(self_width, peer_width);
+}
+
+enum {
+       LINK_MESSAGE = 0,
+       MSG_LINK_UP = 1,
+       MSG_LINK_DOWN = 2,
+       MSG_CHECK_LINK = 3,
+};
+
+static void switchtec_ntb_check_link(struct switchtec_ntb *sndev)
+{
+       int link_sta;
+       int old = sndev->link_is_up;
+
+       link_sta = sndev->self_shared->link_sta;
+       if (link_sta) {
+               u64 peer = ioread64(&sndev->peer_shared->magic);
+
+               if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC)
+                       link_sta = peer >> 32;
+               else
+                       link_sta = 0;
+       }
+
+       sndev->link_is_up = link_sta;
+       switchtec_ntb_set_link_speed(sndev);
+
+       if (link_sta != old) {
+               switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK);
+               ntb_link_event(&sndev->ntb);
+               dev_info(&sndev->stdev->dev, "ntb link %s",
+                        link_sta ? "up" : "down");
+       }
+}
+
+static void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
+{
+       struct switchtec_ntb *sndev = stdev->sndev;
+
+       switchtec_ntb_check_link(sndev);
+}
+
+static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb,
+                                   enum ntb_speed *speed,
+                                   enum ntb_width *width)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (speed)
+               *speed = sndev->link_speed;
+       if (width)
+               *width = sndev->link_width;
+
+       return sndev->link_is_up;
+}
+
+static int switchtec_ntb_link_enable(struct ntb_dev *ntb,
+                                    enum ntb_speed max_speed,
+                                    enum ntb_width max_width)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       dev_dbg(&sndev->stdev->dev, "enabling link");
+
+       sndev->self_shared->link_sta = 1;
+       switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
+
+       switchtec_ntb_check_link(sndev);
+
+       return 0;
+}
+
+static int switchtec_ntb_link_disable(struct ntb_dev *ntb)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       dev_dbg(&sndev->stdev->dev, "disabling link");
+
+       sndev->self_shared->link_sta = 0;
+       switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
+
+       switchtec_ntb_check_link(sndev);
+
+       return 0;
+}
+
+static u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       return sndev->db_valid_mask;
+}
+
+static int switchtec_ntb_db_vector_count(struct ntb_dev *ntb)
+{
+       return 1;
+}
+
+static u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (db_vector < 0 || db_vector > 1)
+               return 0;
+
+       return sndev->db_valid_mask;
+}
+
+static u64 switchtec_ntb_db_read(struct ntb_dev *ntb)
+{
+       u64 ret;
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift;
+
+       return ret & sndev->db_valid_mask;
+}
+
+static int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb);
+
+       return 0;
+}
+
+static int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+       unsigned long irqflags;
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (db_bits & ~sndev->db_valid_mask)
+               return -EINVAL;
+
+       spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
+
+       sndev->db_mask |= db_bits << sndev->db_shift;
+       iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
+
+       spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
+
+       return 0;
+}
+
+static int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+       unsigned long irqflags;
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (db_bits & ~sndev->db_valid_mask)
+               return -EINVAL;
+
+       spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
+
+       sndev->db_mask &= ~(db_bits << sndev->db_shift);
+       iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
+
+       spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
+
+       return 0;
+}
+
+static u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask;
+}
+
+static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb,
+                                     phys_addr_t *db_addr,
+                                     resource_size_t *db_size)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+       unsigned long offset;
+
+       offset = (unsigned long)sndev->mmio_self_dbmsg->odb -
+               (unsigned long)sndev->stdev->mmio;
+
+       offset += sndev->db_shift / 8;
+
+       if (db_addr)
+               *db_addr = pci_resource_start(ntb->pdev, 0) + offset;
+       if (db_size)
+               *db_size = sizeof(u32);
+
+       return 0;
+}
+
+static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       iowrite64(db_bits << sndev->db_peer_shift,
+                 &sndev->mmio_self_dbmsg->odb);
+
+       return 0;
+}
+
+static int switchtec_ntb_spad_count(struct ntb_dev *ntb)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       return ARRAY_SIZE(sndev->self_shared->spad);
+}
+
+static u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
+               return 0;
+
+       if (!sndev->self_shared)
+               return 0;
+
+       return sndev->self_shared->spad[idx];
+}
+
+static int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
+               return -EINVAL;
+
+       if (!sndev->self_shared)
+               return -EIO;
+
+       sndev->self_shared->spad[idx] = val;
+
+       return 0;
+}
+
+static u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx,
+                                       int sidx)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
+               return 0;
+
+       if (!sndev->peer_shared)
+               return 0;
+
+       return ioread32(&sndev->peer_shared->spad[sidx]);
+}
+
+static int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
+                                        int sidx, u32 val)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
+               return -EINVAL;
+
+       if (!sndev->peer_shared)
+               return -EIO;
+
+       iowrite32(val, &sndev->peer_shared->spad[sidx]);
+
+       return 0;
+}
+
+static int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx,
+                                       int sidx, phys_addr_t *spad_addr)
+{
+       struct switchtec_ntb *sndev = ntb_sndev(ntb);
+       unsigned long offset;
+
+       if (pidx != NTB_DEF_PEER_IDX)
+               return -EINVAL;
+
+       offset = (unsigned long)&sndev->peer_shared->spad[sidx] -
+               (unsigned long)sndev->stdev->mmio;
+
+       if (spad_addr)
+               *spad_addr = pci_resource_start(ntb->pdev, 0) + offset;
+
+       return 0;
+}
+
+static const struct ntb_dev_ops switchtec_ntb_ops = {
+       .mw_count               = switchtec_ntb_mw_count,
+       .mw_get_align           = switchtec_ntb_mw_get_align,
+       .mw_set_trans           = switchtec_ntb_mw_set_trans,
+       .peer_mw_count          = switchtec_ntb_peer_mw_count,
+       .peer_mw_get_addr       = switchtec_ntb_peer_mw_get_addr,
+       .link_is_up             = switchtec_ntb_link_is_up,
+       .link_enable            = switchtec_ntb_link_enable,
+       .link_disable           = switchtec_ntb_link_disable,
+       .db_valid_mask          = switchtec_ntb_db_valid_mask,
+       .db_vector_count        = switchtec_ntb_db_vector_count,
+       .db_vector_mask         = switchtec_ntb_db_vector_mask,
+       .db_read                = switchtec_ntb_db_read,
+       .db_clear               = switchtec_ntb_db_clear,
+       .db_set_mask            = switchtec_ntb_db_set_mask,
+       .db_clear_mask          = switchtec_ntb_db_clear_mask,
+       .db_read_mask           = switchtec_ntb_db_read_mask,
+       .peer_db_addr           = switchtec_ntb_peer_db_addr,
+       .peer_db_set            = switchtec_ntb_peer_db_set,
+       .spad_count             = switchtec_ntb_spad_count,
+       .spad_read              = switchtec_ntb_spad_read,
+       .spad_write             = switchtec_ntb_spad_write,
+       .peer_spad_read         = switchtec_ntb_peer_spad_read,
+       .peer_spad_write        = switchtec_ntb_peer_spad_write,
+       .peer_spad_addr         = switchtec_ntb_peer_spad_addr,
+};
+
+static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
+{
+       u64 part_map;
+
+       sndev->ntb.pdev = sndev->stdev->pdev;
+       sndev->ntb.topo = NTB_TOPO_SWITCH;
+       sndev->ntb.ops = &switchtec_ntb_ops;
+
+       sndev->self_partition = sndev->stdev->partition;
+
+       sndev->mmio_ntb = sndev->stdev->mmio_ntb;
+       part_map = ioread64(&sndev->mmio_ntb->ep_map);
+       part_map &= ~(1 << sndev->self_partition);
+       sndev->peer_partition = ffs(part_map) - 1;
+
+       dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)",
+               sndev->self_partition, sndev->stdev->partition_count,
+               part_map);
+
+       sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb +
+               SWITCHTEC_NTB_REG_CTRL_OFFSET;
+       sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb +
+               SWITCHTEC_NTB_REG_DBMSG_OFFSET;
+
+       sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition];
+       sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition];
+       sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition];
+}
+
+static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl)
+{
+       int i;
+       int cnt = 0;
+
+       for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) {
+               u32 r = ioread32(&ctrl->bar_entry[i].ctl);
+
+               if (r & NTB_CTRL_BAR_VALID)
+                       map[cnt++] = i;
+       }
+
+       return cnt;
+}
+
+static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
+{
+       sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar,
+                                      sndev->mmio_self_ctrl);
+
+       sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries);
+       sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
+
+       dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut",
+               sndev->nr_direct_mw, sndev->nr_lut_mw);
+
+       sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar,
+                                           sndev->mmio_peer_ctrl);
+
+       sndev->peer_nr_lut_mw =
+               ioread16(&sndev->mmio_peer_ctrl->lut_table_entries);
+       sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
+
+       dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut",
+               sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw);
+
+}
+
+/*
+ * There are 64 doorbells in the switch hardware but this is
+ * shared among all partitions. So we must split them in half
+ * (32 for each partition). However, the message interrupts are
+ * also shared with the top 4 doorbells so we just limit this to
+ * 28 doorbells per partition
+ */
+static void switchtec_ntb_init_db(struct switchtec_ntb *sndev)
+{
+       sndev->db_valid_mask = 0x0FFFFFFF;
+
+       if (sndev->self_partition < sndev->peer_partition) {
+               sndev->db_shift = 0;
+               sndev->db_peer_shift = 32;
+       } else {
+               sndev->db_shift = 32;
+               sndev->db_peer_shift = 0;
+       }
+
+       sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL;
+       iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
+       iowrite64(sndev->db_valid_mask << sndev->db_peer_shift,
+                 &sndev->mmio_self_dbmsg->odb_mask);
+}
+
+static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev)
+{
+       int i;
+       u32 msg_map = 0;
+
+       for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
+               int m = i | sndev->peer_partition << 2;
+
+               msg_map |= m << i * 8;
+       }
+
+       iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map);
+
+       for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++)
+               iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK,
+                         &sndev->mmio_self_dbmsg->imsg[i]);
+}
+
+static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev)
+{
+       int rc = 0;
+       u16 req_id;
+       u32 error;
+
+       req_id = ioread16(&sndev->mmio_ntb->requester_id);
+
+       if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) {
+               dev_err(&sndev->stdev->dev,
+                       "Not enough requester IDs available.");
+               return -EFAULT;
+       }
+
+       rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
+                                  NTB_CTRL_PART_OP_LOCK,
+                                  NTB_CTRL_PART_STATUS_LOCKED);
+       if (rc)
+               return rc;
+
+       iowrite32(NTB_PART_CTRL_ID_PROT_DIS,
+                 &sndev->mmio_self_ctrl->partition_ctrl);
+
+       /*
+        * Root Complex Requester ID (which is 0:00.0)
+        */
+       iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN,
+                 &sndev->mmio_self_ctrl->req_id_table[0]);
+
+       /*
+        * Host Bridge Requester ID (as read from the mmap address)
+        */
+       iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN,
+                 &sndev->mmio_self_ctrl->req_id_table[1]);
+
+       rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
+                                  NTB_CTRL_PART_OP_CFG,
+                                  NTB_CTRL_PART_STATUS_NORMAL);
+       if (rc == -EIO) {
+               error = ioread32(&sndev->mmio_self_ctrl->req_id_error);
+               dev_err(&sndev->stdev->dev,
+                       "Error setting up the requester ID table: %08x",
+                       error);
+       }
+
+       return rc;
+}
+
+static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev)
+{
+       int i;
+
+       memset(sndev->self_shared, 0, LUT_SIZE);
+       sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC;
+       sndev->self_shared->partition_id = sndev->stdev->partition;
+
+       for (i = 0; i < sndev->nr_direct_mw; i++) {
+               int bar = sndev->direct_mw_to_bar[i];
+               resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar);
+
+               if (i == 0)
+                       sz = min_t(resource_size_t, sz,
+                                  LUT_SIZE * sndev->nr_lut_mw);
+
+               sndev->self_shared->mw_sizes[i] = sz;
+       }
+
+       for (i = 0; i < sndev->nr_lut_mw; i++) {
+               int idx = sndev->nr_direct_mw + i;
+
+               sndev->self_shared->mw_sizes[idx] = LUT_SIZE;
+       }
+}
+
+static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev)
+{
+       struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
+       int bar = sndev->direct_mw_to_bar[0];
+       u32 ctl_val;
+       int rc;
+
+       sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev,
+                                                LUT_SIZE,
+                                                &sndev->self_shared_dma,
+                                                GFP_KERNEL);
+       if (!sndev->self_shared) {
+               dev_err(&sndev->stdev->dev,
+                       "unable to allocate memory for shared mw");
+               return -ENOMEM;
+       }
+
+       switchtec_ntb_init_shared(sndev);
+
+       rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
+                                  NTB_CTRL_PART_STATUS_LOCKED);
+       if (rc)
+               goto unalloc_and_exit;
+
+       ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
+       ctl_val &= 0xFF;
+       ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN;
+       ctl_val |= ilog2(LUT_SIZE) << 8;
+       ctl_val |= (sndev->nr_lut_mw - 1) << 14;
+       iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
+
+       iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) |
+                  sndev->self_shared_dma),
+                 &ctl->lut_entry[0]);
+
+       rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
+                                  NTB_CTRL_PART_STATUS_NORMAL);
+       if (rc) {
+               u32 bar_error, lut_error;
+
+               bar_error = ioread32(&ctl->bar_error);
+               lut_error = ioread32(&ctl->lut_error);
+               dev_err(&sndev->stdev->dev,
+                       "Error setting up shared MW: %08x / %08x",
+                       bar_error, lut_error);
+               goto unalloc_and_exit;
+       }
+
+       sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE);
+       if (!sndev->peer_shared) {
+               rc = -ENOMEM;
+               goto unalloc_and_exit;
+       }
+
+       dev_dbg(&sndev->stdev->dev, "Shared MW Ready");
+       return 0;
+
+unalloc_and_exit:
+       dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
+                         sndev->self_shared, sndev->self_shared_dma);
+
+       return rc;
+}
+
+static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev)
+{
+       if (sndev->peer_shared)
+               pci_iounmap(sndev->stdev->pdev, sndev->peer_shared);
+
+       if (sndev->self_shared)
+               dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
+                                 sndev->self_shared,
+                                 sndev->self_shared_dma);
+}
+
+static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev)
+{
+       struct switchtec_ntb *sndev = dev;
+
+       dev_dbg(&sndev->stdev->dev, "doorbell\n");
+
+       ntb_db_event(&sndev->ntb, 0);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev)
+{
+       int i;
+       struct switchtec_ntb *sndev = dev;
+
+       for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
+               u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]);
+
+               if (msg & NTB_DBMSG_IMSG_STATUS) {
+                       dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i,
+                               (u32)msg);
+                       iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status);
+
+                       if (i == LINK_MESSAGE)
+                               switchtec_ntb_check_link(sndev);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev)
+{
+       int i;
+       int rc;
+       int doorbell_irq = 0;
+       int message_irq = 0;
+       int event_irq;
+       int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map);
+
+       event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number);
+
+       while (doorbell_irq == event_irq)
+               doorbell_irq++;
+       while (message_irq == doorbell_irq ||
+              message_irq == event_irq)
+               message_irq++;
+
+       dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d",
+               event_irq, doorbell_irq, message_irq);
+
+       for (i = 0; i < idb_vecs - 4; i++)
+               iowrite8(doorbell_irq,
+                        &sndev->mmio_self_dbmsg->idb_vec_map[i]);
+
+       for (; i < idb_vecs; i++)
+               iowrite8(message_irq,
+                        &sndev->mmio_self_dbmsg->idb_vec_map[i]);
+
+       sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq);
+       sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq);
+
+       rc = request_irq(sndev->doorbell_irq,
+                        switchtec_ntb_doorbell_isr, 0,
+                        "switchtec_ntb_doorbell", sndev);
+       if (rc)
+               return rc;
+
+       rc = request_irq(sndev->message_irq,
+                        switchtec_ntb_message_isr, 0,
+                        "switchtec_ntb_message", sndev);
+       if (rc) {
+               free_irq(sndev->doorbell_irq, sndev);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev)
+{
+       free_irq(sndev->doorbell_irq, sndev);
+       free_irq(sndev->message_irq, sndev);
+}
+
+static int switchtec_ntb_add(struct device *dev,
+                            struct class_interface *class_intf)
+{
+       struct switchtec_dev *stdev = to_stdev(dev);
+       struct switchtec_ntb *sndev;
+       int rc;
+
+       stdev->sndev = NULL;
+
+       if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE)
+               return -ENODEV;
+
+       if (stdev->partition_count != 2)
+               dev_warn(dev, "ntb driver only supports 2 partitions");
+
+       sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
+       if (!sndev)
+               return -ENOMEM;
+
+       sndev->stdev = stdev;
+       switchtec_ntb_init_sndev(sndev);
+       switchtec_ntb_init_mw(sndev);
+       switchtec_ntb_init_db(sndev);
+       switchtec_ntb_init_msgs(sndev);
+
+       rc = switchtec_ntb_init_req_id_table(sndev);
+       if (rc)
+               goto free_and_exit;
+
+       rc = switchtec_ntb_init_shared_mw(sndev);
+       if (rc)
+               goto free_and_exit;
+
+       rc = switchtec_ntb_init_db_msg_irq(sndev);
+       if (rc)
+               goto deinit_shared_and_exit;
+
+       rc = ntb_register_device(&sndev->ntb);
+       if (rc)
+               goto deinit_and_exit;
+
+       stdev->sndev = sndev;
+       stdev->link_notifier = switchtec_ntb_link_notification;
+       dev_info(dev, "NTB device registered");
+
+       return 0;
+
+deinit_and_exit:
+       switchtec_ntb_deinit_db_msg_irq(sndev);
+deinit_shared_and_exit:
+       switchtec_ntb_deinit_shared_mw(sndev);
+free_and_exit:
+       kfree(sndev);
+       dev_err(dev, "failed to register ntb device: %d", rc);
+       return rc;
+}
+
+void switchtec_ntb_remove(struct device *dev,
+                         struct class_interface *class_intf)
+{
+       struct switchtec_dev *stdev = to_stdev(dev);
+       struct switchtec_ntb *sndev = stdev->sndev;
+
+       if (!sndev)
+               return;
+
+       stdev->link_notifier = NULL;
+       stdev->sndev = NULL;
+       ntb_unregister_device(&sndev->ntb);
+       switchtec_ntb_deinit_db_msg_irq(sndev);
+       switchtec_ntb_deinit_shared_mw(sndev);
+       kfree(sndev);
+       dev_info(dev, "ntb device unregistered");
+}
+
+static struct class_interface switchtec_interface  = {
+       .add_dev = switchtec_ntb_add,
+       .remove_dev = switchtec_ntb_remove,
+};
+
+static int __init switchtec_ntb_init(void)
+{
+       switchtec_interface.class = switchtec_class;
+       return class_interface_register(&switchtec_interface);
+}
+module_init(switchtec_ntb_init);
+
+static void __exit switchtec_ntb_exit(void)
+{
+       class_interface_unregister(&switchtec_interface);
+}
+module_exit(switchtec_ntb_exit);
index f58d8e3053236ad4608e5552052214b0694a3a95..045e3dd4750e572a033dbb0cf2683296b2d0e6c7 100644 (file)
@@ -191,8 +191,6 @@ struct ntb_transport_qp {
 struct ntb_transport_mw {
        phys_addr_t phys_addr;
        resource_size_t phys_size;
-       resource_size_t xlat_align;
-       resource_size_t xlat_align_size;
        void __iomem *vbase;
        size_t xlat_size;
        size_t buff_size;
@@ -687,13 +685,20 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
        struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
        struct pci_dev *pdev = nt->ndev->pdev;
        size_t xlat_size, buff_size;
+       resource_size_t xlat_align;
+       resource_size_t xlat_align_size;
        int rc;
 
        if (!size)
                return -EINVAL;
 
-       xlat_size = round_up(size, mw->xlat_align_size);
-       buff_size = round_up(size, mw->xlat_align);
+       rc = ntb_mw_get_align(nt->ndev, PIDX, num_mw, &xlat_align,
+                             &xlat_align_size, NULL);
+       if (rc)
+               return rc;
+
+       xlat_size = round_up(size, xlat_align_size);
+       buff_size = round_up(size, xlat_align);
 
        /* No need to re-setup */
        if (mw->xlat_size == xlat_size)
@@ -722,7 +727,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
         * is a requirement of the hardware. It is recommended to setup CMA
         * for BAR sizes equal or greater than 4MB.
         */
-       if (!IS_ALIGNED(mw->dma_addr, mw->xlat_align)) {
+       if (!IS_ALIGNED(mw->dma_addr, xlat_align)) {
                dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
                        &mw->dma_addr);
                ntb_free_mw(nt, num_mw);
@@ -1104,11 +1109,6 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        for (i = 0; i < mw_count; i++) {
                mw = &nt->mw_vec[i];
 
-               rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
-                                     &mw->xlat_align_size, NULL);
-               if (rc)
-                       goto err1;
-
                rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
                                          &mw->phys_size);
                if (rc)
index 759f772fa00c6a3970eacaaa05de88155bcf6c8d..427112cf101aa814ee210cd77d59b97c8ff90f33 100644 (file)
@@ -108,8 +108,6 @@ MODULE_PARM_DESC(on_node, "Run threads only on NTB device node (default: true)")
 struct perf_mw {
        phys_addr_t     phys_addr;
        resource_size_t phys_size;
-       resource_size_t xlat_align;
-       resource_size_t xlat_align_size;
        void __iomem    *vbase;
        size_t          xlat_size;
        size_t          buf_size;
@@ -472,13 +470,20 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
 {
        struct perf_mw *mw = &perf->mw;
        size_t xlat_size, buf_size;
+       resource_size_t xlat_align;
+       resource_size_t xlat_align_size;
        int rc;
 
        if (!size)
                return -EINVAL;
 
-       xlat_size = round_up(size, mw->xlat_align_size);
-       buf_size = round_up(size, mw->xlat_align);
+       rc = ntb_mw_get_align(perf->ntb, PIDX, 0, &xlat_align,
+                             &xlat_align_size, NULL);
+       if (rc)
+               return rc;
+
+       xlat_size = round_up(size, xlat_align_size);
+       buf_size = round_up(size, xlat_align);
 
        if (mw->xlat_size == xlat_size)
                return 0;
@@ -567,11 +572,6 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
 
        mw = &perf->mw;
 
-       rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
-                             &mw->xlat_align_size, NULL);
-       if (rc)
-               return rc;
-
        rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
        if (rc)
                return rc;
index a69815c45ce6f2137d9f409bad0b8742fa530df4..91526a986caab7cc69c328df15a145c14f10899b 100644 (file)
@@ -753,9 +753,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
 
        phys_addr_t base;
        resource_size_t mw_size;
-       resource_size_t align_addr;
-       resource_size_t align_size;
-       resource_size_t max_size;
+       resource_size_t align_addr = 0;
+       resource_size_t align_size = 0;
+       resource_size_t max_size = 0;
 
        buf_size = min_t(size_t, size, 512);
 
index f2e649ff746f546b153d5ff1f64dc70958490c56..26618ba8f92a55e8d42db822b507bb8e8827e49f 100644 (file)
@@ -761,10 +761,10 @@ EXPORT_SYMBOL(of_find_node_opts_by_path);
 
 /**
  *     of_find_node_by_name - Find a node by its "name" property
- *     @from:  The node to start searching from or NULL, the node
+ *     @from:  The node to start searching from or NULL; the node
  *             you pass will not be searched, only the next one
- *             will; typically, you pass what the previous call
- *             returned. of_node_put() will be called on it
+ *             will. Typically, you pass what the previous call
+ *             returned. of_node_put() will be called on @from.
  *     @name:  The name string to match against
  *
  *     Returns a node pointer with refcount incremented, use
index e9ec931f5b9a565c7963dc8f3cf1b1c686effa23..a7b1cb6c2f657798a103f6f55acf3ef6f265377c 100644 (file)
@@ -374,7 +374,7 @@ int of_pci_map_rid(struct device_node *np, u32 rid,
 
                pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
                        np, map_name, map_mask, rid_base, out_base,
-                       rid_len, rid, *id_out);
+                       rid_len, rid, masked_rid - rid_base + out_base);
                return 0;
        }
 
index 3031fc2f18f6fd6b8bb5ae8bd17b9c72ed733b4f..32389acfa6164eb69dcd014f18ce12e58cb90050 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+DTC_FLAGS_testcases := -Wno-interrupts_property
 obj-y += testcases.dtb.o
 
 targets += testcases.dtb testcases.dtb.S
index ce49463d9d32b69bd6374ac3ebecdfe08c75b020..55fe0ee20109fd68e7bc663f8f00f78618a5abd6 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /dts-v1/;
+/plugin/;
+
 / {
        testcase-data {
                changeset {
 #include "tests-match.dtsi"
 #include "tests-platform.dtsi"
 #include "tests-overlay.dtsi"
-
-/*
- * phandle fixup data - generated by dtc patches that aren't upstream.
- * This data must be regenerated whenever phandle references are modified in
- * the testdata tree.
- *
- * The format of this data may be subject to change. For the time being consider
- * this a kernel-internal data format.
- */
-/ { __local_fixups__ {
-       testcase-data {
-               phandle-tests {
-                       consumer-a {
-                               phandle-list = <0x00000000 0x00000008
-                                               0x00000018 0x00000028
-                                               0x00000034 0x00000038>;
-                               phandle-list-bad-args = <0x00000000 0x0000000c>;
-                       };
-               };
-               interrupts {
-                       intmap0 {
-                               interrupt-map = <0x00000004 0x00000010
-                                                0x00000024 0x00000034>;
-                       };
-                       intmap1 {
-                               interrupt-map = <0x0000000c>;
-                       };
-                       interrupts0 {
-                               interrupt-parent = <0x00000000>;
-                       };
-                       interrupts1 {
-                               interrupt-parent = <0x00000000>;
-                       };
-                       interrupts-extended0 {
-                               interrupts-extended = <0x00000000 0x00000008
-                                                      0x00000018 0x00000024
-                                                      0x0000002c 0x00000034
-                                                      0x0000003c>;
-                       };
-               };
-               testcase-device1 {
-                       interrupt-parent = <0x00000000>;
-               };
-               testcase-device2 {
-                       interrupt-parent = <0x00000000>;
-               };
-               overlay2 {
-                       fragment@0 {
-                               target = <0x00000000>;
-                       };
-               };
-               overlay3 {
-                       fragment@0 {
-                               target = <0x00000000>;
-                       };
-               };
-               overlay4 {
-                       fragment@0 {
-                               target = <0x00000000>;
-                       };
-               };
-       };
-}; };
index da45dbea20ce6af4d15ed8b758c13b4437b093f8..730cc897b94da0251dac161192fd1bf1fc47b324 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/switchtec.h>
 #include <linux/switchtec_ioctl.h>
 
 #include <linux/interrupt.h>
@@ -20,8 +21,6 @@
 #include <linux/fs.h>
 #include <linux/uaccess.h>
 #include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/cdev.h>
 #include <linux/wait.h>
 
 MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
@@ -34,265 +33,10 @@ module_param(max_devices, int, 0644);
 MODULE_PARM_DESC(max_devices, "max number of switchtec device instances");
 
 static dev_t switchtec_devt;
-static struct class *switchtec_class;
 static DEFINE_IDA(switchtec_minor_ida);
 
-#define MICROSEMI_VENDOR_ID         0x11f8
-#define MICROSEMI_NTB_CLASSCODE     0x068000
-#define MICROSEMI_MGMT_CLASSCODE    0x058000
-
-#define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024
-#define SWITCHTEC_MAX_PFF_CSR 48
-
-#define SWITCHTEC_EVENT_OCCURRED BIT(0)
-#define SWITCHTEC_EVENT_CLEAR    BIT(0)
-#define SWITCHTEC_EVENT_EN_LOG   BIT(1)
-#define SWITCHTEC_EVENT_EN_CLI   BIT(2)
-#define SWITCHTEC_EVENT_EN_IRQ   BIT(3)
-#define SWITCHTEC_EVENT_FATAL    BIT(4)
-
-enum {
-       SWITCHTEC_GAS_MRPC_OFFSET       = 0x0000,
-       SWITCHTEC_GAS_TOP_CFG_OFFSET    = 0x1000,
-       SWITCHTEC_GAS_SW_EVENT_OFFSET   = 0x1800,
-       SWITCHTEC_GAS_SYS_INFO_OFFSET   = 0x2000,
-       SWITCHTEC_GAS_FLASH_INFO_OFFSET = 0x2200,
-       SWITCHTEC_GAS_PART_CFG_OFFSET   = 0x4000,
-       SWITCHTEC_GAS_NTB_OFFSET        = 0x10000,
-       SWITCHTEC_GAS_PFF_CSR_OFFSET    = 0x134000,
-};
-
-struct mrpc_regs {
-       u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
-       u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
-       u32 cmd;
-       u32 status;
-       u32 ret_value;
-} __packed;
-
-enum mrpc_status {
-       SWITCHTEC_MRPC_STATUS_INPROGRESS = 1,
-       SWITCHTEC_MRPC_STATUS_DONE = 2,
-       SWITCHTEC_MRPC_STATUS_ERROR = 0xFF,
-       SWITCHTEC_MRPC_STATUS_INTERRUPTED = 0x100,
-};
-
-struct sw_event_regs {
-       u64 event_report_ctrl;
-       u64 reserved1;
-       u64 part_event_bitmap;
-       u64 reserved2;
-       u32 global_summary;
-       u32 reserved3[3];
-       u32 stack_error_event_hdr;
-       u32 stack_error_event_data;
-       u32 reserved4[4];
-       u32 ppu_error_event_hdr;
-       u32 ppu_error_event_data;
-       u32 reserved5[4];
-       u32 isp_error_event_hdr;
-       u32 isp_error_event_data;
-       u32 reserved6[4];
-       u32 sys_reset_event_hdr;
-       u32 reserved7[5];
-       u32 fw_exception_hdr;
-       u32 reserved8[5];
-       u32 fw_nmi_hdr;
-       u32 reserved9[5];
-       u32 fw_non_fatal_hdr;
-       u32 reserved10[5];
-       u32 fw_fatal_hdr;
-       u32 reserved11[5];
-       u32 twi_mrpc_comp_hdr;
-       u32 twi_mrpc_comp_data;
-       u32 reserved12[4];
-       u32 twi_mrpc_comp_async_hdr;
-       u32 twi_mrpc_comp_async_data;
-       u32 reserved13[4];
-       u32 cli_mrpc_comp_hdr;
-       u32 cli_mrpc_comp_data;
-       u32 reserved14[4];
-       u32 cli_mrpc_comp_async_hdr;
-       u32 cli_mrpc_comp_async_data;
-       u32 reserved15[4];
-       u32 gpio_interrupt_hdr;
-       u32 gpio_interrupt_data;
-       u32 reserved16[4];
-} __packed;
-
-enum {
-       SWITCHTEC_CFG0_RUNNING = 0x04,
-       SWITCHTEC_CFG1_RUNNING = 0x05,
-       SWITCHTEC_IMG0_RUNNING = 0x03,
-       SWITCHTEC_IMG1_RUNNING = 0x07,
-};
-
-struct sys_info_regs {
-       u32 device_id;
-       u32 device_version;
-       u32 firmware_version;
-       u32 reserved1;
-       u32 vendor_table_revision;
-       u32 table_format_version;
-       u32 partition_id;
-       u32 cfg_file_fmt_version;
-       u16 cfg_running;
-       u16 img_running;
-       u32 reserved2[57];
-       char vendor_id[8];
-       char product_id[16];
-       char product_revision[4];
-       char component_vendor[8];
-       u16 component_id;
-       u8 component_revision;
-} __packed;
-
-struct flash_info_regs {
-       u32 flash_part_map_upd_idx;
-
-       struct active_partition_info {
-               u32 address;
-               u32 build_version;
-               u32 build_string;
-       } active_img;
-
-       struct active_partition_info active_cfg;
-       struct active_partition_info inactive_img;
-       struct active_partition_info inactive_cfg;
-
-       u32 flash_length;
-
-       struct partition_info {
-               u32 address;
-               u32 length;
-       } cfg0;
-
-       struct partition_info cfg1;
-       struct partition_info img0;
-       struct partition_info img1;
-       struct partition_info nvlog;
-       struct partition_info vendor[8];
-};
-
-struct ntb_info_regs {
-       u8  partition_count;
-       u8  partition_id;
-       u16 reserved1;
-       u64 ep_map;
-       u16 requester_id;
-} __packed;
-
-struct part_cfg_regs {
-       u32 status;
-       u32 state;
-       u32 port_cnt;
-       u32 usp_port_mode;
-       u32 usp_pff_inst_id;
-       u32 vep_pff_inst_id;
-       u32 dsp_pff_inst_id[47];
-       u32 reserved1[11];
-       u16 vep_vector_number;
-       u16 usp_vector_number;
-       u32 port_event_bitmap;
-       u32 reserved2[3];
-       u32 part_event_summary;
-       u32 reserved3[3];
-       u32 part_reset_hdr;
-       u32 part_reset_data[5];
-       u32 mrpc_comp_hdr;
-       u32 mrpc_comp_data[5];
-       u32 mrpc_comp_async_hdr;
-       u32 mrpc_comp_async_data[5];
-       u32 dyn_binding_hdr;
-       u32 dyn_binding_data[5];
-       u32 reserved4[159];
-} __packed;
-
-enum {
-       SWITCHTEC_PART_CFG_EVENT_RESET = 1 << 0,
-       SWITCHTEC_PART_CFG_EVENT_MRPC_CMP = 1 << 1,
-       SWITCHTEC_PART_CFG_EVENT_MRPC_ASYNC_CMP = 1 << 2,
-       SWITCHTEC_PART_CFG_EVENT_DYN_PART_CMP = 1 << 3,
-};
-
-struct pff_csr_regs {
-       u16 vendor_id;
-       u16 device_id;
-       u32 pci_cfg_header[15];
-       u32 pci_cap_region[48];
-       u32 pcie_cap_region[448];
-       u32 indirect_gas_window[128];
-       u32 indirect_gas_window_off;
-       u32 reserved[127];
-       u32 pff_event_summary;
-       u32 reserved2[3];
-       u32 aer_in_p2p_hdr;
-       u32 aer_in_p2p_data[5];
-       u32 aer_in_vep_hdr;
-       u32 aer_in_vep_data[5];
-       u32 dpc_hdr;
-       u32 dpc_data[5];
-       u32 cts_hdr;
-       u32 cts_data[5];
-       u32 reserved3[6];
-       u32 hotplug_hdr;
-       u32 hotplug_data[5];
-       u32 ier_hdr;
-       u32 ier_data[5];
-       u32 threshold_hdr;
-       u32 threshold_data[5];
-       u32 power_mgmt_hdr;
-       u32 power_mgmt_data[5];
-       u32 tlp_throttling_hdr;
-       u32 tlp_throttling_data[5];
-       u32 force_speed_hdr;
-       u32 force_speed_data[5];
-       u32 credit_timeout_hdr;
-       u32 credit_timeout_data[5];
-       u32 link_state_hdr;
-       u32 link_state_data[5];
-       u32 reserved4[174];
-} __packed;
-
-struct switchtec_dev {
-       struct pci_dev *pdev;
-       struct device dev;
-       struct cdev cdev;
-
-       int partition;
-       int partition_count;
-       int pff_csr_count;
-       char pff_local[SWITCHTEC_MAX_PFF_CSR];
-
-       void __iomem *mmio;
-       struct mrpc_regs __iomem *mmio_mrpc;
-       struct sw_event_regs __iomem *mmio_sw_event;
-       struct sys_info_regs __iomem *mmio_sys_info;
-       struct flash_info_regs __iomem *mmio_flash_info;
-       struct ntb_info_regs __iomem *mmio_ntb;
-       struct part_cfg_regs __iomem *mmio_part_cfg;
-       struct part_cfg_regs __iomem *mmio_part_cfg_all;
-       struct pff_csr_regs __iomem *mmio_pff_csr;
-
-       /*
-        * The mrpc mutex must be held when accessing the other
-        * mrpc_ fields, alive flag and stuser->state field
-        */
-       struct mutex mrpc_mutex;
-       struct list_head mrpc_queue;
-       int mrpc_busy;
-       struct work_struct mrpc_work;
-       struct delayed_work mrpc_timeout;
-       bool alive;
-
-       wait_queue_head_t event_wq;
-       atomic_t event_cnt;
-};
-
-static struct switchtec_dev *to_stdev(struct device *dev)
-{
-       return container_of(dev, struct switchtec_dev, dev);
-}
+struct class *switchtec_class;
+EXPORT_SYMBOL_GPL(switchtec_class);
 
 enum mrpc_state {
        MRPC_IDLE = 0,
@@ -1234,6 +978,49 @@ static const struct file_operations switchtec_fops = {
        .compat_ioctl = switchtec_dev_ioctl,
 };
 
+static void link_event_work(struct work_struct *work)
+{
+       struct switchtec_dev *stdev;
+
+       stdev = container_of(work, struct switchtec_dev, link_event_work);
+
+       if (stdev->link_notifier)
+               stdev->link_notifier(stdev);
+}
+
+static void check_link_state_events(struct switchtec_dev *stdev)
+{
+       int idx;
+       u32 reg;
+       int count;
+       int occurred = 0;
+
+       for (idx = 0; idx < stdev->pff_csr_count; idx++) {
+               reg = ioread32(&stdev->mmio_pff_csr[idx].link_state_hdr);
+               dev_dbg(&stdev->dev, "link_state: %d->%08x\n", idx, reg);
+               count = (reg >> 5) & 0xFF;
+
+               if (count != stdev->link_event_count[idx]) {
+                       occurred = 1;
+                       stdev->link_event_count[idx] = count;
+               }
+       }
+
+       if (occurred)
+               schedule_work(&stdev->link_event_work);
+}
+
+static void enable_link_state_events(struct switchtec_dev *stdev)
+{
+       int idx;
+
+       for (idx = 0; idx < stdev->pff_csr_count; idx++) {
+               iowrite32(SWITCHTEC_EVENT_CLEAR |
+                         SWITCHTEC_EVENT_EN_IRQ,
+                         &stdev->mmio_pff_csr[idx].link_state_hdr);
+       }
+}
+
 static void stdev_release(struct device *dev)
 {
        struct switchtec_dev *stdev = to_stdev(dev);
@@ -1286,6 +1073,7 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev)
        stdev->mrpc_busy = 0;
        INIT_WORK(&stdev->mrpc_work, mrpc_event_work);
        INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work);
+       INIT_WORK(&stdev->link_event_work, link_event_work);
        init_waitqueue_head(&stdev->event_wq);
        atomic_set(&stdev->event_cnt, 0);
 
@@ -1329,6 +1117,9 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
        if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
                return 0;
 
+       if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE)
+               return 0;
+
        dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr);
        hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED);
        iowrite32(hdr, hdr_reg);
@@ -1348,6 +1139,7 @@ static int mask_all_events(struct switchtec_dev *stdev, int eid)
                for (idx = 0; idx < stdev->pff_csr_count; idx++) {
                        if (!stdev->pff_local[idx])
                                continue;
+
                        count += mask_event(stdev, eid, idx);
                }
        } else {
@@ -1372,6 +1164,8 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev)
                iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr);
        }
 
+       check_link_state_events(stdev);
+
        for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++)
                event_count += mask_all_events(stdev, eid);
 
@@ -1481,6 +1275,9 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
        struct switchtec_dev *stdev;
        int rc;
 
+       if (pdev->class == MICROSEMI_NTB_CLASSCODE)
+               request_module_nowait("ntb_hw_switchtec");
+
        stdev = stdev_create(pdev);
        if (IS_ERR(stdev))
                return PTR_ERR(stdev);
@@ -1498,6 +1295,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
        iowrite32(SWITCHTEC_EVENT_CLEAR |
                  SWITCHTEC_EVENT_EN_IRQ,
                  &stdev->mmio_part_cfg->mrpc_comp_hdr);
+       enable_link_state_events(stdev);
 
        rc = cdev_device_add(&stdev->cdev, &stdev->dev);
        if (rc)
index 09dac11337d10bf6abebb836a6db93b6abc5dd4b..2c745e8ccad6c190882725d8864d4f96ae2e68be 100644 (file)
@@ -93,12 +93,31 @@ config ASUS_LAPTOP
 
 config DELL_SMBIOS
        tristate
-       select DCDBAS
+
+config DELL_SMBIOS_WMI
+       tristate "Dell SMBIOS calling interface (WMI implementation)"
+       depends on ACPI_WMI
+       select DELL_WMI_DESCRIPTOR
+       select DELL_SMBIOS
+       ---help---
+       This provides an implementation for the Dell SMBIOS calling interface
+       communicated over ACPI-WMI.
+
+       If you have a Dell computer from >2007 you should say Y or M here.
+       If you aren't sure and this module doesn't work for your computer
+       it just won't load.
+
+config DELL_SMBIOS_SMM
+       tristate "Dell SMBIOS calling interface (SMM implementation)"
+       depends on DCDBAS
+       select DELL_SMBIOS
        ---help---
-       This module provides common functions for kernel modules using
-       Dell SMBIOS.
+       This provides an implementation for the Dell SMBIOS calling interface
+       communicated over SMI/SMM.
 
-       If you have a Dell laptop, say Y or M here.
+       If you have a Dell computer from <=2017 you should say Y or M here.
+       If you aren't sure and this module doesn't work for your computer
+       it just won't load.
 
 config DELL_LAPTOP
        tristate "Dell Laptop Extras"
@@ -116,11 +135,12 @@ config DELL_LAPTOP
        laptops (except for some models covered by the Compal driver).
 
 config DELL_WMI
-       tristate "Dell WMI extras"
+       tristate "Dell WMI notifications"
        depends on ACPI_WMI
        depends on DMI
        depends on INPUT
        depends on ACPI_VIDEO || ACPI_VIDEO = n
+       select DELL_WMI_DESCRIPTOR
        select DELL_SMBIOS
        select INPUT_SPARSEKMAP
        ---help---
@@ -129,6 +149,10 @@ config DELL_WMI
          To compile this driver as a module, choose M here: the module will
          be called dell-wmi.
 
+config DELL_WMI_DESCRIPTOR
+       tristate
+       depends on ACPI_WMI
+
 config DELL_WMI_AIO
        tristate "WMI Hotkeys for Dell All-In-One series"
        depends on ACPI_WMI
@@ -426,7 +450,6 @@ config THINKPAD_ACPI_ALSA_SUPPORT
 config THINKPAD_ACPI_DEBUGFACILITIES
        bool "Maintainer debug facilities"
        depends on THINKPAD_ACPI
-       default n
        ---help---
          Enables extra stuff in the thinkpad-acpi which is completely useless
          for normal use.  Read the driver source to find out what it does.
@@ -437,7 +460,6 @@ config THINKPAD_ACPI_DEBUGFACILITIES
 config THINKPAD_ACPI_DEBUG
        bool "Verbose debug mode"
        depends on THINKPAD_ACPI
-       default n
        ---help---
          Enables extra debugging information, at the expense of a slightly
          increase in driver size.
@@ -447,7 +469,6 @@ config THINKPAD_ACPI_DEBUG
 config THINKPAD_ACPI_UNSAFE_LEDS
        bool "Allow control of important LEDs (unsafe)"
        depends on THINKPAD_ACPI
-       default n
        ---help---
          Overriding LED state on ThinkPads can mask important
          firmware alerts (like critical battery condition), or misled
@@ -515,7 +536,6 @@ config SENSORS_HDAPS
        tristate "Thinkpad Hard Drive Active Protection System (hdaps)"
        depends on INPUT
        select INPUT_POLLDEV
-       default n
        help
          This driver provides support for the IBM Hard Drive Active Protection
          System (hdaps), which provides an accelerometer and other misc. data.
@@ -658,6 +678,18 @@ config WMI_BMOF
          To compile this driver as a module, choose M here: the module will
          be called wmi-bmof.
 
+config INTEL_WMI_THUNDERBOLT
+       tristate "Intel WMI thunderbolt force power driver"
+       depends on ACPI_WMI
+       ---help---
+         Say Y here if you want to be able to use the WMI interface on select
+         systems to force the power control of Intel Thunderbolt controllers.
+         This is useful for updating the firmware when devices are not plugged
+         into the controller.
+
+         To compile this driver as a module, choose M here: the module will
+         be called intel-wmi-thunderbolt.
+
 config MSI_WMI
        tristate "MSI WMI extras"
        depends on ACPI_WMI
@@ -763,7 +795,6 @@ config TOSHIBA_HAPS
 
 config TOSHIBA_WMI
        tristate "Toshiba WMI Hotkeys Driver (EXPERIMENTAL)"
-       default n
        depends on ACPI_WMI
        depends on INPUT
        select INPUT_SPARSEKMAP
@@ -785,7 +816,6 @@ config ACPI_CMPC
        depends on RFKILL || RFKILL=n
        select INPUT
        select BACKLIGHT_CLASS_DEVICE
-       default n
        help
          Support for Intel Classmate PC ACPI devices, including some
          keys as input device, backlight device, tablet and accelerometer
@@ -793,7 +823,7 @@ config ACPI_CMPC
 
 config INTEL_CHT_INT33FE
        tristate "Intel Cherry Trail ACPI INT33FE Driver"
-       depends on X86 && ACPI && I2C
+       depends on X86 && ACPI && I2C && REGULATOR
        ---help---
          This driver add support for the INT33FE ACPI device found on
          some Intel Cherry Trail devices.
@@ -804,6 +834,10 @@ config INTEL_CHT_INT33FE
          This driver instantiates i2c-clients for these, so that standard
          i2c drivers for these chips can bind to the them.
 
+         If you enable this driver it is advised to also select
+         CONFIG_TYPEC_FUSB302=m, CONFIG_CHARGER_BQ24190=m and
+         CONFIG_BATTERY_MAX17042=m.
+
 config INTEL_INT0002_VGPIO
        tristate "Intel ACPI INT0002 Virtual GPIO driver"
        depends on GPIOLIB && ACPI
@@ -892,7 +926,6 @@ config INTEL_IPS
 
 config INTEL_IMR
        bool "Intel Isolated Memory Region support"
-       default n
        depends on X86_INTEL_QUARK && IOSF_MBI
        ---help---
          This option provides a means to manipulate Isolated Memory Regions.
@@ -1088,7 +1121,6 @@ config INTEL_PUNIT_IPC
 
 config INTEL_TELEMETRY
        tristate "Intel SoC Telemetry Driver"
-       default n
        depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64
        ---help---
          This driver provides interfaces to configure and use
@@ -1111,7 +1143,6 @@ config MLX_PLATFORM
 
 config MLX_CPLD_PLATFORM
        tristate "Mellanox platform hotplug driver support"
-       default n
        select HWMON
        select I2C
        ---help---
index f9e3ae683bbe3729757d36f19e02df3c2c5ea8f9..c32b34a724679435d134615c42a9c3f3855cf463 100644 (file)
@@ -13,8 +13,11 @@ obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_ACPI_CMPC)                += classmate-laptop.o
 obj-$(CONFIG_COMPAL_LAPTOP)    += compal-laptop.o
 obj-$(CONFIG_DELL_SMBIOS)      += dell-smbios.o
+obj-$(CONFIG_DELL_SMBIOS_WMI)  += dell-smbios-wmi.o
+obj-$(CONFIG_DELL_SMBIOS_SMM)  += dell-smbios-smm.o
 obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_DELL_WMI)         += dell-wmi.o
+obj-$(CONFIG_DELL_WMI_DESCRIPTOR)      += dell-wmi-descriptor.o
 obj-$(CONFIG_DELL_WMI_AIO)     += dell-wmi-aio.o
 obj-$(CONFIG_DELL_WMI_LED)     += dell-wmi-led.o
 obj-$(CONFIG_DELL_SMO8800)     += dell-smo8800.o
@@ -40,6 +43,7 @@ obj-$(CONFIG_PEAQ_WMI)                += peaq-wmi.o
 obj-$(CONFIG_SURFACE3_WMI)     += surface3-wmi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)   += topstar-laptop.o
 obj-$(CONFIG_WMI_BMOF)         += wmi-bmof.o
+obj-$(CONFIG_INTEL_WMI_THUNDERBOLT)    += intel-wmi-thunderbolt.o
 
 # toshiba_acpi must link after wmi to ensure that wmi devices are found
 # before toshiba_acpi initializes
index 48e1541dc8d4efa3cf24e9c0df5861aeaa431798..a32c5c00e0e7bdf9868e81c655f30f8fb6cc34be 100644 (file)
@@ -119,6 +119,7 @@ MODULE_LICENSE("GPL");
 #define ASUS_WMI_DEVID_BRIGHTNESS      0x00050012
 #define ASUS_WMI_DEVID_KBD_BACKLIGHT   0x00050021
 #define ASUS_WMI_DEVID_LIGHT_SENSOR    0x00050022 /* ?? */
+#define ASUS_WMI_DEVID_LIGHTBAR                0x00050025
 
 /* Misc */
 #define ASUS_WMI_DEVID_CAMERA          0x00060013
@@ -148,6 +149,7 @@ MODULE_LICENSE("GPL");
 #define ASUS_WMI_DSTS_BIOS_BIT         0x00040000
 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK  0x000000FF
 #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK  0x0000FF00
+#define ASUS_WMI_DSTS_LIGHTBAR_MASK    0x0000000F
 
 #define ASUS_FAN_DESC                  "cpu_fan"
 #define ASUS_FAN_MFUN                  0x13
@@ -222,10 +224,13 @@ struct asus_wmi {
        int tpd_led_wk;
        struct led_classdev kbd_led;
        int kbd_led_wk;
+       struct led_classdev lightbar_led;
+       int lightbar_led_wk;
        struct workqueue_struct *led_workqueue;
        struct work_struct tpd_led_work;
        struct work_struct kbd_led_work;
        struct work_struct wlan_led_work;
+       struct work_struct lightbar_led_work;
 
        struct asus_rfkill wlan;
        struct asus_rfkill bluetooth;
@@ -567,6 +572,48 @@ static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
        return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
 }
 
+static void lightbar_led_update(struct work_struct *work)
+{
+       struct asus_wmi *asus;
+       int ctrl_param;
+
+       asus = container_of(work, struct asus_wmi, lightbar_led_work);
+
+       ctrl_param = asus->lightbar_led_wk;
+       asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL);
+}
+
+static void lightbar_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness value)
+{
+       struct asus_wmi *asus;
+
+       asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
+
+       asus->lightbar_led_wk = !!value;
+       queue_work(asus->led_workqueue, &asus->lightbar_led_work);
+}
+
+static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev)
+{
+       struct asus_wmi *asus;
+       u32 result;
+
+       asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
+       asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
+
+       return result & ASUS_WMI_DSTS_LIGHTBAR_MASK;
+}
+
+static int lightbar_led_presence(struct asus_wmi *asus)
+{
+       u32 result;
+
+       asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
+
+       return result & ASUS_WMI_DSTS_PRESENCE_BIT;
+}
+
 static void asus_wmi_led_exit(struct asus_wmi *asus)
 {
        if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
@@ -575,6 +622,8 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
                led_classdev_unregister(&asus->tpd_led);
        if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
                led_classdev_unregister(&asus->wlan_led);
+       if (!IS_ERR_OR_NULL(asus->lightbar_led.dev))
+               led_classdev_unregister(&asus->lightbar_led);
        if (asus->led_workqueue)
                destroy_workqueue(asus->led_workqueue);
 }
@@ -630,6 +679,20 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
 
                rv = led_classdev_register(&asus->platform_device->dev,
                                           &asus->wlan_led);
+               if (rv)
+                       goto error;
+       }
+
+       if (lightbar_led_presence(asus)) {
+               INIT_WORK(&asus->lightbar_led_work, lightbar_led_update);
+
+               asus->lightbar_led.name = "asus::lightbar";
+               asus->lightbar_led.brightness_set = lightbar_led_set;
+               asus->lightbar_led.brightness_get = lightbar_led_get;
+               asus->lightbar_led.max_brightness = 1;
+
+               rv = led_classdev_register(&asus->platform_device->dev,
+                                          &asus->lightbar_led);
        }
 
 error:
index f42159fd20318beb15b6495fa9c3027e47326c2a..2d704361f67284304b17a781ea8b45da617211be 100644 (file)
 #include "dell-rbtn.h"
 #include "dell-smbios.h"
 
-#define BRIGHTNESS_TOKEN 0x7d
-#define KBD_LED_OFF_TOKEN 0x01E1
-#define KBD_LED_ON_TOKEN 0x01E2
-#define KBD_LED_AUTO_TOKEN 0x01E3
-#define KBD_LED_AUTO_25_TOKEN 0x02EA
-#define KBD_LED_AUTO_50_TOKEN 0x02EB
-#define KBD_LED_AUTO_75_TOKEN 0x02EC
-#define KBD_LED_AUTO_100_TOKEN 0x02F6
-#define GLOBAL_MIC_MUTE_ENABLE 0x0364
-#define GLOBAL_MIC_MUTE_DISABLE 0x0365
-#define KBD_LED_AC_TOKEN 0x0451
-
 struct quirk_entry {
        u8 touchpad_led;
 
@@ -85,6 +73,7 @@ static struct platform_driver platform_driver = {
        }
 };
 
+static struct calling_interface_buffer *buffer;
 static struct platform_device *platform_device;
 static struct backlight_device *dell_backlight_device;
 static struct rfkill *wifi_rfkill;
@@ -283,6 +272,27 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
        { }
 };
 
+void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
+{
+       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+       buffer->input[0] = arg0;
+       buffer->input[1] = arg1;
+       buffer->input[2] = arg2;
+       buffer->input[3] = arg3;
+}
+
+int dell_send_request(u16 class, u16 select)
+{
+       int ret;
+
+       buffer->cmd_class = class;
+       buffer->cmd_select = select;
+       ret = dell_smbios_call(buffer);
+       if (ret != 0)
+               return ret;
+       return dell_smbios_error(buffer->output[0]);
+}
+
 /*
  * Derived from information in smbios-wireless-ctl:
  *
@@ -405,7 +415,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
 
 static int dell_rfkill_set(void *data, bool blocked)
 {
-       struct calling_interface_buffer *buffer;
        int disable = blocked ? 1 : 0;
        unsigned long radio = (unsigned long)data;
        int hwswitch_bit = (unsigned long)data - 1;
@@ -413,20 +422,16 @@ static int dell_rfkill_set(void *data, bool blocked)
        int status;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+       if (ret)
+               return ret;
        status = buffer->output[1];
 
-       if (ret != 0)
-               goto out;
-
-       dell_smbios_clear_buffer();
-
-       buffer->input[0] = 0x2;
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0x2, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+       if (ret)
+               return ret;
        hwswitch = buffer->output[1];
 
        /* If the hardware switch controls this radio, and the hardware
@@ -435,28 +440,19 @@ static int dell_rfkill_set(void *data, bool blocked)
            (status & BIT(0)) && !(status & BIT(16)))
                disable = 1;
 
-       dell_smbios_clear_buffer();
-
-       buffer->input[0] = (1 | (radio<<8) | (disable << 16));
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
-
- out:
-       dell_smbios_release_buffer();
-       return dell_smbios_error(ret);
+       dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+       return ret;
 }
 
-/* Must be called with the buffer held */
 static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
-                                       int status,
-                                       struct calling_interface_buffer *buffer)
+                                       int status)
 {
        if (status & BIT(0)) {
                /* Has hw-switch, sync sw_state to BIOS */
                int block = rfkill_blocked(rfkill);
-               dell_smbios_clear_buffer();
-               buffer->input[0] = (1 | (radio << 8) | (block << 16));
-               dell_smbios_send_request(17, 11);
+               dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0);
+               dell_send_request(CLASS_INFO, SELECT_RFKILL);
        } else {
                /* No hw-switch, sync BIOS state to sw_state */
                rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
@@ -472,32 +468,23 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
 
 static void dell_rfkill_query(struct rfkill *rfkill, void *data)
 {
-       struct calling_interface_buffer *buffer;
        int radio = ((unsigned long)data & 0xF);
        int hwswitch;
        int status;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
        status = buffer->output[1];
 
        if (ret != 0 || !(status & BIT(0))) {
-               dell_smbios_release_buffer();
                return;
        }
 
-       dell_smbios_clear_buffer();
-
-       buffer->input[0] = 0x2;
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0x2, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
        hwswitch = buffer->output[1];
 
-       dell_smbios_release_buffer();
-
        if (ret != 0)
                return;
 
@@ -513,27 +500,23 @@ static struct dentry *dell_laptop_dir;
 
 static int dell_debugfs_show(struct seq_file *s, void *data)
 {
-       struct calling_interface_buffer *buffer;
        int hwswitch_state;
        int hwswitch_ret;
        int status;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+       if (ret)
+               return ret;
        status = buffer->output[1];
 
-       dell_smbios_clear_buffer();
-
-       buffer->input[0] = 0x2;
-       dell_smbios_send_request(17, 11);
-       hwswitch_ret = buffer->output[0];
+       dell_set_arguments(0, 0x2, 0, 0);
+       hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+       if (hwswitch_ret)
+               return hwswitch_ret;
        hwswitch_state = buffer->output[1];
 
-       dell_smbios_release_buffer();
-
        seq_printf(s, "return:\t%d\n", ret);
        seq_printf(s, "status:\t0x%X\n", status);
        seq_printf(s, "Bit 0 : Hardware switch supported:   %lu\n",
@@ -613,46 +596,36 @@ static const struct file_operations dell_debugfs_fops = {
 
 static void dell_update_rfkill(struct work_struct *ignored)
 {
-       struct calling_interface_buffer *buffer;
        int hwswitch = 0;
        int status;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
        status = buffer->output[1];
 
        if (ret != 0)
-               goto out;
-
-       dell_smbios_clear_buffer();
+               return;
 
-       buffer->input[0] = 0x2;
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0x2, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
 
        if (ret == 0 && (status & BIT(0)))
                hwswitch = buffer->output[1];
 
        if (wifi_rfkill) {
                dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
-               dell_rfkill_update_sw_state(wifi_rfkill, 1, status, buffer);
+               dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
        }
        if (bluetooth_rfkill) {
                dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status,
                                            hwswitch);
-               dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status,
-                                           buffer);
+               dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
        }
        if (wwan_rfkill) {
                dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch);
-               dell_rfkill_update_sw_state(wwan_rfkill, 3, status, buffer);
+               dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
        }
-
- out:
-       dell_smbios_release_buffer();
 }
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
 
@@ -696,7 +669,6 @@ static struct notifier_block dell_laptop_rbtn_notifier = {
 
 static int __init dell_setup_rfkill(void)
 {
-       struct calling_interface_buffer *buffer;
        int status, ret, whitelisted;
        const char *product;
 
@@ -712,11 +684,9 @@ static int __init dell_setup_rfkill(void)
        if (!force_rfkill && !whitelisted)
                return 0;
 
-       buffer = dell_smbios_get_buffer();
-       dell_smbios_send_request(17, 11);
-       ret = buffer->output[0];
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
        status = buffer->output[1];
-       dell_smbios_release_buffer();
 
        /* dell wireless info smbios call is not supported */
        if (ret != 0)
@@ -869,7 +839,6 @@ static void dell_cleanup_rfkill(void)
 
 static int dell_send_intensity(struct backlight_device *bd)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
        int ret;
 
@@ -877,24 +846,17 @@ static int dell_send_intensity(struct backlight_device *bd)
        if (!token)
                return -ENODEV;
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = token->location;
-       buffer->input[1] = bd->props.brightness;
-
+       dell_set_arguments(token->location, bd->props.brightness, 0, 0);
        if (power_supply_is_system_supplied() > 0)
-               dell_smbios_send_request(1, 2);
+               ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
        else
-               dell_smbios_send_request(1, 1);
+               ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
 
-       ret = dell_smbios_error(buffer->output[0]);
-
-       dell_smbios_release_buffer();
        return ret;
 }
 
 static int dell_get_intensity(struct backlight_device *bd)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
        int ret;
 
@@ -902,20 +864,14 @@ static int dell_get_intensity(struct backlight_device *bd)
        if (!token)
                return -ENODEV;
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = token->location;
-
+       dell_set_arguments(token->location, 0, 0, 0);
        if (power_supply_is_system_supplied() > 0)
-               dell_smbios_send_request(0, 2);
+               ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
        else
-               dell_smbios_send_request(0, 1);
+               ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
 
-       if (buffer->output[0])
-               ret = dell_smbios_error(buffer->output[0]);
-       else
+       if (ret == 0)
                ret = buffer->output[1];
-
-       dell_smbios_release_buffer();
        return ret;
 }
 
@@ -1179,20 +1135,13 @@ static DEFINE_MUTEX(kbd_led_mutex);
 
 static int kbd_get_info(struct kbd_info *info)
 {
-       struct calling_interface_buffer *buffer;
        u8 units;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       buffer->input[0] = 0x0;
-       dell_smbios_send_request(4, 11);
-       ret = buffer->output[0];
-
-       if (ret) {
-               ret = dell_smbios_error(ret);
-               goto out;
-       }
+       dell_set_arguments(0, 0, 0, 0);
+       ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
+       if (ret)
+               return ret;
 
        info->modes = buffer->output[1] & 0xFFFF;
        info->type = (buffer->output[1] >> 24) & 0xFF;
@@ -1209,8 +1158,6 @@ static int kbd_get_info(struct kbd_info *info)
        if (units & BIT(3))
                info->days = (buffer->output[3] >> 24) & 0xFF;
 
- out:
-       dell_smbios_release_buffer();
        return ret;
 }
 
@@ -1269,19 +1216,12 @@ static int kbd_set_level(struct kbd_state *state, u8 level)
 
 static int kbd_get_state(struct kbd_state *state)
 {
-       struct calling_interface_buffer *buffer;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
-
-       buffer->input[0] = 0x1;
-       dell_smbios_send_request(4, 11);
-       ret = buffer->output[0];
-
-       if (ret) {
-               ret = dell_smbios_error(ret);
-               goto out;
-       }
+       dell_set_arguments(0x1, 0, 0, 0);
+       ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
+       if (ret)
+               return ret;
 
        state->mode_bit = ffs(buffer->output[1] & 0xFFFF);
        if (state->mode_bit != 0)
@@ -1296,31 +1236,27 @@ static int kbd_get_state(struct kbd_state *state)
        state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F;
        state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3;
 
- out:
-       dell_smbios_release_buffer();
        return ret;
 }
 
 static int kbd_set_state(struct kbd_state *state)
 {
-       struct calling_interface_buffer *buffer;
        int ret;
+       u32 input1;
+       u32 input2;
+
+       input1 = BIT(state->mode_bit) & 0xFFFF;
+       input1 |= (state->triggers & 0xFF) << 16;
+       input1 |= (state->timeout_value & 0x3F) << 24;
+       input1 |= (state->timeout_unit & 0x3) << 30;
+       input2 = state->als_setting & 0xFF;
+       input2 |= (state->level & 0xFF) << 16;
+       input2 |= (state->timeout_value_ac & 0x3F) << 24;
+       input2 |= (state->timeout_unit_ac & 0x3) << 30;
+       dell_set_arguments(0x2, input1, input2, 0);
+       ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = 0x2;
-       buffer->input[1] = BIT(state->mode_bit) & 0xFFFF;
-       buffer->input[1] |= (state->triggers & 0xFF) << 16;
-       buffer->input[1] |= (state->timeout_value & 0x3F) << 24;
-       buffer->input[1] |= (state->timeout_unit & 0x3) << 30;
-       buffer->input[2] = state->als_setting & 0xFF;
-       buffer->input[2] |= (state->level & 0xFF) << 16;
-       buffer->input[2] |= (state->timeout_value_ac & 0x3F) << 24;
-       buffer->input[2] |= (state->timeout_unit_ac & 0x3) << 30;
-       dell_smbios_send_request(4, 11);
-       ret = buffer->output[0];
-       dell_smbios_release_buffer();
-
-       return dell_smbios_error(ret);
+       return ret;
 }
 
 static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
@@ -1345,7 +1281,6 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
 
 static int kbd_set_token_bit(u8 bit)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
        int ret;
 
@@ -1356,19 +1291,14 @@ static int kbd_set_token_bit(u8 bit)
        if (!token)
                return -EINVAL;
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = token->location;
-       buffer->input[1] = token->value;
-       dell_smbios_send_request(1, 0);
-       ret = buffer->output[0];
-       dell_smbios_release_buffer();
+       dell_set_arguments(token->location, token->value, 0, 0);
+       ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
 
-       return dell_smbios_error(ret);
+       return ret;
 }
 
 static int kbd_get_token_bit(u8 bit)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
        int ret;
        int val;
@@ -1380,15 +1310,12 @@ static int kbd_get_token_bit(u8 bit)
        if (!token)
                return -EINVAL;
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = token->location;
-       dell_smbios_send_request(0, 0);
-       ret = buffer->output[0];
+       dell_set_arguments(token->location, 0, 0, 0);
+       ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD);
        val = buffer->output[1];
-       dell_smbios_release_buffer();
 
        if (ret)
-               return dell_smbios_error(ret);
+               return ret;
 
        return (val == token->value);
 }
@@ -2102,7 +2029,6 @@ static struct notifier_block dell_laptop_notifier = {
 
 int dell_micmute_led_set(int state)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
 
        if (state == 0)
@@ -2115,11 +2041,8 @@ int dell_micmute_led_set(int state)
        if (!token)
                return -ENODEV;
 
-       buffer = dell_smbios_get_buffer();
-       buffer->input[0] = token->location;
-       buffer->input[1] = token->value;
-       dell_smbios_send_request(1, 0);
-       dell_smbios_release_buffer();
+       dell_set_arguments(token->location, token->value, 0, 0);
+       dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
 
        return state;
 }
@@ -2127,7 +2050,6 @@ EXPORT_SYMBOL_GPL(dell_micmute_led_set);
 
 static int __init dell_init(void)
 {
-       struct calling_interface_buffer *buffer;
        struct calling_interface_token *token;
        int max_intensity = 0;
        int ret;
@@ -2151,6 +2073,11 @@ static int __init dell_init(void)
        if (ret)
                goto fail_platform_device2;
 
+       buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
+       if (!buffer)
+               goto fail_buffer;
+
+
        ret = dell_setup_rfkill();
 
        if (ret) {
@@ -2175,12 +2102,10 @@ static int __init dell_init(void)
 
        token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
        if (token) {
-               buffer = dell_smbios_get_buffer();
-               buffer->input[0] = token->location;
-               dell_smbios_send_request(0, 2);
-               if (buffer->output[0] == 0)
+               dell_set_arguments(token->location, 0, 0, 0);
+               ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
+               if (ret)
                        max_intensity = buffer->output[3];
-               dell_smbios_release_buffer();
        }
 
        if (max_intensity) {
@@ -2214,6 +2139,8 @@ static int __init dell_init(void)
 fail_get_brightness:
        backlight_device_unregister(dell_backlight_device);
 fail_backlight:
+       kfree(buffer);
+fail_buffer:
        dell_cleanup_rfkill();
 fail_rfkill:
        platform_device_del(platform_device);
@@ -2233,6 +2160,7 @@ static void __exit dell_exit(void)
                touchpad_led_exit();
        kbd_led_exit();
        backlight_device_unregister(dell_backlight_device);
+       kfree(buffer);
        dell_cleanup_rfkill();
        if (platform_device) {
                platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
new file mode 100644 (file)
index 0000000..89f65c4
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  SMI methods for use with dell-smbios
+ *
+ *  Copyright (c) Red Hat <mjg@redhat.com>
+ *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
+ *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (c) 2017 Dell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include "../../firmware/dcdbas.h"
+#include "dell-smbios.h"
+
+static int da_command_address;
+static int da_command_code;
+static struct calling_interface_buffer *buffer;
+struct platform_device *platform_device;
+static DEFINE_MUTEX(smm_mutex);
+
+static const struct dmi_system_id dell_device_table[] __initconst = {
+       {
+               .ident = "Dell laptop",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
+               },
+       },
+       {
+               .ident = "Dell Computer Corporation",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
+               },
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(dmi, dell_device_table);
+
+static void __init parse_da_table(const struct dmi_header *dm)
+{
+       struct calling_interface_structure *table =
+               container_of(dm, struct calling_interface_structure, header);
+
+       /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
+        * 6 bytes of entry
+        */
+       if (dm->length < 17)
+               return;
+
+       da_command_address = table->cmdIOAddress;
+       da_command_code = table->cmdIOCode;
+}
+
+static void __init find_cmd_address(const struct dmi_header *dm, void *dummy)
+{
+       switch (dm->type) {
+       case 0xda: /* Calling interface */
+               parse_da_table(dm);
+               break;
+       }
+}
+
+int dell_smbios_smm_call(struct calling_interface_buffer *input)
+{
+       struct smi_cmd command;
+       size_t size;
+
+       size = sizeof(struct calling_interface_buffer);
+       command.magic = SMI_CMD_MAGIC;
+       command.command_address = da_command_address;
+       command.command_code = da_command_code;
+       command.ebx = virt_to_phys(buffer);
+       command.ecx = 0x42534931;
+
+       mutex_lock(&smm_mutex);
+       memcpy(buffer, input, size);
+       dcdbas_smi_request(&command);
+       memcpy(input, buffer, size);
+       mutex_unlock(&smm_mutex);
+       return 0;
+}
+
+/* When enabled this indicates that SMM won't work */
+static bool test_wsmt_enabled(void)
+{
+       struct calling_interface_token *wsmt;
+
+       /* if token doesn't exist, SMM will work */
+       wsmt = dell_smbios_find_token(WSMT_EN_TOKEN);
+       if (!wsmt)
+               return false;
+
+       /* If token exists, try to access over SMM but set a dummy return.
+        * - If WSMT disabled it will be overwritten by SMM
+        * - If WSMT enabled then dummy value will remain
+        */
+       buffer->cmd_class = CLASS_TOKEN_READ;
+       buffer->cmd_select = SELECT_TOKEN_STD;
+       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+       buffer->input[0] = wsmt->location;
+       buffer->output[0] = 99;
+       dell_smbios_smm_call(buffer);
+       if (buffer->output[0] == 99)
+               return true;
+
+       return false;
+}
+
+static int __init dell_smbios_smm_init(void)
+{
+       int ret;
+       /*
+        * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
+        * is passed to SMI handler.
+        */
+       buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
+       if (!buffer)
+               return -ENOMEM;
+
+       dmi_walk(find_cmd_address, NULL);
+
+       if (test_wsmt_enabled()) {
+               pr_debug("Disabling due to WSMT enabled\n");
+               ret = -ENODEV;
+               goto fail_wsmt;
+       }
+
+       platform_device = platform_device_alloc("dell-smbios", 1);
+       if (!platform_device) {
+               ret = -ENOMEM;
+               goto fail_platform_device_alloc;
+       }
+
+       ret = platform_device_add(platform_device);
+       if (ret)
+               goto fail_platform_device_add;
+
+       ret = dell_smbios_register_device(&platform_device->dev,
+                                         &dell_smbios_smm_call);
+       if (ret)
+               goto fail_register;
+
+       return 0;
+
+fail_register:
+       platform_device_del(platform_device);
+
+fail_platform_device_add:
+       platform_device_put(platform_device);
+
+fail_wsmt:
+fail_platform_device_alloc:
+       free_page((unsigned long)buffer);
+       return ret;
+}
+
+static void __exit dell_smbios_smm_exit(void)
+{
+       if (platform_device) {
+               dell_smbios_unregister_device(&platform_device->dev);
+               platform_device_unregister(platform_device);
+               free_page((unsigned long)buffer);
+       }
+}
+
+subsys_initcall(dell_smbios_smm_init);
+module_exit(dell_smbios_smm_exit);
+
+MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
+MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_DESCRIPTION("Dell SMBIOS communications over SMI");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c
new file mode 100644 (file)
index 0000000..0cab1f9
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *  WMI methods for use with dell-smbios
+ *
+ *  Copyright (c) 2017 Dell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/wmi.h>
+#include "dell-smbios.h"
+#include "dell-wmi-descriptor.h"
+
+static DEFINE_MUTEX(call_mutex);
+static DEFINE_MUTEX(list_mutex);
+static int wmi_supported;
+
+struct misc_bios_flags_structure {
+       struct dmi_header header;
+       u16 flags0;
+} __packed;
+#define FLAG_HAS_ACPI_WMI 0x02
+
+#define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
+
+struct wmi_smbios_priv {
+       struct dell_wmi_smbios_buffer *buf;
+       struct list_head list;
+       struct wmi_device *wdev;
+       struct device *child;
+       u32 req_buf_size;
+};
+static LIST_HEAD(wmi_list);
+
+static inline struct wmi_smbios_priv *get_first_smbios_priv(void)
+{
+       return list_first_entry_or_null(&wmi_list,
+                                       struct wmi_smbios_priv,
+                                       list);
+}
+
+static int run_smbios_call(struct wmi_device *wdev)
+{
+       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+       struct wmi_smbios_priv *priv;
+       struct acpi_buffer input;
+       union acpi_object *obj;
+       acpi_status status;
+
+       priv = dev_get_drvdata(&wdev->dev);
+       input.length = priv->req_buf_size - sizeof(u64);
+       input.pointer = &priv->buf->std;
+
+       dev_dbg(&wdev->dev, "evaluating: %u/%u [%x,%x,%x,%x]\n",
+               priv->buf->std.cmd_class, priv->buf->std.cmd_select,
+               priv->buf->std.input[0], priv->buf->std.input[1],
+               priv->buf->std.input[2], priv->buf->std.input[3]);
+
+       status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
+       if (ACPI_FAILURE(status))
+               return -EIO;
+       obj = (union acpi_object *)output.pointer;
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               dev_dbg(&wdev->dev, "received type: %d\n", obj->type);
+               if (obj->type == ACPI_TYPE_INTEGER)
+                       dev_dbg(&wdev->dev, "SMBIOS call failed: %llu\n",
+                               obj->integer.value);
+               return -EIO;
+       }
+       memcpy(&priv->buf->std, obj->buffer.pointer, obj->buffer.length);
+       dev_dbg(&wdev->dev, "result: [%08x,%08x,%08x,%08x]\n",
+               priv->buf->std.output[0], priv->buf->std.output[1],
+               priv->buf->std.output[2], priv->buf->std.output[3]);
+
+       return 0;
+}
+
+int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
+{
+       struct wmi_smbios_priv *priv;
+       size_t difference;
+       size_t size;
+       int ret;
+
+       mutex_lock(&call_mutex);
+       priv = get_first_smbios_priv();
+       if (!priv) {
+               ret = -ENODEV;
+               goto out_wmi_call;
+       }
+
+       size = sizeof(struct calling_interface_buffer);
+       difference = priv->req_buf_size - sizeof(u64) - size;
+
+       memset(&priv->buf->ext, 0, difference);
+       memcpy(&priv->buf->std, buffer, size);
+       ret = run_smbios_call(priv->wdev);
+       memcpy(buffer, &priv->buf->std, size);
+out_wmi_call:
+       mutex_unlock(&call_mutex);
+
+       return ret;
+}
+
+static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd,
+                                  struct wmi_ioctl_buffer *arg)
+{
+       struct wmi_smbios_priv *priv;
+       int ret = 0;
+
+       switch (cmd) {
+       case DELL_WMI_SMBIOS_CMD:
+               mutex_lock(&call_mutex);
+               priv = dev_get_drvdata(&wdev->dev);
+               if (!priv) {
+                       ret = -ENODEV;
+                       goto fail_smbios_cmd;
+               }
+               memcpy(priv->buf, arg, priv->req_buf_size);
+               if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) {
+                       dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n",
+                               priv->buf->std.cmd_class,
+                               priv->buf->std.cmd_select,
+                               priv->buf->std.input[0]);
+                       ret = -EFAULT;
+                       goto fail_smbios_cmd;
+               }
+               ret = run_smbios_call(priv->wdev);
+               if (ret)
+                       goto fail_smbios_cmd;
+               memcpy(arg, priv->buf, priv->req_buf_size);
+fail_smbios_cmd:
+               mutex_unlock(&call_mutex);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+       return ret;
+}
+
+static int dell_smbios_wmi_probe(struct wmi_device *wdev)
+{
+       struct wmi_smbios_priv *priv;
+       int count;
+       int ret;
+
+       ret = dell_wmi_get_descriptor_valid();
+       if (ret)
+               return ret;
+
+       priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       /* WMI buffer size will be either 4k or 32k depending on machine */
+       if (!dell_wmi_get_size(&priv->req_buf_size))
+               return -EPROBE_DEFER;
+
+       /* add in the length object we will use internally with ioctl */
+       priv->req_buf_size += sizeof(u64);
+       ret = set_required_buffer_size(wdev, priv->req_buf_size);
+       if (ret)
+               return ret;
+
+       count = get_order(priv->req_buf_size);
+       priv->buf = (void *)__get_free_pages(GFP_KERNEL, count);
+       if (!priv->buf)
+               return -ENOMEM;
+
+       /* ID is used by dell-smbios to set priority of drivers */
+       wdev->dev.id = 1;
+       ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call);
+       if (ret)
+               goto fail_register;
+
+       priv->wdev = wdev;
+       dev_set_drvdata(&wdev->dev, priv);
+       mutex_lock(&list_mutex);
+       list_add_tail(&priv->list, &wmi_list);
+       mutex_unlock(&list_mutex);
+
+       return 0;
+
+fail_register:
+       free_pages((unsigned long)priv->buf, count);
+       return ret;
+}
+
+static int dell_smbios_wmi_remove(struct wmi_device *wdev)
+{
+       struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev);
+       int count;
+
+       mutex_lock(&call_mutex);
+       mutex_lock(&list_mutex);
+       list_del(&priv->list);
+       mutex_unlock(&list_mutex);
+       dell_smbios_unregister_device(&wdev->dev);
+       count = get_order(priv->req_buf_size);
+       free_pages((unsigned long)priv->buf, count);
+       mutex_unlock(&call_mutex);
+       return 0;
+}
+
+static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
+       { .guid_string = DELL_WMI_SMBIOS_GUID },
+       { },
+};
+
+static void __init parse_b1_table(const struct dmi_header *dm)
+{
+       struct misc_bios_flags_structure *flags =
+       container_of(dm, struct misc_bios_flags_structure, header);
+
+       /* 4 bytes header, 8 bytes flags */
+       if (dm->length < 12)
+               return;
+       if (dm->handle != 0xb100)
+               return;
+       if ((flags->flags0 & FLAG_HAS_ACPI_WMI))
+               wmi_supported = 1;
+}
+
+static void __init find_b1(const struct dmi_header *dm, void *dummy)
+{
+       switch (dm->type) {
+       case 0xb1: /* misc bios flags */
+               parse_b1_table(dm);
+               break;
+       }
+}
+
+static struct wmi_driver dell_smbios_wmi_driver = {
+       .driver = {
+               .name = "dell-smbios",
+       },
+       .probe = dell_smbios_wmi_probe,
+       .remove = dell_smbios_wmi_remove,
+       .id_table = dell_smbios_wmi_id_table,
+       .filter_callback = dell_smbios_wmi_filter,
+};
+
+static int __init init_dell_smbios_wmi(void)
+{
+       dmi_walk(find_b1, NULL);
+
+       if (!wmi_supported)
+               return -ENODEV;
+
+       return wmi_driver_register(&dell_smbios_wmi_driver);
+}
+
+static void __exit exit_dell_smbios_wmi(void)
+{
+       wmi_driver_unregister(&dell_smbios_wmi_driver);
+}
+
+module_init(init_dell_smbios_wmi);
+module_exit(exit_dell_smbios_wmi);
+
+MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID);
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_DESCRIPTION("Dell SMBIOS communications over WMI");
+MODULE_LICENSE("GPL");
index 0a5723468bfffdd6f16df829e5131c90d7e38034..6a60db515bdabcb490410b35ea85bb7a3fd621f1 100644 (file)
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/capability.h>
 #include <linux/dmi.h>
 #include <linux/err.h>
-#include <linux/gfp.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/io.h>
-#include "../../firmware/dcdbas.h"
 #include "dell-smbios.h"
 
-struct calling_interface_structure {
-       struct dmi_header header;
-       u16 cmdIOAddress;
-       u8 cmdIOCode;
-       u32 supportedCmds;
-       struct calling_interface_token tokens[];
-} __packed;
-
-static struct calling_interface_buffer *buffer;
-static DEFINE_MUTEX(buffer_mutex);
-
-static int da_command_address;
-static int da_command_code;
+static u32 da_supported_commands;
 static int da_num_tokens;
+static struct platform_device *platform_device;
 static struct calling_interface_token *da_tokens;
+static struct device_attribute *token_location_attrs;
+static struct device_attribute *token_value_attrs;
+static struct attribute **token_attrs;
+static DEFINE_MUTEX(smbios_mutex);
+
+struct smbios_device {
+       struct list_head list;
+       struct device *device;
+       int (*call_fn)(struct calling_interface_buffer *);
+};
+
+struct smbios_call {
+       u32 need_capability;
+       int cmd_class;
+       int cmd_select;
+};
+
+/* calls that are whitelisted for given capabilities */
+static struct smbios_call call_whitelist[] = {
+       /* generally tokens are allowed, but may be further filtered or
+        * restricted by token blacklist or whitelist
+        */
+       {CAP_SYS_ADMIN, CLASS_TOKEN_READ,       SELECT_TOKEN_STD},
+       {CAP_SYS_ADMIN, CLASS_TOKEN_READ,       SELECT_TOKEN_AC},
+       {CAP_SYS_ADMIN, CLASS_TOKEN_READ,       SELECT_TOKEN_BAT},
+       {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE,      SELECT_TOKEN_STD},
+       {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE,      SELECT_TOKEN_AC},
+       {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE,      SELECT_TOKEN_BAT},
+       /* used by userspace: fwupdate */
+       {CAP_SYS_ADMIN, CLASS_ADMIN_PROP,       SELECT_ADMIN_PROP},
+       /* used by userspace: fwupd */
+       {CAP_SYS_ADMIN, CLASS_INFO,             SELECT_DOCK},
+       {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE,  SELECT_FLASH_INTERFACE},
+};
+
+/* calls that are explicitly blacklisted */
+static struct smbios_call call_blacklist[] = {
+       {0x0000, 01, 07}, /* manufacturing use */
+       {0x0000, 06, 05}, /* manufacturing use */
+       {0x0000, 11, 03}, /* write once */
+       {0x0000, 11, 07}, /* write once */
+       {0x0000, 11, 11}, /* write once */
+       {0x0000, 19, -1}, /* diagnostics */
+       /* handled by kernel: dell-laptop */
+       {0x0000, CLASS_INFO, SELECT_RFKILL},
+       {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT},
+};
+
+struct token_range {
+       u32 need_capability;
+       u16 min;
+       u16 max;
+};
+
+/* tokens that are whitelisted for given capabilities */
+static struct token_range token_whitelist[] = {
+       /* used by userspace: fwupdate */
+       {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN,       CAPSULE_DIS_TOKEN},
+       /* can indicate to userspace that WMI is needed */
+       {0x0000,        WSMT_EN_TOKEN,          WSMT_DIS_TOKEN}
+};
+
+/* tokens that are explicitly blacklisted */
+static struct token_range token_blacklist[] = {
+       {0x0000, 0x0058, 0x0059}, /* ME use */
+       {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */
+       {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */
+       {0x0000, 0x0175, 0x0176}, /* write once */
+       {0x0000, 0x0195, 0x0197}, /* diagnostics */
+       {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */
+       {0x0000, 0x027D, 0x0284}, /* diagnostics */
+       {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */
+       {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */
+       {0x0000, 0x0300, 0x0302}, /* manufacturing use */
+       {0x0000, 0x0325, 0x0326}, /* manufacturing use */
+       {0x0000, 0x0332, 0x0335}, /* fan control */
+       {0x0000, 0x0350, 0x0350}, /* manufacturing use */
+       {0x0000, 0x0363, 0x0363}, /* manufacturing use */
+       {0x0000, 0x0368, 0x0368}, /* manufacturing use */
+       {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */
+       {0x0000, 0x049E, 0x049F}, /* manufacturing use */
+       {0x0000, 0x04A0, 0x04A3}, /* disagnostics */
+       {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */
+       {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */
+       {0x0000, 0x9000, 0x9001}, /* internal BIOS use */
+       {0x0000, 0xA000, 0xBFFF}, /* write only */
+       {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */
+       /* handled by kernel: dell-laptop */
+       {0x0000, BRIGHTNESS_TOKEN,      BRIGHTNESS_TOKEN},
+       {0x0000, KBD_LED_OFF_TOKEN,     KBD_LED_AUTO_TOKEN},
+       {0x0000, KBD_LED_AC_TOKEN,      KBD_LED_AC_TOKEN},
+       {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN},
+       {0x0000, KBD_LED_AUTO_100_TOKEN,        KBD_LED_AUTO_100_TOKEN},
+       {0x0000, GLOBAL_MIC_MUTE_ENABLE,        GLOBAL_MIC_MUTE_DISABLE},
+};
+
+static LIST_HEAD(smbios_device_list);
 
 int dell_smbios_error(int value)
 {
@@ -55,42 +141,175 @@ int dell_smbios_error(int value)
 }
 EXPORT_SYMBOL_GPL(dell_smbios_error);
 
-struct calling_interface_buffer *dell_smbios_get_buffer(void)
+int dell_smbios_register_device(struct device *d, void *call_fn)
 {
-       mutex_lock(&buffer_mutex);
-       dell_smbios_clear_buffer();
-       return buffer;
+       struct smbios_device *priv;
+
+       priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       get_device(d);
+       priv->device = d;
+       priv->call_fn = call_fn;
+       mutex_lock(&smbios_mutex);
+       list_add_tail(&priv->list, &smbios_device_list);
+       mutex_unlock(&smbios_mutex);
+       dev_dbg(d, "Added device: %s\n", d->driver->name);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(dell_smbios_get_buffer);
+EXPORT_SYMBOL_GPL(dell_smbios_register_device);
 
-void dell_smbios_clear_buffer(void)
+void dell_smbios_unregister_device(struct device *d)
 {
-       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+       struct smbios_device *priv;
+
+       mutex_lock(&smbios_mutex);
+       list_for_each_entry(priv, &smbios_device_list, list) {
+               if (priv->device == d) {
+                       list_del(&priv->list);
+                       put_device(d);
+                       break;
+               }
+       }
+       mutex_unlock(&smbios_mutex);
+       dev_dbg(d, "Remove device: %s\n", d->driver->name);
 }
-EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer);
+EXPORT_SYMBOL_GPL(dell_smbios_unregister_device);
 
-void dell_smbios_release_buffer(void)
+int dell_smbios_call_filter(struct device *d,
+                           struct calling_interface_buffer *buffer)
 {
-       mutex_unlock(&buffer_mutex);
+       u16 t = 0;
+       int i;
+
+       /* can't make calls over 30 */
+       if (buffer->cmd_class > 30) {
+               dev_dbg(d, "class too big: %u\n", buffer->cmd_class);
+               return -EINVAL;
+       }
+
+       /* supported calls on the particular system */
+       if (!(da_supported_commands & (1 << buffer->cmd_class))) {
+               dev_dbg(d, "invalid command, supported commands: 0x%8x\n",
+                       da_supported_commands);
+               return -EINVAL;
+       }
+
+       /* match against call blacklist  */
+       for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) {
+               if (buffer->cmd_class != call_blacklist[i].cmd_class)
+                       continue;
+               if (buffer->cmd_select != call_blacklist[i].cmd_select &&
+                   call_blacklist[i].cmd_select != -1)
+                       continue;
+               dev_dbg(d, "blacklisted command: %u/%u\n",
+                       buffer->cmd_class, buffer->cmd_select);
+               return -EINVAL;
+       }
+
+       /* if a token call, find token ID */
+
+       if ((buffer->cmd_class == CLASS_TOKEN_READ ||
+            buffer->cmd_class == CLASS_TOKEN_WRITE) &&
+            buffer->cmd_select < 3) {
+               /* find the matching token ID */
+               for (i = 0; i < da_num_tokens; i++) {
+                       if (da_tokens[i].location != buffer->input[0])
+                               continue;
+                       t = da_tokens[i].tokenID;
+                       break;
+               }
+
+               /* token call; but token didn't exist */
+               if (!t) {
+                       dev_dbg(d, "token at location %04x doesn't exist\n",
+                               buffer->input[0]);
+                       return -EINVAL;
+               }
+
+               /* match against token blacklist */
+               for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) {
+                       if (!token_blacklist[i].min || !token_blacklist[i].max)
+                               continue;
+                       if (t >= token_blacklist[i].min &&
+                           t <= token_blacklist[i].max)
+                               return -EINVAL;
+               }
+
+               /* match against token whitelist */
+               for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) {
+                       if (!token_whitelist[i].min || !token_whitelist[i].max)
+                               continue;
+                       if (t < token_whitelist[i].min ||
+                           t > token_whitelist[i].max)
+                               continue;
+                       if (!token_whitelist[i].need_capability ||
+                           capable(token_whitelist[i].need_capability)) {
+                               dev_dbg(d, "whitelisted token: %x\n", t);
+                               return 0;
+                       }
+
+               }
+       }
+       /* match against call whitelist */
+       for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) {
+               if (buffer->cmd_class != call_whitelist[i].cmd_class)
+                       continue;
+               if (buffer->cmd_select != call_whitelist[i].cmd_select)
+                       continue;
+               if (!call_whitelist[i].need_capability ||
+                   capable(call_whitelist[i].need_capability)) {
+                       dev_dbg(d, "whitelisted capable command: %u/%u\n",
+                       buffer->cmd_class, buffer->cmd_select);
+                       return 0;
+               }
+               dev_dbg(d, "missing capability %d for %u/%u\n",
+                       call_whitelist[i].need_capability,
+                       buffer->cmd_class, buffer->cmd_select);
+
+       }
+
+       /* not in a whitelist, only allow processes with capabilities */
+       if (capable(CAP_SYS_RAWIO)) {
+               dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n",
+                       buffer->cmd_class, buffer->cmd_select);
+               return 0;
+       }
+
+       return -EACCES;
 }
-EXPORT_SYMBOL_GPL(dell_smbios_release_buffer);
+EXPORT_SYMBOL_GPL(dell_smbios_call_filter);
 
-void dell_smbios_send_request(int class, int select)
+int dell_smbios_call(struct calling_interface_buffer *buffer)
 {
-       struct smi_cmd command;
+       int (*call_fn)(struct calling_interface_buffer *) = NULL;
+       struct device *selected_dev = NULL;
+       struct smbios_device *priv;
+       int ret;
 
-       command.magic = SMI_CMD_MAGIC;
-       command.command_address = da_command_address;
-       command.command_code = da_command_code;
-       command.ebx = virt_to_phys(buffer);
-       command.ecx = 0x42534931;
+       mutex_lock(&smbios_mutex);
+       list_for_each_entry(priv, &smbios_device_list, list) {
+               if (!selected_dev || priv->device->id >= selected_dev->id) {
+                       dev_dbg(priv->device, "Trying device ID: %d\n",
+                               priv->device->id);
+                       call_fn = priv->call_fn;
+                       selected_dev = priv->device;
+               }
+       }
+
+       if (!selected_dev) {
+               ret = -ENODEV;
+               pr_err("No dell-smbios drivers are loaded\n");
+               goto out_smbios_call;
+       }
 
-       buffer->class = class;
-       buffer->select = select;
+       ret = call_fn(buffer);
 
-       dcdbas_smi_request(&command);
+out_smbios_call:
+       mutex_unlock(&smbios_mutex);
+       return ret;
 }
-EXPORT_SYMBOL_GPL(dell_smbios_send_request);
+EXPORT_SYMBOL_GPL(dell_smbios_call);
 
 struct calling_interface_token *dell_smbios_find_token(int tokenid)
 {
@@ -139,8 +358,7 @@ static void __init parse_da_table(const struct dmi_header *dm)
        if (dm->length < 17)
                return;
 
-       da_command_address = table->cmdIOAddress;
-       da_command_code = table->cmdIOCode;
+       da_supported_commands = table->supportedCmds;
 
        new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
                                 sizeof(struct calling_interface_token),
@@ -156,6 +374,27 @@ static void __init parse_da_table(const struct dmi_header *dm)
        da_num_tokens += tokens;
 }
 
+static void zero_duplicates(struct device *dev)
+{
+       int i, j;
+
+       for (i = 0; i < da_num_tokens; i++) {
+               if (da_tokens[i].tokenID == 0)
+                       continue;
+               for (j = i+1; j < da_num_tokens; j++) {
+                       if (da_tokens[j].tokenID == 0)
+                               continue;
+                       if (da_tokens[i].tokenID == da_tokens[j].tokenID) {
+                               dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n",
+                                       da_tokens[j].tokenID,
+                                       da_tokens[j].location,
+                                       da_tokens[j].value);
+                               da_tokens[j].tokenID = 0;
+                       }
+               }
+       }
+}
+
 static void __init find_tokens(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
@@ -169,10 +408,160 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
        }
 }
 
+static int match_attribute(struct device *dev,
+                          struct device_attribute *attr)
+{
+       int i;
+
+       for (i = 0; i < da_num_tokens * 2; i++) {
+               if (!token_attrs[i])
+                       continue;
+               if (strcmp(token_attrs[i]->name, attr->attr.name) == 0)
+                       return i/2;
+       }
+       dev_dbg(dev, "couldn't match: %s\n", attr->attr.name);
+       return -EINVAL;
+}
+
+static ssize_t location_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       int i;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       i = match_attribute(dev, attr);
+       if (i > 0)
+               return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location);
+       return 0;
+}
+
+static ssize_t value_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       int i;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       i = match_attribute(dev, attr);
+       if (i > 0)
+               return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value);
+       return 0;
+}
+
+static struct attribute_group smbios_attribute_group = {
+       .name = "tokens"
+};
+
+static struct platform_driver platform_driver = {
+       .driver = {
+               .name = "dell-smbios",
+       },
+};
+
+static int build_tokens_sysfs(struct platform_device *dev)
+{
+       char *location_name;
+       char *value_name;
+       size_t size;
+       int ret;
+       int i, j;
+
+       /* (number of tokens  + 1 for null terminated */
+       size = sizeof(struct device_attribute) * (da_num_tokens + 1);
+       token_location_attrs = kzalloc(size, GFP_KERNEL);
+       if (!token_location_attrs)
+               return -ENOMEM;
+       token_value_attrs = kzalloc(size, GFP_KERNEL);
+       if (!token_value_attrs)
+               goto out_allocate_value;
+
+       /* need to store both location and value + terminator*/
+       size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1);
+       token_attrs = kzalloc(size, GFP_KERNEL);
+       if (!token_attrs)
+               goto out_allocate_attrs;
+
+       for (i = 0, j = 0; i < da_num_tokens; i++) {
+               /* skip empty */
+               if (da_tokens[i].tokenID == 0)
+                       continue;
+               /* add location */
+               location_name = kasprintf(GFP_KERNEL, "%04x_location",
+                                         da_tokens[i].tokenID);
+               if (location_name == NULL)
+                       goto out_unwind_strings;
+               sysfs_attr_init(&token_location_attrs[i].attr);
+               token_location_attrs[i].attr.name = location_name;
+               token_location_attrs[i].attr.mode = 0444;
+               token_location_attrs[i].show = location_show;
+               token_attrs[j++] = &token_location_attrs[i].attr;
+
+               /* add value */
+               value_name = kasprintf(GFP_KERNEL, "%04x_value",
+                                      da_tokens[i].tokenID);
+               if (value_name == NULL)
+                       goto loop_fail_create_value;
+               sysfs_attr_init(&token_value_attrs[i].attr);
+               token_value_attrs[i].attr.name = value_name;
+               token_value_attrs[i].attr.mode = 0444;
+               token_value_attrs[i].show = value_show;
+               token_attrs[j++] = &token_value_attrs[i].attr;
+               continue;
+
+loop_fail_create_value:
+               kfree(value_name);
+               goto out_unwind_strings;
+       }
+       smbios_attribute_group.attrs = token_attrs;
+
+       ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group);
+       if (ret)
+               goto out_unwind_strings;
+       return 0;
+
+out_unwind_strings:
+       for (i = i-1; i > 0; i--) {
+               kfree(token_location_attrs[i].attr.name);
+               kfree(token_value_attrs[i].attr.name);
+       }
+       kfree(token_attrs);
+out_allocate_attrs:
+       kfree(token_value_attrs);
+out_allocate_value:
+       kfree(token_location_attrs);
+
+       return -ENOMEM;
+}
+
+static void free_group(struct platform_device *pdev)
+{
+       int i;
+
+       sysfs_remove_group(&pdev->dev.kobj,
+                               &smbios_attribute_group);
+       for (i = 0; i < da_num_tokens; i++) {
+               kfree(token_location_attrs[i].attr.name);
+               kfree(token_value_attrs[i].attr.name);
+       }
+       kfree(token_attrs);
+       kfree(token_value_attrs);
+       kfree(token_location_attrs);
+}
+
 static int __init dell_smbios_init(void)
 {
+       const struct dmi_device *valid;
        int ret;
 
+       valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL);
+       if (!valid) {
+               pr_err("Unable to run on non-Dell system\n");
+               return -ENODEV;
+       }
+
        dmi_walk(find_tokens, NULL);
 
        if (!da_tokens)  {
@@ -180,27 +569,52 @@ static int __init dell_smbios_init(void)
                return -ENODEV;
        }
 
-       /*
-        * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
-        * is passed to SMI handler.
-        */
-       buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
-       if (!buffer) {
+       ret = platform_driver_register(&platform_driver);
+       if (ret)
+               goto fail_platform_driver;
+
+       platform_device = platform_device_alloc("dell-smbios", 0);
+       if (!platform_device) {
                ret = -ENOMEM;
-               goto fail_buffer;
+               goto fail_platform_device_alloc;
        }
+       ret = platform_device_add(platform_device);
+       if (ret)
+               goto fail_platform_device_add;
+
+       /* duplicate tokens will cause problems building sysfs files */
+       zero_duplicates(&platform_device->dev);
+
+       ret = build_tokens_sysfs(platform_device);
+       if (ret)
+               goto fail_create_group;
 
        return 0;
 
-fail_buffer:
+fail_create_group:
+       platform_device_del(platform_device);
+
+fail_platform_device_add:
+       platform_device_put(platform_device);
+
+fail_platform_device_alloc:
+       platform_driver_unregister(&platform_driver);
+
+fail_platform_driver:
        kfree(da_tokens);
        return ret;
 }
 
 static void __exit dell_smbios_exit(void)
 {
+       mutex_lock(&smbios_mutex);
+       if (platform_device) {
+               free_group(platform_device);
+               platform_device_unregister(platform_device);
+               platform_driver_unregister(&platform_driver);
+       }
        kfree(da_tokens);
-       free_page((unsigned long)buffer);
+       mutex_unlock(&smbios_mutex);
 }
 
 subsys_initcall(dell_smbios_init);
index 45cbc2292cd3d703fae5763d05641c1d3e7ec666..138d478d9adc91bdceee7194567cbe40718ec1f7 100644 (file)
 #ifndef _DELL_SMBIOS_H_
 #define _DELL_SMBIOS_H_
 
-struct notifier_block;
+#include <linux/device.h>
+#include <uapi/linux/wmi.h>
 
-/* This structure will be modified by the firmware when we enter
- * system management mode, hence the volatiles */
+/* Classes and selects used only in kernel drivers */
+#define CLASS_KBD_BACKLIGHT 4
+#define SELECT_KBD_BACKLIGHT 11
 
-struct calling_interface_buffer {
-       u16 class;
-       u16 select;
-       volatile u32 input[4];
-       volatile u32 output[4];
-} __packed;
+/* Tokens used in kernel drivers, any of these
+ * should be filtered from userspace access
+ */
+#define BRIGHTNESS_TOKEN       0x007d
+#define KBD_LED_AC_TOKEN       0x0451
+#define KBD_LED_OFF_TOKEN      0x01E1
+#define KBD_LED_ON_TOKEN       0x01E2
+#define KBD_LED_AUTO_TOKEN     0x01E3
+#define KBD_LED_AUTO_25_TOKEN  0x02EA
+#define KBD_LED_AUTO_50_TOKEN  0x02EB
+#define KBD_LED_AUTO_75_TOKEN  0x02EC
+#define KBD_LED_AUTO_100_TOKEN 0x02F6
+#define GLOBAL_MIC_MUTE_ENABLE 0x0364
+#define GLOBAL_MIC_MUTE_DISABLE        0x0365
+
+struct notifier_block;
 
 struct calling_interface_token {
        u16 tokenID;
@@ -37,12 +49,21 @@ struct calling_interface_token {
        };
 };
 
-int dell_smbios_error(int value);
+struct calling_interface_structure {
+       struct dmi_header header;
+       u16 cmdIOAddress;
+       u8 cmdIOCode;
+       u32 supportedCmds;
+       struct calling_interface_token tokens[];
+} __packed;
 
-struct calling_interface_buffer *dell_smbios_get_buffer(void);
-void dell_smbios_clear_buffer(void);
-void dell_smbios_release_buffer(void);
-void dell_smbios_send_request(int class, int select);
+int dell_smbios_register_device(struct device *d, void *call_fn);
+void dell_smbios_unregister_device(struct device *d);
+
+int dell_smbios_error(int value);
+int dell_smbios_call_filter(struct device *d,
+       struct calling_interface_buffer *buffer);
+int dell_smbios_call(struct calling_interface_buffer *buffer);
 
 struct calling_interface_token *dell_smbios_find_token(int tokenid);
 
index 37e646034ef8c07dbeec5317b64433be6aa1bf49..1d87237bc731b05c4d4706b560fdc45dc407a241 100644 (file)
@@ -90,7 +90,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
                                         struct smo8800_device, miscdev);
 
        u32 data = 0;
-       unsigned char byte_data = 0;
+       unsigned char byte_data;
        ssize_t retval = 1;
 
        if (count < 1)
@@ -103,7 +103,6 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
        if (retval)
                return retval;
 
-       byte_data = 1;
        retval = 1;
 
        if (data < 255)
diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c
new file mode 100644 (file)
index 0000000..4dfef1f
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Dell WMI descriptor driver
+ *
+ * Copyright (C) 2017 Dell Inc. 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+#include "dell-wmi-descriptor.h"
+
+#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
+
+struct descriptor_priv {
+       struct list_head list;
+       u32 interface_version;
+       u32 size;
+};
+static int descriptor_valid = -EPROBE_DEFER;
+static LIST_HEAD(wmi_list);
+static DEFINE_MUTEX(list_mutex);
+
+int dell_wmi_get_descriptor_valid(void)
+{
+       if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID))
+               return -ENODEV;
+
+       return descriptor_valid;
+}
+EXPORT_SYMBOL_GPL(dell_wmi_get_descriptor_valid);
+
+bool dell_wmi_get_interface_version(u32 *version)
+{
+       struct descriptor_priv *priv;
+       bool ret = false;
+
+       mutex_lock(&list_mutex);
+       priv = list_first_entry_or_null(&wmi_list,
+                                       struct descriptor_priv,
+                                       list);
+       if (priv) {
+               *version = priv->interface_version;
+               ret = true;
+       }
+       mutex_unlock(&list_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dell_wmi_get_interface_version);
+
+bool dell_wmi_get_size(u32 *size)
+{
+       struct descriptor_priv *priv;
+       bool ret = false;
+
+       mutex_lock(&list_mutex);
+       priv = list_first_entry_or_null(&wmi_list,
+                                       struct descriptor_priv,
+                                       list);
+       if (priv) {
+               *size = priv->size;
+               ret = true;
+       }
+       mutex_unlock(&list_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dell_wmi_get_size);
+
+/*
+ * Descriptor buffer is 128 byte long and contains:
+ *
+ *       Name             Offset  Length  Value
+ * Vendor Signature          0       4    "DELL"
+ * Object Signature          4       4    " WMI"
+ * WMI Interface Version     8       4    <version>
+ * WMI buffer length        12       4    <length>
+ */
+static int dell_wmi_descriptor_probe(struct wmi_device *wdev)
+{
+       union acpi_object *obj = NULL;
+       struct descriptor_priv *priv;
+       u32 *buffer;
+       int ret;
+
+       obj = wmidev_block_query(wdev, 0);
+       if (!obj) {
+               dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
+               ret = -EINVAL;
+               descriptor_valid = ret;
+               goto out;
+       }
+
+       /* Although it's not technically a failure, this would lead to
+        * unexpected behavior
+        */
+       if (obj->buffer.length != 128) {
+               dev_err(&wdev->dev,
+                       "Dell descriptor buffer has unexpected length (%d)\n",
+                       obj->buffer.length);
+               ret = -EINVAL;
+               descriptor_valid = ret;
+               goto out;
+       }
+
+       buffer = (u32 *)obj->buffer.pointer;
+
+       if (strncmp(obj->string.pointer, "DELL WMI", 8) != 0) {
+               dev_err(&wdev->dev, "Dell descriptor buffer has invalid signature (%8ph)\n",
+                       buffer);
+               ret = -EINVAL;
+               descriptor_valid = ret;
+               goto out;
+       }
+       descriptor_valid = 0;
+
+       if (buffer[2] != 0 && buffer[2] != 1)
+               dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%lu)\n",
+                       (unsigned long) buffer[2]);
+
+       priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv),
+       GFP_KERNEL);
+
+       if (!priv) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       priv->interface_version = buffer[2];
+       priv->size = buffer[3];
+       ret = 0;
+       dev_set_drvdata(&wdev->dev, priv);
+       mutex_lock(&list_mutex);
+       list_add_tail(&priv->list, &wmi_list);
+       mutex_unlock(&list_mutex);
+
+       dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu and buffer size %lu\n",
+               (unsigned long) priv->interface_version,
+               (unsigned long) priv->size);
+
+out:
+       kfree(obj);
+       return ret;
+}
+
+static int dell_wmi_descriptor_remove(struct wmi_device *wdev)
+{
+       struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev);
+
+       mutex_lock(&list_mutex);
+       list_del(&priv->list);
+       mutex_unlock(&list_mutex);
+       return 0;
+}
+
+static const struct wmi_device_id dell_wmi_descriptor_id_table[] = {
+       { .guid_string = DELL_WMI_DESCRIPTOR_GUID },
+       { },
+};
+
+static struct wmi_driver dell_wmi_descriptor_driver = {
+       .driver = {
+               .name = "dell-wmi-descriptor",
+       },
+       .probe = dell_wmi_descriptor_probe,
+       .remove = dell_wmi_descriptor_remove,
+       .id_table = dell_wmi_descriptor_id_table,
+};
+
+module_wmi_driver(dell_wmi_descriptor_driver);
+
+MODULE_ALIAS("wmi:" DELL_WMI_DESCRIPTOR_GUID);
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_DESCRIPTION("Dell WMI descriptor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h
new file mode 100644 (file)
index 0000000..1e8cb96
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Dell WMI descriptor driver
+ *
+ *  Copyright (c) 2017 Dell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef _DELL_WMI_DESCRIPTOR_H_
+#define _DELL_WMI_DESCRIPTOR_H_
+
+#include <linux/wmi.h>
+
+/* possible return values:
+ *  -ENODEV: Descriptor GUID missing from WMI bus
+ *  -EPROBE_DEFER: probing for dell-wmi-descriptor not yet run
+ *  0: valid descriptor, successfully probed
+ *  < 0: invalid descriptor, don't probe dependent devices
+ */
+int dell_wmi_get_descriptor_valid(void);
+
+bool dell_wmi_get_interface_version(u32 *version);
+bool dell_wmi_get_size(u32 *size);
+
+#endif
index 28d9f8696081bcb063a09e9b1c481ede0259e049..39d2f451848332d8346201b9cc1cd08bb5e10427 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/wmi.h>
 #include <acpi/video.h>
 #include "dell-smbios.h"
+#include "dell-wmi-descriptor.h"
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
@@ -46,12 +47,10 @@ MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
 MODULE_LICENSE("GPL");
 
 #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
-#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
 
 static bool wmi_requires_smbios_request;
 
 MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
-MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
 
 struct dell_wmi_priv {
        struct input_dev *input_dev;
@@ -618,78 +617,6 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev)
        input_unregister_device(priv->input_dev);
 }
 
-/*
- * Descriptor buffer is 128 byte long and contains:
- *
- *       Name             Offset  Length  Value
- * Vendor Signature          0       4    "DELL"
- * Object Signature          4       4    " WMI"
- * WMI Interface Version     8       4    <version>
- * WMI buffer length        12       4    4096
- */
-static int dell_wmi_check_descriptor_buffer(struct wmi_device *wdev)
-{
-       struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
-       union acpi_object *obj = NULL;
-       struct wmi_device *desc_dev;
-       u32 *buffer;
-       int ret;
-
-       desc_dev = wmidev_get_other_guid(wdev, DELL_DESCRIPTOR_GUID);
-       if (!desc_dev) {
-               dev_err(&wdev->dev, "Dell WMI descriptor does not exist\n");
-               return -ENODEV;
-       }
-
-       obj = wmidev_block_query(desc_dev, 0);
-       if (!obj) {
-               dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       if (obj->type != ACPI_TYPE_BUFFER) {
-               dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (obj->buffer.length != 128) {
-               dev_err(&wdev->dev,
-                       "Dell descriptor buffer has invalid length (%d)\n",
-                       obj->buffer.length);
-               if (obj->buffer.length < 16) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-       }
-
-       buffer = (u32 *)obj->buffer.pointer;
-
-       if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720)
-               dev_warn(&wdev->dev, "Dell descriptor buffer has invalid signature (%*ph)\n",
-                       8, buffer);
-
-       if (buffer[2] != 0 && buffer[2] != 1)
-               dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%d)\n",
-                       buffer[2]);
-
-       if (buffer[3] != 4096)
-               dev_warn(&wdev->dev, "Dell descriptor buffer has invalid buffer length (%d)\n",
-                       buffer[3]);
-
-       priv->interface_version = buffer[2];
-       ret = 0;
-
-       dev_info(&wdev->dev, "Detected Dell WMI interface version %u\n",
-               priv->interface_version);
-
-out:
-       kfree(obj);
-       put_device(&desc_dev->dev);
-       return ret;
-}
-
 /*
  * According to Dell SMBIOS documentation:
  *
@@ -711,13 +638,16 @@ static int dell_wmi_events_set_enabled(bool enable)
        struct calling_interface_buffer *buffer;
        int ret;
 
-       buffer = dell_smbios_get_buffer();
+       buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
+       buffer->cmd_class = CLASS_INFO;
+       buffer->cmd_select = SELECT_APP_REGISTRATION;
        buffer->input[0] = 0x10000;
        buffer->input[1] = 0x51534554;
        buffer->input[3] = enable;
-       dell_smbios_send_request(17, 3);
-       ret = buffer->output[0];
-       dell_smbios_release_buffer();
+       ret = dell_smbios_call(buffer);
+       if (ret == 0)
+               ret = buffer->output[0];
+       kfree(buffer);
 
        return dell_smbios_error(ret);
 }
@@ -725,7 +655,11 @@ static int dell_wmi_events_set_enabled(bool enable)
 static int dell_wmi_probe(struct wmi_device *wdev)
 {
        struct dell_wmi_priv *priv;
-       int err;
+       int ret;
+
+       ret = dell_wmi_get_descriptor_valid();
+       if (ret)
+               return ret;
 
        priv = devm_kzalloc(
                &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
@@ -733,9 +667,8 @@ static int dell_wmi_probe(struct wmi_device *wdev)
                return -ENOMEM;
        dev_set_drvdata(&wdev->dev, priv);
 
-       err = dell_wmi_check_descriptor_buffer(wdev);
-       if (err)
-               return err;
+       if (!dell_wmi_get_interface_version(&priv->interface_version))
+               return -EPROBE_DEFER;
 
        return dell_wmi_input_setup(wdev);
 }
index 56a8195096a229c6975d3f78746ecbc4c6169660..2cfbd3fa5136002362bdc558c14d00e40ed56e22 100644 (file)
@@ -691,6 +691,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev)
 
 static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
 {
+       struct fujitsu_laptop *priv = acpi_driver_data(device);
        struct led_classdev *led;
        int result;
 
@@ -724,12 +725,15 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
        }
 
        /*
-        * BTNI bit 24 seems to indicate the presence of a radio toggle
-        * button in place of a slide switch, and all such machines appear
-        * to also have an RF LED.  Therefore use bit 24 as an indicator
-        * that an RF LED is present.
+        * Some Fujitsu laptops have a radio toggle button in place of a slide
+        * switch and all such machines appear to also have an RF LED.  Based on
+        * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
+        * S7110, S8420; the first one has a radio toggle button, the other
+        * three have slide switches), bit 17 of flags_supported (the value
+        * returned by method S000 of ACPI device FUJ02E3) seems to indicate
+        * whether given model has a radio toggle button.
         */
-       if (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
+       if (priv->flags_supported & BIT(17)) {
                led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
                if (!led)
                        return -ENOMEM;
index b4ed3dc983d5229c7e1726da58789a937a297d39..b4224389febebe4688ea2195d8a3a786ba3c2081 100644 (file)
@@ -297,7 +297,7 @@ static int hp_wmi_hw_state(int mask)
        if (state < 0)
                return state;
 
-       return state & 0x1;
+       return !!(state & mask);
 }
 
 static int __init hp_wmi_bios_2008_later(void)
index 493d8910a74e2eca10812c3202a74cdb21ed37cd..7b12abe86b94f3f71d1fc9cb85d5828554ee8cfb 100644 (file)
@@ -240,6 +240,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
        AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
        AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd),
+       AXIS_DMI_MATCH("HPB440G4", "HP ProBook 440 G4", x_inverted),
        AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
        AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
        AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
index fe98d4ac0df37040c3da8ad470bf7a33c5477fbe..53ab4e0f896255614b2462d5323a03e53959a73e 100644 (file)
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
                },
        },
+       {
+               .ident = "Lenovo YOGA 920-13IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
+               },
+       },
        {}
 };
 
index e34fd70b67afe4d2573f8c4c39dcc4e1290ef97e..f470279c4c100424815c45dacc1304193677ae8a 100644 (file)
@@ -226,6 +226,24 @@ wakeup:
                return;
        }
 
+       /*
+        * Needed for suspend to work on some platforms that don't expose
+        * the 5-button array, but still send notifies with power button
+        * event code to this device object on power button actions.
+        *
+        * Report the power button press; catch and ignore the button release.
+        */
+       if (!priv->array) {
+               if (event == 0xce) {
+                       input_report_key(priv->input_dev, KEY_POWER, 1);
+                       input_sync(priv->input_dev);
+                       return;
+               }
+
+               if (event == 0xcf)
+                       return;
+       }
+
        /* 0xC0 is for HID events, other values are for 5 button array */
        if (event != 0xc0) {
                if (!priv->array ||
diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c
new file mode 100644 (file)
index 0000000..c2257bd
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * WMI Thunderbolt driver
+ *
+ * Copyright (C) 2017 Dell Inc. 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/wmi.h>
+
+#define INTEL_WMI_THUNDERBOLT_GUID "86CCFD48-205E-4A77-9C48-2021CBEDE341"
+
+static ssize_t force_power_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct acpi_buffer input;
+       acpi_status status;
+       u8 mode;
+
+       input.length = sizeof(u8);
+       input.pointer = &mode;
+       mode = hex_to_bin(buf[0]);
+       if (mode == 0 || mode == 1) {
+               status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1,
+                                            &input, NULL);
+               if (ACPI_FAILURE(status))
+                       return -ENODEV;
+       } else {
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR_WO(force_power);
+
+static struct attribute *tbt_attrs[] = {
+       &dev_attr_force_power.attr,
+       NULL
+};
+
+static const struct attribute_group tbt_attribute_group = {
+       .attrs = tbt_attrs,
+};
+
+static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev)
+{
+       int ret;
+
+       ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group);
+       kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
+       return ret;
+}
+
+static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
+{
+       sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group);
+       kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
+       return 0;
+}
+
+static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
+       { .guid_string = INTEL_WMI_THUNDERBOLT_GUID },
+       { },
+};
+
+static struct wmi_driver intel_wmi_thunderbolt_driver = {
+       .driver = {
+               .name = "intel-wmi-thunderbolt",
+       },
+       .probe = intel_wmi_thunderbolt_probe,
+       .remove = intel_wmi_thunderbolt_remove,
+       .id_table = intel_wmi_thunderbolt_id_table,
+};
+
+module_wmi_driver(intel_wmi_thunderbolt_driver);
+
+MODULE_ALIAS("wmi:" INTEL_WMI_THUNDERBOLT_GUID);
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver");
+MODULE_LICENSE("GPL");
index da706e2c4232cf25d40aefd52f54a910ab437e6f..380ef7ec094f309d42e30a08c97924b22c8496ce 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
 #define EXPECTED_PTYPE         4
@@ -34,6 +35,42 @@ struct cht_int33fe_data {
        struct i2c_client *pi3usb30532;
 };
 
+/*
+ * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
+ * the max17047 both through the INT33FE ACPI device (it is right there
+ * in the resources table) as well as through a separate MAX17047 device.
+ *
+ * These helpers are used to work around this by checking if an i2c-client
+ * for the max17047 has already been registered.
+ */
+static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
+{
+       struct i2c_client **max17047 = data;
+       struct acpi_device *adev;
+       const char *hid;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return 0;
+
+       hid = acpi_device_hid(adev);
+
+       /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */
+       if (strcmp(hid, "MAX17047"))
+               return 0;
+
+       *max17047 = to_i2c_client(dev);
+       return 1;
+}
+
+static struct i2c_client *cht_int33fe_find_max17047(void)
+{
+       struct i2c_client *max17047 = NULL;
+
+       i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
+       return max17047;
+}
+
 static const char * const max17047_suppliers[] = { "bq24190-charger" };
 
 static const struct property_entry max17047_props[] = {
@@ -41,14 +78,25 @@ static const struct property_entry max17047_props[] = {
        { }
 };
 
+static const struct property_entry fusb302_props[] = {
+       PROPERTY_ENTRY_STRING("fcs,extcon-name", "cht_wcove_pwrsrc"),
+       PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000),
+       PROPERTY_ENTRY_U32("fcs,max-sink-microamp",   3000000),
+       PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000),
+       { }
+};
+
 static int cht_int33fe_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct i2c_board_info board_info;
        struct cht_int33fe_data *data;
+       struct i2c_client *max17047;
+       struct regulator *regulator;
        unsigned long long ptyp;
        acpi_status status;
        int fusb302_irq;
+       int ret;
 
        status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
        if (ACPI_FAILURE(status)) {
@@ -63,6 +111,34 @@ static int cht_int33fe_probe(struct i2c_client *client)
        if (ptyp != EXPECTED_PTYPE)
                return -ENODEV;
 
+       /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */
+       if (!acpi_dev_present("INT34D3", "1", 3)) {
+               dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n",
+                       EXPECTED_PTYPE);
+               return -ENODEV;
+       }
+
+       /*
+        * We expect the WC PMIC to be paired with a TI bq24292i charger-IC.
+        * We check for the bq24292i vbus regulator here, this has 2 purposes:
+        * 1) The bq24292i allows charging with up to 12V, setting the fusb302's
+        *    max-snk voltage to 12V with another charger-IC is not good.
+        * 2) For the fusb302 driver to get the bq24292i vbus regulator, the
+        *    regulator-map, which is part of the bq24292i regulator_init_data,
+        *    must be registered before the fusb302 is instantiated, otherwise
+        *    it will end up with a dummy-regulator.
+        * Note "cht_wc_usb_typec_vbus" comes from the regulator_init_data
+        * which is defined in i2c-cht-wc.c from where the bq24292i i2c-client
+        * gets instantiated. We use regulator_get_optional here so that we
+        * don't end up getting a dummy-regulator ourselves.
+        */
+       regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus");
+       if (IS_ERR(regulator)) {
+               ret = PTR_ERR(regulator);
+               return (ret == -ENODEV) ? -EPROBE_DEFER : ret;
+       }
+       regulator_put(regulator);
+
        /* The FUSB302 uses the irq at index 1 and is the only irq user */
        fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
        if (fusb302_irq < 0) {
@@ -75,16 +151,31 @@ static int cht_int33fe_probe(struct i2c_client *client)
        if (!data)
                return -ENOMEM;
 
-       memset(&board_info, 0, sizeof(board_info));
-       strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
-       board_info.properties = max17047_props;
-
-       data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
-       if (!data->max17047)
-               return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
+       /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */
+       max17047 = cht_int33fe_find_max17047();
+       if (max17047) {
+               /* Pre-existing i2c-client for the max17047, add device-props */
+               ret = device_add_properties(&max17047->dev, max17047_props);
+               if (ret)
+                       return ret;
+               /* And re-probe to get the new device-props applied. */
+               ret = device_reprobe(&max17047->dev);
+               if (ret)
+                       dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
+       } else {
+               memset(&board_info, 0, sizeof(board_info));
+               strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
+               board_info.dev_name = "max17047";
+               board_info.properties = max17047_props;
+               data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
+               if (!data->max17047)
+                       return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
+       }
 
        memset(&board_info, 0, sizeof(board_info));
-       strlcpy(board_info.type, "fusb302", I2C_NAME_SIZE);
+       strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
+       board_info.dev_name = "fusb302";
+       board_info.properties = fusb302_props;
        board_info.irq = fusb302_irq;
 
        data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
@@ -92,6 +183,7 @@ static int cht_int33fe_probe(struct i2c_client *client)
                goto out_unregister_max17047;
 
        memset(&board_info, 0, sizeof(board_info));
+       board_info.dev_name = "pi3usb30532";
        strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
 
        data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
@@ -106,7 +198,8 @@ out_unregister_fusb302:
        i2c_unregister_device(data->fusb302);
 
 out_unregister_max17047:
-       i2c_unregister_device(data->max17047);
+       if (data->max17047)
+               i2c_unregister_device(data->max17047);
 
        return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
 }
@@ -117,7 +210,8 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
 
        i2c_unregister_device(data->pi3usb30532);
        i2c_unregister_device(data->fusb302);
-       i2c_unregister_device(data->max17047);
+       if (data->max17047)
+               i2c_unregister_device(data->max17047);
 
        return 0;
 }
index 58dcee562d6417be3e1d7ee52fc91c384469cffa..a0c95853fd3f98abbe1979ad2478d6b781c7b046 100644 (file)
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
  * The full GNU General Public License is included in this distribution in
  * the file called "COPYING".
  *
@@ -259,8 +255,6 @@ static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */
 
 /* Per-SKU limits */
 struct ips_mcp_limits {
-       int cpu_family;
-       int cpu_model; /* includes extended model... */
        int mcp_power_limit; /* mW units */
        int core_power_limit;
        int mch_power_limit;
@@ -295,11 +289,14 @@ static struct ips_mcp_limits ips_ulv_limits = {
 };
 
 struct ips_driver {
-       struct pci_dev *dev;
-       void *regmap;
+       struct device *dev;
+       void __iomem *regmap;
+       int irq;
+
        struct task_struct *monitor;
        struct task_struct *adjust;
        struct dentry *debug_root;
+       struct timer_list timer;
 
        /* Average CPU core temps (all averages in .01 degrees C for precision) */
        u16 ctv1_avg_temp;
@@ -594,7 +591,7 @@ static void ips_disable_gpu_turbo(struct ips_driver *ips)
                return;
 
        if (!ips->gpu_turbo_disable())
-               dev_err(&ips->dev->dev, "failed to disable graphics turbo\n");
+               dev_err(ips->dev, "failed to disable graphics turbo\n");
        else
                ips->__gpu_turbo_on = false;
 }
@@ -649,8 +646,7 @@ static bool cpu_exceeded(struct ips_driver *ips, int cpu)
        spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
 
        if (ret)
-               dev_info(&ips->dev->dev,
-                        "CPU power or thermal limit exceeded\n");
+               dev_info(ips->dev, "CPU power or thermal limit exceeded\n");
 
        return ret;
 }
@@ -769,7 +765,7 @@ static int ips_adjust(void *data)
        struct ips_driver *ips = data;
        unsigned long flags;
 
-       dev_dbg(&ips->dev->dev, "starting ips-adjust thread\n");
+       dev_dbg(ips->dev, "starting ips-adjust thread\n");
 
        /*
         * Adjust CPU and GPU clamps every 5s if needed.  Doing it more
@@ -816,7 +812,7 @@ sleep:
                schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD));
        } while (!kthread_should_stop());
 
-       dev_dbg(&ips->dev->dev, "ips-adjust thread stopped\n");
+       dev_dbg(ips->dev, "ips-adjust thread stopped\n");
 
        return 0;
 }
@@ -942,9 +938,10 @@ static u32 calc_avg_power(struct ips_driver *ips, u32 *array)
        return avg;
 }
 
-static void monitor_timeout(unsigned long arg)
+static void monitor_timeout(struct timer_list *t)
 {
-       wake_up_process((struct task_struct *)arg);
+       struct ips_driver *ips = from_timer(ips, t, timer);
+       wake_up_process(ips->monitor);
 }
 
 /**
@@ -961,7 +958,6 @@ static void monitor_timeout(unsigned long arg)
 static int ips_monitor(void *data)
 {
        struct ips_driver *ips = data;
-       struct timer_list timer;
        unsigned long seqno_timestamp, expire, last_msecs, last_sample_period;
        int i;
        u32 *cpu_samples, *mchp_samples, old_cpu_power;
@@ -976,7 +972,7 @@ static int ips_monitor(void *data)
        mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
        if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples ||
                        !cpu_samples || !mchp_samples) {
-               dev_err(&ips->dev->dev,
+               dev_err(ips->dev,
                        "failed to allocate sample array, ips disabled\n");
                kfree(mcp_samples);
                kfree(ctv1_samples);
@@ -1049,8 +1045,7 @@ static int ips_monitor(void *data)
        schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
        last_sample_period = IPS_SAMPLE_PERIOD;
 
-       setup_deferrable_timer_on_stack(&timer, monitor_timeout,
-                                       (unsigned long)current);
+       timer_setup(&ips->timer, monitor_timeout, TIMER_DEFERRABLE);
        do {
                u32 cpu_val, mch_val;
                u16 val;
@@ -1097,7 +1092,8 @@ static int ips_monitor(void *data)
                        ITV_ME_SEQNO_SHIFT;
                if (cur_seqno == last_seqno &&
                    time_after(jiffies, seqno_timestamp + HZ)) {
-                       dev_warn(&ips->dev->dev, "ME failed to update for more than 1s, likely hung\n");
+                       dev_warn(ips->dev,
+                                "ME failed to update for more than 1s, likely hung\n");
                } else {
                        seqno_timestamp = get_jiffies_64();
                        last_seqno = cur_seqno;
@@ -1107,7 +1103,7 @@ static int ips_monitor(void *data)
                expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
 
                __set_current_state(TASK_INTERRUPTIBLE);
-               mod_timer(&timer, expire);
+               mod_timer(&ips->timer, expire);
                schedule();
 
                /* Calculate actual sample period for power averaging */
@@ -1116,10 +1112,9 @@ static int ips_monitor(void *data)
                        last_sample_period = 1;
        } while (!kthread_should_stop());
 
-       del_timer_sync(&timer);
-       destroy_timer_on_stack(&timer);
+       del_timer_sync(&ips->timer);
 
-       dev_dbg(&ips->dev->dev, "ips-monitor thread stopped\n");
+       dev_dbg(ips->dev, "ips-monitor thread stopped\n");
 
        return 0;
 }
@@ -1128,17 +1123,17 @@ static int ips_monitor(void *data)
 #define THM_DUMPW(reg) \
        { \
        u16 val = thm_readw(reg); \
-       dev_dbg(&ips->dev->dev, #reg ": 0x%04x\n", val); \
+       dev_dbg(ips->dev, #reg ": 0x%04x\n", val); \
        }
 #define THM_DUMPL(reg) \
        { \
        u32 val = thm_readl(reg); \
-       dev_dbg(&ips->dev->dev, #reg ": 0x%08x\n", val); \
+       dev_dbg(ips->dev, #reg ": 0x%08x\n", val); \
        }
 #define THM_DUMPQ(reg) \
        { \
        u64 val = thm_readq(reg); \
-       dev_dbg(&ips->dev->dev, #reg ": 0x%016x\n", val); \
+       dev_dbg(ips->dev, #reg ": 0x%016x\n", val); \
        }
 
 static void dump_thermal_info(struct ips_driver *ips)
@@ -1146,7 +1141,7 @@ static void dump_thermal_info(struct ips_driver *ips)
        u16 ptl;
 
        ptl = thm_readw(THM_PTL);
-       dev_dbg(&ips->dev->dev, "Processor temp limit: %d\n", ptl);
+       dev_dbg(ips->dev, "Processor temp limit: %d\n", ptl);
 
        THM_DUMPW(THM_CTA);
        THM_DUMPW(THM_TRC);
@@ -1175,8 +1170,8 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
        if (!tses && !tes)
                return IRQ_NONE;
 
-       dev_info(&ips->dev->dev, "TSES: 0x%02x\n", tses);
-       dev_info(&ips->dev->dev, "TES: 0x%02x\n", tes);
+       dev_info(ips->dev, "TSES: 0x%02x\n", tses);
+       dev_info(ips->dev, "TES: 0x%02x\n", tes);
 
        /* STS update from EC? */
        if (tes & 1) {
@@ -1214,8 +1209,8 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
 
        /* Thermal trip */
        if (tses) {
-               dev_warn(&ips->dev->dev,
-                        "thermal trip occurred, tses: 0x%04x\n", tses);
+               dev_warn(ips->dev, "thermal trip occurred, tses: 0x%04x\n",
+                        tses);
                thm_writeb(THM_TSES, tses);
        }
 
@@ -1330,8 +1325,7 @@ static void ips_debugfs_init(struct ips_driver *ips)
 
        ips->debug_root = debugfs_create_dir("ips", NULL);
        if (!ips->debug_root) {
-               dev_err(&ips->dev->dev,
-                       "failed to create debugfs entries: %ld\n",
+               dev_err(ips->dev, "failed to create debugfs entries: %ld\n",
                        PTR_ERR(ips->debug_root));
                return;
        }
@@ -1345,8 +1339,7 @@ static void ips_debugfs_init(struct ips_driver *ips)
                                          ips->debug_root, node,
                                          &ips_debugfs_ops);
                if (!ent) {
-                       dev_err(&ips->dev->dev,
-                               "failed to create debug file: %ld\n",
+                       dev_err(ips->dev, "failed to create debug file: %ld\n",
                                PTR_ERR(ent));
                        goto err_cleanup;
                }
@@ -1373,8 +1366,8 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
        u16 tdp;
 
        if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) {
-               dev_info(&ips->dev->dev, "Non-IPS CPU detected.\n");
-               goto out;
+               dev_info(ips->dev, "Non-IPS CPU detected.\n");
+               return NULL;
        }
 
        rdmsrl(IA32_MISC_ENABLE, misc_en);
@@ -1395,8 +1388,8 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
        else if (strstr(boot_cpu_data.x86_model_id, "CPU       U"))
                limits = &ips_ulv_limits;
        else {
-               dev_info(&ips->dev->dev, "No CPUID match found.\n");
-               goto out;
+               dev_info(ips->dev, "No CPUID match found.\n");
+               return NULL;
        }
 
        rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power);
@@ -1404,12 +1397,12 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
 
        /* Sanity check TDP against CPU */
        if (limits->core_power_limit != (tdp / 8) * 1000) {
-               dev_info(&ips->dev->dev, "CPU TDP doesn't match expected value (found %d, expected %d)\n",
+               dev_info(ips->dev,
+                        "CPU TDP doesn't match expected value (found %d, expected %d)\n",
                         tdp / 8, limits->core_power_limit / 1000);
                limits->core_power_limit = (tdp / 8) * 1000;
        }
 
-out:
        return limits;
 }
 
@@ -1459,7 +1452,7 @@ ips_gpu_turbo_enabled(struct ips_driver *ips)
 {
        if (!ips->gpu_busy && late_i915_load) {
                if (ips_get_i915_syms(ips)) {
-                       dev_info(&ips->dev->dev,
+                       dev_info(ips->dev,
                                 "i915 driver attached, reenabling gpu turbo\n");
                        ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS);
                }
@@ -1480,8 +1473,7 @@ ips_link_to_i915_driver(void)
 EXPORT_SYMBOL_GPL(ips_link_to_i915_driver);
 
 static const struct pci_device_id ips_id_table[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-                    PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
        { 0, }
 };
 
@@ -1517,62 +1509,45 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (dmi_check_system(ips_blacklist))
                return -ENODEV;
 
-       ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL);
+       ips = devm_kzalloc(&dev->dev, sizeof(*ips), GFP_KERNEL);
        if (!ips)
                return -ENOMEM;
 
-       pci_set_drvdata(dev, ips);
-       ips->dev = dev;
+       spin_lock_init(&ips->turbo_status_lock);
+       ips->dev = &dev->dev;
 
        ips->limits = ips_detect_cpu(ips);
        if (!ips->limits) {
                dev_info(&dev->dev, "IPS not supported on this CPU\n");
-               ret = -ENXIO;
-               goto error_free;
+               return -ENXIO;
        }
 
-       spin_lock_init(&ips->turbo_status_lock);
-
-       ret = pci_enable_device(dev);
+       ret = pcim_enable_device(dev);
        if (ret) {
                dev_err(&dev->dev, "can't enable PCI device, aborting\n");
-               goto error_free;
+               return ret;
        }
 
-       if (!pci_resource_start(dev, 0)) {
-               dev_err(&dev->dev, "TBAR not assigned, aborting\n");
-               ret = -ENXIO;
-               goto error_free;
-       }
-
-       ret = pci_request_regions(dev, "ips thermal sensor");
+       ret = pcim_iomap_regions(dev, 1 << 0, pci_name(dev));
        if (ret) {
-               dev_err(&dev->dev, "thermal resource busy, aborting\n");
-               goto error_free;
-       }
-
-
-       ips->regmap = ioremap(pci_resource_start(dev, 0),
-                             pci_resource_len(dev, 0));
-       if (!ips->regmap) {
                dev_err(&dev->dev, "failed to map thermal regs, aborting\n");
-               ret = -EBUSY;
-               goto error_release;
+               return ret;
        }
+       ips->regmap = pcim_iomap_table(dev)[0];
+
+       pci_set_drvdata(dev, ips);
 
        tse = thm_readb(THM_TSE);
        if (tse != TSE_EN) {
                dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse);
-               ret = -ENXIO;
-               goto error_unmap;
+               return -ENXIO;
        }
 
        trc = thm_readw(THM_TRC);
        trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN;
        if ((trc & trc_required_mask) != trc_required_mask) {
                dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n");
-               ret = -ENXIO;
-               goto error_unmap;
+               return -ENXIO;
        }
 
        if (trc & TRC_CORE2_EN)
@@ -1602,20 +1577,23 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
        rdmsrl(PLATFORM_INFO, platform_info);
        if (!(platform_info & PLATFORM_TDP)) {
                dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n");
-               ret = -ENODEV;
-               goto error_unmap;
+               return -ENODEV;
        }
 
        /*
         * IRQ handler for ME interaction
         * Note: don't use MSI here as the PCH has bugs.
         */
-       pci_disable_msi(dev);
-       ret = request_irq(dev->irq, ips_irq_handler, IRQF_SHARED, "ips",
-                         ips);
+       ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
+       if (ret < 0)
+               return ret;
+
+       ips->irq = pci_irq_vector(dev, 0);
+
+       ret = request_irq(ips->irq, ips_irq_handler, IRQF_SHARED, "ips", ips);
        if (ret) {
                dev_err(&dev->dev, "request irq failed, aborting\n");
-               goto error_unmap;
+               return ret;
        }
 
        /* Enable aux, hot & critical interrupts */
@@ -1672,13 +1650,8 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
 error_thread_cleanup:
        kthread_stop(ips->adjust);
 error_free_irq:
-       free_irq(ips->dev->irq, ips);
-error_unmap:
-       iounmap(ips->regmap);
-error_release:
-       pci_release_regions(dev);
-error_free:
-       kfree(ips);
+       free_irq(ips->irq, ips);
+       pci_free_irq_vectors(dev);
        return ret;
 }
 
@@ -1709,27 +1682,20 @@ static void ips_remove(struct pci_dev *dev)
        wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
        wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
 
-       free_irq(ips->dev->irq, ips);
+       free_irq(ips->irq, ips);
+       pci_free_irq_vectors(dev);
        if (ips->adjust)
                kthread_stop(ips->adjust);
        if (ips->monitor)
                kthread_stop(ips->monitor);
-       iounmap(ips->regmap);
-       pci_release_regions(dev);
-       kfree(ips);
        dev_dbg(&dev->dev, "IPS driver removed\n");
 }
 
-static void ips_shutdown(struct pci_dev *dev)
-{
-}
-
 static struct pci_driver ips_pci_driver = {
        .name = "intel ips",
        .id_table = ips_id_table,
        .probe = ips_probe,
        .remove = ips_remove,
-       .shutdown = ips_shutdown,
 };
 
 module_pci_driver(ips_pci_driver);
index 73299beff5b358b8ba5825d5d83d88d1182e333b..60f4e3ddbe9f5b3f84e02030a57b98793141e615 100644 (file)
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
  * The full GNU General Public License is included in this distribution in
  * the file called "COPYING".
  */
index a47a41fc10ad77c427158811857da4bc21cd747f..b5b890127479f8f586880762828bbd447a383ddf 100644 (file)
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
         * - GTDRIVER_IPC BASE_IFACE
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-       if (res) {
+       if (res && resource_size(res) > 1) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-       if (res) {
+       if (res && resource_size(res) > 1) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
-       if (res) {
+       if (res && resource_size(res) > 1) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
-       if (res) {
+       if (res && resource_size(res) > 1) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
index 0d4c3808a6d892f38b0bf6f3ae87dc9f8ae8dba0..f378621b5fe9d86632a853a33599b1efff88b05a 100644 (file)
@@ -15,9 +15,8 @@
  * Telemetry Framework provides platform related PM and performance statistics.
  * This file provides the core telemetry API implementation.
  */
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
+#include <linux/module.h>
 
 #include <asm/intel_telemetry.h>
 
index d4fc42b4cbebfedeeaf39e8c65e28b2d0a8b6c0a..4249e8267bbcfc321bd83ac678c20de8f967b584 100644 (file)
  * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing
  *                             Verbosity via firmware
  */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/seq_file.h>
 #include <linux/suspend.h>
 
 #include <asm/cpu_device_id.h>
@@ -76,8 +74,6 @@
 #define TELEM_IOSS_DX_D0IX_EVTS                25
 #define TELEM_IOSS_PG_EVTS             30
 
-#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
-
 #define TELEM_DEBUGFS_CPU(model, data) \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data}
 
@@ -304,13 +300,13 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
        .ioss_d0ix_data = telem_apl_ioss_d0ix_data,
        .ioss_pg_data = telem_apl_ioss_pg_data,
 
-       .pss_idle_evts = TELEM_EVT_LEN(telem_apl_pss_idle_data),
-       .pcs_idle_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_idle_blkd_data),
-       .pcs_s0ix_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_s0ix_blkd_data),
-       .pss_ltr_evts = TELEM_EVT_LEN(telem_apl_pss_ltr_data),
-       .pss_wakeup_evts = TELEM_EVT_LEN(telem_apl_pss_wakeup),
-       .ioss_d0ix_evts = TELEM_EVT_LEN(telem_apl_ioss_d0ix_data),
-       .ioss_pg_evts = TELEM_EVT_LEN(telem_apl_ioss_pg_data),
+       .pss_idle_evts = ARRAY_SIZE(telem_apl_pss_idle_data),
+       .pcs_idle_blkd_evts = ARRAY_SIZE(telem_apl_pcs_idle_blkd_data),
+       .pcs_s0ix_blkd_evts = ARRAY_SIZE(telem_apl_pcs_s0ix_blkd_data),
+       .pss_ltr_evts = ARRAY_SIZE(telem_apl_pss_ltr_data),
+       .pss_wakeup_evts = ARRAY_SIZE(telem_apl_pss_wakeup),
+       .ioss_d0ix_evts = ARRAY_SIZE(telem_apl_ioss_d0ix_data),
+       .ioss_pg_evts = ARRAY_SIZE(telem_apl_ioss_pg_data),
 
        .pstates_id = TELEM_APL_PSS_PSTATES_ID,
        .pss_idle_id = TELEM_APL_PSS_IDLE_ID,
index e0424d5a795a5e0a5baa969546df60252c9a230e..2f889d6c270e85c50fd8296af3636cc216e84ed9 100644 (file)
  * It used the PUNIT and PMC IPC interfaces for configuring the counters.
  * The accumulated results are fetched from SRAM.
  */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
+
 #include <linux/io.h>
-#include <linux/uaccess.h>
-#include <linux/pci.h>
-#include <linux/suspend.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <asm/cpu_device_id.h>
@@ -256,7 +250,7 @@ static int telemetry_check_evtid(enum telemetry_unit telem_unit,
                break;
 
        default:
-               pr_err("Unknown Telemetry action Specified %d\n", action);
+               pr_err("Unknown Telemetry action specified %d\n", action);
                return -EINVAL;
        }
 
@@ -659,7 +653,7 @@ static int telemetry_setup(struct platform_device *pdev)
        ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
                                        TELEM_RESET);
        if (ret) {
-               dev_err(&pdev->dev, "TELEMTRY Setup Failed\n");
+               dev_err(&pdev->dev, "TELEMETRY Setup Failed\n");
                return ret;
        }
        return 0;
@@ -685,7 +679,7 @@ static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig,
        ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
                                        TELEM_UPDATE);
        if (ret)
-               pr_err("TELEMTRY Config Failed\n");
+               pr_err("TELEMETRY Config Failed\n");
 
        return ret;
 }
@@ -822,7 +816,7 @@ static int telemetry_plt_reset_events(void)
        ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
                                        TELEM_RESET);
        if (ret)
-               pr_err("TELEMTRY Reset Failed\n");
+               pr_err("TELEMETRY Reset Failed\n");
 
        return ret;
 }
@@ -885,7 +879,7 @@ static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts,
        ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
                                        TELEM_ADD);
        if (ret)
-               pr_err("TELEMTRY ADD Failed\n");
+               pr_err("TELEMETRY ADD Failed\n");
 
        return ret;
 }
@@ -1195,7 +1189,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 
        ret = telemetry_set_pltdata(&telm_pltops, telm_conf);
        if (ret) {
-               dev_err(&pdev->dev, "TELEMTRY Set Pltops Failed.\n");
+               dev_err(&pdev->dev, "TELEMETRY Set Pltops Failed.\n");
                goto out;
        }
 
@@ -1210,7 +1204,7 @@ out:
                iounmap(telm_conf->pss_config.regmap);
        if (telm_conf->ioss_config.regmap)
                iounmap(telm_conf->ioss_config.regmap);
-       dev_err(&pdev->dev, "TELEMTRY Setup Failed.\n");
+       dev_err(&pdev->dev, "TELEMETRY Setup Failed.\n");
 
        return ret;
 }
@@ -1234,7 +1228,6 @@ static struct platform_driver telemetry_soc_driver = {
 
 static int __init telemetry_module_init(void)
 {
-       pr_info(DRIVER_NAME ": version %s loaded\n", DRIVER_VERSION);
        return platform_driver_register(&telemetry_soc_driver);
 }
 
index 4f60d8e32a0a538b9632d809d5e52186007d1db3..d4ea01805879b4c9049b1657fad6f6ddb9de27d9 100644 (file)
@@ -125,6 +125,7 @@ static int itmt_legacy_cpu_online(unsigned int cpu)
 
 static const struct x86_cpu_id itmt_legacy_cpu_ids[] = {
        ICPU(INTEL_FAM6_BROADWELL_X),
+       ICPU(INTEL_FAM6_SKYLAKE_X),
        {}
 };
 
index 4f3de2a8c4dfe4fd594a44d9fa9081a9157b9069..504256c3660d84e15444d265ca1fd9747f4fc0dc 100644 (file)
@@ -216,8 +216,8 @@ static struct resource mlxplat_mlxcpld_resources[] = {
        [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
 };
 
-struct platform_device *mlxplat_dev;
-struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
+static struct platform_device *mlxplat_dev;
+static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
 
 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
 {
index bc98ef95514a1770c285ed54b4913d7c41ff5ad6..9b9e1f39bbfbb8a75a643783072080bc10b10735 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/input-polldev.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -64,8 +65,23 @@ static void peaq_wmi_poll(struct input_polled_dev *dev)
        }
 }
 
+/* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */
+static const struct dmi_system_id peaq_dmi_table[] __initconst = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
+               },
+       },
+       {}
+};
+
 static int __init peaq_wmi_init(void)
 {
+       /* WMI GUID is not unique, also check for a DMI match */
+       if (!dmi_check_system(peaq_dmi_table))
+               return -ENODEV;
+
        if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
                return -ENODEV;
 
@@ -86,9 +102,6 @@ static int __init peaq_wmi_init(void)
 
 static void __exit peaq_wmi_exit(void)
 {
-       if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
-               return;
-
        input_unregister_polled_device(peaq_poll_dev);
 }
 
index 1157a7b646d66c17682e985eb22d81e6bea7ab45..266535c2a72f21dc7309962542bd71b68fe9b98f 100644 (file)
@@ -58,6 +58,7 @@ static const struct property_entry dexp_ursus_7w_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-y", 630),
        PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"),
        PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
        { }
 };
 
@@ -72,6 +73,7 @@ static const struct property_entry surftab_wintron70_st70416_6_props[] = {
        PROPERTY_ENTRY_STRING("firmware-name",
                              "gsl1686-surftab-wintron70-st70416-6.fw"),
        PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
        { }
 };
 
@@ -83,6 +85,8 @@ static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = {
 static const struct property_entry gp_electronic_t701_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
        PROPERTY_ENTRY_STRING("firmware-name",
                              "gsl1680-gp-electronic-t701.fw"),
        { }
@@ -114,6 +118,7 @@ static const struct property_entry pov_mobii_wintab_p800w_props[] = {
        PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
        PROPERTY_ENTRY_STRING("firmware-name",
                              "gsl3692-pov-mobii-wintab-p800w.fw"),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
        { }
 };
 
@@ -136,6 +141,36 @@ static const struct silead_ts_dmi_data itworks_tw891_data = {
        .properties     = itworks_tw891_props,
 };
 
+static const struct property_entry chuwi_hi8_pro_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct silead_ts_dmi_data chuwi_hi8_pro_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = chuwi_hi8_pro_props,
+};
+
+static const struct property_entry digma_citi_e200_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_STRING("firmware-name",
+                             "gsl1686-digma_citi_e200.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct silead_ts_dmi_data digma_citi_e200_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = digma_citi_e200_props,
+};
+
 static const struct dmi_system_id silead_ts_dmi_table[] = {
        {
                /* CUBE iwork8 Air */
@@ -219,6 +254,23 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "TW891"),
                },
        },
+       {
+               /* Chuwi Hi8 Pro */
+               .driver_data = (void *)&chuwi_hi8_pro_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"),
+               },
+       },
+       {
+               /* Digma Citi E200 */
+               .driver_data = (void *)&digma_citi_e200_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Digma"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+               },
+       },
        { },
 };
 
index a16cea2be9c34a0c83d17a6ce7a35a1704956682..62aa2c37b8d2821450008fb820cbd7be9552f6a7 100644 (file)
@@ -1627,7 +1627,7 @@ static const struct rfkill_ops sony_rfkill_ops = {
 static int sony_nc_setup_rfkill(struct acpi_device *device,
                                enum sony_nc_rfkill nc_type)
 {
-       int err = 0;
+       int err;
        struct rfkill *rfk;
        enum rfkill_type type;
        const char *name;
@@ -1660,17 +1660,19 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
        if (!rfk)
                return -ENOMEM;
 
-       if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) {
+       err = sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
+       if (err < 0) {
                rfkill_destroy(rfk);
-               return -1;
+               return err;
        }
        hwblock = !(result & 0x1);
 
-       if (sony_call_snc_handle(sony_rfkill_handle,
-                               sony_rfkill_address[nc_type],
-                               &result) < 0) {
+       err = sony_call_snc_handle(sony_rfkill_handle,
+                                  sony_rfkill_address[nc_type],
+                                  &result);
+       if (err < 0) {
                rfkill_destroy(rfk);
-               return -1;
+               return err;
        }
        swblock = !(result & 0x2);
 
index 3887dfeafc964522e43c077534bf62e0747f7dcf..117be48ff4de9a3a70df898565cf6495e92d7ddd 100644 (file)
@@ -310,8 +310,7 @@ static struct {
        enum {
                TP_HOTKEY_TABLET_NONE = 0,
                TP_HOTKEY_TABLET_USES_MHKG,
-               /* X1 Yoga 2016, seen on BIOS N1FET44W */
-               TP_HOTKEY_TABLET_USES_CMMD,
+               TP_HOTKEY_TABLET_USES_GMMS,
        } hotkey_tablet;
        u32 kbdlight:1;
        u32 light:1;
@@ -2044,8 +2043,28 @@ static void hotkey_poll_setup(const bool may_warn);
 
 /* HKEY.MHKG() return bits */
 #define TP_HOTKEY_TABLET_MASK (1 << 3)
-/* ThinkPad X1 Yoga (2016) */
-#define TP_EC_CMMD_TABLET_MODE 0x6
+enum {
+       TP_ACPI_MULTI_MODE_INVALID      = 0,
+       TP_ACPI_MULTI_MODE_UNKNOWN      = 1 << 0,
+       TP_ACPI_MULTI_MODE_LAPTOP       = 1 << 1,
+       TP_ACPI_MULTI_MODE_TABLET       = 1 << 2,
+       TP_ACPI_MULTI_MODE_FLAT         = 1 << 3,
+       TP_ACPI_MULTI_MODE_STAND        = 1 << 4,
+       TP_ACPI_MULTI_MODE_TENT         = 1 << 5,
+       TP_ACPI_MULTI_MODE_STAND_TENT   = 1 << 6,
+};
+
+enum {
+       /* The following modes are considered tablet mode for the purpose of
+        * reporting the status to userspace. i.e. in all these modes it makes
+        * sense to disable the laptop input devices such as touchpad and
+        * keyboard.
+        */
+       TP_ACPI_MULTI_MODE_TABLET_LIKE  = TP_ACPI_MULTI_MODE_TABLET |
+                                         TP_ACPI_MULTI_MODE_STAND |
+                                         TP_ACPI_MULTI_MODE_TENT |
+                                         TP_ACPI_MULTI_MODE_STAND_TENT,
+};
 
 static int hotkey_get_wlsw(void)
 {
@@ -2066,6 +2085,90 @@ static int hotkey_get_wlsw(void)
        return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
+static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
+{
+       int type = (s >> 16) & 0xffff;
+       int value = s & 0xffff;
+       int mode = TP_ACPI_MULTI_MODE_INVALID;
+       int valid_modes = 0;
+
+       if (has_tablet_mode)
+               *has_tablet_mode = 0;
+
+       switch (type) {
+       case 1:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND_TENT;
+               break;
+       case 2:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND |
+                             TP_ACPI_MULTI_MODE_TENT;
+               break;
+       case 3:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT;
+               break;
+       case 4:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND |
+                             TP_ACPI_MULTI_MODE_TENT;
+               break;
+       case 5:
+               valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
+                             TP_ACPI_MULTI_MODE_FLAT |
+                             TP_ACPI_MULTI_MODE_TABLET |
+                             TP_ACPI_MULTI_MODE_STAND |
+                             TP_ACPI_MULTI_MODE_TENT;
+               break;
+       default:
+               pr_err("Unknown multi mode status type %d with value 0x%04X, please report this to %s\n",
+                      type, value, TPACPI_MAIL);
+               return 0;
+       }
+
+       if (has_tablet_mode && (valid_modes & TP_ACPI_MULTI_MODE_TABLET_LIKE))
+               *has_tablet_mode = 1;
+
+       switch (value) {
+       case 1:
+               mode = TP_ACPI_MULTI_MODE_LAPTOP;
+               break;
+       case 2:
+               mode = TP_ACPI_MULTI_MODE_FLAT;
+               break;
+       case 3:
+               mode = TP_ACPI_MULTI_MODE_TABLET;
+               break;
+       case 4:
+               if (type == 1)
+                       mode = TP_ACPI_MULTI_MODE_STAND_TENT;
+               else
+                       mode = TP_ACPI_MULTI_MODE_STAND;
+               break;
+       case 5:
+               mode = TP_ACPI_MULTI_MODE_TENT;
+               break;
+       default:
+               if (type == 5 && value == 0xffff) {
+                       pr_warn("Multi mode status is undetected, assuming laptop\n");
+                       return 0;
+               }
+       }
+
+       if (!(mode & valid_modes)) {
+               pr_err("Unknown/reserved multi mode value 0x%04X for type %d, please report this to %s\n",
+                      value, type, TPACPI_MAIL);
+               return 0;
+       }
+
+       return !!(mode & TP_ACPI_MULTI_MODE_TABLET_LIKE);
+}
+
 static int hotkey_get_tablet_mode(int *status)
 {
        int s;
@@ -2077,11 +2180,11 @@ static int hotkey_get_tablet_mode(int *status)
 
                *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
                break;
-       case TP_HOTKEY_TABLET_USES_CMMD:
-               if (!acpi_evalf(ec_handle, &s, "CMMD", "d"))
+       case TP_HOTKEY_TABLET_USES_GMMS:
+               if (!acpi_evalf(hkey_handle, &s, "GMMS", "dd", 0))
                        return -EIO;
 
-               *status = (s == TP_EC_CMMD_TABLET_MODE);
+               *status = hotkey_gmms_get_tablet_mode(s, NULL);
                break;
        default:
                break;
@@ -3113,16 +3216,19 @@ static int hotkey_init_tablet_mode(void)
        int in_tablet_mode = 0, res;
        char *type = NULL;
 
-       if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
+       if (acpi_evalf(hkey_handle, &res, "GMMS", "qdd", 0)) {
+               int has_tablet_mode;
+
+               in_tablet_mode = hotkey_gmms_get_tablet_mode(res,
+                                                            &has_tablet_mode);
+               if (has_tablet_mode)
+                       tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GMMS;
+               type = "GMMS";
+       } else if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
                /* For X41t, X60t, X61t Tablets... */
                tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG;
                in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK);
                type = "MHKG";
-       } else if (acpi_evalf(ec_handle, &res, "CMMD", "qd")) {
-               /* For X1 Yoga (2016) */
-               tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_CMMD;
-               in_tablet_mode = res == TP_EC_CMMD_TABLET_MODE;
-               type = "CMMD";
        }
 
        if (!tp_features.hotkey_tablet)
index 0765b1797d4c0d35cd58f588d8c4717bf6b1179d..791449a2370f4f10af698dbaf27bb3749d6d263a 100644 (file)
 
 #define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
+#include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/acpi.h>
-#include <linux/slab.h>
+#include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/wmi.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
 #include <linux/uuid.h>
+#include <linux/wmi.h>
+#include <uapi/linux/wmi.h>
 
 ACPI_MODULE_NAME("wmi");
 MODULE_AUTHOR("Carlos Corbacho");
@@ -69,9 +72,12 @@ struct wmi_block {
        struct wmi_device dev;
        struct list_head list;
        struct guid_block gblock;
+       struct miscdevice char_dev;
+       struct mutex char_mutex;
        struct acpi_device *acpi_device;
        wmi_notify_handler handler;
        void *handler_data;
+       u64 req_buf_size;
 
        bool read_takes_no_args;
 };
@@ -188,6 +194,25 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
 /*
  * Exported WMI functions
  */
+
+/**
+ * set_required_buffer_size - Sets the buffer size needed for performing IOCTL
+ * @wdev: A wmi bus device from a driver
+ * @instance: Instance index
+ *
+ * Allocates memory needed for buffer, stores the buffer size in that memory
+ */
+int set_required_buffer_size(struct wmi_device *wdev, u64 length)
+{
+       struct wmi_block *wblock;
+
+       wblock = container_of(wdev, struct wmi_block, dev);
+       wblock->req_buf_size = length;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(set_required_buffer_size);
+
 /**
  * wmi_evaluate_method - Evaluate a WMI method
  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -200,6 +225,28 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
  */
 acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
+{
+       struct wmi_block *wblock = NULL;
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_ERROR;
+       return wmidev_evaluate_method(&wblock->dev, instance, method_id,
+                                     in, out);
+}
+EXPORT_SYMBOL_GPL(wmi_evaluate_method);
+
+/**
+ * wmidev_evaluate_method - Evaluate a WMI method
+ * @wdev: A wmi bus device from a driver
+ * @instance: Instance index
+ * @method_id: Method ID to call
+ * &in: Buffer containing input for the method call
+ * &out: Empty buffer to return the method results
+ *
+ * Call an ACPI-WMI method
+ */
+acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance,
+       u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
 {
        struct guid_block *block = NULL;
        struct wmi_block *wblock = NULL;
@@ -209,9 +256,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
        union acpi_object params[3];
        char method[5] = "WM";
 
-       if (!find_guid(guid_string, &wblock))
-               return AE_ERROR;
-
+       wblock = container_of(wdev, struct wmi_block, dev);
        block = &wblock->gblock;
        handle = wblock->acpi_device->handle;
 
@@ -246,7 +291,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
 
        return status;
 }
-EXPORT_SYMBOL_GPL(wmi_evaluate_method);
+EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
 
 static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
                                 struct acpi_buffer *out)
@@ -348,23 +393,6 @@ union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)
 }
 EXPORT_SYMBOL_GPL(wmidev_block_query);
 
-struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
-                                        const char *guid_string)
-{
-       struct wmi_block *this_wb = container_of(wdev, struct wmi_block, dev);
-       struct wmi_block *other_wb;
-
-       if (!find_guid(guid_string, &other_wb))
-               return NULL;
-
-       if (other_wb->acpi_device != this_wb->acpi_device)
-               return NULL;
-
-       get_device(&other_wb->dev.dev);
-       return &other_wb->dev;
-}
-EXPORT_SYMBOL_GPL(wmidev_get_other_guid);
-
 /**
  * wmi_set_block - Write to a WMI block
  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -761,6 +789,113 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
 
        return 0;
 }
+static int wmi_char_open(struct inode *inode, struct file *filp)
+{
+       const char *driver_name = filp->f_path.dentry->d_iname;
+       struct wmi_block *wblock = NULL;
+       struct wmi_block *next = NULL;
+
+       list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
+               if (!wblock->dev.dev.driver)
+                       continue;
+               if (strcmp(driver_name, wblock->dev.dev.driver->name) == 0) {
+                       filp->private_data = wblock;
+                       break;
+               }
+       }
+
+       if (!filp->private_data)
+               return -ENODEV;
+
+       return nonseekable_open(inode, filp);
+}
+
+static ssize_t wmi_char_read(struct file *filp, char __user *buffer,
+       size_t length, loff_t *offset)
+{
+       struct wmi_block *wblock = filp->private_data;
+
+       return simple_read_from_buffer(buffer, length, offset,
+                                      &wblock->req_buf_size,
+                                      sizeof(wblock->req_buf_size));
+}
+
+static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct wmi_ioctl_buffer __user *input =
+               (struct wmi_ioctl_buffer __user *) arg;
+       struct wmi_block *wblock = filp->private_data;
+       struct wmi_ioctl_buffer *buf = NULL;
+       struct wmi_driver *wdriver = NULL;
+       int ret;
+
+       if (_IOC_TYPE(cmd) != WMI_IOC)
+               return -ENOTTY;
+
+       /* make sure we're not calling a higher instance than exists*/
+       if (_IOC_NR(cmd) >= wblock->gblock.instance_count)
+               return -EINVAL;
+
+       mutex_lock(&wblock->char_mutex);
+       buf = wblock->handler_data;
+       if (get_user(buf->length, &input->length)) {
+               dev_dbg(&wblock->dev.dev, "Read length from user failed\n");
+               ret = -EFAULT;
+               goto out_ioctl;
+       }
+       /* if it's too small, abort */
+       if (buf->length < wblock->req_buf_size) {
+               dev_err(&wblock->dev.dev,
+                       "Buffer %lld too small, need at least %lld\n",
+                       buf->length, wblock->req_buf_size);
+               ret = -EINVAL;
+               goto out_ioctl;
+       }
+       /* if it's too big, warn, driver will only use what is needed */
+       if (buf->length > wblock->req_buf_size)
+               dev_warn(&wblock->dev.dev,
+                       "Buffer %lld is bigger than required %lld\n",
+                       buf->length, wblock->req_buf_size);
+
+       /* copy the structure from userspace */
+       if (copy_from_user(buf, input, wblock->req_buf_size)) {
+               dev_dbg(&wblock->dev.dev, "Copy %llu from user failed\n",
+                       wblock->req_buf_size);
+               ret = -EFAULT;
+               goto out_ioctl;
+       }
+
+       /* let the driver do any filtering and do the call */
+       wdriver = container_of(wblock->dev.dev.driver,
+                              struct wmi_driver, driver);
+       if (!try_module_get(wdriver->driver.owner)) {
+               ret = -EBUSY;
+               goto out_ioctl;
+       }
+       ret = wdriver->filter_callback(&wblock->dev, cmd, buf);
+       module_put(wdriver->driver.owner);
+       if (ret)
+               goto out_ioctl;
+
+       /* return the result (only up to our internal buffer size) */
+       if (copy_to_user(input, buf, wblock->req_buf_size)) {
+               dev_dbg(&wblock->dev.dev, "Copy %llu to user failed\n",
+                       wblock->req_buf_size);
+               ret = -EFAULT;
+       }
+
+out_ioctl:
+       mutex_unlock(&wblock->char_mutex);
+       return ret;
+}
+
+static const struct file_operations wmi_fops = {
+       .owner          = THIS_MODULE,
+       .read           = wmi_char_read,
+       .open           = wmi_char_open,
+       .unlocked_ioctl = wmi_ioctl,
+       .compat_ioctl   = wmi_ioctl,
+};
 
 static int wmi_dev_probe(struct device *dev)
 {
@@ -768,16 +903,63 @@ static int wmi_dev_probe(struct device *dev)
        struct wmi_driver *wdriver =
                container_of(dev->driver, struct wmi_driver, driver);
        int ret = 0;
+       int count;
+       char *buf;
 
        if (ACPI_FAILURE(wmi_method_enable(wblock, 1)))
                dev_warn(dev, "failed to enable device -- probing anyway\n");
 
        if (wdriver->probe) {
                ret = wdriver->probe(dev_to_wdev(dev));
-               if (ret != 0 && ACPI_FAILURE(wmi_method_enable(wblock, 0)))
-                       dev_warn(dev, "failed to disable device\n");
+               if (ret != 0)
+                       goto probe_failure;
+       }
+
+       /* driver wants a character device made */
+       if (wdriver->filter_callback) {
+               /* check that required buffer size declared by driver or MOF */
+               if (!wblock->req_buf_size) {
+                       dev_err(&wblock->dev.dev,
+                               "Required buffer size not set\n");
+                       ret = -EINVAL;
+                       goto probe_failure;
+               }
+
+               count = get_order(wblock->req_buf_size);
+               wblock->handler_data = (void *)__get_free_pages(GFP_KERNEL,
+                                                               count);
+               if (!wblock->handler_data) {
+                       ret = -ENOMEM;
+                       goto probe_failure;
+               }
+
+               buf = kmalloc(strlen(wdriver->driver.name) + 4, GFP_KERNEL);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto probe_string_failure;
+               }
+               sprintf(buf, "wmi/%s", wdriver->driver.name);
+               wblock->char_dev.minor = MISC_DYNAMIC_MINOR;
+               wblock->char_dev.name = buf;
+               wblock->char_dev.fops = &wmi_fops;
+               wblock->char_dev.mode = 0444;
+               ret = misc_register(&wblock->char_dev);
+               if (ret) {
+                       dev_warn(dev, "failed to register char dev: %d", ret);
+                       ret = -ENOMEM;
+                       goto probe_misc_failure;
+               }
        }
 
+       return 0;
+
+probe_misc_failure:
+       kfree(buf);
+probe_string_failure:
+       kfree(wblock->handler_data);
+probe_failure:
+       if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
+               dev_warn(dev, "failed to disable device\n");
        return ret;
 }
 
@@ -788,6 +970,13 @@ static int wmi_dev_remove(struct device *dev)
                container_of(dev->driver, struct wmi_driver, driver);
        int ret = 0;
 
+       if (wdriver->filter_callback) {
+               misc_deregister(&wblock->char_dev);
+               kfree(wblock->char_dev.name);
+               free_pages((unsigned long)wblock->handler_data,
+                          get_order(wblock->req_buf_size));
+       }
+
        if (wdriver->remove)
                ret = wdriver->remove(dev_to_wdev(dev));
 
@@ -844,6 +1033,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
 
        if (gblock->flags & ACPI_WMI_METHOD) {
                wblock->dev.dev.type = &wmi_type_method;
+               mutex_init(&wblock->char_mutex);
                goto out_init;
        }
 
@@ -1145,7 +1335,7 @@ static int acpi_wmi_remove(struct platform_device *device)
        acpi_remove_address_space_handler(acpi_device->handle,
                                ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
        wmi_free_devices(acpi_device);
-       device_unregister((struct device *)dev_get_drvdata(&device->dev));
+       device_destroy(&wmi_bus_class, MKDEV(0, 0));
 
        return 0;
 }
@@ -1199,7 +1389,7 @@ static int acpi_wmi_probe(struct platform_device *device)
        return 0;
 
 err_remove_busdev:
-       device_unregister(wmi_bus_dev);
+       device_destroy(&wmi_bus_class, MKDEV(0, 0));
 
 err_remove_notify_handler:
        acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
@@ -1264,8 +1454,8 @@ err_unreg_class:
 static void __exit acpi_wmi_exit(void)
 {
        platform_driver_unregister(&acpi_wmi_driver);
-       class_unregister(&wmi_bus_class);
        bus_unregister(&wmi_bus_type);
+       class_unregister(&wmi_bus_class);
 }
 
 subsys_initcall(acpi_wmi_init);
index 5e58f5ec0a28e449afa8813a652b1aa3469e0721..2f615b7f1c9f61e1e04a4857069f7a450d757130 100644 (file)
@@ -905,16 +905,6 @@ config FB_LEO
          This is the frame buffer device driver for the SBUS-based Sun ZX
          (leo) frame buffer cards.
 
-config FB_IGA
-       bool "IGA 168x display support"
-       depends on (FB = y) && SPARC32
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       help
-         This is the framebuffer device for the INTERGRAPHICS 1680 and
-         successor frame buffer cards.
-
 config FB_XVR500
        bool "Sun XVR-500 3DLABS Wildcat support"
        depends on (FB = y) && PCI && SPARC64
index 8895536a20d648723197affff38d1bbf8fc140a8..115961e0721b8ba1aaab4dcfb3b4032a50760637 100644 (file)
@@ -65,7 +65,6 @@ obj-$(CONFIG_FB_HGA)              += hgafb.o
 obj-$(CONFIG_FB_XVR500)           += sunxvr500.o
 obj-$(CONFIG_FB_XVR2500)          += sunxvr2500.o
 obj-$(CONFIG_FB_XVR1000)          += sunxvr1000.o
-obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o
 obj-$(CONFIG_FB_Q40)              += q40fb.o
 obj-$(CONFIG_FB_TGA)              += tgafb.o
index 3ec72f19114badf5cb26fe1cb530c04916b9d8c0..a9a8272f7a6eeda70a8e8d1a3c8b6381bbfaea41 100644 (file)
@@ -2272,10 +2272,10 @@ static void aty_bl_exit(struct backlight_device *bd)
 
 static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
 {
-       const int ragepro_tbl[] = {
+       static const int ragepro_tbl[] = {
                44, 50, 55, 66, 75, 80, 100
        };
-       const int ragexl_tbl[] = {
+       static const int ragexl_tbl[] = {
                50, 66, 75, 83, 90, 95, 100, 105,
                110, 115, 120, 125, 133, 143, 166
        };
index 1e2ec360f8c16da91b8ee9e921452ef4bda77834..4d77daeecf99b4d45b7876921379b8e1c95ec71d 100644 (file)
@@ -1454,9 +1454,9 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
 /*
  * Timer function for delayed LVDS panel power up/down
  */
-static void radeon_lvds_timer_func(unsigned long data)
+static void radeon_lvds_timer_func(struct timer_list *t)
 {
-       struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+       struct radeonfb_info *rinfo = from_timer(rinfo, t, lvds_timer);
 
        radeon_engine_idle();
 
@@ -1534,7 +1534,7 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
 static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs,
                                 unsigned long freq)
 {
-       const struct {
+       static const struct {
                int divider;
                int bitvalue;
        } *post_div,
@@ -2291,9 +2291,7 @@ static int radeonfb_pci_register(struct pci_dev *pdev,
        rinfo->pdev = pdev;
        
        spin_lock_init(&rinfo->reg_lock);
-       init_timer(&rinfo->lvds_timer);
-       rinfo->lvds_timer.function = radeon_lvds_timer_func;
-       rinfo->lvds_timer.data = (unsigned long)rinfo;
+       timer_setup(&rinfo->lvds_timer, radeon_lvds_timer_func, 0);
 
        c1 = ent->device >> 8;
        c2 = ent->device & 0xff;
index f7c253dd5899f1e887abe7c768b1681a51b4162d..7137c12cbcee30ce60bbdcc27c62fdaf0c9cfbdc 100644 (file)
@@ -1208,9 +1208,11 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (mc & 0x4)
                        break;
+               /* fall through */
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET;
+               /* fall through */
        case 0:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET;
@@ -1219,6 +1221,7 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (!(mc & 0x4))
                        break;
+               /* fall through */
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET;
index 5f04b4096c428883be0b4032fb9b055916cda5f5..87d5a62bf6ca446fb8141b602c38839363dc120e 100644 (file)
@@ -1518,7 +1518,7 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
 static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 {
        struct fb_info *fbi = fbdev->fb_info;
-       int bpp;
+       int bpp, ret;
 
        fbi->fbops = &au1200fb_fb_ops;
 
@@ -1546,15 +1546,14 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
        }
 
        fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
-       if (!fbi->pseudo_palette) {
+       if (!fbi->pseudo_palette)
                return -ENOMEM;
-       }
 
-       if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+       ret = fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0);
+       if (ret < 0) {
                print_err("Fail to allocate colormap (%d entries)",
-                          AU1200_LCD_NBR_PALETTE_ENTRIES);
-               kfree(fbi->pseudo_palette);
-               return -EFAULT;
+                         AU1200_LCD_NBR_PALETTE_ENTRIES);
+               return ret;
        }
 
        strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
@@ -1668,10 +1667,6 @@ static int au1200fb_drv_probe(struct platform_device *dev)
        printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
        printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
 
-       /* shut gcc up */
-       ret = 0;
-       fbdev = NULL;
-
        for (plane = 0; plane < device_count; ++plane) {
                bpp = winbpp(win->w[plane].mode_winctrl1);
                if (win->w[plane].xres == 0)
@@ -1681,8 +1676,10 @@ static int au1200fb_drv_probe(struct platform_device *dev)
 
                fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
                                        &dev->dev);
-               if (!fbi)
+               if (!fbi) {
+                       ret = -ENOMEM;
                        goto failed;
+               }
 
                _au1200fb_infos[plane] = fbi;
                fbdev = fbi->par;
@@ -1701,7 +1698,8 @@ static int au1200fb_drv_probe(struct platform_device *dev)
                if (!fbdev->fb_mem) {
                        print_err("fail to allocate frambuffer (size: %dK))",
                                  fbdev->fb_len / 1024);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto failed;
                }
 
                /*
@@ -1718,7 +1716,8 @@ static int au1200fb_drv_probe(struct platform_device *dev)
                print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
 
                /* Init FB data */
-               if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
+               ret = au1200fb_init_fbinfo(fbdev);
+               if (ret < 0)
                        goto failed;
 
                /* Register new framebuffer */
@@ -1758,21 +1757,26 @@ static int au1200fb_drv_probe(struct platform_device *dev)
        return 0;
 
 failed:
-       /* NOTE: This only does the current plane/window that failed; others are still active */
-       if (fbi) {
+       for (plane = 0; plane < device_count; ++plane) {
+               fbi = _au1200fb_infos[plane];
+               if (!fbi)
+                       break;
+
+               /* Clean up all probe data */
+               unregister_framebuffer(fbi);
                if (fbi->cmap.len != 0)
                        fb_dealloc_cmap(&fbi->cmap);
                kfree(fbi->pseudo_palette);
+
+               framebuffer_release(fbi);
+               _au1200fb_infos[plane] = NULL;
        }
-       if (plane == 0)
-               free_irq(AU1200_LCD_INT, (void*)dev);
        return ret;
 }
 
 static int au1200fb_drv_remove(struct platform_device *dev)
 {
        struct au1200fb_platdata *pd = platform_get_drvdata(dev);
-       struct au1200fb_device *fbdev;
        struct fb_info *fbi;
        int plane;
 
@@ -1781,7 +1785,6 @@ static int au1200fb_drv_remove(struct platform_device *dev)
 
        for (plane = 0; plane < device_count; ++plane)  {
                fbi = _au1200fb_infos[plane];
-               fbdev = fbi->par;
 
                /* Clean up all probe data */
                unregister_framebuffer(fbi);
index d992aa5eb3f0dc6557b23b4ec3e4868301c5ede8..b3be06dd290882e5c7d75db66977e73f6dcae128 100644 (file)
@@ -1477,10 +1477,12 @@ static void init_vgachip(struct fb_info *info)
                mdelay(100);
                /* mode */
                vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
-       case BT_GD5480:  /* fall through */
+               /* fall through */
+       case BT_GD5480:
                /* from Klaus' NetBSD driver: */
                vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
-       case BT_ALPINE:  /* fall through */
+               /* fall through */
+       case BT_ALPINE:
                /* put blitter into 542x compat */
                vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
                break;
index 6026c60fc1007e007ec568d23ad26fa3910795e6..261522fabdac89ae2644089aba612dee880b4d24 100644 (file)
@@ -141,5 +141,7 @@ static struct max_cmodes control_mac_modes[] = {
        {{ 1, 2}},      /* 1152x870, 75Hz */
        {{ 0, 1}},      /* 1280x960, 75Hz */
        {{ 0, 1}},      /* 1280x1024, 75Hz */
+       {{ 1, 2}},      /* 1152x768, 60Hz */
+       {{ 0, 1}},      /* 1600x1024, 60Hz */
 };
 
index 04612f938bab1fc3eecf457d070fe501b8a1a3de..929ca472c5242ef50bd9653cffe315d72daac2aa 100644 (file)
@@ -395,10 +395,10 @@ static void fb_flashcursor(struct work_struct *work)
        console_unlock();
 }
 
-static void cursor_timer_handler(unsigned long dev_addr)
+static void cursor_timer_handler(struct timer_list *t)
 {
-       struct fb_info *info = (struct fb_info *) dev_addr;
-       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_ops *ops = from_timer(ops, t, cursor_timer);
+       struct fb_info *info = ops->info;
 
        queue_work(system_power_efficient_wq, &info->queue);
        mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
@@ -414,8 +414,7 @@ static void fbcon_add_cursor_timer(struct fb_info *info)
                if (!info->queue.func)
                        INIT_WORK(&info->queue, fb_flashcursor);
 
-               setup_timer(&ops->cursor_timer, cursor_timer_handler,
-                           (unsigned long) info);
+               timer_setup(&ops->cursor_timer, cursor_timer_handler, 0);
                mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
                ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
        }
@@ -714,6 +713,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
 
        if (!err) {
                ops->cur_blink_jiffies = HZ / 5;
+               ops->info = info;
                info->fbcon_par = ops;
 
                if (vc)
@@ -962,6 +962,7 @@ static const char *fbcon_startup(void)
        ops->graphics = 1;
        ops->cur_rotate = -1;
        ops->cur_blink_jiffies = HZ / 5;
+       ops->info = info;
        info->fbcon_par = ops;
        if (initial_rotation != -1)
                p->con_rotate = initial_rotation;
index 18f3ac14423706adc006f37bee55b1241627f99d..9f7744fbc962dc1c19f6b2f4b9d518126fedf0cc 100644 (file)
@@ -69,6 +69,7 @@ struct fbcon_ops {
        struct timer_list cursor_timer; /* Cursor timer */
        struct fb_cursor cursor_state;
        struct display *p;
+       struct fb_info *info;
         int    currcon;                        /* Current VC. */
        int    cur_blink_jiffies;
        int    cursor_flash;
index 7b1492d34e989ab92a1a4819192afc00294af4d7..5505fa00c6348a26597aaa6f65a90092aff5c14c 100644 (file)
@@ -115,7 +115,7 @@ static struct fb_ops dn_fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-struct fb_var_screeninfo dnfb_var = {
+static const struct fb_var_screeninfo dnfb_var = {
        .xres           = 1280,
        .yres           = 1024,
        .xres_virtual   = 2048,
@@ -242,16 +242,13 @@ static int dnfb_probe(struct platform_device *dev)
        info->screen_base = (u_char *) info->fix.smem_start;
 
        err = fb_alloc_cmap(&info->cmap, 2, 0);
-       if (err < 0) {
-               framebuffer_release(info);
-               return err;
-       }
+       if (err < 0)
+               goto release_framebuffer;
 
        err = register_framebuffer(info);
        if (err < 0) {
                fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-               return err;
+               goto release_framebuffer;
        }
        platform_set_drvdata(dev, info);
 
@@ -265,6 +262,10 @@ static int dnfb_probe(struct platform_device *dev)
 
        printk("apollo frame buffer alive and kicking !\n");
        return err;
+
+release_framebuffer:
+       framebuffer_release(info);
+       return err;
 }
 
 static struct platform_driver dnfb_driver = {
index 7f6c9e6cfc6c99d8d9912db5d2f78242923f51c5..3b70044773b67566b6c7ebf516bc23dde166f95b 100644 (file)
@@ -304,12 +304,18 @@ static int goldfish_fb_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id goldfish_fb_of_match[] = {
+       { .compatible = "google,goldfish-fb", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_fb_of_match);
 
 static struct platform_driver goldfish_fb_driver = {
        .probe          = goldfish_fb_probe,
        .remove         = goldfish_fb_remove,
        .driver = {
-               .name = "goldfish_fb"
+               .name = "goldfish_fb",
+               .of_match_table = goldfish_fb_of_match,
        }
 };
 
diff --git a/drivers/video/fbdev/igafb.c b/drivers/video/fbdev/igafb.c
deleted file mode 100644 (file)
index 486f188..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- *  linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
- *
- *      Copyright (C) 1998  Vladimir Roganov and Gleb Raiko
- *
- *  This driver is partly based on the Frame buffer device for ATI Mach64
- *  and partially on VESA-related code.
- *
- *      Copyright (C) 1997-1998  Geert Uytterhoeven
- *      Copyright (C) 1998  Bernd Harries
- *      Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License. See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-/******************************************************************************
-
-  TODO:
-       Despite of IGA Card has advanced graphic acceleration, 
-       initial version is almost dummy and does not support it.
-       Support for video modes and acceleration must be added
-       together with accelerated X-Windows driver implementation.
-
-       Most important thing at this moment is that we have working
-       JavaEngine1  console & X  with new console interface.
-
-******************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/nvram.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_SPARC
-#include <asm/prom.h>
-#include <asm/pcic.h>
-#endif
-
-#include <video/iga.h>
-
-struct pci_mmap_map {
-    unsigned long voff;
-    unsigned long poff;
-    unsigned long size;
-    unsigned long prot_flag;
-    unsigned long prot_mask;
-};
-
-struct iga_par {
-       struct pci_mmap_map *mmap_map;
-       unsigned long frame_buffer_phys;
-       unsigned long io_base;
-};
-
-struct fb_info fb_info;
-
-struct fb_fix_screeninfo igafb_fix __initdata = {
-        .id            = "IGA 1682",
-       .type           = FB_TYPE_PACKED_PIXELS,
-       .mmio_len       = 1000
-};
-
-struct fb_var_screeninfo default_var = {
-       /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
-       .xres           = 640,
-       .yres           = 480,
-       .xres_virtual   = 640,
-       .yres_virtual   = 480,
-       .bits_per_pixel = 8,
-       .red            = {0, 8, 0 },
-       .green          = {0, 8, 0 },
-       .blue           = {0, 8, 0 },
-       .height         = -1,
-       .width          = -1,
-       .accel_flags    = FB_ACCEL_NONE,
-       .pixclock       = 39722,
-       .left_margin    = 48,
-       .right_margin   = 16,
-       .upper_margin   = 33,
-       .lower_margin   = 10,
-       .hsync_len      = 96,
-       .vsync_len      = 2,
-       .vmode          = FB_VMODE_NONINTERLACED
-};
-
-#ifdef CONFIG_SPARC
-struct fb_var_screeninfo default_var_1024x768 __initdata = {
-       /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
-       .xres           = 1024,
-       .yres           = 768,
-       .xres_virtual   = 1024,
-       .yres_virtual   = 768,
-       .bits_per_pixel = 8,
-       .red            = {0, 8, 0 },
-       .green          = {0, 8, 0 },
-       .blue           = {0, 8, 0 },
-       .height         = -1,
-       .width          = -1,
-       .accel_flags    = FB_ACCEL_NONE,
-       .pixclock       = 12699,
-       .left_margin    = 176,
-       .right_margin   = 16,
-       .upper_margin   = 28,
-       .lower_margin   = 1,
-       .hsync_len      = 96,
-       .vsync_len      = 3,
-       .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-};
-
-struct fb_var_screeninfo default_var_1152x900 __initdata = {
-       /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
-       .xres           = 1152,
-       .yres           = 900,
-       .xres_virtual   = 1152,
-       .yres_virtual   = 900,
-       .bits_per_pixel = 8,
-       .red            = { 0, 8, 0 },
-       .green          = { 0, 8, 0 },
-       .blue           = { 0, 8, 0 },
-       .height         = -1,
-       .width          = -1,
-       .accel_flags    = FB_ACCEL_NONE,
-       .pixclock       = 9091,
-       .left_margin    = 234,
-       .right_margin   = 24,
-       .upper_margin   = 34,
-       .lower_margin   = 3,
-       .hsync_len      = 100,
-       .vsync_len      = 3,
-       .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-};
-
-struct fb_var_screeninfo default_var_1280x1024 __initdata = {
-       /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
-       .xres           = 1280,
-       .yres           = 1024,
-       .xres_virtual   = 1280,
-       .yres_virtual   = 1024,
-       .bits_per_pixel = 8,
-       .red            = {0, 8, 0 }, 
-       .green          = {0, 8, 0 },
-       .blue           = {0, 8, 0 },
-       .height         = -1,
-       .width          = -1,
-       .accel_flags    = 0,
-       .pixclock       = 7408,
-       .left_margin    = 248,
-       .right_margin   = 16,
-       .upper_margin   = 38,
-       .lower_margin   = 1,
-       .hsync_len      = 144,
-       .vsync_len      = 3,
-       .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-};
-
-/*
- *   Memory-mapped I/O functions for Sparc PCI
- *
- * On sparc we happen to access I/O with memory mapped functions too.
- */ 
-#define pci_inb(par, reg)        readb(par->io_base+(reg))
-#define pci_outb(par, val, reg)  writeb(val, par->io_base+(reg))
-
-static inline unsigned int iga_inb(struct iga_par *par, unsigned int reg,
-                                  unsigned int idx)
-{
-        pci_outb(par, idx, reg);
-        return pci_inb(par, reg + 1);
-}
-
-static inline void iga_outb(struct iga_par *par, unsigned char val,
-                           unsigned int reg, unsigned int idx )
-{
-        pci_outb(par, idx, reg);
-        pci_outb(par, val, reg+1);
-}
-
-#endif /* CONFIG_SPARC */
-
-/*
- *  Very important functionality for the JavaEngine1 computer:
- *  make screen border black (usign special IGA registers) 
- */
-static void iga_blank_border(struct iga_par *par)
-{
-        int i;
-#if 0
-       /*
-        * PROM does this for us, so keep this code as a reminder
-        * about required read from 0x3DA and writing of 0x20 in the end.
-        */
-       (void) pci_inb(par, 0x3DA);             /* required for every access */
-       pci_outb(par, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL);
-       (void) pci_inb(par, IGA_ATTR_CTL+1);
-       pci_outb(par, 0x38, IGA_ATTR_CTL);
-       pci_outb(par, 0x20, IGA_ATTR_CTL);      /* re-enable visual */
-#endif
-       /*
-        * This does not work as it was designed because the overscan
-        * color is looked up in the palette. Therefore, under X11
-        * overscan changes color.
-        */
-       for (i=0; i < 3; i++)
-               iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
-}
-
-#ifdef CONFIG_SPARC
-static int igafb_mmap(struct fb_info *info,
-                     struct vm_area_struct *vma)
-{
-       struct iga_par *par = (struct iga_par *)info->par;
-       unsigned int size, page, map_size = 0;
-       unsigned long map_offset = 0;
-       int i;
-
-       if (!par->mmap_map)
-               return -ENXIO;
-
-       size = vma->vm_end - vma->vm_start;
-
-       /* Each page, see which map applies */
-       for (page = 0; page < size; ) {
-               map_size = 0;
-               for (i = 0; par->mmap_map[i].size; i++) {
-                       unsigned long start = par->mmap_map[i].voff;
-                       unsigned long end = start + par->mmap_map[i].size;
-                       unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page;
-
-                       if (start > offset)
-                               continue;
-                       if (offset >= end)
-                               continue;
-
-                       map_size = par->mmap_map[i].size - (offset - start);
-                       map_offset = par->mmap_map[i].poff + (offset - start);
-                       break;
-               }
-               if (!map_size) {
-                       page += PAGE_SIZE;
-                       continue;
-               }
-               if (page + map_size > size)
-                       map_size = size - page;
-
-               pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
-               pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
-
-               if (remap_pfn_range(vma, vma->vm_start + page,
-                       map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
-                       return -EAGAIN;
-
-               page += map_size;
-       }
-
-       if (!map_size)
-               return -EINVAL;
-
-       vma->vm_flags |= VM_IO;
-       return 0;
-}
-#endif /* CONFIG_SPARC */
-
-static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                           unsigned blue, unsigned transp,
-                           struct fb_info *info)
-{
-        /*
-         *  Set a single color register. The values supplied are
-         *  already rounded down to the hardware's capabilities
-         *  (according to the entries in the `var' structure). Return
-         *  != 0 for invalid regno.
-         */
-       struct iga_par *par = (struct iga_par *)info->par;
-
-        if (regno >= info->cmap.len)
-                return 1;
-
-       pci_outb(par, regno, DAC_W_INDEX);
-       pci_outb(par, red,   DAC_DATA);
-       pci_outb(par, green, DAC_DATA);
-       pci_outb(par, blue,  DAC_DATA);
-
-       if (regno < 16) {
-               switch (info->var.bits_per_pixel) {
-               case 16:
-                       ((u16*)(info->pseudo_palette))[regno] = 
-                               (regno << 10) | (regno << 5) | regno;
-                       break;
-               case 24:
-                       ((u32*)(info->pseudo_palette))[regno] = 
-                               (regno << 16) | (regno << 8) | regno;
-               break;
-               case 32:
-                       { int i;
-                       i = (regno << 8) | regno;
-                       ((u32*)(info->pseudo_palette))[regno] = (i << 16) | i;
-                       }
-                       break;
-               }
-       }
-       return 0;
-}
-
-/*
- * Framebuffer option structure
- */
-static struct fb_ops igafb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_setcolreg   = igafb_setcolreg,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
-#ifdef CONFIG_SPARC
-       .fb_mmap        = igafb_mmap,
-#endif
-};
-
-static int __init iga_init(struct fb_info *info, struct iga_par *par)
-{
-        char vramsz = iga_inb(par, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
-                                                        & MEM_SIZE_ALIAS;
-       int video_cmap_len;
-
-        switch (vramsz) {
-        case MEM_SIZE_1M:
-                info->fix.smem_len = 0x100000;
-                break;
-        case MEM_SIZE_2M:
-                info->fix.smem_len = 0x200000;
-                break;
-        case MEM_SIZE_4M:
-        case MEM_SIZE_RESERVED:
-                info->fix.smem_len = 0x400000;
-                break;
-        }
-
-        if (info->var.bits_per_pixel > 8) 
-                video_cmap_len = 16;
-        else 
-                video_cmap_len = 256;
-
-       info->fbops = &igafb_ops;
-       info->flags = FBINFO_DEFAULT;
-
-       fb_alloc_cmap(&info->cmap, video_cmap_len, 0);
-
-       if (register_framebuffer(info) < 0)
-               return 0;
-
-       fb_info(info, "%s frame buffer device at 0x%08lx [%dMB VRAM]\n",
-               info->fix.id, par->frame_buffer_phys, info->fix.smem_len >> 20);
-
-       iga_blank_border(par); 
-       return 1;
-}
-
-static int __init igafb_init(void)
-{
-        struct fb_info *info;
-        struct pci_dev *pdev;
-        struct iga_par *par;
-       unsigned long addr;
-       int size, iga2000 = 0;
-
-       if (fb_get_options("igafb", NULL))
-               return -ENODEV;
-
-        pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
-                               PCI_DEVICE_ID_INTERG_1682, 0);
-       if (pdev == NULL) {
-               /*
-                * XXX We tried to use cyber2000fb.c for IGS 2000.
-                * But it does not initialize the chip in JavaStation-E, alas.
-                */
-               pdev = pci_get_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
-               if(pdev == NULL) {
-                       return -ENXIO;
-               }
-               iga2000 = 1;
-       }
-       /* We leak a reference here but as it cannot be unloaded this is
-          fine. If you write unload code remember to free it in unload */
-       
-       size = sizeof(struct iga_par) + sizeof(u32)*16;
-
-       info = framebuffer_alloc(size, &pdev->dev);
-        if (!info) {
-                printk("igafb_init: can't alloc fb_info\n");
-                pci_dev_put(pdev);
-                return -ENOMEM;
-        }
-
-       par = info->par;
-
-       if ((addr = pdev->resource[0].start) == 0) {
-                printk("igafb_init: no memory start\n");
-               kfree(info);
-               pci_dev_put(pdev);
-               return -ENXIO;
-       }
-
-       if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
-                printk("igafb_init: can't remap %lx[2M]\n", addr);
-               kfree(info);
-               pci_dev_put(pdev);
-               return -ENXIO;
-       }
-
-       par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
-
-#ifdef CONFIG_SPARC
-       /*
-        * The following is sparc specific and this is why:
-        *
-        * IGS2000 has its I/O memory mapped and we want
-        * to generate memory cycles on PCI, e.g. do ioremap(),
-        * then readb/writeb() as in Documentation/io-mapping.txt.
-        *
-        * IGS1682 is more traditional, it responds to PCI I/O
-        * cycles, so we want to access it with inb()/outb().
-        *
-        * On sparc, PCIC converts CPU memory access within
-        * phys window 0x3000xxxx into PCI I/O cycles. Therefore
-        * we may use readb/writeb to access them with IGS1682.
-        *
-        * We do not take io_base_phys from resource[n].start
-        * on IGS1682 because that chip is BROKEN. It does not
-        * have a base register for I/O. We just "know" what its
-        * I/O addresses are.
-        */
-       if (iga2000) {
-               igafb_fix.mmio_start = par->frame_buffer_phys | 0x00800000;
-       } else {
-               igafb_fix.mmio_start = 0x30000000;      /* XXX */
-       }
-       if ((par->io_base = (int) ioremap(igafb_fix.mmio_start, igafb_fix.smem_len)) == 0) {
-                printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
-               iounmap((void *)info->screen_base);
-               kfree(info);
-               pci_dev_put(pdev);
-               return -ENXIO;
-       }
-
-       /*
-        * Figure mmap addresses from PCI config space.
-        * We need two regions: for video memory and for I/O ports.
-        * Later one can add region for video coprocessor registers.
-        * However, mmap routine loops until size != 0, so we put
-        * one additional region with size == 0. 
-        */
-
-       par->mmap_map = kzalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC);
-       if (!par->mmap_map) {
-               printk("igafb_init: can't alloc mmap_map\n");
-               iounmap((void *)par->io_base);
-               iounmap(info->screen_base);
-               kfree(info);
-               pci_dev_put(pdev);
-               return -ENOMEM;
-       }
-
-       /*
-        * Set default vmode and cmode from PROM properties.
-        */
-       {
-               struct device_node *dp = pci_device_to_OF_node(pdev);
-                int node = dp->node;
-                int width = prom_getintdefault(node, "width", 1024);
-                int height = prom_getintdefault(node, "height", 768);
-                int depth = prom_getintdefault(node, "depth", 8);
-                switch (width) {
-                    case 1024:
-                        if (height == 768)
-                            default_var = default_var_1024x768;
-                        break;
-                    case 1152:
-                        if (height == 900)
-                            default_var = default_var_1152x900;
-                        break;
-                    case 1280:
-                        if (height == 1024)
-                            default_var = default_var_1280x1024;
-                        break;
-                    default:
-                        break;
-                }
-
-                switch (depth) {
-                    case 8:
-                        default_var.bits_per_pixel = 8;
-                        break;
-                    case 16:
-                        default_var.bits_per_pixel = 16;
-                        break;
-                    case 24:
-                        default_var.bits_per_pixel = 24;
-                        break;
-                    case 32:
-                        default_var.bits_per_pixel = 32;
-                        break;
-                    default:
-                        break;
-                }
-            }
-
-#endif
-       igafb_fix.smem_start = (unsigned long) info->screen_base;
-       igafb_fix.line_length = default_var.xres*(default_var.bits_per_pixel/8);
-       igafb_fix.visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-
-       info->var = default_var;
-       info->fix = igafb_fix;
-       info->pseudo_palette = (void *)(par + 1);
-
-       if (!iga_init(info, par)) {
-               iounmap((void *)par->io_base);
-               iounmap(info->screen_base);
-               kfree(par->mmap_map);
-               kfree(info);
-               return -ENODEV;
-        }
-
-#ifdef CONFIG_SPARC
-           /*
-            * Add /dev/fb mmap values.
-            */
-           
-           /* First region is for video memory */
-           par->mmap_map[0].voff = 0x0;  
-           par->mmap_map[0].poff = par->frame_buffer_phys & PAGE_MASK;
-           par->mmap_map[0].size = info->fix.smem_len & PAGE_MASK;
-           par->mmap_map[0].prot_mask = SRMMU_CACHE;
-           par->mmap_map[0].prot_flag = SRMMU_WRITE;
-
-           /* Second region is for I/O ports */
-           par->mmap_map[1].voff = par->frame_buffer_phys & PAGE_MASK;
-           par->mmap_map[1].poff = info->fix.smem_start & PAGE_MASK;
-           par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
-           par->mmap_map[1].prot_mask = SRMMU_CACHE;
-           par->mmap_map[1].prot_flag = SRMMU_WRITE;
-#endif /* CONFIG_SPARC */
-
-       return 0;
-}
-
-static int __init igafb_setup(char *options)
-{
-    char *this_opt;
-
-    if (!options || !*options)
-        return 0;
-
-    while ((this_opt = strsep(&options, ",")) != NULL) {
-    }
-    return 0;
-}
-
-module_init(igafb_init);
-MODULE_LICENSE("GPL");
-static struct pci_device_id igafb_pci_tbl[] = {
-       { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { }
-};
-
-MODULE_DEVICE_TABLE(pci, igafb_pci_tbl);
index d31ed4e2c46f1020ab84e8899337c3bd82fabd18..83fec573cceb78f6fa9b5a13e1787bdd2fcb5e41 100644 (file)
@@ -937,15 +937,11 @@ static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
 {
        u32 m1, m2, n, p1, p2, n1, testm;
        u32 f_vco, p, p_best = 0, m, f_out = 0;
-       u32 err_max, err_target, err_best = 10000000;
-       u32 n_best = 0, m_best = 0, f_best, f_err;
+       u32 err_best = 10000000;
+       u32 n_best = 0, m_best = 0, f_err;
        u32 p_min, p_max, p_inc, div_max;
        struct pll_min_max *pll = &plls[index];
 
-       /* Accept 0.5% difference, but aim for 0.1% */
-       err_max = 5 * clock / 1000;
-       err_target = clock / 1000;
-
        DBG_MSG("Clock is %d\n", clock);
 
        div_max = pll->max_vco / clock;
@@ -992,7 +988,6 @@ static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
                                        m_best = testm;
                                        n_best = n;
                                        p_best = p;
-                                       f_best = f_out;
                                        err_best = f_err;
                                }
                        }
index b9b284d79631d35b11f65536d516314b6157b956..838869c6490c2e4dcf87a4b35d5103d62976657b 100644 (file)
@@ -2056,7 +2056,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
 
        minfo = kzalloc(sizeof(*minfo), GFP_KERNEL);
        if (!minfo)
-               return -1;
+               return -ENOMEM;
 
        minfo->pcidev = pdev;
        minfo->dead = 0;
index 7846f0e8bbbb55f9ad691b733b6d2333452a672e..79b1dc7f042b220277a997169efdee2757784554 100644 (file)
 #define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
 
 #define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT        (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT  (1 << 7) /* negtive edge sampling */
+#define MXSFB_SYNC_DOTCLK_FALLING_ACT  (1 << 7) /* negative edge sampling */
 
 enum mxsfb_devtype {
        MXSFB_V3,
@@ -788,7 +788,16 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host,
 
        if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
                host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
-       if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+
+       /*
+        * The PIXDATA flags of the display_flags enum are controller
+        * centric, e.g. NEGEDGE means drive data on negative edge.
+        * However, the drivers flag is display centric: Sample the
+        * data on negative (falling) edge. Therefore, check for the
+        * POSEDGE flag:
+        * drive on positive edge => sample on negative edge
+        */
+       if (vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
                host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
 
 put_display_node:
index a4ee65b8f9187f8788aec8ae9a92e0169319c38c..6199d48061938c536e7f9803e4286d548e160f15 100644 (file)
@@ -474,7 +474,7 @@ static void auto_update_complete(void *data)
                          jiffies + HWA742_AUTO_UPDATE_TIME);
 }
 
-static void hwa742_update_window_auto(unsigned long arg)
+static void hwa742_update_window_auto(struct timer_list *unused)
 {
        LIST_HEAD(req_list);
        struct hwa742_request *last;
@@ -1002,9 +1002,7 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
        hwa742.auto_update_window.height = fbdev->panel->y_res;
        hwa742.auto_update_window.format = 0;
 
-       init_timer(&hwa742.auto_update_timer);
-       hwa742.auto_update_timer.function = hwa742_update_window_auto;
-       hwa742.auto_update_timer.data = 0;
+       timer_setup(&hwa742.auto_update_timer, hwa742_update_window_auto, 0);
 
        hwa742.prev_color_mode = -1;
        hwa742.prev_flags = 0;
index 30d49f3800b334b0a3f6b8ed29ea437d30cb632e..8e1d60d48dbb0edb507093581bd45833bd563d0c 100644 (file)
@@ -3988,7 +3988,7 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev)
 }
 
 #ifdef DSI_CATCH_MISSING_TE
-static void dsi_te_timeout(unsigned long arg)
+static void dsi_te_timeout(struct timer_list *unused)
 {
        DSSERR("TE not received for 250ms!\n");
 }
@@ -5298,9 +5298,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
                             dsi_framedone_timeout_work_callback);
 
 #ifdef DSI_CATCH_MISSING_TE
-       init_timer(&dsi->te_timer);
-       dsi->te_timer.function = dsi_te_timeout;
-       dsi->te_timer.data = 0;
+       timer_setup(&dsi->te_timer, dsi_te_timeout, 0);
 #endif
 
        res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto");
index 1d7c012f09dbb70cb0c5d1aed909272c94c4b4b3..e08e5664e330f84adcb99afbfda605556611fe64 100644 (file)
@@ -1477,7 +1477,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
 static int omapfb_parse_vram_param(const char *param, int max_entries,
                unsigned long *sizes, unsigned long *paddrs)
 {
-       int fbnum;
+       unsigned int fbnum;
        unsigned long size;
        unsigned long paddr = 0;
        char *p, *start;
index 933619da1a94b94e97c5c5f81b082b2eab7385df..55fbb432c05352271380f25fd5da5c5502a7af51 100644 (file)
@@ -512,28 +512,26 @@ pxa3xx_gcu_mmap(struct file *file, struct vm_area_struct *vma)
 
 #ifdef PXA3XX_GCU_DEBUG_TIMER
 static struct timer_list pxa3xx_gcu_debug_timer;
+static struct pxa3xx_gcu_priv *debug_timer_priv;
 
-static void pxa3xx_gcu_debug_timedout(unsigned long ptr)
+static void pxa3xx_gcu_debug_timedout(struct timer_list *unused)
 {
-       struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr;
+       struct pxa3xx_gcu_priv *priv = debug_timer_priv;
 
        QERROR("Timer DUMP");
 
-       /* init the timer structure */
-       init_timer(&pxa3xx_gcu_debug_timer);
-       pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout;
-       pxa3xx_gcu_debug_timer.data = ptr;
-       pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */
-
-       add_timer(&pxa3xx_gcu_debug_timer);
+       mod_timer(&pxa3xx_gcu_debug_timer, jiffies + 5 * HZ);
 }
 
-static void pxa3xx_gcu_init_debug_timer(void)
+static void pxa3xx_gcu_init_debug_timer(struct pxa3xx_gcu_priv *priv)
 {
-       pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer);
+       /* init the timer structure */
+       debug_timer_priv = priv;
+       timer_setup(&pxa3xx_gcu_debug_timer, pxa3xx_gcu_debug_timedout, 0);
+       pxa3xx_gcu_debug_timedout(NULL);
 }
 #else
-static inline void pxa3xx_gcu_init_debug_timer(void) {}
+static inline void pxa3xx_gcu_init_debug_timer(struct pxa3xx_gcu_priv *priv) {}
 #endif
 
 static int
@@ -670,7 +668,7 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, priv);
        priv->resource_mem = r;
        pxa3xx_gcu_reset(priv);
-       pxa3xx_gcu_init_debug_timer();
+       pxa3xx_gcu_init_debug_timer(priv);
 
        dev_info(dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
                        (void *) r->start, (void *) priv->shared_phys,
index fc2aaa5aca2347e705c6eb1623ec188b5262e498..15ae50063296ed823836066b7e3a4a26a2021d9b 100644 (file)
@@ -323,13 +323,11 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                 * according to the RGB bitfield information.
                 */
                if (regno < 16) {
-                       u32 *pal = fbi->fb.pseudo_palette;
-
                        val  = chan_to_field(red, &fbi->fb.var.red);
                        val |= chan_to_field(green, &fbi->fb.var.green);
                        val |= chan_to_field(blue, &fbi->fb.var.blue);
 
-                       pal[regno] = val;
+                       fbi->pseudo_palette[regno] = val;
                        ret = 0;
                }
                break;
@@ -1132,12 +1130,10 @@ static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
        struct sa1100fb_info *fbi;
        unsigned i;
 
-       fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
-                     GFP_KERNEL);
+       fbi = devm_kzalloc(dev, sizeof(struct sa1100fb_info), GFP_KERNEL);
        if (!fbi)
                return NULL;
 
-       memset(fbi, 0, sizeof(struct sa1100fb_info));
        fbi->dev = dev;
 
        strcpy(fbi->fb.fix.id, SA1100_NAME);
@@ -1159,7 +1155,7 @@ static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
        fbi->fb.fbops           = &sa1100fb_ops;
        fbi->fb.flags           = FBINFO_DEFAULT;
        fbi->fb.monspecs        = monspecs;
-       fbi->fb.pseudo_palette  = (fbi + 1);
+       fbi->fb.pseudo_palette  = fbi->pseudo_palette;
 
        fbi->rgb[RGB_4]         = &rgb_4;
        fbi->rgb[RGB_8]         = &rgb_8;
@@ -1218,48 +1214,42 @@ static int sa1100fb_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0 || !res)
+       if (irq < 0)
                return -EINVAL;
 
-       if (!request_mem_region(res->start, resource_size(res), "LCD"))
-               return -EBUSY;
-
        fbi = sa1100fb_init_fbinfo(&pdev->dev);
-       ret = -ENOMEM;
        if (!fbi)
-               goto failed;
-
-       fbi->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(fbi->clk)) {
-               ret = PTR_ERR(fbi->clk);
-               fbi->clk = NULL;
-               goto failed;
-       }
+               return -ENOMEM;
 
-       fbi->base = ioremap(res->start, resource_size(res));
-       if (!fbi->base)
-               goto failed;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       fbi->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(fbi->base))
+               return PTR_ERR(fbi->base);
 
-       /* Initialize video memory */
-       ret = sa1100fb_map_video_memory(fbi);
-       if (ret)
-               goto failed;
+       fbi->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(fbi->clk))
+               return PTR_ERR(fbi->clk);
 
-       ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
+       ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0,
+                              "LCD", fbi);
        if (ret) {
                dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
-               goto failed;
+               return ret;
        }
 
        if (machine_is_shannon()) {
-               ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
+               ret = devm_gpio_request_one(&pdev->dev, SHANNON_GPIO_DISP_EN,
                        GPIOF_OUT_INIT_LOW, "display enable");
                if (ret)
-                       goto err_free_irq;
+                       return ret;
        }
 
+       /* Initialize video memory */
+       ret = sa1100fb_map_video_memory(fbi);
+       if (ret)
+               return ret;
+
        /*
         * This makes sure that our colour bitfield
         * descriptors are correctly initialised.
@@ -1269,8 +1259,11 @@ static int sa1100fb_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, fbi);
 
        ret = register_framebuffer(&fbi->fb);
-       if (ret < 0)
-               goto err_reg_fb;
+       if (ret < 0) {
+               dma_free_wc(fbi->dev, fbi->map_size, fbi->map_cpu,
+                           fbi->map_dma);
+               return ret;
+       }
 
 #ifdef CONFIG_CPU_FREQ
        fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
@@ -1281,20 +1274,6 @@ static int sa1100fb_probe(struct platform_device *pdev)
 
        /* This driver cannot be unloaded at the moment */
        return 0;
-
- err_reg_fb:
-       if (machine_is_shannon())
-               gpio_free(SHANNON_GPIO_DISP_EN);
- err_free_irq:
-       free_irq(irq, fbi);
- failed:
-       if (fbi)
-               iounmap(fbi->base);
-       if (fbi->clk)
-               clk_put(fbi->clk);
-       kfree(fbi);
-       release_mem_region(res->start, resource_size(res));
-       return ret;
 }
 
 static struct platform_driver sa1100fb_driver = {
index 0139d13377a5efaf5e6667c4db7ef8ce99531257..7a1a9ca33cec55d81d579c31e7b2a3320491a168 100644 (file)
@@ -69,6 +69,8 @@ struct sa1100fb_info {
 
        const struct sa1100fb_mach_info *inf;
        struct clk *clk;
+
+       u32 pseudo_palette[16];
 };
 
 #define TO_INF(ptr,member)     container_of(ptr,struct sa1100fb_info,member)
index 1ec9c3e0e1d85092f4e06b3a2db04d9836e36a1f..02ee752d5000567148cf24a174471b559cfc80b1 100644 (file)
@@ -6486,7 +6486,7 @@ SiS_SetTVSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 
   if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
      if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
-        const unsigned char specialtv[] = {
+        static const unsigned char specialtv[] = {
                0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53,
                0x13,0x40,0x34,0xf4,0x63,0xbb,0xcc,0x7a,
                0x58,0xe4,0x73,0xda,0x13
index e92303823a4b083987090920011c79bb7b45c001..ecdd054d89510d0d68281c37ac7eb9caa9bb2c8e 100644 (file)
@@ -1702,6 +1702,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
+               /* fall through */
           case SISFB_GET_INFO:  /* For communication with X driver */
                ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
                ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
@@ -1755,6 +1756,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
+               /* fall through */
           case SISFB_GET_VBRSTATUS:
                if(sisfb_CheckVBRetrace(ivideo))
                        return put_user((u32)1, argp);
@@ -1765,6 +1767,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
+               /* fall through */
           case SISFB_GET_AUTOMAXIMIZE:
                if(ivideo->sisfb_max)
                        return put_user((u32)1, argp);
@@ -1775,6 +1778,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
+               /* fall through */
           case SISFB_SET_AUTOMAXIMIZE:
                if(get_user(gpu32, argp))
                        return -EFAULT;
index 076dd2711630e1f78c3bf19572915b0b2b9831ee..6f0a19501c6a8d959e1f4a994e705934808d4c77 100644 (file)
@@ -1008,6 +1008,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
        case FB_BLANK_POWERDOWN:
                ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
                sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
+               /* fall through */
 
        case FB_BLANK_NORMAL:
                ctrl |= SM501_DC_CRT_CONTROL_BLANK;
@@ -1889,6 +1890,9 @@ static void sm501_free_init_fb(struct sm501fb_info *info,
 {
        struct fb_info *fbi = info->fb[head];
 
+       if (!fbi)
+               return;
+
        fb_dealloc_cmap(&fbi->cmap);
 }
 
@@ -2076,8 +2080,10 @@ static int sm501fb_remove(struct platform_device *pdev)
        sm501_free_init_fb(info, HEAD_CRT);
        sm501_free_init_fb(info, HEAD_PANEL);
 
-       unregister_framebuffer(fbinfo_crt);
-       unregister_framebuffer(fbinfo_pnl);
+       if (fbinfo_crt)
+               unregister_framebuffer(fbinfo_crt);
+       if (fbinfo_pnl)
+               unregister_framebuffer(fbinfo_pnl);
 
        sm501fb_stop(info);
        kfree(info);
@@ -2094,8 +2100,12 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
                              enum sm501_controller head)
 {
        struct fb_info *fbi = info->fb[head];
-       struct sm501fb_par *par = fbi->par;
+       struct sm501fb_par *par;
+
+       if (!fbi)
+               return 0;
 
+       par = fbi->par;
        if (par->screen.size == 0)
                return 0;
 
@@ -2141,8 +2151,12 @@ static void sm501fb_resume_fb(struct sm501fb_info *info,
                              enum sm501_controller head)
 {
        struct fb_info *fbi = info->fb[head];
-       struct sm501fb_par *par = fbi->par;
+       struct sm501fb_par *par;
+
+       if (!fbi)
+               return;
 
+       par = fbi->par;
        if (par->screen.size == 0)
                return;
 
index ef08a104fb42c6dafe3c88d32ca18b7430ede759..d44f14242016e07682134c4f2bfa4832e6286462 100644 (file)
@@ -769,11 +769,11 @@ static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
 
        for (i = 0; i < len; i++) {
                ret = usb_control_msg(dev->udev,
-                                   usb_rcvctrlpipe(dev->udev, 0), (0x02),
-                                   (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
-                                   HZ);
-               if (ret < 1) {
-                       pr_err("Read EDID byte %d failed err %x\n", i, ret);
+                                     usb_rcvctrlpipe(dev->udev, 0), 0x02,
+                                     (0x80 | (0x02 << 5)), i << 8, 0xA1,
+                                     rbuf, 2, USB_CTRL_GET_TIMEOUT);
+               if (ret < 2) {
+                       pr_err("Read EDID byte %d failed: %d\n", i, ret);
                        i--;
                        break;
                }
index ff5d32cf9578f77aa28bebd2634fd61cb3d27064..a14b2c974c9eacea27943fe7a995e21ce4e1bb3a 100644 (file)
@@ -1160,7 +1160,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        struct ceph_inode_info *ci = cap->ci;
        struct inode *inode = &ci->vfs_inode;
        struct cap_msg_args arg;
-       int held, revoking, dropping;
+       int held, revoking;
        int wake = 0;
        int delayed = 0;
        int ret;
@@ -1168,7 +1168,6 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        held = cap->issued | cap->implemented;
        revoking = cap->implemented & ~cap->issued;
        retain &= ~revoking;
-       dropping = cap->issued & ~retain;
 
        dout("__send_cap %p cap %p session %p %s -> %s (revoking %s)\n",
             inode, cap, cap->session,
@@ -1712,7 +1711,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
 
        /* if we are unmounting, flush any unused caps immediately. */
        if (mdsc->stopping)
-               is_delayed = 1;
+               is_delayed = true;
 
        spin_lock(&ci->i_ceph_lock);
 
@@ -3189,8 +3188,8 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
        int dirty = le32_to_cpu(m->dirty);
        int cleaned = 0;
        bool drop = false;
-       bool wake_ci = 0;
-       bool wake_mdsc = 0;
+       bool wake_ci = false;
+       bool wake_mdsc = false;
 
        list_for_each_entry_safe(cf, tmp_cf, &ci->i_cap_flush_list, i_list) {
                if (cf->tid == flush_tid)
index f2550a076edc4e65da6e36354ef9ba2ba517d184..ab81652198c48e1e90a5545cb06089a6fa30da1a 100644 (file)
@@ -493,6 +493,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_wb_ref = 0;
        ci->i_wrbuffer_ref = 0;
        ci->i_wrbuffer_ref_head = 0;
+       atomic_set(&ci->i_filelock_ref, 0);
        ci->i_shared_gen = 0;
        ci->i_rdcache_gen = 0;
        ci->i_rdcache_revoking = 0;
@@ -786,7 +787,6 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
 
        /* update inode */
        ci->i_version = le64_to_cpu(info->version);
-       inode->i_version++;
        inode->i_rdev = le32_to_cpu(info->rdev);
        inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
 
@@ -1185,6 +1185,7 @@ retry_lookup:
                                    ceph_snap(d_inode(dn)) != tvino.snap)) {
                                dout(" dn %p points to wrong inode %p\n",
                                     dn, d_inode(dn));
+                               ceph_dir_clear_ordered(dir);
                                d_delete(dn);
                                dput(dn);
                                goto retry_lookup;
@@ -1322,6 +1323,7 @@ retry_lookup:
                        dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
                             dn, d_inode(dn), ceph_vinop(d_inode(dn)),
                             ceph_vinop(in));
+                       ceph_dir_clear_ordered(dir);
                        d_invalidate(dn);
                        have_lease = false;
                }
@@ -1573,6 +1575,7 @@ retry_lookup:
                            ceph_snap(d_inode(dn)) != tvino.snap)) {
                        dout(" dn %p points to wrong inode %p\n",
                             dn, d_inode(dn));
+                       __ceph_dir_clear_ordered(ci);
                        d_delete(dn);
                        dput(dn);
                        goto retry_lookup;
@@ -1597,7 +1600,9 @@ retry_lookup:
                                 &req->r_caps_reservation);
                if (ret < 0) {
                        pr_err("fill_inode badness on %p\n", in);
-                       if (d_really_is_negative(dn))
+                       if (d_really_is_positive(dn))
+                               __ceph_dir_clear_ordered(ci);
+                       else
                                iput(in);
                        d_drop(dn);
                        err = ret;
index e7cce412f2cf7b5362606f2286291290a218b9c8..9e66f69ee8a5ecc9e8455465f232bf70529e59a8 100644 (file)
@@ -30,19 +30,52 @@ void __init ceph_flock_init(void)
        get_random_bytes(&lock_secret, sizeof(lock_secret));
 }
 
+static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
+{
+       struct inode *inode = file_inode(src->fl_file);
+       atomic_inc(&ceph_inode(inode)->i_filelock_ref);
+}
+
+static void ceph_fl_release_lock(struct file_lock *fl)
+{
+       struct inode *inode = file_inode(fl->fl_file);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       if (atomic_dec_and_test(&ci->i_filelock_ref)) {
+               /* clear error when all locks are released */
+               spin_lock(&ci->i_ceph_lock);
+               ci->i_ceph_flags &= ~CEPH_I_ERROR_FILELOCK;
+               spin_unlock(&ci->i_ceph_lock);
+       }
+}
+
+static const struct file_lock_operations ceph_fl_lock_ops = {
+       .fl_copy_lock = ceph_fl_copy_lock,
+       .fl_release_private = ceph_fl_release_lock,
+};
+
 /**
  * Implement fcntl and flock locking functions.
  */
-static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
+static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
                             int cmd, u8 wait, struct file_lock *fl)
 {
-       struct inode *inode = file_inode(file);
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        int err;
        u64 length = 0;
        u64 owner;
 
+       if (operation == CEPH_MDS_OP_SETFILELOCK) {
+               /*
+                * increasing i_filelock_ref closes race window between
+                * handling request reply and adding file_lock struct to
+                * inode. Otherwise, auth caps may get trimmed in the
+                * window. Caller function will decrease the counter.
+                */
+               fl->fl_ops = &ceph_fl_lock_ops;
+               atomic_inc(&ceph_inode(inode)->i_filelock_ref);
+       }
+
        if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
                wait = 0;
 
@@ -180,10 +213,12 @@ static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
  */
 int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 {
-       u8 lock_cmd;
-       int err;
-       u8 wait = 0;
+       struct inode *inode = file_inode(file);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int err = 0;
        u16 op = CEPH_MDS_OP_SETFILELOCK;
+       u8 wait = 0;
+       u8 lock_cmd;
 
        if (!(fl->fl_flags & FL_POSIX))
                return -ENOLCK;
@@ -199,6 +234,26 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        else if (IS_SETLKW(cmd))
                wait = 1;
 
+       spin_lock(&ci->i_ceph_lock);
+       if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
+               err = -EIO;
+       } else if (op == CEPH_MDS_OP_SETFILELOCK) {
+               /*
+                * increasing i_filelock_ref closes race window between
+                * handling request reply and adding file_lock struct to
+                * inode. Otherwise, i_auth_cap may get trimmed in the
+                * window. Caller function will decrease the counter.
+                */
+               fl->fl_ops = &ceph_fl_lock_ops;
+               atomic_inc(&ci->i_filelock_ref);
+       }
+       spin_unlock(&ci->i_ceph_lock);
+       if (err < 0) {
+               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type)
+                       posix_lock_file(file, fl, NULL);
+               return err;
+       }
+
        if (F_RDLCK == fl->fl_type)
                lock_cmd = CEPH_LOCK_SHARED;
        else if (F_WRLCK == fl->fl_type)
@@ -206,16 +261,16 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
-       err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
+       err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl);
        if (!err) {
-               if (op != CEPH_MDS_OP_GETFILELOCK) {
+               if (op == CEPH_MDS_OP_SETFILELOCK) {
                        dout("mds locked, locking locally");
                        err = posix_lock_file(file, fl, NULL);
-                       if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
+                       if (err) {
                                /* undo! This should only happen if
                                 * the kernel detects local
                                 * deadlock. */
-                               ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
+                               ceph_lock_message(CEPH_LOCK_FCNTL, op, inode,
                                                  CEPH_LOCK_UNLOCK, 0, fl);
                                dout("got %d on posix_lock_file, undid lock",
                                     err);
@@ -227,9 +282,11 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 
 int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
 {
-       u8 lock_cmd;
-       int err;
+       struct inode *inode = file_inode(file);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int err = 0;
        u8 wait = 0;
+       u8 lock_cmd;
 
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
@@ -239,6 +296,21 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
 
        dout("ceph_flock, fl_file: %p", fl->fl_file);
 
+       spin_lock(&ci->i_ceph_lock);
+       if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
+               err = -EIO;
+       } else {
+               /* see comment in ceph_lock */
+               fl->fl_ops = &ceph_fl_lock_ops;
+               atomic_inc(&ci->i_filelock_ref);
+       }
+       spin_unlock(&ci->i_ceph_lock);
+       if (err < 0) {
+               if (F_UNLCK == fl->fl_type)
+                       locks_lock_file_wait(file, fl);
+               return err;
+       }
+
        if (IS_SETLKW(cmd))
                wait = 1;
 
@@ -250,13 +322,13 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
                lock_cmd = CEPH_LOCK_UNLOCK;
 
        err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
-                               file, lock_cmd, wait, fl);
+                               inode, lock_cmd, wait, fl);
        if (!err) {
                err = locks_lock_file_wait(file, fl);
                if (err) {
                        ceph_lock_message(CEPH_LOCK_FLOCK,
                                          CEPH_MDS_OP_SETFILELOCK,
-                                         file, CEPH_LOCK_UNLOCK, 0, fl);
+                                         inode, CEPH_LOCK_UNLOCK, 0, fl);
                        dout("got %d on locks_lock_file_wait, undid lock", err);
                }
        }
@@ -288,6 +360,37 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
             *flock_count, *fcntl_count);
 }
 
+/*
+ * Given a pointer to a lock, convert it to a ceph filelock
+ */
+static int lock_to_ceph_filelock(struct file_lock *lock,
+                                struct ceph_filelock *cephlock)
+{
+       int err = 0;
+       cephlock->start = cpu_to_le64(lock->fl_start);
+       cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
+       cephlock->client = cpu_to_le64(0);
+       cephlock->pid = cpu_to_le64((u64)lock->fl_pid);
+       cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
+
+       switch (lock->fl_type) {
+       case F_RDLCK:
+               cephlock->type = CEPH_LOCK_SHARED;
+               break;
+       case F_WRLCK:
+               cephlock->type = CEPH_LOCK_EXCL;
+               break;
+       case F_UNLCK:
+               cephlock->type = CEPH_LOCK_UNLOCK;
+               break;
+       default:
+               dout("Have unknown lock type %d", lock->fl_type);
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
 /**
  * Encode the flock and fcntl locks for the given inode into the ceph_filelock
  * array. Must be called with inode->i_lock already held.
@@ -356,50 +459,22 @@ int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
        if (err)
                goto out_fail;
 
-       err = ceph_pagelist_append(pagelist, flocks,
-                                  num_fcntl_locks * sizeof(*flocks));
-       if (err)
-               goto out_fail;
+       if (num_fcntl_locks > 0) {
+               err = ceph_pagelist_append(pagelist, flocks,
+                                          num_fcntl_locks * sizeof(*flocks));
+               if (err)
+                       goto out_fail;
+       }
 
        nlocks = cpu_to_le32(num_flock_locks);
        err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
        if (err)
                goto out_fail;
 
-       err = ceph_pagelist_append(pagelist,
-                                  &flocks[num_fcntl_locks],
-                                  num_flock_locks * sizeof(*flocks));
-out_fail:
-       return err;
-}
-
-/*
- * Given a pointer to a lock, convert it to a ceph filelock
- */
-int lock_to_ceph_filelock(struct file_lock *lock,
-                         struct ceph_filelock *cephlock)
-{
-       int err = 0;
-       cephlock->start = cpu_to_le64(lock->fl_start);
-       cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
-       cephlock->client = cpu_to_le64(0);
-       cephlock->pid = cpu_to_le64((u64)lock->fl_pid);
-       cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
-
-       switch (lock->fl_type) {
-       case F_RDLCK:
-               cephlock->type = CEPH_LOCK_SHARED;
-               break;
-       case F_WRLCK:
-               cephlock->type = CEPH_LOCK_EXCL;
-               break;
-       case F_UNLCK:
-               cephlock->type = CEPH_LOCK_UNLOCK;
-               break;
-       default:
-               dout("Have unknown lock type %d", lock->fl_type);
-               err = -EINVAL;
+       if (num_flock_locks > 0) {
+               err = ceph_pagelist_append(pagelist, &flocks[num_fcntl_locks],
+                                          num_flock_locks * sizeof(*flocks));
        }
-
+out_fail:
        return err;
 }
index 0687ab3c32674d863213186dc4554d17ad219bf3..ab69dcb70e8ae342733f589338c02dc226f95356 100644 (file)
@@ -1039,22 +1039,23 @@ void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc,
  * session caps
  */
 
-/* caller holds s_cap_lock, we drop it */
-static void cleanup_cap_releases(struct ceph_mds_client *mdsc,
-                                struct ceph_mds_session *session)
-       __releases(session->s_cap_lock)
+static void detach_cap_releases(struct ceph_mds_session *session,
+                               struct list_head *target)
 {
-       LIST_HEAD(tmp_list);
-       list_splice_init(&session->s_cap_releases, &tmp_list);
+       lockdep_assert_held(&session->s_cap_lock);
+
+       list_splice_init(&session->s_cap_releases, target);
        session->s_num_cap_releases = 0;
-       spin_unlock(&session->s_cap_lock);
+       dout("dispose_cap_releases mds%d\n", session->s_mds);
+}
 
-       dout("cleanup_cap_releases mds%d\n", session->s_mds);
-       while (!list_empty(&tmp_list)) {
+static void dispose_cap_releases(struct ceph_mds_client *mdsc,
+                                struct list_head *dispose)
+{
+       while (!list_empty(dispose)) {
                struct ceph_cap *cap;
                /* zero out the in-progress message */
-               cap = list_first_entry(&tmp_list,
-                                       struct ceph_cap, session_caps);
+               cap = list_first_entry(dispose, struct ceph_cap, session_caps);
                list_del(&cap->session_caps);
                ceph_put_cap(mdsc, cap);
        }
@@ -1215,6 +1216,13 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                }
                spin_unlock(&mdsc->cap_dirty_lock);
 
+               if (atomic_read(&ci->i_filelock_ref) > 0) {
+                       /* make further file lock syscall return -EIO */
+                       ci->i_ceph_flags |= CEPH_I_ERROR_FILELOCK;
+                       pr_warn_ratelimited(" dropping file locks for %p %lld\n",
+                                           inode, ceph_ino(inode));
+               }
+
                if (!ci->i_dirty_caps && ci->i_prealloc_cap_flush) {
                        list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove);
                        ci->i_prealloc_cap_flush = NULL;
@@ -1244,6 +1252,8 @@ static void remove_session_caps(struct ceph_mds_session *session)
 {
        struct ceph_fs_client *fsc = session->s_mdsc->fsc;
        struct super_block *sb = fsc->sb;
+       LIST_HEAD(dispose);
+
        dout("remove_session_caps on %p\n", session);
        iterate_session_caps(session, remove_session_caps_cb, fsc);
 
@@ -1278,10 +1288,12 @@ static void remove_session_caps(struct ceph_mds_session *session)
        }
 
        // drop cap expires and unlock s_cap_lock
-       cleanup_cap_releases(session->s_mdsc, session);
+       detach_cap_releases(session, &dispose);
 
        BUG_ON(session->s_nr_caps > 0);
        BUG_ON(!list_empty(&session->s_cap_flushing));
+       spin_unlock(&session->s_cap_lock);
+       dispose_cap_releases(session->s_mdsc, &dispose);
 }
 
 /*
@@ -1462,6 +1474,11 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
                        goto out;
                if ((used | wanted) & CEPH_CAP_ANY_WR)
                        goto out;
+               /* Note: it's possible that i_filelock_ref becomes non-zero
+                * after dropping auth caps. It doesn't hurt because reply
+                * of lock mds request will re-add auth caps. */
+               if (atomic_read(&ci->i_filelock_ref) > 0)
+                       goto out;
        }
        /* The inode has cached pages, but it's no longer used.
         * we can safely drop it */
@@ -2827,7 +2844,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                struct ceph_mds_cap_reconnect v2;
                struct ceph_mds_cap_reconnect_v1 v1;
        } rec;
-       struct ceph_inode_info *ci;
+       struct ceph_inode_info *ci = cap->ci;
        struct ceph_reconnect_state *recon_state = arg;
        struct ceph_pagelist *pagelist = recon_state->pagelist;
        char *path;
@@ -2836,8 +2853,6 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
        u64 snap_follows;
        struct dentry *dentry;
 
-       ci = cap->ci;
-
        dout(" adding %p ino %llx.%llx cap %p %lld %s\n",
             inode, ceph_vinop(inode), cap, cap->cap_id,
             ceph_cap_string(cap->issued));
@@ -2870,7 +2885,8 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                rec.v2.issued = cpu_to_le32(cap->issued);
                rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
                rec.v2.pathbase = cpu_to_le64(pathbase);
-               rec.v2.flock_len = 0;
+               rec.v2.flock_len = (__force __le32)
+                       ((ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) ? 0 : 1);
        } else {
                rec.v1.cap_id = cpu_to_le64(cap->cap_id);
                rec.v1.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
@@ -2894,26 +2910,37 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
 
        if (recon_state->msg_version >= 2) {
                int num_fcntl_locks, num_flock_locks;
-               struct ceph_filelock *flocks;
+               struct ceph_filelock *flocks = NULL;
                size_t struct_len, total_len = 0;
                u8 struct_v = 0;
 
 encode_again:
-               ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
-               flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
-                                sizeof(struct ceph_filelock), GFP_NOFS);
-               if (!flocks) {
-                       err = -ENOMEM;
-                       goto out_free;
+               if (rec.v2.flock_len) {
+                       ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
+               } else {
+                       num_fcntl_locks = 0;
+                       num_flock_locks = 0;
                }
-               err = ceph_encode_locks_to_buffer(inode, flocks,
-                                                 num_fcntl_locks,
-                                                 num_flock_locks);
-               if (err) {
+               if (num_fcntl_locks + num_flock_locks > 0) {
+                       flocks = kmalloc((num_fcntl_locks + num_flock_locks) *
+                                        sizeof(struct ceph_filelock), GFP_NOFS);
+                       if (!flocks) {
+                               err = -ENOMEM;
+                               goto out_free;
+                       }
+                       err = ceph_encode_locks_to_buffer(inode, flocks,
+                                                         num_fcntl_locks,
+                                                         num_flock_locks);
+                       if (err) {
+                               kfree(flocks);
+                               flocks = NULL;
+                               if (err == -ENOSPC)
+                                       goto encode_again;
+                               goto out_free;
+                       }
+               } else {
                        kfree(flocks);
-                       if (err == -ENOSPC)
-                               goto encode_again;
-                       goto out_free;
+                       flocks = NULL;
                }
 
                if (recon_state->msg_version >= 3) {
@@ -2993,6 +3020,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
        int s_nr_caps;
        struct ceph_pagelist *pagelist;
        struct ceph_reconnect_state recon_state;
+       LIST_HEAD(dispose);
 
        pr_info("mds%d reconnect start\n", mds);
 
@@ -3026,7 +3054,9 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
         */
        session->s_cap_reconnect = 1;
        /* drop old cap expires; we're about to reestablish that state */
-       cleanup_cap_releases(mdsc, session);
+       detach_cap_releases(session, &dispose);
+       spin_unlock(&session->s_cap_lock);
+       dispose_cap_releases(mdsc, &dispose);
 
        /* trim unused caps to reduce MDS's cache rejoin time */
        if (mdsc->fsc->sb->s_root)
@@ -3857,14 +3887,14 @@ void ceph_mdsc_handle_fsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
                goto err_out;
        }
        return;
+
 bad:
        pr_err("error decoding fsmap\n");
 err_out:
        mutex_lock(&mdsc->mutex);
-       mdsc->mdsmap_err = -ENOENT;
+       mdsc->mdsmap_err = err;
        __wake_requests(mdsc, &mdsc->waiting_for_map);
        mutex_unlock(&mdsc->mutex);
-       return;
 }
 
 /*
index e4082afedcb15a447ee7fd344aa2a3def391d43c..fe9fbb3f13f7c7128c00e103888cbbd8d1136717 100644 (file)
@@ -84,8 +84,9 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_ffree = -1;
        buf->f_namelen = NAME_MAX;
 
-       /* leave fsid little-endian, regardless of host endianness */
-       fsid = *(u64 *)(&monmap->fsid) ^ *((u64 *)&monmap->fsid + 1);
+       /* Must convert the fsid, for consistent values across arches */
+       fsid = le64_to_cpu(*(__le64 *)(&monmap->fsid)) ^
+              le64_to_cpu(*((__le64 *)&monmap->fsid + 1));
        buf->f_fsid.val[0] = fsid & 0xffffffff;
        buf->f_fsid.val[1] = fsid >> 32;
 
index 3e27a28aa44adfd2da34ff995ff9481ac749d043..2beeec07fa76ce199e7d461831b9b93a705419ee 100644 (file)
@@ -352,6 +352,7 @@ struct ceph_inode_info {
        int i_pin_ref;
        int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
        int i_wrbuffer_ref, i_wrbuffer_ref_head;
+       atomic_t i_filelock_ref;
        u32 i_shared_gen;       /* increment each time we get FILE_SHARED */
        u32 i_rdcache_gen;      /* incremented each time we get FILE_CACHE. */
        u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
@@ -487,6 +488,8 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
 #define CEPH_I_KICK_FLUSH      (1 << 9)  /* kick flushing caps */
 #define CEPH_I_FLUSH_SNAPS     (1 << 10) /* need flush snapss */
 #define CEPH_I_ERROR_WRITE     (1 << 11) /* have seen write errors */
+#define CEPH_I_ERROR_FILELOCK  (1 << 12) /* have seen file lock errors */
+
 
 /*
  * We set the ERROR_WRITE bit when we start seeing write errors on an inode
@@ -1011,7 +1014,6 @@ extern int ceph_encode_locks_to_buffer(struct inode *inode,
 extern int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
                                  struct ceph_pagelist *pagelist,
                                  int num_fcntl_locks, int num_flock_locks);
-extern int lock_to_ceph_filelock(struct file_lock *fl, struct ceph_filelock *c);
 
 /* debugfs.c */
 extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
index b837fb7e290a6a63346f1ad7f00e63f2db8a5382..a8e3777c94dc6c44ae050168bf7906eecf71d085 100644 (file)
@@ -369,6 +369,7 @@ static int lockd_start_svc(struct svc_serv *serv)
                printk(KERN_WARNING
                        "lockd_up: svc_rqst allocation failed, error=%d\n",
                        error);
+               lockd_unregister_notifiers();
                goto out_rqst;
        }
 
@@ -459,13 +460,16 @@ int lockd_up(struct net *net)
        }
 
        error = lockd_up_net(serv, net);
-       if (error < 0)
-               goto err_net;
+       if (error < 0) {
+               lockd_unregister_notifiers();
+               goto err_put;
+       }
 
        error = lockd_start_svc(serv);
-       if (error < 0)
-               goto err_start;
-
+       if (error < 0) {
+               lockd_down_net(serv, net);
+               goto err_put;
+       }
        nlmsvc_users++;
        /*
         * Note: svc_serv structures have an initial use count of 1,
@@ -476,12 +480,6 @@ err_put:
 err_create:
        mutex_unlock(&nlmsvc_mutex);
        return error;
-
-err_start:
-       lockd_down_net(serv, net);
-err_net:
-       lockd_unregister_notifiers();
-       goto err_put;
 }
 EXPORT_SYMBOL_GPL(lockd_up);
 
index 420d3a0ab258fb2b312310e50081bbab30f2c2ae..897b299db55e01e291641b35d25f4c903962fec5 100644 (file)
@@ -55,14 +55,7 @@ locks_end_grace(struct lock_manager *lm)
 }
 EXPORT_SYMBOL_GPL(locks_end_grace);
 
-/**
- * locks_in_grace
- *
- * Lock managers call this function to determine when it is OK for them
- * to answer ordinary lock requests, and when they should accept only
- * lock reclaims.
- */
-int
+static bool
 __state_in_grace(struct net *net, bool open)
 {
        struct list_head *grace_list = net_generic(net, grace_net_id);
@@ -78,15 +71,22 @@ __state_in_grace(struct net *net, bool open)
        return false;
 }
 
-int locks_in_grace(struct net *net)
+/**
+ * locks_in_grace
+ *
+ * Lock managers call this function to determine when it is OK for them
+ * to answer ordinary lock requests, and when they should accept only
+ * lock reclaims.
+ */
+bool locks_in_grace(struct net *net)
 {
-       return __state_in_grace(net, 0);
+       return __state_in_grace(net, false);
 }
 EXPORT_SYMBOL_GPL(locks_in_grace);
 
-int opens_in_grace(struct net *net)
+bool opens_in_grace(struct net *net)
 {
-       return __state_in_grace(net, 1);
+       return __state_in_grace(net, true);
 }
 EXPORT_SYMBOL_GPL(opens_in_grace);
 
index 6dfede6d172aa276ba99544cf561cf4744220ff7..84831253203dda4a4926db4a532098ffee8a1f4c 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/nsproxy.h>
 #include <linux/sunrpc/addr.h>
 #include <linux/uaccess.h>
+#include <linux/kernel.h>
 
 #include "state.h"
 #include "netns.h"
@@ -126,8 +127,6 @@ static struct nfsd_fault_inject_op inject_ops[] = {
        },
 };
 
-#define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op))
-
 int nfsd_fault_inject_init(void)
 {
        unsigned int i;
@@ -138,7 +137,7 @@ int nfsd_fault_inject_init(void)
        if (!debug_dir)
                goto fail;
 
-       for (i = 0; i < NUM_INJECT_OPS; i++) {
+       for (i = 0; i < ARRAY_SIZE(inject_ops); i++) {
                op = &inject_ops[i];
                if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
                        goto fail;
index 3714231a9d0fb71e4e440a9f8efa7113839c4392..1c91391f48055699bb5c9ffbe64ca31d709c7518 100644 (file)
@@ -107,7 +107,7 @@ struct nfsd_net {
        bool lockd_up;
 
        /* Time of server startup */
-       struct timeval nfssvc_boot;
+       struct timespec64 nfssvc_boot;
 
        /*
         * Max number of connections this nfsd container will allow. Defaults
index f38acd9054419606e3abd25060599960d38c6f2c..2758480555faa504b1aafc204ea549361bf3b932 100644 (file)
@@ -748,8 +748,9 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
        if (resp->status == 0) {
                *p++ = htonl(resp->count);
                *p++ = htonl(resp->committed);
-               *p++ = htonl(nn->nfssvc_boot.tv_sec);
-               *p++ = htonl(nn->nfssvc_boot.tv_usec);
+               /* unique identifier, y2038 overflow can be ignored */
+               *p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
+               *p++ = htonl(nn->nfssvc_boot.tv_nsec);
        }
        return xdr_ressize_check(rqstp, p);
 }
@@ -1119,8 +1120,9 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
        p = encode_wcc_data(rqstp, p, &resp->fh);
        /* Write verifier */
        if (resp->status == 0) {
-               *p++ = htonl(nn->nfssvc_boot.tv_sec);
-               *p++ = htonl(nn->nfssvc_boot.tv_usec);
+               /* unique identifier, y2038 overflow can be ignored */
+               *p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
+               *p++ = htonl(nn->nfssvc_boot.tv_nsec);
        }
        return xdr_ressize_check(rqstp, p);
 }
index ea45d954e8d7c53cbb3db6dcbf8ac3958b314a90..7d888369f85a4194b0ddf0c2202bb693fe9cac99 100644 (file)
@@ -336,7 +336,7 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
 
        trace_layout_recall(&ls->ls_stid.sc_stateid);
 
-       atomic_inc(&ls->ls_stid.sc_count);
+       refcount_inc(&ls->ls_stid.sc_count);
        nfsd4_run_cb(&ls->ls_recall);
 
 out_unlock:
@@ -441,7 +441,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls)
                        goto done;
        }
 
-       atomic_inc(&ls->ls_stid.sc_count);
+       refcount_inc(&ls->ls_stid.sc_count);
        list_add_tail(&new->lo_perstate, &ls->ls_layouts);
        new = NULL;
 done:
index 8487486ec4963efb72477e7cf2f19616108f12f2..008ea0b627d02d5a06f8b3febb793627e11b70c3 100644 (file)
@@ -485,9 +485,6 @@ static __be32
 nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            union nfsd4_op_u *u)
 {
-       if (!cstate->current_fh.fh_dentry)
-               return nfserr_nofilehandle;
-
        u->getfh = &cstate->current_fh;
        return nfs_ok;
 }
@@ -535,9 +532,6 @@ static __be32
 nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
             union nfsd4_op_u *u)
 {
-       if (!cstate->current_fh.fh_dentry)
-               return nfserr_nofilehandle;
-
        fh_dup2(&cstate->save_fh, &cstate->current_fh);
        if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
                memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
@@ -570,10 +564,11 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
 
        /*
         * This is opaque to client, so no need to byte-swap. Use
-        * __force to keep sparse happy
+        * __force to keep sparse happy. y2038 time_t overflow is
+        * irrelevant in this usage.
         */
        verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
-       verf[1] = (__force __be32)nn->nfssvc_boot.tv_usec;
+       verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec;
        memcpy(verifier->data, verf, sizeof(verifier->data));
 }
 
@@ -703,10 +698,8 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
           union nfsd4_op_u *u)
 {
        struct nfsd4_link *link = &u->link;
-       __be32 status = nfserr_nofilehandle;
+       __be32 status;
 
-       if (!cstate->save_fh.fh_dentry)
-               return status;
        status = nfsd_link(rqstp, &cstate->current_fh,
                           link->li_name, link->li_namelen, &cstate->save_fh);
        if (!status)
@@ -850,10 +843,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
             union nfsd4_op_u *u)
 {
        struct nfsd4_rename *rename = &u->rename;
-       __be32 status = nfserr_nofilehandle;
+       __be32 status;
 
-       if (!cstate->save_fh.fh_dentry)
-               return status;
        if (opens_in_grace(SVC_NET(rqstp)) &&
                !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK))
                return nfserr_grace;
index 0c04f81aa63b225b2207b226b1113e1973ec1e1b..b82817767b9da4ea6e8e3fc0cde8e6f068756ca7 100644 (file)
@@ -359,7 +359,7 @@ put_nfs4_file(struct nfs4_file *fi)
 {
        might_lock(&state_lock);
 
-       if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
+       if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
                hlist_del_rcu(&fi->fi_hash);
                spin_unlock(&state_lock);
                WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
@@ -568,7 +568,7 @@ alloc_clnt_odstate(struct nfs4_client *clp)
        co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
        if (co) {
                co->co_client = clp;
-               atomic_set(&co->co_odcount, 1);
+               refcount_set(&co->co_odcount, 1);
        }
        return co;
 }
@@ -586,7 +586,7 @@ static inline void
 get_clnt_odstate(struct nfs4_clnt_odstate *co)
 {
        if (co)
-               atomic_inc(&co->co_odcount);
+               refcount_inc(&co->co_odcount);
 }
 
 static void
@@ -598,7 +598,7 @@ put_clnt_odstate(struct nfs4_clnt_odstate *co)
                return;
 
        fp = co->co_file;
-       if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
+       if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
                list_del(&co->co_perfile);
                spin_unlock(&fp->fi_lock);
 
@@ -656,7 +656,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
        stid->sc_stateid.si_opaque.so_id = new_id;
        stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
        /* Will be incremented before return to client: */
-       atomic_set(&stid->sc_count, 1);
+       refcount_set(&stid->sc_count, 1);
        spin_lock_init(&stid->sc_lock);
 
        /*
@@ -813,7 +813,7 @@ nfs4_put_stid(struct nfs4_stid *s)
 
        might_lock(&clp->cl_lock);
 
-       if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
+       if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
                wake_up_all(&close_wq);
                return;
        }
@@ -913,7 +913,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
        if (status)
                return status;
        ++fp->fi_delegees;
-       atomic_inc(&dp->dl_stid.sc_count);
+       refcount_inc(&dp->dl_stid.sc_count);
        dp->dl_stid.sc_type = NFS4_DELEG_STID;
        list_add(&dp->dl_perfile, &fp->fi_delegations);
        list_add(&dp->dl_perclnt, &clp->cl_delegations);
@@ -1214,7 +1214,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
 
        WARN_ON_ONCE(!list_empty(&stp->st_locks));
 
-       if (!atomic_dec_and_test(&s->sc_count)) {
+       if (!refcount_dec_and_test(&s->sc_count)) {
                wake_up_all(&close_wq);
                return;
        }
@@ -1439,8 +1439,10 @@ free_session_slots(struct nfsd4_session *ses)
 {
        int i;
 
-       for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+       for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
+               free_svc_cred(&ses->se_slots[i]->sl_cred);
                kfree(ses->se_slots[i]);
+       }
 }
 
 /*
@@ -1472,6 +1474,11 @@ static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
        spin_lock(&nfsd_drc_lock);
        avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
                    nfsd_drc_max_mem - nfsd_drc_mem_used);
+       /*
+        * Never use more than a third of the remaining memory,
+        * unless it's the only way to give this client a slot:
+        */
+       avail = clamp_t(int, avail, slotsize, avail/3);
        num = min_t(int, num, avail / slotsize);
        nfsd_drc_mem_used += num * slotsize;
        spin_unlock(&nfsd_drc_lock);
@@ -2072,7 +2079,7 @@ find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
        s = find_stateid_locked(cl, t);
        if (s != NULL) {
                if (typemask & s->sc_type)
-                       atomic_inc(&s->sc_count);
+                       refcount_inc(&s->sc_count);
                else
                        s = NULL;
        }
@@ -2287,14 +2294,18 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
 
        dprintk("--> %s slot %p\n", __func__, slot);
 
+       slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
        slot->sl_opcnt = resp->opcnt;
        slot->sl_status = resp->cstate.status;
+       free_svc_cred(&slot->sl_cred);
+       copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
 
-       slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
-       if (nfsd4_not_cached(resp)) {
-               slot->sl_datalen = 0;
+       if (!nfsd4_cache_this(resp)) {
+               slot->sl_flags &= ~NFSD4_SLOT_CACHED;
                return;
        }
+       slot->sl_flags |= NFSD4_SLOT_CACHED;
+
        base = resp->cstate.data_offset;
        slot->sl_datalen = buf->len - base;
        if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
@@ -2321,8 +2332,16 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
        op = &args->ops[resp->opcnt - 1];
        nfsd4_encode_operation(resp, op);
 
-       /* Return nfserr_retry_uncached_rep in next operation. */
-       if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
+       if (slot->sl_flags & NFSD4_SLOT_CACHED)
+               return op->status;
+       if (args->opcnt == 1) {
+               /*
+                * The original operation wasn't a solo sequence--we
+                * always cache those--so this retry must not match the
+                * original:
+                */
+               op->status = nfserr_seq_false_retry;
+       } else {
                op = &args->ops[resp->opcnt++];
                op->status = nfserr_retry_uncached_rep;
                nfsd4_encode_operation(resp, op);
@@ -2986,6 +3005,34 @@ static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
        return xb->len > session->se_fchannel.maxreq_sz;
 }
 
+static bool replay_matches_cache(struct svc_rqst *rqstp,
+                struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
+{
+       struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+
+       if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
+           (bool)seq->cachethis)
+               return false;
+       /*
+        * If there's an error than the reply can have fewer ops than
+        * the call.  But if we cached a reply with *more* ops than the
+        * call you're sending us now, then this new call is clearly not
+        * really a replay of the old one:
+        */
+       if (slot->sl_opcnt < argp->opcnt)
+               return false;
+       /* This is the only check explicitly called by spec: */
+       if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
+               return false;
+       /*
+        * There may be more comparisons we could actually do, but the
+        * spec doesn't require us to catch every case where the calls
+        * don't match (that would require caching the call as well as
+        * the reply), so we don't bother.
+        */
+       return true;
+}
+
 __be32
 nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                union nfsd4_op_u *u)
@@ -3045,6 +3092,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfserr_seq_misordered;
                if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
                        goto out_put_session;
+               status = nfserr_seq_false_retry;
+               if (!replay_matches_cache(rqstp, seq, slot))
+                       goto out_put_session;
                cstate->slot = slot;
                cstate->session = session;
                cstate->clp = clp;
@@ -3351,7 +3401,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
 {
        lockdep_assert_held(&state_lock);
 
-       atomic_set(&fp->fi_ref, 1);
+       refcount_set(&fp->fi_ref, 1);
        spin_lock_init(&fp->fi_lock);
        INIT_LIST_HEAD(&fp->fi_stateids);
        INIT_LIST_HEAD(&fp->fi_delegations);
@@ -3514,7 +3564,7 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
                        continue;
                if (local->st_stateowner == &oo->oo_owner) {
                        ret = local;
-                       atomic_inc(&ret->st_stid.sc_count);
+                       refcount_inc(&ret->st_stid.sc_count);
                        break;
                }
        }
@@ -3573,7 +3623,7 @@ init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
                goto out_unlock;
 
        open->op_stp = NULL;
-       atomic_inc(&stp->st_stid.sc_count);
+       refcount_inc(&stp->st_stid.sc_count);
        stp->st_stid.sc_type = NFS4_OPEN_STID;
        INIT_LIST_HEAD(&stp->st_locks);
        stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
@@ -3621,7 +3671,7 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
         * there should be no danger of the refcount going back up again at
         * this point.
         */
-       wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2);
+       wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2);
 
        release_all_access(s);
        if (s->st_stid.sc_file) {
@@ -3647,7 +3697,7 @@ find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
 
        hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
                if (fh_match(&fp->fi_fhandle, fh)) {
-                       if (atomic_inc_not_zero(&fp->fi_ref))
+                       if (refcount_inc_not_zero(&fp->fi_ref))
                                return fp;
                }
        }
@@ -3783,7 +3833,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
         * lock) we know the server hasn't removed the lease yet, we know
         * it's safe to take a reference.
         */
-       atomic_inc(&dp->dl_stid.sc_count);
+       refcount_inc(&dp->dl_stid.sc_count);
        nfsd4_run_cb(&dp->dl_recall);
 }
 
@@ -3966,7 +4016,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei
 {
        struct nfs4_stid *ret;
 
-       ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
+       ret = find_stateid_by_type(cl, s,
+                               NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
        if (!ret)
                return NULL;
        return delegstateid(ret);
@@ -3989,6 +4040,12 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
        deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
        if (deleg == NULL)
                goto out;
+       if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
+               nfs4_put_stid(&deleg->dl_stid);
+               if (cl->cl_minorversion)
+                       status = nfserr_deleg_revoked;
+               goto out;
+       }
        flags = share_access_to_flags(open->op_share_access);
        status = nfs4_check_delegmode(deleg, flags);
        if (status) {
@@ -4858,6 +4915,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
                     struct nfs4_stid **s, struct nfsd_net *nn)
 {
        __be32 status;
+       bool return_revoked = false;
+
+       /*
+        *  only return revoked delegations if explicitly asked.
+        *  otherwise we report revoked or bad_stateid status.
+        */
+       if (typemask & NFS4_REVOKED_DELEG_STID)
+               return_revoked = true;
+       else if (typemask & NFS4_DELEG_STID)
+               typemask |= NFS4_REVOKED_DELEG_STID;
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
                return nfserr_bad_stateid;
@@ -4872,6 +4939,12 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
        *s = find_stateid_by_type(cstate->clp, stateid, typemask);
        if (!*s)
                return nfserr_bad_stateid;
+       if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
+               nfs4_put_stid(*s);
+               if (cstate->minorversion)
+                       return nfserr_deleg_revoked;
+               return nfserr_bad_stateid;
+       }
        return nfs_ok;
 }
 
@@ -5071,7 +5144,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                ret = nfserr_locks_held;
                break;
        case NFS4_LOCK_STID:
-               atomic_inc(&s->sc_count);
+               refcount_inc(&s->sc_count);
                spin_unlock(&cl->cl_lock);
                ret = nfsd4_free_lock_stateid(stateid, s);
                goto out;
@@ -5578,7 +5651,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
 
        lockdep_assert_held(&clp->cl_lock);
 
-       atomic_inc(&stp->st_stid.sc_count);
+       refcount_inc(&stp->st_stid.sc_count);
        stp->st_stid.sc_type = NFS4_LOCK_STID;
        stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
        get_nfs4_file(fp);
@@ -5604,7 +5677,7 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
 
        list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
                if (lst->st_stid.sc_file == fp) {
-                       atomic_inc(&lst->st_stid.sc_count);
+                       refcount_inc(&lst->st_stid.sc_count);
                        return lst;
                }
        }
@@ -7006,8 +7079,8 @@ nfs4_state_start_net(struct net *net)
        nn->nfsd4_manager.block_opens = true;
        locks_start_grace(net, &nn->nfsd4_manager);
        nfsd4_client_tracking_init(net);
-       printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
-              nn->nfsd4_grace, net);
+       printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n",
+              nn->nfsd4_grace, net->ns.inum);
        queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
        return 0;
 }
index e02bd278312463af174de08b017c445eb4e86b5b..33117d4ffce0753e987ff8fc67b03c719b180676 100644 (file)
@@ -447,7 +447,7 @@ void nfsd_reset_versions(void)
  */
 static void set_max_drc(void)
 {
-       #define NFSD_DRC_SIZE_SHIFT     10
+       #define NFSD_DRC_SIZE_SHIFT     7
        nfsd_drc_max_mem = (nr_free_buffer_pages()
                                        >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
        nfsd_drc_mem_used = 0;
@@ -517,7 +517,7 @@ int nfsd_create_serv(struct net *net)
                register_inet6addr_notifier(&nfsd_inet6addr_notifier);
 #endif
        }
-       do_gettimeofday(&nn->nfssvc_boot);              /* record boot time */
+       ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */
        return 0;
 }
 
index 005c911b34ac4553a2c02da05b4e5d975b660710..f3772ea8ba0d394f95c302584093d57fc19e37d7 100644 (file)
@@ -36,6 +36,7 @@
 #define _NFSD4_STATE_H
 
 #include <linux/idr.h>
+#include <linux/refcount.h>
 #include <linux/sunrpc/svc_xprt.h>
 #include "nfsfh.h"
 
@@ -83,7 +84,7 @@ struct nfsd4_callback_ops {
  * fields that are of general use to any stateid.
  */
 struct nfs4_stid {
-       atomic_t                sc_count;
+       refcount_t              sc_count;
 #define NFS4_OPEN_STID 1
 #define NFS4_LOCK_STID 2
 #define NFS4_DELEG_STID 4
@@ -169,11 +170,13 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
 struct nfsd4_slot {
        u32     sl_seqid;
        __be32  sl_status;
+       struct svc_cred sl_cred;
        u32     sl_datalen;
        u16     sl_opcnt;
 #define NFSD4_SLOT_INUSE       (1 << 0)
 #define NFSD4_SLOT_CACHETHIS   (1 << 1)
 #define NFSD4_SLOT_INITIALIZED (1 << 2)
+#define NFSD4_SLOT_CACHED      (1 << 3)
        u8      sl_flags;
        char    sl_data[];
 };
@@ -465,7 +468,7 @@ struct nfs4_clnt_odstate {
        struct nfs4_client      *co_client;
        struct nfs4_file        *co_file;
        struct list_head        co_perfile;
-       atomic_t                co_odcount;
+       refcount_t              co_odcount;
 };
 
 /*
@@ -481,7 +484,7 @@ struct nfs4_clnt_odstate {
  * the global state_lock spinlock.
  */
 struct nfs4_file {
-       atomic_t                fi_ref;
+       refcount_t              fi_ref;
        spinlock_t              fi_lock;
        struct hlist_node       fi_hash;        /* hash on fi_fhandle */
        struct list_head        fi_stateids;
@@ -634,7 +637,7 @@ struct nfs4_file *find_file(struct knfsd_fh *fh);
 void put_nfs4_file(struct nfs4_file *fi);
 static inline void get_nfs4_file(struct nfs4_file *fi)
 {
-       atomic_inc(&fi->fi_ref);
+       refcount_inc(&fi->fi_ref);
 }
 struct file *find_any_file(struct nfs4_file *f);
 
index 1e4edbf70052bf5f6c8c0af06e0d7bf1812e80a5..bc29511b6405275522a09db2c596991cdd99e710 100644 (file)
@@ -649,9 +649,18 @@ static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
        return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
 }
 
-static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
+/*
+ * The session reply cache only needs to cache replies that the client
+ * actually asked us to.  But it's almost free for us to cache compounds
+ * consisting of only a SEQUENCE op, so we may as well cache those too.
+ * Also, the protocol doesn't give us a convenient response in the case
+ * of a replay of a solo SEQUENCE op that wasn't cached
+ * (RETRY_UNCACHED_REP can only be returned in the second op of a
+ * compound).
+ */
+static inline bool nfsd4_cache_this(struct nfsd4_compoundres *resp)
 {
-       return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+       return (resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
                || nfsd4_is_solo_sequence(resp);
 }
 
index c2d8233b1e826cc99abb615d55c1b590bc89d0b8..480ea059a6802785c78a291c14e7ca01abdcf548 100644 (file)
@@ -155,13 +155,11 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 
 int orangefs_init_acl(struct inode *inode, struct inode *dir)
 {
-       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
        struct posix_acl *default_acl, *acl;
        umode_t mode = inode->i_mode;
+       struct iattr iattr;
        int error = 0;
 
-       ClearModeFlag(orangefs_inode);
-
        error = posix_acl_create(dir, &mode, &default_acl, &acl);
        if (error)
                return error;
@@ -180,9 +178,11 @@ int orangefs_init_acl(struct inode *inode, struct inode *dir)
 
        /* If mode of the inode was changed, then do a forcible ->setattr */
        if (mode != inode->i_mode) {
-               SetModeFlag(orangefs_inode);
+               memset(&iattr, 0, sizeof iattr);
                inode->i_mode = mode;
-               orangefs_flush_inode(inode);
+               iattr.ia_mode = mode;
+               iattr.ia_valid |= ATTR_MODE;
+               orangefs_inode_setattr(inode, &iattr);
        }
 
        return error;
index a8cc588d6224f3b48c2e9be7f7881612889ef2bd..e2c2699d8016274dbe2225b14c0ab8828ceae00f 100644 (file)
@@ -386,7 +386,6 @@ static int orangefs_dir_release(struct inode *inode, struct file *file)
 {
        struct orangefs_dir *od = file->private_data;
        struct orangefs_dir_part *part = od->part;
-       orangefs_flush_inode(inode);
        while (part) {
                struct orangefs_dir_part *next = part->next;
                vfree(part);
index e4a8e6a7eb17b6aaa4b0ab5bf34e16b514c0ea82..1668fd645c453609473f9d6ab89b30499300d940 100644 (file)
@@ -383,9 +383,15 @@ out:
                if (type == ORANGEFS_IO_READ) {
                        file_accessed(file);
                } else {
-                       SetMtimeFlag(orangefs_inode);
-                       inode->i_mtime = current_time(inode);
-                       mark_inode_dirty_sync(inode);
+                       file_update_time(file);
+                       /*
+                        * Must invalidate to ensure write loop doesn't
+                        * prevent kernel from reading updated
+                        * attribute.  Size probably changed because of
+                        * the write, and other clients could update
+                        * any other attribute.
+                        */
+                       orangefs_inode->getattr_time = jiffies - 1;
                }
        }
 
@@ -615,8 +621,6 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
                     "orangefs_file_release: called on %pD\n",
                     file);
 
-       orangefs_flush_inode(inode);
-
        /*
         * remove all associated inode pages from the page cache and
         * readahead cache (if any); this forces an expensive refresh of
@@ -666,8 +670,6 @@ static int orangefs_fsync(struct file *file,
                     ret);
 
        op_release(new_op);
-
-       orangefs_flush_inode(file_inode(file));
        return ret;
 }
 
index 28825a5b6d098f5fbfad1741e0476f7601f41a56..fe1d705ad91fac90c8d496a1c78611e42da9d1d1 100644 (file)
@@ -290,6 +290,22 @@ int orangefs_permission(struct inode *inode, int mask)
        return generic_permission(inode, mask);
 }
 
+int orangefs_update_time(struct inode *inode, struct timespec *time, int flags)
+{
+       struct iattr iattr;
+       gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
+           get_khandle_from_ino(inode));
+       generic_update_time(inode, time, flags);
+       memset(&iattr, 0, sizeof iattr);
+        if (flags & S_ATIME)
+               iattr.ia_valid |= ATTR_ATIME;
+       if (flags & S_CTIME)
+               iattr.ia_valid |= ATTR_CTIME;
+       if (flags & S_MTIME)
+               iattr.ia_valid |= ATTR_MTIME;
+       return orangefs_inode_setattr(inode, &iattr);
+}
+
 /* ORANGEDS2 implementation of VFS inode operations for files */
 const struct inode_operations orangefs_file_inode_operations = {
        .get_acl = orangefs_get_acl,
@@ -298,6 +314,7 @@ const struct inode_operations orangefs_file_inode_operations = {
        .getattr = orangefs_getattr,
        .listxattr = orangefs_listxattr,
        .permission = orangefs_permission,
+       .update_time = orangefs_update_time,
 };
 
 static int orangefs_init_iops(struct inode *inode)
index 7e9e5d0ea3bc24a9b8f270497c3319a1f5bd0848..c98bba2dbc94c3547782f7f485bbdd4793d354f4 100644 (file)
@@ -22,7 +22,9 @@ static int orangefs_create(struct inode *dir,
 {
        struct orangefs_inode_s *parent = ORANGEFS_I(dir);
        struct orangefs_kernel_op_s *new_op;
+       struct orangefs_object_kref ref;
        struct inode *inode;
+       struct iattr iattr;
        int ret;
 
        gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
@@ -55,8 +57,10 @@ static int orangefs_create(struct inode *dir,
        if (ret < 0)
                goto out;
 
-       inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
-                               &new_op->downcall.resp.create.refn);
+       ref = new_op->downcall.resp.create.refn;
+       op_release(new_op);
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0, &ref);
        if (IS_ERR(inode)) {
                gossip_err("%s: Failed to allocate inode for file :%pd:\n",
                           __func__,
@@ -82,12 +86,13 @@ static int orangefs_create(struct inode *dir,
                     __func__,
                     dentry);
 
-       SetMtimeFlag(parent);
        dir->i_mtime = dir->i_ctime = current_time(dir);
+       memset(&iattr, 0, sizeof iattr);
+       iattr.ia_valid |= ATTR_MTIME;
+       orangefs_inode_setattr(dir, &iattr);
        mark_inode_dirty_sync(dir);
        ret = 0;
 out:
-       op_release(new_op);
        gossip_debug(GOSSIP_NAME_DEBUG,
                     "%s: %pd: returning %d\n",
                     __func__,
@@ -221,6 +226,7 @@ static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
        struct inode *inode = dentry->d_inode;
        struct orangefs_inode_s *parent = ORANGEFS_I(dir);
        struct orangefs_kernel_op_s *new_op;
+       struct iattr iattr;
        int ret;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
@@ -253,8 +259,10 @@ static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
        if (!ret) {
                drop_nlink(inode);
 
-               SetMtimeFlag(parent);
                dir->i_mtime = dir->i_ctime = current_time(dir);
+               memset(&iattr, 0, sizeof iattr);
+               iattr.ia_valid |= ATTR_MTIME;
+               orangefs_inode_setattr(dir, &iattr);
                mark_inode_dirty_sync(dir);
        }
        return ret;
@@ -266,7 +274,9 @@ static int orangefs_symlink(struct inode *dir,
 {
        struct orangefs_inode_s *parent = ORANGEFS_I(dir);
        struct orangefs_kernel_op_s *new_op;
+       struct orangefs_object_kref ref;
        struct inode *inode;
+       struct iattr iattr;
        int mode = 755;
        int ret;
 
@@ -307,8 +317,10 @@ static int orangefs_symlink(struct inode *dir,
                goto out;
        }
 
-       inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
-                               &new_op->downcall.resp.sym.refn);
+       ref = new_op->downcall.resp.sym.refn;
+       op_release(new_op);
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0, &ref);
        if (IS_ERR(inode)) {
                gossip_err
                    ("*** Failed to allocate orangefs symlink inode\n");
@@ -331,12 +343,13 @@ static int orangefs_symlink(struct inode *dir,
                     get_khandle_from_ino(inode),
                     dentry);
 
-       SetMtimeFlag(parent);
        dir->i_mtime = dir->i_ctime = current_time(dir);
+       memset(&iattr, 0, sizeof iattr);
+       iattr.ia_valid |= ATTR_MTIME;
+       orangefs_inode_setattr(dir, &iattr);
        mark_inode_dirty_sync(dir);
        ret = 0;
 out:
-       op_release(new_op);
        return ret;
 }
 
@@ -344,7 +357,9 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
 {
        struct orangefs_inode_s *parent = ORANGEFS_I(dir);
        struct orangefs_kernel_op_s *new_op;
+       struct orangefs_object_kref ref;
        struct inode *inode;
+       struct iattr iattr;
        int ret;
 
        new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
@@ -373,8 +388,10 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
                goto out;
        }
 
-       inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
-                               &new_op->downcall.resp.mkdir.refn);
+       ref = new_op->downcall.resp.mkdir.refn;
+       op_release(new_op);
+
+       inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref);
        if (IS_ERR(inode)) {
                gossip_err("*** Failed to allocate orangefs dir inode\n");
                ret = PTR_ERR(inode);
@@ -400,11 +417,12 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
         * NOTE: we have no good way to keep nlink consistent for directories
         * across clients; keep constant at 1.
         */
-       SetMtimeFlag(parent);
        dir->i_mtime = dir->i_ctime = current_time(dir);
+       memset(&iattr, 0, sizeof iattr);
+       iattr.ia_valid |= ATTR_MTIME;
+       orangefs_inode_setattr(dir, &iattr);
        mark_inode_dirty_sync(dir);
 out:
-       op_release(new_op);
        return ret;
 }
 
@@ -470,4 +488,5 @@ const struct inode_operations orangefs_dir_inode_operations = {
        .getattr = orangefs_getattr,
        .listxattr = orangefs_listxattr,
        .permission = orangefs_permission,
+       .update_time = orangefs_update_time,
 };
index b6001bb28f5a94f6d86a17a76b3245525748be9c..c7db56a31b9209076975f6380aad69761cccfde9 100644 (file)
 
 #ifdef __KERNEL__
 #include <linux/types.h>
+#include <linux/kernel.h>
 #else
 #include <stdint.h>
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 #endif
 
 #define        GOSSIP_NO_DEBUG                 (__u64)0
@@ -88,6 +90,6 @@ static struct __keyword_mask_s s_kmod_keyword_mask_map[] = {
 };
 
 static const int num_kmod_keyword_mask_map = (int)
-       (sizeof(s_kmod_keyword_mask_map) / sizeof(struct __keyword_mask_s));
+       (ARRAY_SIZE(s_kmod_keyword_mask_map));
 
 #endif /* __ORANGEFS_DEBUG_H */
index f44d5eb74fcc84f37fe69606f63b6a50dd171dba..97adf7d100b5fe498f70345d1fcdfc525f1d2309 100644 (file)
@@ -209,37 +209,10 @@ struct orangefs_inode_s {
        struct inode vfs_inode;
        sector_t last_failed_block_index_read;
 
-       /*
-        * State of in-memory attributes not yet flushed to disk associated
-        * with this object
-        */
-       unsigned long pinode_flags;
-
        unsigned long getattr_time;
        u32 getattr_mask;
 };
 
-#define P_ATIME_FLAG 0
-#define P_MTIME_FLAG 1
-#define P_CTIME_FLAG 2
-#define P_MODE_FLAG  3
-
-#define ClearAtimeFlag(pinode) clear_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
-#define SetAtimeFlag(pinode)   set_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
-#define AtimeFlag(pinode)      test_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
-
-#define ClearMtimeFlag(pinode) clear_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
-#define SetMtimeFlag(pinode)   set_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
-#define MtimeFlag(pinode)      test_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
-
-#define ClearCtimeFlag(pinode) clear_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
-#define SetCtimeFlag(pinode)   set_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
-#define CtimeFlag(pinode)      test_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
-
-#define ClearModeFlag(pinode) clear_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
-#define SetModeFlag(pinode)   set_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
-#define ModeFlag(pinode)      test_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
-
 /* per superblock private orangefs info */
 struct orangefs_sb_info_s {
        struct orangefs_khandle root_khandle;
@@ -436,6 +409,8 @@ int orangefs_getattr(const struct path *path, struct kstat *stat,
 
 int orangefs_permission(struct inode *inode, int mask);
 
+int orangefs_update_time(struct inode *, struct timespec *, int);
+
 /*
  * defined in xattr.c
  */
@@ -478,8 +453,6 @@ bool __is_daemon_in_service(void);
  */
 __s32 fsid_of_op(struct orangefs_kernel_op_s *op);
 
-int orangefs_flush_inode(struct inode *inode);
-
 ssize_t orangefs_inode_getxattr(struct inode *inode,
                             const char *name,
                             void *buffer,
index f82336496311c532c3150f1e85b1caf59de03abb..97fe93129f38872eb40e7828bf6824d3b348dfae 100644 (file)
@@ -4,6 +4,7 @@
  *
  * See COPYING in top-level directory.
  */
+#include <linux/kernel.h>
 #include "protocol.h"
 #include "orangefs-kernel.h"
 #include "orangefs-dev-proto.h"
@@ -437,89 +438,8 @@ int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
 
        op_release(new_op);
 
-       /*
-        * successful setattr should clear the atime, mtime and
-        * ctime flags.
-        */
-       if (ret == 0) {
-               ClearAtimeFlag(orangefs_inode);
-               ClearMtimeFlag(orangefs_inode);
-               ClearCtimeFlag(orangefs_inode);
-               ClearModeFlag(orangefs_inode);
+       if (ret == 0)
                orangefs_inode->getattr_time = jiffies - 1;
-       }
-
-       return ret;
-}
-
-int orangefs_flush_inode(struct inode *inode)
-{
-       /*
-        * If it is a dirty inode, this function gets called.
-        * Gather all the information that needs to be setattr'ed
-        * Right now, this will only be used for mode, atime, mtime
-        * and/or ctime.
-        */
-       struct iattr wbattr;
-       int ret;
-       int mtime_flag;
-       int ctime_flag;
-       int atime_flag;
-       int mode_flag;
-       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
-
-       memset(&wbattr, 0, sizeof(wbattr));
-
-       /*
-        * check inode flags up front, and clear them if they are set.  This
-        * will prevent multiple processes from all trying to flush the same
-        * inode if they call close() simultaneously
-        */
-       mtime_flag = MtimeFlag(orangefs_inode);
-       ClearMtimeFlag(orangefs_inode);
-       ctime_flag = CtimeFlag(orangefs_inode);
-       ClearCtimeFlag(orangefs_inode);
-       atime_flag = AtimeFlag(orangefs_inode);
-       ClearAtimeFlag(orangefs_inode);
-       mode_flag = ModeFlag(orangefs_inode);
-       ClearModeFlag(orangefs_inode);
-
-       /*  -- Lazy atime,mtime and ctime update --
-        * Note: all times are dictated by server in the new scheme
-        * and not by the clients
-        *
-        * Also mode updates are being handled now..
-        */
-
-       if (mtime_flag)
-               wbattr.ia_valid |= ATTR_MTIME;
-       if (ctime_flag)
-               wbattr.ia_valid |= ATTR_CTIME;
-       if (atime_flag)
-               wbattr.ia_valid |= ATTR_ATIME;
-
-       if (mode_flag) {
-               wbattr.ia_mode = inode->i_mode;
-               wbattr.ia_valid |= ATTR_MODE;
-       }
-
-       gossip_debug(GOSSIP_UTILS_DEBUG,
-                    "*********** orangefs_flush_inode: %pU "
-                    "(ia_valid %d)\n",
-                    get_khandle_from_ino(inode),
-                    wbattr.ia_valid);
-       if (wbattr.ia_valid == 0) {
-               gossip_debug(GOSSIP_UTILS_DEBUG,
-                            "orangefs_flush_inode skipping setattr()\n");
-               return 0;
-       }
-
-       gossip_debug(GOSSIP_UTILS_DEBUG,
-                    "orangefs_flush_inode (%pU) writing mode %o\n",
-                    get_khandle_from_ino(inode),
-                    inode->i_mode);
-
-       ret = orangefs_inode_setattr(inode, &wbattr);
 
        return ret;
 }
@@ -606,7 +526,7 @@ int orangefs_normalize_to_errno(__s32 error_code)
        /* Convert ORANGEFS encoded errno values into regular errno values. */
        } else if ((-error_code) & ORANGEFS_ERROR_BIT) {
                i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS);
-               if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping))
+               if (i < ARRAY_SIZE(PINT_errno_mapping))
                        error_code = -PINT_errno_mapping[i];
                else
                        error_code = -EINVAL;
index 47ebd9bfd1a1be6c638261c4167d530cd5cb3b2a..366750eef2019201146b5fe3a21f2f3a2bfa4da4 100644 (file)
@@ -99,8 +99,6 @@ static void orangefs_inode_cache_ctor(void *req)
 
        inode_init_once(&orangefs_inode->vfs_inode);
        init_rwsem(&orangefs_inode->xattr_sem);
-
-       orangefs_inode->vfs_inode.i_version = 1;
 }
 
 static struct inode *orangefs_alloc_inode(struct super_block *sb)
@@ -119,7 +117,6 @@ static struct inode *orangefs_alloc_inode(struct super_block *sb)
        orangefs_inode->refn.fs_id = ORANGEFS_FS_ID_NULL;
        orangefs_inode->last_failed_block_index_read = 0;
        memset(orangefs_inode->link_target, 0, sizeof(orangefs_inode->link_target));
-       orangefs_inode->pinode_flags = 0;
 
        gossip_debug(GOSSIP_SUPER_DEBUG,
                     "orangefs_alloc_inode: allocated %p\n",
@@ -299,21 +296,9 @@ void fsid_key_table_finalize(void)
 {
 }
 
-/* Called whenever the VFS dirties the inode in response to atime updates */
-static void orangefs_dirty_inode(struct inode *inode, int flags)
-{
-       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
-
-       gossip_debug(GOSSIP_SUPER_DEBUG,
-                    "orangefs_dirty_inode: %pU\n",
-                    get_khandle_from_ino(inode));
-       SetAtimeFlag(orangefs_inode);
-}
-
 static const struct super_operations orangefs_s_ops = {
        .alloc_inode = orangefs_alloc_inode,
        .destroy_inode = orangefs_destroy_inode,
-       .dirty_inode = orangefs_dirty_inode,
        .drop_inode = generic_delete_inode,
        .statfs = orangefs_statfs,
        .remount_fs = orangefs_remount_fs,
index d856cdf917634cd97abdec56bd5daab45a6f7d9a..db107fe91ab398462f23622ea5bcf6ddd3151458 100644 (file)
@@ -15,4 +15,5 @@ const struct inode_operations orangefs_symlink_inode_operations = {
        .getattr = orangefs_getattr,
        .listxattr = orangefs_listxattr,
        .permission = orangefs_permission,
+       .update_time = orangefs_update_time,
 };
index c397934f91dd78acb9b051d13f4ee4e5cbe76569..e55e4255a21082325f0888ffcd464615add708b8 100644 (file)
@@ -78,6 +78,7 @@ enum bpf_arg_type {
         * functions that access data on eBPF program stack
         */
        ARG_PTR_TO_MEM,         /* pointer to valid memory (stack, packet, map value) */
+       ARG_PTR_TO_MEM_OR_NULL, /* pointer to valid memory or NULL */
        ARG_PTR_TO_UNINIT_MEM,  /* pointer to memory does not need to be initialized,
                                 * helper function must fill all bytes or clear
                                 * them in error case.
@@ -334,9 +335,8 @@ extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops;
 extern const struct bpf_verifier_ops xdp_analyzer_ops;
 
 struct bpf_prog *bpf_prog_get(u32 ufd);
-struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
 struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
-                                      struct net_device *netdev);
+                                      bool attach_drv);
 struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i);
 void bpf_prog_sub(struct bpf_prog *prog, int i);
 struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog);
@@ -425,15 +425,9 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd)
        return ERR_PTR(-EOPNOTSUPP);
 }
 
-static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
-                                                enum bpf_prog_type type)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
 static inline struct bpf_prog *bpf_prog_get_type_dev(u32 ufd,
                                                     enum bpf_prog_type type,
-                                                    struct net_device *netdev)
+                                                    bool attach_drv)
 {
        return ERR_PTR(-EOPNOTSUPP);
 }
@@ -514,9 +508,14 @@ static inline int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu,
 }
 #endif /* CONFIG_BPF_SYSCALL */
 
+static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
+                                                enum bpf_prog_type type)
+{
+       return bpf_prog_get_type_dev(ufd, type, false);
+}
+
 int bpf_prog_offload_compile(struct bpf_prog *prog);
 void bpf_prog_offload_destroy(struct bpf_prog *prog);
-u32 bpf_prog_offload_ifindex(struct bpf_prog *prog);
 
 #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
 int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
index 07b96aaca2567df8dd3cd6064b861cbd8a961f0e..c561b986bab0ebf886000ea34e377ea789138a3b 100644 (file)
@@ -115,7 +115,7 @@ struct bpf_insn_aux_data {
                struct bpf_map *map_ptr;        /* pointer for call insn into lookup_elem */
        };
        int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
-       int converted_op_size; /* the valid value width after perceived conversion */
+       bool seen; /* this insn was processed by the verifier */
 };
 
 #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
@@ -171,7 +171,7 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env)
 #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
 int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env);
 #else
-int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
+static inline int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
 {
        return -EOPNOTSUPP;
 }
index e9379e258d6464587bd25b31edaf62856c44b96d..2995a271ec466c54117025cf819ce65931d5166c 100644 (file)
@@ -971,8 +971,8 @@ struct lock_manager {
 struct net;
 void locks_start_grace(struct net *, struct lock_manager *);
 void locks_end_grace(struct lock_manager *);
-int locks_in_grace(struct net *);
-int opens_in_grace(struct net *);
+bool locks_in_grace(struct net *);
+bool opens_in_grace(struct net *);
 
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
index dc8b4896b77b090e8329bdee9766033a6a3b95fb..b1b0ca7ccb2bacac5d997f97f86848e928bc9da7 100644 (file)
@@ -54,8 +54,9 @@ enum {
        NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */
        NETIF_F_GSO_SCTP_BIT,           /* ... SCTP fragmentation */
        NETIF_F_GSO_ESP_BIT,            /* ... ESP with TSO */
+       NETIF_F_GSO_UDP_BIT,            /* ... UFO, deprecated except tuntap */
        /**/NETIF_F_GSO_LAST =          /* last bit, see GSO_MASK */
-               NETIF_F_GSO_ESP_BIT,
+               NETIF_F_GSO_UDP_BIT,
 
        NETIF_F_FCOE_CRC_BIT,           /* FCoE CRC32 */
        NETIF_F_SCTP_CRC_BIT,           /* SCTP checksum offload */
@@ -132,6 +133,7 @@ enum {
 #define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
 #define NETIF_F_GSO_SCTP       __NETIF_F(GSO_SCTP)
 #define NETIF_F_GSO_ESP                __NETIF_F(GSO_ESP)
+#define NETIF_F_GSO_UDP                __NETIF_F(GSO_UDP)
 #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
 #define NETIF_F_HW_VLAN_STAG_RX        __NETIF_F(HW_VLAN_STAG_RX)
 #define NETIF_F_HW_VLAN_STAG_TX        __NETIF_F(HW_VLAN_STAG_TX)
index 6b274bfe489f61332ebd503fcd28dedf0f79b42e..ef789e1d679efd349ed0b20c315defac1f1fb27c 100644 (file)
@@ -4140,6 +4140,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
        BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_SCTP    != (NETIF_F_GSO_SCTP >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_ESP != (NETIF_F_GSO_ESP >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_GSO_UDP >> NETIF_F_GSO_SHIFT));
 
        return (features & feature) == feature;
 }
index 609e232c00da824739f461dceb1abc4481404f7c..c308964777eb98cd2edc6c36e1a75d9e3d3861f1 100644 (file)
@@ -70,6 +70,7 @@ struct pci_dev;
  * @NTB_TOPO_SEC:      On secondary side of remote ntb.
  * @NTB_TOPO_B2B_USD:  On primary side of local ntb upstream of remote ntb.
  * @NTB_TOPO_B2B_DSD:  On primary side of local ntb downstream of remote ntb.
+ * @NTB_TOPO_SWITCH:   Connected via a switch which supports ntb.
  */
 enum ntb_topo {
        NTB_TOPO_NONE = -1,
@@ -77,6 +78,7 @@ enum ntb_topo {
        NTB_TOPO_SEC,
        NTB_TOPO_B2B_USD,
        NTB_TOPO_B2B_DSD,
+       NTB_TOPO_SWITCH,
 };
 
 static inline int ntb_topo_is_b2b(enum ntb_topo topo)
@@ -97,6 +99,7 @@ static inline char *ntb_topo_string(enum ntb_topo topo)
        case NTB_TOPO_SEC:      return "NTB_TOPO_SEC";
        case NTB_TOPO_B2B_USD:  return "NTB_TOPO_B2B_USD";
        case NTB_TOPO_B2B_DSD:  return "NTB_TOPO_B2B_DSD";
+       case NTB_TOPO_SWITCH:   return "NTB_TOPO_SWITCH";
        }
        return "NTB_TOPO_INVALID";
 }
@@ -730,7 +733,8 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
  * Hardware and topology may support a different number of memory windows.
  * Moreover different peer devices can support different number of memory
  * windows. Simply speaking this method returns the number of possible inbound
- * memory windows to share with specified peer device.
+ * memory windows to share with specified peer device. Note: this may return
+ * zero if the link is not up yet.
  *
  * Return: the number of memory windows.
  */
@@ -751,7 +755,7 @@ static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
  * Get the alignments of an inbound memory window with specified index.
  * NULL may be given for any output parameter if the value is not needed.
  * The alignment and size parameters may be used for allocation of proper
- * shared memory.
+ * shared memory. Note: this must only be called when the link is up.
  *
  * Return: Zero on success, otherwise a negative error number.
  */
@@ -760,6 +764,9 @@ static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
                                   resource_size_t *size_align,
                                   resource_size_t *size_max)
 {
+       if (!(ntb_link_is_up(ntb, NULL, NULL) & (1 << pidx)))
+               return -ENOTCONN;
+
        return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
                                      size_max);
 }
index 905bba92f01598ae535b2d2cd737d1a78e739476..e9b603ee99532266a735555ffb784a939f18f5cf 100644 (file)
@@ -132,10 +132,8 @@ struct va_format {
  */
 #define no_printk(fmt, ...)                            \
 ({                                                     \
-       do {                                            \
-               if (0)                                  \
-                       printk(fmt, ##__VA_ARGS__);     \
-       } while (0);                                    \
+       if (0)                                          \
+               printk(fmt, ##__VA_ARGS__);             \
        0;                                              \
 })
 
index ed06e1c28fc72739774ee0dc83ec001825da0138..bc486ef23f20f91ce3ed183e935399d1e4c55e18 100644 (file)
@@ -568,6 +568,8 @@ enum {
        SKB_GSO_SCTP = 1 << 14,
 
        SKB_GSO_ESP = 1 << 15,
+
+       SKB_GSO_UDP = 1 << 16,
 };
 
 #if BITS_PER_LONG > 32
index 3b9f0d1dbb808587b608c0941edc43e55d002bae..786ae2255f0566bc50b44368303a9daba049678c 100644 (file)
@@ -47,6 +47,7 @@ struct svc_pool {
        struct svc_pool_stats   sp_stats;       /* statistics on pool operation */
 #define        SP_TASK_PENDING         (0)             /* still work to do even if no
                                                 * xprt is queued. */
+#define SP_CONGESTED           (1)
        unsigned long           sp_flags;
 } ____cacheline_aligned_in_smp;
 
diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h
new file mode 100644 (file)
index 0000000..09d73d0
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Microsemi Switchtec PCIe Driver
+ * Copyright (c) 2017, Microsemi Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+
+#ifndef _SWITCHTEC_H
+#define _SWITCHTEC_H
+
+#include <linux/pci.h>
+#include <linux/cdev.h>
+
+#define MICROSEMI_VENDOR_ID         0x11f8
+#define MICROSEMI_NTB_CLASSCODE     0x068000
+#define MICROSEMI_MGMT_CLASSCODE    0x058000
+
+#define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024
+#define SWITCHTEC_MAX_PFF_CSR 48
+
+#define SWITCHTEC_EVENT_OCCURRED BIT(0)
+#define SWITCHTEC_EVENT_CLEAR    BIT(0)
+#define SWITCHTEC_EVENT_EN_LOG   BIT(1)
+#define SWITCHTEC_EVENT_EN_CLI   BIT(2)
+#define SWITCHTEC_EVENT_EN_IRQ   BIT(3)
+#define SWITCHTEC_EVENT_FATAL    BIT(4)
+
+enum {
+       SWITCHTEC_GAS_MRPC_OFFSET       = 0x0000,
+       SWITCHTEC_GAS_TOP_CFG_OFFSET    = 0x1000,
+       SWITCHTEC_GAS_SW_EVENT_OFFSET   = 0x1800,
+       SWITCHTEC_GAS_SYS_INFO_OFFSET   = 0x2000,
+       SWITCHTEC_GAS_FLASH_INFO_OFFSET = 0x2200,
+       SWITCHTEC_GAS_PART_CFG_OFFSET   = 0x4000,
+       SWITCHTEC_GAS_NTB_OFFSET        = 0x10000,
+       SWITCHTEC_GAS_PFF_CSR_OFFSET    = 0x134000,
+};
+
+struct mrpc_regs {
+       u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
+       u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
+       u32 cmd;
+       u32 status;
+       u32 ret_value;
+} __packed;
+
+enum mrpc_status {
+       SWITCHTEC_MRPC_STATUS_INPROGRESS = 1,
+       SWITCHTEC_MRPC_STATUS_DONE = 2,
+       SWITCHTEC_MRPC_STATUS_ERROR = 0xFF,
+       SWITCHTEC_MRPC_STATUS_INTERRUPTED = 0x100,
+};
+
+struct sw_event_regs {
+       u64 event_report_ctrl;
+       u64 reserved1;
+       u64 part_event_bitmap;
+       u64 reserved2;
+       u32 global_summary;
+       u32 reserved3[3];
+       u32 stack_error_event_hdr;
+       u32 stack_error_event_data;
+       u32 reserved4[4];
+       u32 ppu_error_event_hdr;
+       u32 ppu_error_event_data;
+       u32 reserved5[4];
+       u32 isp_error_event_hdr;
+       u32 isp_error_event_data;
+       u32 reserved6[4];
+       u32 sys_reset_event_hdr;
+       u32 reserved7[5];
+       u32 fw_exception_hdr;
+       u32 reserved8[5];
+       u32 fw_nmi_hdr;
+       u32 reserved9[5];
+       u32 fw_non_fatal_hdr;
+       u32 reserved10[5];
+       u32 fw_fatal_hdr;
+       u32 reserved11[5];
+       u32 twi_mrpc_comp_hdr;
+       u32 twi_mrpc_comp_data;
+       u32 reserved12[4];
+       u32 twi_mrpc_comp_async_hdr;
+       u32 twi_mrpc_comp_async_data;
+       u32 reserved13[4];
+       u32 cli_mrpc_comp_hdr;
+       u32 cli_mrpc_comp_data;
+       u32 reserved14[4];
+       u32 cli_mrpc_comp_async_hdr;
+       u32 cli_mrpc_comp_async_data;
+       u32 reserved15[4];
+       u32 gpio_interrupt_hdr;
+       u32 gpio_interrupt_data;
+       u32 reserved16[4];
+} __packed;
+
+enum {
+       SWITCHTEC_CFG0_RUNNING = 0x04,
+       SWITCHTEC_CFG1_RUNNING = 0x05,
+       SWITCHTEC_IMG0_RUNNING = 0x03,
+       SWITCHTEC_IMG1_RUNNING = 0x07,
+};
+
+struct sys_info_regs {
+       u32 device_id;
+       u32 device_version;
+       u32 firmware_version;
+       u32 reserved1;
+       u32 vendor_table_revision;
+       u32 table_format_version;
+       u32 partition_id;
+       u32 cfg_file_fmt_version;
+       u16 cfg_running;
+       u16 img_running;
+       u32 reserved2[57];
+       char vendor_id[8];
+       char product_id[16];
+       char product_revision[4];
+       char component_vendor[8];
+       u16 component_id;
+       u8 component_revision;
+} __packed;
+
+struct flash_info_regs {
+       u32 flash_part_map_upd_idx;
+
+       struct active_partition_info {
+               u32 address;
+               u32 build_version;
+               u32 build_string;
+       } active_img;
+
+       struct active_partition_info active_cfg;
+       struct active_partition_info inactive_img;
+       struct active_partition_info inactive_cfg;
+
+       u32 flash_length;
+
+       struct partition_info {
+               u32 address;
+               u32 length;
+       } cfg0;
+
+       struct partition_info cfg1;
+       struct partition_info img0;
+       struct partition_info img1;
+       struct partition_info nvlog;
+       struct partition_info vendor[8];
+};
+
+enum {
+       SWITCHTEC_NTB_REG_INFO_OFFSET   = 0x0000,
+       SWITCHTEC_NTB_REG_CTRL_OFFSET   = 0x4000,
+       SWITCHTEC_NTB_REG_DBMSG_OFFSET  = 0x64000,
+};
+
+struct ntb_info_regs {
+       u8  partition_count;
+       u8  partition_id;
+       u16 reserved1;
+       u64 ep_map;
+       u16 requester_id;
+} __packed;
+
+struct part_cfg_regs {
+       u32 status;
+       u32 state;
+       u32 port_cnt;
+       u32 usp_port_mode;
+       u32 usp_pff_inst_id;
+       u32 vep_pff_inst_id;
+       u32 dsp_pff_inst_id[47];
+       u32 reserved1[11];
+       u16 vep_vector_number;
+       u16 usp_vector_number;
+       u32 port_event_bitmap;
+       u32 reserved2[3];
+       u32 part_event_summary;
+       u32 reserved3[3];
+       u32 part_reset_hdr;
+       u32 part_reset_data[5];
+       u32 mrpc_comp_hdr;
+       u32 mrpc_comp_data[5];
+       u32 mrpc_comp_async_hdr;
+       u32 mrpc_comp_async_data[5];
+       u32 dyn_binding_hdr;
+       u32 dyn_binding_data[5];
+       u32 reserved4[159];
+} __packed;
+
+enum {
+       NTB_CTRL_PART_OP_LOCK = 0x1,
+       NTB_CTRL_PART_OP_CFG = 0x2,
+       NTB_CTRL_PART_OP_RESET = 0x3,
+
+       NTB_CTRL_PART_STATUS_NORMAL = 0x1,
+       NTB_CTRL_PART_STATUS_LOCKED = 0x2,
+       NTB_CTRL_PART_STATUS_LOCKING = 0x3,
+       NTB_CTRL_PART_STATUS_CONFIGURING = 0x4,
+       NTB_CTRL_PART_STATUS_RESETTING = 0x5,
+
+       NTB_CTRL_BAR_VALID = 1 << 0,
+       NTB_CTRL_BAR_DIR_WIN_EN = 1 << 4,
+       NTB_CTRL_BAR_LUT_WIN_EN = 1 << 5,
+
+       NTB_CTRL_REQ_ID_EN = 1 << 0,
+
+       NTB_CTRL_LUT_EN = 1 << 0,
+
+       NTB_PART_CTRL_ID_PROT_DIS = 1 << 0,
+};
+
+struct ntb_ctrl_regs {
+       u32 partition_status;
+       u32 partition_op;
+       u32 partition_ctrl;
+       u32 bar_setup;
+       u32 bar_error;
+       u16 lut_table_entries;
+       u16 lut_table_offset;
+       u32 lut_error;
+       u16 req_id_table_size;
+       u16 req_id_table_offset;
+       u32 req_id_error;
+       u32 reserved1[7];
+       struct {
+               u32 ctl;
+               u32 win_size;
+               u64 xlate_addr;
+       } bar_entry[6];
+       u32 reserved2[216];
+       u32 req_id_table[256];
+       u32 reserved3[512];
+       u64 lut_entry[512];
+} __packed;
+
+#define NTB_DBMSG_IMSG_STATUS BIT_ULL(32)
+#define NTB_DBMSG_IMSG_MASK   BIT_ULL(40)
+
+struct ntb_dbmsg_regs {
+       u32 reserved1[1024];
+       u64 odb;
+       u64 odb_mask;
+       u64 idb;
+       u64 idb_mask;
+       u8  idb_vec_map[64];
+       u32 msg_map;
+       u32 reserved2;
+       struct {
+               u32 msg;
+               u32 status;
+       } omsg[4];
+
+       struct {
+               u32 msg;
+               u8  status;
+               u8  mask;
+               u8  src;
+               u8  reserved;
+       } imsg[4];
+
+       u8 reserved3[3928];
+       u8 msix_table[1024];
+       u8 reserved4[3072];
+       u8 pba[24];
+       u8 reserved5[4072];
+} __packed;
+
+enum {
+       SWITCHTEC_PART_CFG_EVENT_RESET = 1 << 0,
+       SWITCHTEC_PART_CFG_EVENT_MRPC_CMP = 1 << 1,
+       SWITCHTEC_PART_CFG_EVENT_MRPC_ASYNC_CMP = 1 << 2,
+       SWITCHTEC_PART_CFG_EVENT_DYN_PART_CMP = 1 << 3,
+};
+
+struct pff_csr_regs {
+       u16 vendor_id;
+       u16 device_id;
+       u32 pci_cfg_header[15];
+       u32 pci_cap_region[48];
+       u32 pcie_cap_region[448];
+       u32 indirect_gas_window[128];
+       u32 indirect_gas_window_off;
+       u32 reserved[127];
+       u32 pff_event_summary;
+       u32 reserved2[3];
+       u32 aer_in_p2p_hdr;
+       u32 aer_in_p2p_data[5];
+       u32 aer_in_vep_hdr;
+       u32 aer_in_vep_data[5];
+       u32 dpc_hdr;
+       u32 dpc_data[5];
+       u32 cts_hdr;
+       u32 cts_data[5];
+       u32 reserved3[6];
+       u32 hotplug_hdr;
+       u32 hotplug_data[5];
+       u32 ier_hdr;
+       u32 ier_data[5];
+       u32 threshold_hdr;
+       u32 threshold_data[5];
+       u32 power_mgmt_hdr;
+       u32 power_mgmt_data[5];
+       u32 tlp_throttling_hdr;
+       u32 tlp_throttling_data[5];
+       u32 force_speed_hdr;
+       u32 force_speed_data[5];
+       u32 credit_timeout_hdr;
+       u32 credit_timeout_data[5];
+       u32 link_state_hdr;
+       u32 link_state_data[5];
+       u32 reserved4[174];
+} __packed;
+
+struct switchtec_ntb;
+
+struct switchtec_dev {
+       struct pci_dev *pdev;
+       struct device dev;
+       struct cdev cdev;
+
+       int partition;
+       int partition_count;
+       int pff_csr_count;
+       char pff_local[SWITCHTEC_MAX_PFF_CSR];
+
+       void __iomem *mmio;
+       struct mrpc_regs __iomem *mmio_mrpc;
+       struct sw_event_regs __iomem *mmio_sw_event;
+       struct sys_info_regs __iomem *mmio_sys_info;
+       struct flash_info_regs __iomem *mmio_flash_info;
+       struct ntb_info_regs __iomem *mmio_ntb;
+       struct part_cfg_regs __iomem *mmio_part_cfg;
+       struct part_cfg_regs __iomem *mmio_part_cfg_all;
+       struct pff_csr_regs __iomem *mmio_pff_csr;
+
+       /*
+        * The mrpc mutex must be held when accessing the other
+        * mrpc_ fields, alive flag and stuser->state field
+        */
+       struct mutex mrpc_mutex;
+       struct list_head mrpc_queue;
+       int mrpc_busy;
+       struct work_struct mrpc_work;
+       struct delayed_work mrpc_timeout;
+       bool alive;
+
+       wait_queue_head_t event_wq;
+       atomic_t event_cnt;
+
+       struct work_struct link_event_work;
+       void (*link_notifier)(struct switchtec_dev *stdev);
+       u8 link_event_count[SWITCHTEC_MAX_PFF_CSR];
+
+       struct switchtec_ntb *sndev;
+};
+
+static inline struct switchtec_dev *to_stdev(struct device *dev)
+{
+       return container_of(dev, struct switchtec_dev, dev);
+}
+
+extern struct class *switchtec_class;
+
+#endif
index 210034c896e31e725c6de6bfb33b0406c3b1927a..f144216febc642fd70512df9dddefe1a7f119478 100644 (file)
@@ -9,7 +9,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
                                        const struct virtio_net_hdr *hdr,
                                        bool little_endian)
 {
-       unsigned short gso_type = 0;
+       unsigned int gso_type = 0;
 
        if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
@@ -19,6 +19,9 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
                case VIRTIO_NET_HDR_GSO_TCPV6:
                        gso_type = SKB_GSO_TCPV6;
                        break;
+               case VIRTIO_NET_HDR_GSO_UDP:
+                       gso_type = SKB_GSO_UDP;
+                       break;
                default:
                        return -EINVAL;
                }
index cd0d7734dc49838eef044dc1a3ad2c47286a72ac..4757cb5077e538feb793cb06bb3d7fcb335430b9 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/device.h>
 #include <linux/acpi.h>
+#include <uapi/linux/wmi.h>
 
 struct wmi_device {
        struct device dev;
@@ -26,13 +27,17 @@ struct wmi_device {
        bool setable;
 };
 
+/* evaluate the ACPI method associated with this device */
+extern acpi_status wmidev_evaluate_method(struct wmi_device *wdev,
+                                         u8 instance, u32 method_id,
+                                         const struct acpi_buffer *in,
+                                         struct acpi_buffer *out);
+
 /* Caller must kfree the result. */
 extern union acpi_object *wmidev_block_query(struct wmi_device *wdev,
                                             u8 instance);
 
-/* Gets another device on the same bus.  Caller must put_device the result. */
-extern struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
-                                               const char *guid_string);
+extern int set_required_buffer_size(struct wmi_device *wdev, u64 length);
 
 struct wmi_device_id {
        const char *guid_string;
@@ -45,6 +50,8 @@ struct wmi_driver {
        int (*probe)(struct wmi_device *wdev);
        int (*remove)(struct wmi_device *wdev);
        void (*notify)(struct wmi_device *device, union acpi_object *data);
+       long (*filter_callback)(struct wmi_device *wdev, unsigned int cmd,
+                               struct wmi_ioctl_buffer *arg);
 };
 
 extern int __must_check __wmi_driver_register(struct wmi_driver *driver,
index ec14f0d5a3a189f5d461f71e530e425c83d64e0b..f73797e2fa60c51a81c8d7a0e231bd2be0137119 100644 (file)
@@ -767,6 +767,7 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
 __be32 ipv6_select_ident(struct net *net,
                         const struct in6_addr *daddr,
                         const struct in6_addr *saddr);
+__be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb);
 
 int ip6_dst_hoplimit(struct dst_entry *dst);
 
index ecbdbfe86eb6620350fe5eca369906cd3ea60823..8c153f68509e297225db7614f8e706479476bb9c 100644 (file)
@@ -486,20 +486,22 @@ TRACE_EVENT(svc_recv,
        TP_ARGS(rqst, status),
 
        TP_STRUCT__entry(
-               __field(struct sockaddr *, addr)
                __field(u32, xid)
                __field(int, status)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
        ),
 
        TP_fast_assign(
-               __entry->addr = (struct sockaddr *)&rqst->rq_addr;
                __entry->xid = status > 0 ? be32_to_cpu(rqst->rq_xid) : 0;
                __entry->status = status;
                __entry->flags = rqst->rq_flags;
+               memcpy(__get_dynamic_array(addr),
+                       &rqst->rq_addr, rqst->rq_addrlen);
        ),
 
-       TP_printk("addr=%pIScp xid=0x%08x status=%d flags=%s", __entry->addr,
+       TP_printk("addr=%pIScp xid=0x%08x status=%d flags=%s",
+                       (struct sockaddr *)__get_dynamic_array(addr),
                        __entry->xid, __entry->status,
                        show_rqstp_flags(__entry->flags))
 );
@@ -544,22 +546,23 @@ DECLARE_EVENT_CLASS(svc_rqst_status,
        TP_ARGS(rqst, status),
 
        TP_STRUCT__entry(
-               __field(struct sockaddr *, addr)
                __field(u32, xid)
-               __field(int, dropme)
                __field(int, status)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
        ),
 
        TP_fast_assign(
-               __entry->addr = (struct sockaddr *)&rqst->rq_addr;
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->status = status;
                __entry->flags = rqst->rq_flags;
+               memcpy(__get_dynamic_array(addr),
+                       &rqst->rq_addr, rqst->rq_addrlen);
        ),
 
        TP_printk("addr=%pIScp rq_xid=0x%08x status=%d flags=%s",
-               __entry->addr, __entry->xid,
+               (struct sockaddr *)__get_dynamic_array(addr),
+               __entry->xid,
                __entry->status, show_rqstp_flags(__entry->flags))
 );
 
index e880ae6434eed9eb29db99169c716c94c7cf30aa..4c223ab30293cd1e07248b960e213c7f22b778c5 100644 (file)
@@ -262,7 +262,7 @@ union bpf_attr {
                __u32           kern_version;   /* checked when prog_type=kprobe */
                __u32           prog_flags;
                char            prog_name[BPF_OBJ_NAME_LEN];
-               __u32           prog_target_ifindex;    /* ifindex of netdev to prep for */
+               __u32           prog_ifindex;   /* ifindex of netdev to prep for */
        };
 
        struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -897,10 +897,6 @@ enum sk_action {
 
 #define BPF_TAG_SIZE   8
 
-enum bpf_prog_status {
-       BPF_PROG_STATUS_DEV_BOUND       = (1 << 0),
-};
-
 struct bpf_prog_info {
        __u32 type;
        __u32 id;
@@ -914,8 +910,6 @@ struct bpf_prog_info {
        __u32 nr_map_ids;
        __aligned_u64 map_ids;
        char name[BPF_OBJ_NAME_LEN];
-       __u32 ifindex;
-       __u32 status;
 } __attribute__((aligned(8)));
 
 struct bpf_map_info {
diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h
new file mode 100644 (file)
index 0000000..7a92e9e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  User API methods for ACPI-WMI mapping driver
+ *
+ *  Copyright (C) 2017 Dell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _UAPI_LINUX_WMI_H
+#define _UAPI_LINUX_WMI_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* WMI bus will filter all WMI vendor driver requests through this IOC */
+#define WMI_IOC 'W'
+
+/* All ioctl requests through WMI should declare their size followed by
+ * relevant data objects
+ */
+struct wmi_ioctl_buffer {
+       __u64   length;
+       __u8    data[];
+};
+
+/* This structure may be modified by the firmware when we enter
+ * system management mode through SMM, hence the volatiles
+ */
+struct calling_interface_buffer {
+       __u16 cmd_class;
+       __u16 cmd_select;
+       volatile __u32 input[4];
+       volatile __u32 output[4];
+} __packed;
+
+struct dell_wmi_extensions {
+       __u32 argattrib;
+       __u32 blength;
+       __u8 data[];
+} __packed;
+
+struct dell_wmi_smbios_buffer {
+       __u64 length;
+       struct calling_interface_buffer std;
+       struct dell_wmi_extensions      ext;
+} __packed;
+
+/* Whitelisted smbios class/select commands */
+#define CLASS_TOKEN_READ       0
+#define CLASS_TOKEN_WRITE      1
+#define SELECT_TOKEN_STD       0
+#define SELECT_TOKEN_BAT       1
+#define SELECT_TOKEN_AC                2
+#define CLASS_FLASH_INTERFACE  7
+#define SELECT_FLASH_INTERFACE 3
+#define CLASS_ADMIN_PROP       10
+#define SELECT_ADMIN_PROP      3
+#define CLASS_INFO             17
+#define SELECT_RFKILL          11
+#define SELECT_APP_REGISTRATION        3
+#define SELECT_DOCK            22
+
+/* whitelisted tokens */
+#define CAPSULE_EN_TOKEN       0x0461
+#define CAPSULE_DIS_TOKEN      0x0462
+#define WSMT_EN_TOKEN          0x04EC
+#define WSMT_DIS_TOKEN         0x04ED
+
+/* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
+#define DELL_WMI_SMBIOS_CMD    _IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer)
+
+#endif
diff --git a/include/video/iga.h b/include/video/iga.h
deleted file mode 100644 (file)
index 83ca184..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* $Id: iga.h,v 1.2 1999/09/11 22:56:31 zaitcev Exp $
- * iga1682.h: Sparc/PCI iga1682 driver constants etc.
- *
- * Copyleft 1998 V. Roganov and G. Raiko
- */
-
-#ifndef _IGA1682_H
-#define _IGA1682_H 1
-
-#define IGA_ATTR_CTL                   0x3C0
-#define   IGA_IDX_VGA_OVERSCAN         0x11
-#define DAC_W_INDEX                     0x03C8
-#define DAC_DATA                        0x03C9
-#define IGA_EXT_CNTRL                   0x3CE
-#define   IGA_IDX_EXT_BUS_CNTL          0x30
-#define     MEM_SIZE_ALIAS              0x3
-#define     MEM_SIZE_1M                 0x0
-#define     MEM_SIZE_2M                 0x1
-#define     MEM_SIZE_4M                 0x2
-#define     MEM_SIZE_RESERVED           0x3
-#define   IGA_IDX_OVERSCAN_COLOR        0x58
-#define   IGA_IDX_EXT_MEM_2             0x72
-
-#endif /* !(_IGA1682_H) */
index 2816feb38be16a0137bc7aa351606f24466c55e1..68ec884440b75da08824249db74bb992f6d938ce 100644 (file)
@@ -14,8 +14,9 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
        struct net *net = current->nsproxy->net_ns;
        struct bpf_dev_offload *offload;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
+       if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
+           attr->prog_type != BPF_PROG_TYPE_XDP)
+               return -EINVAL;
 
        if (attr->prog_flags)
                return -EINVAL;
@@ -28,7 +29,7 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
        init_waitqueue_head(&offload->verifier_done);
 
        rtnl_lock();
-       offload->netdev = __dev_get_by_index(net, attr->prog_target_ifindex);
+       offload->netdev = __dev_get_by_index(net, attr->prog_ifindex);
        if (!offload->netdev) {
                rtnl_unlock();
                kfree(offload);
@@ -85,6 +86,10 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
        struct bpf_dev_offload *offload = prog->aux->offload;
        struct netdev_bpf data = {};
 
+       /* Caution - if netdev is destroyed before the program, this function
+        * will be called twice.
+        */
+
        data.offload.prog = prog;
 
        if (offload->verifier_running)
@@ -144,18 +149,6 @@ int bpf_prog_offload_compile(struct bpf_prog *prog)
        return bpf_prog_offload_translate(prog);
 }
 
-u32 bpf_prog_offload_ifindex(struct bpf_prog *prog)
-{
-       struct bpf_dev_offload *offload = prog->aux->offload;
-       u32 ifindex;
-
-       rtnl_lock();
-       ifindex = offload->netdev ? offload->netdev->ifindex : 0;
-       rtnl_unlock();
-
-       return ifindex;
-}
-
 const struct bpf_prog_ops bpf_offload_prog_ops = {
 };
 
@@ -169,6 +162,10 @@ static int bpf_offload_notification(struct notifier_block *notifier,
 
        switch (event) {
        case NETDEV_UNREGISTER:
+               /* ignore namespace changes */
+               if (netdev->reg_state != NETREG_UNREGISTERING)
+                       break;
+
                list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
                                         offloads) {
                        if (offload->netdev == netdev)
index 09badc37e86467bdef5923c52b4448b9eccc1d18..2c4cfeaa8d5e785f16758be08cb8a462766363d9 100644 (file)
@@ -1057,22 +1057,23 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
 }
 EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
 
-static bool bpf_prog_can_attach(struct bpf_prog *prog,
-                               enum bpf_prog_type *attach_type,
-                               struct net_device *netdev)
+static bool bpf_prog_get_ok(struct bpf_prog *prog,
+                           enum bpf_prog_type *attach_type, bool attach_drv)
 {
-       struct bpf_dev_offload *offload = prog->aux->offload;
+       /* not an attachment, just a refcount inc, always allow */
+       if (!attach_type)
+               return true;
 
        if (prog->type != *attach_type)
                return false;
-       if (offload && offload->netdev != netdev)
+       if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
                return false;
 
        return true;
 }
 
 static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
-                                      struct net_device *netdev)
+                                      bool attach_drv)
 {
        struct fd f = fdget(ufd);
        struct bpf_prog *prog;
@@ -1080,7 +1081,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
        prog = ____bpf_prog_get(f);
        if (IS_ERR(prog))
                return prog;
-       if (attach_type && !bpf_prog_can_attach(prog, attach_type, netdev)) {
+       if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
                prog = ERR_PTR(-EINVAL);
                goto out;
        }
@@ -1093,23 +1094,13 @@ out:
 
 struct bpf_prog *bpf_prog_get(u32 ufd)
 {
-       return __bpf_prog_get(ufd, NULL, NULL);
+       return __bpf_prog_get(ufd, NULL, false);
 }
 
-struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
-{
-       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, NULL);
-
-       if (!IS_ERR(prog))
-               trace_bpf_prog_get_type(prog);
-       return prog;
-}
-EXPORT_SYMBOL_GPL(bpf_prog_get_type);
-
 struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
-                                      struct net_device *netdev)
+                                      bool attach_drv)
 {
-       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, netdev);
+       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, attach_drv);
 
        if (!IS_ERR(prog))
                trace_bpf_prog_get_type(prog);
@@ -1118,7 +1109,7 @@ struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
 EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
 
 /* last field in 'union bpf_attr' used by this command */
-#define        BPF_PROG_LOAD_LAST_FIELD prog_target_ifindex
+#define        BPF_PROG_LOAD_LAST_FIELD prog_ifindex
 
 static int bpf_prog_load(union bpf_attr *attr)
 {
@@ -1181,7 +1172,7 @@ static int bpf_prog_load(union bpf_attr *attr)
        atomic_set(&prog->aux->refcnt, 1);
        prog->gpl_compatible = is_gpl ? 1 : 0;
 
-       if (attr->prog_target_ifindex) {
+       if (attr->prog_ifindex) {
                err = bpf_prog_offload_init(prog, attr);
                if (err)
                        goto free_prog;
@@ -1625,11 +1616,6 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                        return -EFAULT;
        }
 
-       if (bpf_prog_is_dev_bound(prog->aux)) {
-               info.status |= BPF_PROG_STATUS_DEV_BOUND;
-               info.ifindex = bpf_prog_offload_ifindex(prog);
-       }
-
 done:
        if (copy_to_user(uinfo, &info, info_len) ||
            put_user(info_len, &uattr->info.info_len))
index dd54d20ace2ff7bc3aa942f4a08e08dadfb1a4e6..d4593571c4049b8d046f53f81f8e17911a21e0c9 100644 (file)
@@ -1384,13 +1384,15 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
                if (type != expected_type)
                        goto err_type;
        } else if (arg_type == ARG_PTR_TO_MEM ||
+                  arg_type == ARG_PTR_TO_MEM_OR_NULL ||
                   arg_type == ARG_PTR_TO_UNINIT_MEM) {
                expected_type = PTR_TO_STACK;
                /* One exception here. In case function allows for NULL to be
                 * passed in as argument, it's a SCALAR_VALUE type. Final test
                 * happens during stack boundary checking.
                 */
-               if (register_is_null(*reg))
+               if (register_is_null(*reg) &&
+                   arg_type == ARG_PTR_TO_MEM_OR_NULL)
                        /* final test in check_stack_boundary() */;
                else if (!type_is_pkt_pointer(type) &&
                         type != PTR_TO_MAP_VALUE &&
@@ -3825,6 +3827,7 @@ static int do_check(struct bpf_verifier_env *env)
                        return err;
 
                regs = cur_regs(env);
+               env->insn_aux_data[insn_idx].seen = true;
                if (class == BPF_ALU || class == BPF_ALU64) {
                        err = check_alu_op(env, insn);
                        if (err)
@@ -4020,6 +4023,7 @@ process_bpf_exit:
                                        return err;
 
                                insn_idx++;
+                               env->insn_aux_data[insn_idx].seen = true;
                        } else {
                                verbose(env, "invalid BPF_LD mode\n");
                                return -EINVAL;
@@ -4202,6 +4206,7 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
                                u32 off, u32 cnt)
 {
        struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
+       int i;
 
        if (cnt == 1)
                return 0;
@@ -4211,6 +4216,8 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
        memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
        memcpy(new_data + off + cnt - 1, old_data + off,
               sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
+       for (i = off; i < off + cnt - 1; i++)
+               new_data[i].seen = true;
        env->insn_aux_data = new_data;
        vfree(old_data);
        return 0;
@@ -4229,6 +4236,25 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
        return new_prog;
 }
 
+/* The verifier does more data flow analysis than llvm and will not explore
+ * branches that are dead at run time. Malicious programs can have dead code
+ * too. Therefore replace all dead at-run-time code with nops.
+ */
+static void sanitize_dead_code(struct bpf_verifier_env *env)
+{
+       struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
+       struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0);
+       struct bpf_insn *insn = env->prog->insnsi;
+       const int insn_cnt = env->prog->len;
+       int i;
+
+       for (i = 0; i < insn_cnt; i++) {
+               if (aux_data[i].seen)
+                       continue;
+               memcpy(insn + i, &nop, sizeof(nop));
+       }
+}
+
 /* convert load instructions that access fields of 'struct __sk_buff'
  * into sequence of instructions that access fields of 'struct sk_buff'
  */
@@ -4555,6 +4581,9 @@ skip_full_check:
        while (!pop_stack(env, NULL, NULL));
        free_states(env);
 
+       if (ret == 0)
+               sanitize_dead_code(env);
+
        if (ret == 0)
                /* program is valid, convert *(u32*)(ctx + off) accesses */
                ret = convert_ctx_accesses(env);
index 512f7c2baedd59bef5300e361c22e92b7a4845a0..5d81206a572d721e7d96b129f160a4e16d2e2f2e 100644 (file)
@@ -2190,7 +2190,7 @@ again:
                }
 
                if (console_seq < log_first_seq) {
-                       len = sprintf(text, "** %u printk messages dropped ** ",
+                       len = sprintf(text, "** %u printk messages dropped **\n",
                                      (unsigned)(log_first_seq - console_seq));
 
                        /* messages are gone, move to first one */
index 724d9292d4b9614e62b78e7e0c27e0e8fb0dd49c..3e3c2004bb232661bae666e00e4645fad438aee6 100644 (file)
@@ -72,7 +72,7 @@ static void queue_flush_work(struct printk_safe_seq_buf *s)
  * have dedicated buffers, because otherwise printk-safe preempted by
  * NMI-printk would have overwritten the NMI messages.
  *
- * The messages are fushed from irq work (or from panic()), possibly,
+ * The messages are flushed from irq work (or from panic()), possibly,
  * from other CPU, concurrently with printk_safe_log_store(). Should this
  * happen, printk_safe_log_store() will notice the buffer->len mismatch
  * and repeat the write.
index a5580c6708668033313e9c5185f2122d364ab72f..27d1f4ffa3def946525b2d248757fac3620504e5 100644 (file)
@@ -78,16 +78,12 @@ EXPORT_SYMBOL_GPL(trace_call_bpf);
 
 BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr)
 {
-       int ret = 0;
-
-       if (unlikely(size == 0))
-               goto out;
+       int ret;
 
        ret = probe_kernel_read(dst, unsafe_ptr, size);
        if (unlikely(ret < 0))
                memset(dst, 0, size);
 
- out:
        return ret;
 }
 
@@ -407,7 +403,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
        .arg2_type      = ARG_CONST_MAP_PTR,
        .arg3_type      = ARG_ANYTHING,
        .arg4_type      = ARG_PTR_TO_MEM,
-       .arg5_type      = ARG_CONST_SIZE,
+       .arg5_type      = ARG_CONST_SIZE_OR_ZERO,
 };
 
 static DEFINE_PER_CPU(struct pt_regs, bpf_pt_regs);
@@ -498,7 +494,7 @@ static const struct bpf_func_proto bpf_probe_read_str_proto = {
        .gpl_only       = true,
        .ret_type       = RET_INTEGER,
        .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
-       .arg2_type      = ARG_CONST_SIZE,
+       .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
        .arg3_type      = ARG_ANYTHING,
 };
 
@@ -609,7 +605,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {
        .arg2_type      = ARG_CONST_MAP_PTR,
        .arg3_type      = ARG_ANYTHING,
        .arg4_type      = ARG_PTR_TO_MEM,
-       .arg5_type      = ARG_CONST_SIZE,
+       .arg5_type      = ARG_CONST_SIZE_OR_ZERO,
 };
 
 BPF_CALL_3(bpf_get_stackid_tp, void *, tp_buff, struct bpf_map *, map,
index 67bb1f11e613ca4bcd4f635e096c00c9a61804a5..9a5850f264ed2fa1396fbb35db002e9e50309dbd 100644 (file)
@@ -47,28 +47,38 @@ unsigned int ceph_str_hash_rjenkins(const char *str, unsigned int length)
 
        /* handle the last 11 bytes */
        c = c + length;
-       switch (len) {            /* all the case statements fall through */
+       switch (len) {
        case 11:
                c = c + ((__u32)k[10] << 24);
+               /* fall through */
        case 10:
                c = c + ((__u32)k[9] << 16);
+               /* fall through */
        case 9:
                c = c + ((__u32)k[8] << 8);
                /* the first byte of c is reserved for the length */
+               /* fall through */
        case 8:
                b = b + ((__u32)k[7] << 24);
+               /* fall through */
        case 7:
                b = b + ((__u32)k[6] << 16);
+               /* fall through */
        case 6:
                b = b + ((__u32)k[5] << 8);
+               /* fall through */
        case 5:
                b = b + k[4];
+               /* fall through */
        case 4:
                a = a + ((__u32)k[3] << 24);
+               /* fall through */
        case 3:
                a = a + ((__u32)k[2] << 16);
+               /* fall through */
        case 2:
                a = a + ((__u32)k[1] << 8);
+               /* fall through */
        case 1:
                a = a + k[0];
                /* case 0: nothing left to add */
index 489610ac1cddad2e284515def1bb2185f620d3aa..bf9d079cbafd6e89d56ef5f10d81727bd5cbd42b 100644 (file)
@@ -37,7 +37,9 @@ static int set_secret(struct ceph_crypto_key *key, void *buf)
                return -ENOTSUPP;
        }
 
-       WARN_ON(!key->len);
+       if (!key->len)
+               return -EINVAL;
+
        key->key = kmemdup(buf, key->len, GFP_NOIO);
        if (!key->key) {
                ret = -ENOMEM;
index ad93342c90d72cad59d4797608940b293f2a71fa..8a4d3758030b73d3b9ca24b09f91b1e65be0844e 100644 (file)
@@ -430,6 +430,7 @@ static void ceph_sock_state_change(struct sock *sk)
        switch (sk->sk_state) {
        case TCP_CLOSE:
                dout("%s TCP_CLOSE\n", __func__);
+               /* fall through */
        case TCP_CLOSE_WAIT:
                dout("%s TCP_CLOSE_WAIT\n", __func__);
                con_sock_state_closing(con);
index 9ae1bab8c05db7005d5c345dcb62f6e4b9e145fb..1547107f48544e9690319e4fe9415968448a9f87 100644 (file)
@@ -1279,9 +1279,10 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
 
                /*
                 * Older OSDs don't set reply tid even if the orignal
-                * request had a non-zero tid.  Workaround this weirdness
-                * by falling through to the allocate case.
+                * request had a non-zero tid.  Work around this weirdness
+                * by allocating a new message.
                 */
+               /* fall through */
        case CEPH_MSG_MON_MAP:
        case CEPH_MSG_MDS_MAP:
        case CEPH_MSG_OSD_MAP:
index 8ee29f4f5fa91894e63734cfee3ee6909fd21b26..07ed21d64f92b39da9b683aa432efde6a14afdf0 100644 (file)
@@ -2746,7 +2746,8 @@ EXPORT_SYMBOL(skb_mac_gso_segment);
 static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
 {
        if (tx_path)
-               return skb->ip_summed != CHECKSUM_PARTIAL;
+               return skb->ip_summed != CHECKSUM_PARTIAL &&
+                      skb->ip_summed != CHECKSUM_UNNECESSARY;
 
        return skb->ip_summed == CHECKSUM_NONE;
 }
@@ -7139,13 +7140,17 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
                    __dev_xdp_attached(dev, bpf_op, NULL))
                        return -EBUSY;
 
-               if (bpf_op == ops->ndo_bpf)
-                       prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,
-                                                    dev);
-               else
-                       prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
+               prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,
+                                            bpf_op == ops->ndo_bpf);
                if (IS_ERR(prog))
                        return PTR_ERR(prog);
+
+               if (!(flags & XDP_FLAGS_HW_MODE) &&
+                   bpf_prog_is_dev_bound(prog->aux)) {
+                       NL_SET_ERR_MSG(extack, "using device-bound program without HW_MODE flag is not supported");
+                       bpf_prog_put(prog);
+                       return -EINVAL;
+               }
        }
 
        err = dev_xdp_install(dev, bpf_op, extack, flags, prog);
index 1afa17935954b71ff6ae30d84511a0023afa9cc8..6a85e67fafce224b534dd87bb9407ae115f8ba7a 100644 (file)
@@ -1646,9 +1646,9 @@ static const struct bpf_func_proto bpf_csum_diff_proto = {
        .gpl_only       = false,
        .pkt_access     = true,
        .ret_type       = RET_INTEGER,
-       .arg1_type      = ARG_PTR_TO_MEM,
+       .arg1_type      = ARG_PTR_TO_MEM_OR_NULL,
        .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
-       .arg3_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_PTR_TO_MEM_OR_NULL,
        .arg4_type      = ARG_CONST_SIZE_OR_ZERO,
        .arg5_type      = ARG_ANYTHING,
 };
index ce4aa827be059fe83ec36f3fe1c31f2068a95d8b..f00499a469271fb2165c8ca25fe3b4538e45a01e 100644 (file)
@@ -1223,9 +1223,10 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);
 struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                                 netdev_features_t features)
 {
-       bool fixedid = false, gso_partial, encap;
+       bool udpfrag = false, fixedid = false, gso_partial, encap;
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        const struct net_offload *ops;
+       unsigned int offset = 0;
        struct iphdr *iph;
        int proto, tot_len;
        int nhoff;
@@ -1260,6 +1261,7 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb,
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
        if (!skb->encapsulation || encap) {
+               udpfrag = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
                fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID);
 
                /* fixed ID is invalid if DF bit is not set */
@@ -1279,7 +1281,13 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb,
        skb = segs;
        do {
                iph = (struct iphdr *)(skb_mac_header(skb) + nhoff);
-               if (skb_is_gso(skb)) {
+               if (udpfrag) {
+                       iph->frag_off = htons(offset >> 3);
+                       if (skb->next)
+                               iph->frag_off |= htons(IP_MF);
+                       offset += skb->len - nhoff - ihl;
+                       tot_len = skb->len - nhoff;
+               } else if (skb_is_gso(skb)) {
                        if (!fixedid) {
                                iph->id = htons(id);
                                id += skb_shinfo(skb)->gso_segs;
index e360d55be5554d1bee56d3f493752ba9ae2c8015..01801b77bd0da45764fd0e9a80f22b0e46633934 100644 (file)
@@ -187,16 +187,57 @@ out_unlock:
 }
 EXPORT_SYMBOL(skb_udp_tunnel_segment);
 
-static struct sk_buff *udp4_tunnel_segment(struct sk_buff *skb,
-                                          netdev_features_t features)
+static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
+                                        netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
+       unsigned int mss;
+       __wsum csum;
+       struct udphdr *uh;
+       struct iphdr *iph;
 
        if (skb->encapsulation &&
            (skb_shinfo(skb)->gso_type &
-            (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)))
+            (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) {
                segs = skb_udp_tunnel_segment(skb, features, false);
+               goto out;
+       }
+
+       if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+               goto out;
+
+       mss = skb_shinfo(skb)->gso_size;
+       if (unlikely(skb->len <= mss))
+               goto out;
+
+       /* Do software UFO. Complete and fill in the UDP checksum as
+        * HW cannot do checksum of UDP packets sent as multiple
+        * IP fragments.
+        */
 
+       uh = udp_hdr(skb);
+       iph = ip_hdr(skb);
+
+       uh->check = 0;
+       csum = skb_checksum(skb, 0, skb->len, 0);
+       uh->check = udp_v4_check(skb->len, iph->saddr, iph->daddr, csum);
+       if (uh->check == 0)
+               uh->check = CSUM_MANGLED_0;
+
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       /* If there is no outer header we can fake a checksum offload
+        * due to the fact that we have already done the checksum in
+        * software prior to segmenting the frame.
+        */
+       if (!skb->encap_hdr_csum)
+               features |= NETIF_F_HW_CSUM;
+
+       /* Fragment the skb. IP headers of the fragments are updated in
+        * inet_gso_segment()
+        */
+       segs = skb_segment(skb, features);
+out:
        return segs;
 }
 
@@ -330,7 +371,7 @@ static int udp4_gro_complete(struct sk_buff *skb, int nhoff)
 
 static const struct net_offload udpv4_offload = {
        .callbacks = {
-               .gso_segment = udp4_tunnel_segment,
+               .gso_segment = udp4_ufo_fragment,
                .gro_receive  = udp4_gro_receive,
                .gro_complete = udp4_gro_complete,
        },
index 4a7e5ffa51083112fa3927cfe0c5f7d36cd60235..4fe7c90962ddae3356200376aa911bab6d75bb48 100644 (file)
@@ -31,6 +31,37 @@ static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
        return id;
 }
 
+/* This function exists only for tap drivers that must support broken
+ * clients requesting UFO without specifying an IPv6 fragment ID.
+ *
+ * This is similar to ipv6_select_ident() but we use an independent hash
+ * seed to limit information leakage.
+ *
+ * The network header must be set before calling this.
+ */
+__be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
+{
+       static u32 ip6_proxy_idents_hashrnd __read_mostly;
+       struct in6_addr buf[2];
+       struct in6_addr *addrs;
+       u32 id;
+
+       addrs = skb_header_pointer(skb,
+                                  skb_network_offset(skb) +
+                                  offsetof(struct ipv6hdr, saddr),
+                                  sizeof(buf), buf);
+       if (!addrs)
+               return 0;
+
+       net_get_random_once(&ip6_proxy_idents_hashrnd,
+                           sizeof(ip6_proxy_idents_hashrnd));
+
+       id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd,
+                                &addrs[1], &addrs[0]);
+       return htonl(id);
+}
+EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
+
 __be32 ipv6_select_ident(struct net *net,
                         const struct in6_addr *daddr,
                         const struct in6_addr *saddr)
index 05eb7bc36156a3e571f728ad33d61b1a41a81a1c..7a8d1500d374b4089e623ed2b20d68110cff498e 100644 (file)
@@ -472,6 +472,11 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
                                &match->rt6i_siblings, rt6i_siblings) {
                        route_choosen--;
                        if (route_choosen == 0) {
+                               struct inet6_dev *idev = sibling->rt6i_idev;
+
+                               if (!netif_carrier_ok(sibling->dst.dev) &&
+                                   idev->cnf.ignore_routes_with_linkdown)
+                                       break;
                                if (rt6_score_route(sibling, oif, strict) < 0)
                                        break;
                                match = sibling;
@@ -1019,7 +1024,7 @@ static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)
 {
        struct net_device *dev = rt->dst.dev;
 
-       if (rt->rt6i_flags & RTF_LOCAL) {
+       if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) {
                /* for copies of local routes, dst->dev needs to be the
                 * device if it is a master device, the master device if
                 * device is enslaved, and the loopback as the default
index 455fd4e39333233289e9a844de512f200119ff1a..a0f89ad76f9d2233b9e048418069aacd92ac6a25 100644 (file)
 #include <net/ip6_checksum.h>
 #include "ip6_offload.h"
 
-static struct sk_buff *udp6_tunnel_segment(struct sk_buff *skb,
-                                          netdev_features_t features)
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
+                                        netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
+       unsigned int mss;
+       unsigned int unfrag_ip6hlen, unfrag_len;
+       struct frag_hdr *fptr;
+       u8 *packet_start, *prevhdr;
+       u8 nexthdr;
+       u8 frag_hdr_sz = sizeof(struct frag_hdr);
+       __wsum csum;
+       int tnl_hlen;
+       int err;
+
+       mss = skb_shinfo(skb)->gso_size;
+       if (unlikely(skb->len <= mss))
+               goto out;
 
        if (skb->encapsulation && skb_shinfo(skb)->gso_type &
            (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))
                segs = skb_udp_tunnel_segment(skb, features, true);
+       else {
+               const struct ipv6hdr *ipv6h;
+               struct udphdr *uh;
+
+               if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+                       goto out;
+
+               /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+                * do checksum of UDP packets sent as multiple IP fragments.
+                */
+
+               uh = udp_hdr(skb);
+               ipv6h = ipv6_hdr(skb);
+
+               uh->check = 0;
+               csum = skb_checksum(skb, 0, skb->len, 0);
+               uh->check = udp_v6_check(skb->len, &ipv6h->saddr,
+                                         &ipv6h->daddr, csum);
+               if (uh->check == 0)
+                       uh->check = CSUM_MANGLED_0;
+
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               /* If there is no outer header we can fake a checksum offload
+                * due to the fact that we have already done the checksum in
+                * software prior to segmenting the frame.
+                */
+               if (!skb->encap_hdr_csum)
+                       features |= NETIF_F_HW_CSUM;
+
+               /* Check if there is enough headroom to insert fragment header. */
+               tnl_hlen = skb_tnl_header_len(skb);
+               if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) {
+                       if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz))
+                               goto out;
+               }
+
+               /* Find the unfragmentable header and shift it left by frag_hdr_sz
+                * bytes to insert fragment header.
+                */
+               err = ip6_find_1stfragopt(skb, &prevhdr);
+               if (err < 0)
+                       return ERR_PTR(err);
+               unfrag_ip6hlen = err;
+               nexthdr = *prevhdr;
+               *prevhdr = NEXTHDR_FRAGMENT;
+               unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
+                            unfrag_ip6hlen + tnl_hlen;
+               packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset;
+               memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len);
+
+               SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz;
+               skb->mac_header -= frag_hdr_sz;
+               skb->network_header -= frag_hdr_sz;
+
+               fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
+               fptr->nexthdr = nexthdr;
+               fptr->reserved = 0;
+               fptr->identification = ipv6_proxy_select_ident(dev_net(skb->dev), skb);
+
+               /* Fragment the skb. ipv6 header and the remaining fields of the
+                * fragment header are updated in ipv6_gso_segment()
+                */
+               segs = skb_segment(skb, features);
+       }
 
+out:
        return segs;
 }
 
@@ -75,7 +154,7 @@ static int udp6_gro_complete(struct sk_buff *skb, int nhoff)
 
 static const struct net_offload udpv6_offload = {
        .callbacks = {
-               .gso_segment    =       udp6_tunnel_segment,
+               .gso_segment    =       udp6_ufo_fragment,
                .gro_receive    =       udp6_gro_receive,
                .gro_complete   =       udp6_gro_complete,
        },
index 88cc1ae935ead5f1a2b4a46d2d3af3fbf4cefd8d..d444752dbf40789cfb0d93d3d572b6bd04263671 100644 (file)
@@ -151,21 +151,17 @@ EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
  * After accepting the AddBA Request we activated a timer,
  * resetting it after each frame that arrives from the originator.
  */
-static void sta_rx_agg_session_timer_expired(unsigned long data)
+static void sta_rx_agg_session_timer_expired(struct timer_list *t)
 {
-       /* not an elegant detour, but there is no choice as the timer passes
-        * only one argument, and various sta_info are needed here, so init
-        * flow in sta_info_create gives the TID as data, while the timer_to_id
-        * array gives the sta through container_of */
-       u8 *ptid = (u8 *)data;
-       u8 *timer_to_id = ptid - *ptid;
-       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
-                                        timer_to_tid[0]);
+       struct tid_ampdu_rx *tid_rx_timer =
+               from_timer(tid_rx_timer, t, session_timer);
+       struct sta_info *sta = tid_rx_timer->sta;
+       u8 tid = tid_rx_timer->tid;
        struct tid_ampdu_rx *tid_rx;
        unsigned long timeout;
 
        rcu_read_lock();
-       tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
+       tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
        if (!tid_rx) {
                rcu_read_unlock();
                return;
@@ -180,21 +176,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
        rcu_read_unlock();
 
        ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
-              sta->sta.addr, (u16)*ptid);
+              sta->sta.addr, tid);
 
-       set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
+       set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
        ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
 
-static void sta_rx_agg_reorder_timer_expired(unsigned long data)
+static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
 {
-       u8 *ptid = (u8 *)data;
-       u8 *timer_to_id = ptid - *ptid;
-       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
-                       timer_to_tid[0]);
+       struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, reorder_timer);
 
        rcu_read_lock();
-       ieee80211_release_reorder_timeout(sta, *ptid);
+       ieee80211_release_reorder_timeout(tid_rx->sta, tid_rx->tid);
        rcu_read_unlock();
 }
 
@@ -356,14 +349,12 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
        spin_lock_init(&tid_agg_rx->reorder_lock);
 
        /* rx timer */
-       setup_deferrable_timer(&tid_agg_rx->session_timer,
-                              sta_rx_agg_session_timer_expired,
-                              (unsigned long)&sta->timer_to_tid[tid]);
+       timer_setup(&tid_agg_rx->session_timer,
+                   sta_rx_agg_session_timer_expired, TIMER_DEFERRABLE);
 
        /* rx reorder timer */
-       setup_timer(&tid_agg_rx->reorder_timer,
-                   sta_rx_agg_reorder_timer_expired,
-                   (unsigned long)&sta->timer_to_tid[tid]);
+       timer_setup(&tid_agg_rx->reorder_timer,
+                   sta_rx_agg_reorder_timer_expired, 0);
 
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
@@ -399,6 +390,8 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
        tid_agg_rx->auto_seq = auto_seq;
        tid_agg_rx->started = false;
        tid_agg_rx->reorder_buf_filtered = 0;
+       tid_agg_rx->tid = tid;
+       tid_agg_rx->sta = sta;
        status = WLAN_STATUS_SUCCESS;
 
        /* activate it for RX */
index bef516ec47f94c19f57da37d80c744bb534deeb4..5f8ab5be369fe9705744473b5dc5928a643d50d1 100644 (file)
@@ -330,6 +330,11 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        spin_lock_bh(&sta->lock);
 
+       /* free struct pending for start, if present */
+       tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
+       kfree(tid_tx);
+       sta->ampdu_mlme.tid_start_tx[tid] = NULL;
+
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        if (!tid_tx) {
                spin_unlock_bh(&sta->lock);
@@ -422,15 +427,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
  * add Block Ack response will arrive from the recipient.
  * If this timer expires sta_addba_resp_timer_expired will be executed.
  */
-static void sta_addba_resp_timer_expired(unsigned long data)
+static void sta_addba_resp_timer_expired(struct timer_list *t)
 {
-       /* not an elegant detour, but there is no choice as the timer passes
-        * only one argument, and both sta_info and TID are needed, so init
-        * flow in sta_info_create gives the TID as data, while the timer_to_id
-        * array gives the sta through container_of */
-       u16 tid = *(u8 *)data;
-       struct sta_info *sta = container_of((void *)data,
-               struct sta_info, timer_to_tid[tid]);
+       struct tid_ampdu_tx *tid_tx_timer =
+               from_timer(tid_tx_timer, t, addba_resp_timer);
+       struct sta_info *sta = tid_tx_timer->sta;
+       u8 tid = tid_tx_timer->tid;
        struct tid_ampdu_tx *tid_tx;
 
        /* check if the TID waits for addBA response */
@@ -525,21 +527,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
  * After accepting the AddBA Response we activated a timer,
  * resetting it after each frame that we send.
  */
-static void sta_tx_agg_session_timer_expired(unsigned long data)
+static void sta_tx_agg_session_timer_expired(struct timer_list *t)
 {
-       /* not an elegant detour, but there is no choice as the timer passes
-        * only one argument, and various sta_info are needed here, so init
-        * flow in sta_info_create gives the TID as data, while the timer_to_id
-        * array gives the sta through container_of */
-       u8 *ptid = (u8 *)data;
-       u8 *timer_to_id = ptid - *ptid;
-       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
-                                        timer_to_tid[0]);
+       struct tid_ampdu_tx *tid_tx_timer =
+               from_timer(tid_tx_timer, t, session_timer);
+       struct sta_info *sta = tid_tx_timer->sta;
+       u8 tid = tid_tx_timer->tid;
        struct tid_ampdu_tx *tid_tx;
        unsigned long timeout;
 
        rcu_read_lock();
-       tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]);
+       tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
        if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
                rcu_read_unlock();
                return;
@@ -555,9 +553,9 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
        rcu_read_unlock();
 
        ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
-              sta->sta.addr, (u16)*ptid);
+              sta->sta.addr, tid);
 
-       ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
+       ieee80211_stop_tx_ba_session(&sta->sta, tid);
 }
 
 int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
@@ -670,16 +668,15 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
 
        tid_tx->timeout = timeout;
+       tid_tx->sta = sta;
+       tid_tx->tid = tid;
 
        /* response timer */
-       setup_timer(&tid_tx->addba_resp_timer,
-                   sta_addba_resp_timer_expired,
-                   (unsigned long)&sta->timer_to_tid[tid]);
+       timer_setup(&tid_tx->addba_resp_timer, sta_addba_resp_timer_expired, 0);
 
        /* tx timer */
-       setup_deferrable_timer(&tid_tx->session_timer,
-                              sta_tx_agg_session_timer_expired,
-                              (unsigned long)&sta->timer_to_tid[tid]);
+       timer_setup(&tid_tx->session_timer,
+                   sta_tx_agg_session_timer_expired, TIMER_DEFERRABLE);
 
        /* assign a dialog token */
        sta->ampdu_mlme.dialog_token_allocator++;
index e9c6aa3ed05b8ddb8cf03decce82c00e59b4c0a7..db07e0de9a0374229857f5a2fb4e081928ea936f 100644 (file)
@@ -1711,10 +1711,10 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
        sdata_unlock(sdata);
 }
 
-static void ieee80211_ibss_timer(unsigned long data)
+static void ieee80211_ibss_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.ibss.timer);
 
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
@@ -1723,8 +1723,7 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-       setup_timer(&ifibss->timer, ieee80211_ibss_timer,
-                   (unsigned long) sdata);
+       timer_setup(&ifibss->timer, ieee80211_ibss_timer, 0);
        INIT_LIST_HEAD(&ifibss->incomplete_stations);
        spin_lock_init(&ifibss->incomplete_lock);
        INIT_WORK(&ifibss->csa_connection_drop_work,
index 68f874e73561e8fe4d1a2ba379b26205e9c2cdb4..885d00b419119a2bef3fd0b7c3f00f92c2a968ad 100644 (file)
@@ -1057,6 +1057,7 @@ struct tpt_led_trigger {
        const struct ieee80211_tpt_blink *blink_table;
        unsigned int blink_table_len;
        struct timer_list timer;
+       struct ieee80211_local *local;
        unsigned long prev_traffic;
        unsigned long tx_bytes, rx_bytes;
        unsigned int active, want;
@@ -1932,7 +1933,7 @@ static inline int ieee80211_ac_from_tid(int tid)
 
 void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
 void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
-void ieee80211_dynamic_ps_timer(unsigned long data);
+void ieee80211_dynamic_ps_timer(struct timer_list *t);
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
                             bool powersave);
index 0505845b7ab836c15888a06b3b7d76995d46e685..ba0b507ea6910f2d645f1fecfcb5d09877e2340c 100644 (file)
@@ -248,10 +248,10 @@ static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
        return DIV_ROUND_UP(delta, 1024 / 8);
 }
 
-static void tpt_trig_timer(unsigned long data)
+static void tpt_trig_timer(struct timer_list *t)
 {
-       struct ieee80211_local *local = (void *)data;
-       struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
+       struct tpt_led_trigger *tpt_trig = from_timer(tpt_trig, t, timer);
+       struct ieee80211_local *local = tpt_trig->local;
        struct led_classdev *led_cdev;
        unsigned long on, off, tpt;
        int i;
@@ -306,8 +306,9 @@ __ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
        tpt_trig->blink_table = blink_table;
        tpt_trig->blink_table_len = blink_table_len;
        tpt_trig->want = flags;
+       tpt_trig->local = local;
 
-       setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
+       timer_setup(&tpt_trig->timer, tpt_trig_timer, 0);
 
        local->tpt_led_trigger = tpt_trig;
 
@@ -326,7 +327,7 @@ static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
        tpt_trig_traffic(local, tpt_trig);
        tpt_trig->running = true;
 
-       tpt_trig_timer((unsigned long)local);
+       tpt_trig_timer(&tpt_trig->timer);
        mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
 }
 
index 8aa1f5b6a05145b0838b494abdf2b2c5b0aa17ab..e054a2fd8d38bd00c0e181ca01180b19c3ffb132 100644 (file)
@@ -633,8 +633,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                  ieee80211_dynamic_ps_enable_work);
        INIT_WORK(&local->dynamic_ps_disable_work,
                  ieee80211_dynamic_ps_disable_work);
-       setup_timer(&local->dynamic_ps_timer,
-                   ieee80211_dynamic_ps_timer, (unsigned long) local);
+       timer_setup(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, 0);
 
        INIT_WORK(&local->sched_scan_stopped_work,
                  ieee80211_sched_scan_stopped_work);
index 7a76c4a6df306574f8189f132c148295ac14119e..5e27364e10acf3420e8f192b09488ab4bc252d09 100644 (file)
@@ -37,9 +37,10 @@ void ieee80211s_stop(void)
        kmem_cache_destroy(rm_cache);
 }
 
-static void ieee80211_mesh_housekeeping_timer(unsigned long data)
+static void ieee80211_mesh_housekeeping_timer(struct timer_list *t)
 {
-       struct ieee80211_sub_if_data *sdata = (void *) data;
+       struct ieee80211_sub_if_data *sdata =
+               from_timer(sdata, t, u.mesh.housekeeping_timer);
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
@@ -528,18 +529,18 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-static void ieee80211_mesh_path_timer(unsigned long data)
+static void ieee80211_mesh_path_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mesh.mesh_path_timer);
 
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
 
-static void ieee80211_mesh_path_root_timer(unsigned long data)
+static void ieee80211_mesh_path_root_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mesh.mesh_path_root_timer);
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
        set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
@@ -1442,9 +1443,8 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        static u8 zero_addr[ETH_ALEN] = {};
 
-       setup_timer(&ifmsh->housekeeping_timer,
-                   ieee80211_mesh_housekeeping_timer,
-                   (unsigned long) sdata);
+       timer_setup(&ifmsh->housekeeping_timer,
+                   ieee80211_mesh_housekeeping_timer, 0);
 
        ifmsh->accepting_plinks = true;
        atomic_set(&ifmsh->mpaths, 0);
@@ -1458,12 +1458,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 
        mesh_pathtbl_init(sdata);
 
-       setup_timer(&ifmsh->mesh_path_timer,
-                   ieee80211_mesh_path_timer,
-                   (unsigned long) sdata);
-       setup_timer(&ifmsh->mesh_path_root_timer,
-                   ieee80211_mesh_path_root_timer,
-                   (unsigned long) sdata);
+       timer_setup(&ifmsh->mesh_path_timer, ieee80211_mesh_path_timer, 0);
+       timer_setup(&ifmsh->mesh_path_root_timer,
+                   ieee80211_mesh_path_root_timer, 0);
        INIT_LIST_HEAD(&ifmsh->preq_queue.list);
        skb_queue_head_init(&ifmsh->ps.bc_buf);
        spin_lock_init(&ifmsh->mesh_preq_queue_lock);
index 465b7853edc0b1c85a2145f2b248c81f86fb92eb..ee56f18cad3f7e89e1c60fe4829dab7bfa1ef340 100644 (file)
@@ -296,7 +296,7 @@ void mesh_path_tx_pending(struct mesh_path *mpath);
 int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
 void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata);
 int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
-void mesh_path_timer(unsigned long data);
+void mesh_path_timer(struct timer_list *t);
 void mesh_path_flush_by_nexthop(struct sta_info *sta);
 void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
                             struct sk_buff *skb);
index 146ec6c0f12f86f1de27db23e51326b05bf3e643..4f7826d7b47cd8c63acc14479dacdd379abe9021 100644 (file)
@@ -1194,9 +1194,9 @@ endlookup:
        return err;
 }
 
-void mesh_path_timer(unsigned long data)
+void mesh_path_timer(struct timer_list *t)
 {
-       struct mesh_path *mpath = (void *) data;
+       struct mesh_path *mpath = from_timer(mpath, t, timer);
        struct ieee80211_sub_if_data *sdata = mpath->sdata;
        int ret;
 
index 97269caafecd7b52e644e9bb645d305fdfb67196..86c8dfef56a4c8f021b68aa723ced9447b5b9602 100644 (file)
@@ -399,8 +399,7 @@ struct mesh_path *mesh_path_new(struct ieee80211_sub_if_data *sdata,
        skb_queue_head_init(&new_mpath->frame_queue);
        new_mpath->exp_time = jiffies;
        spin_lock_init(&new_mpath->state_lock);
-       setup_timer(&new_mpath->timer, mesh_path_timer,
-                   (unsigned long) new_mpath);
+       timer_setup(&new_mpath->timer, mesh_path_timer, 0);
 
        return new_mpath;
 }
index e4ededa1909d86590bb1f96116f61951acefcd6c..04460440d731423fe37204d4422db05783820bf2 100644 (file)
@@ -1066,10 +1066,10 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
 }
 EXPORT_SYMBOL(ieee80211_chswitch_done);
 
-static void ieee80211_chswitch_timer(unsigned long data)
+static void ieee80211_chswitch_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mgd.chswitch_timer);
 
        ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
 }
@@ -1577,9 +1577,9 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
        }
 }
 
-void ieee80211_dynamic_ps_timer(unsigned long data)
+void ieee80211_dynamic_ps_timer(struct timer_list *t)
 {
-       struct ieee80211_local *local = (void *) data;
+       struct ieee80211_local *local = from_timer(local, t, dynamic_ps_timer);
 
        ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
 }
@@ -3711,10 +3711,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        sdata_unlock(sdata);
 }
 
-static void ieee80211_sta_timer(unsigned long data)
+static void ieee80211_sta_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mgd.timer);
 
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
@@ -3991,10 +3991,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
        sdata_unlock(sdata);
 }
 
-static void ieee80211_sta_bcn_mon_timer(unsigned long data)
+static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mgd.bcn_mon_timer);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
@@ -4005,10 +4005,10 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
                             &sdata->u.mgd.beacon_connection_loss_work);
 }
 
-static void ieee80211_sta_conn_mon_timer(unsigned long data)
+static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
-               (struct ieee80211_sub_if_data *) data;
+               from_timer(sdata, t, u.mgd.conn_mon_timer);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
@@ -4139,14 +4139,10 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
        INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
        INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
                          ieee80211_tdls_peer_del_work);
-       setup_timer(&ifmgd->timer, ieee80211_sta_timer,
-                   (unsigned long) sdata);
-       setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
-                   (unsigned long) sdata);
-       setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer,
-                   (unsigned long) sdata);
-       setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
-                   (unsigned long) sdata);
+       timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
+       timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
+       timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
+       timer_setup(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, 0);
        INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
                          ieee80211_sta_handle_tspec_ac_params_wk);
 
index 88e6ebbbe24f5562eb69df3c92ca132d15f5733b..d351dc1162beef273c8db1a6902db6216a97bfb7 100644 (file)
@@ -150,9 +150,10 @@ void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata)
        sdata_unlock(sdata);
 }
 
-static void ieee80211_ocb_housekeeping_timer(unsigned long data)
+static void ieee80211_ocb_housekeeping_timer(struct timer_list *t)
 {
-       struct ieee80211_sub_if_data *sdata = (void *)data;
+       struct ieee80211_sub_if_data *sdata =
+               from_timer(sdata, t, u.ocb.housekeeping_timer);
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 
@@ -165,9 +166,8 @@ void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 
-       setup_timer(&ifocb->housekeeping_timer,
-                   ieee80211_ocb_housekeeping_timer,
-                   (unsigned long)sdata);
+       timer_setup(&ifocb->housekeeping_timer,
+                   ieee80211_ocb_housekeeping_timer, 0);
        INIT_LIST_HEAD(&ifocb->incomplete_stations);
        spin_lock_init(&ifocb->incomplete_lock);
 }
index a3060e55122c666eb3eedb6c8c93714e0783cab8..0c5627f8a104e17fb54f55c09da597ef84af5be3 100644 (file)
@@ -379,14 +379,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        if (sta_prepare_rate_control(local, sta, gfp))
                goto free_txq;
 
-       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
-               /*
-                * timer_to_tid must be initialized with identity mapping
-                * to enable session_timer's data differentiation. See
-                * sta_rx_agg_session_timer_expired for usage.
-                */
-               sta->timer_to_tid[i] = i;
-       }
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                skb_queue_head_init(&sta->ps_tx_buf[i]);
                skb_queue_head_init(&sta->tx_filtered[i]);
@@ -1064,9 +1056,9 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
        return ret;
 }
 
-static void sta_info_cleanup(unsigned long data)
+static void sta_info_cleanup(struct timer_list *t)
 {
-       struct ieee80211_local *local = (struct ieee80211_local *) data;
+       struct ieee80211_local *local = from_timer(local, t, sta_cleanup);
        struct sta_info *sta;
        bool timer_needed = false;
 
@@ -1098,8 +1090,7 @@ int sta_info_init(struct ieee80211_local *local)
        mutex_init(&local->sta_mtx);
        INIT_LIST_HEAD(&local->sta_list);
 
-       setup_timer(&local->sta_cleanup, sta_info_cleanup,
-                   (unsigned long)local);
+       timer_setup(&local->sta_cleanup, sta_info_cleanup, 0);
        return 0;
 }
 
index 5c54acd10562a66df8aa093b9352d097cadb17b9..cd53619435b641c446ed4e0e69eda1d97714f54a 100644 (file)
@@ -126,6 +126,8 @@ enum ieee80211_agg_stop_reason {
        AGG_STOP_DESTROY_STA,
 };
 
+struct sta_info;
+
 /**
  * struct tid_ampdu_tx - TID aggregation information (Tx).
  *
@@ -133,8 +135,10 @@ enum ieee80211_agg_stop_reason {
  * @session_timer: check if we keep Tx-ing on the TID (by timeout value)
  * @addba_resp_timer: timer for peer's response to addba request
  * @pending: pending frames queue -- use sta's spinlock to protect
+ * @sta: station we are attached to
  * @dialog_token: dialog token for aggregation session
  * @timeout: session timeout value to be filled in ADDBA requests
+ * @tid: TID number
  * @state: session state (see above)
  * @last_tx: jiffies of last tx activity
  * @stop_initiator: initiator of a session stop
@@ -158,6 +162,7 @@ struct tid_ampdu_tx {
        struct timer_list session_timer;
        struct timer_list addba_resp_timer;
        struct sk_buff_head pending;
+       struct sta_info *sta;
        unsigned long state;
        unsigned long last_tx;
        u16 timeout;
@@ -169,6 +174,7 @@ struct tid_ampdu_tx {
        u16 failed_bar_ssn;
        bool bar_pending;
        bool amsdu;
+       u8 tid;
 };
 
 /**
@@ -181,12 +187,14 @@ struct tid_ampdu_tx {
  * @reorder_time: jiffies when skb was added
  * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
  * @reorder_timer: releases expired frames from the reorder buffer.
+ * @sta: station we are attached to
  * @last_rx: jiffies of last rx activity
  * @head_seq_num: head sequence number in reordering buffer.
  * @stored_mpdu_num: number of MPDUs in reordering buffer
  * @ssn: Starting Sequence Number expected to be aggregated.
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
+ * @tid: TID number
  * @rcu_head: RCU head used for freeing this struct
  * @reorder_lock: serializes access to reorder buffer, see below.
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
@@ -208,6 +216,7 @@ struct tid_ampdu_rx {
        u64 reorder_buf_filtered;
        struct sk_buff_head *reorder_buf;
        unsigned long *reorder_time;
+       struct sta_info *sta;
        struct timer_list session_timer;
        struct timer_list reorder_timer;
        unsigned long last_rx;
@@ -216,6 +225,7 @@ struct tid_ampdu_rx {
        u16 ssn;
        u16 buf_size;
        u16 timeout;
+       u8 tid;
        u8 auto_seq:1,
           removed:1,
           started:1;
@@ -447,7 +457,6 @@ struct ieee80211_sta_rx_stats {
  *     plus one for non-QoS frames)
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
- * @timer_to_tid: identity mapping to ID timers
  * @mesh: mesh STA information
  * @debugfs_dir: debug filesystem directory dentry
  * @dead: set to true when sta is unlinked
@@ -554,7 +563,6 @@ struct sta_info {
         * Aggregation information, locked with lock.
         */
        struct sta_ampdu_mlme ampdu_mlme;
-       u8 timer_to_tid[IEEE80211_NUM_TIDS];
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct dentry *debugfs_dir;
index 0dab33fb9844cd0b2207c2d816780391fb08baa3..99cfafc2a139bac19f8ca78524060fcee3308b89 100644 (file)
@@ -308,6 +308,8 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
                             const struct dp_upcall_info *upcall_info,
                                 uint32_t cutlen)
 {
+       unsigned short gso_type = skb_shinfo(skb)->gso_type;
+       struct sw_flow_key later_key;
        struct sk_buff *segs, *nskb;
        int err;
 
@@ -318,9 +320,21 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
        if (segs == NULL)
                return -EINVAL;
 
+       if (gso_type & SKB_GSO_UDP) {
+               /* The initial flow key extracted by ovs_flow_key_extract()
+                * in this case is for a first fragment, so we need to
+                * properly mark later fragments.
+                */
+               later_key = *key;
+               later_key.ip.frag = OVS_FRAG_TYPE_LATER;
+       }
+
        /* Queue all of the segments. */
        skb = segs;
        do {
+               if (gso_type & SKB_GSO_UDP && skb != segs)
+                       key = &later_key;
+
                err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
                if (err)
                        break;
index 864ddb1e3642bd26d8ca8a9153c9f16d5d766680..dbe2379329c5517fb164b6024d40fabebe7855c8 100644 (file)
@@ -631,7 +631,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
                        key->ip.frag = OVS_FRAG_TYPE_LATER;
                        return 0;
                }
-               if (nh->frag_off & htons(IP_MF))
+               if (nh->frag_off & htons(IP_MF) ||
+                       skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
                        key->ip.frag = OVS_FRAG_TYPE_FIRST;
                else
                        key->ip.frag = OVS_FRAG_TYPE_NONE;
@@ -747,6 +748,9 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 
                if (key->ip.frag == OVS_FRAG_TYPE_LATER)
                        return 0;
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+                       key->ip.frag = OVS_FRAG_TYPE_FIRST;
+
                /* Transport layer. */
                if (key->ip.proto == NEXTHDR_TCP) {
                        if (tcphdr_ok(skb)) {
index 1c40caadcff959ba0c6cec6b8e32f7b459c42cfa..d836f998117b2417548b22a73940300405ce65b8 100644 (file)
@@ -229,6 +229,9 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl,
        const struct iphdr *iph;
        u16 ul;
 
+       if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+               return 1;
+
        /*
         * Support both UDP and UDPLITE checksum algorithms, Don't use
         * udph->len to get the real length without any protocol check,
@@ -282,6 +285,9 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl,
        const struct ipv6hdr *ip6h;
        u16 ul;
 
+       if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+               return 1;
+
        /*
         * Support both UDP and UDPLITE checksum algorithms, Don't use
         * udph->len to get the real length without any protocol check,
index ab255b421781b86d5b76dd1e67b8473e5a928af0..7d97f612c9b94d17ef2f9c454426922105ccc146 100644 (file)
@@ -205,13 +205,14 @@ static void tcf_chain_head_change(struct tcf_chain *chain,
 
 static void tcf_chain_flush(struct tcf_chain *chain)
 {
-       struct tcf_proto *tp;
+       struct tcf_proto *tp = rtnl_dereference(chain->filter_chain);
 
        tcf_chain_head_change(chain, NULL);
-       while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) {
+       while (tp) {
                RCU_INIT_POINTER(chain->filter_chain, tp->next);
-               tcf_chain_put(chain);
                tcf_proto_destroy(tp);
+               tp = rtnl_dereference(chain->filter_chain);
+               tcf_chain_put(chain);
        }
 }
 
index fb680dafac5a2e49515ab84ecc820c592bca4ae0..a9f3e317055c46bae55568627404e2bbc2dc31d9 100644 (file)
@@ -382,15 +382,13 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
 {
        struct bpf_prog *fp;
        char *name = NULL;
+       bool skip_sw;
        u32 bpf_fd;
 
        bpf_fd = nla_get_u32(tb[TCA_BPF_FD]);
+       skip_sw = gen_flags & TCA_CLS_FLAGS_SKIP_SW;
 
-       if (gen_flags & TCA_CLS_FLAGS_SKIP_SW)
-               fp = bpf_prog_get_type_dev(bpf_fd, BPF_PROG_TYPE_SCHED_CLS,
-                                          qdisc_dev(tp->q));
-       else
-               fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_CLS);
+       fp = bpf_prog_get_type_dev(bpf_fd, BPF_PROG_TYPE_SCHED_CLS, skip_sw);
        if (IS_ERR(fp))
                return PTR_ERR(fp);
 
index 2578fbd95664af84ab6b20aeaf4902d52a7ec265..94f21116dac5eff94f99e2254a9eaef7d8378608 100644 (file)
@@ -562,7 +562,7 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_rmb)
 {
        struct smc_connection *conn = &smc->conn;
        struct smc_link_group *lgr = conn->lgr;
-       struct smc_buf_desc *buf_desc = NULL;
+       struct smc_buf_desc *buf_desc = ERR_PTR(-ENOMEM);
        struct list_head *buf_list;
        int bufsize, bufsize_short;
        int sk_buf_size;
@@ -575,7 +575,7 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_rmb)
                /* use socket send buffer size (w/o overhead) as start value */
                sk_buf_size = smc->sk.sk_sndbuf / 2;
 
-       for (bufsize_short = smc_compress_bufsize(smc->sk.sk_sndbuf / 2);
+       for (bufsize_short = smc_compress_bufsize(sk_buf_size);
             bufsize_short >= 0; bufsize_short--) {
 
                if (is_rmb) {
index 7b1ee5a0b03cd10d167a6ca522243c4285996151..73165e9ca5bfd2c2a928f7d1c16569cd1b59e65a 100644 (file)
@@ -855,11 +855,13 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
                return stat;
        if (integ_len > buf->len)
                return stat;
-       if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
-               BUG();
+       if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len)) {
+               WARN_ON_ONCE(1);
+               return stat;
+       }
        /* copy out mic... */
        if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
-               BUG();
+               return stat;
        if (mic.len > RPC_MAX_AUTH_SIZE)
                return stat;
        mic.data = kmalloc(mic.len, GFP_KERNEL);
@@ -1611,8 +1613,10 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
        BUG_ON(integ_len % 4);
        *p++ = htonl(integ_len);
        *p++ = htonl(gc->gc_seq);
-       if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len))
-               BUG();
+       if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len)) {
+               WARN_ON_ONCE(1);
+               goto out_err;
+       }
        if (resbuf->tail[0].iov_base == NULL) {
                if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
                        goto out_err;
index 71de77bd44236dee6bd7ea1e86b8e317aee65060..e8e0831229cfcce48b2d6802493e80a429aa108b 100644 (file)
@@ -250,9 +250,9 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
        svc_xprt_received(new);
 }
 
-int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
-                   struct net *net, const int family,
-                   const unsigned short port, int flags)
+static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
+                           struct net *net, const int family,
+                           const unsigned short port, int flags)
 {
        struct svc_xprt_class *xcl;
 
@@ -380,7 +380,6 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt)
        struct svc_pool *pool;
        struct svc_rqst *rqstp = NULL;
        int cpu;
-       bool queued = false;
 
        if (!svc_xprt_has_something_to_do(xprt))
                goto out;
@@ -401,58 +400,25 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt)
 
        atomic_long_inc(&pool->sp_stats.packets);
 
-redo_search:
+       dprintk("svc: transport %p put into queue\n", xprt);
+       spin_lock_bh(&pool->sp_lock);
+       list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
+       pool->sp_stats.sockets_queued++;
+       spin_unlock_bh(&pool->sp_lock);
+
        /* find a thread for this xprt */
        rcu_read_lock();
        list_for_each_entry_rcu(rqstp, &pool->sp_all_threads, rq_all) {
-               /* Do a lockless check first */
-               if (test_bit(RQ_BUSY, &rqstp->rq_flags))
+               if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags))
                        continue;
-
-               /*
-                * Once the xprt has been queued, it can only be dequeued by
-                * the task that intends to service it. All we can do at that
-                * point is to try to wake this thread back up so that it can
-                * do so.
-                */
-               if (!queued) {
-                       spin_lock_bh(&rqstp->rq_lock);
-                       if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags)) {
-                               /* already busy, move on... */
-                               spin_unlock_bh(&rqstp->rq_lock);
-                               continue;
-                       }
-
-                       /* this one will do */
-                       rqstp->rq_xprt = xprt;
-                       svc_xprt_get(xprt);
-                       spin_unlock_bh(&rqstp->rq_lock);
-               }
-               rcu_read_unlock();
-
                atomic_long_inc(&pool->sp_stats.threads_woken);
                wake_up_process(rqstp->rq_task);
-               put_cpu();
-               goto out;
-       }
-       rcu_read_unlock();
-
-       /*
-        * We didn't find an idle thread to use, so we need to queue the xprt.
-        * Do so and then search again. If we find one, we can't hook this one
-        * up to it directly but we can wake the thread up in the hopes that it
-        * will pick it up once it searches for a xprt to service.
-        */
-       if (!queued) {
-               queued = true;
-               dprintk("svc: transport %p put into queue\n", xprt);
-               spin_lock_bh(&pool->sp_lock);
-               list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
-               pool->sp_stats.sockets_queued++;
-               spin_unlock_bh(&pool->sp_lock);
-               goto redo_search;
+               goto out_unlock;
        }
+       set_bit(SP_CONGESTED, &pool->sp_flags);
        rqstp = NULL;
+out_unlock:
+       rcu_read_unlock();
        put_cpu();
 out:
        trace_svc_xprt_do_enqueue(xprt, rqstp);
@@ -721,38 +687,25 @@ rqst_should_sleep(struct svc_rqst *rqstp)
 
 static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
 {
-       struct svc_xprt *xprt;
        struct svc_pool         *pool = rqstp->rq_pool;
        long                    time_left = 0;
 
        /* rq_xprt should be clear on entry */
        WARN_ON_ONCE(rqstp->rq_xprt);
 
-       /* Normally we will wait up to 5 seconds for any required
-        * cache information to be provided.
-        */
-       rqstp->rq_chandle.thread_wait = 5*HZ;
-
-       xprt = svc_xprt_dequeue(pool);
-       if (xprt) {
-               rqstp->rq_xprt = xprt;
-
-               /* As there is a shortage of threads and this request
-                * had to be queued, don't allow the thread to wait so
-                * long for cache updates.
-                */
-               rqstp->rq_chandle.thread_wait = 1*HZ;
-               clear_bit(SP_TASK_PENDING, &pool->sp_flags);
-               return xprt;
-       }
+       rqstp->rq_xprt = svc_xprt_dequeue(pool);
+       if (rqstp->rq_xprt)
+               goto out_found;
 
        /*
         * We have to be able to interrupt this wait
         * to bring down the daemons ...
         */
        set_current_state(TASK_INTERRUPTIBLE);
+       smp_mb__before_atomic();
+       clear_bit(SP_CONGESTED, &pool->sp_flags);
        clear_bit(RQ_BUSY, &rqstp->rq_flags);
-       smp_mb();
+       smp_mb__after_atomic();
 
        if (likely(rqst_should_sleep(rqstp)))
                time_left = schedule_timeout(timeout);
@@ -761,13 +714,11 @@ static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
 
        try_to_freeze();
 
-       spin_lock_bh(&rqstp->rq_lock);
        set_bit(RQ_BUSY, &rqstp->rq_flags);
-       spin_unlock_bh(&rqstp->rq_lock);
-
-       xprt = rqstp->rq_xprt;
-       if (xprt != NULL)
-               return xprt;
+       smp_mb__after_atomic();
+       rqstp->rq_xprt = svc_xprt_dequeue(pool);
+       if (rqstp->rq_xprt)
+               goto out_found;
 
        if (!time_left)
                atomic_long_inc(&pool->sp_stats.threads_timedout);
@@ -775,6 +726,15 @@ static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
        if (signalled() || kthread_should_stop())
                return ERR_PTR(-EINTR);
        return ERR_PTR(-EAGAIN);
+out_found:
+       /* Normally we will wait up to 5 seconds for any required
+        * cache information to be provided.
+        */
+       if (!test_bit(SP_CONGESTED, &pool->sp_flags))
+               rqstp->rq_chandle.thread_wait = 5*HZ;
+       else
+               rqstp->rq_chandle.thread_wait = 1*HZ;
+       return rqstp->rq_xprt;
 }
 
 static void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
index 992594b7cc6b699d75614ca45bbf4631c5e1ede2..af7893501e40acdbaf678a373f721264cf398029 100644 (file)
@@ -133,6 +133,10 @@ static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma,
        if (ret)
                goto out_err;
 
+       /* Bump page refcnt so Send completion doesn't release
+        * the rq_buffer before all retransmits are complete.
+        */
+       get_page(virt_to_page(rqst->rq_buffer));
        ret = svc_rdma_post_send_wr(rdma, ctxt, 1, 0);
        if (ret)
                goto out_unmap;
@@ -165,7 +169,6 @@ xprt_rdma_bc_allocate(struct rpc_task *task)
                return -EINVAL;
        }
 
-       /* svc_rdma_sendto releases this page */
        page = alloc_page(RPCRDMA_DEF_GFP);
        if (!page)
                return -ENOMEM;
@@ -184,6 +187,7 @@ xprt_rdma_bc_free(struct rpc_task *task)
 {
        struct rpc_rqst *rqst = task->tk_rqstp;
 
+       put_page(virt_to_page(rqst->rq_buffer));
        kfree(rqst->rq_rbuffer);
 }
 
index 5caf8e722a118659f8b9e8c3531f60a8e738158b..46ec069150d50ff53e93a7f17b0d716fa80503a2 100644 (file)
@@ -290,6 +290,7 @@ static void qp_event_handler(struct ib_event *event, void *context)
                        ib_event_msg(event->event), event->event,
                        event->element.qp);
                set_bit(XPT_CLOSE, &xprt->xpt_flags);
+               svc_xprt_enqueue(xprt);
                break;
        }
 }
@@ -322,8 +323,7 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
        set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
        if (test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
                goto out;
-       svc_xprt_enqueue(&xprt->sc_xprt);
-       goto out;
+       goto out_enqueue;
 
 flushed:
        if (wc->status != IB_WC_WR_FLUSH_ERR)
@@ -333,6 +333,8 @@ flushed:
        set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
        svc_rdma_put_context(ctxt, 1);
 
+out_enqueue:
+       svc_xprt_enqueue(&xprt->sc_xprt);
 out:
        svc_xprt_put(&xprt->sc_xprt);
 }
@@ -358,6 +360,7 @@ void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
 
        if (unlikely(wc->status != IB_WC_SUCCESS)) {
                set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+               svc_xprt_enqueue(&xprt->sc_xprt);
                if (wc->status != IB_WC_WR_FLUSH_ERR)
                        pr_err("svcrdma: Send: %s (%u/0x%x)\n",
                               ib_wc_status_msg(wc->status),
@@ -569,8 +572,10 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
                dprintk("svcrdma: Device removal xprt=%p, cm_id=%p\n",
                        xprt, cma_id);
-               if (xprt)
+               if (xprt) {
                        set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+                       svc_xprt_enqueue(&xprt->sc_xprt);
+               }
                break;
 
        default:
index 7821085a7dd87cb81b1b5e3f5c4d33273c65e3d9..12777cac638a6918a626953647a1bf803ced89ad 100644 (file)
@@ -539,8 +539,8 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
                        tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq);
 
                if (leave) {
-                       tipc_group_delete_member(grp, m);
                        __skb_queue_purge(defq);
+                       tipc_group_delete_member(grp, m);
                        break;
                }
                if (!update)
index a0e1951227fab1297ee8929dddb3a4a911ef2a56..b1ac23ca20c86be0af71e9a1ba92cc99d8d5a967 100644 (file)
@@ -2605,10 +2605,32 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                        goto nla_put_failure;
        }
 
-       if (wdev->ssid_len) {
-               if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
+       wdev_lock(wdev);
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_AP:
+               if (wdev->ssid_len &&
+                   nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
                        goto nla_put_failure;
+               break;
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_ADHOC: {
+               const u8 *ssid_ie;
+               if (!wdev->current_bss)
+                       break;
+               ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
+                                              WLAN_EID_SSID);
+               if (!ssid_ie)
+                       break;
+               if (nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
+                       goto nla_put_failure;
+               break;
+               }
+       default:
+               /* nothing */
+               break;
        }
+       wdev_unlock(wdev);
 
        genlmsg_end(msg, hdr);
        return 0;
index 3871998059de7beb9a2bff9a5321a8eb81bfcff4..78e71b0390be90bc16655d380fa6869391c52729 100644 (file)
@@ -3644,27 +3644,14 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy,
        }
 }
 
-int __init regulatory_init(void)
+static int __init regulatory_init_db(void)
 {
-       int err = 0;
+       int err;
 
        err = load_builtin_regdb_keys();
        if (err)
                return err;
 
-       reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
-       if (IS_ERR(reg_pdev))
-               return PTR_ERR(reg_pdev);
-
-       spin_lock_init(&reg_requests_lock);
-       spin_lock_init(&reg_pending_beacons_lock);
-       spin_lock_init(&reg_indoor_lock);
-
-       rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
-
-       user_alpha2[0] = '9';
-       user_alpha2[1] = '7';
-
        /* We always try to get an update for the static regdomain */
        err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
        if (err) {
@@ -3692,6 +3679,31 @@ int __init regulatory_init(void)
 
        return 0;
 }
+#ifndef MODULE
+late_initcall(regulatory_init_db);
+#endif
+
+int __init regulatory_init(void)
+{
+       reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
+       if (IS_ERR(reg_pdev))
+               return PTR_ERR(reg_pdev);
+
+       spin_lock_init(&reg_requests_lock);
+       spin_lock_init(&reg_pending_beacons_lock);
+       spin_lock_init(&reg_indoor_lock);
+
+       rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
+
+       user_alpha2[0] = '9';
+       user_alpha2[1] = '7';
+
+#ifdef MODULE
+       return regulatory_init_db();
+#else
+       return 0;
+#endif
+}
 
 void regulatory_exit(void)
 {
index ec7dfa02c0519483818c40cce40ba0993fbd4712..65fbcf3c32c735b9547a9f77b4a94bd7666d87fd 100644 (file)
@@ -320,6 +320,9 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
        if (iint->flags & IMA_DIGSIG)
                return;
 
+       if (iint->ima_file_status != INTEGRITY_PASS)
+               return;
+
        rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
        if (rc < 0)
                return;
index c03b4f69d5b737defdff632340c4b6095cb0ce57..be02c8b904dba1f3e9135d22d7393895e853f9d3 100644 (file)
@@ -30,6 +30,7 @@ help:
        @echo '  usb                    - USB testing tools'
        @echo '  virtio                 - vhost test module'
        @echo '  vm                     - misc vm tools'
+       @echo '  wmi                    - WMI interface examples'
        @echo '  x86_energy_perf_policy - Intel energy policy tool'
        @echo ''
        @echo 'You can do:'
@@ -58,7 +59,7 @@ acpi: FORCE
 cpupower: FORCE
        $(call descend,power/$@)
 
-cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds: FORCE
+cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
        $(call descend,$@)
 
 liblockdep: FORCE
@@ -93,7 +94,7 @@ kvm_stat: FORCE
 all: acpi cgroup cpupower gpio hv firewire liblockdep \
                perf selftests spi turbostat usb \
                virtio vm bpf x86_energy_perf_policy \
-               tmon freefall iio objtool kvm_stat
+               tmon freefall iio objtool kvm_stat wmi
 
 acpi_install:
        $(call descend,power/$(@:_install=),install)
@@ -101,7 +102,7 @@ acpi_install:
 cpupower_install:
        $(call descend,power/$(@:_install=),install)
 
-cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install:
+cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install:
        $(call descend,$(@:_install=),install)
 
 liblockdep_install:
@@ -126,7 +127,8 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
                hv_install firewire_install iio_install liblockdep_install \
                perf_install selftests_install turbostat_install usb_install \
                virtio_install vm_install bpf_install x86_energy_perf_policy_install \
-               tmon_install freefall_install objtool_install kvm_stat_install
+               tmon_install freefall_install objtool_install kvm_stat_install \
+               wmi_install
 
 acpi_clean:
        $(call descend,power/acpi,clean)
@@ -134,7 +136,7 @@ acpi_clean:
 cpupower_clean:
        $(call descend,power/cpupower,clean)
 
-cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
+cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
        $(call descend,$(@:_clean=),clean)
 
 liblockdep_clean:
@@ -172,6 +174,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
                perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
                vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
                freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
-               gpio_clean objtool_clean leds_clean
+               gpio_clean objtool_clean leds_clean wmi_clean
 
 .PHONY: FORCE
index f45c44ef9beca35139e1c8262ef88fe7396cd7dc..ad619b96c27664300df9a78bc28958c4d8662a4b 100644 (file)
@@ -41,7 +41,6 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <net/if.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -230,21 +229,6 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
                     info->tag[0], info->tag[1], info->tag[2], info->tag[3],
                     info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
 
-       if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
-               jsonw_name(json_wtr, "dev");
-               if (info->ifindex) {
-                       char name[IF_NAMESIZE];
-
-                       if (!if_indextoname(info->ifindex, name))
-                               jsonw_printf(json_wtr, "\"ifindex:%d\"",
-                                            info->ifindex);
-                       else
-                               jsonw_printf(json_wtr, "\"%s\"", name);
-               } else {
-                       jsonw_printf(json_wtr, "\"unknown\"");
-               }
-       }
-
        if (info->load_time) {
                char buf[32];
 
@@ -302,21 +286,6 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
 
        printf("tag ");
        fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
-       printf(" ");
-
-       if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
-               printf("dev ");
-               if (info->ifindex) {
-                       char name[IF_NAMESIZE];
-
-                       if (!if_indextoname(info->ifindex, name))
-                               printf("ifindex:%d ", info->ifindex);
-                       else
-                               printf("%s ", name);
-               } else {
-                       printf("unknown ");
-               }
-       }
        printf("\n");
 
        if (info->load_time) {
index e880ae6434eed9eb29db99169c716c94c7cf30aa..4c223ab30293cd1e07248b960e213c7f22b778c5 100644 (file)
@@ -262,7 +262,7 @@ union bpf_attr {
                __u32           kern_version;   /* checked when prog_type=kprobe */
                __u32           prog_flags;
                char            prog_name[BPF_OBJ_NAME_LEN];
-               __u32           prog_target_ifindex;    /* ifindex of netdev to prep for */
+               __u32           prog_ifindex;   /* ifindex of netdev to prep for */
        };
 
        struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -897,10 +897,6 @@ enum sk_action {
 
 #define BPF_TAG_SIZE   8
 
-enum bpf_prog_status {
-       BPF_PROG_STATUS_DEV_BOUND       = (1 << 0),
-};
-
 struct bpf_prog_info {
        __u32 type;
        __u32 id;
@@ -914,8 +910,6 @@ struct bpf_prog_info {
        __u32 nr_map_ids;
        __aligned_u64 map_ids;
        char name[BPF_OBJ_NAME_LEN];
-       __u32 ifindex;
-       __u32 status;
 } __attribute__((aligned(8)));
 
 struct bpf_map_info {
index bf092b83e45382e063fbfadf5ae5c84613fdd9f5..3c64f30cf63cc2b6adb532a3b1f3201533193f7f 100644 (file)
@@ -4377,11 +4377,10 @@ static struct bpf_test tests[] = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
                        BPF_LD_MAP_FD(BPF_REG_1, 0),
                        BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
-                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
-                       BPF_MOV64_IMM(BPF_REG_1, 0),
-                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
-                       BPF_MOV64_IMM(BPF_REG_3, 0),
-                       BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_trace_printk),
                        BPF_EXIT_INSN(),
                },
                .fixup_map2 = { 3 },
@@ -4481,14 +4480,12 @@ static struct bpf_test tests[] = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
                        BPF_LD_MAP_FD(BPF_REG_1, 0),
                        BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
-                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_1,
                                offsetof(struct test_val, foo)),
-                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
-                       BPF_MOV64_IMM(BPF_REG_1, 0),
-                       BPF_MOV64_IMM(BPF_REG_3, 0),
-                       BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_trace_printk),
                        BPF_EXIT_INSN(),
                },
                .fixup_map2 = { 3 },
@@ -4618,18 +4615,16 @@ static struct bpf_test tests[] = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
                        BPF_LD_MAP_FD(BPF_REG_1, 0),
                        BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
-                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
                        BPF_MOV64_IMM(BPF_REG_3, 0),
                        BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3),
-                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
-                       BPF_MOV64_IMM(BPF_REG_1, 0),
-                       BPF_MOV64_IMM(BPF_REG_3, 0),
-                       BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_trace_printk),
                        BPF_EXIT_INSN(),
                },
                .fixup_map2 = { 3 },
-               .errstr = "R2 min value is outside of the array range",
+               .errstr = "R1 min value is outside of the array range",
                .result = REJECT,
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
        },
@@ -4760,20 +4755,18 @@ static struct bpf_test tests[] = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
                        BPF_LD_MAP_FD(BPF_REG_1, 0),
                        BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
-                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
                        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
                        BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
-                               offsetof(struct test_val, foo), 4),
+                               offsetof(struct test_val, foo), 3),
                        BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3),
-                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
-                       BPF_MOV64_IMM(BPF_REG_1, 0),
-                       BPF_MOV64_IMM(BPF_REG_3, 0),
-                       BPF_EMIT_CALL(BPF_FUNC_probe_write_user),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_trace_printk),
                        BPF_EXIT_INSN(),
                },
                .fixup_map2 = { 3 },
-               .errstr = "R2 min value is outside of the array range",
+               .errstr = "R1 min value is outside of the array range",
                .result = REJECT,
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
        },
@@ -5638,7 +5631,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
        },
        {
-               "helper access to variable memory: size = 0 allowed on NULL",
+               "helper access to variable memory: size = 0 allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_1, 0),
                        BPF_MOV64_IMM(BPF_REG_2, 0),
@@ -5652,7 +5645,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size > 0 not allowed on NULL",
+               "helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_1, 0),
                        BPF_MOV64_IMM(BPF_REG_2, 0),
@@ -5670,7 +5663,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size = 0 allowed on != NULL stack pointer",
+               "helper access to variable memory: size = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
@@ -5687,7 +5680,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size = 0 allowed on != NULL map pointer",
+               "helper access to variable memory: size = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
                        BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5709,7 +5702,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer",
+               "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
                        BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5734,7 +5727,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size possible = 0 allowed on != NULL map pointer",
+               "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
                        BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -5757,7 +5750,7 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
-               "helper access to variable memory: size possible = 0 allowed on != NULL packet pointer",
+               "helper access to variable memory: size possible = 0 allowed on != NULL packet pointer (ARG_PTR_TO_MEM_OR_NULL)",
                .insns = {
                        BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
                                    offsetof(struct __sk_buff, data)),
@@ -5778,6 +5771,105 @@ static struct bpf_test tests[] = {
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
+       {
+               "helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr = "R1 type=inv expected=fp",
+               .result = REJECT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
+       {
+               "helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_2, 1),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr = "R1 type=inv expected=fp",
+               .result = REJECT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
+       {
+               "helper access to variable memory: size = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .result = ACCEPT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
+       {
+               "helper access to variable memory: size = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .result = ACCEPT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
+       {
+               "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+                       BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 4),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .result = ACCEPT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
+       {
+               "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+                       BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 2),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_EMIT_CALL(BPF_FUNC_probe_read),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .result = ACCEPT,
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+       },
        {
                "helper access to variable memory: 8 bytes leak",
                .insns = {
diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile
new file mode 100644 (file)
index 0000000..e664f11
--- /dev/null
@@ -0,0 +1,18 @@
+PREFIX ?= /usr
+SBINDIR ?= sbin
+INSTALL ?= install
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+CC = $(CROSS_COMPILE)gcc
+
+TARGET = dell-smbios-example
+
+all: $(TARGET)
+
+%: %.c
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+       $(RM) $(TARGET)
+
+install: dell-smbios-example
+       $(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
diff --git a/tools/wmi/dell-smbios-example.c b/tools/wmi/dell-smbios-example.c
new file mode 100644 (file)
index 0000000..9d3bde0
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ *  Sample application for SMBIOS communication over WMI interface
+ *  Performs the following:
+ *  - Simple cmd_class/cmd_select lookup for TPM information
+ *  - Simple query of known tokens and their values
+ *  - Simple activation of a token
+ *
+ *  Copyright (C) 2017 Dell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+/* if uapi header isn't installed, this might not yet exist */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+#include <linux/wmi.h>
+
+/* It would be better to discover these using udev, but for a simple
+ * application they're hardcoded
+ */
+static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
+static const char *token_sysfs =
+                       "/sys/bus/platform/devices/dell-smbios.0/tokens";
+
+static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
+{
+       printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
+       buffer->std.cmd_class, buffer->std.cmd_select,
+       buffer->std.input[0], buffer->std.input[1],
+       buffer->std.input[2], buffer->std.input[3],
+       buffer->std.output[0], buffer->std.output[1],
+       buffer->std.output[2], buffer->std.output[3]);
+}
+
+static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
+{
+       int fd;
+       int ret;
+
+       fd = open(ioctl_devfs, O_NONBLOCK);
+       ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
+       close(fd);
+       return ret;
+}
+
+static int find_token(__u16 token, __u16 *location, __u16 *value)
+{
+       char location_sysfs[60];
+       char value_sysfs[57];
+       char buf[4096];
+       FILE *f;
+       int ret;
+
+       ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
+       if (ret < 0) {
+               printf("sprintf value failed\n");
+               return 2;
+       }
+       f = fopen(value_sysfs, "rb");
+       if (!f) {
+               printf("failed to open %s\n", value_sysfs);
+               return 2;
+       }
+       fread(buf, 1, 4096, f);
+       fclose(f);
+       *value = (__u16) strtol(buf, NULL, 16);
+
+       ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
+       if (ret < 0) {
+               printf("sprintf location failed\n");
+               return 1;
+       }
+       f = fopen(location_sysfs, "rb");
+       if (!f) {
+               printf("failed to open %s\n", location_sysfs);
+               return 2;
+       }
+       fread(buf, 1, 4096, f);
+       fclose(f);
+       *location = (__u16) strtol(buf, NULL, 16);
+
+       if (*location)
+               return 0;
+       return 2;
+}
+
+static int token_is_active(__u16 *location, __u16 *cmpvalue,
+                          struct dell_wmi_smbios_buffer *buffer)
+{
+       int ret;
+
+       buffer->std.cmd_class = CLASS_TOKEN_READ;
+       buffer->std.cmd_select = SELECT_TOKEN_STD;
+       buffer->std.input[0] = *location;
+       ret = run_wmi_smbios_cmd(buffer);
+       if (ret != 0 || buffer->std.output[0] != 0)
+               return ret;
+       ret = (buffer->std.output[1] == *cmpvalue);
+       return ret;
+}
+
+static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
+{
+       __u16 location;
+       __u16 value;
+       int ret;
+
+       ret = find_token(token, &location, &value);
+       if (ret != 0) {
+               printf("unable to find token %04x\n", token);
+               return 1;
+       }
+       return token_is_active(&location, &value, buffer);
+}
+
+static int activate_token(struct dell_wmi_smbios_buffer *buffer,
+                  __u16 token)
+{
+       __u16 location;
+       __u16 value;
+       int ret;
+
+       ret = find_token(token, &location, &value);
+       if (ret != 0) {
+               printf("unable to find token %04x\n", token);
+               return 1;
+       }
+       buffer->std.cmd_class = CLASS_TOKEN_WRITE;
+       buffer->std.cmd_select = SELECT_TOKEN_STD;
+       buffer->std.input[0] = location;
+       buffer->std.input[1] = 1;
+       ret = run_wmi_smbios_cmd(buffer);
+       return ret;
+}
+
+static int query_buffer_size(__u64 *buffer_size)
+{
+       FILE *f;
+
+       f = fopen(ioctl_devfs, "rb");
+       if (!f)
+               return -EINVAL;
+       fread(buffer_size, sizeof(__u64), 1, f);
+       fclose(f);
+       return EXIT_SUCCESS;
+}
+
+int main(void)
+{
+       struct dell_wmi_smbios_buffer *buffer;
+       int ret;
+       __u64 value = 0;
+
+       ret = query_buffer_size(&value);
+       if (ret == EXIT_FAILURE || !value) {
+               printf("Unable to read buffer size\n");
+               goto out;
+       }
+       printf("Detected required buffer size %lld\n", value);
+
+       buffer = malloc(value);
+       if (buffer == NULL) {
+               printf("failed to alloc memory for ioctl\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       buffer->length = value;
+
+       /* simple SMBIOS call for looking up TPM info */
+       buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
+       buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
+       buffer->std.input[0] = 2;
+       ret = run_wmi_smbios_cmd(buffer);
+       if (ret) {
+               printf("smbios ioctl failed: %d\n", ret);
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+       show_buffer(buffer);
+
+       /* query some tokens */
+       ret = query_token(CAPSULE_EN_TOKEN, buffer);
+       printf("UEFI Capsule enabled token is: %d\n", ret);
+       ret = query_token(CAPSULE_DIS_TOKEN, buffer);
+       printf("UEFI Capsule disabled token is: %d\n", ret);
+
+       /* activate UEFI capsule token if disabled */
+       if (ret) {
+               printf("Enabling UEFI capsule token");
+               if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
+                       printf("activate failed\n");
+                       ret = -1;
+                       goto out;
+               }
+       }
+       ret = EXIT_SUCCESS;
+out:
+       free(buffer);
+       return ret;
+}