summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-samsung-laptop2
-rw-r--r--Documentation/bpf/bpf_devel_QA.txt31
-rw-r--r--Documentation/devicetree/bindings/thermal/armada-thermal.txt37
-rw-r--r--Documentation/devicetree/bindings/thermal/rcar-thermal.txt1
-rw-r--r--Documentation/networking/ip-sysctl.txt4
-rw-r--r--MAINTAINERS16
-rw-r--r--arch/x86/events/perf_event.h3
-rw-r--r--arch/x86/include/asm/intel-family.h6
-rw-r--r--arch/x86/include/asm/intel_pmc_ipc.h6
-rw-r--r--arch/x86/include/asm/pmc_core.h27
-rw-r--r--drivers/acpi/acpi_lpit.c1
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c4
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h7
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c1
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h1
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c113
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c14
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h24
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c10
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h43
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c21
-rw-r--r--drivers/net/netdevsim/bpf.c5
-rw-r--r--drivers/net/phy/mdio_bus.c3
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/mellanox/Kconfig26
-rw-r--r--drivers/platform/mellanox/Makefile6
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c638
-rw-r--r--drivers/platform/x86/Kconfig56
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wireless.c71
-rw-r--r--drivers/platform/x86/alienware-wmi.c17
-rw-r--r--drivers/platform/x86/apple-gmux.c48
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c13
-rw-r--r--drivers/platform/x86/dell-laptop.c260
-rw-r--r--drivers/platform/x86/dell-smbios.c8
-rw-r--r--drivers/platform/x86/dell-wmi.c3
-rw-r--r--drivers/platform/x86/gpd-pocket-fan.c216
-rw-r--r--drivers/platform/x86/ideapad-laptop.c28
-rw-r--r--drivers/platform/x86/intel-hid.c41
-rw-r--r--drivers/platform/x86/intel-vbtn.c65
-rw-r--r--drivers/platform/x86/intel_chtdc_ti_pwrbtn.c93
-rw-r--r--drivers/platform/x86/intel_int0002_vgpio.c2
-rw-r--r--drivers/platform/x86/intel_pmc_core.c280
-rw-r--r--drivers/platform/x86/intel_pmc_core.h29
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c33
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c83
-rw-r--r--drivers/platform/x86/mlx-platform.c324
-rw-r--r--drivers/platform/x86/mlxcpld-hotplug.c515
-rw-r--r--drivers/platform/x86/pmc_atom.c56
-rw-r--r--drivers/platform/x86/silead_dmi.c175
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c18
-rw-r--r--drivers/thermal/Kconfig4
-rw-r--r--drivers/thermal/armada_thermal.c253
-rw-r--r--drivers/thermal/hisi_thermal.c2
-rw-r--r--drivers/thermal/imx_thermal.c74
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c12
-rw-r--r--drivers/thermal/mtk_thermal.c9
-rw-r--r--drivers/thermal/of-thermal.c1
-rw-r--r--drivers/thermal/power_allocator.c2
-rw-r--r--drivers/thermal/tegra/soctherm.c103
-rw-r--r--drivers/thermal/thermal_hwmon.c20
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c4
-rw-r--r--include/asm-generic/qrwlock_types.h1
-rw-r--r--include/linux/jump_label.h4
-rw-r--r--include/linux/netdevice.h6
-rw-r--r--include/linux/platform_data/mlxcpld-hotplug.h99
-rw-r--r--include/linux/platform_data/mlxreg.h144
-rw-r--r--include/media/dvb_vb2.h10
-rw-r--r--include/net/erspan.h26
-rw-r--r--include/uapi/linux/input-event-codes.h1
-rw-r--r--kernel/bpf/core.c32
-rw-r--r--net/bpf/test_run.c4
-rw-r--r--net/ipv4/ip_gre.c14
-rw-r--r--net/ipv6/ip6_gre.c15
-rw-r--r--net/rds/ib.c3
-rw-r--r--net/sched/cls_u32.c21
-rw-r--r--net/sctp/ipv6.c10
-rw-r--r--net/sctp/protocol.c10
-rw-r--r--samples/bpf/Makefile2
-rw-r--r--samples/bpf/bpf_load.c102
-rw-r--r--samples/bpf/bpf_load.h2
-rw-r--r--samples/bpf/tcbpf2_kern.c41
-rwxr-xr-xsamples/bpf/test_tunnel_bpf.sh4
-rw-r--r--samples/bpf/xdp1_user.c4
-rw-r--r--samples/bpf/xdp_redirect_cpu_user.c6
-rw-r--r--samples/bpf/xdp_redirect_map_user.c8
-rw-r--r--samples/bpf/xdp_redirect_user.c8
-rw-r--r--samples/bpf/xdp_router_ipv4_user.c10
-rw-r--r--samples/bpf/xdp_rxq_info_user.c4
-rw-r--r--samples/bpf/xdp_tx_iptunnel_user.c6
-rw-r--r--tools/arch/powerpc/include/uapi/asm/kvm.h25
-rw-r--r--tools/arch/s390/include/uapi/asm/kvm.h5
-rw-r--r--tools/arch/x86/include/asm/cpufeatures.h24
-rw-r--r--tools/arch/x86/include/asm/disabled-features.h3
-rw-r--r--tools/arch/x86/include/asm/required-features.h3
-rw-r--r--tools/include/uapi/linux/if_link.h943
-rw-r--r--tools/include/uapi/linux/kvm.h4
-rw-r--r--tools/include/uapi/linux/netlink.h251
-rw-r--r--tools/include/uapi/linux/sched.h5
-rw-r--r--tools/include/uapi/sound/asound.h9
-rw-r--r--tools/lib/bpf/Build2
-rw-r--r--tools/lib/bpf/Makefile6
-rw-r--r--tools/lib/bpf/bpf.c135
-rw-r--r--tools/lib/bpf/bpf.h2
-rw-r--r--tools/lib/bpf/libbpf.c4
-rw-r--r--tools/lib/bpf/libbpf.h6
-rw-r--r--tools/lib/bpf/nlattr.c187
-rw-r--r--tools/lib/bpf/nlattr.h72
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/builtin-trace.c5
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/evsel.c13
-rw-r--r--tools/testing/selftests/bpf/.gitignore1
-rw-r--r--tools/testing/selftests/bpf/Makefile4
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c14
119 files changed, 4630 insertions, 1678 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
index 63c1ad0212fc..34d3a3359cf4 100644
--- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -3,7 +3,7 @@ Date: January 1, 2010
KernelVersion: 2.6.33
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Description: Some Samsung laptops have different "performance levels"
- that are can be modified by a function key, and by this
+ that can be modified by a function key, and by this
sysfs file. These values don't always make a whole lot
of sense, but some users like to modify them to keep
their fans quiet at all costs. Reading from this file
diff --git a/Documentation/bpf/bpf_devel_QA.txt b/Documentation/bpf/bpf_devel_QA.txt
index cefef855dea4..84cbb302f2b5 100644
--- a/Documentation/bpf/bpf_devel_QA.txt
+++ b/Documentation/bpf/bpf_devel_QA.txt
@@ -516,4 +516,35 @@ A: LLVM has a -mcpu selector for the BPF back end in order to allow the
By the way, the BPF kernel selftests run with -mcpu=probe for better
test coverage.
+Q: In some cases clang flag "-target bpf" is used but in other cases the
+ default clang target, which matches the underlying architecture, is used.
+ What is the difference and when I should use which?
+
+A: Although LLVM IR generation and optimization try to stay architecture
+ independent, "-target <arch>" still has some impact on generated code:
+
+ - BPF program may recursively include header file(s) with file scope
+ inline assembly codes. The default target can handle this well,
+ while bpf target may fail if bpf backend assembler does not
+ understand these assembly codes, which is true in most cases.
+
+ - When compiled without -g, additional elf sections, e.g.,
+ .eh_frame and .rela.eh_frame, may be present in the object file
+ with default target, but not with bpf target.
+
+ - The default target may turn a C switch statement into a switch table
+ lookup and jump operation. Since the switch table is placed
+ in the global readonly section, the bpf program will fail to load.
+ The bpf target does not support switch table optimization.
+ The clang option "-fno-jump-tables" can be used to disable
+ switch table generation.
+
+ You should use default target when:
+
+ - Your program includes a header file, e.g., ptrace.h, which eventually
+ pulls in some header files containing file scope host assembly codes.
+ - You can add "-fno-jump-tables" to work around the switch table issue.
+
+ Otherwise, you can use bpf target.
+
Happy BPF hacking!
diff --git a/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/Documentation/devicetree/bindings/thermal/armada-thermal.txt
index 24aacf8948c5..e0d013a2e66d 100644
--- a/Documentation/devicetree/bindings/thermal/armada-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/armada-thermal.txt
@@ -2,22 +2,35 @@
Required properties:
-- compatible: Should be set to one of the following:
- marvell,armada370-thermal
- marvell,armada375-thermal
- marvell,armada380-thermal
- marvell,armadaxp-thermal
+- compatible: Should be set to one of the following:
+ * marvell,armada370-thermal
+ * marvell,armada375-thermal
+ * marvell,armada380-thermal
+ * marvell,armadaxp-thermal
+ * marvell,armada-ap806-thermal
+ * marvell,armada-cp110-thermal
-- reg: Device's register space.
- Two entries are expected, see the examples below.
- The first one is required for the sensor register;
- the second one is required for the control register
- to be used for sensor initialization (a.k.a. calibration).
+- reg: Device's register space.
+ Two entries are expected, see the examples below. The first one points
+ to the status register (4B). The second one points to the control
+ registers (8B).
+ Note: The compatibles marvell,armada370-thermal,
+ marvell,armada380-thermal, and marvell,armadaxp-thermal must point to
+ "control MSB/control 1", with size of 4 (deprecated binding), or point
+ to "control LSB/control 0" with size of 8 (current binding). All other
+ compatibles must point to "control LSB/control 0" with size of 8.
-Example:
+Examples:
+ /* Legacy bindings */
thermal@d0018300 {
compatible = "marvell,armada370-thermal";
- reg = <0xd0018300 0x4
+ reg = <0xd0018300 0x4
0xd0018304 0x4>;
};
+
+ ap_thermal: thermal@6f8084 {
+ compatible = "marvell,armada-ap806-thermal";
+ reg = <0x6f808C 0x4>,
+ <0x6f8084 0x8>;
+ };
diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
index a8e52c8ccfcc..349e635f2d87 100644
--- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt
@@ -6,6 +6,7 @@ Required properties:
"renesas,rcar-thermal" (without thermal-zone) as fallback.
Examples with soctypes are:
- "renesas,thermal-r8a73a4" (R-Mobile APE6)
+ - "renesas,thermal-r8a7743" (RZ/G1M)
- "renesas,thermal-r8a7779" (R-Car H1)
- "renesas,thermal-r8a7790" (R-Car H2)
- "renesas,thermal-r8a7791" (R-Car M2-W)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 3f2c40d8e6aa..a553d4e4a0fb 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -508,7 +508,7 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
min: Minimal size of receive buffer used by TCP sockets.
It is guaranteed to each TCP socket, even under moderate memory
pressure.
- Default: 1 page
+ Default: 4K
default: initial size of receive buffer used by TCP sockets.
This value overrides net.core.rmem_default used by other protocols.
@@ -667,7 +667,7 @@ tcp_window_scaling - BOOLEAN
tcp_wmem - vector of 3 INTEGERs: min, default, max
min: Amount of memory reserved for send buffers for TCP sockets.
Each TCP socket has rights to use it due to fact of its birth.
- Default: 1 page
+ Default: 4K
default: initial size of send buffer used by TCP sockets. This
value overrides net.core.wmem_default used by other protocols.
diff --git a/MAINTAINERS b/MAINTAINERS
index a284684b1463..d1212226cbba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6001,6 +6001,12 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/goodix.c
+GPD POCKET FAN DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/gpd-pocket-fan.c
+
GPIO ACPI SUPPORT
M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
@@ -8939,12 +8945,13 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxfw/
-MELLANOX MLX CPLD HOTPLUG DRIVER
+MELLANOX HARDWARE PLATFORM SUPPORT
+M: Andy Shevchenko <andy@infradead.org>
+M: Darren Hart <dvhart@infradead.org>
M: Vadim Pasternak <vadimp@mellanox.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
-F: drivers/platform/x86/mlxcpld-hotplug.c
-F: include/linux/platform_data/mlxcpld-hotplug.h
+F: drivers/platform/mellanox/
MELLANOX MLX4 core VPI driver
M: Tariq Toukan <tariqt@mellanox.com>
@@ -13320,7 +13327,6 @@ F: include/linux/platform_data/dma-dw.h
F: drivers/dma/dw/
SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
-M: Jie Deng <jiedeng@synopsys.com>
M: Jose Abreu <Jose.Abreu@synopsys.com>
L: netdev@vger.kernel.org
S: Supported
@@ -15135,7 +15141,7 @@ X86 PLATFORM DRIVERS
M: Darren Hart <dvhart@infradead.org>
M: Andy Shevchenko <andy@infradead.org>
L: platform-driver-x86@vger.kernel.org
-T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
+T: git git://git.infradead.org/linux-platform-drivers-x86.git
S: Maintained
F: drivers/platform/x86/
F: drivers/platform/olpc/
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 8e4ea143ed96..78f91ec1056e 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -93,7 +93,8 @@ struct amd_nb {
PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \
PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | \
- PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER)
+ PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | \
+ PERF_SAMPLE_PERIOD)
#define PEBS_REGS \
(PERF_REG_X86_AX | \
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
index 35a6bc4da8ad..cf090e584202 100644
--- a/arch/x86/include/asm/intel-family.h
+++ b/arch/x86/include/asm/intel-family.h
@@ -10,6 +10,10 @@
*
* Things ending in "2" are usually because we have no better
* name for them. There's no processor called "SILVERMONT2".
+ *
+ * While adding a new CPUID for a new microarchitecture, add a new
+ * group to keep logically sorted out in chronological order. Within
+ * that group keep the CPUID for the variants sorted by model number.
*/
#define INTEL_FAM6_CORE_YONAH 0x0E
@@ -49,6 +53,8 @@
#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
+#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66
+
/* "Small Core" Processors (Atom) */
#define INTEL_FAM6_ATOM_PINEVIEW 0x1C
diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h
index 528ed4be4393..9e7adcdbe031 100644
--- a/arch/x86/include/asm/intel_pmc_ipc.h
+++ b/arch/x86/include/asm/intel_pmc_ipc.h
@@ -38,6 +38,7 @@ int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen);
int intel_pmc_s0ix_counter_read(u64 *data);
int intel_pmc_gcr_read(u32 offset, u32 *data);
+int intel_pmc_gcr_read64(u32 offset, u64 *data);
int intel_pmc_gcr_write(u32 offset, u32 data);
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
@@ -70,6 +71,11 @@ static inline int intel_pmc_gcr_read(u32 offset, u32 *data)
return -EINVAL;
}
+static inline int intel_pmc_gcr_read64(u32 offset, u64 *data)
+{
+ return -EINVAL;
+}
+
static inline int intel_pmc_gcr_write(u32 offset, u32 data)
{
return -EINVAL;
diff --git a/arch/x86/include/asm/pmc_core.h b/arch/x86/include/asm/pmc_core.h
deleted file mode 100644
index d4855f11136d..000000000000
--- a/arch/x86/include/asm/pmc_core.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Intel Core SoC Power Management Controller Header File
- *
- * Copyright (c) 2016, Intel Corporation.
- * All Rights Reserved.
- *
- * Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
- * Vishwanath Somayaji <vishwanath.somayaji@intel.com>
- *
- * 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 _ASM_PMC_CORE_H
-#define _ASM_PMC_CORE_H
-
-/* API to read SLP_S0_RESIDENCY counter */
-int intel_pmc_slp_s0_counter_read(u32 *data);
-
-#endif /* _ASM_PMC_CORE_H */
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
index e94e478dd18b..cf4fc0161164 100644
--- a/drivers/acpi/acpi_lpit.c
+++ b/drivers/acpi/acpi_lpit.c
@@ -100,6 +100,7 @@ int lpit_read_residency_count_address(u64 *address)
return 0;
}
+EXPORT_SYMBOL_GPL(lpit_read_residency_count_address);
static void lpit_update_residency(struct lpit_residency_info *info,
struct acpi_lpit_native *lpit_native)
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 889abf9becd8..763145d74e83 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -421,8 +421,8 @@ int dvb_vb2_mmap(struct dvb_vb2_ctx *ctx, struct vm_area_struct *vma)
return 0;
}
-unsigned int dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
- poll_table *wait)
+__poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
+ poll_table *wait)
{
dprintk(3, "[%s]\n", ctx->name);
return vb2_core_poll(&ctx->vb_q, file, wait);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 7a3ebfd236f5..100adee778df 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -595,7 +595,7 @@ isr_done:
reissue_mask = 1 << 0;
if (!pdata->per_channel_irq)
- reissue_mask |= 0xffff < 4;
+ reissue_mask |= 0xffff << 4;
XP_IOWRITE(pdata, XP_INT_REISSUE_EN, reissue_mask);
}
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 8984c4938881..382891f81e09 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -248,6 +248,7 @@ struct be_tx_stats {
u32 tx_spoof_check_err;
u32 tx_qinq_err;
u32 tx_internal_parity_err;
+ u32 tx_sge_err;
struct u64_stats_sync sync;
struct u64_stats_sync sync_compl;
};
@@ -944,8 +945,10 @@ static inline bool is_ipv6_ext_hdr(struct sk_buff *skb)
#define BE_ERROR_EEH 1
#define BE_ERROR_UE BIT(1)
#define BE_ERROR_FW BIT(2)
-#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE)
-#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW)
+#define BE_ERROR_TX BIT(3)
+#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_TX)
+#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW | \
+ BE_ERROR_TX)
#define BE_CLEAR_ALL 0xFF
static inline u8 be_check_error(struct be_adapter *adapter, u32 err_type)
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 7d1819c9e8cc..7f7e206f95f8 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -189,6 +189,7 @@ static const struct be_ethtool_stat et_tx_stats[] = {
* packet data. This counter is applicable only for Lancer adapters.
*/
{DRVSTAT_TX_INFO(tx_internal_parity_err)},
+ {DRVSTAT_TX_INFO(tx_sge_err)},
{DRVSTAT_TX_INFO(tx_bytes)},
{DRVSTAT_TX_INFO(tx_pkts)},
{DRVSTAT_TX_INFO(tx_vxlan_offload_pkts)},
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index c967f45705d9..db5f92fb87e0 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -261,6 +261,7 @@ struct be_eth_hdr_wrb {
#define LANCER_TX_COMP_HSW_DROP_MAC_ERR 0x3
#define LANCER_TX_COMP_HSW_DROP_VLAN_ERR 0x5
#define LANCER_TX_COMP_QINQ_ERR 0x7
+#define LANCER_TX_COMP_SGE_ERR 0x9
#define LANCER_TX_COMP_PARITY_ERR 0xb
#define LANCER_TX_COMP_DMA_ERR 0xd
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index d81e2d37bc3d..5774fb6f8aa0 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2583,7 +2583,48 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp, u32 frags_needed)
}
}
-static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo)
+static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status)
+{
+ switch (status) {
+ case BE_TX_COMP_HDR_PARSE_ERR:
+ tx_stats(txo)->tx_hdr_parse_err++;
+ break;
+ case BE_TX_COMP_NDMA_ERR:
+ tx_stats(txo)->tx_dma_err++;
+ break;
+ case BE_TX_COMP_ACL_ERR:
+ tx_stats(txo)->tx_spoof_check_err++;
+ break;
+ }
+}
+
+static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status)
+{
+ switch (status) {
+ case LANCER_TX_COMP_LSO_ERR:
+ tx_stats(txo)->tx_tso_err++;
+ break;
+ case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
+ case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
+ tx_stats(txo)->tx_spoof_check_err++;
+ break;
+ case LANCER_TX_COMP_QINQ_ERR:
+ tx_stats(txo)->tx_qinq_err++;
+ break;
+ case LANCER_TX_COMP_PARITY_ERR:
+ tx_stats(txo)->tx_internal_parity_err++;
+ break;
+ case LANCER_TX_COMP_DMA_ERR:
+ tx_stats(txo)->tx_dma_err++;
+ break;
+ case LANCER_TX_COMP_SGE_ERR:
+ tx_stats(txo)->tx_sge_err++;
+ break;
+ }
+}
+
+static struct be_tx_compl_info *be_tx_compl_get(struct be_adapter *adapter,
+ struct be_tx_obj *txo)
{
struct be_queue_info *tx_cq = &txo->cq;
struct be_tx_compl_info *txcp = &txo->txcp;
@@ -2599,6 +2640,24 @@ static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo)
txcp->status = GET_TX_COMPL_BITS(status, compl);
txcp->end_index = GET_TX_COMPL_BITS(wrb_index, compl);
+ if (txcp->status) {
+ if (lancer_chip(adapter)) {
+ lancer_update_tx_err(txo, txcp->status);
+ /* Reset the adapter incase of TSO,
+ * SGE or Parity error
+ */
+ if (txcp->status == LANCER_TX_COMP_LSO_ERR ||
+ txcp->status == LANCER_TX_COMP_PARITY_ERR ||
+ txcp->status == LANCER_TX_COMP_SGE_ERR)
+ be_set_error(adapter, BE_ERROR_TX);
+ } else {
+ be_update_tx_err(txo, txcp->status);
+ }
+ }
+
+ if (be_check_error(adapter, BE_ERROR_TX))
+ return NULL;
+
compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
queue_tail_inc(tx_cq);
return txcp;
@@ -2741,7 +2800,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
cmpl = 0;
num_wrbs = 0;
txq = &txo->q;
- while ((txcp = be_tx_compl_get(txo))) {
+ while ((txcp = be_tx_compl_get(adapter, txo))) {
num_wrbs +=
be_tx_compl_process(adapter, txo,
txcp->end_index);
@@ -3120,42 +3179,6 @@ loop_continue:
return work_done;
}
-static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status)
-{
- switch (status) {
- case BE_TX_COMP_HDR_PARSE_ERR:
- tx_stats(txo)->tx_hdr_parse_err++;
- break;
- case BE_TX_COMP_NDMA_ERR:
- tx_stats(txo)->tx_dma_err++;
- break;
- case BE_TX_COMP_ACL_ERR:
- tx_stats(txo)->tx_spoof_check_err++;
- break;
- }
-}
-
-static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status)
-{
- switch (status) {
- case LANCER_TX_COMP_LSO_ERR:
- tx_stats(txo)->tx_tso_err++;
- break;
- case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
- case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
- tx_stats(txo)->tx_spoof_check_err++;
- break;
- case LANCER_TX_COMP_QINQ_ERR:
- tx_stats(txo)->tx_qinq_err++;
- break;
- case LANCER_TX_COMP_PARITY_ERR:
- tx_stats(txo)->tx_internal_parity_err++;
- break;
- case LANCER_TX_COMP_DMA_ERR:
- tx_stats(txo)->tx_dma_err++;
- break;
- }
-}
static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
int idx)
@@ -3163,16 +3186,9 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
int num_wrbs = 0, work_done = 0;
struct be_tx_compl_info *txcp;
- while ((txcp = be_tx_compl_get(txo))) {
+ while ((txcp = be_tx_compl_get(adapter, txo))) {
num_wrbs += be_tx_compl_process(adapter, txo, txcp->end_index);
work_done++;
-
- if (txcp->status) {
- if (lancer_chip(adapter))
- lancer_update_tx_err(txo, txcp->status);
- else
- be_update_tx_err(txo, txcp->status);
- }
}
if (work_done) {
@@ -5104,9 +5120,12 @@ static netdev_features_t be_features_check(struct sk_buff *skb,
features &= ~NETIF_F_TSO6;
/* Lancer cannot handle the packet with MSS less than 256.
+ * Also it can't handle a TSO packet with a single segment
* Disable the GSO support in such cases
*/
- if (lancer_chip(adapter) && skb_shinfo(skb)->gso_size < 256)
+ if (lancer_chip(adapter) &&
+ (skb_shinfo(skb)->gso_size < 256 ||
+ skb_shinfo(skb)->gso_segs == 1))
features &= ~NETIF_F_GSO_MASK;
}
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 5caaa9033841..afaf29b201dc 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -3286,7 +3286,7 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
- unsigned char *substr = NULL, *ptr = NULL;
+ unsigned char *substr = NULL;
u8 fw_level_len = 0;
memset(adapter->fw_version, 0, 32);
@@ -3306,10 +3306,6 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
if (!substr) {
dev_info(dev, "Warning - No FW level has been provided in the VPD buffer by the VIOS Server\n");
- ptr = strncpy((char *)adapter->fw_version, "N/A",
- 3 * sizeof(char));
- if (!ptr)
- dev_err(dev, "Failed to inform that firmware version is unavailable to the adapter\n");
goto complete;
}
@@ -3324,16 +3320,14 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
/* copy firmware version string from vpd into adapter */
if ((substr + 3 + fw_level_len) <
(adapter->vpd->buff + adapter->vpd->len)) {
- ptr = strncpy((char *)adapter->fw_version,
- substr + 3, fw_level_len);
-
- if (!ptr)
- dev_err(dev, "Failed to isolate FW level string\n");
+ strncpy((char *)adapter->fw_version, substr + 3, fw_level_len);
} else {
dev_info(dev, "FW substr extrapolated VPD buff\n");
}
complete:
+ if (adapter->fw_version[0] == '\0')
+ strncpy((char *)adapter->fw_version, "N/A", 3 * sizeof(char));
complete(&adapter->fw_done);
}
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index 424fe8338105..054df3dc0698 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -112,22 +112,22 @@ enum pkt_vec {
* @map_elems_in_use: number of elements allocated to offloaded maps
*
* @adjust_head: adjust head capability
- * @flags: extra flags for adjust head
- * @off_min: minimal packet offset within buffer required
- * @off_max: maximum packet offset within buffer required
- * @guaranteed_sub: amount of negative adjustment guaranteed possible
- * @guaranteed_add: amount of positive adjustment guaranteed possible
+ * @adjust_head.flags: extra flags for adjust head
+ * @adjust_head.off_min: minimal packet offset within buffer required
+ * @adjust_head.off_max: maximum packet offset within buffer required
+ * @adjust_head.guaranteed_sub: negative adjustment guaranteed possible
+ * @adjust_head.guaranteed_add: positive adjustment guaranteed possible
*
* @maps: map capability
- * @types: supported map types
- * @max_maps: max number of maps supported
- * @max_elems: max number of entries in each map
- * @max_key_sz: max size of map key
- * @max_val_sz: max size of map value
- * @max_elem_sz: max size of map entry (key + value)
+ * @maps.types: supported map types
+ * @maps.max_maps: max number of maps supported
+ * @maps.max_elems: max number of entries in each map
+ * @maps.max_key_sz: max size of map key
+ * @maps.max_val_sz: max size of map value
+ * @maps.max_elem_sz: max size of map entry (key + value)
*
* @helpers: helper addressess for various calls
- * @map_lookup: map lookup helper address
+ * @helpers.map_lookup: map lookup helper address
*/
struct nfp_app_bpf {
struct nfp_app *app;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index b03f22f29612..ec524d97869d 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -50,9 +50,9 @@
* @seq: sequence number of the message
* @count: number of tunnels report in message
* @flags: options part of the request
- * @ipv4: dest IPv4 address of active route
- * @egress_port: port the encapsulated packet egressed
- * @extra: reserved for future use
+ * @tun_info.ipv4: dest IPv4 address of active route
+ * @tun_info.egress_port: port the encapsulated packet egressed
+ * @tun_info.extra: reserved for future use
* @tun_info: tunnels that have sent traffic in reported period
*/
struct nfp_tun_active_tuns {
@@ -132,8 +132,8 @@ struct nfp_ipv4_addr_entry {
* struct nfp_tun_mac_addr - configure MAC address of tunnel EP on NFP
* @reserved: reserved for future use
* @count: number of MAC addresses in the message
- * @index: index of MAC address in the lookup table
- * @addr: interface MAC address
+ * @addresses.index: index of MAC address in the lookup table
+ * @addresses.addr: interface MAC address
* @addresses: series of MACs to offload
*/
struct nfp_tun_mac_addr {
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index d88eda9707e6..787df47ec430 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -193,7 +193,8 @@ struct nfp_net_tx_desc {
/**
* struct nfp_net_tx_buf - software TX buffer descriptor
- * @skb: sk_buff associated with this buffer
+ * @skb: normal ring, sk_buff associated with this buffer
+ * @frag: XDP ring, page frag associated with this buffer
* @dma_addr: DMA mapping address of the buffer
* @fidx: Fragment index (-1 for the head and [0..nr_frags-1] for frags)
* @pkt_cnt: Number of packets to be produced out of the skb associated
@@ -377,6 +378,9 @@ struct nfp_net_rx_ring {
* struct nfp_net_r_vector - Per ring interrupt vector configuration
* @nfp_net: Backpointer to nfp_net structure
* @napi: NAPI structure for this ring vec
+ * @tasklet: ctrl vNIC, tasklet for servicing the r_vec
+ * @queue: ctrl vNIC, send queue
+ * @lock: ctrl vNIC, r_vec lock protects @queue
* @tx_ring: Pointer to TX ring
* @rx_ring: Pointer to RX ring
* @xdp_ring: Pointer to an extra TX ring for XDP
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index e983c9d7f86c..f23d9e06f097 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -98,28 +98,29 @@ enum nfp_eth_fec {
* @max_index: max of @index fields of all @ports
* @ports: table of ports
*
- * @eth_index: port index according to legacy ethX numbering
- * @index: chip-wide first channel index
- * @nbi: NBI index
- * @base: first channel index (within NBI)
- * @lanes: number of channels
- * @speed: interface speed (in Mbps)
- * @interface: interface (module) plugged in
- * @media: media type of the @interface
- * @fec: forward error correction mode
- * @aneg: auto negotiation mode
- * @mac_addr: interface MAC address
- * @label_port: port id
- * @label_subport: id of interface within port (for split ports)
- * @enabled: is enabled?
- * @tx_enabled: is TX enabled?
- * @rx_enabled: is RX enabled?
- * @override_changed: is media reconfig pending?
+ * @ports.eth_index: port index according to legacy ethX numbering
+ * @ports.index: chip-wide first channel index
+ * @ports.nbi: NBI index
+ * @ports.base: first channel index (within NBI)
+ * @ports.lanes: number of channels
+ * @ports.speed: interface speed (in Mbps)
+ * @ports.interface: interface (module) plugged in
+ * @ports.media: media type of the @interface
+ * @ports.fec: forward error correction mode
+ * @ports.aneg: auto negotiation mode
+ * @ports.mac_addr: interface MAC address
+ * @ports.label_port: port id
+ * @ports.label_subport: id of interface within port (for split ports)
+ * @ports.enabled: is enabled?
+ * @ports.tx_enabled: is TX enabled?
+ * @ports.rx_enabled: is RX enabled?
+ * @ports.override_changed: is media reconfig pending?
*
- * @port_type: one of %PORT_* defines for ethtool
- * @port_lanes: total number of lanes on the port (sum of lanes of all subports)
- * @is_split: is interface part of a split port
- * @fec_modes_supported: bitmap of FEC modes supported
+ * @ports.port_type: one of %PORT_* defines for ethtool
+ * @ports.port_lanes: total number of lanes on the port (sum of lanes of all
+ * subports)
+ * @ports.is_split: is interface part of a split port
+ * @ports.fec_modes_supported: bitmap of FEC modes supported
*/
struct nfp_eth_table {
unsigned int count;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
index b1dd13ff282b..7e14725055c7 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
@@ -56,16 +56,17 @@
/**
* struct nfp_resource_entry - Resource table entry
- * @owner: NFP CPP Lock, interface owner
- * @key: NFP CPP Lock, posix_crc32(name, 8)
- * @region: Memory region descriptor
- * @name: ASCII, zero padded name
- * @reserved
- * @cpp_action: CPP Action
- * @cpp_token: CPP Token
- * @cpp_target: CPP Target ID
- * @page_offset: 256-byte page offset into target's CPP address
- * @page_size: size, in 256-byte pages
+ * @mutex: NFP CPP Lock
+ * @mutex.owner: NFP CPP Lock, interface owner
+ * @mutex.key: NFP CPP Lock, posix_crc32(name, 8)
+ * @region: Memory region descriptor
+ * @region.name: ASCII, zero padded name
+ * @region.reserved: padding
+ * @region.cpp_action: CPP Action
+ * @region.cpp_token: CPP Token
+ * @region.cpp_target: CPP Target ID
+ * @region.page_offset: 256-byte page offset into target's CPP address
+ * @region.page_size: size, in 256-byte pages
*/
struct nfp_resource_entry {
struct nfp_resource_entry_mutex {
diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c
index de73c1ff0939..75c25306d234 100644
--- a/drivers/net/netdevsim/bpf.c
+++ b/drivers/net/netdevsim/bpf.c
@@ -480,8 +480,7 @@ static int
nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
{
struct nsim_bpf_bound_map *nmap;
- unsigned int i;
- int err;
+ int i, err;
if (WARN_ON(offmap->map.map_type != BPF_MAP_TYPE_ARRAY &&
offmap->map.map_type != BPF_MAP_TYPE_HASH))
@@ -518,7 +517,7 @@ nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
return 0;
err_free:
- while (--i) {
+ while (--i >= 0) {
kfree(nmap->entry[i].key);
kfree(nmap->entry[i].value);
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 88272b3ac2e2..24b5511222c8 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -56,7 +56,8 @@ static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
"reset-gpios", 0, GPIOD_OUT_LOW,
"PHY reset");
- if (PTR_ERR(gpiod) == -ENOENT)
+ if (PTR_ERR(gpiod) == -ENOENT ||
+ PTR_ERR(gpiod) == -ENOSYS)
gpiod = NULL;
else if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index c11db8bceea1..d4c2e424a700 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -8,3 +8,5 @@ endif
source "drivers/platform/goldfish/Kconfig"
source "drivers/platform/chrome/Kconfig"
+
+source "drivers/platform/mellanox/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index d3a6630266a0..4b2ce58bcd9c 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_X86) += x86/
+obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/
obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
new file mode 100644
index 000000000000..591bccdeaff9
--- /dev/null
+++ b/drivers/platform/mellanox/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Platform support for Mellanox hardware
+#
+
+menuconfig MELLANOX_PLATFORM
+ bool "Platform support for Mellanox hardware"
+ depends on X86 || ARM || COMPILE_TEST
+ ---help---
+ Say Y here to get to see options for platform support for
+ Mellanox systems. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if MELLANOX_PLATFORM
+
+config MLXREG_HOTPLUG
+ tristate "Mellanox platform hotplug driver support"
+ depends on REGMAP
+ depends on HWMON
+ depends on I2C
+ ---help---
+ This driver handles hot-plug events for the power suppliers, power
+ cables and fans on the wide range Mellanox IB and Ethernet systems.
+
+endif # MELLANOX_PLATFORM
diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
new file mode 100644
index 000000000000..7c8385e497a8
--- /dev/null
+++ b/drivers/platform/mellanox/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for linux/drivers/platform/mellanox
+# Mellanox Platform-Specific Drivers
+#
+obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
new file mode 100644
index 000000000000..0dfa1ca0d05b
--- /dev/null
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+
+/* Offset of event and mask registers from status register. */
+#define MLXREG_HOTPLUG_EVENT_OFF 1
+#define MLXREG_HOTPLUG_MASK_OFF 2
+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
+
+/* ASIC health parameters. */
+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
+#define MLXREG_HOTPLUG_RST_CNTR 3
+
+#define MLXREG_HOTPLUG_ATTRS_MAX 24
+
+/**
+ * struct mlxreg_hotplug_priv_data - platform private data:
+ * @irq: platform device interrupt number;
+ * @pdev: platform device;
+ * @plat: platform data;
+ * @dwork: delayed work template;
+ * @lock: spin lock;
+ * @hwmon: hwmon device;
+ * @mlxreg_hotplug_attr: sysfs attributes array;
+ * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
+ * @group: sysfs attribute group;
+ * @groups: list of sysfs attribute group for hwmon registration;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
+ * @aggr_cache: last value of aggregation register status;
+ */
+struct mlxreg_hotplug_priv_data {
+ int irq;
+ struct device *dev;
+ struct platform_device *pdev;
+ struct mlxreg_hotplug_platform_data *plat;
+ struct regmap *regmap;
+ struct delayed_work dwork_irq;
+ struct delayed_work dwork;
+ spinlock_t lock; /* sync with interrupt */
+ struct device *hwmon;
+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
+ struct sensor_device_attribute_2
+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
+ struct attribute_group group;
+ const struct attribute_group *groups[2];
+ u32 cell;
+ u32 mask;
+ u32 aggr_cache;
+ bool after_probe;
+};
+
+static int mlxreg_hotplug_device_create(struct device *dev,
+ struct mlxreg_core_data *data)
+{
+ /*
+ * Return if adapter number is negative. It could be in case hotplug
+ * event is not associated with hotplug device.
+ */
+ if (data->hpdev.nr < 0)
+ return 0;
+
+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
+ if (!data->hpdev.adapter) {
+ dev_err(dev, "Failed to get adapter for bus %d\n",
+ data->hpdev.nr);
+ return -EFAULT;
+ }
+
+ data->hpdev.client = i2c_new_device(data->hpdev.adapter,
+ data->hpdev.brdinfo);
+ if (!data->hpdev.client) {
+ dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
+ data->hpdev.brdinfo->type, data->hpdev.nr,
+ data->hpdev.brdinfo->addr);
+
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
+{
+ if (data->hpdev.client) {
+ i2c_unregister_device(data->hpdev.client);
+ data->hpdev.client = NULL;
+ }
+
+ if (data->hpdev.adapter) {
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
+ }
+}
+
+static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ u32 regval;
+ int ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items + nr;
+ data = item->data + index;
+
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ return ret;
+
+ if (item->health) {
+ regval &= data->mask;
+ } else {
+ /* Bit = 0 : functional if item->inversed is true. */
+ if (item->inversed)
+ regval = !(regval & data->mask);
+ else
+ regval = !!(regval & data->mask);
+ }
+
+ return sprintf(buf, "%u\n", regval);
+}
+
+#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
+#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
+
+static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int num_attrs = 0, id = 0, i, j;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ /* Go over all kinds of items - psu, pwr, fan. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ num_attrs += item->count;
+ data = item->data;
+ /* Go over all units within the item. */
+ for (j = 0; j < item->count; j++, data++, id++) {
+ PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
+ PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
+ GFP_KERNEL,
+ data->label);
+
+ if (!PRIV_ATTR(id)->name) {
+ dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
+ id);
+ return -ENOMEM;
+ }
+
+ PRIV_DEV_ATTR(id).dev_attr.attr.name =
+ PRIV_ATTR(id)->name;
+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
+ PRIV_DEV_ATTR(id).dev_attr.show =
+ mlxreg_hotplug_attr_show;
+ PRIV_DEV_ATTR(id).nr = i;
+ PRIV_DEV_ATTR(id).index = j;
+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
+ }
+ }
+
+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
+ sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!priv->group.attrs)
+ return -ENOMEM;
+
+ priv->group.attrs = priv->mlxreg_hotplug_attr;
+ priv->groups[0] = &priv->group;
+ priv->groups[1] = NULL;
+
+ return 0;
+}
+
+static void
+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
+{
+ struct mlxreg_core_data *data;
+ u32 asserted, regval, bit;
+ int ret;
+
+ /*
+ * Validate if item related to received signal type is valid.
+ * It should never happen, excepted the situation when some
+ * piece of hardware is broken. In such situation just produce
+ * error message and return. Caller must continue to handle the
+ * signals from other devices if any.
+ */
+ if (unlikely(!item)) {
+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
+ item->reg, item->mask);
+
+ return;
+ }
+
+ /* Mask event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ if (ret)
+ goto out;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, item->reg, &regval);
+ if (ret)
+ goto out;
+
+ /* Set asserted bits and save last status. */
+ regval &= item->mask;
+ asserted = item->cache ^ regval;
+ item->cache = regval;
+
+ for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
+ data = item->data + bit;
+ if (regval & BIT(bit)) {
+ if (item->inversed)
+ mlxreg_hotplug_device_destroy(data);
+ else
+ mlxreg_hotplug_device_create(priv->dev, data);
+ } else {
+ if (item->inversed)
+ mlxreg_hotplug_device_create(priv->dev, data);
+ else
+ mlxreg_hotplug_device_destroy(data);
+ }
+ }
+
+ /* Acknowledge event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
+ 0);
+ if (ret)
+ goto out;
+
+ /* Unmask event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+static void
+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
+{
+ struct mlxreg_core_data *data = item->data;
+ u32 regval;
+ int i, ret;
+
+ for (i = 0; i < item->count; i++, data++) {
+ /* Mask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ goto out;
+
+ regval &= data->mask;
+ item->cache = regval;
+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
+ !priv->after_probe) {
+ mlxreg_hotplug_device_create(priv->dev, data);
+ data->attached = true;
+ }
+ } else {
+ if (data->attached) {
+ mlxreg_hotplug_device_destroy(data);
+ data->attached = false;
+ data->health_cntr = 0;
+ }
+ }
+
+ /* Acknowledge event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Unmask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, data->mask);
+ if (ret)
+ goto out;
+ }
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+/*
+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt
+ * registers according to the below hierarchy schema:
+ *
+ * Aggregation registers (status/mask)
+ * PSU registers: *---*
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * Power registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * FAN registers: | |--> CPU
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * ASIC registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * *---*
+ *
+ * In case some system changed are detected: FAN in/out, PSU in/out, power
+ * cable attached/detached, ASIC health good/bad, relevant device is created
+ * or destroyed.
+ */
+static void mlxreg_hotplug_work_handler(struct work_struct *work)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_hotplug_priv_data *priv;
+ struct mlxreg_core_item *item;
+ u32 regval, aggr_asserted;
+ unsigned long flags;
+ int i, ret;
+
+ priv = container_of(work, struct mlxreg_hotplug_priv_data,
+ dwork_irq.work);
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ /* Mask aggregation event. */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+ if (ret < 0)
+ goto out;
+
+ /* Read aggregation status. */
+ ret = regmap_read(priv->regmap, pdata->cell, &regval);
+ if (ret)
+ goto out;
+
+ regval &= pdata->mask;
+ aggr_asserted = priv->aggr_cache ^ regval;
+ priv->aggr_cache = regval;
+
+ /* Handle topology and health configuration changes. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ if (aggr_asserted & item->aggr_mask) {
+ if (item->health)
+ mlxreg_hotplug_health_work_helper(priv, item);
+ else
+ mlxreg_hotplug_work_helper(priv, item);
+ }
+ }
+
+ if (aggr_asserted) {
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /*
+ * It is possible, that some signals have been inserted, while
+ * interrupt has been masked by mlxreg_hotplug_work_handler.
+ * In this case such signals will be missed. In order to handle
+ * these signals delayed work is canceled and work task
+ * re-scheduled for immediate execution. It allows to handle
+ * missed signals, if any. In other case work handler just
+ * validates that no new signals have been received during
+ * masking.
+ */
+ cancel_delayed_work(&priv->dwork_irq);
+ schedule_delayed_work(&priv->dwork_irq, 0);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+ /* Unmask aggregation event (no need acknowledge). */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ int i, ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ for (i = 0; i < pdata->counter; i++, item++) {
+ /* Clear group presense event. */
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Set group initial status as mask and unmask group event. */
+ if (item->inversed) {
+ item->cache = item->mask;
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+ if (ret)
+ goto out;
+ }
+ }
+
+ /* Keep aggregation initial status as zero and unmask events. */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+ if (ret)
+ goto out;
+
+ /* Keep low aggregation initial status as zero and unmask events. */
+ if (pdata->cell_low) {
+ ret = regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ pdata->mask_low);
+ if (ret)
+ goto out;
+ }
+
+ /* Invoke work handler for initializing hot plug devices setting. */
+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to set interrupts.\n");
+ enable_irq(priv->irq);
+ return ret;
+}
+
+static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int count, i, j;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+ disable_irq(priv->irq);
+ cancel_delayed_work_sync(&priv->dwork_irq);
+
+ /* Mask low aggregation event, if defined. */
+ if (pdata->cell_low)
+ regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+
+ /* Mask aggregation event. */
+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ 0);
+
+ /* Clear topology configurations. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ data = item->data;
+ /* Mask group presense event. */
+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ /* Clear group presense event. */
+ regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+
+ /* Remove all the attached devices in group. */
+ count = item->count;
+ for (j = 0; j < count; j++, data++)
+ mlxreg_hotplug_device_destroy(data);
+ }
+}
+
+static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
+{
+ struct mlxreg_hotplug_priv_data *priv;
+
+ priv = (struct mlxreg_hotplug_priv_data *)dev;
+
+ /* Schedule work task for immediate execution.*/
+ schedule_delayed_work(&priv->dwork_irq, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int mlxreg_hotplug_probe(struct platform_device *pdev)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_hotplug_priv_data *priv;
+ int err;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (pdata->irq) {
+ priv->irq = pdata->irq;
+ } else {
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+ priv->irq);
+ return priv->irq;
+ }
+ }
+
+ priv->regmap = pdata->regmap;
+ priv->dev = pdev->dev.parent;
+ priv->pdev = pdev;
+
+ err = devm_request_irq(&pdev->dev, priv->irq,
+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
+ | IRQF_SHARED, "mlxreg-hotplug", priv);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
+ return err;
+ }
+
+ disable_irq(priv->irq);
+ spin_lock_init(&priv->lock);
+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
+ /* Perform initial interrupts setup. */
+ mlxreg_hotplug_set_irq(priv);
+
+ priv->after_probe = true;
+ dev_set_drvdata(&pdev->dev, priv);
+
+ err = mlxreg_hotplug_attr_init(priv);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
+ err);
+ return err;
+ }
+
+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
+ "mlxreg_hotplug", priv, priv->groups);
+ if (IS_ERR(priv->hwmon)) {
+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
+ PTR_ERR(priv->hwmon));
+ return PTR_ERR(priv->hwmon);
+ }
+
+ return 0;
+}
+
+static int mlxreg_hotplug_remove(struct platform_device *pdev)
+{
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
+
+ /* Clean interrupts setup. */
+ mlxreg_hotplug_unset_irq(priv);
+
+ return 0;
+}
+
+static struct platform_driver mlxreg_hotplug_driver = {
+ .driver = {
+ .name = "mlxreg-hotplug",
+ },
+ .probe = mlxreg_hotplug_probe,
+ .remove = mlxreg_hotplug_remove,
+};
+
+module_platform_driver(mlxreg_hotplug_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:mlxreg-hotplug");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2c745e8ccad6..9a8f96465cdc 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -36,6 +36,20 @@ config ACER_WMI
If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
here.
+config ACER_WIRELESS
+ tristate "Acer Wireless Radio Control Driver"
+ depends on ACPI
+ depends on INPUT
+ ---help---
+ The Acer Wireless Radio Control handles the airplane mode hotkey
+ present on new Acer laptops.
+
+ Say Y or M here if you have an Acer notebook with an airplane mode
+ hotkey.
+
+ If you choose to compile this driver as a module the module will be
+ called acer-wireless.
+
config ACERHDF
tristate "Acer Aspire One temperature and fan driver"
depends on ACPI && THERMAL
@@ -244,6 +258,18 @@ config AMILO_RFKILL
This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
laptops.
+config GPD_POCKET_FAN
+ tristate "GPD Pocket Fan Controller support"
+ depends on ACPI
+ depends on THERMAL
+ ---help---
+ Driver for the GPD Pocket vendor specific FAN02501 ACPI device
+ which controls the fan speed on the GPD Pocket.
+
+ Without this driver the fan on the Pocket will stay off independent
+ of the CPU temperature. Say Y or M if the kernel may be used on a
+ GPD pocket.
+
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras"
depends on !X86_64
@@ -812,9 +838,8 @@ config TOSHIBA_WMI
config ACPI_CMPC
tristate "CMPC Laptop Extras"
- depends on ACPI
+ depends on ACPI && INPUT
depends on RFKILL || RFKILL=n
- select INPUT
select BACKLIGHT_CLASS_DEVICE
help
Support for Intel Classmate PC ACPI devices, including some
@@ -949,7 +974,7 @@ config INTEL_IMR
If you are running on a Galileo/Quark say Y here.
config INTEL_PMC_CORE
- bool "Intel PMC Core driver"
+ tristate "Intel PMC Core driver"
depends on PCI
---help---
The Intel Platform Controller Hub for Intel Core SoCs provides access
@@ -958,7 +983,10 @@ config INTEL_PMC_CORE
exposed by the Power Management Controller.
Supported features:
- - SLP_S0_RESIDENCY counter.
+ - SLP_S0_RESIDENCY counter
+ - PCH IP Power Gating status
+ - LTR Ignore
+ - MPHY/PLL gating status (Sunrisepoint PCH only)
config IBM_RTL
tristate "Device driver to enable PRTL support"
@@ -1131,7 +1159,6 @@ config INTEL_TELEMETRY
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
- depends on X86_64
---help---
This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking
@@ -1141,14 +1168,6 @@ config MLX_PLATFORM
If you have a Mellanox system, say Y or M here.
-config MLX_CPLD_PLATFORM
- tristate "Mellanox platform hotplug driver support"
- select HWMON
- select I2C
- ---help---
- This driver handles hot-plug events for the power suppliers, power
- cables and fans on the wide range Mellanox IB and Ethernet systems.
-
config INTEL_TURBO_MAX_3
bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
depends on X86_64 && SCHED_MC_PRIO
@@ -1170,6 +1189,17 @@ config SILEAD_DMI
with the OS-image for the device. This option supplies the missing
information. Enable this for x86 tablets with Silead touchscreens.
+config INTEL_CHTDC_TI_PWRBTN
+ tristate "Intel Cherry Trail Dollar Cove TI power button driver"
+ depends on INTEL_SOC_PMIC_CHTDC_TI
+ depends on INPUT
+ ---help---
+ This option adds a power button driver driver for Dollar Cove TI
+ PMIC on Intel Cherry Trail devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called intel_chtdc_ti_pwrbtn.
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index c32b34a72467..c388608ad2a3 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -23,11 +23,13 @@ obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
+obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
+obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
@@ -86,5 +88,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
-obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
+obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c
new file mode 100644
index 000000000000..858037987b33
--- /dev/null
+++ b/drivers/platform/x86/acer-wireless.c
@@ -0,0 +1,71 @@
+/*
+ * Acer Wireless Radio Control Driver
+ *
+ * Copyright (C) 2017 Endless Mobile, 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 <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci_ids.h>
+#include <linux/types.h>
+
+static const struct acpi_device_id acer_wireless_acpi_ids[] = {
+ {"10251229", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids);
+
+static void acer_wireless_notify(struct acpi_device *adev, u32 event)
+{
+ struct input_dev *idev = acpi_driver_data(adev);
+
+ dev_dbg(&adev->dev, "event=%#x\n", event);
+ if (event != 0x80) {
+ dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event);
+ return;
+ }
+ input_report_key(idev, KEY_RFKILL, 1);
+ input_report_key(idev, KEY_RFKILL, 0);
+ input_sync(idev);
+}
+
+static int acer_wireless_add(struct acpi_device *adev)
+{
+ struct input_dev *idev;
+
+ idev = devm_input_allocate_device(&adev->dev);
+ if (!idev)
+ return -ENOMEM;
+
+ adev->driver_data = idev;
+ idev->name = "Acer Wireless Radio Control";
+ idev->phys = "acer-wireless/input0";
+ idev->id.bustype = BUS_HOST;
+ idev->id.vendor = PCI_VENDOR_ID_AI;
+ idev->id.product = 0x1229;
+ set_bit(EV_KEY, idev->evbit);
+ set_bit(KEY_RFKILL, idev->keybit);
+
+ return input_register_device(idev);
+}
+
+static struct acpi_driver acer_wireless_driver = {
+ .name = "Acer Wireless Radio Control Driver",
+ .class = "hotkey",
+ .ids = acer_wireless_acpi_ids,
+ .ops = {
+ .add = acer_wireless_add,
+ .notify = acer_wireless_notify,
+ },
+};
+module_acpi_driver(acer_wireless_driver);
+
+MODULE_DESCRIPTION("Acer Wireless Radio Control Driver");
+MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c
index 4eb8e1a472b2..9d7dbd925065 100644
--- a/drivers/platform/x86/alienware-wmi.c
+++ b/drivers/platform/x86/alienware-wmi.c
@@ -68,6 +68,14 @@ struct quirk_entry {
static struct quirk_entry *quirks;
+
+static struct quirk_entry quirk_inspiron5675 = {
+ .num_zones = 2,
+ .hdmi_mux = 0,
+ .amplifier = 0,
+ .deepslp = 0,
+};
+
static struct quirk_entry quirk_unknown = {
.num_zones = 2,
.hdmi_mux = 0,
@@ -171,6 +179,15 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
},
.driver_data = &quirk_asm201,
},
+ {
+ .callback = dmi_matched,
+ .ident = "Dell Inc. Inspiron 5675",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
+ },
+ .driver_data = &quirk_inspiron5675,
+ },
{}
};
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 623d322447a2..7c4eb86c851e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -24,7 +24,6 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
-#include <linux/vgaarb.h>
#include <acpi/video.h>
#include <asm/io.h>
@@ -54,7 +53,6 @@ struct apple_gmux_data {
bool indexed;
struct mutex index_lock;
- struct pci_dev *pdev;
struct backlight_device *bdev;
/* switcheroo data */
@@ -599,23 +597,6 @@ static int gmux_resume(struct device *dev)
return 0;
}
-static struct pci_dev *gmux_get_io_pdev(void)
-{
- struct pci_dev *pdev = NULL;
-
- while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) {
- u16 cmd;
-
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- if (!(cmd & PCI_COMMAND_IO))
- continue;
-
- return pdev;
- }
-
- return NULL;
-}
-
static int is_thunderbolt(struct device *dev, void *data)
{
return to_pci_dev(dev)->is_thunderbolt;
@@ -631,7 +612,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
int ret = -ENXIO;
acpi_status status;
unsigned long long gpe;
- struct pci_dev *pdev = NULL;
if (apple_gmux_data)
return -EBUSY;
@@ -682,7 +662,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
ver_minor = (version >> 16) & 0xff;
ver_release = (version >> 8) & 0xff;
} else {
- pr_info("gmux device not present or IO disabled\n");
+ pr_info("gmux device not present\n");
ret = -ENODEV;
goto err_release;
}
@@ -690,23 +670,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
ver_release, (gmux_data->indexed ? "indexed" : "classic"));
- /*
- * Apple systems with gmux are EFI based and normally don't use
- * VGA. In addition changing IO+MEM ownership between IGP and dGPU
- * disables IO/MEM used for backlight control on some systems.
- * Lock IO+MEM to GPU with active IO to prevent switch.
- */
- pdev = gmux_get_io_pdev();
- if (pdev && vga_tryget(pdev,
- VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) {
- pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n",
- pci_name(pdev));
- ret = -EBUSY;
- goto err_release;
- } else if (pdev)
- pr_info("locked IO for PCI:%s\n", pci_name(pdev));
- gmux_data->pdev = pdev;
-
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
@@ -822,10 +785,6 @@ err_enable_gpe:
err_notify:
backlight_device_unregister(bdev);
err_release:
- if (gmux_data->pdev)
- vga_put(gmux_data->pdev,
- VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
- pci_dev_put(pdev);
release_region(gmux_data->iostart, gmux_data->iolen);
err_free:
kfree(gmux_data);
@@ -845,11 +804,6 @@ static void gmux_remove(struct pnp_dev *pnp)
&gmux_notify_handler);
}
- if (gmux_data->pdev) {
- vga_put(gmux_data->pdev,
- VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
- pci_dev_put(gmux_data->pdev);
- }
backlight_device_unregister(gmux_data->bdev);
release_region(gmux_data->iostart, gmux_data->iolen);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 5269a01d9bdd..136ff2b4cce5 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -111,7 +111,7 @@ static struct quirk_entry quirk_asus_x550lb = {
.xusb2pr = 0x01D9,
};
-static struct quirk_entry quirk_asus_ux330uak = {
+static struct quirk_entry quirk_asus_forceals = {
.wmi_force_als_set = true,
};
@@ -387,7 +387,7 @@ static const struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
},
- .driver_data = &quirk_asus_ux330uak,
+ .driver_data = &quirk_asus_forceals,
},
{
.callback = dmi_matched,
@@ -398,6 +398,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_x550lb,
},
+ {
+ .callback = dmi_matched,
+ .ident = "ASUSTeK COMPUTER INC. UX430UQ",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"),
+ },
+ .driver_data = &quirk_asus_forceals,
+ },
{},
};
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index cd4725e7e0b5..a7b141992cb3 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -36,10 +36,10 @@
#include "dell-smbios.h"
struct quirk_entry {
- u8 touchpad_led;
- u8 kbd_led_levels_off_1;
+ bool touchpad_led;
+ bool kbd_led_levels_off_1;
- int needs_kbd_timeouts;
+ bool needs_kbd_timeouts;
/*
* Ordered list of timeouts expressed in seconds.
* The list must end with -1
@@ -50,7 +50,7 @@ struct quirk_entry {
static struct quirk_entry *quirks;
static struct quirk_entry quirk_dell_vostro_v130 = {
- .touchpad_led = 1,
+ .touchpad_led = true,
};
static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -64,12 +64,12 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
* is used then BIOS silently set timeout to 0 without any error message.
*/
static struct quirk_entry quirk_dell_xps13_9333 = {
- .needs_kbd_timeouts = 1,
+ .needs_kbd_timeouts = true,
.kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
};
static struct quirk_entry quirk_dell_latitude_e6410 = {
- .kbd_led_levels_off_1 = 1,
+ .kbd_led_levels_off_1 = true,
};
static struct platform_driver platform_driver = {
@@ -78,7 +78,6 @@ 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;
@@ -110,6 +109,42 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
},
},
{
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
+ },
+ },
+ {
.ident = "Dell Computer Corporation",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -286,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
{ }
};
-void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
+static void dell_fill_request(struct calling_interface_buffer *buffer,
+ u32 arg0, u32 arg1, u32 arg2, u32 arg3)
{
memset(buffer, 0, sizeof(struct calling_interface_buffer));
buffer->input[0] = arg0;
@@ -295,7 +331,8 @@ void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
buffer->input[3] = arg3;
}
-int dell_send_request(u16 class, u16 select)
+static int dell_send_request(struct calling_interface_buffer *buffer,
+ u16 class, u16 select)
{
int ret;
@@ -432,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked)
int disable = blocked ? 1 : 0;
unsigned long radio = (unsigned long)data;
int hwswitch_bit = (unsigned long)data - 1;
+ struct calling_interface_buffer buffer;
int hwswitch;
int status;
int ret;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (ret)
return ret;
- status = buffer->output[1];
+ status = buffer.output[1];
- dell_set_arguments(0x2, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 0x2, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (ret)
return ret;
- hwswitch = buffer->output[1];
+ hwswitch = buffer.output[1];
/* If the hardware switch controls this radio, and the hardware
switch is disabled, always disable the radio */
@@ -454,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked)
(status & BIT(0)) && !(status & BIT(16)))
disable = 1;
- dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
return ret;
}
@@ -464,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
{
if (status & BIT(0)) {
/* Has hw-switch, sync sw_state to BIOS */
+ struct calling_interface_buffer buffer;
int block = rfkill_blocked(rfkill);
- dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0);
- dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer,
+ 1 | (radio << 8) | (block << 16), 0, 0, 0);
+ dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
} else {
/* No hw-switch, sync BIOS state to sw_state */
rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
@@ -483,21 +523,22 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
int radio = ((unsigned long)data & 0xF);
+ struct calling_interface_buffer buffer;
int hwswitch;
int status;
int ret;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
- status = buffer->output[1];
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
+ status = buffer.output[1];
if (ret != 0 || !(status & BIT(0))) {
return;
}
- dell_set_arguments(0, 0x2, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
- hwswitch = buffer->output[1];
+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
+ hwswitch = buffer.output[1];
if (ret != 0)
return;
@@ -514,22 +555,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;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (ret)
return ret;
- status = buffer->output[1];
+ status = buffer.output[1];
- dell_set_arguments(0, 0x2, 0, 0);
- hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
+ hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (hwswitch_ret)
return hwswitch_ret;
- hwswitch_state = buffer->output[1];
+ hwswitch_state = buffer.output[1];
seq_printf(s, "return:\t%d\n", ret);
seq_printf(s, "status:\t0x%X\n", status);
@@ -610,22 +652,23 @@ 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;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
- status = buffer->output[1];
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
+ status = buffer.output[1];
if (ret != 0)
return;
- dell_set_arguments(0, 0x2, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (ret == 0 && (status & BIT(0)))
- hwswitch = buffer->output[1];
+ hwswitch = buffer.output[1];
if (wifi_rfkill) {
dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
@@ -683,6 +726,7 @@ 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;
@@ -698,9 +742,9 @@ static int __init dell_setup_rfkill(void)
if (!force_rfkill && !whitelisted)
return 0;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
- status = buffer->output[1];
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
+ status = buffer.output[1];
/* dell wireless info smbios call is not supported */
if (ret != 0)
@@ -853,6 +897,7 @@ 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;
@@ -860,17 +905,21 @@ static int dell_send_intensity(struct backlight_device *bd)
if (!token)
return -ENODEV;
- dell_set_arguments(token->location, bd->props.brightness, 0, 0);
+ dell_fill_request(&buffer,
+ token->location, bd->props.brightness, 0, 0);
if (power_supply_is_system_supplied() > 0)
- ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
+ ret = dell_send_request(&buffer,
+ CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
else
- ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
+ ret = dell_send_request(&buffer,
+ CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
return ret;
}
static int dell_get_intensity(struct backlight_device *bd)
{
+ struct calling_interface_buffer buffer;
struct calling_interface_token *token;
int ret;
@@ -878,14 +927,17 @@ static int dell_get_intensity(struct backlight_device *bd)
if (!token)
return -ENODEV;
- dell_set_arguments(token->location, 0, 0, 0);
+ dell_fill_request(&buffer, token->location, 0, 0, 0);
if (power_supply_is_system_supplied() > 0)
- ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
+ ret = dell_send_request(&buffer,
+ CLASS_TOKEN_READ, SELECT_TOKEN_AC);
else
- ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
+ ret = dell_send_request(&buffer,
+ CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
if (ret == 0)
- ret = buffer->output[1];
+ ret = buffer.output[1];
+
return ret;
}
@@ -1133,6 +1185,7 @@ static u8 kbd_previous_mode_bit;
static bool kbd_led_present;
static DEFINE_MUTEX(kbd_led_mutex);
+static enum led_brightness kbd_led_level;
/*
* NOTE: there are three ways to set the keyboard backlight level.
@@ -1149,31 +1202,33 @@ static DEFINE_MUTEX(kbd_led_mutex);
static int kbd_get_info(struct kbd_info *info)
{
+ struct calling_interface_buffer buffer;
u8 units;
int ret;
- dell_set_arguments(0, 0, 0, 0);
- ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer,
+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
if (ret)
return ret;
- info->modes = buffer->output[1] & 0xFFFF;
- info->type = (buffer->output[1] >> 24) & 0xFF;
- info->triggers = buffer->output[2] & 0xFF;
- units = (buffer->output[2] >> 8) & 0xFF;
- info->levels = (buffer->output[2] >> 16) & 0xFF;
+ info->modes = buffer.output[1] & 0xFFFF;
+ info->type = (buffer.output[1] >> 24) & 0xFF;
+ info->triggers = buffer.output[2] & 0xFF;
+ units = (buffer.output[2] >> 8) & 0xFF;
+ info->levels = (buffer.output[2] >> 16) & 0xFF;
if (quirks && quirks->kbd_led_levels_off_1 && info->levels)
info->levels--;
if (units & BIT(0))
- info->seconds = (buffer->output[3] >> 0) & 0xFF;
+ info->seconds = (buffer.output[3] >> 0) & 0xFF;
if (units & BIT(1))
- info->minutes = (buffer->output[3] >> 8) & 0xFF;
+ info->minutes = (buffer.output[3] >> 8) & 0xFF;
if (units & BIT(2))
- info->hours = (buffer->output[3] >> 16) & 0xFF;
+ info->hours = (buffer.output[3] >> 16) & 0xFF;
if (units & BIT(3))
- info->days = (buffer->output[3] >> 24) & 0xFF;
+ info->days = (buffer.output[3] >> 24) & 0xFF;
return ret;
}
@@ -1233,31 +1288,34 @@ 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;
- dell_set_arguments(0x1, 0, 0, 0);
- ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
+ dell_fill_request(&buffer, 0, 0, 0, 0);
+ ret = dell_send_request(&buffer,
+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
if (ret)
return ret;
- state->mode_bit = ffs(buffer->output[1] & 0xFFFF);
+ state->mode_bit = ffs(buffer.output[1] & 0xFFFF);
if (state->mode_bit != 0)
state->mode_bit--;
- state->triggers = (buffer->output[1] >> 16) & 0xFF;
- state->timeout_value = (buffer->output[1] >> 24) & 0x3F;
- state->timeout_unit = (buffer->output[1] >> 30) & 0x3;
- state->als_setting = buffer->output[2] & 0xFF;
- state->als_value = (buffer->output[2] >> 8) & 0xFF;
- state->level = (buffer->output[2] >> 16) & 0xFF;
- state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F;
- state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3;
+ state->triggers = (buffer.output[1] >> 16) & 0xFF;
+ state->timeout_value = (buffer.output[1] >> 24) & 0x3F;
+ state->timeout_unit = (buffer.output[1] >> 30) & 0x3;
+ state->als_setting = buffer.output[2] & 0xFF;
+ state->als_value = (buffer.output[2] >> 8) & 0xFF;
+ state->level = (buffer.output[2] >> 16) & 0xFF;
+ state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F;
+ state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3;
return ret;
}
static int kbd_set_state(struct kbd_state *state)
{
+ struct calling_interface_buffer buffer;
int ret;
u32 input1;
u32 input2;
@@ -1270,8 +1328,9 @@ static int kbd_set_state(struct kbd_state *state)
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);
+ dell_fill_request(&buffer, 0x2, input1, input2, 0);
+ ret = dell_send_request(&buffer,
+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
return ret;
}
@@ -1298,6 +1357,7 @@ 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;
@@ -1308,14 +1368,15 @@ static int kbd_set_token_bit(u8 bit)
if (!token)
return -EINVAL;
- dell_set_arguments(token->location, token->value, 0, 0);
- ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
+ dell_fill_request(&buffer, token->location, token->value, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
return ret;
}
static int kbd_get_token_bit(u8 bit)
{
+ struct calling_interface_buffer buffer;
struct calling_interface_token *token;
int ret;
int val;
@@ -1327,9 +1388,9 @@ static int kbd_get_token_bit(u8 bit)
if (!token)
return -EINVAL;
- dell_set_arguments(token->location, 0, 0, 0);
- ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD);
- val = buffer->output[1];
+ dell_fill_request(&buffer, token->location, 0, 0, 0);
+ ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD);
+ val = buffer.output[1];
if (ret)
return ret;
@@ -1947,6 +2008,7 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
static int kbd_led_level_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
+ enum led_brightness new_value = value;
struct kbd_state state;
struct kbd_state new_state;
u16 num;
@@ -1976,6 +2038,9 @@ static int kbd_led_level_set(struct led_classdev *led_cdev,
}
out:
+ if (ret == 0)
+ kbd_led_level = new_value;
+
mutex_unlock(&kbd_led_mutex);
return ret;
}
@@ -2003,6 +2068,9 @@ static int __init kbd_led_init(struct device *dev)
if (kbd_led.max_brightness)
kbd_led.max_brightness--;
}
+
+ kbd_led_level = kbd_led_level_get(NULL);
+
ret = led_classdev_register(dev, &kbd_led);
if (ret)
kbd_led_present = false;
@@ -2027,13 +2095,25 @@ static void kbd_led_exit(void)
static int dell_laptop_notifier_call(struct notifier_block *nb,
unsigned long action, void *data)
{
+ bool changed = false;
+ enum led_brightness new_kbd_led_level;
+
switch (action) {
case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED:
if (!kbd_led_present)
break;
- led_classdev_notify_brightness_hw_changed(&kbd_led,
- kbd_led_level_get(&kbd_led));
+ mutex_lock(&kbd_led_mutex);
+ new_kbd_led_level = kbd_led_level_get(&kbd_led);
+ if (kbd_led_level != new_kbd_led_level) {
+ kbd_led_level = new_kbd_led_level;
+ changed = true;
+ }
+ mutex_unlock(&kbd_led_mutex);
+
+ if (changed)
+ led_classdev_notify_brightness_hw_changed(&kbd_led,
+ kbd_led_level);
break;
}
@@ -2046,6 +2126,7 @@ 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)
@@ -2058,8 +2139,8 @@ int dell_micmute_led_set(int state)
if (!token)
return -ENODEV;
- dell_set_arguments(token->location, token->value, 0, 0);
- dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
+ dell_fill_request(&buffer, token->location, token->value, 0, 0);
+ dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
return state;
}
@@ -2090,13 +2171,6 @@ static int __init dell_init(void)
if (ret)
goto fail_platform_device2;
- buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
- if (!buffer) {
- ret = -ENOMEM;
- goto fail_buffer;
- }
-
-
ret = dell_setup_rfkill();
if (ret) {
@@ -2121,10 +2195,13 @@ static int __init dell_init(void)
token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
if (token) {
- dell_set_arguments(token->location, 0, 0, 0);
- ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
+ struct calling_interface_buffer buffer;
+
+ dell_fill_request(&buffer, token->location, 0, 0, 0);
+ ret = dell_send_request(&buffer,
+ CLASS_TOKEN_READ, SELECT_TOKEN_AC);
if (ret)
- max_intensity = buffer->output[3];
+ max_intensity = buffer.output[3];
}
if (max_intensity) {
@@ -2158,8 +2235,6 @@ 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);
@@ -2179,7 +2254,6 @@ 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.c b/drivers/platform/x86/dell-smbios.c
index 6a60db515bda..8541cde4cb7d 100644
--- a/drivers/platform/x86/dell-smbios.c
+++ b/drivers/platform/x86/dell-smbios.c
@@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = {
/* 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, 1, 7}, /* manufacturing use */
+ {0x0000, 6, 5}, /* manufacturing use */
+ {0x0000, 11, 3}, /* write once */
+ {0x0000, 11, 7}, /* write once */
{0x0000, 11, 11}, /* write once */
{0x0000, 19, -1}, /* diagnostics */
/* handled by kernel: dell-laptop */
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index fb25b20df316..2c9927430d85 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -261,6 +261,9 @@ static const u16 bios_to_linux_keycode[256] = {
* override them.
*/
static const struct key_entry dell_wmi_keymap_type_0010[] = {
+ /* Mic mute */
+ { KE_KEY, 0x150, { KEY_MICMUTE } },
+
/* Fn-lock */
{ KE_IGNORE, 0x151, { KEY_RESERVED } },
diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c
new file mode 100644
index 000000000000..2d645c505f81
--- /dev/null
+++ b/drivers/platform/x86/gpd-pocket-fan.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * GPD Pocket fan controller driver
+ *
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/thermal.h>
+#include <linux/workqueue.h>
+
+#define MAX_SPEED 3
+
+static int temp_limits[3] = { 55000, 60000, 65000 };
+module_param_array(temp_limits, int, NULL, 0444);
+MODULE_PARM_DESC(temp_limits,
+ "Milli-celcius values above which the fan speed increases");
+
+static int hysteresis = 3000;
+module_param(hysteresis, int, 0444);
+MODULE_PARM_DESC(hysteresis,
+ "Hysteresis in milli-celcius before lowering the fan speed");
+
+static int speed_on_ac = 2;
+module_param(speed_on_ac, int, 0444);
+MODULE_PARM_DESC(speed_on_ac,
+ "minimum fan speed to allow when system is powered by AC");
+
+struct gpd_pocket_fan_data {
+ struct device *dev;
+ struct thermal_zone_device *dts0;
+ struct thermal_zone_device *dts1;
+ struct gpio_desc *gpio0;
+ struct gpio_desc *gpio1;
+ struct delayed_work work;
+ int last_speed;
+};
+
+static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed)
+{
+ if (speed == fan->last_speed)
+ return;
+
+ gpiod_direction_output(fan->gpio0, !!(speed & 1));
+ gpiod_direction_output(fan->gpio1, !!(speed & 2));
+
+ fan->last_speed = speed;
+}
+
+static int gpd_pocket_fan_min_speed(void)
+{
+ if (power_supply_is_system_supplied())
+ return speed_on_ac;
+ else
+ return 0;
+}
+
+static void gpd_pocket_fan_worker(struct work_struct *work)
+{
+ struct gpd_pocket_fan_data *fan =
+ container_of(work, struct gpd_pocket_fan_data, work.work);
+ int t0, t1, temp, speed, min_speed, i;
+
+ if (thermal_zone_get_temp(fan->dts0, &t0) ||
+ thermal_zone_get_temp(fan->dts1, &t1)) {
+ dev_warn(fan->dev, "Error getting temperature\n");
+ speed = MAX_SPEED;
+ goto set_speed;
+ }
+
+ temp = max(t0, t1);
+
+ speed = fan->last_speed;
+ min_speed = gpd_pocket_fan_min_speed();
+
+ /* Determine minimum speed */
+ for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
+ if (temp < temp_limits[i])
+ break;
+ }
+ if (speed < i)
+ speed = i;
+
+ /* Use hysteresis before lowering speed again */
+ for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
+ if (temp <= (temp_limits[i] - hysteresis))
+ break;
+ }
+ if (speed > i)
+ speed = i;
+
+ if (fan->last_speed <= 0 && speed)
+ speed = MAX_SPEED; /* kick start motor */
+
+set_speed:
+ gpd_pocket_fan_set_speed(fan, speed);
+
+ /* When mostly idle (low temp/speed), slow down the poll interval. */
+ queue_delayed_work(system_wq, &fan->work,
+ msecs_to_jiffies(4000 / (speed + 1)));
+}
+
+static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan)
+{
+ fan->last_speed = -1;
+ mod_delayed_work(system_wq, &fan->work, 0);
+}
+
+static int gpd_pocket_fan_probe(struct platform_device *pdev)
+{
+ struct gpd_pocket_fan_data *fan;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(temp_limits); i++) {
+ if (temp_limits[i] < 40000 || temp_limits[i] > 70000) {
+ dev_err(&pdev->dev, "Invalid temp-limit %d (must be between 40000 and 70000)\n",
+ temp_limits[i]);
+ return -EINVAL;
+ }
+ }
+ if (hysteresis < 1000 || hysteresis > 10000) {
+ dev_err(&pdev->dev, "Invalid hysteresis %d (must be between 1000 and 10000)\n",
+ hysteresis);
+ return -EINVAL;
+ }
+ if (speed_on_ac < 0 || speed_on_ac > MAX_SPEED) {
+ dev_err(&pdev->dev, "Invalid speed_on_ac %d (must be between 0 and 3)\n",
+ speed_on_ac);
+ return -EINVAL;
+ }
+
+ fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
+ if (!fan)
+ return -ENOMEM;
+
+ fan->dev = &pdev->dev;
+ INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker);
+
+ /* Note this returns a "weak" reference which we don't need to free */
+ fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0");
+ if (IS_ERR(fan->dts0))
+ return -EPROBE_DEFER;
+
+ fan->dts1 = thermal_zone_get_zone_by_name("soc_dts1");
+ if (IS_ERR(fan->dts1))
+ return -EPROBE_DEFER;
+
+ fan->gpio0 = devm_gpiod_get_index(fan->dev, NULL, 0, GPIOD_ASIS);
+ if (IS_ERR(fan->gpio0))
+ return PTR_ERR(fan->gpio0);
+
+ fan->gpio1 = devm_gpiod_get_index(fan->dev, NULL, 1, GPIOD_ASIS);
+ if (IS_ERR(fan->gpio1))
+ return PTR_ERR(fan->gpio1);
+
+ gpd_pocket_fan_force_update(fan);
+
+ platform_set_drvdata(pdev, fan);
+ return 0;
+}
+
+static int gpd_pocket_fan_remove(struct platform_device *pdev)
+{
+ struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&fan->work);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int gpd_pocket_fan_suspend(struct device *dev)
+{
+ struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&fan->work);
+ gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed());
+ return 0;
+}
+
+static int gpd_pocket_fan_resume(struct device *dev)
+{
+ struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
+
+ gpd_pocket_fan_force_update(fan);
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops,
+ gpd_pocket_fan_suspend,
+ gpd_pocket_fan_resume);
+
+static struct acpi_device_id gpd_pocket_fan_acpi_match[] = {
+ { "FAN02501" },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match);
+
+static struct platform_driver gpd_pocket_fan_driver = {
+ .probe = gpd_pocket_fan_probe,
+ .remove = gpd_pocket_fan_remove,
+ .driver = {
+ .name = "gpd_pocket_fan",
+ .acpi_match_table = gpd_pocket_fan_acpi_match,
+ .pm = &gpd_pocket_fan_pm_ops,
+ },
+};
+
+module_platform_driver(gpd_pocket_fan_driver);
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
+MODULE_DESCRIPTION("GPD pocket fan driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 53ab4e0f8962..b2bbddd09a52 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -124,10 +124,10 @@ static int read_method_int(acpi_handle handle, const char *method, int *val)
if (ACPI_FAILURE(status)) {
*val = -1;
return -1;
- } else {
- *val = result;
- return 0;
}
+ *val = result;
+ return 0;
+
}
static int method_gbmd(acpi_handle handle, unsigned long *ret)
@@ -164,10 +164,10 @@ static int method_vpcr(acpi_handle handle, int cmd, int *ret)
if (ACPI_FAILURE(status)) {
*ret = -1;
return -1;
- } else {
- *ret = result;
- return 0;
}
+ *ret = result;
+ return 0;
+
}
static int method_vpcw(acpi_handle handle, int cmd, int data)
@@ -231,7 +231,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
if (val == 0)
return 0;
}
- pr_err("timeout in write_ec_cmd\n");
+ pr_err("timeout in %s\n", __func__);
return -1;
}
@@ -964,6 +964,13 @@ static void ideapad_wmi_notify(u32 value, void *context)
*/
static const struct dmi_system_id no_hw_rfkill_list[] = {
{
+ .ident = "Lenovo RESCUER R720-15IKBN",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_BOARD_NAME, "80WW"),
+ },
+ },
+ {
.ident = "Lenovo G40-30",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1104,6 +1111,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo Legion Y720-15IKB",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
+ },
+ },
+ {
.ident = "Lenovo Legion Y720-15IKBN",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index f470279c4c10..d1a01311c1a2 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -25,6 +25,7 @@
#include <linux/acpi.h>
#include <linux/suspend.h>
#include <acpi/acpi_bus.h>
+#include <linux/dmi.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex Hung");
@@ -73,6 +74,24 @@ static const struct key_entry intel_array_keymap[] = {
{ KE_END },
};
+static const struct dmi_system_id button_array_table[] = {
+ {
+ .ident = "Wacom MobileStudio Pro 13",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"),
+ },
+ },
+ {
+ .ident = "Wacom MobileStudio Pro 16",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"),
+ },
+ },
+ { }
+};
+
struct intel_hid_priv {
struct input_dev *input_dev;
struct input_dev *array;
@@ -263,10 +282,27 @@ wakeup:
ev_index);
}
+static bool button_array_present(struct platform_device *device)
+{
+ acpi_handle handle = ACPI_HANDLE(&device->dev);
+ unsigned long long event_cap;
+ acpi_status status;
+ bool supported = false;
+
+ status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
+ if (ACPI_SUCCESS(status) && (event_cap & 0x20000))
+ supported = true;
+
+ if (dmi_check_system(button_array_table))
+ supported = true;
+
+ return supported;
+}
+
static int intel_hid_probe(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
- unsigned long long event_cap, mode;
+ unsigned long long mode;
struct intel_hid_priv *priv;
acpi_status status;
int err;
@@ -299,8 +335,7 @@ static int intel_hid_probe(struct platform_device *device)
}
/* Setup 5 button array */
- status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
- if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
+ if (button_array_present(device)) {
dev_info(&device->dev, "platform supports 5 button array\n");
err = intel_button_array_input_setup(device);
if (err)
diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
index 58c5ff36523a..b703d6f5b099 100644
--- a/drivers/platform/x86/intel-vbtn.c
+++ b/drivers/platform/x86/intel-vbtn.c
@@ -1,30 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Intel Virtual Button driver for Windows 8.1+
*
* Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
* Copyright (C) 2016 Alex Hung <alex.hung@canonical.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
#include <linux/platform_device.h>
-#include <linux/input/sparse-keymap.h>
-#include <linux/acpi.h>
#include <linux/suspend.h>
-#include <acpi/acpi_bus.h>
+
+/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
+#define TABLET_MODE_FLAG 0x40
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AceLan Kao");
@@ -38,10 +29,16 @@ static const struct acpi_device_id intel_vbtn_ids[] = {
static const struct key_entry intel_vbtn_keymap[] = {
{ KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */
{ KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */
+ { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* 'Windows' key press */
+ { KE_KEY, 0xC3, { KEY_LEFTMETA } }, /* 'Windows' key release */
{ KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */
{ KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */
{ KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */
{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */
+ { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */
+ { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */
+ { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */
+ { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */
{ KE_END },
};
@@ -74,20 +71,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
{
struct platform_device *device = context;
struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
+ unsigned int val = !(event & 1); /* Even=press, Odd=release */
+ const struct key_entry *ke_rel;
+ bool autorelease;
if (priv->wakeup_mode) {
if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) {
pm_wakeup_hard_event(&device->dev);
return;
}
- } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) {
- return;
+ goto out_unknown;
}
+
+ /*
+ * Even press events are autorelease if there is no corresponding odd
+ * release event, or if the odd event is KE_IGNORE.
+ */
+ ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, event | 1);
+ autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE);
+
+ if (sparse_keymap_report_event(priv->input_dev, event, val, autorelease))
+ return;
+
+out_unknown:
dev_dbg(&device->dev, "unknown event index 0x%x\n", event);
}
static int intel_vbtn_probe(struct platform_device *device)
{
+ struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle handle = ACPI_HANDLE(&device->dev);
struct intel_vbtn_priv *priv;
acpi_status status;
@@ -110,6 +122,23 @@ static int intel_vbtn_probe(struct platform_device *device)
return err;
}
+ /*
+ * VGBS being present and returning something means we have
+ * a tablet mode switch.
+ */
+ status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output);
+ if (ACPI_SUCCESS(status)) {
+ union acpi_object *obj = vgbs_output.pointer;
+
+ if (obj && obj->type == ACPI_TYPE_INTEGER) {
+ int m = !(obj->integer.value & TABLET_MODE_FLAG);
+
+ input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
+ }
+ }
+
+ kfree(vgbs_output.pointer);
+
status = acpi_install_notify_handler(handle,
ACPI_DEVICE_NOTIFY,
notify_handler,
diff --git a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
new file mode 100644
index 000000000000..38b8e7cfe88c
--- /dev/null
+++ b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
@@ -0,0 +1,93 @@
+/*
+ * Power-button driver for Dollar Cove TI PMIC
+ * Copyright (C) 2014 Intel Corp
+ * Copyright (c) 2017 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/slab.h>
+
+#define CHTDC_TI_SIRQ_REG 0x3
+#define SIRQ_PWRBTN_REL BIT(0)
+
+static irqreturn_t chtdc_ti_pwrbtn_interrupt(int irq, void *dev_id)
+{
+ struct input_dev *input = dev_id;
+ struct device *dev = input->dev.parent;
+ struct regmap *regmap = dev_get_drvdata(dev);
+ int state;
+
+ if (!regmap_read(regmap, CHTDC_TI_SIRQ_REG, &state)) {
+ dev_dbg(dev, "SIRQ_REG=0x%x\n", state);
+ input_report_key(input, KEY_POWER, !(state & SIRQ_PWRBTN_REL));
+ input_sync(input);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
+ struct input_dev *input;
+ int irq, err;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+ input->name = pdev->name;
+ input->phys = "power-button/input0";
+ input->id.bustype = BUS_HOST;
+ input_set_capability(input, EV_KEY, KEY_POWER);
+ err = input_register_device(input);
+ if (err)
+ return err;
+
+ dev_set_drvdata(dev, pmic->regmap);
+
+ err = devm_request_threaded_irq(dev, irq, NULL,
+ chtdc_ti_pwrbtn_interrupt,
+ 0, KBUILD_MODNAME, input);
+ if (err)
+ return err;
+
+ device_init_wakeup(dev, true);
+ dev_pm_set_wake_irq(dev, irq);
+ return 0;
+}
+
+static int chtdc_ti_pwrbtn_remove(struct platform_device *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+ return 0;
+}
+
+static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = {
+ { .name = "chtdc_ti_pwrbtn" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table);
+
+static struct platform_driver chtdc_ti_pwrbtn_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+ .probe = chtdc_ti_pwrbtn_probe,
+ .remove = chtdc_ti_pwrbtn_remove,
+ .id_table = chtdc_ti_pwrbtn_id_table,
+};
+module_platform_driver(chtdc_ti_pwrbtn_driver);
+
+MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index f7b67e898abc..a473dc51b18d 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -180,7 +180,7 @@ static int int0002_probe(struct platform_device *pdev)
* to gpiochip_set_chained_irqchip, because the irq is shared.
*/
ret = devm_request_irq(dev, irq, int0002_irq,
- IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip);
+ IRQF_SHARED, "INT0002", chip);
if (ret) {
dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret);
return ret;
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 17e08b42b0a9..43bbe74743d9 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -18,20 +18,24 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/init.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
-#include <asm/pmc_core.h>
#include "intel_pmc_core.h"
+#define ICPU(model, data) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data }
+
static struct pmc_dev pmc;
static const struct pmc_bit_map spt_pll_map[] = {
@@ -119,10 +123,88 @@ static const struct pmc_reg_map spt_reg_map = {
.pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
};
-static const struct pci_device_id pmc_pci_ids[] = {
- { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID),
- (kernel_ulong_t)&spt_reg_map },
- { 0, },
+/* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */
+static const struct pmc_bit_map cnp_pfear_map[] = {
+ {"PMC", BIT(0)},
+ {"OPI-DMI", BIT(1)},
+ {"SPI/eSPI", BIT(2)},
+ {"XHCI", BIT(3)},
+ {"SPA", BIT(4)},
+ {"SPB", BIT(5)},
+ {"SPC", BIT(6)},
+ {"GBE", BIT(7)},
+
+ {"SATA", BIT(0)},
+ {"HDA_PGD0", BIT(1)},
+ {"HDA_PGD1", BIT(2)},
+ {"HDA_PGD2", BIT(3)},
+ {"HDA_PGD3", BIT(4)},
+ {"SPD", BIT(5)},
+ {"LPSS", BIT(6)},
+ {"LPC", BIT(7)},
+
+ {"SMB", BIT(0)},
+ {"ISH", BIT(1)},
+ {"P2SB", BIT(2)},
+ {"NPK_VNN", BIT(3)},
+ {"SDX", BIT(4)},
+ {"SPE", BIT(5)},
+ {"Fuse", BIT(6)},
+ {"Res_23", BIT(7)},
+
+ {"CSME_FSC", BIT(0)},
+ {"USB3_OTG", BIT(1)},
+ {"EXI", BIT(2)},
+ {"CSE", BIT(3)},
+ {"csme_kvm", BIT(4)},
+ {"csme_pmt", BIT(5)},
+ {"csme_clink", BIT(6)},
+ {"csme_ptio", BIT(7)},
+
+ {"csme_usbr", BIT(0)},
+ {"csme_susram", BIT(1)},
+ {"csme_smt1", BIT(2)},
+ {"CSME_SMT4", BIT(3)},
+ {"csme_sms2", BIT(4)},
+ {"csme_sms1", BIT(5)},
+ {"csme_rtc", BIT(6)},
+ {"csme_psf", BIT(7)},
+
+ {"SBR0", BIT(0)},
+ {"SBR1", BIT(1)},
+ {"SBR2", BIT(2)},
+ {"SBR3", BIT(3)},
+ {"SBR4", BIT(4)},
+ {"SBR5", BIT(5)},
+ {"CSME_PECI", BIT(6)},
+ {"PSF1", BIT(7)},
+
+ {"PSF2", BIT(0)},
+ {"PSF3", BIT(1)},
+ {"PSF4", BIT(2)},
+ {"CNVI", BIT(3)},
+ {"UFS0", BIT(4)},
+ {"EMMC", BIT(5)},
+ {"Res_6", BIT(6)},
+ {"SBR6", BIT(7)},
+
+ {"SBR7", BIT(0)},
+ {"NPK_AON", BIT(1)},
+ {"HDA_PGD4", BIT(2)},
+ {"HDA_PGD5", BIT(3)},
+ {"HDA_PGD6", BIT(4)},
+ {}
+};
+
+static const struct pmc_reg_map cnp_reg_map = {
+ .pfear_sts = cnp_pfear_map,
+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
};
static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
@@ -146,37 +228,6 @@ static inline u32 pmc_core_adjust_slp_s0_step(u32 value)
return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP;
}
-/**
- * intel_pmc_slp_s0_counter_read() - Read SLP_S0 residency.
- * @data: Out param that contains current SLP_S0 count.
- *
- * This API currently supports Intel Skylake SoC and Sunrise
- * Point Platform Controller Hub. Future platform support
- * should be added for platforms that support low power modes
- * beyond Package C10 state.
- *
- * SLP_S0_RESIDENCY counter counts in 100 us granularity per
- * step hence function populates the multiplied value in out
- * parameter @data.
- *
- * Return: an error code or 0 on success.
- */
-int intel_pmc_slp_s0_counter_read(u32 *data)
-{
- struct pmc_dev *pmcdev = &pmc;
- const struct pmc_reg_map *map = pmcdev->map;
- u32 value;
-
- if (!pmcdev->has_slp_s0_res)
- return -EACCES;
-
- value = pmc_core_reg_read(pmcdev, map->slp_s0_offset);
- *data = pmc_core_adjust_slp_s0_step(value);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read);
-
static int pmc_core_dev_state_get(void *data, u64 *val)
{
struct pmc_dev *pmcdev = data;
@@ -437,47 +488,33 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
{
- struct dentry *dir, *file;
+ struct dentry *dir;
dir = debugfs_create_dir("pmc_core", NULL);
if (!dir)
return -ENOMEM;
pmcdev->dbgfs_dir = dir;
- file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO,
- dir, pmcdev, &pmc_core_dev_state);
- if (!file)
- goto err;
-
- file = debugfs_create_file("pch_ip_power_gating_status",
- S_IFREG | S_IRUGO, dir, pmcdev,
- &pmc_core_ppfear_ops);
- if (!file)
- goto err;
-
- file = debugfs_create_file("mphy_core_lanes_power_gating_status",
- S_IFREG | S_IRUGO, dir, pmcdev,
- &pmc_core_mphy_pg_ops);
- if (!file)
- goto err;
-
- file = debugfs_create_file("pll_status",
- S_IFREG | S_IRUGO, dir, pmcdev,
- &pmc_core_pll_ops);
- if (!file)
- goto err;
-
- file = debugfs_create_file("ltr_ignore",
- S_IFREG | S_IRUGO, dir, pmcdev,
- &pmc_core_ltr_ignore_ops);
-
- if (!file)
- goto err;
+
+ debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
+ &pmc_core_dev_state);
+
+ debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
+ &pmc_core_ppfear_ops);
+
+ debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
+ &pmc_core_ltr_ignore_ops);
+
+ if (pmcdev->map->pll_sts)
+ debugfs_create_file("pll_status", 0444, dir, pmcdev,
+ &pmc_core_pll_ops);
+
+ if (pmcdev->map->mphy_sts)
+ debugfs_create_file("mphy_core_lanes_power_gating_status",
+ 0444, dir, pmcdev,
+ &pmc_core_mphy_pg_ops);
return 0;
-err:
- pmc_core_dbgfs_unregister(pmcdev);
- return -ENODEV;
}
#else
static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
@@ -491,71 +528,76 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
#endif /* CONFIG_DEBUG_FS */
static const struct x86_cpu_id intel_pmc_core_ids[] = {
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT,
- (kernel_ulong_t)NULL},
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT,
- (kernel_ulong_t)NULL},
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT,
- (kernel_ulong_t)NULL},
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT,
- (kernel_ulong_t)NULL},
+ ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map),
+ ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map),
+ ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map),
+ ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map),
+ ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map),
{}
};
-static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
+MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
+
+static const struct pci_device_id pmc_pci_ids[] = {
+ { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0},
+ { 0, },
+};
+
+static int __init pmc_core_probe(void)
{
- struct device *ptr_dev = &dev->dev;
struct pmc_dev *pmcdev = &pmc;
const struct x86_cpu_id *cpu_id;
- const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data;
+ u64 slp_s0_addr;
int err;
cpu_id = x86_match_cpu(intel_pmc_core_ids);
- if (!cpu_id) {
- dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n");
- return -EINVAL;
- }
-
- err = pcim_enable_device(dev);
- if (err < 0) {
- dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n");
- return err;
- }
-
- err = pci_read_config_dword(dev,
- SPT_PMC_BASE_ADDR_OFFSET,
- &pmcdev->base_addr);
- if (err < 0) {
- dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n");
- return err;
- }
- pmcdev->base_addr &= PMC_BASE_ADDR_MASK;
- dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr);
-
- pmcdev->regbase = devm_ioremap_nocache(ptr_dev,
- pmcdev->base_addr,
- SPT_PMC_MMIO_REG_LEN);
- if (!pmcdev->regbase) {
- dev_dbg(&dev->dev, "PMC Core: ioremap failed.\n");
+ if (!cpu_id)
+ return -ENODEV;
+
+ pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data;
+
+ /*
+ * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here
+ * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap
+ * in this case.
+ */
+ if (!pci_dev_present(pmc_pci_ids))
+ pmcdev->map = &cnp_reg_map;
+
+ if (lpit_read_residency_count_address(&slp_s0_addr))
+ pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT;
+ else
+ pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset;
+
+ pmcdev->regbase = ioremap(pmcdev->base_addr,
+ pmcdev->map->regmap_length);
+ if (!pmcdev->regbase)
return -ENOMEM;
- }
mutex_init(&pmcdev->lock);
- pmcdev->map = map;
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
err = pmc_core_dbgfs_register(pmcdev);
- if (err < 0)
- dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n");
+ if (err < 0) {
+ pr_warn(" debugfs register failed.\n");
+ iounmap(pmcdev->regbase);
+ return err;
+ }
- pmc.has_slp_s0_res = true;
+ pr_info(" initialized\n");
return 0;
}
+module_init(pmc_core_probe)
-static struct pci_driver intel_pmc_core_driver = {
- .name = "intel_pmc_core",
- .id_table = pmc_pci_ids,
- .probe = pmc_core_probe,
-};
+static void __exit pmc_core_remove(void)
+{
+ struct pmc_dev *pmcdev = &pmc;
+
+ pmc_core_dbgfs_unregister(pmcdev);
+ mutex_destroy(&pmcdev->lock);
+ iounmap(pmcdev->regbase);
+}
+module_exit(pmc_core_remove)
-builtin_pci_driver(intel_pmc_core_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel PMC Core Driver");
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index 3d225a9cc09f..5fa5f97870aa 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -21,9 +21,10 @@
#ifndef PMC_CORE_H
#define PMC_CORE_H
+#define PMC_BASE_ADDR_DEFAULT 0xFE000000
+
/* Sunrise Point Power Management Controller PCI Device ID */
#define SPT_PMC_PCI_DEVICE_ID 0x9d21
-
#define SPT_PMC_BASE_ADDR_OFFSET 0x48
#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
#define SPT_PMC_PM_CFG_OFFSET 0x18
@@ -122,6 +123,17 @@ enum ppfear_regs {
#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2)
#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3)
+/* Cannonlake Power Management Controller register offsets */
+#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C
+#define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C
+#define CNP_PMC_PM_CFG_OFFSET 0x1818
+/* Cannonlake: PGD PFET Enable Ack Status Register(s) start */
+#define CNP_PMC_HOST_PPFEAR0A 0x1D90
+
+#define CNP_PMC_MMIO_REG_LEN 0x2000
+#define CNP_PPFEAR_NUM_ENTRIES 8
+#define CNP_PMC_READ_DISABLE_BIT 22
+
struct pmc_bit_map {
const char *name;
u32 bit_mask;
@@ -135,7 +147,6 @@ struct pmc_bit_map {
* @pll_sts: Maps name of PLL to corresponding bit status
* @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
* @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
- * @base_address: Base address of PWRMBASE defined in BIOS writer guide
* @regmap_length: Length of memory to map from PWRMBASE address to access
* @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
* @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
@@ -152,7 +163,6 @@ struct pmc_reg_map {
const struct pmc_bit_map *pll_sts;
const u32 slp_s0_offset;
const u32 ltr_ignore_offset;
- const u32 base_address;
const int regmap_length;
const u32 ppfear0_offset;
const int ppfear_buckets;
@@ -162,12 +172,14 @@ struct pmc_reg_map {
/**
* struct pmc_dev - pmc device structure
- * @base_addr: comtains pmc base address
+ * @base_addr: contains pmc base address
* @regbase: pointer to io-remapped memory location
- * @dbgfs_dir: path to debug fs interface
- * @feature_available: flag to indicate whether
- * the feature is available
- * on a particular platform or not.
+ * @map: pointer to pmc_reg_map struct that contains platform
+ * specific attributes
+ * @dbgfs_dir: path to debugfs interface
+ * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
+ * used to read MPHY PG and PLL status are available
+ * @mutex_lock: mutex to complete one transcation
*
* pmc_dev contains info about power management controller device.
*/
@@ -178,7 +190,6 @@ struct pmc_dev {
#if IS_ENABLED(CONFIG_DEBUG_FS)
struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */
- bool has_slp_s0_res;
int pmc_xram_read_bit;
struct mutex lock; /* generic mutex lock for PMC Core */
};
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e03fa31446ca..e7edc8c63936 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -215,11 +215,11 @@ static inline int is_gcr_valid(u32 offset)
}
/**
- * intel_pmc_gcr_read() - Read PMC GCR register
+ * intel_pmc_gcr_read() - Read a 32-bit PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: data pointer for storing the register output
*
- * Reads the PMC GCR register of given offset.
+ * Reads the 32-bit PMC GCR register at given offset.
*
* Return: negative value on error or 0 on success.
*/
@@ -244,6 +244,35 @@ int intel_pmc_gcr_read(u32 offset, u32 *data)
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
/**
+ * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
+ * @offset: offset of GCR register from GCR address base
+ * @data: data pointer for storing the register output
+ *
+ * Reads the 64-bit PMC GCR register at given offset.
+ *
+ * Return: negative value on error or 0 on success.
+ */
+int intel_pmc_gcr_read64(u32 offset, u64 *data)
+{
+ int ret;
+
+ spin_lock(&ipcdev.gcr_lock);
+
+ ret = is_gcr_valid(offset);
+ if (ret < 0) {
+ spin_unlock(&ipcdev.gcr_lock);
+ return ret;
+ }
+
+ *data = readq(ipcdev.gcr_mem_base + offset);
+
+ spin_unlock(&ipcdev.gcr_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
+
+/**
* intel_pmc_gcr_write() - Write PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: register update value
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index 4249e8267bbc..ffd0474b0531 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -23,7 +23,6 @@
*/
#include <linux/debugfs.h>
#include <linux/device.h>
-#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
@@ -32,11 +31,10 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/intel_pmc_ipc.h>
-#include <asm/intel_punit_ipc.h>
#include <asm/intel_telemetry.h>
-#define DRIVER_NAME "telemetry_soc_debugfs"
-#define DRIVER_VERSION "1.0.0"
+#define DRIVER_NAME "telemetry_soc_debugfs"
+#define DRIVER_VERSION "1.0.0"
/* ApolloLake SoC Event-IDs */
#define TELEM_APL_PSS_PSTATES_ID 0x2802
@@ -98,10 +96,6 @@ static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
struct telemetry_susp_stats {
- u32 shlw_swake_ctr;
- u32 deep_swake_ctr;
- u64 shlw_swake_res;
- u64 deep_swake_res;
u32 shlw_ctr;
u32 deep_ctr;
u64 shlw_res;
@@ -250,7 +244,6 @@ static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = {
{"PRTC", 25},
};
-
struct telemetry_debugfs_conf {
struct telemetry_susp_stats suspend_stats;
struct dentry *telemetry_dbg_dir;
@@ -385,7 +378,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
TELEM_APL_MASK_PCS_STATE;
}
-
TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
conf->pss_idle_evts - 1,
pss_idle, evtlog[index].telem_evtlog,
@@ -405,7 +397,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
conf->pcs_s0ix_blkd_data,
TELEM_MASK_BYTE);
-
TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
conf->pss_wakeup_evts,
pss_s0ix_wakeup,
@@ -498,7 +489,6 @@ static const struct file_operations telem_pss_ops = {
.release = single_release,
};
-
static int telem_ioss_states_show(struct seq_file *s, void *unused)
{
struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
@@ -598,19 +588,15 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
s0ix_shlw_ctr -
- conf->suspend_stats.shlw_ctr -
- conf->suspend_stats.shlw_swake_ctr,
+ conf->suspend_stats.shlw_ctr,
(u64)((s0ix_shlw_res -
- conf->suspend_stats.shlw_res -
- conf->suspend_stats.shlw_swake_res)*10/192));
+ conf->suspend_stats.shlw_res)*10/192));
seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
s0ix_deep_ctr -
- conf->suspend_stats.deep_ctr -
- conf->suspend_stats.deep_swake_ctr,
+ conf->suspend_stats.deep_ctr,
(u64)((s0ix_deep_res -
- conf->suspend_stats.deep_res -
- conf->suspend_stats.deep_swake_res)*10/192));
+ conf->suspend_stats.deep_res)*10/192));
seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
conf->suspend_stats.shlw_ctr,
@@ -620,14 +606,8 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
conf->suspend_stats.deep_ctr,
(u64)(conf->suspend_stats.deep_res*10)/192);
- seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n",
- conf->suspend_stats.shlw_swake_ctr +
- conf->suspend_stats.deep_swake_ctr,
- (u64)((conf->suspend_stats.shlw_swake_res +
- conf->suspend_stats.deep_swake_res)*10/192));
-
- seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr,
- (u64)(s0ix_total_res*10/192));
+ seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr,
+ (u64)(s0ix_total_res*10/192));
seq_puts(s, "\n-------------------------------------------------\n");
seq_puts(s, "\t\tDEVICE STATES\n");
seq_puts(s, "-------------------------------------------------\n");
@@ -772,7 +752,6 @@ static const struct file_operations telem_pss_trc_verb_ops = {
.release = single_release,
};
-
static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
{
u32 verbosity;
@@ -890,28 +869,45 @@ static int pm_suspend_exit_cb(void)
goto out;
}
+ /*
+ * Due to some design limitations in the firmware, sometimes the
+ * counters do not get updated by the time we reach here. As a
+ * workaround, we try to see if this was a genuine case of sleep
+ * failure or not by cross-checking from PMC GCR registers directly.
+ */
+ if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp &&
+ suspend_deep_ctr_exit == suspend_deep_ctr_temp) {
+ ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG,
+ &suspend_shlw_res_exit);
+ if (ret < 0)
+ goto out;
+
+ ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG,
+ &suspend_deep_res_exit);
+ if (ret < 0)
+ goto out;
+
+ if (suspend_shlw_res_exit > suspend_shlw_res_temp)
+ suspend_shlw_ctr_exit++;
+
+ if (suspend_deep_res_exit > suspend_deep_res_temp)
+ suspend_deep_ctr_exit++;
+ }
+
suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
suspend_shlw_res_exit -= suspend_shlw_res_temp;
suspend_deep_res_exit -= suspend_deep_res_temp;
- if (suspend_shlw_ctr_exit == 1) {
+ if (suspend_shlw_ctr_exit != 0) {
conf->suspend_stats.shlw_ctr +=
suspend_shlw_ctr_exit;
conf->suspend_stats.shlw_res +=
suspend_shlw_res_exit;
}
- /* Shallow Wakes Case */
- else if (suspend_shlw_ctr_exit > 1) {
- conf->suspend_stats.shlw_swake_ctr +=
- suspend_shlw_ctr_exit;
- conf->suspend_stats.shlw_swake_res +=
- suspend_shlw_res_exit;
- }
-
- if (suspend_deep_ctr_exit == 1) {
+ if (suspend_deep_ctr_exit != 0) {
conf->suspend_stats.deep_ctr +=
suspend_deep_ctr_exit;
@@ -919,15 +915,6 @@ static int pm_suspend_exit_cb(void)
suspend_deep_res_exit;
}
- /* Shallow Wakes Case */
- else if (suspend_deep_ctr_exit > 1) {
- conf->suspend_stats.deep_swake_ctr +=
- suspend_deep_ctr_exit;
-
- conf->suspend_stats.deep_swake_res +=
- suspend_deep_res_exit;
- }
-
out:
suspend_prep_ok = 0;
return NOTIFY_OK;
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 504256c3660d..27de29961f5e 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -35,20 +35,31 @@
#include <linux/dmi.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-mux-reg.h>
-#include <linux/platform_data/mlxcpld-hotplug.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/regmap.h>
#define MLX_PLAT_DEVICE_NAME "mlxplat"
/* LPC bus IO offsets */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
-#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a
-#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558
-#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564
-#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588
+#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
+#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
+#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
+#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
+#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
+#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
+#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
+#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
+#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
+#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
+#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
+#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
+#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -81,6 +92,7 @@
/* mlxplat_priv - platform private data
* @pdev_i2c - i2c controller platform device
* @pdev_mux - array of mux platform devices
+ * @pdev_hotplug - hotplug platform devices
*/
struct mlxplat_priv {
struct platform_device *pdev_i2c;
@@ -138,86 +150,264 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
};
/* Platform hotplug devices */
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = {
+static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
{
- .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
- .bus = 10,
+ I2C_BOARD_INFO("24c02", 0x51),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
- .bus = 10,
+ I2C_BOARD_INFO("24c02", 0x50),
},
};
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = {
+static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
{
- .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
- .bus = 10,
+ I2C_BOARD_INFO("dps460", 0x59),
},
{
- .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
- .bus = 10,
+ I2C_BOARD_INFO("dps460", 0x58),
},
};
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = {
+static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 11,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 12,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 13,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 14,
+ I2C_BOARD_INFO("24c32", 0x50),
},
};
/* Platform hotplug default data */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
+ {
+ .label = "psu1",
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
+ .hpdev.nr = 10,
+ },
+ {
+ .label = "psu2",
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
+ .hpdev.nr = 10,
+ },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
+ {
+ .label = "pwr1",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
+ .hpdev.nr = 10,
+ },
+ {
+ .label = "pwr2",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
+ .hpdev.nr = 10,
+ },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
+ {
+ .label = "fan1",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
+ .hpdev.nr = 11,
+ },
+ {
+ .label = "fan2",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
+ .hpdev.nr = 12,
+ },
+ {
+ .label = "fan3",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(2),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
+ .hpdev.nr = 13,
+ },
+ {
+ .label = "fan4",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(3),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
+ .hpdev.nr = 14,
+ },
+};
+
+static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_psu_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = MLXPLAT_CPLD_PSU_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_pwr_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+ .inversed = 0,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_fan_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = MLXPLAT_CPLD_FAN_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
+ .inversed = 1,
+ .health = false,
+ },
+};
+
static
-struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = {
- .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
- .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
- .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
- .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR,
- .psu_mask = MLXPLAT_CPLD_PSU_MASK,
- .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
- .psu = mlxplat_mlxcpld_psu,
- .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
- .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
- .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
- .pwr = mlxplat_mlxcpld_pwr,
- .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
- .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
- .fan_mask = MLXPLAT_CPLD_FAN_MASK,
- .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
- .fan = mlxplat_mlxcpld_fan,
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
+ .items = mlxplat_mlxcpld_default_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
};
/* Platform hotplug MSN21xx system family data */
+static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_pwr_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+ .inversed = 0,
+ .health = false,
+ },
+};
+
static
-struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
- .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
- .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
- .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
- .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
- .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
+ .items = mlxplat_mlxcpld_msn21xx_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
+};
+
+static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ return true;
+ }
+ return false;
+}
+
+static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ return true;
+ }
+ return false;
+}
+
+static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ return true;
+ }
+ return false;
+}
+
+struct mlxplat_mlxcpld_regmap_context {
+ void __iomem *base;
+};
+
+static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
+
+static int
+mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
+
+ *val = ioread8(ctx->base + reg);
+ return 0;
+}
+
+static int
+mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
+
+ iowrite8(val, ctx->base + reg);
+ return 0;
+}
+
+static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 255,
+ .cache_type = REGCACHE_FLAT,
+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
+ .readable_reg = mlxplat_mlxcpld_readable_reg,
+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
+ .reg_read = mlxplat_mlxcpld_reg_read,
+ .reg_write = mlxplat_mlxcpld_reg_write,
};
static struct resource mlxplat_mlxcpld_resources[] = {
- [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
+ [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
};
static struct platform_device *mlxplat_dev;
-static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
+static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
@@ -286,6 +476,8 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
{ }
};
+MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
+
static int __init mlxplat_init(void)
{
struct mlxplat_priv *priv;
@@ -328,8 +520,23 @@ static int __init mlxplat_init(void)
}
}
+ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
+ mlxplat_lpc_resources[1].start, 1);
+ if (!mlxplat_mlxcpld_regmap_ctx.base) {
+ err = -ENOMEM;
+ goto fail_platform_mux_register;
+ }
+
+ mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
+ &mlxplat_mlxcpld_regmap_ctx,
+ &mlxplat_mlxcpld_regmap_config);
+ if (IS_ERR(mlxplat_hotplug->regmap)) {
+ err = PTR_ERR(mlxplat_hotplug->regmap);
+ goto fail_platform_mux_register;
+ }
+
priv->pdev_hotplug = platform_device_register_resndata(
- &mlxplat_dev->dev, "mlxcpld-hotplug",
+ &mlxplat_dev->dev, "mlxreg-hotplug",
PLATFORM_DEVID_NONE,
mlxplat_mlxcpld_resources,
ARRAY_SIZE(mlxplat_mlxcpld_resources),
@@ -339,8 +546,16 @@ static int __init mlxplat_init(void)
goto fail_platform_mux_register;
}
+ /* Sync registers with hardware. */
+ regcache_mark_dirty(mlxplat_hotplug->regmap);
+ err = regcache_sync(mlxplat_hotplug->regmap);
+ if (err)
+ goto fail_platform_hotplug_register;
+
return 0;
+fail_platform_hotplug_register:
+ platform_device_unregister(priv->pdev_hotplug);
fail_platform_mux_register:
while (--i >= 0)
platform_device_unregister(priv->pdev_mux[i]);
@@ -370,8 +585,3 @@ module_exit(mlxplat_exit);
MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
MODULE_DESCRIPTION("Mellanox platform driver");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
diff --git a/drivers/platform/x86/mlxcpld-hotplug.c b/drivers/platform/x86/mlxcpld-hotplug.c
deleted file mode 100644
index aff3686b3b37..000000000000
--- a/drivers/platform/x86/mlxcpld-hotplug.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * drivers/platform/x86/mlxcpld-hotplug.c
- * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/bitops.h>
-#include <linux/device.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_data/mlxcpld-hotplug.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-/* Offset of event and mask registers from status register */
-#define MLXCPLD_HOTPLUG_EVENT_OFF 1
-#define MLXCPLD_HOTPLUG_MASK_OFF 2
-#define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1
-
-#define MLXCPLD_HOTPLUG_ATTRS_NUM 8
-
-/**
- * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events:
- * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute;
- * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute;
- * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute;
- */
-enum mlxcpld_hotplug_attr_type {
- MLXCPLD_HOTPLUG_ATTR_TYPE_PSU,
- MLXCPLD_HOTPLUG_ATTR_TYPE_PWR,
- MLXCPLD_HOTPLUG_ATTR_TYPE_FAN,
-};
-
-/**
- * struct mlxcpld_hotplug_priv_data - platform private data:
- * @irq: platform interrupt number;
- * @pdev: platform device;
- * @plat: platform data;
- * @hwmon: hwmon device;
- * @mlxcpld_hotplug_attr: sysfs attributes array;
- * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array;
- * @group: sysfs attribute group;
- * @groups: list of sysfs attribute group for hwmon registration;
- * @dwork: delayed work template;
- * @lock: spin lock;
- * @aggr_cache: last value of aggregation register status;
- * @psu_cache: last value of PSU register status;
- * @pwr_cache: last value of power register status;
- * @fan_cache: last value of FAN register status;
- */
-struct mlxcpld_hotplug_priv_data {
- int irq;
- struct platform_device *pdev;
- struct mlxcpld_hotplug_platform_data *plat;
- struct device *hwmon;
- struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1];
- struct sensor_device_attribute_2
- mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM];
- struct attribute_group group;
- const struct attribute_group *groups[2];
- struct delayed_work dwork;
- spinlock_t lock;
- u8 aggr_cache;
- u8 psu_cache;
- u8 pwr_cache;
- u8 fan_cache;
-};
-
-static ssize_t mlxcpld_hotplug_attr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
- int index = to_sensor_dev_attr_2(attr)->index;
- int nr = to_sensor_dev_attr_2(attr)->nr;
- u8 reg_val = 0;
-
- switch (nr) {
- case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU:
- /* Bit = 0 : PSU is present. */
- reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index));
- break;
-
- case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR:
- /* Bit = 1 : power cable is attached. */
- reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index %
- priv->plat->pwr_count));
- break;
-
- case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN:
- /* Bit = 0 : FAN is present. */
- reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index %
- priv->plat->fan_count));
- break;
- }
-
- return sprintf(buf, "%u\n", reg_val);
-}
-
-#define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i]
-#define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i]
-static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv)
-{
- int num_attrs = priv->plat->psu_count + priv->plat->pwr_count +
- priv->plat->fan_count;
- int i;
-
- priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
- sizeof(struct attribute *),
- GFP_KERNEL);
- if (!priv->group.attrs)
- return -ENOMEM;
-
- for (i = 0; i < num_attrs; i++) {
- PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr;
-
- if (i < priv->plat->psu_count) {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "psu%u", i + 1);
- PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU;
- } else if (i < priv->plat->psu_count + priv->plat->pwr_count) {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "pwr%u", i %
- priv->plat->pwr_count + 1);
- PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR;
- } else {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "fan%u", i %
- priv->plat->fan_count + 1);
- PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN;
- }
-
- if (!PRIV_ATTR(i)->name) {
- dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
- i + 1);
- return -ENOMEM;
- }
-
- PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name;
- PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO;
- PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show;
- PRIV_DEV_ATTR(i).index = i;
- sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr);
- }
-
- priv->group.attrs = priv->mlxcpld_hotplug_attr;
- priv->groups[0] = &priv->group;
- priv->groups[1] = NULL;
-
- return 0;
-}
-
-static int mlxcpld_hotplug_device_create(struct device *dev,
- struct mlxcpld_hotplug_device *item)
-{
- item->adapter = i2c_get_adapter(item->bus);
- if (!item->adapter) {
- dev_err(dev, "Failed to get adapter for bus %d\n",
- item->bus);
- return -EFAULT;
- }
-
- item->client = i2c_new_device(item->adapter, &item->brdinfo);
- if (!item->client) {
- dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
- item->brdinfo.type, item->bus, item->brdinfo.addr);
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
- return -EFAULT;
- }
-
- return 0;
-}
-
-static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item)
-{
- if (item->client) {
- i2c_unregister_device(item->client);
- item->client = NULL;
- }
-
- if (item->adapter) {
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
- }
-}
-
-static inline void
-mlxcpld_hotplug_work_helper(struct device *dev,
- struct mlxcpld_hotplug_device *item, u8 is_inverse,
- u16 offset, u8 mask, u8 *cache)
-{
- u8 val, asserted;
- int bit;
-
- /* Mask event. */
- outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF);
- /* Read status. */
- val = inb(offset) & mask;
- asserted = *cache ^ val;
- *cache = val;
-
- /*
- * Validate if item related to received signal type is valid.
- * It should never happen, excepted the situation when some
- * piece of hardware is broken. In such situation just produce
- * error message and return. Caller must continue to handle the
- * signals from other devices if any.
- */
- if (unlikely(!item)) {
- dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n",
- offset, mask);
- return;
- }
-
- for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
- if (val & BIT(bit)) {
- if (is_inverse)
- mlxcpld_hotplug_device_destroy(item + bit);
- else
- mlxcpld_hotplug_device_create(dev, item + bit);
- } else {
- if (is_inverse)
- mlxcpld_hotplug_device_create(dev, item + bit);
- else
- mlxcpld_hotplug_device_destroy(item + bit);
- }
- }
-
- /* Acknowledge event. */
- outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF);
- /* Unmask event. */
- outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF);
-}
-
-/*
- * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt
- * registers according to the below hierarchy schema:
- *
- * Aggregation registers (status/mask)
- * PSU registers: *---*
- * *-----------------* | |
- * |status/event/mask|----->| * |
- * *-----------------* | |
- * Power registers: | |
- * *-----------------* | |
- * |status/event/mask|----->| * |---> CPU
- * *-----------------* | |
- * FAN registers:
- * *-----------------* | |
- * |status/event/mask|----->| * |
- * *-----------------* | |
- * *---*
- * In case some system changed are detected: FAN in/out, PSU in/out, power
- * cable attached/detached, relevant device is created or destroyed.
- */
-static void mlxcpld_hotplug_work_handler(struct work_struct *work)
-{
- struct mlxcpld_hotplug_priv_data *priv = container_of(work,
- struct mlxcpld_hotplug_priv_data, dwork.work);
- u8 val, aggr_asserted;
- unsigned long flags;
-
- /* Mask aggregation event. */
- outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
- /* Read aggregation status. */
- val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask;
- aggr_asserted = priv->aggr_cache ^ val;
- priv->aggr_cache = val;
-
- /* Handle PSU configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_psu_mask)
- mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu,
- 1, priv->plat->psu_reg_offset,
- priv->plat->psu_mask,
- &priv->psu_cache);
-
- /* Handle power cable configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_pwr_mask)
- mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr,
- 0, priv->plat->pwr_reg_offset,
- priv->plat->pwr_mask,
- &priv->pwr_cache);
-
- /* Handle FAN configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_fan_mask)
- mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan,
- 1, priv->plat->fan_reg_offset,
- priv->plat->fan_mask,
- &priv->fan_cache);
-
- if (aggr_asserted) {
- spin_lock_irqsave(&priv->lock, flags);
-
- /*
- * It is possible, that some signals have been inserted, while
- * interrupt has been masked by mlxcpld_hotplug_work_handler.
- * In this case such signals will be missed. In order to handle
- * these signals delayed work is canceled and work task
- * re-scheduled for immediate execution. It allows to handle
- * missed signals, if any. In other case work handler just
- * validates that no new signals have been received during
- * masking.
- */
- cancel_delayed_work(&priv->dwork);
- schedule_delayed_work(&priv->dwork, 0);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return;
- }
-
- /* Unmask aggregation event (no need acknowledge). */
- outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
- MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
-}
-
-static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv)
-{
- /* Clear psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
- /* Set psu initial status as mask and unmask psu event. */
- priv->psu_cache = priv->plat->psu_mask;
- outb(priv->plat->psu_mask, priv->plat->psu_reg_offset +
- MLXCPLD_HOTPLUG_MASK_OFF);
-
- /* Clear power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
- /* Keep power initial status as zero and unmask power event. */
- outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset +
- MLXCPLD_HOTPLUG_MASK_OFF);
-
- /* Clear fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
- /* Set fan initial status as mask and unmask fan event. */
- priv->fan_cache = priv->plat->fan_mask;
- outb(priv->plat->fan_mask, priv->plat->fan_reg_offset +
- MLXCPLD_HOTPLUG_MASK_OFF);
-
- /* Keep aggregation initial status as zero and unmask events. */
- outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
- MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
-
- /* Invoke work handler for initializing hot plug devices setting. */
- mlxcpld_hotplug_work_handler(&priv->dwork.work);
-
- enable_irq(priv->irq);
-}
-
-static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv)
-{
- int i;
-
- disable_irq(priv->irq);
- cancel_delayed_work_sync(&priv->dwork);
-
- /* Mask aggregation event. */
- outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
-
- /* Mask psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
- /* Clear psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
-
- /* Mask power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
- /* Clear power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
-
- /* Mask fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
- /* Clear fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
-
- /* Remove all the attached devices. */
- for (i = 0; i < priv->plat->psu_count; i++)
- mlxcpld_hotplug_device_destroy(priv->plat->psu + i);
-
- for (i = 0; i < priv->plat->pwr_count; i++)
- mlxcpld_hotplug_device_destroy(priv->plat->pwr + i);
-
- for (i = 0; i < priv->plat->fan_count; i++)
- mlxcpld_hotplug_device_destroy(priv->plat->fan + i);
-}
-
-static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev)
-{
- struct mlxcpld_hotplug_priv_data *priv =
- (struct mlxcpld_hotplug_priv_data *)dev;
-
- /* Schedule work task for immediate execution.*/
- schedule_delayed_work(&priv->dwork, 0);
-
- return IRQ_HANDLED;
-}
-
-static int mlxcpld_hotplug_probe(struct platform_device *pdev)
-{
- struct mlxcpld_hotplug_platform_data *pdata;
- struct mlxcpld_hotplug_priv_data *priv;
- int err;
-
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "Failed to get platform data.\n");
- return -EINVAL;
- }
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->pdev = pdev;
- priv->plat = pdata;
-
- priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq < 0) {
- dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
- priv->irq);
- return priv->irq;
- }
-
- err = devm_request_irq(&pdev->dev, priv->irq,
- mlxcpld_hotplug_irq_handler, 0, pdev->name,
- priv);
- if (err) {
- dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
- return err;
- }
- disable_irq(priv->irq);
-
- INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler);
- spin_lock_init(&priv->lock);
-
- err = mlxcpld_hotplug_attr_init(priv);
- if (err) {
- dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err);
- return err;
- }
-
- priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
- "mlxcpld_hotplug", priv, priv->groups);
- if (IS_ERR(priv->hwmon)) {
- dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
- PTR_ERR(priv->hwmon));
- return PTR_ERR(priv->hwmon);
- }
-
- platform_set_drvdata(pdev, priv);
-
- /* Perform initial interrupts setup. */
- mlxcpld_hotplug_set_irq(priv);
-
- return 0;
-}
-
-static int mlxcpld_hotplug_remove(struct platform_device *pdev)
-{
- struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
-
- /* Clean interrupts setup. */
- mlxcpld_hotplug_unset_irq(priv);
-
- return 0;
-}
-
-static struct platform_driver mlxcpld_hotplug_driver = {
- .driver = {
- .name = "mlxcpld-hotplug",
- },
- .probe = mlxcpld_hotplug_probe,
- .remove = mlxcpld_hotplug_remove,
-};
-
-module_platform_driver(mlxcpld_hotplug_driver);
-
-MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
-MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("platform:mlxcpld-hotplug");
diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c
index 77bac859342d..4b3c37b6288c 100644
--- a/drivers/platform/x86/pmc_atom.c
+++ b/drivers/platform/x86/pmc_atom.c
@@ -208,6 +208,20 @@ static const struct pmc_data cht_data = {
.clks = cht_clks,
};
+#define DEFINE_SHOW_ATTRIBUTE(__name) \
+static int __name ## _open(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, __name ## _show, inode->i_private); \
+} \
+ \
+static const struct file_operations __name ## _fops = { \
+ .owner = THIS_MODULE, \
+ .open = __name ## _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
{
return readl(pmc->regmap + reg_offset);
@@ -309,17 +323,7 @@ static int pmc_dev_state_show(struct seq_file *s, void *unused)
return 0;
}
-static int pmc_dev_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pmc_dev_state_show, inode->i_private);
-}
-
-static const struct file_operations pmc_dev_state_ops = {
- .open = pmc_dev_state_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_dev_state);
static int pmc_pss_state_show(struct seq_file *s, void *unused)
{
@@ -336,17 +340,7 @@ static int pmc_pss_state_show(struct seq_file *s, void *unused)
return 0;
}
-static int pmc_pss_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pmc_pss_state_show, inode->i_private);
-}
-
-static const struct file_operations pmc_pss_state_ops = {
- .open = pmc_pss_state_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_pss_state);
static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
{
@@ -367,17 +361,7 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
return 0;
}
-static int pmc_sleep_tmr_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pmc_sleep_tmr_show, inode->i_private);
-}
-
-static const struct file_operations pmc_sleep_tmr_ops = {
- .open = pmc_sleep_tmr_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
{
@@ -395,17 +379,17 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc)
pmc->dbgfs_dir = dir;
f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_dev_state_ops);
+ dir, pmc, &pmc_dev_state_fops);
if (!f)
goto err;
f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_pss_state_ops);
+ dir, pmc, &pmc_pss_state_fops);
if (!f)
goto err;
f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_sleep_tmr_ops);
+ dir, pmc, &pmc_sleep_tmr_fops);
if (!f)
goto err;
diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c
index 266535c2a72f..3a624090191d 100644
--- a/drivers/platform/x86/silead_dmi.c
+++ b/drivers/platform/x86/silead_dmi.c
@@ -67,6 +67,21 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = {
.properties = dexp_ursus_7w_props,
};
+static const struct property_entry surftab_twin_10_1_st10432_8_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1900),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
+ PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl3670-surftab-twin-10-1-st10432-8.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = surftab_twin_10_1_st10432_8_props,
+};
+
static const struct property_entry surftab_wintron70_st70416_6_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
@@ -171,6 +186,97 @@ static const struct silead_ts_dmi_data digma_citi_e200_data = {
.properties = digma_citi_e200_props,
};
+static const struct property_entry onda_obook_20_plus_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct silead_ts_dmi_data onda_obook_20_plus_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = onda_obook_20_plus_props,
+};
+
+static const struct property_entry chuwi_hi8_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
+ { }
+};
+
+static const struct silead_ts_dmi_data chuwi_hi8_data = {
+ .acpi_name = "MSSL0001:00",
+ .properties = chuwi_hi8_props,
+};
+
+static const struct property_entry chuwi_vi8_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1724),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct silead_ts_dmi_data chuwi_vi8_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = chuwi_vi8_props,
+};
+
+static const struct property_entry trekstor_primebook_c13_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 2624),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl1680-trekstor-primebook-c13.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct silead_ts_dmi_data trekstor_primebook_c13_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = trekstor_primebook_c13_props,
+};
+
+static const struct property_entry teclast_x98plus2_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 2048),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl1686-teclast_x98plus2.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data teclast_x98plus2_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = teclast_x98plus2_props,
+};
+
+static const struct property_entry teclast_x3_plus_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct silead_ts_dmi_data teclast_x3_plus_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = teclast_x3_plus_props,
+};
+
static const struct dmi_system_id silead_ts_dmi_table[] = {
{
/* CUBE iwork8 Air */
@@ -199,6 +305,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
},
},
{
+ /* TrekStor SurfTab twin 10.1 ST10432-8 */
+ .driver_data = (void *)&surftab_twin_10_1_st10432_8_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"),
+ },
+ },
+ {
/* Trekstor Surftab Wintron 7.0 ST70416-6 */
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
.matches = {
@@ -209,6 +323,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
},
},
{
+ /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */
+ .driver_data = (void *)&surftab_wintron70_st70416_6_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "SurfTab wintron 7.0 ST70416-6"),
+ /* Exact match, different versions need different fw */
+ DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"),
+ },
+ },
+ {
/* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
.matches = {
@@ -271,6 +396,56 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
},
},
+ {
+ /* Onda oBook 20 Plus */
+ .driver_data = (void *)&onda_obook_20_plus_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ONDA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"),
+ },
+ },
+ {
+ /* Chuwi Hi8 */
+ .driver_data = (void *)&chuwi_hi8_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ilife"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S806"),
+ },
+ },
+ {
+ /* Chuwi Vi8 (CWI506) */
+ .driver_data = (void *)&chuwi_vi8_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "i86"),
+ DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
+ },
+ },
+ {
+ /* Trekstor Primebook C13 */
+ .driver_data = (void *)&trekstor_primebook_c13_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
+ },
+ },
+ {
+ /* Teclast X98 Plus II */
+ .driver_data = (void *)&teclast_x98plus2_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"),
+ },
+ },
+ {
+ /* Teclast X3 Plus */
+ .driver_data = (void *)&teclast_x3_plus_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X3 Plus"),
+ DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"),
+ },
+ },
{ },
};
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 117be48ff4de..d5eaf3b1edba 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t {
/* AC-related events */
TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
+ /* Further user-interface events */
+ TP_HKEY_EV_PALM_DETECTED = 0x60b0, /* palm hoveres keyboard */
+ TP_HKEY_EV_PALM_UNDETECTED = 0x60b1, /* palm removed */
+
/* Misc */
TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
};
@@ -2113,12 +2117,10 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
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:
+ /* In mode 4, FLAT is not specified as a valid mode. However,
+ * it can be seen at least on the X1 Yoga 2nd Generation.
+ */
valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
TP_ACPI_MULTI_MODE_FLAT |
TP_ACPI_MULTI_MODE_TABLET |
@@ -4079,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
*send_acpi_ev = false;
break;
+ case TP_HKEY_EV_PALM_DETECTED:
+ case TP_HKEY_EV_PALM_UNDETECTED:
+ /* palm detected hovering the keyboard, forward to user-space
+ * via netlink for consumption */
+ return true;
+
default:
pr_warn("unknown possible thermal alarm or keyboard event received\n");
known = false;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 315ae2926e20..b6adc54b96f1 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -301,13 +301,13 @@ config DB8500_THERMAL
thermal zone if trip points reached.
config ARMADA_THERMAL
- tristate "Armada 370/XP thermal management"
+ tristate "Marvell EBU Armada SoCs thermal management"
depends on ARCH_MVEBU || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Enable this option if you want to have support for thermal management
- controller present in Armada 370 and Armada XP SoC.
+ controller present in Marvell EBU Armada SoCs (370,375,XP,38x,7K,8K).
config DA9062_THERMAL
tristate "DA9062/DA9061 Dialog Semiconductor thermal driver"
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 706d74798cbe..4c275ec10ac5 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -1,5 +1,5 @@
/*
- * Marvell Armada 370/XP thermal sensor driver
+ * Marvell EBU Armada SoCs thermal sensor driver
*
* Copyright (C) 2013 Marvell
*
@@ -23,8 +23,7 @@
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/thermal.h>
-
-#define THERMAL_VALID_MASK 0x1
+#include <linux/iopoll.h>
/* Thermal Manager Control and Status Register */
#define PMU_TDC0_SW_RST_MASK (0x1 << 1)
@@ -39,14 +38,38 @@
#define A375_UNIT_CONTROL_MASK 0x7
#define A375_READOUT_INVERT BIT(15)
#define A375_HW_RESETn BIT(8)
-#define A380_HW_RESET BIT(8)
+
+/* Legacy bindings */
+#define LEGACY_CONTROL_MEM_LEN 0x4
+
+/* Current bindings with the 2 control registers under the same memory area */
+#define LEGACY_CONTROL1_OFFSET 0x0
+#define CONTROL0_OFFSET 0x0
+#define CONTROL1_OFFSET 0x4
+
+/* Errata fields */
+#define CONTROL0_TSEN_TC_TRIM_MASK 0x7
+#define CONTROL0_TSEN_TC_TRIM_VAL 0x3
+
+/* TSEN refers to the temperature sensors within the AP */
+#define CONTROL0_TSEN_START BIT(0)
+#define CONTROL0_TSEN_RESET BIT(1)
+#define CONTROL0_TSEN_ENABLE BIT(2)
+
+/* EXT_TSEN refers to the external temperature sensors, out of the AP */
+#define CONTROL1_EXT_TSEN_SW_RESET BIT(7)
+#define CONTROL1_EXT_TSEN_HW_RESETn BIT(8)
+
+#define STATUS_POLL_PERIOD_US 1000
+#define STATUS_POLL_TIMEOUT_US 100000
struct armada_thermal_data;
/* Marvell EBU Thermal Sensor Dev Structure */
struct armada_thermal_priv {
- void __iomem *sensor;
- void __iomem *control;
+ void __iomem *status;
+ void __iomem *control0;
+ void __iomem *control1;
struct armada_thermal_data *data;
};
@@ -59,107 +82,142 @@ struct armada_thermal_data {
bool (*is_valid)(struct armada_thermal_priv *);
/* Formula coeficients: temp = (b - m * reg) / div */
- unsigned long coef_b;
- unsigned long coef_m;
- unsigned long coef_div;
+ s64 coef_b;
+ s64 coef_m;
+ u32 coef_div;
bool inverted;
+ bool signed_sample;
/* Register shift and mask to access the sensor temperature */
unsigned int temp_shift;
unsigned int temp_mask;
- unsigned int is_valid_shift;
+ u32 is_valid_bit;
+ bool needs_control0;
};
static void armadaxp_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
- unsigned long reg;
+ u32 reg;
- reg = readl_relaxed(priv->control);
+ reg = readl_relaxed(priv->control1);
reg |= PMU_TDC0_OTF_CAL_MASK;
- writel(reg, priv->control);
+ writel(reg, priv->control1);
/* Reference calibration value */
reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
- writel(reg, priv->control);
+ writel(reg, priv->control1);
/* Reset the sensor */
- reg = readl_relaxed(priv->control);
- writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
+ reg = readl_relaxed(priv->control1);
+ writel((reg | PMU_TDC0_SW_RST_MASK), priv->control1);
- writel(reg, priv->control);
+ writel(reg, priv->control1);
/* Enable the sensor */
- reg = readl_relaxed(priv->sensor);
+ reg = readl_relaxed(priv->status);
reg &= ~PMU_TM_DISABLE_MASK;
- writel(reg, priv->sensor);
+ writel(reg, priv->status);
}
static void armada370_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
- unsigned long reg;
+ u32 reg;
- reg = readl_relaxed(priv->control);
+ reg = readl_relaxed(priv->control1);
reg |= PMU_TDC0_OTF_CAL_MASK;
- writel(reg, priv->control);
+ writel(reg, priv->control1);
/* Reference calibration value */
reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
- writel(reg, priv->control);
+ writel(reg, priv->control1);
reg &= ~PMU_TDC0_START_CAL_MASK;
- writel(reg, priv->control);
+ writel(reg, priv->control1);
- mdelay(10);
+ msleep(10);
}
static void armada375_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
- unsigned long reg;
+ u32 reg;
- reg = readl(priv->control + 4);
+ reg = readl(priv->control1);
reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT);
reg &= ~A375_READOUT_INVERT;
reg &= ~A375_HW_RESETn;
- writel(reg, priv->control + 4);
- mdelay(20);
+ writel(reg, priv->control1);
+ msleep(20);
reg |= A375_HW_RESETn;
- writel(reg, priv->control + 4);
- mdelay(50);
+ writel(reg, priv->control1);
+ msleep(50);
+}
+
+static void armada_wait_sensor_validity(struct armada_thermal_priv *priv)
+{
+ u32 reg;
+
+ readl_relaxed_poll_timeout(priv->status, reg,
+ reg & priv->data->is_valid_bit,
+ STATUS_POLL_PERIOD_US,
+ STATUS_POLL_TIMEOUT_US);
}
static void armada380_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
- unsigned long reg = readl_relaxed(priv->control);
-
- /* Reset hardware once */
- if (!(reg & A380_HW_RESET)) {
- reg |= A380_HW_RESET;
- writel(reg, priv->control);
- mdelay(10);
+ u32 reg = readl_relaxed(priv->control1);
+
+ /* Disable the HW/SW reset */
+ reg |= CONTROL1_EXT_TSEN_HW_RESETn;
+ reg &= ~CONTROL1_EXT_TSEN_SW_RESET;
+ writel(reg, priv->control1);
+
+ /* Set Tsen Tc Trim to correct default value (errata #132698) */
+ if (priv->control0) {
+ reg = readl_relaxed(priv->control0);
+ reg &= ~CONTROL0_TSEN_TC_TRIM_MASK;
+ reg |= CONTROL0_TSEN_TC_TRIM_VAL;
+ writel(reg, priv->control0);
}
+
+ /* Wait the sensors to be valid or the core will warn the user */
+ armada_wait_sensor_validity(priv);
+}
+
+static void armada_ap806_init_sensor(struct platform_device *pdev,
+ struct armada_thermal_priv *priv)
+{
+ u32 reg;
+
+ reg = readl_relaxed(priv->control0);
+ reg &= ~CONTROL0_TSEN_RESET;
+ reg |= CONTROL0_TSEN_START | CONTROL0_TSEN_ENABLE;
+ writel(reg, priv->control0);
+
+ /* Wait the sensors to be valid or the core will warn the user */
+ armada_wait_sensor_validity(priv);
}
static bool armada_is_valid(struct armada_thermal_priv *priv)
{
- unsigned long reg = readl_relaxed(priv->sensor);
+ u32 reg = readl_relaxed(priv->status);
- return (reg >> priv->data->is_valid_shift) & THERMAL_VALID_MASK;
+ return reg & priv->data->is_valid_bit;
}
static int armada_get_temp(struct thermal_zone_device *thermal,
- int *temp)
+ int *temp)
{
struct armada_thermal_priv *priv = thermal->devdata;
- unsigned long reg;
- unsigned long m, b, div;
+ u32 reg, div;
+ s64 sample, b, m;
/* Valid check */
if (priv->data->is_valid && !priv->data->is_valid(priv)) {
@@ -168,8 +226,13 @@ static int armada_get_temp(struct thermal_zone_device *thermal,
return -EIO;
}
- reg = readl_relaxed(priv->sensor);
+ reg = readl_relaxed(priv->status);
reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask;
+ if (priv->data->signed_sample)
+ /* The most significant bit is the sign bit */
+ sample = sign_extend32(reg, fls(priv->data->temp_mask) - 1);
+ else
+ sample = reg;
/* Get formula coeficients */
b = priv->data->coef_b;
@@ -177,9 +240,10 @@ static int armada_get_temp(struct thermal_zone_device *thermal,
div = priv->data->coef_div;
if (priv->data->inverted)
- *temp = ((m * reg) - b) / div;
+ *temp = div_s64((m * sample) - b, div);
else
- *temp = (b - (m * reg)) / div;
+ *temp = div_s64(b - (m * sample), div);
+
return 0;
}
@@ -191,45 +255,73 @@ static const struct armada_thermal_data armadaxp_data = {
.init_sensor = armadaxp_init_sensor,
.temp_shift = 10,
.temp_mask = 0x1ff,
- .coef_b = 3153000000UL,
- .coef_m = 10000000UL,
+ .coef_b = 3153000000ULL,
+ .coef_m = 10000000ULL,
.coef_div = 13825,
};
static const struct armada_thermal_data armada370_data = {
.is_valid = armada_is_valid,
.init_sensor = armada370_init_sensor,
- .is_valid_shift = 9,
+ .is_valid_bit = BIT(9),
.temp_shift = 10,
.temp_mask = 0x1ff,
- .coef_b = 3153000000UL,
- .coef_m = 10000000UL,
+ .coef_b = 3153000000ULL,
+ .coef_m = 10000000ULL,
.coef_div = 13825,
};
static const struct armada_thermal_data armada375_data = {
.is_valid = armada_is_valid,
.init_sensor = armada375_init_sensor,
- .is_valid_shift = 10,
+ .is_valid_bit = BIT(10),
.temp_shift = 0,
.temp_mask = 0x1ff,
- .coef_b = 3171900000UL,
- .coef_m = 10000000UL,
+ .coef_b = 3171900000ULL,
+ .coef_m = 10000000ULL,
.coef_div = 13616,
+ .needs_control0 = true,
};
static const struct armada_thermal_data armada380_data = {
.is_valid = armada_is_valid,
.init_sensor = armada380_init_sensor,
- .is_valid_shift = 10,
+ .is_valid_bit = BIT(10),
.temp_shift = 0,
.temp_mask = 0x3ff,
- .coef_b = 1172499100UL,
- .coef_m = 2000096UL,
+ .coef_b = 1172499100ULL,
+ .coef_m = 2000096ULL,
.coef_div = 4201,
.inverted = true,
};
+static const struct armada_thermal_data armada_ap806_data = {
+ .is_valid = armada_is_valid,
+ .init_sensor = armada_ap806_init_sensor,
+ .is_valid_bit = BIT(16),
+ .temp_shift = 0,
+ .temp_mask = 0x3ff,
+ .coef_b = -150000LL,
+ .coef_m = 423ULL,
+ .coef_div = 1,
+ .inverted = true,
+ .signed_sample = true,
+ .needs_control0 = true,
+};
+
+static const struct armada_thermal_data armada_cp110_data = {
+ .is_valid = armada_is_valid,
+ .init_sensor = armada380_init_sensor,
+ .is_valid_bit = BIT(10),
+ .temp_shift = 0,
+ .temp_mask = 0x3ff,
+ .coef_b = 1172499100ULL,
+ .coef_m = 2000096ULL,
+ .coef_div = 4201,
+ .inverted = true,
+ .needs_control0 = true,
+};
+
static const struct of_device_id armada_thermal_id_table[] = {
{
.compatible = "marvell,armadaxp-thermal",
@@ -248,6 +340,14 @@ static const struct of_device_id armada_thermal_id_table[] = {
.data = &armada380_data,
},
{
+ .compatible = "marvell,armada-ap806-thermal",
+ .data = &armada_ap806_data,
+ },
+ {
+ .compatible = "marvell,armada-cp110-thermal",
+ .data = &armada_cp110_data,
+ },
+ {
/* sentinel */
},
};
@@ -255,6 +355,7 @@ MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
static int armada_thermal_probe(struct platform_device *pdev)
{
+ void __iomem *control = NULL;
struct thermal_zone_device *thermal;
const struct of_device_id *match;
struct armada_thermal_priv *priv;
@@ -269,20 +370,40 @@ static int armada_thermal_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->sensor = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->sensor))
- return PTR_ERR(priv->sensor);
+ priv->status = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->status))
+ return PTR_ERR(priv->status);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->control = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->control))
- return PTR_ERR(priv->control);
+ control = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(control))
+ return PTR_ERR(control);
priv->data = (struct armada_thermal_data *)match->data;
+
+ /*
+ * Legacy DT bindings only described "control1" register (also referred
+ * as "control MSB" on old documentation). New bindings cover
+ * "control0/control LSB" and "control1/control MSB" registers within
+ * the same resource, which is then of size 8 instead of 4.
+ */
+ if (resource_size(res) == LEGACY_CONTROL_MEM_LEN) {
+ /* ->control0 unavailable in this configuration */
+ if (priv->data->needs_control0) {
+ dev_err(&pdev->dev, "No access to control0 register\n");
+ return -EINVAL;
+ }
+
+ priv->control1 = control + LEGACY_CONTROL1_OFFSET;
+ } else {
+ priv->control0 = control + CONTROL0_OFFSET;
+ priv->control1 = control + CONTROL1_OFFSET;
+ }
+
priv->data->init_sensor(pdev, priv);
- thermal = thermal_zone_device_register("armada_thermal", 0, 0,
- priv, &ops, NULL, 0, 0);
+ thermal = thermal_zone_device_register(dev_name(&pdev->dev), 0, 0, priv,
+ &ops, NULL, 0, 0);
if (IS_ERR(thermal)) {
dev_err(&pdev->dev,
"Failed to register thermal zone device\n");
@@ -316,5 +437,5 @@ static struct platform_driver armada_thermal_driver = {
module_platform_driver(armada_thermal_driver);
MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
-MODULE_DESCRIPTION("Armada 370/XP thermal driver");
+MODULE_DESCRIPTION("Marvell EBU Armada SoCs thermal driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 2d855a96cdd9..761d0559c268 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -527,7 +527,7 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
static int hisi_thermal_probe(struct platform_device *pdev)
{
struct hisi_thermal_data *data;
- int const (*platform_probe)(struct hisi_thermal_data *);
+ int (*platform_probe)(struct hisi_thermal_data *);
struct device *dev = &pdev->dev;
int ret;
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e7d4ffc3de7f..a67781b7a0b2 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -70,10 +70,6 @@ enum imx_thermal_trip {
#define IMX_POLLING_DELAY 2000 /* millisecond */
#define IMX_PASSIVE_DELAY 1000
-#define FACTOR0 10000000
-#define FACTOR1 15976
-#define FACTOR2 4297157
-
#define TEMPMON_IMX6Q 1
#define TEMPMON_IMX6SX 2
@@ -347,78 +343,74 @@ static struct thermal_zone_device_ops imx_tz_ops = {
.set_trip_temp = imx_set_trip_temp,
};
-static int imx_init_calib(struct platform_device *pdev, u32 val)
+static int imx_init_calib(struct platform_device *pdev, u32 ocotp_ana1)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);
- int t1, n1;
+ int n1;
u64 temp64;
- if (val == 0 || val == ~0) {
+ if (ocotp_ana1 == 0 || ocotp_ana1 == ~0) {
dev_err(&pdev->dev, "invalid sensor calibration data\n");
return -EINVAL;
}
/*
- * Sensor data layout:
- * [31:20] - sensor value @ 25C
- * Use universal formula now and only need sensor value @ 25C
- * slope = 0.4297157 - (0.0015976 * 25C fuse)
+ * The sensor is calibrated at 25 °C (aka T1) and the value measured
+ * (aka N1) at this temperature is provided in bits [31:20] in the
+ * i.MX's OCOTP value ANA1.
+ * To find the actual temperature T, the following formula has to be used
+ * when reading value n from the sensor:
+ *
+ * T = T1 + (N - N1) / (0.4148468 - 0.0015423 * N1) °C + 3.580661 °C
+ * = [T1' - N1 / (0.4148468 - 0.0015423 * N1) °C] + N / (0.4148468 - 0.0015423 * N1) °C
+ * = [T1' + N1 / (0.0015423 * N1 - 0.4148468) °C] - N / (0.0015423 * N1 - 0.4148468) °C
+ * = c2 - c1 * N
+ *
+ * with
+ *
+ * T1' = 28.580661 °C
+ * c1 = 1 / (0.0015423 * N1 - 0.4297157) °C
+ * c2 = T1' + N1 / (0.0015423 * N1 - 0.4148468) °C
+ * = T1' + N1 * c1
*/
- n1 = val >> 20;
- t1 = 25; /* t1 always 25C */
+ n1 = ocotp_ana1 >> 20;
- /*
- * Derived from linear interpolation:
- * slope = 0.4297157 - (0.0015976 * 25C fuse)
- * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
- * (Nmeas - n1) / (Tmeas - t1) = slope
- * We want to reduce this down to the minimum computation necessary
- * for each temperature read. Also, we want Tmeas in millicelsius
- * and we don't want to lose precision from integer division. So...
- * Tmeas = (Nmeas - n1) / slope + t1
- * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1
- * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1
- * Let constant c1 = (-1000 / slope)
- * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1
- * Let constant c2 = n1 *c1 + 1000 * t1
- * milli_Tmeas = c2 - Nmeas * c1
- */
- temp64 = FACTOR0;
- temp64 *= 1000;
- do_div(temp64, FACTOR1 * n1 - FACTOR2);
+ temp64 = 10000000; /* use 10^7 as fixed point constant for values in formula */
+ temp64 *= 1000; /* to get result in °mC */
+ do_div(temp64, 15423 * n1 - 4148468);
data->c1 = temp64;
- data->c2 = n1 * data->c1 + 1000 * t1;
+ data->c2 = n1 * data->c1 + 28581;
return 0;
}
-static void imx_init_temp_grade(struct platform_device *pdev, u32 val)
+static void imx_init_temp_grade(struct platform_device *pdev, u32 ocotp_mem0)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);
/* The maximum die temp is specified by the Temperature Grade */
- switch ((val >> 6) & 0x3) {
- case 0: /* Commercial (0 to 95C) */
+ switch ((ocotp_mem0 >> 6) & 0x3) {
+ case 0: /* Commercial (0 to 95 °C) */
data->temp_grade = "Commercial";
data->temp_max = 95000;
break;
- case 1: /* Extended Commercial (-20 to 105C) */
+ case 1: /* Extended Commercial (-20 °C to 105 °C) */
data->temp_grade = "Extended Commercial";
data->temp_max = 105000;
break;
- case 2: /* Industrial (-40 to 105C) */
+ case 2: /* Industrial (-40 °C to 105 °C) */
data->temp_grade = "Industrial";
data->temp_max = 105000;
break;
- case 3: /* Automotive (-40 to 125C) */
+ case 3: /* Automotive (-40 °C to 125 °C) */
data->temp_grade = "Automotive";
data->temp_max = 125000;
break;
}
/*
- * Set the critical trip point at 5C under max
- * Set the passive trip point at 10C under max (can change via sysfs)
+ * Set the critical trip point at 5 °C under max
+ * Set the passive trip point at 10 °C under max (changeable via sysfs)
*/
data->temp_critical = data->temp_max - (1000 * 5);
data->temp_passive = data->temp_max - (1000 * 10);
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
index 8ee38f55c7f3..e26b01c05e82 100644
--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -211,7 +211,7 @@ static void int3400_notify(acpi_handle handle,
thermal_prop);
break;
default:
- dev_err(&priv->adev->dev, "Unsupported event [0x%x]\n", event);
+ /* Ignore unknown notification codes sent to INT3400 device */
break;
}
}
@@ -319,17 +319,21 @@ static int int3400_thermal_probe(struct platform_device *pdev)
result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group);
if (result)
- goto free_zone;
+ goto free_rel_misc;
result = acpi_install_notify_handler(
priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify,
(void *)priv);
if (result)
- goto free_zone;
+ goto free_sysfs;
return 0;
-free_zone:
+free_sysfs:
+ sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
+free_rel_misc:
+ if (!priv->rel_misc_dev_res)
+ acpi_thermal_rel_misc_device_remove(priv->adev->handle);
thermal_zone_device_unregister(priv->thermal);
free_art_trt:
kfree(priv->trts);
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 1e61c09153c9..c75661a3801a 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -32,15 +32,10 @@
#include <linux/types.h>
/* AUXADC Registers */
-#define AUXADC_CON0_V 0x000
-#define AUXADC_CON1_V 0x004
#define AUXADC_CON1_SET_V 0x008
#define AUXADC_CON1_CLR_V 0x00c
#define AUXADC_CON2_V 0x010
#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
-#define AUXADC_MISC_V 0x094
-
-#define AUXADC_CON1_CHANNEL(x) BIT(x)
#define APMIXED_SYS_TS_CON1 0x604
@@ -158,8 +153,6 @@
/* The number of sensing points per bank */
#define MT2712_NUM_SENSORS_PER_ZONE 4
-#define THERMAL_NAME "mtk-thermal"
-
struct mtk_thermal;
struct thermal_bank_cfg {
@@ -765,7 +758,7 @@ static struct platform_driver mtk_thermal_driver = {
.probe = mtk_thermal_probe,
.remove = mtk_thermal_remove,
.driver = {
- .name = THERMAL_NAME,
+ .name = "mtk-thermal",
.of_match_table = mtk_thermal_of_match,
},
};
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d04ec3b9e5ff..e09f0354a4bc 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -30,7 +30,6 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/string.h>
-#include <linux/thermal.h>
#include "thermal_core.h"
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index b4d3116cfdaf..3055f9a12a17 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -523,6 +523,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)
struct thermal_instance *instance;
struct power_allocator_params *params = tz->governor_data;
+ mutex_lock(&tz->lock);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if ((instance->trip != params->trip_max_desired_temperature) ||
(!cdev_is_power_actor(instance->cdev)))
@@ -534,6 +535,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)
mutex_unlock(&instance->cdev->lock);
thermal_cdev_update(instance->cdev);
}
+ mutex_unlock(&tz->lock);
}
/**
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 075db1de5e53..455b58ce2652 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -341,62 +341,6 @@ static int tegra_thermctl_get_temp(void *data, int *out_temp)
return 0;
}
-static int
-thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
- int trip_temp);
-static int
-throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
- struct soctherm_throt_cfg *stc, int trip_temp);
-static struct soctherm_throt_cfg *
-find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name);
-
-static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
-{
- struct tegra_thermctl_zone *zone = data;
- struct thermal_zone_device *tz = zone->tz;
- struct tegra_soctherm *ts = zone->ts;
- const struct tegra_tsensor_group *sg = zone->sg;
- struct device *dev = zone->dev;
- enum thermal_trip_type type;
- int ret;
-
- if (!tz)
- return -EINVAL;
-
- ret = tz->ops->get_trip_type(tz, trip, &type);
- if (ret)
- return ret;
-
- if (type == THERMAL_TRIP_CRITICAL) {
- return thermtrip_program(dev, sg, temp);
- } else if (type == THERMAL_TRIP_HOT) {
- int i;
-
- for (i = 0; i < THROTTLE_SIZE; i++) {
- struct thermal_cooling_device *cdev;
- struct soctherm_throt_cfg *stc;
-
- if (!ts->throt_cfgs[i].init)
- continue;
-
- cdev = ts->throt_cfgs[i].cdev;
- if (get_thermal_instance(tz, cdev, trip))
- stc = find_throttle_cfg_by_name(ts, cdev->type);
- else
- continue;
-
- return throttrip_program(dev, sg, stc, temp);
- }
- }
-
- return 0;
-}
-
-static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
- .get_temp = tegra_thermctl_get_temp,
- .set_trip_temp = tegra_thermctl_set_trip_temp,
-};
-
/**
* enforce_temp_range() - check and enforce temperature range [min, max]
* @trip_temp: the trip temperature to check
@@ -527,6 +471,53 @@ find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name)
return NULL;
}
+static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
+{
+ struct tegra_thermctl_zone *zone = data;
+ struct thermal_zone_device *tz = zone->tz;
+ struct tegra_soctherm *ts = zone->ts;
+ const struct tegra_tsensor_group *sg = zone->sg;
+ struct device *dev = zone->dev;
+ enum thermal_trip_type type;
+ int ret;
+
+ if (!tz)
+ return -EINVAL;
+
+ ret = tz->ops->get_trip_type(tz, trip, &type);
+ if (ret)
+ return ret;
+
+ if (type == THERMAL_TRIP_CRITICAL) {
+ return thermtrip_program(dev, sg, temp);
+ } else if (type == THERMAL_TRIP_HOT) {
+ int i;
+
+ for (i = 0; i < THROTTLE_SIZE; i++) {
+ struct thermal_cooling_device *cdev;
+ struct soctherm_throt_cfg *stc;
+
+ if (!ts->throt_cfgs[i].init)
+ continue;
+
+ cdev = ts->throt_cfgs[i].cdev;
+ if (get_thermal_instance(tz, cdev, trip))
+ stc = find_throttle_cfg_by_name(ts, cdev->type);
+ else
+ continue;
+
+ return throttrip_program(dev, sg, stc, temp);
+ }
+ }
+
+ return 0;
+}
+
+static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
+ .get_temp = tegra_thermctl_get_temp,
+ .set_trip_temp = tegra_thermctl_set_trip_temp,
+};
+
static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
{
int ntrips, i, ret;
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
index 541af5946203..c4a508a124dc 100644
--- a/drivers/thermal/thermal_hwmon.c
+++ b/drivers/thermal/thermal_hwmon.c
@@ -59,14 +59,6 @@ static LIST_HEAD(thermal_hwmon_list);
static DEFINE_MUTEX(thermal_hwmon_list_lock);
static ssize_t
-name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", hwmon->type);
-}
-static DEVICE_ATTR_RO(name);
-
-static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int temperature;
@@ -165,15 +157,12 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
INIT_LIST_HEAD(&hwmon->tz_list);
strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
- hwmon->device = hwmon_device_register(NULL);
+ hwmon->device = hwmon_device_register_with_info(NULL, hwmon->type,
+ hwmon, NULL, NULL);
if (IS_ERR(hwmon->device)) {
result = PTR_ERR(hwmon->device);
goto free_mem;
}
- dev_set_drvdata(hwmon->device, hwmon);
- result = device_create_file(hwmon->device, &dev_attr_name);
- if (result)
- goto free_mem;
register_sys_interface:
temp = kzalloc(sizeof(*temp), GFP_KERNEL);
@@ -222,10 +211,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
free_temp_mem:
kfree(temp);
unregister_name:
- if (new_hwmon_device) {
- device_remove_file(hwmon->device, &dev_attr_name);
+ if (new_hwmon_device)
hwmon_device_unregister(hwmon->device);
- }
free_mem:
if (new_hwmon_device)
kfree(hwmon);
@@ -267,7 +254,6 @@ void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
list_del(&hwmon->node);
mutex_unlock(&thermal_hwmon_list_lock);
- device_remove_file(hwmon->device, &dev_attr_name);
hwmon_device_unregister(hwmon->device);
kfree(hwmon);
}
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index d93eee2f101b..1a6c88b10a39 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -96,12 +96,12 @@ static int pkg_temp_debugfs_init(void)
return -ENOENT;
d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
- (u32 *)&pkg_interrupt_cnt);
+ &pkg_interrupt_cnt);
if (!d)
goto err_out;
d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
- (u32 *)&pkg_work_cnt);
+ &pkg_work_cnt);
if (!d)
goto err_out;
diff --git a/include/asm-generic/qrwlock_types.h b/include/asm-generic/qrwlock_types.h
index 137ecdd16daa..c36f1d5a2572 100644
--- a/include/asm-generic/qrwlock_types.h
+++ b/include/asm-generic/qrwlock_types.h
@@ -3,6 +3,7 @@
#define __ASM_GENERIC_QRWLOCK_TYPES_H
#include <linux/types.h>
+#include <asm/byteorder.h>
#include <asm/spinlock_types.h>
/*
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index e0340ca08d98..b6a29c126cc4 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -393,7 +393,7 @@ extern bool ____wrong_branch_error(void);
branch = !arch_static_branch_jump(&(x)->key, true); \
else \
branch = ____wrong_branch_error(); \
- branch; \
+ likely(branch); \
})
#define static_branch_unlikely(x) \
@@ -405,7 +405,7 @@ extern bool ____wrong_branch_error(void);
branch = arch_static_branch(&(x)->key, false); \
else \
branch = ____wrong_branch_error(); \
- branch; \
+ unlikely(branch); \
})
#else /* !HAVE_JUMP_LABEL */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4c77f39ebd65..5eef6c8e2741 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3228,6 +3228,12 @@ static inline int netif_set_real_num_rx_queues(struct net_device *dev,
}
#endif
+static inline struct netdev_rx_queue *
+__netif_get_rx_queue(struct net_device *dev, unsigned int rxq)
+{
+ return dev->_rx + rxq;
+}
+
#ifdef CONFIG_SYSFS
static inline unsigned int get_netdev_rx_queue_index(
struct netdev_rx_queue *queue)
diff --git a/include/linux/platform_data/mlxcpld-hotplug.h b/include/linux/platform_data/mlxcpld-hotplug.h
deleted file mode 100644
index e4cfcffaa6f4..000000000000
--- a/include/linux/platform_data/mlxcpld-hotplug.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * include/linux/platform_data/mlxcpld-hotplug.h
- * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
-#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
-
-/**
- * struct mlxcpld_hotplug_device - I2C device data:
- * @adapter: I2C device adapter;
- * @client: I2C device client;
- * @brdinfo: device board information;
- * @bus: I2C bus, where device is attached;
- *
- * Structure represents I2C hotplug device static data (board topology) and
- * dynamic data (related kernel objects handles).
- */
-struct mlxcpld_hotplug_device {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- struct i2c_board_info brdinfo;
- u16 bus;
-};
-
-/**
- * struct mlxcpld_hotplug_platform_data - device platform data:
- * @top_aggr_offset: offset of top aggregation interrupt register;
- * @top_aggr_mask: top aggregation interrupt common mask;
- * @top_aggr_psu_mask: top aggregation interrupt PSU mask;
- * @psu_reg_offset: offset of PSU interrupt register;
- * @psu_mask: PSU interrupt mask;
- * @psu_count: number of equipped replaceable PSUs;
- * @psu: pointer to PSU devices data array;
- * @top_aggr_pwr_mask: top aggregation interrupt power mask;
- * @pwr_reg_offset: offset of power interrupt register
- * @pwr_mask: power interrupt mask;
- * @pwr_count: number of power sources;
- * @pwr: pointer to power devices data array;
- * @top_aggr_fan_mask: top aggregation interrupt FAN mask;
- * @fan_reg_offset: offset of FAN interrupt register;
- * @fan_mask: FAN interrupt mask;
- * @fan_count: number of equipped replaceable FANs;
- * @fan: pointer to FAN devices data array;
- *
- * Structure represents board platform data, related to system hotplug events,
- * like FAN, PSU, power cable insertion and removing. This data provides the
- * number of hot-pluggable devices and hardware description for event handling.
- */
-struct mlxcpld_hotplug_platform_data {
- u16 top_aggr_offset;
- u8 top_aggr_mask;
- u8 top_aggr_psu_mask;
- u16 psu_reg_offset;
- u8 psu_mask;
- u8 psu_count;
- struct mlxcpld_hotplug_device *psu;
- u8 top_aggr_pwr_mask;
- u16 pwr_reg_offset;
- u8 pwr_mask;
- u8 pwr_count;
- struct mlxcpld_hotplug_device *pwr;
- u8 top_aggr_fan_mask;
- u16 fan_reg_offset;
- u8 fan_mask;
- u8 fan_count;
- struct mlxcpld_hotplug_device *fan;
-};
-
-#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
new file mode 100644
index 000000000000..fcdc707eab99
--- /dev/null
+++ b/include/linux/platform_data/mlxreg.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
+#define __LINUX_PLATFORM_DATA_MLXREG_H
+
+#define MLXREG_CORE_LABEL_MAX_SIZE 32
+
+/**
+ * struct mlxreg_hotplug_device - I2C device data:
+ *
+ * @adapter: I2C device adapter;
+ * @client: I2C device client;
+ * @brdinfo: device board information;
+ * @nr: I2C device adapter number, to which device is to be attached;
+ *
+ * Structure represents I2C hotplug device static data (board topology) and
+ * dynamic data (related kernel objects handles).
+ */
+struct mlxreg_hotplug_device {
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info *brdinfo;
+ int nr;
+};
+
+/**
+ * struct mlxreg_core_data - attributes control data:
+ *
+ * @label: attribute label;
+ * @label: attribute register offset;
+ * @reg: attribute register;
+ * @mask: attribute access mask;
+ * @mode: access mode;
+ * @bit: attribute effective bit;
+ * @np - pointer to node platform associated with attribute;
+ * @hpdev - hotplug device data;
+ * @health_cntr: dynamic device health indication counter;
+ * @attached: true if device has been attached after good health indication;
+ */
+struct mlxreg_core_data {
+ char label[MLXREG_CORE_LABEL_MAX_SIZE];
+ u32 reg;
+ u32 mask;
+ u32 bit;
+ umode_t mode;
+ struct device_node *np;
+ struct mlxreg_hotplug_device hpdev;
+ u8 health_cntr;
+ bool attached;
+};
+
+/**
+ * struct mlxreg_core_item - same type components controlled by the driver:
+ *
+ * @data: component data;
+ * @aggr_mask: group aggregation mask;
+ * @reg: group interrupt status register;
+ * @mask: group interrupt mask;
+ * @cache: last status value for elements fro the same group;
+ * @count: number of available elements in the group;
+ * @ind: element's index inside the group;
+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
+ * @health: true if device has health indication, false in other case;
+ */
+struct mlxreg_core_item {
+ struct mlxreg_core_data *data;
+ u32 aggr_mask;
+ u32 reg;
+ u32 mask;
+ u32 cache;
+ u8 count;
+ u8 ind;
+ u8 inversed;
+ u8 health;
+};
+
+/**
+ * struct mlxreg_core_platform_data - platform data:
+ *
+ * @led_data: led private data;
+ * @regmap: register map of parent device;
+ * @counter: number of led instances;
+ */
+struct mlxreg_core_platform_data {
+ struct mlxreg_core_data *data;
+ void *regmap;
+ int counter;
+};
+
+/**
+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
+ *
+ * @items: same type components with the hotplug capability;
+ * @irq: platform interrupt number;
+ * @regmap: register map of parent device;
+ * @counter: number of the components with the hotplug capability;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
+ * @cell_low: location of low aggregation interrupt register;
+ * @mask_low: low aggregation interrupt common mask;
+ */
+struct mlxreg_core_hotplug_platform_data {
+ struct mlxreg_core_item *items;
+ int irq;
+ void *regmap;
+ int counter;
+ u32 cell;
+ u32 mask;
+ u32 cell_low;
+ u32 mask_low;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
diff --git a/include/media/dvb_vb2.h b/include/media/dvb_vb2.h
index dda61af7c4cd..01d1202d1a55 100644
--- a/include/media/dvb_vb2.h
+++ b/include/media/dvb_vb2.h
@@ -116,9 +116,9 @@ static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
#define dvb_vb2_is_streaming(ctx) (0)
#define dvb_vb2_fill_buffer(ctx, file, wait) (0)
-static inline unsigned int dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
- struct file *file,
- poll_table *wait)
+static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
+ struct file *file,
+ poll_table *wait)
{
return 0;
}
@@ -169,8 +169,8 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
*
* Implements poll syscall() logic.
*/
-unsigned int dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
- poll_table *wait);
+__poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
+ poll_table *wait);
#endif
/**
diff --git a/include/net/erspan.h b/include/net/erspan.h
index 5daa4866412b..d044aa60cc76 100644
--- a/include/net/erspan.h
+++ b/include/net/erspan.h
@@ -159,13 +159,13 @@ static inline void erspan_build_header(struct sk_buff *skb,
struct ethhdr *eth = (struct ethhdr *)skb->data;
enum erspan_encap_type enc_type;
struct erspan_base_hdr *ershdr;
- struct erspan_metadata *ersmd;
struct qtag_prefix {
__be16 eth_type;
__be16 tci;
} *qp;
u16 vlan_tci = 0;
u8 tos;
+ __be32 *idx;
tos = is_ipv4 ? ip_hdr(skb)->tos :
(ipv6_hdr(skb)->priority << 4) +
@@ -195,8 +195,8 @@ static inline void erspan_build_header(struct sk_buff *skb,
set_session_id(ershdr, id);
/* Build metadata */
- ersmd = (struct erspan_metadata *)(ershdr + 1);
- ersmd->u.index = htonl(index & INDEX_MASK);
+ idx = (__be32 *)(ershdr + 1);
+ *idx = htonl(index & INDEX_MASK);
}
/* ERSPAN GRA: timestamp granularity
@@ -225,7 +225,7 @@ static inline void erspan_build_header_v2(struct sk_buff *skb,
{
struct ethhdr *eth = (struct ethhdr *)skb->data;
struct erspan_base_hdr *ershdr;
- struct erspan_metadata *md;
+ struct erspan_md2 *md2;
struct qtag_prefix {
__be16 eth_type;
__be16 tci;
@@ -261,15 +261,15 @@ static inline void erspan_build_header_v2(struct sk_buff *skb,
set_session_id(ershdr, id);
/* Build metadata */
- md = (struct erspan_metadata *)(ershdr + 1);
- md->u.md2.timestamp = erspan_get_timestamp();
- md->u.md2.sgt = htons(sgt);
- md->u.md2.p = 1;
- md->u.md2.ft = 0;
- md->u.md2.dir = direction;
- md->u.md2.gra = gra;
- md->u.md2.o = 0;
- set_hwid(&md->u.md2, hwid);
+ md2 = (struct erspan_md2 *)(ershdr + 1);
+ md2->timestamp = erspan_get_timestamp();
+ md2->sgt = htons(sgt);
+ md2->p = 1;
+ md2->ft = 0;
+ md2->dir = direction;
+ md2->gra = gra;
+ md2->o = 0;
+ set_hwid(md2, hwid);
}
#endif
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 061fa62958a2..53fbae27b280 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -594,6 +594,7 @@
#define BTN_DPAD_RIGHT 0x223
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
+#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 5f35f93dcab2..29ca9208dcfa 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1576,25 +1576,41 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
__u32 __user *prog_ids, u32 cnt)
{
struct bpf_prog **prog;
- u32 i = 0, id;
-
+ unsigned long err = 0;
+ u32 i = 0, *ids;
+ bool nospc;
+
+ /* users of this function are doing:
+ * cnt = bpf_prog_array_length();
+ * if (cnt > 0)
+ * bpf_prog_array_copy_to_user(..., cnt);
+ * so below kcalloc doesn't need extra cnt > 0 check, but
+ * bpf_prog_array_length() releases rcu lock and
+ * prog array could have been swapped with empty or larger array,
+ * so always copy 'cnt' prog_ids to the user.
+ * In a rare race the user will see zero prog_ids
+ */
+ ids = kcalloc(cnt, sizeof(u32), GFP_USER);
+ if (!ids)
+ return -ENOMEM;
rcu_read_lock();
prog = rcu_dereference(progs)->progs;
for (; *prog; prog++) {
if (*prog == &dummy_bpf_prog.prog)
continue;
- id = (*prog)->aux->id;
- if (copy_to_user(prog_ids + i, &id, sizeof(id))) {
- rcu_read_unlock();
- return -EFAULT;
- }
+ ids[i] = (*prog)->aux->id;
if (++i == cnt) {
prog++;
break;
}
}
+ nospc = !!(*prog);
rcu_read_unlock();
- if (*prog)
+ err = copy_to_user(prog_ids, ids, cnt * sizeof(u32));
+ kfree(ids);
+ if (err)
+ return -EFAULT;
+ if (nospc)
return -ENOSPC;
return 0;
}
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index a86e6687026e..2ced48662c1f 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -151,6 +151,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
{
u32 size = kattr->test.data_size_in;
u32 repeat = kattr->test.repeat;
+ struct netdev_rx_queue *rxqueue;
struct xdp_buff xdp = {};
u32 retval, duration;
void *data;
@@ -165,6 +166,9 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
xdp.data_meta = xdp.data;
xdp.data_end = xdp.data + size;
+ rxqueue = __netif_get_rx_queue(current->nsproxy->net_ns->loopback_dev, 0);
+ xdp.rxq = &rxqueue->xdp_rxq;
+
retval = bpf_test_run(prog, &xdp, repeat, &duration);
if (xdp.data != data + XDP_PACKET_HEADROOM + NET_IP_ALIGN)
size = xdp.data_end - xdp.data;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 6ec670fbbbdd..45d97e9b2759 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -261,6 +261,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
struct ip_tunnel_net *itn;
struct ip_tunnel *tunnel;
const struct iphdr *iph;
+ struct erspan_md2 *md2;
int ver;
int len;
@@ -313,21 +314,14 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
return PACKET_REJECT;
md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
- memcpy(md, pkt_md, sizeof(*md));
md->version = ver;
+ md2 = &md->u.md2;
+ memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
+ ERSPAN_V2_MDSIZE);
info = &tun_dst->u.tun_info;
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
info->options_len = sizeof(*md);
- } else {
- tunnel->erspan_ver = ver;
- if (ver == 1) {
- tunnel->index = ntohl(pkt_md->u.index);
- } else {
- tunnel->dir = pkt_md->u.md2.dir;
- tunnel->hwid = get_hwid(&pkt_md->u.md2);
- }
-
}
skb_reset_mac_header(skb);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 05f070e123e4..3c353125546d 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -505,6 +505,7 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
struct erspan_base_hdr *ershdr;
struct erspan_metadata *pkt_md;
const struct ipv6hdr *ipv6h;
+ struct erspan_md2 *md2;
struct ip6_tnl *tunnel;
u8 ver;
@@ -551,24 +552,16 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
info = &tun_dst->u.tun_info;
md = ip_tunnel_info_opts(info);
-
- memcpy(md, pkt_md, sizeof(*md));
md->version = ver;
+ md2 = &md->u.md2;
+ memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
+ ERSPAN_V2_MDSIZE);
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
info->options_len = sizeof(*md);
ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
} else {
- tunnel->parms.erspan_ver = ver;
-
- if (ver == 1) {
- tunnel->parms.index = ntohl(pkt_md->u.index);
- } else {
- tunnel->parms.dir = pkt_md->u.md2.dir;
- tunnel->parms.hwid = get_hwid(&pkt_md->u.md2);
- }
-
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
}
diff --git a/net/rds/ib.c b/net/rds/ib.c
index b2a5067b4afe..ff0c98096af1 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -345,7 +345,8 @@ static int rds_ib_laddr_check(struct net *net, __be32 addr)
/* Create a CMA ID and try to bind it. This catches both
* IB and iWARP capable NICs.
*/
- cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+ cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler,
+ NULL, RDMA_PS_TCP, IB_QPT_RC);
if (IS_ERR(cm_id))
return PTR_ERR(cm_id);
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index e3c5e390ec23..6311a548046b 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -398,10 +398,12 @@ static int u32_init(struct tcf_proto *tp)
static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
bool free_pf)
{
+ struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
+
tcf_exts_destroy(&n->exts);
tcf_exts_put_net(&n->exts);
- if (n->ht_down)
- n->ht_down->refcnt--;
+ if (ht && --ht->refcnt == 0)
+ kfree(ht);
#ifdef CONFIG_CLS_U32_PERF
if (free_pf)
free_percpu(n->pf);
@@ -659,16 +661,15 @@ static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
hlist_del(&tp_c->hnode);
- for (ht = rtnl_dereference(tp_c->hlist);
- ht;
- ht = rtnl_dereference(ht->next)) {
- ht->refcnt--;
- u32_clear_hnode(tp, ht, extack);
- }
-
while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
+ u32_clear_hnode(tp, ht, extack);
RCU_INIT_POINTER(tp_c->hlist, ht->next);
- kfree_rcu(ht, rcu);
+
+ /* u32_destroy_key() will later free ht for us, if it's
+ * still referenced by some knode
+ */
+ if (--ht->refcnt == 0)
+ kfree_rcu(ht, rcu);
}
idr_destroy(&tp_c->handle_idr);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 5d4c15bf66d2..e35d4f73d2df 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -326,8 +326,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
bdst = ip6_dst_lookup_flow(sk, fl6, final_p);
- if (!IS_ERR(bdst) &&
- ipv6_chk_addr(dev_net(bdst->dev),
+ if (IS_ERR(bdst))
+ continue;
+
+ if (ipv6_chk_addr(dev_net(bdst->dev),
&laddr->a.v6.sin6_addr, bdst->dev, 1)) {
if (!IS_ERR_OR_NULL(dst))
dst_release(dst);
@@ -336,8 +338,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
}
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
- if (matchlen > bmatchlen)
+ if (matchlen > bmatchlen) {
+ dst_release(bdst);
continue;
+ }
if (!IS_ERR_OR_NULL(dst))
dst_release(dst);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 6a38c2503649..91813e686c67 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -514,22 +514,20 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
if (IS_ERR(rt))
continue;
- if (!dst)
- dst = &rt->dst;
-
/* Ensure the src address belongs to the output
* interface.
*/
odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr,
false);
if (!odev || odev->ifindex != fl4->flowi4_oif) {
- if (&rt->dst != dst)
+ if (!dst)
+ dst = &rt->dst;
+ else
dst_release(&rt->dst);
continue;
}
- if (dst != &rt->dst)
- dst_release(dst);
+ dst_release(dst);
dst = &rt->dst;
break;
}
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 64335bb94f9f..ec3fc8d88e87 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -45,7 +45,7 @@ hostprogs-y += xdp_rxq_info
hostprogs-y += syscall_tp
# Libbpf dependencies
-LIBBPF := ../../tools/lib/bpf/bpf.o
+LIBBPF := ../../tools/lib/bpf/bpf.o ../../tools/lib/bpf/nlattr.o
CGROUP_HELPERS := ../../tools/testing/selftests/bpf/cgroup_helpers.o
test_lru_dist-objs := test_lru_dist.o $(LIBBPF)
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 242631aa4ea2..69806d74fa53 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -695,105 +695,3 @@ struct ksym *ksym_search(long key)
return &syms[0];
}
-int set_link_xdp_fd(int ifindex, int fd, __u32 flags)
-{
- struct sockaddr_nl sa;
- int sock, seq = 0, len, ret = -1;
- char buf[4096];
- struct nlattr *nla, *nla_xdp;
- struct {
- struct nlmsghdr nh;
- struct ifinfomsg ifinfo;
- char attrbuf[64];
- } req;
- struct nlmsghdr *nh;
- struct nlmsgerr *err;
-
- memset(&sa, 0, sizeof(sa));
- sa.nl_family = AF_NETLINK;
-
- sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock < 0) {
- printf("open netlink socket: %s\n", strerror(errno));
- return -1;
- }
-
- if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
- printf("bind to netlink: %s\n", strerror(errno));
- goto cleanup;
- }
-
- memset(&req, 0, sizeof(req));
- req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- req.nh.nlmsg_type = RTM_SETLINK;
- req.nh.nlmsg_pid = 0;
- req.nh.nlmsg_seq = ++seq;
- req.ifinfo.ifi_family = AF_UNSPEC;
- req.ifinfo.ifi_index = ifindex;
-
- /* started nested attribute for XDP */
- nla = (struct nlattr *)(((char *)&req)
- + NLMSG_ALIGN(req.nh.nlmsg_len));
- nla->nla_type = NLA_F_NESTED | 43/*IFLA_XDP*/;
- nla->nla_len = NLA_HDRLEN;
-
- /* add XDP fd */
- nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
- nla_xdp->nla_type = 1/*IFLA_XDP_FD*/;
- nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
- memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
- nla->nla_len += nla_xdp->nla_len;
-
- /* if user passed in any flags, add those too */
- if (flags) {
- nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
- nla_xdp->nla_type = 3/*IFLA_XDP_FLAGS*/;
- nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
- memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
- nla->nla_len += nla_xdp->nla_len;
- }
-
- req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
-
- if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
- printf("send to netlink: %s\n", strerror(errno));
- goto cleanup;
- }
-
- len = recv(sock, buf, sizeof(buf), 0);
- if (len < 0) {
- printf("recv from netlink: %s\n", strerror(errno));
- goto cleanup;
- }
-
- for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
- nh = NLMSG_NEXT(nh, len)) {
- if (nh->nlmsg_pid != getpid()) {
- printf("Wrong pid %d, expected %d\n",
- nh->nlmsg_pid, getpid());
- goto cleanup;
- }
- if (nh->nlmsg_seq != seq) {
- printf("Wrong seq %d, expected %d\n",
- nh->nlmsg_seq, seq);
- goto cleanup;
- }
- switch (nh->nlmsg_type) {
- case NLMSG_ERROR:
- err = (struct nlmsgerr *)NLMSG_DATA(nh);
- if (!err->error)
- continue;
- printf("nlmsg error %s\n", strerror(-err->error));
- goto cleanup;
- case NLMSG_DONE:
- break;
- }
- }
-
- ret = 0;
-
-cleanup:
- close(sock);
- return ret;
-}
diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h
index 7d57a4248893..453c200b389b 100644
--- a/samples/bpf/bpf_load.h
+++ b/samples/bpf/bpf_load.h
@@ -61,5 +61,5 @@ struct ksym {
int load_kallsyms(void);
struct ksym *ksym_search(long key);
-int set_link_xdp_fd(int ifindex, int fd, __u32 flags);
+int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
#endif
diff --git a/samples/bpf/tcbpf2_kern.c b/samples/bpf/tcbpf2_kern.c
index f6bbf8f50da3..efdc16d195ff 100644
--- a/samples/bpf/tcbpf2_kern.c
+++ b/samples/bpf/tcbpf2_kern.c
@@ -15,6 +15,7 @@
#include <uapi/linux/tcp.h>
#include <uapi/linux/filter.h>
#include <uapi/linux/pkt_cls.h>
+#include <uapi/linux/erspan.h>
#include <net/ipv6.h>
#include "bpf_helpers.h"
#include "bpf_endian.h"
@@ -35,24 +36,10 @@ struct geneve_opt {
u8 opt_data[8]; /* hard-coded to 8 byte */
};
-struct erspan_md2 {
- __be32 timestamp;
- __be16 sgt;
- __be16 flags;
-};
-
struct vxlan_metadata {
u32 gbp;
};
-struct erspan_metadata {
- union {
- __be32 index;
- struct erspan_md2 md2;
- } u;
- int version;
-};
-
SEC("gre_set_tunnel")
int _gre_set_tunnel(struct __sk_buff *skb)
{
@@ -156,13 +143,15 @@ int _erspan_set_tunnel(struct __sk_buff *skb)
__builtin_memset(&md, 0, sizeof(md));
#ifdef ERSPAN_V1
md.version = 1;
- md.u.index = htonl(123);
+ md.u.index = bpf_htonl(123);
#else
u8 direction = 1;
- u16 hwid = 7;
+ u8 hwid = 7;
md.version = 2;
- md.u.md2.flags = htons((direction << 3) | (hwid << 4));
+ md.u.md2.dir = direction;
+ md.u.md2.hwid = hwid & 0xf;
+ md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
#endif
ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
@@ -207,9 +196,9 @@ int _erspan_get_tunnel(struct __sk_buff *skb)
char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
bpf_trace_printk(fmt2, sizeof(fmt2),
- (ntohs(md.u.md2.flags) >> 3) & 0x1,
- (ntohs(md.u.md2.flags) >> 4) & 0x3f,
- bpf_ntohl(md.u.md2.timestamp));
+ md.u.md2.dir,
+ (md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
+ bpf_ntohl(md.u.md2.timestamp));
#endif
return TC_ACT_OK;
@@ -242,10 +231,12 @@ int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
md.version = 1;
#else
u8 direction = 0;
- u16 hwid = 17;
+ u8 hwid = 17;
md.version = 2;
- md.u.md2.flags = htons((direction << 3) | (hwid << 4));
+ md.u.md2.dir = direction;
+ md.u.md2.hwid = hwid & 0xf;
+ md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
#endif
ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
@@ -290,9 +281,9 @@ int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
bpf_trace_printk(fmt2, sizeof(fmt2),
- (ntohs(md.u.md2.flags) >> 3) & 0x1,
- (ntohs(md.u.md2.flags) >> 4) & 0x3f,
- bpf_ntohl(md.u.md2.timestamp));
+ md.u.md2.dir,
+ (md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
+ bpf_ntohl(md.u.md2.timestamp));
#endif
return TC_ACT_OK;
diff --git a/samples/bpf/test_tunnel_bpf.sh b/samples/bpf/test_tunnel_bpf.sh
index ae7f7c38309b..43ce049996ee 100755
--- a/samples/bpf/test_tunnel_bpf.sh
+++ b/samples/bpf/test_tunnel_bpf.sh
@@ -68,7 +68,7 @@ function add_erspan_tunnel {
ip netns exec at_ns0 \
ip link add dev $DEV_NS type $TYPE seq key 2 \
local 172.16.1.100 remote 172.16.1.200 \
- erspan_ver 2 erspan_dir 1 erspan_hwid 3
+ erspan_ver 2 erspan_dir egress erspan_hwid 3
fi
ip netns exec at_ns0 ip link set dev $DEV_NS up
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
@@ -97,7 +97,7 @@ function add_ip6erspan_tunnel {
ip netns exec at_ns0 \
ip link add dev $DEV_NS type $TYPE seq key 2 \
local ::11 remote ::22 \
- erspan_ver 2 erspan_dir 1 erspan_hwid 7
+ erspan_ver 2 erspan_dir egress erspan_hwid 7
fi
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
ip netns exec at_ns0 ip link set dev $DEV_NS up
diff --git a/samples/bpf/xdp1_user.c b/samples/bpf/xdp1_user.c
index fdaefe91801d..b901ee2b3336 100644
--- a/samples/bpf/xdp1_user.c
+++ b/samples/bpf/xdp1_user.c
@@ -25,7 +25,7 @@ static __u32 xdp_flags;
static void int_exit(int sig)
{
- set_link_xdp_fd(ifindex, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
exit(0);
}
@@ -116,7 +116,7 @@ int main(int argc, char **argv)
signal(SIGINT, int_exit);
signal(SIGTERM, int_exit);
- if (set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
printf("link set xdp fd failed\n");
return 1;
}
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 35fec9fecb57..23744a8aaf21 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -26,7 +26,7 @@ static const char *__doc__ =
/* Wanted to get rid of bpf_load.h and fake-"libbpf.h" (and instead
* use bpf/libbpf.h), but cannot as (currently) needed for XDP
- * attaching to a device via set_link_xdp_fd()
+ * attaching to a device via bpf_set_link_xdp_fd()
*/
#include "libbpf.h"
#include "bpf_load.h"
@@ -67,7 +67,7 @@ static void int_exit(int sig)
"Interrupted: Removing XDP program on ifindex:%d device:%s\n",
ifindex, ifname);
if (ifindex > -1)
- set_link_xdp_fd(ifindex, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
exit(EXIT_OK);
}
@@ -682,7 +682,7 @@ int main(int argc, char **argv)
/* Remove XDP program when program is interrupted */
signal(SIGINT, int_exit);
- if (set_link_xdp_fd(ifindex, prog_fd[prog_num], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex, prog_fd[prog_num], xdp_flags) < 0) {
fprintf(stderr, "link set xdp fd failed\n");
return EXIT_FAIL_XDP;
}
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index 978a532f0748..7eae07d7293e 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -34,9 +34,9 @@ static __u32 xdp_flags;
static void int_exit(int sig)
{
- set_link_xdp_fd(ifindex_in, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex_in, -1, xdp_flags);
if (ifindex_out_xdp_dummy_attached)
- set_link_xdp_fd(ifindex_out, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex_out, -1, xdp_flags);
exit(0);
}
@@ -120,13 +120,13 @@ int main(int argc, char **argv)
return 1;
}
- if (set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) {
printf("ERROR: link set xdp fd failed on %d\n", ifindex_in);
return 1;
}
/* Loading dummy XDP prog on out-device */
- if (set_link_xdp_fd(ifindex_out, prog_fd[1],
+ if (bpf_set_link_xdp_fd(ifindex_out, prog_fd[1],
(xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) {
printf("WARN: link set xdp fd failed on %d\n", ifindex_out);
ifindex_out_xdp_dummy_attached = false;
diff --git a/samples/bpf/xdp_redirect_user.c b/samples/bpf/xdp_redirect_user.c
index 4475d837bf2c..d54e91eb6cbf 100644
--- a/samples/bpf/xdp_redirect_user.c
+++ b/samples/bpf/xdp_redirect_user.c
@@ -33,9 +33,9 @@ static __u32 xdp_flags;
static void int_exit(int sig)
{
- set_link_xdp_fd(ifindex_in, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex_in, -1, xdp_flags);
if (ifindex_out_xdp_dummy_attached)
- set_link_xdp_fd(ifindex_out, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex_out, -1, xdp_flags);
exit(0);
}
@@ -114,13 +114,13 @@ int main(int argc, char **argv)
return 1;
}
- if (set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) {
printf("ERROR: link set xdp fd failed on %d\n", ifindex_in);
return 1;
}
/* Loading dummy XDP prog on out-device */
- if (set_link_xdp_fd(ifindex_out, prog_fd[1],
+ if (bpf_set_link_xdp_fd(ifindex_out, prog_fd[1],
(xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) {
printf("WARN: link set xdp fd failed on %d\n", ifindex_out);
ifindex_out_xdp_dummy_attached = false;
diff --git a/samples/bpf/xdp_router_ipv4_user.c b/samples/bpf/xdp_router_ipv4_user.c
index 916462112d55..6296741c1fbd 100644
--- a/samples/bpf/xdp_router_ipv4_user.c
+++ b/samples/bpf/xdp_router_ipv4_user.c
@@ -37,7 +37,7 @@ static void int_exit(int sig)
int i = 0;
for (i = 0; i < total_ifindex; i++)
- set_link_xdp_fd(ifindex_list[i], -1, flags);
+ bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
exit(0);
}
@@ -49,7 +49,7 @@ static void close_and_exit(int sig)
close(sock_arp);
for (i = 0; i < total_ifindex; i++)
- set_link_xdp_fd(ifindex_list[i], -1, flags);
+ bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
exit(0);
}
@@ -183,7 +183,7 @@ static void read_route(struct nlmsghdr *nh, int nll)
int i = 0;
for (i = 0; i < total_ifindex; i++)
- set_link_xdp_fd(ifindex_list[i], -1, flags);
+ bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
exit(0);
}
assert(bpf_map_update_elem(map_fd[4], &route.iface, &route.iface, 0) == 0);
@@ -633,12 +633,12 @@ int main(int ac, char **argv)
}
}
for (i = 0; i < total_ifindex; i++) {
- if (set_link_xdp_fd(ifindex_list[i], prog_fd[0], flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd[0], flags) < 0) {
printf("link set xdp fd failed\n");
int recovery_index = i;
for (i = 0; i < recovery_index; i++)
- set_link_xdp_fd(ifindex_list[i], -1, flags);
+ bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
return 1;
}
diff --git a/samples/bpf/xdp_rxq_info_user.c b/samples/bpf/xdp_rxq_info_user.c
index 32430e8b3a6a..478d95412de4 100644
--- a/samples/bpf/xdp_rxq_info_user.c
+++ b/samples/bpf/xdp_rxq_info_user.c
@@ -56,7 +56,7 @@ static void int_exit(int sig)
"Interrupted: Removing XDP program on ifindex:%d device:%s\n",
ifindex, ifname);
if (ifindex > -1)
- set_link_xdp_fd(ifindex, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
exit(EXIT_OK);
}
@@ -521,7 +521,7 @@ int main(int argc, char **argv)
/* Remove XDP program when program is interrupted */
signal(SIGINT, int_exit);
- if (set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
fprintf(stderr, "link set xdp fd failed\n");
return EXIT_FAIL_XDP;
}
diff --git a/samples/bpf/xdp_tx_iptunnel_user.c b/samples/bpf/xdp_tx_iptunnel_user.c
index 715cd12eaca5..f0a787268a87 100644
--- a/samples/bpf/xdp_tx_iptunnel_user.c
+++ b/samples/bpf/xdp_tx_iptunnel_user.c
@@ -30,7 +30,7 @@ static __u32 xdp_flags = 0;
static void int_exit(int sig)
{
if (ifindex > -1)
- set_link_xdp_fd(ifindex, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
exit(0);
}
@@ -254,14 +254,14 @@ int main(int argc, char **argv)
}
}
- if (set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
+ if (bpf_set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) {
printf("link set xdp fd failed\n");
return 1;
}
poll_stats(kill_after_s);
- set_link_xdp_fd(ifindex, -1, xdp_flags);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
return 0;
}
diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h
index 61d6049f4c1e..637b7263cb86 100644
--- a/tools/arch/powerpc/include/uapi/asm/kvm.h
+++ b/tools/arch/powerpc/include/uapi/asm/kvm.h
@@ -443,6 +443,31 @@ struct kvm_ppc_rmmu_info {
__u32 ap_encodings[8];
};
+/* For KVM_PPC_GET_CPU_CHAR */
+struct kvm_ppc_cpu_char {
+ __u64 character; /* characteristics of the CPU */
+ __u64 behaviour; /* recommended software behaviour */
+ __u64 character_mask; /* valid bits in character */
+ __u64 behaviour_mask; /* valid bits in behaviour */
+};
+
+/*
+ * Values for character and character_mask.
+ * These are identical to the values used by H_GET_CPU_CHARACTERISTICS.
+ */
+#define KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 (1ULL << 63)
+#define KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED (1ULL << 62)
+#define KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 (1ULL << 61)
+#define KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 (1ULL << 60)
+#define KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV (1ULL << 59)
+#define KVM_PPC_CPU_CHAR_BR_HINT_HONOURED (1ULL << 58)
+#define KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF (1ULL << 57)
+#define KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS (1ULL << 56)
+
+#define KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY (1ULL << 63)
+#define KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR (1ULL << 62)
+#define KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ULL << 61)
+
/* Per-vcpu XICS interrupt controller state */
#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c)
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h
index 38535a57fef8..4cdaa55fabfe 100644
--- a/tools/arch/s390/include/uapi/asm/kvm.h
+++ b/tools/arch/s390/include/uapi/asm/kvm.h
@@ -224,6 +224,7 @@ struct kvm_guest_debug_arch {
#define KVM_SYNC_RICCB (1UL << 7)
#define KVM_SYNC_FPRS (1UL << 8)
#define KVM_SYNC_GSCB (1UL << 9)
+#define KVM_SYNC_BPBC (1UL << 10)
/* length and alignment of the sdnx as a power of two */
#define SDNXC 8
#define SDNXL (1UL << SDNXC)
@@ -247,7 +248,9 @@ struct kvm_sync_regs {
};
__u8 reserved[512]; /* for future vector expansion */
__u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
- __u8 padding1[52]; /* riccb needs to be 64byte aligned */
+ __u8 bpbc : 1; /* bp mode */
+ __u8 reserved2 : 7;
+ __u8 padding1[51]; /* riccb needs to be 64byte aligned */
__u8 riccb[64]; /* runtime instrumentation controls block */
__u8 padding2[192]; /* sdnx needs to be 256byte aligned */
union {
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index 21ac898df2d8..1d9199e1c2ad 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -13,7 +13,7 @@
/*
* Defines x86 CPU feature bits
*/
-#define NCAPINTS 18 /* N 32-bit words worth of info */
+#define NCAPINTS 19 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
/*
@@ -203,12 +203,15 @@
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */
#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */
+#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */
-#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */
-#define X86_FEATURE_AVX512_4VNNIW ( 7*32+16) /* AVX-512 Neural Network Instructions */
-#define X86_FEATURE_AVX512_4FMAPS ( 7*32+17) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */
#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */
+#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */
+
+#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
@@ -243,6 +246,7 @@
#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */
#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */
#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */
+#define X86_FEATURE_INTEL_PT ( 9*32+25) /* Intel Processor Trace */
#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */
#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */
#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */
@@ -268,6 +272,9 @@
#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */
#define X86_FEATURE_IRPERF (13*32+ 1) /* Instructions Retired Count */
#define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* Always save/restore FP error pointers */
+#define X86_FEATURE_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */
+#define X86_FEATURE_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */
+#define X86_FEATURE_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */
/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */
@@ -316,6 +323,13 @@
#define X86_FEATURE_SUCCOR (17*32+ 1) /* Uncorrectable error containment and recovery */
#define X86_FEATURE_SMCA (17*32+ 3) /* Scalable MCA */
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
+#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
+#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
+
/*
* BUG word(s)
*/
@@ -342,5 +356,7 @@
#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */
#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */
#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */
+#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
+#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
#endif /* _ASM_X86_CPUFEATURES_H */
diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h
index b027633e7300..33833d1909af 100644
--- a/tools/arch/x86/include/asm/disabled-features.h
+++ b/tools/arch/x86/include/asm/disabled-features.h
@@ -77,6 +77,7 @@
#define DISABLED_MASK15 0
#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP)
#define DISABLED_MASK17 0
-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define DISABLED_MASK18 0
+#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
#endif /* _ASM_X86_DISABLED_FEATURES_H */
diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h
index d91ba04dd007..fb3a6de7440b 100644
--- a/tools/arch/x86/include/asm/required-features.h
+++ b/tools/arch/x86/include/asm/required-features.h
@@ -106,6 +106,7 @@
#define REQUIRED_MASK15 0
#define REQUIRED_MASK16 (NEED_LA57)
#define REQUIRED_MASK17 0
-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define REQUIRED_MASK18 0
+#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
#endif /* _ASM_X86_REQUIRED_FEATURES_H */
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
new file mode 100644
index 000000000000..8616131e2c61
--- /dev/null
+++ b/tools/include/uapi/linux/if_link.h
@@ -0,0 +1,943 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_IF_LINK_H
+#define _UAPI_LINUX_IF_LINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+/* This struct should be in sync with struct rtnl_link_stats64 */
+struct rtnl_link_stats {
+ __u32 rx_packets; /* total packets received */
+ __u32 tx_packets; /* total packets transmitted */
+ __u32 rx_bytes; /* total bytes received */
+ __u32 tx_bytes; /* total bytes transmitted */
+ __u32 rx_errors; /* bad packets received */
+ __u32 tx_errors; /* packet transmit problems */
+ __u32 rx_dropped; /* no space in linux buffers */
+ __u32 tx_dropped; /* no space available in linux */
+ __u32 multicast; /* multicast packets received */
+ __u32 collisions;
+
+ /* detailed rx_errors: */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors; /* receiver ring buff overflow */
+ __u32 rx_crc_errors; /* recved pkt with crc error */
+ __u32 rx_frame_errors; /* recv'd frame alignment error */
+ __u32 rx_fifo_errors; /* recv'r fifo overrun */
+ __u32 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+
+ __u32 rx_nohandler; /* dropped, no handler found */
+};
+
+/* The main device statistics structure */
+struct rtnl_link_stats64 {
+ __u64 rx_packets; /* total packets received */
+ __u64 tx_packets; /* total packets transmitted */
+ __u64 rx_bytes; /* total bytes received */
+ __u64 tx_bytes; /* total bytes transmitted */
+ __u64 rx_errors; /* bad packets received */
+ __u64 tx_errors; /* packet transmit problems */
+ __u64 rx_dropped; /* no space in linux buffers */
+ __u64 tx_dropped; /* no space available in linux */
+ __u64 multicast; /* multicast packets received */
+ __u64 collisions;
+
+ /* detailed rx_errors: */
+ __u64 rx_length_errors;
+ __u64 rx_over_errors; /* receiver ring buff overflow */
+ __u64 rx_crc_errors; /* recved pkt with crc error */
+ __u64 rx_frame_errors; /* recv'd frame alignment error */
+ __u64 rx_fifo_errors; /* recv'r fifo overrun */
+ __u64 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u64 tx_aborted_errors;
+ __u64 tx_carrier_errors;
+ __u64 tx_fifo_errors;
+ __u64 tx_heartbeat_errors;
+ __u64 tx_window_errors;
+
+ /* for cslip etc */
+ __u64 rx_compressed;
+ __u64 tx_compressed;
+
+ __u64 rx_nohandler; /* dropped, no handler found */
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap {
+ __u64 mem_start;
+ __u64 mem_end;
+ __u64 base_addr;
+ __u16 irq;
+ __u8 dma;
+ __u8 port;
+};
+
+/*
+ * IFLA_AF_SPEC
+ * Contains nested attributes for address family specific attributes.
+ * Each address family may create a attribute with the address family
+ * number as type and create its own attribute structure in it.
+ *
+ * Example:
+ * [IFLA_AF_SPEC] = {
+ * [AF_INET] = {
+ * [IFLA_INET_CONF] = ...,
+ * },
+ * [AF_INET6] = {
+ * [IFLA_INET6_FLAGS] = ...,
+ * [IFLA_INET6_CONF] = ...,
+ * }
+ * }
+ */
+
+enum {
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+ IFLA_PROTINFO, /* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+ IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+ IFLA_OPERSTATE,
+ IFLA_LINKMODE,
+ IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+ IFLA_NET_NS_PID,
+ IFLA_IFALIAS,
+ IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */
+ IFLA_VFINFO_LIST,
+ IFLA_STATS64,
+ IFLA_VF_PORTS,
+ IFLA_PORT_SELF,
+ IFLA_AF_SPEC,
+ IFLA_GROUP, /* Group the device belongs to */
+ IFLA_NET_NS_FD,
+ IFLA_EXT_MASK, /* Extended info mask, VFs, etc */
+ IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */
+#define IFLA_PROMISCUITY IFLA_PROMISCUITY
+ IFLA_NUM_TX_QUEUES,
+ IFLA_NUM_RX_QUEUES,
+ IFLA_CARRIER,
+ IFLA_PHYS_PORT_ID,
+ IFLA_CARRIER_CHANGES,
+ IFLA_PHYS_SWITCH_ID,
+ IFLA_LINK_NETNSID,
+ IFLA_PHYS_PORT_NAME,
+ IFLA_PROTO_DOWN,
+ IFLA_GSO_MAX_SEGS,
+ IFLA_GSO_MAX_SIZE,
+ IFLA_PAD,
+ IFLA_XDP,
+ IFLA_EVENT,
+ IFLA_NEW_NETNSID,
+ IFLA_IF_NETNSID,
+ IFLA_CARRIER_UP_COUNT,
+ IFLA_CARRIER_DOWN_COUNT,
+ __IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+/* backwards compatibility for userspace */
+#ifndef __KERNEL__
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+#endif
+
+enum {
+ IFLA_INET_UNSPEC,
+ IFLA_INET_CONF,
+ __IFLA_INET_MAX,
+};
+
+#define IFLA_INET_MAX (__IFLA_INET_MAX - 1)
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neither of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum {
+ IFLA_INET6_UNSPEC,
+ IFLA_INET6_FLAGS, /* link flags */
+ IFLA_INET6_CONF, /* sysctl parameters */
+ IFLA_INET6_STATS, /* statistics */
+ IFLA_INET6_MCAST, /* MC things. What of them? */
+ IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
+ IFLA_INET6_TOKEN, /* device token */
+ IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
+ __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+enum in6_addr_gen_mode {
+ IN6_ADDR_GEN_MODE_EUI64,
+ IN6_ADDR_GEN_MODE_NONE,
+ IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
+ IN6_ADDR_GEN_MODE_RANDOM,
+};
+
+/* Bridge section */
+
+enum {
+ IFLA_BR_UNSPEC,
+ IFLA_BR_FORWARD_DELAY,
+ IFLA_BR_HELLO_TIME,
+ IFLA_BR_MAX_AGE,
+ IFLA_BR_AGEING_TIME,
+ IFLA_BR_STP_STATE,
+ IFLA_BR_PRIORITY,
+ IFLA_BR_VLAN_FILTERING,
+ IFLA_BR_VLAN_PROTOCOL,
+ IFLA_BR_GROUP_FWD_MASK,
+ IFLA_BR_ROOT_ID,
+ IFLA_BR_BRIDGE_ID,
+ IFLA_BR_ROOT_PORT,
+ IFLA_BR_ROOT_PATH_COST,
+ IFLA_BR_TOPOLOGY_CHANGE,
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+ IFLA_BR_HELLO_TIMER,
+ IFLA_BR_TCN_TIMER,
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+ IFLA_BR_GC_TIMER,
+ IFLA_BR_GROUP_ADDR,
+ IFLA_BR_FDB_FLUSH,
+ IFLA_BR_MCAST_ROUTER,
+ IFLA_BR_MCAST_SNOOPING,
+ IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ IFLA_BR_MCAST_QUERIER,
+ IFLA_BR_MCAST_HASH_ELASTICITY,
+ IFLA_BR_MCAST_HASH_MAX,
+ IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ IFLA_BR_MCAST_QUERIER_INTVL,
+ IFLA_BR_MCAST_QUERY_INTVL,
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+ IFLA_BR_NF_CALL_IPTABLES,
+ IFLA_BR_NF_CALL_IP6TABLES,
+ IFLA_BR_NF_CALL_ARPTABLES,
+ IFLA_BR_VLAN_DEFAULT_PVID,
+ IFLA_BR_PAD,
+ IFLA_BR_VLAN_STATS_ENABLED,
+ IFLA_BR_MCAST_STATS_ENABLED,
+ IFLA_BR_MCAST_IGMP_VERSION,
+ IFLA_BR_MCAST_MLD_VERSION,
+ __IFLA_BR_MAX,
+};
+
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+
+struct ifla_bridge_id {
+ __u8 prio[2];
+ __u8 addr[6]; /* ETH_ALEN */
+};
+
+enum {
+ BRIDGE_MODE_UNSPEC,
+ BRIDGE_MODE_HAIRPIN,
+};
+
+enum {
+ IFLA_BRPORT_UNSPEC,
+ IFLA_BRPORT_STATE, /* Spanning tree state */
+ IFLA_BRPORT_PRIORITY, /* " priority */
+ IFLA_BRPORT_COST, /* " cost */
+ IFLA_BRPORT_MODE, /* mode (hairpin) */
+ IFLA_BRPORT_GUARD, /* bpdu guard */
+ IFLA_BRPORT_PROTECT, /* root port protection */
+ IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
+ IFLA_BRPORT_LEARNING, /* mac learning */
+ IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
+ IFLA_BRPORT_PROXYARP, /* proxy ARP */
+ IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
+ IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
+ IFLA_BRPORT_ROOT_ID, /* designated root */
+ IFLA_BRPORT_BRIDGE_ID, /* designated bridge */
+ IFLA_BRPORT_DESIGNATED_PORT,
+ IFLA_BRPORT_DESIGNATED_COST,
+ IFLA_BRPORT_ID,
+ IFLA_BRPORT_NO,
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
+ IFLA_BRPORT_CONFIG_PENDING,
+ IFLA_BRPORT_MESSAGE_AGE_TIMER,
+ IFLA_BRPORT_FORWARD_DELAY_TIMER,
+ IFLA_BRPORT_HOLD_TIMER,
+ IFLA_BRPORT_FLUSH,
+ IFLA_BRPORT_MULTICAST_ROUTER,
+ IFLA_BRPORT_PAD,
+ IFLA_BRPORT_MCAST_FLOOD,
+ IFLA_BRPORT_MCAST_TO_UCAST,
+ IFLA_BRPORT_VLAN_TUNNEL,
+ IFLA_BRPORT_BCAST_FLOOD,
+ IFLA_BRPORT_GROUP_FWD_MASK,
+ IFLA_BRPORT_NEIGH_SUPPRESS,
+ __IFLA_BRPORT_MAX
+};
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+
+struct ifla_cacheinfo {
+ __u32 max_reasm_len;
+ __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
+ __u32 reachable_time;
+ __u32 retrans_time;
+};
+
+enum {
+ IFLA_INFO_UNSPEC,
+ IFLA_INFO_KIND,
+ IFLA_INFO_DATA,
+ IFLA_INFO_XSTATS,
+ IFLA_INFO_SLAVE_KIND,
+ IFLA_INFO_SLAVE_DATA,
+ __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum {
+ IFLA_VLAN_UNSPEC,
+ IFLA_VLAN_ID,
+ IFLA_VLAN_FLAGS,
+ IFLA_VLAN_EGRESS_QOS,
+ IFLA_VLAN_INGRESS_QOS,
+ IFLA_VLAN_PROTOCOL,
+ __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+enum {
+ IFLA_VLAN_QOS_UNSPEC,
+ IFLA_VLAN_QOS_MAPPING,
+ __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping {
+ __u32 from;
+ __u32 to;
+};
+
+/* MACVLAN section */
+enum {
+ IFLA_MACVLAN_UNSPEC,
+ IFLA_MACVLAN_MODE,
+ IFLA_MACVLAN_FLAGS,
+ IFLA_MACVLAN_MACADDR_MODE,
+ IFLA_MACVLAN_MACADDR,
+ IFLA_MACVLAN_MACADDR_DATA,
+ IFLA_MACVLAN_MACADDR_COUNT,
+ __IFLA_MACVLAN_MAX,
+};
+
+#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
+
+enum macvlan_mode {
+ MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
+ MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
+ MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
+ MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
+ MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */
+};
+
+enum macvlan_macaddr_mode {
+ MACVLAN_MACADDR_ADD,
+ MACVLAN_MACADDR_DEL,
+ MACVLAN_MACADDR_FLUSH,
+ MACVLAN_MACADDR_SET,
+};
+
+#define MACVLAN_FLAG_NOPROMISC 1
+
+/* VRF section */
+enum {
+ IFLA_VRF_UNSPEC,
+ IFLA_VRF_TABLE,
+ __IFLA_VRF_MAX
+};
+
+#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1)
+
+enum {
+ IFLA_VRF_PORT_UNSPEC,
+ IFLA_VRF_PORT_TABLE,
+ __IFLA_VRF_PORT_MAX
+};
+
+#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1)
+
+/* MACSEC section */
+enum {
+ IFLA_MACSEC_UNSPEC,
+ IFLA_MACSEC_SCI,
+ IFLA_MACSEC_PORT,
+ IFLA_MACSEC_ICV_LEN,
+ IFLA_MACSEC_CIPHER_SUITE,
+ IFLA_MACSEC_WINDOW,
+ IFLA_MACSEC_ENCODING_SA,
+ IFLA_MACSEC_ENCRYPT,
+ IFLA_MACSEC_PROTECT,
+ IFLA_MACSEC_INC_SCI,
+ IFLA_MACSEC_ES,
+ IFLA_MACSEC_SCB,
+ IFLA_MACSEC_REPLAY_PROTECT,
+ IFLA_MACSEC_VALIDATION,
+ IFLA_MACSEC_PAD,
+ __IFLA_MACSEC_MAX,
+};
+
+#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1)
+
+enum macsec_validation_type {
+ MACSEC_VALIDATE_DISABLED = 0,
+ MACSEC_VALIDATE_CHECK = 1,
+ MACSEC_VALIDATE_STRICT = 2,
+ __MACSEC_VALIDATE_END,
+ MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+};
+
+/* IPVLAN section */
+enum {
+ IFLA_IPVLAN_UNSPEC,
+ IFLA_IPVLAN_MODE,
+ IFLA_IPVLAN_FLAGS,
+ __IFLA_IPVLAN_MAX
+};
+
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+
+enum ipvlan_mode {
+ IPVLAN_MODE_L2 = 0,
+ IPVLAN_MODE_L3,
+ IPVLAN_MODE_L3S,
+ IPVLAN_MODE_MAX
+};
+
+#define IPVLAN_F_PRIVATE 0x01
+#define IPVLAN_F_VEPA 0x02
+
+/* VXLAN section */
+enum {
+ IFLA_VXLAN_UNSPEC,
+ IFLA_VXLAN_ID,
+ IFLA_VXLAN_GROUP, /* group or remote address */
+ IFLA_VXLAN_LINK,
+ IFLA_VXLAN_LOCAL,
+ IFLA_VXLAN_TTL,
+ IFLA_VXLAN_TOS,
+ IFLA_VXLAN_LEARNING,
+ IFLA_VXLAN_AGEING,
+ IFLA_VXLAN_LIMIT,
+ IFLA_VXLAN_PORT_RANGE, /* source port */
+ IFLA_VXLAN_PROXY,
+ IFLA_VXLAN_RSC,
+ IFLA_VXLAN_L2MISS,
+ IFLA_VXLAN_L3MISS,
+ IFLA_VXLAN_PORT, /* destination port */
+ IFLA_VXLAN_GROUP6,
+ IFLA_VXLAN_LOCAL6,
+ IFLA_VXLAN_UDP_CSUM,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
+ IFLA_VXLAN_REMCSUM_TX,
+ IFLA_VXLAN_REMCSUM_RX,
+ IFLA_VXLAN_GBP,
+ IFLA_VXLAN_REMCSUM_NOPARTIAL,
+ IFLA_VXLAN_COLLECT_METADATA,
+ IFLA_VXLAN_LABEL,
+ IFLA_VXLAN_GPE,
+ __IFLA_VXLAN_MAX
+};
+#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
+
+struct ifla_vxlan_port_range {
+ __be16 low;
+ __be16 high;
+};
+
+/* GENEVE section */
+enum {
+ IFLA_GENEVE_UNSPEC,
+ IFLA_GENEVE_ID,
+ IFLA_GENEVE_REMOTE,
+ IFLA_GENEVE_TTL,
+ IFLA_GENEVE_TOS,
+ IFLA_GENEVE_PORT, /* destination port */
+ IFLA_GENEVE_COLLECT_METADATA,
+ IFLA_GENEVE_REMOTE6,
+ IFLA_GENEVE_UDP_CSUM,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+ IFLA_GENEVE_LABEL,
+ __IFLA_GENEVE_MAX
+};
+#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
+
+/* PPP section */
+enum {
+ IFLA_PPP_UNSPEC,
+ IFLA_PPP_DEV_FD,
+ __IFLA_PPP_MAX
+};
+#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1)
+
+/* GTP section */
+
+enum ifla_gtp_role {
+ GTP_ROLE_GGSN = 0,
+ GTP_ROLE_SGSN,
+};
+
+enum {
+ IFLA_GTP_UNSPEC,
+ IFLA_GTP_FD0,
+ IFLA_GTP_FD1,
+ IFLA_GTP_PDP_HASHSIZE,
+ IFLA_GTP_ROLE,
+ __IFLA_GTP_MAX,
+};
+#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
+
+/* Bonding section */
+
+enum {
+ IFLA_BOND_UNSPEC,
+ IFLA_BOND_MODE,
+ IFLA_BOND_ACTIVE_SLAVE,
+ IFLA_BOND_MIIMON,
+ IFLA_BOND_UPDELAY,
+ IFLA_BOND_DOWNDELAY,
+ IFLA_BOND_USE_CARRIER,
+ IFLA_BOND_ARP_INTERVAL,
+ IFLA_BOND_ARP_IP_TARGET,
+ IFLA_BOND_ARP_VALIDATE,
+ IFLA_BOND_ARP_ALL_TARGETS,
+ IFLA_BOND_PRIMARY,
+ IFLA_BOND_PRIMARY_RESELECT,
+ IFLA_BOND_FAIL_OVER_MAC,
+ IFLA_BOND_XMIT_HASH_POLICY,
+ IFLA_BOND_RESEND_IGMP,
+ IFLA_BOND_NUM_PEER_NOTIF,
+ IFLA_BOND_ALL_SLAVES_ACTIVE,
+ IFLA_BOND_MIN_LINKS,
+ IFLA_BOND_LP_INTERVAL,
+ IFLA_BOND_PACKETS_PER_SLAVE,
+ IFLA_BOND_AD_LACP_RATE,
+ IFLA_BOND_AD_SELECT,
+ IFLA_BOND_AD_INFO,
+ IFLA_BOND_AD_ACTOR_SYS_PRIO,
+ IFLA_BOND_AD_USER_PORT_KEY,
+ IFLA_BOND_AD_ACTOR_SYSTEM,
+ IFLA_BOND_TLB_DYNAMIC_LB,
+ __IFLA_BOND_MAX,
+};
+
+#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
+
+enum {
+ IFLA_BOND_AD_INFO_UNSPEC,
+ IFLA_BOND_AD_INFO_AGGREGATOR,
+ IFLA_BOND_AD_INFO_NUM_PORTS,
+ IFLA_BOND_AD_INFO_ACTOR_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_MAC,
+ __IFLA_BOND_AD_INFO_MAX,
+};
+
+#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1)
+
+enum {
+ IFLA_BOND_SLAVE_UNSPEC,
+ IFLA_BOND_SLAVE_STATE,
+ IFLA_BOND_SLAVE_MII_STATUS,
+ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT,
+ IFLA_BOND_SLAVE_PERM_HWADDR,
+ IFLA_BOND_SLAVE_QUEUE_ID,
+ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+ __IFLA_BOND_SLAVE_MAX,
+};
+
+#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1)
+
+/* SR-IOV virtual function management section */
+
+enum {
+ IFLA_VF_INFO_UNSPEC,
+ IFLA_VF_INFO,
+ __IFLA_VF_INFO_MAX,
+};
+
+#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1)
+
+enum {
+ IFLA_VF_UNSPEC,
+ IFLA_VF_MAC, /* Hardware queue specific attributes */
+ IFLA_VF_VLAN, /* VLAN ID and QoS */
+ IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */
+ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
+ IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */
+ IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */
+ IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query
+ * on/off switch
+ */
+ IFLA_VF_STATS, /* network device statistics */
+ IFLA_VF_TRUST, /* Trust VF */
+ IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
+ IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
+ IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
+ __IFLA_VF_MAX,
+};
+
+#define IFLA_VF_MAX (__IFLA_VF_MAX - 1)
+
+struct ifla_vf_mac {
+ __u32 vf;
+ __u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_vlan {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+};
+
+enum {
+ IFLA_VF_VLAN_INFO_UNSPEC,
+ IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */
+ __IFLA_VF_VLAN_INFO_MAX,
+};
+
+#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1)
+#define MAX_VLAN_LIST_LEN 1
+
+struct ifla_vf_vlan_info {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+ __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
+};
+
+struct ifla_vf_tx_rate {
+ __u32 vf;
+ __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_rate {
+ __u32 vf;
+ __u32 min_tx_rate; /* Min Bandwidth in Mbps */
+ __u32 max_tx_rate; /* Max Bandwidth in Mbps */
+};
+
+struct ifla_vf_spoofchk {
+ __u32 vf;
+ __u32 setting;
+};
+
+struct ifla_vf_guid {
+ __u32 vf;
+ __u64 guid;
+};
+
+enum {
+ IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */
+ IFLA_VF_LINK_STATE_ENABLE, /* link always up */
+ IFLA_VF_LINK_STATE_DISABLE, /* link always down */
+ __IFLA_VF_LINK_STATE_MAX,
+};
+
+struct ifla_vf_link_state {
+ __u32 vf;
+ __u32 link_state;
+};
+
+struct ifla_vf_rss_query_en {
+ __u32 vf;
+ __u32 setting;
+};
+
+enum {
+ IFLA_VF_STATS_RX_PACKETS,
+ IFLA_VF_STATS_TX_PACKETS,
+ IFLA_VF_STATS_RX_BYTES,
+ IFLA_VF_STATS_TX_BYTES,
+ IFLA_VF_STATS_BROADCAST,
+ IFLA_VF_STATS_MULTICAST,
+ IFLA_VF_STATS_PAD,
+ IFLA_VF_STATS_RX_DROPPED,
+ IFLA_VF_STATS_TX_DROPPED,
+ __IFLA_VF_STATS_MAX,
+};
+
+#define IFLA_VF_STATS_MAX (__IFLA_VF_STATS_MAX - 1)
+
+struct ifla_vf_trust {
+ __u32 vf;
+ __u32 setting;
+};
+
+/* VF ports management section
+ *
+ * Nested layout of set/get msg is:
+ *
+ * [IFLA_NUM_VF]
+ * [IFLA_VF_PORTS]
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * ...
+ * [IFLA_PORT_SELF]
+ * [IFLA_PORT_*], ...
+ */
+
+enum {
+ IFLA_VF_PORT_UNSPEC,
+ IFLA_VF_PORT, /* nest */
+ __IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+ IFLA_PORT_UNSPEC,
+ IFLA_PORT_VF, /* __u32 */
+ IFLA_PORT_PROFILE, /* string */
+ IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */
+ IFLA_PORT_INSTANCE_UUID, /* binary UUID */
+ IFLA_PORT_HOST_UUID, /* binary UUID */
+ IFLA_PORT_REQUEST, /* __u8 */
+ IFLA_PORT_RESPONSE, /* __u16, output only */
+ __IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX 40
+#define PORT_UUID_MAX 16
+#define PORT_SELF_VF -1
+
+enum {
+ PORT_REQUEST_PREASSOCIATE = 0,
+ PORT_REQUEST_PREASSOCIATE_RR,
+ PORT_REQUEST_ASSOCIATE,
+ PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+ PORT_VDP_RESPONSE_SUCCESS = 0,
+ PORT_VDP_RESPONSE_INVALID_FORMAT,
+ PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_VDP_RESPONSE_UNUSED_VTID,
+ PORT_VDP_RESPONSE_VTID_VIOLATION,
+ PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+ PORT_VDP_RESPONSE_OUT_OF_SYNC,
+ /* 0x08-0xFF reserved for future VDP use */
+ PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+ PORT_PROFILE_RESPONSE_INPROGRESS,
+ PORT_PROFILE_RESPONSE_INVALID,
+ PORT_PROFILE_RESPONSE_BADSTATE,
+ PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+ __u8 vsi_mgr_id;
+ __u8 vsi_type_id[3];
+ __u8 vsi_type_version;
+ __u8 pad[3];
+};
+
+
+/* IPoIB section */
+
+enum {
+ IFLA_IPOIB_UNSPEC,
+ IFLA_IPOIB_PKEY,
+ IFLA_IPOIB_MODE,
+ IFLA_IPOIB_UMCAST,
+ __IFLA_IPOIB_MAX
+};
+
+enum {
+ IPOIB_MODE_DATAGRAM = 0, /* using unreliable datagram QPs */
+ IPOIB_MODE_CONNECTED = 1, /* using connected QPs */
+};
+
+#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
+
+
+/* HSR section */
+
+enum {
+ IFLA_HSR_UNSPEC,
+ IFLA_HSR_SLAVE1,
+ IFLA_HSR_SLAVE2,
+ IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */
+ IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */
+ IFLA_HSR_SEQ_NR,
+ IFLA_HSR_VERSION, /* HSR version */
+ __IFLA_HSR_MAX,
+};
+
+#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
+
+/* STATS section */
+
+struct if_stats_msg {
+ __u8 family;
+ __u8 pad1;
+ __u16 pad2;
+ __u32 ifindex;
+ __u32 filter_mask;
+};
+
+/* A stats attribute can be netdev specific or a global stat.
+ * For netdev stats, lets use the prefix IFLA_STATS_LINK_*
+ */
+enum {
+ IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
+ IFLA_STATS_LINK_64,
+ IFLA_STATS_LINK_XSTATS,
+ IFLA_STATS_LINK_XSTATS_SLAVE,
+ IFLA_STATS_LINK_OFFLOAD_XSTATS,
+ IFLA_STATS_AF_SPEC,
+ __IFLA_STATS_MAX,
+};
+
+#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1)
+
+#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1))
+
+/* These are embedded into IFLA_STATS_LINK_XSTATS:
+ * [IFLA_STATS_LINK_XSTATS]
+ * -> [LINK_XSTATS_TYPE_xxx]
+ * -> [rtnl link type specific attributes]
+ */
+enum {
+ LINK_XSTATS_TYPE_UNSPEC,
+ LINK_XSTATS_TYPE_BRIDGE,
+ __LINK_XSTATS_TYPE_MAX
+};
+#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
+
+/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */
+enum {
+ IFLA_OFFLOAD_XSTATS_UNSPEC,
+ IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
+ __IFLA_OFFLOAD_XSTATS_MAX
+};
+#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
+
+/* XDP section */
+
+#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
+#define XDP_FLAGS_SKB_MODE (1U << 1)
+#define XDP_FLAGS_DRV_MODE (1U << 2)
+#define XDP_FLAGS_HW_MODE (1U << 3)
+#define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \
+ XDP_FLAGS_DRV_MODE | \
+ XDP_FLAGS_HW_MODE)
+#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \
+ XDP_FLAGS_MODES)
+
+/* These are stored into IFLA_XDP_ATTACHED on dump. */
+enum {
+ XDP_ATTACHED_NONE = 0,
+ XDP_ATTACHED_DRV,
+ XDP_ATTACHED_SKB,
+ XDP_ATTACHED_HW,
+};
+
+enum {
+ IFLA_XDP_UNSPEC,
+ IFLA_XDP_FD,
+ IFLA_XDP_ATTACHED,
+ IFLA_XDP_FLAGS,
+ IFLA_XDP_PROG_ID,
+ __IFLA_XDP_MAX,
+};
+
+#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1)
+
+enum {
+ IFLA_EVENT_NONE,
+ IFLA_EVENT_REBOOT, /* internal reset / reboot */
+ IFLA_EVENT_FEATURES, /* change in offload features */
+ IFLA_EVENT_BONDING_FAILOVER, /* change in active slave */
+ IFLA_EVENT_NOTIFY_PEERS, /* re-sent grat. arp/ndisc */
+ IFLA_EVENT_IGMP_RESEND, /* re-sent IGMP JOIN */
+ IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */
+};
+
+#endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 496e59a2738b..8fb90a0819c3 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -932,6 +932,8 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_HYPERV_SYNIC2 148
#define KVM_CAP_HYPERV_VP_INDEX 149
#define KVM_CAP_S390_AIS_MIGRATION 150
+#define KVM_CAP_PPC_GET_CPU_CHAR 151
+#define KVM_CAP_S390_BPB 152
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1261,6 +1263,8 @@ struct kvm_s390_ucas_mapping {
#define KVM_PPC_CONFIGURE_V3_MMU _IOW(KVMIO, 0xaf, struct kvm_ppc_mmuv3_cfg)
/* Available with KVM_CAP_PPC_RADIX_MMU */
#define KVM_PPC_GET_RMMU_INFO _IOW(KVMIO, 0xb0, struct kvm_ppc_rmmu_info)
+/* Available with KVM_CAP_PPC_GET_CPU_CHAR */
+#define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
diff --git a/tools/include/uapi/linux/netlink.h b/tools/include/uapi/linux/netlink.h
new file mode 100644
index 000000000000..776bc92e9118
--- /dev/null
+++ b/tools/include/uapi/linux/netlink.h
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__LINUX_NETLINK_H
+#define _UAPI__LINUX_NETLINK_H
+
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_UNUSED 1 /* Unused number */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
+#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_SELINUX 7 /* SELinux event notifications */
+#define NETLINK_ISCSI 8 /* Open-iSCSI */
+#define NETLINK_AUDIT 9 /* auditing */
+#define NETLINK_FIB_LOOKUP 10
+#define NETLINK_CONNECTOR 11
+#define NETLINK_NETFILTER 12 /* netfilter subsystem */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
+#define NETLINK_GENERIC 16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+#define NETLINK_ECRYPTFS 19
+#define NETLINK_RDMA 20
+#define NETLINK_CRYPTO 21 /* Crypto layer */
+#define NETLINK_SMC 22 /* SMC monitoring */
+
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl {
+ __kernel_sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ __u32 nl_pid; /* port ID */
+ __u32 nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr {
+ __u32 nlmsg_len; /* Length of message including header */
+ __u16 nlmsg_type; /* Message content */
+ __u16 nlmsg_flags; /* Additional flags */
+ __u32 nlmsg_seq; /* Sequence number */
+ __u32 nlmsg_pid; /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 0x01 /* It is request message. */
+#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 0x08 /* Echo this request */
+#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+ int error;
+ struct nlmsghdr msg;
+ /*
+ * followed by the message contents unless NETLINK_CAP_ACK was set
+ * or the ACK indicates success (error == 0)
+ * message length is aligned with NLMSG_ALIGN()
+ */
+ /*
+ * followed by TLVs defined in enum nlmsgerr_attrs
+ * if NETLINK_EXT_ACK was set
+ */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ * message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
+#ifndef __KERNEL__
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+#endif
+#define NETLINK_LISTEN_ALL_NSID 8
+#define NETLINK_LIST_MEMBERSHIPS 9
+#define NETLINK_CAP_ACK 10
+#define NETLINK_EXT_ACK 11
+
+struct nl_pktinfo {
+ __u32 group;
+};
+
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+#ifndef __KERNEL__
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+#endif
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+
+enum {
+ NETLINK_UNCONNECTED = 0,
+ NETLINK_CONNECTED,
+};
+
+/*
+ * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * | Header | Pad | Payload | Pad |
+ * | (struct nlattr) | ing | | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+ __u16 nla_len;
+ __u16 nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO 4
+#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ * value = 0x0, and selector = 0x1
+ * implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ * value = 0x2, and selector = 0x2
+ * implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+ __u32 value;
+ __u32 selector;
+};
+
+#endif /* _UAPI__LINUX_NETLINK_H */
diff --git a/tools/include/uapi/linux/sched.h b/tools/include/uapi/linux/sched.h
index 30a9e51bbb1e..22627f80063e 100644
--- a/tools/include/uapi/linux/sched.h
+++ b/tools/include/uapi/linux/sched.h
@@ -49,5 +49,10 @@
*/
#define SCHED_FLAG_RESET_ON_FORK 0x01
#define SCHED_FLAG_RECLAIM 0x02
+#define SCHED_FLAG_DL_OVERRUN 0x04
+
+#define SCHED_FLAG_ALL (SCHED_FLAG_RESET_ON_FORK | \
+ SCHED_FLAG_RECLAIM | \
+ SCHED_FLAG_DL_OVERRUN)
#endif /* _UAPI_LINUX_SCHED_H */
diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h
index c227ccba60ae..07d61583fd02 100644
--- a/tools/include/uapi/sound/asound.h
+++ b/tools/include/uapi/sound/asound.h
@@ -214,6 +214,11 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
+#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */
+/* gap in the numbering for a future standard linear format */
#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */
#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */
@@ -248,6 +253,8 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
+#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE
+#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE
#endif
#ifdef SNDRV_BIG_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
@@ -259,6 +266,8 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
+#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE
+#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE
#endif
typedef int __bitwise snd_pcm_subformat_t;
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index d8749756352d..64c679d67109 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o
+libbpf-y := libbpf.o bpf.o nlattr.o
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index 83714ca1f22b..e6d5f8d1477f 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -160,6 +160,12 @@ $(BPF_IN): force elfdep bpfdep
@(test -f ../../include/uapi/linux/bpf_common.h -a -f ../../../include/uapi/linux/bpf_common.h && ( \
(diff -B ../../include/uapi/linux/bpf_common.h ../../../include/uapi/linux/bpf_common.h >/dev/null) || \
echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf_common.h' differs from latest version at 'include/uapi/linux/bpf_common.h'" >&2 )) || true
+ @(test -f ../../include/uapi/linux/netlink.h -a -f ../../../include/uapi/linux/netlink.h && ( \
+ (diff -B ../../include/uapi/linux/netlink.h ../../../include/uapi/linux/netlink.h >/dev/null) || \
+ echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/netlink.h' differs from latest version at 'include/uapi/linux/netlink.h'" >&2 )) || true
+ @(test -f ../../include/uapi/linux/if_link.h -a -f ../../../include/uapi/linux/if_link.h && ( \
+ (diff -B ../../include/uapi/linux/if_link.h ../../../include/uapi/linux/if_link.h >/dev/null) || \
+ echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/if_link.h' differs from latest version at 'include/uapi/linux/if_link.h'" >&2 )) || true
$(Q)$(MAKE) $(build)=libbpf
$(OUTPUT)libbpf.so: $(BPF_IN)
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 5128677e4117..592a58a2b681 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: LGPL-2.1
+
/*
* common eBPF ELF operations.
*
@@ -25,6 +27,16 @@
#include <asm/unistd.h>
#include <linux/bpf.h>
#include "bpf.h"
+#include "libbpf.h"
+#include "nlattr.h"
+#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
/*
* When building perf, unistd.h is overridden. __NR_bpf is
@@ -46,7 +58,9 @@
# endif
#endif
+#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
static inline __u64 ptr_to_u64(const void *ptr)
{
@@ -413,3 +427,124 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
return err;
}
+
+int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
+{
+ struct sockaddr_nl sa;
+ int sock, seq = 0, len, ret = -1;
+ char buf[4096];
+ struct nlattr *nla, *nla_xdp;
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg ifinfo;
+ char attrbuf[64];
+ } req;
+ struct nlmsghdr *nh;
+ struct nlmsgerr *err;
+ socklen_t addrlen;
+ int one = 1;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock < 0) {
+ return -errno;
+ }
+
+ if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
+ &one, sizeof(one)) < 0) {
+ fprintf(stderr, "Netlink error reporting not supported\n");
+ }
+
+ if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ addrlen = sizeof(sa);
+ if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ if (addrlen != sizeof(sa)) {
+ ret = -LIBBPF_ERRNO__INTERNAL;
+ goto cleanup;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.nh.nlmsg_type = RTM_SETLINK;
+ req.nh.nlmsg_pid = 0;
+ req.nh.nlmsg_seq = ++seq;
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_index = ifindex;
+
+ /* started nested attribute for XDP */
+ nla = (struct nlattr *)(((char *)&req)
+ + NLMSG_ALIGN(req.nh.nlmsg_len));
+ nla->nla_type = NLA_F_NESTED | IFLA_XDP;
+ nla->nla_len = NLA_HDRLEN;
+
+ /* add XDP fd */
+ nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
+ nla_xdp->nla_type = IFLA_XDP_FD;
+ nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
+ memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
+ nla->nla_len += nla_xdp->nla_len;
+
+ /* if user passed in any flags, add those too */
+ if (flags) {
+ nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
+ nla_xdp->nla_type = IFLA_XDP_FLAGS;
+ nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
+ memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
+ nla->nla_len += nla_xdp->nla_len;
+ }
+
+ req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
+ nh = NLMSG_NEXT(nh, len)) {
+ if (nh->nlmsg_pid != sa.nl_pid) {
+ ret = -LIBBPF_ERRNO__WRNGPID;
+ goto cleanup;
+ }
+ if (nh->nlmsg_seq != seq) {
+ ret = -LIBBPF_ERRNO__INVSEQ;
+ goto cleanup;
+ }
+ switch (nh->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(nh);
+ if (!err->error)
+ continue;
+ ret = err->error;
+ nla_dump_errormsg(nh);
+ goto cleanup;
+ case NLMSG_DONE:
+ break;
+ default:
+ break;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ close(sock);
+ return ret;
+}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 9f44c196931e..8d18fb73d7fb 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
/*
* common eBPF ELF operations.
*
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 30c776375118..71ddc481f349 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: LGPL-2.1
+
/*
* Common eBPF ELF object loading operations.
*
@@ -106,6 +108,8 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
[ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
[ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
[ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
+ [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
+ [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
};
int libbpf_strerror(int err, char *buf, size_t size)
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 6e20003109e0..f85906533cdd 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
/*
* Common eBPF ELF object loading operations.
*
@@ -42,6 +44,8 @@ enum libbpf_errno {
LIBBPF_ERRNO__PROG2BIG, /* Program too big */
LIBBPF_ERRNO__KVER, /* Incorrect kernel version */
LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */
+ LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */
+ LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */
__LIBBPF_ERRNO__END,
};
@@ -246,4 +250,6 @@ long libbpf_get_error(const void *ptr);
int bpf_prog_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd);
+
+int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
#endif
diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c
new file mode 100644
index 000000000000..4719434278b2
--- /dev/null
+++ b/tools/lib/bpf/nlattr.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * NETLINK Netlink attributes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <errno.h>
+#include "nlattr.h"
+#include <linux/rtnetlink.h>
+#include <string.h>
+#include <stdio.h>
+
+static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
+ [NLA_U8] = sizeof(uint8_t),
+ [NLA_U16] = sizeof(uint16_t),
+ [NLA_U32] = sizeof(uint32_t),
+ [NLA_U64] = sizeof(uint64_t),
+ [NLA_STRING] = 1,
+ [NLA_FLAG] = 0,
+};
+
+static int nla_len(const struct nlattr *nla)
+{
+ return nla->nla_len - NLA_HDRLEN;
+}
+
+static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+ int totlen = NLA_ALIGN(nla->nla_len);
+
+ *remaining -= totlen;
+ return (struct nlattr *) ((char *) nla + totlen);
+}
+
+static int nla_ok(const struct nlattr *nla, int remaining)
+{
+ return remaining >= sizeof(*nla) &&
+ nla->nla_len >= sizeof(*nla) &&
+ nla->nla_len <= remaining;
+}
+
+static void *nla_data(const struct nlattr *nla)
+{
+ return (char *) nla + NLA_HDRLEN;
+}
+
+static int nla_type(const struct nlattr *nla)
+{
+ return nla->nla_type & NLA_TYPE_MASK;
+}
+
+static int validate_nla(struct nlattr *nla, int maxtype,
+ struct nla_policy *policy)
+{
+ struct nla_policy *pt;
+ unsigned int minlen = 0;
+ int type = nla_type(nla);
+
+ if (type < 0 || type > maxtype)
+ return 0;
+
+ pt = &policy[type];
+
+ if (pt->type > NLA_TYPE_MAX)
+ return 0;
+
+ if (pt->minlen)
+ minlen = pt->minlen;
+ else if (pt->type != NLA_UNSPEC)
+ minlen = nla_attr_minlen[pt->type];
+
+ if (nla_len(nla) < minlen)
+ return -1;
+
+ if (pt->maxlen && nla_len(nla) > pt->maxlen)
+ return -1;
+
+ if (pt->type == NLA_STRING) {
+ char *data = nla_data(nla);
+ if (data[nla_len(nla) - 1] != '\0')
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int nlmsg_len(const struct nlmsghdr *nlh)
+{
+ return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+/**
+ * Create attribute index based on a stream of attributes.
+ * @arg tb Index array to be filled (maxtype+1 elements).
+ * @arg maxtype Maximum attribute type expected and accepted.
+ * @arg head Head of attribute stream.
+ * @arg len Length of attribute stream.
+ * @arg policy Attribute validation policy.
+ *
+ * Iterates over the stream of attributes and stores a pointer to each
+ * attribute in the index array using the attribute type as index to
+ * the array. Attribute with a type greater than the maximum type
+ * specified will be silently ignored in order to maintain backwards
+ * compatibility. If \a policy is not NULL, the attribute will be
+ * validated using the specified policy.
+ *
+ * @see nla_validate
+ * @return 0 on success or a negative error code.
+ */
+static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+ struct nla_policy *policy)
+{
+ struct nlattr *nla;
+ int rem, err;
+
+ memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+ nla_for_each_attr(nla, head, len, rem) {
+ int type = nla_type(nla);
+
+ if (type > maxtype)
+ continue;
+
+ if (policy) {
+ err = validate_nla(nla, maxtype, policy);
+ if (err < 0)
+ goto errout;
+ }
+
+ if (tb[type])
+ fprintf(stderr, "Attribute of type %#x found multiple times in message, "
+ "previous attribute is being ignored.\n", type);
+
+ tb[type] = nla;
+ }
+
+ err = 0;
+errout:
+ return err;
+}
+
+/* dump netlink extended ack error message */
+int nla_dump_errormsg(struct nlmsghdr *nlh)
+{
+ struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
+ [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING },
+ [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 },
+ };
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
+ struct nlmsgerr *err;
+ char *errmsg = NULL;
+ int hlen, alen;
+
+ /* no TLVs, nothing to do here */
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ return 0;
+
+ err = (struct nlmsgerr *)NLMSG_DATA(nlh);
+ hlen = sizeof(*err);
+
+ /* if NLM_F_CAPPED is set then the inner err msg was capped */
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += nlmsg_len(&err->msg);
+
+ attr = (struct nlattr *) ((void *) err + hlen);
+ alen = nlh->nlmsg_len - hlen;
+
+ if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) {
+ fprintf(stderr,
+ "Failed to parse extended error attributes\n");
+ return 0;
+ }
+
+ if (tb[NLMSGERR_ATTR_MSG])
+ errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]);
+
+ fprintf(stderr, "Kernel error message: %s\n", errmsg);
+
+ return 0;
+}
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h
new file mode 100644
index 000000000000..931a71f68f93
--- /dev/null
+++ b/tools/lib/bpf/nlattr.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * NETLINK Netlink attributes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NLATTR_H
+#define __NLATTR_H
+
+#include <stdint.h>
+#include <linux/netlink.h>
+/* avoid multiple definition of netlink features */
+#define __LINUX_NETLINK_H
+
+/**
+ * Standard attribute types to specify validation policy
+ */
+enum {
+ NLA_UNSPEC, /**< Unspecified type, binary data chunk */
+ NLA_U8, /**< 8 bit integer */
+ NLA_U16, /**< 16 bit integer */
+ NLA_U32, /**< 32 bit integer */
+ NLA_U64, /**< 64 bit integer */
+ NLA_STRING, /**< NUL terminated character string */
+ NLA_FLAG, /**< Flag */
+ NLA_MSECS, /**< Micro seconds (64bit) */
+ NLA_NESTED, /**< Nested attributes */
+ __NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/**
+ * @ingroup attr
+ * Attribute validation policy.
+ *
+ * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
+ */
+struct nla_policy {
+ /** Type of attribute or NLA_UNSPEC */
+ uint16_t type;
+
+ /** Minimal length of payload required */
+ uint16_t minlen;
+
+ /** Maximal length of payload allowed */
+ uint16_t maxlen;
+};
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of attributes
+ * @arg pos loop counter, set to current attribute
+ * @arg head head of attribute stream
+ * @arg len length of attribute stream
+ * @arg rem initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+ for (pos = head, rem = len; \
+ nla_ok(pos, rem); \
+ pos = nla_next(pos, &(rem)))
+
+int nla_dump_errormsg(struct nlmsghdr *nlh);
+
+#endif /* __NLATTR_H */
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 643cc4ba6872..3e5135dded16 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -31,5 +31,6 @@ config.mak.autogen
.config-detected
util/intel-pt-decoder/inat-tables.c
arch/*/include/generated/
+trace/beauty/generated/
pmu-events/pmu-events.c
pmu-events/jevents
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 65681a1a292a..bf4ca749d1ac 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1566,7 +1566,8 @@ static struct option __record_options[] = {
OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
&record.opts.sample_time_set,
"Record the sample timestamps"),
- OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
+ OPT_BOOLEAN_SET('P', "period", &record.opts.period, &record.opts.period_set,
+ "Record the sample period"),
OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
"don't sample"),
OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 17d11deeb88d..e7f1b182fc15 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1661,9 +1661,12 @@ static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evse
struct callchain_cursor *cursor)
{
struct addr_location al;
+ int max_stack = evsel->attr.sample_max_stack ?
+ evsel->attr.sample_max_stack :
+ trace->max_stack;
if (machine__resolve(trace->host, &al, sample) < 0 ||
- thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, evsel->attr.sample_max_stack))
+ thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
return -1;
return 0;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 2357f4ccc9c7..cfe46236a5e5 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -50,6 +50,7 @@ struct record_opts {
bool sample_time_set;
bool sample_cpu;
bool period;
+ bool period_set;
bool running_time;
bool full_auxtrace;
bool auxtrace_snapshot_mode;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 66fa45198a11..ff359c9ece2e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -745,12 +745,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
if (!(term->weak && opts->user_interval != ULLONG_MAX)) {
attr->sample_period = term->val.period;
attr->freq = 0;
+ perf_evsel__reset_sample_bit(evsel, PERIOD);
}
break;
case PERF_EVSEL__CONFIG_TERM_FREQ:
if (!(term->weak && opts->user_freq != UINT_MAX)) {
attr->sample_freq = term->val.freq;
attr->freq = 1;
+ perf_evsel__set_sample_bit(evsel, PERIOD);
}
break;
case PERF_EVSEL__CONFIG_TERM_TIME:
@@ -969,9 +971,6 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
if (target__has_cpu(&opts->target) || opts->sample_cpu)
perf_evsel__set_sample_bit(evsel, CPU);
- if (opts->period)
- perf_evsel__set_sample_bit(evsel, PERIOD);
-
/*
* When the user explicitly disabled time don't force it here.
*/
@@ -1073,6 +1072,14 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
apply_config_terms(evsel, opts, track);
evsel->ignore_missing_thread = opts->ignore_missing_thread;
+
+ /* The --period option takes the precedence. */
+ if (opts->period_set) {
+ if (opts->period)
+ perf_evsel__set_sample_bit(evsel, PERIOD);
+ else
+ perf_evsel__reset_sample_bit(evsel, PERIOD);
+ }
}
static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index 1e09d77f1948..cc15af2e54fe 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -8,5 +8,6 @@ fixdep
test_align
test_dev_cgroup
test_progs
+test_tcpbpf_user
test_verifier_log
feature
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index bf05bc5e36e5..566d6adc172a 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -27,7 +27,7 @@ TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \
include ../lib.mk
-BPFOBJ := $(OUTPUT)/libbpf.a $(OUTPUT)/cgroup_helpers.c
+BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c
$(TEST_GEN_PROGS): $(BPFOBJ)
@@ -58,7 +58,7 @@ CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
$(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
$(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline
-%.o: %.c
+$(OUTPUT)/%.o: %.c
$(CLANG) $(CLANG_FLAGS) \
-O2 -target bpf -emit-llvm -c $< -o - | \
$(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 697bd83de295..c0f16e93f9bd 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -7780,6 +7780,20 @@ static struct bpf_test tests[] = {
.result = REJECT,
},
{
+ "XDP, using ifindex from netdev",
+ .insns = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, ingress_ifindex)),
+ BPF_JMP_IMM(BPF_JLT, BPF_REG_2, 1, 1),
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .retval = 1,
+ },
+ {
"meta access, test1",
.insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,