History

Merge tag 'platform-drivers-x86-v5.2-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform driver updates from Andy Shevchenko: "Gathered pile of patches for Platform Drivers x86. No surprises and no merge conflicts. Business as usual. Summary: - New driver of power button for Basin Cove PMIC. - ASUS WMI driver has got a Fn lock mode switch support. - Resolve a never end story with non working Wi-Fi on newer Lenovo Ideapad computers. Now the black list is replaced with white list. - New facility to debug S0ix failures on Intel Atom platforms. The Intel PMC and accompanying drivers are cleaned up. - Mellanox got a new TmFifo driver. Besides tachometer sensor and watchdog are enabled on Mellanox platforms. - The information of embedded controller is now recognized on new Thinkpads. Bluetooth driver on Thinkpads is blacklisted for some models. - Touchscreen DMI driver extended to support 'jumper ezpad 6 pro b' and Myria MY8307 2-in-1. - Additionally few small fixes here and there for WMI and ACPI laptop drivers. - The following is an automated git shortlog grouped by driver: - alienware-wmi: - printing the wrong error code - fix kfree on potentially uninitialized pointer - asus-wmi: - Add fn-lock mode switch support - dell-laptop: - fix rfkill functionality - dell-rbtn: - Add missing #include - ideapad-laptop: - Remove no_hw_rfkill_list - intel_pmc_core: - Allow to dump debug registers on S0ix failure - Convert to a platform_driver - Mark local function static - intel_pmc_ipc: - Don't map non-used optional resources - Apply same width for offset definitions - Use BIT() macro - adding error handling - intel_punit_ipc: - Revert "Fix resource ioremap warning" - mlx-platform: - Add mlx-wdt platform driver activation - Add support for tachometer speed register - Add TmFifo driver for Mellanox BlueField Soc - sony-laptop: - Fix unintentional fall-through - thinkpad_acpi: - cleanup for Thinkpad ACPI led - Mark expected switch fall-throughs - fix spelling mistake "capabilites" -> "capabilities" - Read EC information on newer models - Disable Bluetooth for some machines - touchscreen_dmi: - Add info for 'jumper ezpad 6 pro b' touchscreen - Add info for Myria MY8307 2-in-1" * tag 'platform-drivers-x86-v5.2-1' of git://git.infradead.org/linux-platform-drivers-x86: (26 commits) platform/x86: Add support for Basin Cove power button platform/x86: asus-wmi: Add fn-lock mode switch support platform/x86: ideapad-laptop: Remove no_hw_rfkill_list platform/x86: touchscreen_dmi: Add info for 'jumper ezpad 6 pro b' touchscreen platform/x86: thinkpad_acpi: cleanup for Thinkpad ACPI led platform/x86: thinkpad_acpi: Mark expected switch fall-throughs platform/x86: sony-laptop: Fix unintentional fall-through platform/x86: alienware-wmi: printing the wrong error code platform/x86: intel_pmc_core: Allow to dump debug registers on S0ix failure platform/x86: intel_pmc_core: Convert to a platform_driver platform/x86: mlx-platform: Add mlx-wdt platform driver activation platform/x86: mlx-platform: Add support for tachometer speed register platform/mellanox: Add TmFifo driver for Mellanox BlueField Soc platform/x86: thinkpad_acpi: fix spelling mistake "capabilites" -> "capabilities" platform/x86: intel_punit_ipc: Revert "Fix resource ioremap warning" platform/x86: intel_pmc_ipc: Don't map non-used optional resources platform/x86: intel_pmc_ipc: Apply same width for offset definitions platform/x86: intel_pmc_ipc: Use BIT() macro platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer platform/x86: dell-laptop: fix rfkill functionality ...

Linus Torvalds committed 7 years ago

Commit 7817ffd2 parents cccd559 6456fd721 files · +2147 −381Browse files

Unified · Split

21 files
  1. drivers/platform/mellanox/Kconfig +11 −1
  2. drivers/platform/mellanox/Makefile +1 −0
  3. drivers/platform/mellanox/mlxbf-tmfifo-regs.h +63 −0
  4. drivers/platform/mellanox/mlxbf-tmfifo.c +1281 −0
  5. drivers/platform/x86/Kconfig +11 −0
  6. drivers/platform/x86/Makefile +1 −0
  7. drivers/platform/x86/alienware-wmi.c +9 −10
  8. drivers/platform/x86/asus-wmi.c +37 −0
  9. drivers/platform/x86/dell-laptop.c +3 −3
  10. drivers/platform/x86/dell-rbtn.c +2 −0
  11. drivers/platform/x86/ideapad-laptop.c +15 −306
  12. drivers/platform/x86/intel_mrfld_pwrbtn.c +107 −0
  13. drivers/platform/x86/intel_pmc_core.c +163 −9
  14. drivers/platform/x86/intel_pmc_core.h +7 −0
  15. drivers/platform/x86/intel_pmc_ipc.c +24 −22
  16. drivers/platform/x86/intel_punit_ipc.c +4 −4
  17. drivers/platform/x86/mlx-platform.c +226 −2
  18. drivers/platform/x86/sony-laptop.c +5 −3
  19. drivers/platform/x86/thinkpad_acpi.c +125 −21
  20. drivers/platform/x86/touchscreen_dmi.c +51 −0
  21. include/linux/platform_data/x86/asus-wmi.h +1 −0
drivers/platform/mellanox/Kconfig+11−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
55
66 menuconfig MELLANOX_PLATFORM
77 bool "Platform support for Mellanox hardware"
8− depends on X86 || ARM || COMPILE_TEST
8+ depends on X86 || ARM || ARM64 || COMPILE_TEST
99 ---help---
1010 Say Y here to get to see options for platform support for
1111 Mellanox systems. This option alone does not add any kernel code.
@@ -34,4 +34,14 @@ config MLXREG_IO · 22 unmodified lines
3434 to system resets operation, system reset causes monitoring and some
3535 kinds of mux selection.
3636
37+config MLXBF_TMFIFO
38+ tristate "Mellanox BlueField SoC TmFifo platform driver"
39+ depends on ARM64
40+ depends on ACPI
41+ depends on VIRTIO_CONSOLE && VIRTIO_NET
42+ help
43+ Say y here to enable TmFifo support. The TmFifo driver provides
44+ platform driver support for the TmFifo which supports console
45+ and networking based on the virtio framework.
46+
3747 endif # MELLANOX_PLATFORM
drivers/platform/mellanox/Makefile+1−0
@@ -3,5 +3,6 @@ · 2 unmodified lines
33 # Makefile for linux/drivers/platform/mellanox
44 # Mellanox Platform-Specific Drivers
55 #
6+obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
67 obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
78 obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
drivers/platform/mellanox/mlxbf-tmfifo-regs.h+63−0
@@ -0,0 +1,63 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+/*
3+ * Copyright (c) 2019, Mellanox Technologies. All rights reserved.
4+ */
5+
6+#ifndef __MLXBF_TMFIFO_REGS_H__
7+#define __MLXBF_TMFIFO_REGS_H__
8+
9+#include <linux/types.h>
10+#include <linux/bits.h>
11+
12+#define MLXBF_TMFIFO_TX_DATA 0x00
13+#define MLXBF_TMFIFO_TX_STS 0x08
14+#define MLXBF_TMFIFO_TX_STS__LENGTH 0x0001
15+#define MLXBF_TMFIFO_TX_STS__COUNT_SHIFT 0
16+#define MLXBF_TMFIFO_TX_STS__COUNT_WIDTH 9
17+#define MLXBF_TMFIFO_TX_STS__COUNT_RESET_VAL 0
18+#define MLXBF_TMFIFO_TX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
19+#define MLXBF_TMFIFO_TX_STS__COUNT_MASK GENMASK_ULL(8, 0)
20+#define MLXBF_TMFIFO_TX_CTL 0x10
21+#define MLXBF_TMFIFO_TX_CTL__LENGTH 0x0001
22+#define MLXBF_TMFIFO_TX_CTL__LWM_SHIFT 0
23+#define MLXBF_TMFIFO_TX_CTL__LWM_WIDTH 8
24+#define MLXBF_TMFIFO_TX_CTL__LWM_RESET_VAL 128
25+#define MLXBF_TMFIFO_TX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
26+#define MLXBF_TMFIFO_TX_CTL__LWM_MASK GENMASK_ULL(7, 0)
27+#define MLXBF_TMFIFO_TX_CTL__HWM_SHIFT 8
28+#define MLXBF_TMFIFO_TX_CTL__HWM_WIDTH 8
29+#define MLXBF_TMFIFO_TX_CTL__HWM_RESET_VAL 128
30+#define MLXBF_TMFIFO_TX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
31+#define MLXBF_TMFIFO_TX_CTL__HWM_MASK GENMASK_ULL(15, 8)
32+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_SHIFT 32
33+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_WIDTH 9
34+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RESET_VAL 256
35+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
36+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
37+#define MLXBF_TMFIFO_RX_DATA 0x00
38+#define MLXBF_TMFIFO_RX_STS 0x08
39+#define MLXBF_TMFIFO_RX_STS__LENGTH 0x0001
40+#define MLXBF_TMFIFO_RX_STS__COUNT_SHIFT 0
41+#define MLXBF_TMFIFO_RX_STS__COUNT_WIDTH 9
42+#define MLXBF_TMFIFO_RX_STS__COUNT_RESET_VAL 0
43+#define MLXBF_TMFIFO_RX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
44+#define MLXBF_TMFIFO_RX_STS__COUNT_MASK GENMASK_ULL(8, 0)
45+#define MLXBF_TMFIFO_RX_CTL 0x10
46+#define MLXBF_TMFIFO_RX_CTL__LENGTH 0x0001
47+#define MLXBF_TMFIFO_RX_CTL__LWM_SHIFT 0
48+#define MLXBF_TMFIFO_RX_CTL__LWM_WIDTH 8
49+#define MLXBF_TMFIFO_RX_CTL__LWM_RESET_VAL 128
50+#define MLXBF_TMFIFO_RX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
51+#define MLXBF_TMFIFO_RX_CTL__LWM_MASK GENMASK_ULL(7, 0)
52+#define MLXBF_TMFIFO_RX_CTL__HWM_SHIFT 8
53+#define MLXBF_TMFIFO_RX_CTL__HWM_WIDTH 8
54+#define MLXBF_TMFIFO_RX_CTL__HWM_RESET_VAL 128
55+#define MLXBF_TMFIFO_RX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
56+#define MLXBF_TMFIFO_RX_CTL__HWM_MASK GENMASK_ULL(15, 8)
57+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_SHIFT 32
58+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_WIDTH 9
59+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RESET_VAL 256
60+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
61+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
62+
63+#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
drivers/platform/mellanox/mlxbf-tmfifo.c+1281−0
@@ -0,0 +1,1281 @@
1+// SPDX-License-Identifier: GPL-2.0+
2+/*
3+ * Mellanox BlueField SoC TmFifo driver
4+ *
5+ * Copyright (C) 2019 Mellanox Technologies
6+ */
7+
8+#include <linux/acpi.h>
9+#include <linux/bitfield.h>
10+#include <linux/circ_buf.h>
11+#include <linux/efi.h>
12+#include <linux/irq.h>
13+#include <linux/module.h>
14+#include <linux/mutex.h>
15+#include <linux/platform_device.h>
16+#include <linux/types.h>
17+
18+#include <linux/virtio_config.h>
19+#include <linux/virtio_console.h>
20+#include <linux/virtio_ids.h>
21+#include <linux/virtio_net.h>
22+#include <linux/virtio_ring.h>
23+
24+#include "mlxbf-tmfifo-regs.h"
25+
26+/* Vring size. */
27+#define MLXBF_TMFIFO_VRING_SIZE SZ_1K
28+
29+/* Console Tx buffer size. */
30+#define MLXBF_TMFIFO_CON_TX_BUF_SIZE SZ_32K
31+
32+/* Console Tx buffer reserved space. */
33+#define MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE 8
34+
35+/* House-keeping timer interval. */
36+#define MLXBF_TMFIFO_TIMER_INTERVAL (HZ / 10)
37+
38+/* Virtual devices sharing the TM FIFO. */
39+#define MLXBF_TMFIFO_VDEV_MAX (VIRTIO_ID_CONSOLE + 1)
40+
41+/*
42+ * Reserve 1/16 of TmFifo space, so console messages are not starved by
43+ * the networking traffic.
44+ */
45+#define MLXBF_TMFIFO_RESERVE_RATIO 16
46+
47+/* Message with data needs at least two words (for header & data). */
48+#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
49+
50+struct mlxbf_tmfifo;
51+
52+/**
53+ * mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring
54+ * @va: virtual address of the ring
55+ * @dma: dma address of the ring
56+ * @vq: pointer to the virtio virtqueue
57+ * @desc: current descriptor of the pending packet
58+ * @desc_head: head descriptor of the pending packet
59+ * @cur_len: processed length of the current descriptor
60+ * @rem_len: remaining length of the pending packet
61+ * @pkt_len: total length of the pending packet
62+ * @next_avail: next avail descriptor id
63+ * @num: vring size (number of descriptors)
64+ * @align: vring alignment size
65+ * @index: vring index
66+ * @vdev_id: vring virtio id (VIRTIO_ID_xxx)
67+ * @fifo: pointer to the tmfifo structure
68+ */
69+struct mlxbf_tmfifo_vring {
70+ void *va;
71+ dma_addr_t dma;
72+ struct virtqueue *vq;
73+ struct vring_desc *desc;
74+ struct vring_desc *desc_head;
75+ int cur_len;
76+ int rem_len;
77+ u32 pkt_len;
78+ u16 next_avail;
79+ int num;
80+ int align;
81+ int index;
82+ int vdev_id;
83+ struct mlxbf_tmfifo *fifo;
84+};
85+
86+/* Interrupt types. */
87+enum {
88+ MLXBF_TM_RX_LWM_IRQ,
89+ MLXBF_TM_RX_HWM_IRQ,
90+ MLXBF_TM_TX_LWM_IRQ,
91+ MLXBF_TM_TX_HWM_IRQ,
92+ MLXBF_TM_MAX_IRQ
93+};
94+
95+/* Ring types (Rx & Tx). */
96+enum {
97+ MLXBF_TMFIFO_VRING_RX,
98+ MLXBF_TMFIFO_VRING_TX,
99+ MLXBF_TMFIFO_VRING_MAX
100+};
101+
102+/**
103+ * mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device
104+ * @vdev: virtio device, in which the vdev.id.device field has the
105+ * VIRTIO_ID_xxx id to distinguish the virtual device.
106+ * @status: status of the device
107+ * @features: supported features of the device
108+ * @vrings: array of tmfifo vrings of this device
109+ * @config.cons: virtual console config -
110+ * select if vdev.id.device is VIRTIO_ID_CONSOLE
111+ * @config.net: virtual network config -
112+ * select if vdev.id.device is VIRTIO_ID_NET
113+ * @tx_buf: tx buffer used to buffer data before writing into the FIFO
114+ */
115+struct mlxbf_tmfifo_vdev {
116+ struct virtio_device vdev;
117+ u8 status;
118+ u64 features;
119+ struct mlxbf_tmfifo_vring vrings[MLXBF_TMFIFO_VRING_MAX];
120+ union {
121+ struct virtio_console_config cons;
122+ struct virtio_net_config net;
123+ } config;
124+ struct circ_buf tx_buf;
125+};
126+
127+/**
128+ * mlxbf_tmfifo_irq_info - Structure of the interrupt information
129+ * @fifo: pointer to the tmfifo structure
130+ * @irq: interrupt number
131+ * @index: index into the interrupt array
132+ */
133+struct mlxbf_tmfifo_irq_info {
134+ struct mlxbf_tmfifo *fifo;
135+ int irq;
136+ int index;
137+};
138+
139+/**
140+ * mlxbf_tmfifo - Structure of the TmFifo
141+ * @vdev: array of the virtual devices running over the TmFifo
142+ * @lock: lock to protect the TmFifo access
143+ * @rx_base: mapped register base address for the Rx FIFO
144+ * @tx_base: mapped register base address for the Tx FIFO
145+ * @rx_fifo_size: number of entries of the Rx FIFO
146+ * @tx_fifo_size: number of entries of the Tx FIFO
147+ * @pend_events: pending bits for deferred events
148+ * @irq_info: interrupt information
149+ * @work: work struct for deferred process
150+ * @timer: background timer
151+ * @vring: Tx/Rx ring
152+ * @spin_lock: spin lock
153+ * @is_ready: ready flag
154+ */
155+struct mlxbf_tmfifo {
156+ struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
157+ struct mutex lock; /* TmFifo lock */
158+ void __iomem *rx_base;
159+ void __iomem *tx_base;
160+ int rx_fifo_size;
161+ int tx_fifo_size;
162+ unsigned long pend_events;
163+ struct mlxbf_tmfifo_irq_info irq_info[MLXBF_TM_MAX_IRQ];
164+ struct work_struct work;
165+ struct timer_list timer;
166+ struct mlxbf_tmfifo_vring *vring[2];
167+ spinlock_t spin_lock; /* spin lock */
168+ bool is_ready;
169+};
170+
171+/**
172+ * mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header
173+ * @type: message type
174+ * @len: payload length in network byte order. Messages sent into the FIFO
175+ * will be read by the other side as data stream in the same byte order.
176+ * The length needs to be encoded into network order so both sides
177+ * could understand it.
178+ */
179+struct mlxbf_tmfifo_msg_hdr {
180+ u8 type;
181+ __be16 len;
182+ u8 unused[5];
183+} __packed __aligned(sizeof(u64));
184+
185+/*
186+ * Default MAC.
187+ * This MAC address will be read from EFI persistent variable if configured.
188+ * It can also be reconfigured with standard Linux tools.
189+ */
190+static u8 mlxbf_tmfifo_net_default_mac[ETH_ALEN] = {
191+ 0x00, 0x1A, 0xCA, 0xFF, 0xFF, 0x01
192+};
193+
194+/* EFI variable name of the MAC address. */
195+static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr";
196+
197+/* Maximum L2 header length. */
198+#define MLXBF_TMFIFO_NET_L2_OVERHEAD 36
199+
200+/* Supported virtio-net features. */
201+#define MLXBF_TMFIFO_NET_FEATURES \
202+ (BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_STATUS) | \
203+ BIT_ULL(VIRTIO_NET_F_MAC))
204+
205+#define mlxbf_vdev_to_tmfifo(d) container_of(d, struct mlxbf_tmfifo_vdev, vdev)
206+
207+/* Free vrings of the FIFO device. */
208+static void mlxbf_tmfifo_free_vrings(struct mlxbf_tmfifo *fifo,
209+ struct mlxbf_tmfifo_vdev *tm_vdev)
210+{
211+ struct mlxbf_tmfifo_vring *vring;
212+ int i, size;
213+
214+ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
215+ vring = &tm_vdev->vrings[i];
216+ if (vring->va) {
217+ size = vring_size(vring->num, vring->align);
218+ dma_free_coherent(tm_vdev->vdev.dev.parent, size,
219+ vring->va, vring->dma);
220+ vring->va = NULL;
221+ if (vring->vq) {
222+ vring_del_virtqueue(vring->vq);
223+ vring->vq = NULL;
224+ }
225+ }
226+ }
227+}
228+
229+/* Allocate vrings for the FIFO. */
230+static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo,
231+ struct mlxbf_tmfifo_vdev *tm_vdev)
232+{
233+ struct mlxbf_tmfifo_vring *vring;
234+ struct device *dev;
235+ dma_addr_t dma;
236+ int i, size;
237+ void *va;
238+
239+ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
240+ vring = &tm_vdev->vrings[i];
241+ vring->fifo = fifo;
242+ vring->num = MLXBF_TMFIFO_VRING_SIZE;
243+ vring->align = SMP_CACHE_BYTES;
244+ vring->index = i;
245+ vring->vdev_id = tm_vdev->vdev.id.device;
246+ dev = &tm_vdev->vdev.dev;
247+
248+ size = vring_size(vring->num, vring->align);
249+ va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
250+ if (!va) {
251+ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
252+ dev_err(dev->parent, "dma_alloc_coherent failed\n");
253+ return -ENOMEM;
254+ }
255+
256+ vring->va = va;
257+ vring->dma = dma;
258+ }
259+
260+ return 0;
261+}
262+
263+/* Disable interrupts of the FIFO device. */
264+static void mlxbf_tmfifo_disable_irqs(struct mlxbf_tmfifo *fifo)
265+{
266+ int i, irq;
267+
268+ for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
269+ irq = fifo->irq_info[i].irq;
270+ fifo->irq_info[i].irq = 0;
271+ disable_irq(irq);
272+ }
273+}
274+
275+/* Interrupt handler. */
276+static irqreturn_t mlxbf_tmfifo_irq_handler(int irq, void *arg)
277+{
278+ struct mlxbf_tmfifo_irq_info *irq_info = arg;
279+
280+ if (!test_and_set_bit(irq_info->index, &irq_info->fifo->pend_events))
281+ schedule_work(&irq_info->fifo->work);
282+
283+ return IRQ_HANDLED;
284+}
285+
286+/* Get the next packet descriptor from the vring. */
287+static struct vring_desc *
288+mlxbf_tmfifo_get_next_desc(struct mlxbf_tmfifo_vring *vring)
289+{
290+ const struct vring *vr = virtqueue_get_vring(vring->vq);
291+ struct virtio_device *vdev = vring->vq->vdev;
292+ unsigned int idx, head;
293+
294+ if (vring->next_avail == virtio16_to_cpu(vdev, vr->avail->idx))
295+ return NULL;
296+
297+ idx = vring->next_avail % vr->num;
298+ head = virtio16_to_cpu(vdev, vr->avail->ring[idx]);
299+ if (WARN_ON(head >= vr->num))
300+ return NULL;
301+
302+ vring->next_avail++;
303+
304+ return &vr->desc[head];
305+}
306+
307+/* Release virtio descriptor. */
308+static void mlxbf_tmfifo_release_desc(struct mlxbf_tmfifo_vring *vring,
309+ struct vring_desc *desc, u32 len)
310+{
311+ const struct vring *vr = virtqueue_get_vring(vring->vq);
312+ struct virtio_device *vdev = vring->vq->vdev;
313+ u16 idx, vr_idx;
314+
315+ vr_idx = virtio16_to_cpu(vdev, vr->used->idx);
316+ idx = vr_idx % vr->num;
317+ vr->used->ring[idx].id = cpu_to_virtio32(vdev, desc - vr->desc);
318+ vr->used->ring[idx].len = cpu_to_virtio32(vdev, len);
319+
320+ /*
321+ * Virtio could poll and check the 'idx' to decide whether the desc is
322+ * done or not. Add a memory barrier here to make sure the update above
323+ * completes before updating the idx.
324+ */
325+ mb();
326+ vr->used->idx = cpu_to_virtio16(vdev, vr_idx + 1);
327+}
328+
329+/* Get the total length of the descriptor chain. */
330+static u32 mlxbf_tmfifo_get_pkt_len(struct mlxbf_tmfifo_vring *vring,
331+ struct vring_desc *desc)
332+{
333+ const struct vring *vr = virtqueue_get_vring(vring->vq);
334+ struct virtio_device *vdev = vring->vq->vdev;
335+ u32 len = 0, idx;
336+
337+ while (desc) {
338+ len += virtio32_to_cpu(vdev, desc->len);
339+ if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
340+ break;
341+ idx = virtio16_to_cpu(vdev, desc->next);
342+ desc = &vr->desc[idx];
343+ }
344+
345+ return len;
346+}
347+
348+static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring)
349+{
350+ struct vring_desc *desc_head;
351+ u32 len = 0;
352+
353+ if (vring->desc_head) {
354+ desc_head = vring->desc_head;
355+ len = vring->pkt_len;
356+ } else {
357+ desc_head = mlxbf_tmfifo_get_next_desc(vring);
358+ len = mlxbf_tmfifo_get_pkt_len(vring, desc_head);
359+ }
360+
361+ if (desc_head)
362+ mlxbf_tmfifo_release_desc(vring, desc_head, len);
363+
364+ vring->pkt_len = 0;
365+ vring->desc = NULL;
366+ vring->desc_head = NULL;
367+}
368+
369+static void mlxbf_tmfifo_init_net_desc(struct mlxbf_tmfifo_vring *vring,
370+ struct vring_desc *desc, bool is_rx)
371+{
372+ struct virtio_device *vdev = vring->vq->vdev;
373+ struct virtio_net_hdr *net_hdr;
374+
375+ net_hdr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
376+ memset(net_hdr, 0, sizeof(*net_hdr));
377+}
378+
379+/* Get and initialize the next packet. */
380+static struct vring_desc *
381+mlxbf_tmfifo_get_next_pkt(struct mlxbf_tmfifo_vring *vring, bool is_rx)
382+{
383+ struct vring_desc *desc;
384+
385+ desc = mlxbf_tmfifo_get_next_desc(vring);
386+ if (desc && is_rx && vring->vdev_id == VIRTIO_ID_NET)
387+ mlxbf_tmfifo_init_net_desc(vring, desc, is_rx);
388+
389+ vring->desc_head = desc;
390+ vring->desc = desc;
391+
392+ return desc;
393+}
394+
395+/* House-keeping timer. */
396+static void mlxbf_tmfifo_timer(struct timer_list *t)
397+{
398+ struct mlxbf_tmfifo *fifo = container_of(t, struct mlxbf_tmfifo, timer);
399+ int rx, tx;
400+
401+ rx = !test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events);
402+ tx = !test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
403+
404+ if (rx || tx)
405+ schedule_work(&fifo->work);
406+
407+ mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
408+}
409+
410+/* Copy one console packet into the output buffer. */
411+static void mlxbf_tmfifo_console_output_one(struct mlxbf_tmfifo_vdev *cons,
412+ struct mlxbf_tmfifo_vring *vring,
413+ struct vring_desc *desc)
414+{
415+ const struct vring *vr = virtqueue_get_vring(vring->vq);
416+ struct virtio_device *vdev = &cons->vdev;
417+ u32 len, idx, seg;
418+ void *addr;
419+
420+ while (desc) {
421+ addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
422+ len = virtio32_to_cpu(vdev, desc->len);
423+
424+ seg = CIRC_SPACE_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
425+ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
426+ if (len <= seg) {
427+ memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, len);
428+ } else {
429+ memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, seg);
430+ addr += seg;
431+ memcpy(cons->tx_buf.buf, addr, len - seg);
432+ }
433+ cons->tx_buf.head = (cons->tx_buf.head + len) %
434+ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
435+
436+ if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
437+ break;
438+ idx = virtio16_to_cpu(vdev, desc->next);
439+ desc = &vr->desc[idx];
440+ }
441+}
442+
443+/* Copy console data into the output buffer. */
444+static void mlxbf_tmfifo_console_output(struct mlxbf_tmfifo_vdev *cons,
445+ struct mlxbf_tmfifo_vring *vring)
446+{
447+ struct vring_desc *desc;
448+ u32 len, avail;
449+
450+ desc = mlxbf_tmfifo_get_next_desc(vring);
451+ while (desc) {
452+ /* Release the packet if not enough space. */
453+ len = mlxbf_tmfifo_get_pkt_len(vring, desc);
454+ avail = CIRC_SPACE(cons->tx_buf.head, cons->tx_buf.tail,
455+ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
456+ if (len + MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE > avail) {
457+ mlxbf_tmfifo_release_desc(vring, desc, len);
458+ break;
459+ }
460+
461+ mlxbf_tmfifo_console_output_one(cons, vring, desc);
462+ mlxbf_tmfifo_release_desc(vring, desc, len);
463+ desc = mlxbf_tmfifo_get_next_desc(vring);
464+ }
465+}
466+
467+/* Get the number of available words in Rx FIFO for receiving. */
468+static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo)
469+{
470+ u64 sts;
471+
472+ sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS);
473+ return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts);
474+}
475+
476+/* Get the number of available words in the TmFifo for sending. */
477+static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
478+{
479+ int tx_reserve;
480+ u32 count;
481+ u64 sts;
482+
483+ /* Reserve some room in FIFO for console messages. */
484+ if (vdev_id == VIRTIO_ID_NET)
485+ tx_reserve = fifo->tx_fifo_size / MLXBF_TMFIFO_RESERVE_RATIO;
486+ else
487+ tx_reserve = 1;
488+
489+ sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS);
490+ count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts);
491+ return fifo->tx_fifo_size - tx_reserve - count;
492+}
493+
494+/* Console Tx (move data from the output buffer into the TmFifo). */
495+static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
496+{
497+ struct mlxbf_tmfifo_msg_hdr hdr;
498+ struct mlxbf_tmfifo_vdev *cons;
499+ unsigned long flags;
500+ int size, seg;
501+ void *addr;
502+ u64 data;
503+
504+ /* Return if not enough space available. */
505+ if (avail < MLXBF_TMFIFO_DATA_MIN_WORDS)
506+ return;
507+
508+ cons = fifo->vdev[VIRTIO_ID_CONSOLE];
509+ if (!cons || !cons->tx_buf.buf)
510+ return;
511+
512+ /* Return if no data to send. */
513+ size = CIRC_CNT(cons->tx_buf.head, cons->tx_buf.tail,
514+ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
515+ if (size == 0)
516+ return;
517+
518+ /* Adjust the size to available space. */
519+ if (size + sizeof(hdr) > avail * sizeof(u64))
520+ size = avail * sizeof(u64) - sizeof(hdr);
521+
522+ /* Write header. */
523+ hdr.type = VIRTIO_ID_CONSOLE;
524+ hdr.len = htons(size);
525+ writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
526+
527+ /* Use spin-lock to protect the 'cons->tx_buf'. */
528+ spin_lock_irqsave(&fifo->spin_lock, flags);
529+
530+ while (size > 0) {
531+ addr = cons->tx_buf.buf + cons->tx_buf.tail;
532+
533+ seg = CIRC_CNT_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
534+ MLXBF_TMFIFO_CON_TX_BUF_SIZE);
535+ if (seg >= sizeof(u64)) {
536+ memcpy(&data, addr, sizeof(u64));
537+ } else {
538+ memcpy(&data, addr, seg);
539+ memcpy((u8 *)&data + seg, cons->tx_buf.buf,
540+ sizeof(u64) - seg);
541+ }
542+ writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
543+
544+ if (size >= sizeof(u64)) {
545+ cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) %
546+ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
547+ size -= sizeof(u64);
548+ } else {
549+ cons->tx_buf.tail = (cons->tx_buf.tail + size) %
550+ MLXBF_TMFIFO_CON_TX_BUF_SIZE;
551+ size = 0;
552+ }
553+ }
554+
555+ spin_unlock_irqrestore(&fifo->spin_lock, flags);
556+}
557+
558+/* Rx/Tx one word in the descriptor buffer. */
559+static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
560+ struct vring_desc *desc,
561+ bool is_rx, int len)
562+{
563+ struct virtio_device *vdev = vring->vq->vdev;
564+ struct mlxbf_tmfifo *fifo = vring->fifo;
565+ void *addr;
566+ u64 data;
567+
568+ /* Get the buffer address of this desc. */
569+ addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
570+
571+ /* Read a word from FIFO for Rx. */
572+ if (is_rx)
573+ data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
574+
575+ if (vring->cur_len + sizeof(u64) <= len) {
576+ /* The whole word. */
577+ if (is_rx)
578+ memcpy(addr + vring->cur_len, &data, sizeof(u64));
579+ else
580+ memcpy(&data, addr + vring->cur_len, sizeof(u64));
581+ vring->cur_len += sizeof(u64);
582+ } else {
583+ /* Leftover bytes. */
584+ if (is_rx)
585+ memcpy(addr + vring->cur_len, &data,
586+ len - vring->cur_len);
587+ else
588+ memcpy(&data, addr + vring->cur_len,
589+ len - vring->cur_len);
590+ vring->cur_len = len;
591+ }
592+
593+ /* Write the word into FIFO for Tx. */
594+ if (!is_rx)
595+ writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
596+}
597+
598+/*
599+ * Rx/Tx packet header.
600+ *
601+ * In Rx case, the packet might be found to belong to a different vring since
602+ * the TmFifo is shared by different services. In such case, the 'vring_change'
603+ * flag is set.
604+ */
605+static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
606+ struct vring_desc *desc,
607+ bool is_rx, bool *vring_change)
608+{
609+ struct mlxbf_tmfifo *fifo = vring->fifo;
610+ struct virtio_net_config *config;
611+ struct mlxbf_tmfifo_msg_hdr hdr;
612+ int vdev_id, hdr_len;
613+
614+ /* Read/Write packet header. */
615+ if (is_rx) {
616+ /* Drain one word from the FIFO. */
617+ *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
618+
619+ /* Skip the length 0 packets (keepalive). */
620+ if (hdr.len == 0)
621+ return;
622+
623+ /* Check packet type. */
624+ if (hdr.type == VIRTIO_ID_NET) {
625+ vdev_id = VIRTIO_ID_NET;
626+ hdr_len = sizeof(struct virtio_net_hdr);
627+ config = &fifo->vdev[vdev_id]->config.net;
628+ if (ntohs(hdr.len) > config->mtu +
629+ MLXBF_TMFIFO_NET_L2_OVERHEAD)
630+ return;
631+ } else {
632+ vdev_id = VIRTIO_ID_CONSOLE;
633+ hdr_len = 0;
634+ }
635+
636+ /*
637+ * Check whether the new packet still belongs to this vring.
638+ * If not, update the pkt_len of the new vring.
639+ */
640+ if (vdev_id != vring->vdev_id) {
641+ struct mlxbf_tmfifo_vdev *tm_dev2 = fifo->vdev[vdev_id];
642+
643+ if (!tm_dev2)
644+ return;
645+ vring->desc = desc;
646+ vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX];
647+ *vring_change = true;
648+ }
649+ vring->pkt_len = ntohs(hdr.len) + hdr_len;
650+ } else {
651+ /* Network virtio has an extra header. */
652+ hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ?
653+ sizeof(struct virtio_net_hdr) : 0;
654+ vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc);
655+ hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?
656+ VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;
657+ hdr.len = htons(vring->pkt_len - hdr_len);
658+ writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
659+ }
660+
661+ vring->cur_len = hdr_len;
662+ vring->rem_len = vring->pkt_len;
663+ fifo->vring[is_rx] = vring;
664+}
665+
666+/*
667+ * Rx/Tx one descriptor.
668+ *
669+ * Return true to indicate more data available.
670+ */
671+static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,
672+ bool is_rx, int *avail)
673+{
674+ const struct vring *vr = virtqueue_get_vring(vring->vq);
675+ struct mlxbf_tmfifo *fifo = vring->fifo;
676+ struct virtio_device *vdev;
677+ bool vring_change = false;
678+ struct vring_desc *desc;
679+ unsigned long flags;
680+ u32 len, idx;
681+
682+ vdev = &fifo->vdev[vring->vdev_id]->vdev;
683+
684+ /* Get the descriptor of the next packet. */
685+ if (!vring->desc) {
686+ desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx);
687+ if (!desc)
688+ return false;
689+ } else {
690+ desc = vring->desc;
691+ }
692+
693+ /* Beginning of a packet. Start to Rx/Tx packet header. */
694+ if (vring->pkt_len == 0) {
695+ mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change);
696+ (*avail)--;
697+
698+ /* Return if new packet is for another ring. */
699+ if (vring_change)
700+ return false;
701+ goto mlxbf_tmfifo_desc_done;
702+ }
703+
704+ /* Get the length of this desc. */
705+ len = virtio32_to_cpu(vdev, desc->len);
706+ if (len > vring->rem_len)
707+ len = vring->rem_len;
708+
709+ /* Rx/Tx one word (8 bytes) if not done. */
710+ if (vring->cur_len < len) {
711+ mlxbf_tmfifo_rxtx_word(vring, desc, is_rx, len);
712+ (*avail)--;
713+ }
714+
715+ /* Check again whether it's done. */
716+ if (vring->cur_len == len) {
717+ vring->cur_len = 0;
718+ vring->rem_len -= len;
719+
720+ /* Get the next desc on the chain. */
721+ if (vring->rem_len > 0 &&
722+ (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) {
723+ idx = virtio16_to_cpu(vdev, desc->next);
724+ desc = &vr->desc[idx];
725+ goto mlxbf_tmfifo_desc_done;
726+ }
727+
728+ /* Done and release the pending packet. */
729+ mlxbf_tmfifo_release_pending_pkt(vring);
730+ desc = NULL;
731+ fifo->vring[is_rx] = NULL;
732+
733+ /* Notify upper layer that packet is done. */
734+ spin_lock_irqsave(&fifo->spin_lock, flags);
735+ vring_interrupt(0, vring->vq);
736+ spin_unlock_irqrestore(&fifo->spin_lock, flags);
737+ }
738+
739+mlxbf_tmfifo_desc_done:
740+ /* Save the current desc. */
741+ vring->desc = desc;
742+
743+ return true;
744+}
745+
746+/* Rx & Tx processing of a queue. */
747+static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
748+{
749+ int avail = 0, devid = vring->vdev_id;
750+ struct mlxbf_tmfifo *fifo;
751+ bool more;
752+
753+ fifo = vring->fifo;
754+
755+ /* Return if vdev is not ready. */
756+ if (!fifo->vdev[devid])
757+ return;
758+
759+ /* Return if another vring is running. */
760+ if (fifo->vring[is_rx] && fifo->vring[is_rx] != vring)
761+ return;
762+
763+ /* Only handle console and network for now. */
764+ if (WARN_ON(devid != VIRTIO_ID_NET && devid != VIRTIO_ID_CONSOLE))
765+ return;
766+
767+ do {
768+ /* Get available FIFO space. */
769+ if (avail == 0) {
770+ if (is_rx)
771+ avail = mlxbf_tmfifo_get_rx_avail(fifo);
772+ else
773+ avail = mlxbf_tmfifo_get_tx_avail(fifo, devid);
774+ if (avail <= 0)
775+ break;
776+ }
777+
778+ /* Console output always comes from the Tx buffer. */
779+ if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
780+ mlxbf_tmfifo_console_tx(fifo, avail);
781+ break;
782+ }
783+
784+ /* Handle one descriptor. */
785+ more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
786+ } while (more);
787+}
788+
789+/* Handle Rx or Tx queues. */
790+static void mlxbf_tmfifo_work_rxtx(struct mlxbf_tmfifo *fifo, int queue_id,
791+ int irq_id, bool is_rx)
792+{
793+ struct mlxbf_tmfifo_vdev *tm_vdev;
794+ struct mlxbf_tmfifo_vring *vring;
795+ int i;
796+
797+ if (!test_and_clear_bit(irq_id, &fifo->pend_events) ||
798+ !fifo->irq_info[irq_id].irq)
799+ return;
800+
801+ for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++) {
802+ tm_vdev = fifo->vdev[i];
803+ if (tm_vdev) {
804+ vring = &tm_vdev->vrings[queue_id];
805+ if (vring->vq)
806+ mlxbf_tmfifo_rxtx(vring, is_rx);
807+ }
808+ }
809+}
810+
811+/* Work handler for Rx and Tx case. */
812+static void mlxbf_tmfifo_work_handler(struct work_struct *work)
813+{
814+ struct mlxbf_tmfifo *fifo;
815+
816+ fifo = container_of(work, struct mlxbf_tmfifo, work);
817+ if (!fifo->is_ready)
818+ return;
819+
820+ mutex_lock(&fifo->lock);
821+
822+ /* Tx (Send data to the TmFifo). */
823+ mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_TX,
824+ MLXBF_TM_TX_LWM_IRQ, false);
825+
826+ /* Rx (Receive data from the TmFifo). */
827+ mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_RX,
828+ MLXBF_TM_RX_HWM_IRQ, true);
829+
830+ mutex_unlock(&fifo->lock);
831+}
832+
833+/* The notify function is called when new buffers are posted. */
834+static bool mlxbf_tmfifo_virtio_notify(struct virtqueue *vq)
835+{
836+ struct mlxbf_tmfifo_vring *vring = vq->priv;
837+ struct mlxbf_tmfifo_vdev *tm_vdev;
838+ struct mlxbf_tmfifo *fifo;
839+ unsigned long flags;
840+
841+ fifo = vring->fifo;
842+
843+ /*
844+ * Virtio maintains vrings in pairs, even number ring for Rx
845+ * and odd number ring for Tx.
846+ */
847+ if (vring->index & BIT(0)) {
848+ /*
849+ * Console could make blocking call with interrupts disabled.
850+ * In such case, the vring needs to be served right away. For
851+ * other cases, just set the TX LWM bit to start Tx in the
852+ * worker handler.
853+ */
854+ if (vring->vdev_id == VIRTIO_ID_CONSOLE) {
855+ spin_lock_irqsave(&fifo->spin_lock, flags);
856+ tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE];
857+ mlxbf_tmfifo_console_output(tm_vdev, vring);
858+ spin_unlock_irqrestore(&fifo->spin_lock, flags);
859+ } else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ,
860+ &fifo->pend_events)) {
861+ return true;
862+ }
863+ } else {
864+ if (test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events))
865+ return true;
866+ }
867+
868+ schedule_work(&fifo->work);
869+
870+ return true;
871+}
872+
873+/* Get the array of feature bits for this device. */
874+static u64 mlxbf_tmfifo_virtio_get_features(struct virtio_device *vdev)
875+{
876+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
877+
878+ return tm_vdev->features;
879+}
880+
881+/* Confirm device features to use. */
882+static int mlxbf_tmfifo_virtio_finalize_features(struct virtio_device *vdev)
883+{
884+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
885+
886+ tm_vdev->features = vdev->features;
887+
888+ return 0;
889+}
890+
891+/* Free virtqueues found by find_vqs(). */
892+static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev)
893+{
894+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
895+ struct mlxbf_tmfifo_vring *vring;
896+ struct virtqueue *vq;
897+ int i;
898+
899+ for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
900+ vring = &tm_vdev->vrings[i];
901+
902+ /* Release the pending packet. */
903+ if (vring->desc)
904+ mlxbf_tmfifo_release_pending_pkt(vring);
905+ vq = vring->vq;
906+ if (vq) {
907+ vring->vq = NULL;
908+ vring_del_virtqueue(vq);
909+ }
910+ }
911+}
912+
913+/* Create and initialize the virtual queues. */
914+static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev,
915+ unsigned int nvqs,
916+ struct virtqueue *vqs[],
917+ vq_callback_t *callbacks[],
918+ const char * const names[],
919+ const bool *ctx,
920+ struct irq_affinity *desc)
921+{
922+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
923+ struct mlxbf_tmfifo_vring *vring;
924+ struct virtqueue *vq;
925+ int i, ret, size;
926+
927+ if (nvqs > ARRAY_SIZE(tm_vdev->vrings))
928+ return -EINVAL;
929+
930+ for (i = 0; i < nvqs; ++i) {
931+ if (!names[i]) {
932+ ret = -EINVAL;
933+ goto error;
934+ }
935+ vring = &tm_vdev->vrings[i];
936+
937+ /* zero vring */
938+ size = vring_size(vring->num, vring->align);
939+ memset(vring->va, 0, size);
940+ vq = vring_new_virtqueue(i, vring->num, vring->align, vdev,
941+ false, false, vring->va,
942+ mlxbf_tmfifo_virtio_notify,
943+ callbacks[i], names[i]);
944+ if (!vq) {
945+ dev_err(&vdev->dev, "vring_new_virtqueue failed\n");
946+ ret = -ENOMEM;
947+ goto error;
948+ }
949+
950+ vqs[i] = vq;
951+ vring->vq = vq;
952+ vq->priv = vring;
953+ }
954+
955+ return 0;
956+
957+error:
958+ mlxbf_tmfifo_virtio_del_vqs(vdev);
959+ return ret;
960+}
961+
962+/* Read the status byte. */
963+static u8 mlxbf_tmfifo_virtio_get_status(struct virtio_device *vdev)
964+{
965+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
966+
967+ return tm_vdev->status;
968+}
969+
970+/* Write the status byte. */
971+static void mlxbf_tmfifo_virtio_set_status(struct virtio_device *vdev,
972+ u8 status)
973+{
974+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
975+
976+ tm_vdev->status = status;
977+}
978+
979+/* Reset the device. Not much here for now. */
980+static void mlxbf_tmfifo_virtio_reset(struct virtio_device *vdev)
981+{
982+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
983+
984+ tm_vdev->status = 0;
985+}
986+
987+/* Read the value of a configuration field. */
988+static void mlxbf_tmfifo_virtio_get(struct virtio_device *vdev,
989+ unsigned int offset,
990+ void *buf,
991+ unsigned int len)
992+{
993+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
994+
995+ if ((u64)offset + len > sizeof(tm_vdev->config))
996+ return;
997+
998+ memcpy(buf, (u8 *)&tm_vdev->config + offset, len);
999+}
1000+
1001+/* Write the value of a configuration field. */
1002+static void mlxbf_tmfifo_virtio_set(struct virtio_device *vdev,
1003+ unsigned int offset,
1004+ const void *buf,
1005+ unsigned int len)
1006+{
1007+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
1008+
1009+ if ((u64)offset + len > sizeof(tm_vdev->config))
1010+ return;
1011+
1012+ memcpy((u8 *)&tm_vdev->config + offset, buf, len);
1013+}
1014+
1015+static void tmfifo_virtio_dev_release(struct device *device)
1016+{
1017+ struct virtio_device *vdev =
1018+ container_of(device, struct virtio_device, dev);
1019+ struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
1020+
1021+ kfree(tm_vdev);
1022+}
1023+
1024+/* Virtio config operations. */
1025+static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = {
1026+ .get_features = mlxbf_tmfifo_virtio_get_features,
1027+ .finalize_features = mlxbf_tmfifo_virtio_finalize_features,
1028+ .find_vqs = mlxbf_tmfifo_virtio_find_vqs,
1029+ .del_vqs = mlxbf_tmfifo_virtio_del_vqs,
1030+ .reset = mlxbf_tmfifo_virtio_reset,
1031+ .set_status = mlxbf_tmfifo_virtio_set_status,
1032+ .get_status = mlxbf_tmfifo_virtio_get_status,
1033+ .get = mlxbf_tmfifo_virtio_get,
1034+ .set = mlxbf_tmfifo_virtio_set,
1035+};
1036+
1037+/* Create vdev for the FIFO. */
1038+static int mlxbf_tmfifo_create_vdev(struct device *dev,
1039+ struct mlxbf_tmfifo *fifo,
1040+ int vdev_id, u64 features,
1041+ void *config, u32 size)
1042+{
1043+ struct mlxbf_tmfifo_vdev *tm_vdev, *reg_dev = NULL;
1044+ int ret;
1045+
1046+ mutex_lock(&fifo->lock);
1047+
1048+ tm_vdev = fifo->vdev[vdev_id];
1049+ if (tm_vdev) {
1050+ dev_err(dev, "vdev %d already exists\n", vdev_id);
1051+ ret = -EEXIST;
1052+ goto fail;
1053+ }
1054+
1055+ tm_vdev = kzalloc(sizeof(*tm_vdev), GFP_KERNEL);
1056+ if (!tm_vdev) {
1057+ ret = -ENOMEM;
1058+ goto fail;
1059+ }
1060+
1061+ tm_vdev->vdev.id.device = vdev_id;
1062+ tm_vdev->vdev.config = &mlxbf_tmfifo_virtio_config_ops;
1063+ tm_vdev->vdev.dev.parent = dev;
1064+ tm_vdev->vdev.dev.release = tmfifo_virtio_dev_release;
1065+ tm_vdev->features = features;
1066+ if (config)
1067+ memcpy(&tm_vdev->config, config, size);
1068+
1069+ if (mlxbf_tmfifo_alloc_vrings(fifo, tm_vdev)) {
1070+ dev_err(dev, "unable to allocate vring\n");
1071+ ret = -ENOMEM;
1072+ goto vdev_fail;
1073+ }
1074+
1075+ /* Allocate an output buffer for the console device. */
1076+ if (vdev_id == VIRTIO_ID_CONSOLE)
1077+ tm_vdev->tx_buf.buf = devm_kmalloc(dev,
1078+ MLXBF_TMFIFO_CON_TX_BUF_SIZE,
1079+ GFP_KERNEL);
1080+ fifo->vdev[vdev_id] = tm_vdev;
1081+
1082+ /* Register the virtio device. */
1083+ ret = register_virtio_device(&tm_vdev->vdev);
1084+ reg_dev = tm_vdev;
1085+ if (ret) {
1086+ dev_err(dev, "register_virtio_device failed\n");
1087+ goto vdev_fail;
1088+ }
1089+
1090+ mutex_unlock(&fifo->lock);
1091+ return 0;
1092+
1093+vdev_fail:
1094+ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
1095+ fifo->vdev[vdev_id] = NULL;
1096+ if (reg_dev)
1097+ put_device(&tm_vdev->vdev.dev);
1098+ else
1099+ kfree(tm_vdev);
1100+fail:
1101+ mutex_unlock(&fifo->lock);
1102+ return ret;
1103+}
1104+
1105+/* Delete vdev for the FIFO. */
1106+static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id)
1107+{
1108+ struct mlxbf_tmfifo_vdev *tm_vdev;
1109+
1110+ mutex_lock(&fifo->lock);
1111+
1112+ /* Unregister vdev. */
1113+ tm_vdev = fifo->vdev[vdev_id];
1114+ if (tm_vdev) {
1115+ unregister_virtio_device(&tm_vdev->vdev);
1116+ mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
1117+ fifo->vdev[vdev_id] = NULL;
1118+ }
1119+
1120+ mutex_unlock(&fifo->lock);
1121+
1122+ return 0;
1123+}
1124+
1125+/* Read the configured network MAC address from efi variable. */
1126+static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
1127+{
1128+ efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
1129+ unsigned long size = ETH_ALEN;
1130+ u8 buf[ETH_ALEN];
1131+ efi_status_t rc;
1132+
1133+ rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
1134+ if (rc == EFI_SUCCESS && size == ETH_ALEN)
1135+ ether_addr_copy(mac, buf);
1136+ else
1137+ ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
1138+}
1139+
1140+/* Set TmFifo thresolds which is used to trigger interrupts. */
1141+static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
1142+{
1143+ u64 ctl;
1144+
1145+ /* Get Tx FIFO size and set the low/high watermark. */
1146+ ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
1147+ fifo->tx_fifo_size =
1148+ FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl);
1149+ ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) |
1150+ FIELD_PREP(MLXBF_TMFIFO_TX_CTL__LWM_MASK,
1151+ fifo->tx_fifo_size / 2);
1152+ ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) |
1153+ FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK,
1154+ fifo->tx_fifo_size - 1);
1155+ writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
1156+
1157+ /* Get Rx FIFO size and set the low/high watermark. */
1158+ ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
1159+ fifo->rx_fifo_size =
1160+ FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl);
1161+ ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) |
1162+ FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0);
1163+ ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) |
1164+ FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1);
1165+ writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
1166+}
1167+
1168+static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
1169+{
1170+ int i;
1171+
1172+ fifo->is_ready = false;
1173+ del_timer_sync(&fifo->timer);
1174+ mlxbf_tmfifo_disable_irqs(fifo);
1175+ cancel_work_sync(&fifo->work);
1176+ for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++)
1177+ mlxbf_tmfifo_delete_vdev(fifo, i);
1178+}
1179+
1180+/* Probe the TMFIFO. */
1181+static int mlxbf_tmfifo_probe(struct platform_device *pdev)
1182+{
1183+ struct virtio_net_config net_config;
1184+ struct device *dev = &pdev->dev;
1185+ struct mlxbf_tmfifo *fifo;
1186+ int i, rc;
1187+
1188+ fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
1189+ if (!fifo)
1190+ return -ENOMEM;
1191+
1192+ spin_lock_init(&fifo->spin_lock);
1193+ INIT_WORK(&fifo->work, mlxbf_tmfifo_work_handler);
1194+ mutex_init(&fifo->lock);
1195+
1196+ /* Get the resource of the Rx FIFO. */
1197+ fifo->rx_base = devm_platform_ioremap_resource(pdev, 0);
1198+ if (IS_ERR(fifo->rx_base))
1199+ return PTR_ERR(fifo->rx_base);
1200+
1201+ /* Get the resource of the Tx FIFO. */
1202+ fifo->tx_base = devm_platform_ioremap_resource(pdev, 1);
1203+ if (IS_ERR(fifo->tx_base))
1204+ return PTR_ERR(fifo->tx_base);
1205+
1206+ platform_set_drvdata(pdev, fifo);
1207+
1208+ timer_setup(&fifo->timer, mlxbf_tmfifo_timer, 0);
1209+
1210+ for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
1211+ fifo->irq_info[i].index = i;
1212+ fifo->irq_info[i].fifo = fifo;
1213+ fifo->irq_info[i].irq = platform_get_irq(pdev, i);
1214+ rc = devm_request_irq(dev, fifo->irq_info[i].irq,
1215+ mlxbf_tmfifo_irq_handler, 0,
1216+ "tmfifo", &fifo->irq_info[i]);
1217+ if (rc) {
1218+ dev_err(dev, "devm_request_irq failed\n");
1219+ fifo->irq_info[i].irq = 0;
1220+ return rc;
1221+ }
1222+ }
1223+
1224+ mlxbf_tmfifo_set_threshold(fifo);
1225+
1226+ /* Create the console vdev. */
1227+ rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_CONSOLE, 0, NULL, 0);
1228+ if (rc)
1229+ goto fail;
1230+
1231+ /* Create the network vdev. */
1232+ memset(&net_config, 0, sizeof(net_config));
1233+ net_config.mtu = ETH_DATA_LEN;
1234+ net_config.status = VIRTIO_NET_S_LINK_UP;
1235+ mlxbf_tmfifo_get_cfg_mac(net_config.mac);
1236+ rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_NET,
1237+ MLXBF_TMFIFO_NET_FEATURES, &net_config,
1238+ sizeof(net_config));
1239+ if (rc)
1240+ goto fail;
1241+
1242+ mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
1243+
1244+ fifo->is_ready = true;
1245+ return 0;
1246+
1247+fail:
1248+ mlxbf_tmfifo_cleanup(fifo);
1249+ return rc;
1250+}
1251+
1252+/* Device remove function. */
1253+static int mlxbf_tmfifo_remove(struct platform_device *pdev)
1254+{
1255+ struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev);
1256+
1257+ mlxbf_tmfifo_cleanup(fifo);
1258+
1259+ return 0;
1260+}
1261+
1262+static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = {
1263+ { "MLNXBF01", 0 },
1264+ {}
1265+};
1266+MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);
1267+
1268+static struct platform_driver mlxbf_tmfifo_driver = {
1269+ .probe = mlxbf_tmfifo_probe,
1270+ .remove = mlxbf_tmfifo_remove,
1271+ .driver = {
1272+ .name = "bf-tmfifo",
1273+ .acpi_match_table = mlxbf_tmfifo_acpi_match,
1274+ },
1275+};
1276+
1277+module_platform_driver(mlxbf_tmfifo_driver);
1278+
1279+MODULE_DESCRIPTION("Mellanox BlueField SoC TmFifo Driver");
1280+MODULE_LICENSE("GPL v2");
1281+MODULE_AUTHOR("Mellanox Technologies");
drivers/platform/x86/Kconfig+11−0
@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN · 1262 unmodified lines
12631263 To compile this driver as a module, choose M here: the module
12641264 will be called intel_chtdc_ti_pwrbtn.
12651265
1266+config INTEL_MRFLD_PWRBTN
1267+ tristate "Intel Merrifield Basin Cove power button driver"
1268+ depends on INTEL_SOC_PMIC_MRFLD
1269+ depends on INPUT
1270+ ---help---
1271+ This option adds a power button driver for Basin Cove PMIC
1272+ on Intel Merrifield devices.
1273+
1274+ To compile this driver as a module, choose M here: the module
1275+ will be called intel_mrfld_pwrbtn.
1276+
12661277 config I2C_MULTI_INSTANTIATE
12671278 tristate "I2C multi instantiate pseudo device driver"
12681279 depends on I2C && ACPI
drivers/platform/x86/Makefile+1−0
@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o · 93 unmodified lines
9494 obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
9595 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
9696 obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
97+obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
9798 obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
9899 obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
99100 obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
drivers/platform/x86/alienware-wmi.c+9−10
@@ -522,23 +522,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, · 521 unmodified lines
522522
523523 input.length = (acpi_size) sizeof(*in_args);
524524 input.pointer = in_args;
525− if (out_data != NULL) {
525+ if (out_data) {
526526 output.length = ACPI_ALLOCATE_BUFFER;
527527 output.pointer = NULL;
528528 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
529529 command, &input, &output);
530− } else
530+ if (ACPI_SUCCESS(status)) {
531+ obj = (union acpi_object *)output.pointer;
532+ if (obj && obj->type == ACPI_TYPE_INTEGER)
533+ *out_data = (u32)obj->integer.value;
534+ }
535+ kfree(output.pointer);
536+ } else {
531537 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
532538 command, &input, NULL);
533−
534− if (ACPI_SUCCESS(status) && out_data != NULL) {
535− obj = (union acpi_object *)output.pointer;
536− if (obj && obj->type == ACPI_TYPE_INTEGER)
537− *out_data = (u32) obj->integer.value;
538539 }
539− kfree(output.pointer);
540540 return status;
541−
542541 }
543542
544543 /*
@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev, · 43 unmodified lines
588587 return scnprintf(buf, PAGE_SIZE,
589588 "input [gpu] unknown\n");
590589 }
591− pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data);
590+ pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
592591 return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
593592 }
594593
drivers/platform/x86/asus-wmi.c+37−0
@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL"); · 65 unmodified lines
6666 #define NOTIFY_BRNUP_MAX 0x1f
6767 #define NOTIFY_BRNDOWN_MIN 0x20
6868 #define NOTIFY_BRNDOWN_MAX 0x2e
69+#define NOTIFY_FNLOCK_TOGGLE 0x4e
6970 #define NOTIFY_KBD_BRTUP 0xc4
7071 #define NOTIFY_KBD_BRTDWN 0xc5
7172 #define NOTIFY_KBD_BRTTOGGLE 0xc7
7273
74+#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
75+
7376 #define ASUS_FAN_DESC "cpu_fan"
7477 #define ASUS_FAN_MFUN 0x13
7578 #define ASUS_FAN_SFUN_READ 0x06
@@ -177,6 +180,8 @@ struct asus_wmi { · 101 unmodified lines
177180 struct workqueue_struct *hotplug_workqueue;
178181 struct work_struct hotplug_work;
179182
183+ bool fnlock_locked;
184+
180185 struct asus_wmi_debug debug;
181186
182187 struct asus_wmi_driver *driver;
@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code) · 1436 unmodified lines
16191624 return 0;
16201625 }
16211626
1627+static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
1628+{
1629+ u32 result;
1630+
1631+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result);
1632+
1633+ return (result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
1634+ !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED);
1635+}
1636+
1637+static void asus_wmi_fnlock_update(struct asus_wmi *asus)
1638+{
1639+ int mode = asus->fnlock_locked;
1640+
1641+ asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
1642+}
1643+
16221644 static void asus_wmi_notify(u32 value, void *context)
16231645 {
16241646 struct asus_wmi *asus = context;
@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context) · 55 unmodified lines
16801702 goto exit;
16811703 }
16821704
1705+ if (code == NOTIFY_FNLOCK_TOGGLE) {
1706+ asus->fnlock_locked = !asus->fnlock_locked;
1707+ asus_wmi_fnlock_update(asus);
1708+ goto exit;
1709+ }
1710+
16831711 if (is_display_toggle(code) &&
16841712 asus->driver->quirks->no_display_toggle)
16851713 goto exit;
@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev) · 448 unmodified lines
21342162 } else
21352163 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
21362164
2165+ if (asus_wmi_has_fnlock_key(asus)) {
2166+ asus->fnlock_locked = true;
2167+ asus_wmi_fnlock_update(asus);
2168+ }
2169+
21372170 status = wmi_install_notify_handler(asus->driver->event_guid,
21382171 asus_wmi_notify, asus);
21392172 if (ACPI_FAILURE(status)) {
@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device) · 73 unmodified lines
22132246 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
22142247 kbd_led_update(asus);
22152248
2249+ if (asus_wmi_has_fnlock_key(asus))
2250+ asus_wmi_fnlock_update(asus);
22162251 return 0;
22172252 }
22182253
@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device) · 30 unmodified lines
22492284 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
22502285 kbd_led_update(asus);
22512286
2287+ if (asus_wmi_has_fnlock_key(asus))
2288+ asus_wmi_fnlock_update(asus);
22522289 return 0;
22532290 }
22542291
drivers/platform/x86/dell-laptop.c+3−3
@@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) · 530 unmodified lines
531531 return;
532532 }
533533
534− dell_fill_request(&buffer, 0, 0x2, 0, 0);
534+ dell_fill_request(&buffer, 0x2, 0, 0, 0);
535535 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
536536 hwswitch = buffer.output[1];
537537
@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) · 24 unmodified lines
562562 return ret;
563563 status = buffer.output[1];
564564
565− dell_fill_request(&buffer, 0, 0x2, 0, 0);
565+ dell_fill_request(&buffer, 0x2, 0, 0, 0);
566566 hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
567567 if (hwswitch_ret)
568568 return hwswitch_ret;
@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored) · 78 unmodified lines
647647 if (ret != 0)
648648 return;
649649
650− dell_fill_request(&buffer, 0, 0x2, 0, 0);
650+ dell_fill_request(&buffer, 0x2, 0, 0, 0);
651651 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
652652
653653 if (ret == 0 && (status & BIT(0)))
drivers/platform/x86/dell-rbtn.c+2−0
@@ -18,6 +18,8 @@ · 17 unmodified lines
1818 #include <linux/rfkill.h>
1919 #include <linux/input.h>
2020
21+#include "dell-rbtn.h"
22+
2123 enum rbtn_type {
2224 RBTN_UNKNOWN,
2325 RBTN_TOGGLE,
drivers/platform/x86/ideapad-laptop.c+15−306
@@ -980,312 +980,21 @@ static void ideapad_wmi_notify(u32 value, void *context) · 979 unmodified lines
980980 #endif
981981
982982 /*
983− * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
984− * always results in 0 on these models, causing ideapad_laptop to wrongly
985− * report all radios as hardware-blocked.
983+ * Some ideapads have a hardware rfkill switch, but most do not have one.
984+ * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
985+ * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
986+ * There used to be a long list of DMI ids for models without a hw rfkill
987+ * switch here, but that resulted in playing whack a mole.
988+ * More importantly wrongly reporting the wifi radio as hw-blocked, results in
989+ * non working wifi. Whereas not reporting it hw-blocked, when it actually is
990+ * hw-blocked results in an empty SSID list, which is a much more benign
991+ * failure mode.
992+ * So the default now is the much safer option of assuming there is no
993+ * hardware rfkill switch. This default also actually matches most hardware,
994+ * since having a hw rfkill switch is quite rare on modern hardware, so this
995+ * also leads to a much shorter list.
986996 */
987−static const struct dmi_system_id no_hw_rfkill_list[] = {
988− {
989− .ident = "Lenovo RESCUER R720-15IKBN",
990− .matches = {
991− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
992− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo R720-15IKBN"),
993− },
994− },
995− {
996− .ident = "Lenovo G40-30",
997− .matches = {
998− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
999− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
1000− },
1001− },
1002− {
1003− .ident = "Lenovo G50-30",
1004− .matches = {
1005− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1006− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
1007− },
1008− },
1009− {
1010− .ident = "Lenovo V310-14IKB",
1011− .matches = {
1012− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1013− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
1014− },
1015− },
1016− {
1017− .ident = "Lenovo V310-14ISK",
1018− .matches = {
1019− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1020− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
1021− },
1022− },
1023− {
1024− .ident = "Lenovo V310-15IKB",
1025− .matches = {
1026− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1027− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
1028− },
1029− },
1030− {
1031− .ident = "Lenovo V310-15ISK",
1032− .matches = {
1033− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1034− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
1035− },
1036− },
1037− {
1038− .ident = "Lenovo V510-15IKB",
1039− .matches = {
1040− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1041− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
1042− },
1043− },
1044− {
1045− .ident = "Lenovo ideapad 300-15IBR",
1046− .matches = {
1047− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1048− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
1049− },
1050− },
1051− {
1052− .ident = "Lenovo ideapad 300-15IKB",
1053− .matches = {
1054− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1055− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
1056− },
1057− },
1058− {
1059− .ident = "Lenovo ideapad 300S-11IBR",
1060− .matches = {
1061− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1062− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
1063− },
1064− },
1065− {
1066− .ident = "Lenovo ideapad 310-15ABR",
1067− .matches = {
1068− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1069− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
1070− },
1071− },
1072− {
1073− .ident = "Lenovo ideapad 310-15IAP",
1074− .matches = {
1075− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1076− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
1077− },
1078− },
1079− {
1080− .ident = "Lenovo ideapad 310-15IKB",
1081− .matches = {
1082− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1083− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
1084− },
1085− },
1086− {
1087− .ident = "Lenovo ideapad 310-15ISK",
1088− .matches = {
1089− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1090− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
1091− },
1092− },
1093− {
1094− .ident = "Lenovo ideapad 330-15ICH",
1095− .matches = {
1096− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1097− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 330-15ICH"),
1098− },
1099− },
1100− {
1101− .ident = "Lenovo ideapad 530S-14ARR",
1102− .matches = {
1103− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1104− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 530S-14ARR"),
1105− },
1106− },
1107− {
1108− .ident = "Lenovo ideapad S130-14IGM",
1109− .matches = {
1110− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1111− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad S130-14IGM"),
1112− },
1113− },
1114− {
1115− .ident = "Lenovo ideapad Y700-14ISK",
1116− .matches = {
1117− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1118− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
1119− },
1120− },
1121− {
1122− .ident = "Lenovo ideapad Y700-15ACZ",
1123− .matches = {
1124− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1125− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
1126− },
1127− },
1128− {
1129− .ident = "Lenovo ideapad Y700-15ISK",
1130− .matches = {
1131− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1132− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
1133− },
1134− },
1135− {
1136− .ident = "Lenovo ideapad Y700 Touch-15ISK",
1137− .matches = {
1138− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1139− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
1140− },
1141− },
1142− {
1143− .ident = "Lenovo ideapad Y700-17ISK",
1144− .matches = {
1145− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1146− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
1147− },
1148− },
1149− {
1150− .ident = "Lenovo ideapad MIIX 720-12IKB",
1151− .matches = {
1152− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1153− DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 720-12IKB"),
1154− },
1155− },
1156− {
1157− .ident = "Lenovo Legion Y520-15IKB",
1158− .matches = {
1159− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1160− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"),
1161− },
1162− },
1163− {
1164− .ident = "Lenovo Y520-15IKBM",
1165− .matches = {
1166− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1167− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"),
1168− },
1169− },
1170− {
1171− .ident = "Lenovo Legion Y530-15ICH",
1172− .matches = {
1173− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1174− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH"),
1175− },
1176− },
1177− {
1178− .ident = "Lenovo Legion Y530-15ICH-1060",
1179− .matches = {
1180− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1181− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH-1060"),
1182− },
1183− },
1184− {
1185− .ident = "Lenovo Legion Y720-15IKB",
1186− .matches = {
1187− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1188− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
1189− },
1190− },
1191− {
1192− .ident = "Lenovo Legion Y720-15IKBN",
1193− .matches = {
1194− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1195− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
1196− },
1197− },
1198− {
1199− .ident = "Lenovo Y720-15IKBM",
1200− .matches = {
1201− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1202− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"),
1203− },
1204− },
1205− {
1206− .ident = "Lenovo Yoga 2 11 / 13 / Pro",
1207− .matches = {
1208− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1209− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
1210− },
1211− },
1212− {
1213− .ident = "Lenovo Yoga 2 11 / 13 / Pro",
1214− .matches = {
1215− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1216− DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
1217− },
1218− },
1219− {
1220− .ident = "Lenovo Yoga 2 13",
1221− .matches = {
1222− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1223− DMI_MATCH(DMI_PRODUCT_VERSION, "Yoga 2 13"),
1224− },
1225− },
1226− {
1227− .ident = "Lenovo Yoga 3 1170 / 1470",
1228− .matches = {
1229− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1230− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"),
1231− },
1232− },
1233− {
1234− .ident = "Lenovo Yoga 3 Pro 1370",
1235− .matches = {
1236− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1237− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
1238− },
1239− },
1240− {
1241− .ident = "Lenovo Yoga 700",
1242− .matches = {
1243− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1244− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
1245− },
1246− },
1247− {
1248− .ident = "Lenovo Yoga 900",
1249− .matches = {
1250− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1251− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
1252− },
1253− },
1254− {
1255− .ident = "Lenovo Yoga 900",
1256− .matches = {
1257− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1258− DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
1259− },
1260− },
1261− {
1262− .ident = "Lenovo YOGA 910-13IKB",
1263− .matches = {
1264− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1265− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
1266− },
1267− },
1268− {
1269− .ident = "Lenovo YOGA 920-13IKB",
1270− .matches = {
1271− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1272− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
1273− },
1274− },
1275− {
1276− .ident = "Lenovo YOGA C930-13IKB",
1277− .matches = {
1278− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1279− DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA C930-13IKB"),
1280− },
1281− },
1282− {
1283− .ident = "Lenovo Zhaoyang E42-80",
1284− .matches = {
1285− DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1286− DMI_MATCH(DMI_PRODUCT_VERSION, "ZHAOYANG E42-80"),
1287− },
1288− },
997+static const struct dmi_system_id hw_rfkill_list[] = {
1289998 {}
1290999 };
12911000
@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) · 19 unmodified lines
13111020 priv->cfg = cfg;
13121021 priv->adev = adev;
13131022 priv->platform_device = pdev;
1314− priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
1023+ priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
13151024
13161025 ret = ideapad_sysfs_init(priv);
13171026 if (ret)
drivers/platform/x86/intel_mrfld_pwrbtn.c+107−0
@@ -0,0 +1,107 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * Power-button driver for Basin Cove PMIC
4+ *
5+ * Copyright (c) 2019, Intel Corporation.
6+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
7+ */
8+
9+#include <linux/input.h>
10+#include <linux/interrupt.h>
11+#include <linux/device.h>
12+#include <linux/mfd/intel_soc_pmic.h>
13+#include <linux/mfd/intel_soc_pmic_mrfld.h>
14+#include <linux/module.h>
15+#include <linux/platform_device.h>
16+#include <linux/pm_wakeirq.h>
17+#include <linux/slab.h>
18+
19+#define BCOVE_PBSTATUS 0x27
20+#define BCOVE_PBSTATUS_PBLVL BIT(4) /* 1 - release, 0 - press */
21+
22+static irqreturn_t mrfld_pwrbtn_interrupt(int irq, void *dev_id)
23+{
24+ struct input_dev *input = dev_id;
25+ struct device *dev = input->dev.parent;
26+ struct regmap *regmap = dev_get_drvdata(dev);
27+ unsigned int state;
28+ int ret;
29+
30+ ret = regmap_read(regmap, BCOVE_PBSTATUS, &state);
31+ if (ret)
32+ return IRQ_NONE;
33+
34+ dev_dbg(dev, "PBSTATUS=0x%x\n", state);
35+ input_report_key(input, KEY_POWER, !(state & BCOVE_PBSTATUS_PBLVL));
36+ input_sync(input);
37+
38+ regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
39+ return IRQ_HANDLED;
40+}
41+
42+static int mrfld_pwrbtn_probe(struct platform_device *pdev)
43+{
44+ struct device *dev = &pdev->dev;
45+ struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
46+ struct input_dev *input;
47+ int irq, ret;
48+
49+ irq = platform_get_irq(pdev, 0);
50+ if (irq < 0)
51+ return irq;
52+
53+ input = devm_input_allocate_device(dev);
54+ if (!input)
55+ return -ENOMEM;
56+ input->name = pdev->name;
57+ input->phys = "power-button/input0";
58+ input->id.bustype = BUS_HOST;
59+ input->dev.parent = dev;
60+ input_set_capability(input, EV_KEY, KEY_POWER);
61+ ret = input_register_device(input);
62+ if (ret)
63+ return ret;
64+
65+ dev_set_drvdata(dev, pmic->regmap);
66+
67+ ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_pwrbtn_interrupt,
68+ IRQF_ONESHOT | IRQF_SHARED, pdev->name,
69+ input);
70+ if (ret)
71+ return ret;
72+
73+ regmap_update_bits(pmic->regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
74+ regmap_update_bits(pmic->regmap, BCOVE_MPBIRQ, BCOVE_PBIRQ_PBTN, 0);
75+
76+ device_init_wakeup(dev, true);
77+ dev_pm_set_wake_irq(dev, irq);
78+ return 0;
79+}
80+
81+static int mrfld_pwrbtn_remove(struct platform_device *pdev)
82+{
83+ struct device *dev = &pdev->dev;
84+
85+ dev_pm_clear_wake_irq(dev);
86+ device_init_wakeup(dev, false);
87+ return 0;
88+}
89+
90+static const struct platform_device_id mrfld_pwrbtn_id_table[] = {
91+ { .name = "mrfld_bcove_pwrbtn" },
92+ {}
93+};
94+MODULE_DEVICE_TABLE(platform, mrfld_pwrbtn_id_table);
95+
96+static struct platform_driver mrfld_pwrbtn_driver = {
97+ .driver = {
98+ .name = "mrfld_bcove_pwrbtn",
99+ },
100+ .probe = mrfld_pwrbtn_probe,
101+ .remove = mrfld_pwrbtn_remove,
102+ .id_table = mrfld_pwrbtn_id_table,
103+};
104+module_platform_driver(mrfld_pwrbtn_driver);
105+
106+MODULE_DESCRIPTION("Power-button driver for Basin Cove PMIC");
107+MODULE_LICENSE("GPL v2");
drivers/platform/x86/intel_pmc_core.c+163−9
@@ -19,6 +19,8 @@ · 18 unmodified lines
1919 #include <linux/io.h>
2020 #include <linux/module.h>
2121 #include <linux/pci.h>
22+#include <linux/platform_device.h>
23+#include <linux/suspend.h>
2224 #include <linux/uaccess.h>
2325
2426 #include <asm/cpu_device_id.h>
@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = { · 803 unmodified lines
828830 * the platform BIOS enforces 24Mhx Crystal to shutdown
829831 * before PMC can assert SLP_S0#.
830832 */
831−int quirk_xtal_ignore(const struct dmi_system_id *id)
833+static int quirk_xtal_ignore(const struct dmi_system_id *id)
832834 {
833835 struct pmc_dev *pmcdev = &pmc;
834836 u32 value;
@@ -854,13 +856,17 @@ static const struct dmi_system_id pmc_core_dmi_table[] = { · 19 unmodified lines
854856 {}
855857 };
856858
857−static int __init pmc_core_probe(void)
859+static int pmc_core_probe(struct platform_device *pdev)
858860 {
861+ static bool device_initialized;
859862 struct pmc_dev *pmcdev = &pmc;
860863 const struct x86_cpu_id *cpu_id;
861864 u64 slp_s0_addr;
862865 int err;
863866
867+ if (device_initialized)
868+ return -ENODEV;
869+
864870 cpu_id = x86_match_cpu(intel_pmc_core_ids);
865871 if (!cpu_id)
866872 return -ENODEV;
@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void) · 19 unmodified lines
886892 return -ENOMEM;
887893
888894 mutex_init(&pmcdev->lock);
895+ platform_set_drvdata(pdev, pmcdev);
889896 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
897+ dmi_check_system(pmc_core_dmi_table);
890898
891899 err = pmc_core_dbgfs_register(pmcdev);
892900 if (err < 0) {
893− pr_warn(" debugfs register failed.\n");
901+ dev_warn(&pdev->dev, "debugfs register failed.\n");
894902 iounmap(pmcdev->regbase);
895903 return err;
896904 }
897905
898− dmi_check_system(pmc_core_dmi_table);
899− pr_info(" initialized\n");
906+ device_initialized = true;
907+ dev_info(&pdev->dev, " initialized\n");
908+
900909 return 0;
901910 }
902−module_init(pmc_core_probe)
903911
904−static void __exit pmc_core_remove(void)
912+static int pmc_core_remove(struct platform_device *pdev)
905913 {
906− struct pmc_dev *pmcdev = &pmc;
914+ struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
907915
908916 pmc_core_dbgfs_unregister(pmcdev);
917+ platform_set_drvdata(pdev, NULL);
909918 mutex_destroy(&pmcdev->lock);
910919 iounmap(pmcdev->regbase);
920+ return 0;
911921 }
912−module_exit(pmc_core_remove)
922+
923+#ifdef CONFIG_PM_SLEEP
924+
925+static bool warn_on_s0ix_failures;
926+module_param(warn_on_s0ix_failures, bool, 0644);
927+MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
928+
929+static int pmc_core_suspend(struct device *dev)
930+{
931+ struct pmc_dev *pmcdev = dev_get_drvdata(dev);
932+
933+ pmcdev->check_counters = false;
934+
935+ /* No warnings on S0ix failures */
936+ if (!warn_on_s0ix_failures)
937+ return 0;
938+
939+ /* Check if the syspend will actually use S0ix */
940+ if (pm_suspend_via_firmware())
941+ return 0;
942+
943+ /* Save PC10 residency for checking later */
944+ if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pmcdev->pc10_counter))
945+ return -EIO;
946+
947+ /* Save S0ix residency for checking later */
948+ if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
949+ return -EIO;
950+
951+ pmcdev->check_counters = true;
952+ return 0;
953+}
954+
955+static inline bool pmc_core_is_pc10_failed(struct pmc_dev *pmcdev)
956+{
957+ u64 pc10_counter;
958+
959+ if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pc10_counter))
960+ return false;
961+
962+ if (pc10_counter == pmcdev->pc10_counter)
963+ return true;
964+
965+ return false;
966+}
967+
968+static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
969+{
970+ u64 s0ix_counter;
971+
972+ if (pmc_core_dev_state_get(pmcdev, &s0ix_counter))
973+ return false;
974+
975+ if (s0ix_counter == pmcdev->s0ix_counter)
976+ return true;
977+
978+ return false;
979+}
980+
981+static int pmc_core_resume(struct device *dev)
982+{
983+ struct pmc_dev *pmcdev = dev_get_drvdata(dev);
984+ const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
985+ int offset = pmcdev->map->slps0_dbg_offset;
986+ const struct pmc_bit_map *map;
987+ u32 data;
988+
989+ if (!pmcdev->check_counters)
990+ return 0;
991+
992+ if (!pmc_core_is_s0ix_failed(pmcdev))
993+ return 0;
994+
995+ if (pmc_core_is_pc10_failed(pmcdev)) {
996+ /* S0ix failed because of PC10 entry failure */
997+ dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n",
998+ pmcdev->pc10_counter);
999+ return 0;
1000+ }
1001+
1002+ /* The real interesting case - S0ix failed - lets ask PMC why. */
1003+ dev_warn(dev, "CPU did not enter SLP_S0!!! (S0ix cnt=%llu)\n",
1004+ pmcdev->s0ix_counter);
1005+ while (*maps) {
1006+ map = *maps;
1007+ data = pmc_core_reg_read(pmcdev, offset);
1008+ offset += 4;
1009+ while (map->name) {
1010+ dev_dbg(dev, "SLP_S0_DBG: %-32s\tState: %s\n",
1011+ map->name,
1012+ data & map->bit_mask ? "Yes" : "No");
1013+ map++;
1014+ }
1015+ maps++;
1016+ }
1017+ return 0;
1018+}
1019+
1020+#endif
1021+
1022+static const struct dev_pm_ops pmc_core_pm_ops = {
1023+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume)
1024+};
1025+
1026+static struct platform_driver pmc_core_driver = {
1027+ .driver = {
1028+ .name = "intel_pmc_core",
1029+ .pm = &pmc_core_pm_ops,
1030+ },
1031+ .probe = pmc_core_probe,
1032+ .remove = pmc_core_remove,
1033+};
1034+
1035+static struct platform_device pmc_core_device = {
1036+ .name = "intel_pmc_core",
1037+};
1038+
1039+static int __init pmc_core_init(void)
1040+{
1041+ int ret;
1042+
1043+ if (!x86_match_cpu(intel_pmc_core_ids))
1044+ return -ENODEV;
1045+
1046+ ret = platform_driver_register(&pmc_core_driver);
1047+ if (ret)
1048+ return ret;
1049+
1050+ ret = platform_device_register(&pmc_core_device);
1051+ if (ret) {
1052+ platform_driver_unregister(&pmc_core_driver);
1053+ return ret;
1054+ }
1055+
1056+ return 0;
1057+}
1058+
1059+static void __exit pmc_core_exit(void)
1060+{
1061+ platform_device_unregister(&pmc_core_device);
1062+ platform_driver_unregister(&pmc_core_driver);
1063+}
1064+
1065+module_init(pmc_core_init)
1066+module_exit(pmc_core_exit)
9131067
9141068 MODULE_LICENSE("GPL v2");
9151069 MODULE_DESCRIPTION("Intel PMC Core Driver");
drivers/platform/x86/intel_pmc_core.h+7−0
@@ -241,6 +241,9 @@ struct pmc_reg_map { · 240 unmodified lines
241241 * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
242242 * used to read MPHY PG and PLL status are available
243243 * @mutex_lock: mutex to complete one transcation
244+ * @check_counters: On resume, check if counters are getting incremented
245+ * @pc10_counter: PC10 residency counter
246+ * @s0ix_counter: S0ix residency (step adjusted)
244247 *
245248 * pmc_dev contains info about power management controller device.
246249 */
@@ -253,6 +256,10 @@ struct pmc_dev { · 6 unmodified lines
253256 #endif /* CONFIG_DEBUG_FS */
254257 int pmc_xram_read_bit;
255258 struct mutex lock; /* generic mutex lock for PMC Core */
259+
260+ bool check_counters; /* Check for counter increments on resume */
261+ u64 pc10_counter;
262+ u64 s0ix_counter;
256263 };
257264
258265 #endif /* PMC_CORE_H */
drivers/platform/x86/intel_pmc_ipc.c+24−22
@@ -40,14 +40,14 @@ · 39 unmodified lines
4040 * The ARC handles the interrupt and services it, writing optional data to
4141 * the IPC1 registers, updates the IPC_STS response register with the status.
4242 */
43−#define IPC_CMD 0x0
44−#define IPC_CMD_MSI 0x100
43+#define IPC_CMD 0x00
44+#define IPC_CMD_MSI BIT(8)
4545 #define IPC_CMD_SIZE 16
4646 #define IPC_CMD_SUBCMD 12
4747 #define IPC_STATUS 0x04
48−#define IPC_STATUS_IRQ 0x4
49−#define IPC_STATUS_ERR 0x2
50−#define IPC_STATUS_BUSY 0x1
48+#define IPC_STATUS_IRQ BIT(2)
49+#define IPC_STATUS_ERR BIT(1)
50+#define IPC_STATUS_BUSY BIT(0)
5151 #define IPC_SPTR 0x08
5252 #define IPC_DPTR 0x0C
5353 #define IPC_WRITE_BUFFER 0x80
@@ -101,13 +101,13 @@ · 47 unmodified lines
101101 #define TELEM_SSRAM_SIZE 240
102102 #define TELEM_PMC_SSRAM_OFFSET 0x1B00
103103 #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00
104−#define TCO_PMC_OFFSET 0x8
105−#define TCO_PMC_SIZE 0x4
104+#define TCO_PMC_OFFSET 0x08
105+#define TCO_PMC_SIZE 0x04
106106
107107 /* PMC register bit definitions */
108108
109109 /* PMC_CFG_REG bit masks */
110−#define PMC_CFG_NO_REBOOT_MASK (1 << 4)
110+#define PMC_CFG_NO_REBOOT_MASK BIT_MASK(4)
111111 #define PMC_CFG_NO_REBOOT_EN (1 << 4)
112112 #define PMC_CFG_NO_REBOOT_DIS (0 << 4)
113113
@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev { · 17 unmodified lines
131131
132132 /* punit */
133133 struct platform_device *punit_dev;
134+ unsigned int punit_res_count;
134135
135136 /* Telemetry */
136137 resource_size_t telem_pmc_ssram_base;
@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void) · 545 unmodified lines
682683 .name = PUNIT_DEVICE_NAME,
683684 .id = -1,
684685 .res = punit_res_array,
685− .num_res = ARRAY_SIZE(punit_res_array),
686+ .num_res = ipcdev.punit_res_count,
686687 };
687688
688689 pdev = platform_device_register_full(&pdevinfo);
@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void) · 82 unmodified lines
771772 if (ret) {
772773 dev_err(ipcdev.dev, "Failed to add punit platform device\n");
773774 platform_device_unregister(ipcdev.tco_dev);
775+ return ret;
774776 }
775777
776778 if (!ipcdev.telem_res_inval) {
777779 ret = ipc_create_telemetry_device();
778− if (ret)
780+ if (ret) {
779781 dev_warn(ipcdev.dev,
780782 "Failed to add telemetry platform device\n");
783+ platform_device_unregister(ipcdev.punit_dev);
784+ platform_device_unregister(ipcdev.tco_dev);
785+ }
781786 }
782787
783788 return ret;
@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void) · 1 unmodified line
785790
786791 static int ipc_plat_get_res(struct platform_device *pdev)
787792 {
788− struct resource *res, *punit_res;
793+ struct resource *res, *punit_res = punit_res_array;
789794 void __iomem *addr;
790795 int size;
791796
@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev) · 8 unmodified lines
800805 ipcdev.acpi_io_size = size;
801806 dev_info(&pdev->dev, "io res: %pR\n", res);
802807
803− punit_res = punit_res_array;
808+ ipcdev.punit_res_count = 0;
809+
804810 /* This is index 0 to cover BIOS data register */
805811 res = platform_get_resource(pdev, IORESOURCE_MEM,
806812 PLAT_RESOURCE_BIOS_DATA_INDEX);
@@ -808,7 +814,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) · 1 unmodified line
808814 dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
809815 return -ENXIO;
810816 }
811− *punit_res = *res;
817+ punit_res[ipcdev.punit_res_count++] = *res;
812818 dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
813819
814820 /* This is index 1 to cover BIOS interface register */
@@ -818,42 +824,38 @@ static int ipc_plat_get_res(struct platform_device *pdev) · 3 unmodified lines
818824 dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
819825 return -ENXIO;
820826 }
821− *++punit_res = *res;
827+ punit_res[ipcdev.punit_res_count++] = *res;
822828 dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
823829
824830 /* This is index 2 to cover ISP data register, optional */
825831 res = platform_get_resource(pdev, IORESOURCE_MEM,
826832 PLAT_RESOURCE_ISP_DATA_INDEX);
827− ++punit_res;
828833 if (res) {
829− *punit_res = *res;
834+ punit_res[ipcdev.punit_res_count++] = *res;
830835 dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
831836 }
832837
833838 /* This is index 3 to cover ISP interface register, optional */
834839 res = platform_get_resource(pdev, IORESOURCE_MEM,
835840 PLAT_RESOURCE_ISP_IFACE_INDEX);
836− ++punit_res;
837841 if (res) {
838− *punit_res = *res;
842+ punit_res[ipcdev.punit_res_count++] = *res;
839843 dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
840844 }
841845
842846 /* This is index 4 to cover GTD data register, optional */
843847 res = platform_get_resource(pdev, IORESOURCE_MEM,
844848 PLAT_RESOURCE_GTD_DATA_INDEX);
845− ++punit_res;
846849 if (res) {
847− *punit_res = *res;
850+ punit_res[ipcdev.punit_res_count++] = *res;
848851 dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
849852 }
850853
851854 /* This is index 5 to cover GTD interface register, optional */
852855 res = platform_get_resource(pdev, IORESOURCE_MEM,
853856 PLAT_RESOURCE_GTD_IFACE_INDEX);
854− ++punit_res;
855857 if (res) {
856− *punit_res = *res;
858+ punit_res[ipcdev.punit_res_count++] = *res;
857859 dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
858860 }
859861
drivers/platform/x86/intel_punit_ipc.c+4−4
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev) · 251 unmodified lines
252252 * - GTDRIVER_IPC BASE_IFACE
253253 */
254254 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
255− if (res && resource_size(res) > 1) {
255+ if (res) {
256256 addr = devm_ioremap_resource(&pdev->dev, res);
257257 if (!IS_ERR(addr))
258258 punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
259259 }
260260
261261 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
262− if (res && resource_size(res) > 1) {
262+ if (res) {
263263 addr = devm_ioremap_resource(&pdev->dev, res);
264264 if (!IS_ERR(addr))
265265 punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
266266 }
267267
268268 res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
269− if (res && resource_size(res) > 1) {
269+ if (res) {
270270 addr = devm_ioremap_resource(&pdev->dev, res);
271271 if (!IS_ERR(addr))
272272 punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
273273 }
274274
275275 res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
276− if (res && resource_size(res) > 1) {
276+ if (res) {
277277 addr = devm_ioremap_resource(&pdev->dev, res);
278278 if (!IS_ERR(addr))
279279 punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
drivers/platform/x86/mlx-platform.c+226−2
@@ -56,6 +56,16 @@ · 55 unmodified lines
5656 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
5757 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
5858 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
59+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7
60+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8
61+#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9
62+#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb
63+#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd
64+#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET 0xce
65+#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf
66+#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
67+#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
68+#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
5969 #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3
6070 #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4
6171 #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5
@@ -72,6 +82,7 @@ · 10 unmodified lines
7282 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5
7383 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6
7484 #define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7
85+#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8
7586 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
7687 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
7788 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -128,6 +139,18 @@ · 50 unmodified lines
128139 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
129140 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
130141
142+/* Masks and default values for watchdogs */
143+#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1)
144+#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1))
145+
146+#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4)
147+#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0
148+#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1)
149+#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4))
150+#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7))
151+#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30
152+#define MLXPLAT_CPLD_WD_MAX_DEVS 2
153+
131154 /* mlxplat_priv - platform private data
132155 * @pdev_i2c - i2c controller platform device
133156 * @pdev_mux - array of mux platform devices
@@ -135,6 +158,7 @@ · 1 unmodified line
135158 * @pdev_led - led platform devices
136159 * @pdev_io_regs - register access platform devices
137160 * @pdev_fan - FAN platform devices
161+ * @pdev_wd - array of watchdog platform devices
138162 */
139163 struct mlxplat_priv {
140164 struct platform_device *pdev_i2c;
@@ -143,6 +167,7 @@ struct mlxplat_priv { · 2 unmodified lines
143167 struct platform_device *pdev_led;
144168 struct platform_device *pdev_io_regs;
145169 struct platform_device *pdev_fan;
170+ struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
146171 };
147172
148173 /* Regions for LPC I2C controller and LPC base register space */
@@ -1339,6 +1364,10 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { · 1190 unmodified lines
13391364 .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
13401365 .bit = BIT(3),
13411366 },
1367+ {
1368+ .label = "conf",
1369+ .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET,
1370+ },
13421371 };
13431372
13441373 static struct mlxreg_core_platform_data mlxplat_default_fan_data = {
@@ -1346,6 +1375,148 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = { · 1 unmodified line
13461375 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data),
13471376 };
13481377
1378+/* Watchdog type1: hardware implementation version1
1379+ * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems).
1380+ */
1381+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = {
1382+ {
1383+ .label = "action",
1384+ .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET,
1385+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
1386+ .bit = 0,
1387+ },
1388+ {
1389+ .label = "timeout",
1390+ .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET,
1391+ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
1392+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
1393+ },
1394+ {
1395+ .label = "ping",
1396+ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
1397+ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
1398+ .bit = 0,
1399+ },
1400+ {
1401+ .label = "reset",
1402+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
1403+ .mask = GENMASK(7, 0) & ~BIT(6),
1404+ .bit = 6,
1405+ },
1406+};
1407+
1408+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = {
1409+ {
1410+ .label = "action",
1411+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
1412+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
1413+ .bit = 4,
1414+ },
1415+ {
1416+ .label = "timeout",
1417+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
1418+ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
1419+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
1420+ },
1421+ {
1422+ .label = "ping",
1423+ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
1424+ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
1425+ .bit = 1,
1426+ },
1427+};
1428+
1429+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = {
1430+ {
1431+ .data = mlxplat_mlxcpld_wd_main_regs_type1,
1432+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1),
1433+ .version = MLX_WDT_TYPE1,
1434+ .identity = "mlx-wdt-main",
1435+ },
1436+ {
1437+ .data = mlxplat_mlxcpld_wd_aux_regs_type1,
1438+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1),
1439+ .version = MLX_WDT_TYPE1,
1440+ .identity = "mlx-wdt-aux",
1441+ },
1442+};
1443+
1444+/* Watchdog type2: hardware implementation version 2
1445+ * (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140).
1446+ */
1447+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = {
1448+ {
1449+ .label = "action",
1450+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
1451+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
1452+ .bit = 0,
1453+ },
1454+ {
1455+ .label = "timeout",
1456+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
1457+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
1458+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
1459+ },
1460+ {
1461+ .label = "timeleft",
1462+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET,
1463+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
1464+ },
1465+ {
1466+ .label = "ping",
1467+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
1468+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
1469+ .bit = 0,
1470+ },
1471+ {
1472+ .label = "reset",
1473+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
1474+ .mask = GENMASK(7, 0) & ~BIT(6),
1475+ .bit = 6,
1476+ },
1477+};
1478+
1479+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = {
1480+ {
1481+ .label = "action",
1482+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
1483+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
1484+ .bit = 4,
1485+ },
1486+ {
1487+ .label = "timeout",
1488+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET,
1489+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
1490+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
1491+ },
1492+ {
1493+ .label = "timeleft",
1494+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET,
1495+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
1496+ },
1497+ {
1498+ .label = "ping",
1499+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
1500+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
1501+ .bit = 4,
1502+ },
1503+};
1504+
1505+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = {
1506+ {
1507+ .data = mlxplat_mlxcpld_wd_main_regs_type2,
1508+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2),
1509+ .version = MLX_WDT_TYPE2,
1510+ .identity = "mlx-wdt-main",
1511+ },
1512+ {
1513+ .data = mlxplat_mlxcpld_wd_aux_regs_type2,
1514+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2),
1515+ .version = MLX_WDT_TYPE2,
1516+ .identity = "mlx-wdt-aux",
1517+ },
1518+};
1519+
13491520 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
13501521 {
13511522 switch (reg) {
@@ -1368,6 +1539,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) · 16 unmodified lines
13681539 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
13691540 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
13701541 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
1542+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
1543+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
1544+ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
1545+ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
1546+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
1547+ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
1548+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
1549+ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
13711550 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
13721551 case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:
13731552 return true;
@@ -1411,6 +1590,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) · 37 unmodified lines
14111590 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
14121591 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
14131592 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
1593+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
1594+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
1595+ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
1596+ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
1597+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
1598+ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
1599+ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
1600+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
1601+ case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
1602+ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
14141603 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
14151604 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
14161605 case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
@@ -1428,6 +1617,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) · 11 unmodified lines
14281617 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
14291618 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
14301619 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
1620+ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
14311621 return true;
14321622 }
14331623 return false;
@@ -1467,6 +1657,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) · 33 unmodified lines
14671657 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
14681658 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
14691659 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
1660+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
1661+ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
1662+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
1663+ case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
14701664 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
14711665 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
14721666 case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
@@ -1484,6 +1678,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) · 11 unmodified lines
14841678 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
14851679 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
14861680 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
1681+ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
14871682 return true;
14881683 }
14891684 return false;
@@ -1493,6 +1688,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { · 3 unmodified lines
14931688 { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 },
14941689 { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 },
14951690 { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
1691+ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
14961692 };
14971693
14981694 struct mlxplat_mlxcpld_regmap_context {
@@ -1542,6 +1738,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; · 43 unmodified lines
15421738 static struct mlxreg_core_platform_data *mlxplat_led;
15431739 static struct mlxreg_core_platform_data *mlxplat_regs_io;
15441740 static struct mlxreg_core_platform_data *mlxplat_fan;
1741+static struct mlxreg_core_platform_data
1742+ *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
15451743
15461744 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
15471745 {
@@ -1557,6 +1755,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) · 9 unmodified lines
15571755 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
15581756 mlxplat_led = &mlxplat_default_led_data;
15591757 mlxplat_regs_io = &mlxplat_default_regs_io_data;
1758+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
15601759
15611760 return 1;
15621761 };
@@ -1575,6 +1774,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
15751774 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
15761775 mlxplat_led = &mlxplat_msn21xx_led_data;
15771776 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1777+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
15781778
15791779 return 1;
15801780 };
@@ -1593,6 +1793,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
15931793 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
15941794 mlxplat_led = &mlxplat_default_led_data;
15951795 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1796+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
15961797
15971798 return 1;
15981799 };
@@ -1611,6 +1812,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
16111812 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
16121813 mlxplat_led = &mlxplat_msn21xx_led_data;
16131814 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1815+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
16141816
16151817 return 1;
16161818 };
@@ -1630,6 +1832,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) · 13 unmodified lines
16301832 mlxplat_led = &mlxplat_default_ng_led_data;
16311833 mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
16321834 mlxplat_fan = &mlxplat_default_fan_data;
1835+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
1836+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
16331837
16341838 return 1;
16351839 };
@@ -1912,15 +2116,33 @@ static int __init mlxplat_init(void) · 276 unmodified lines
19122116 }
19132117 }
19142118
2119+ /* Add WD drivers. */
2120+ for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) {
2121+ if (mlxplat_wd_data[j]) {
2122+ mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap;
2123+ priv->pdev_wd[j] = platform_device_register_resndata(
2124+ &mlxplat_dev->dev, "mlx-wdt",
2125+ j, NULL, 0,
2126+ mlxplat_wd_data[j],
2127+ sizeof(*mlxplat_wd_data[j]));
2128+ if (IS_ERR(priv->pdev_wd[j])) {
2129+ err = PTR_ERR(priv->pdev_wd[j]);
2130+ goto fail_platform_wd_register;
2131+ }
2132+ }
2133+ }
2134+
19152135 /* Sync registers with hardware. */
19162136 regcache_mark_dirty(mlxplat_hotplug->regmap);
19172137 err = regcache_sync(mlxplat_hotplug->regmap);
19182138 if (err)
1919− goto fail_platform_fan_register;
2139+ goto fail_platform_wd_register;
19202140
19212141 return 0;
19222142
1923−fail_platform_fan_register:
2143+fail_platform_wd_register:
2144+ while (--j >= 0)
2145+ platform_device_unregister(priv->pdev_wd[j]);
19242146 if (mlxplat_fan)
19252147 platform_device_unregister(priv->pdev_fan);
19262148 fail_platform_io_regs_register:
@@ -1946,6 +2168,8 @@ static void __exit mlxplat_exit(void) · 19 unmodified lines
19462168 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
19472169 int i;
19482170
2171+ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--)
2172+ platform_device_unregister(priv->pdev_wd[i]);
19492173 if (priv->pdev_fan)
19502174 platform_device_unregister(priv->pdev_fan);
19512175 if (priv->pdev_io_regs)
drivers/platform/x86/sony-laptop.c+5−3
@@ -4424,14 +4424,16 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) · 4423 unmodified lines
44244424 }
44254425 return AE_OK;
44264426 }
4427+
4428+ case ACPI_RESOURCE_TYPE_END_TAG:
4429+ return AE_OK;
4430+
44274431 default:
44284432 dprintk("Resource %d isn't an IRQ nor an IO port\n",
44294433 resource->type);
4434+ return AE_CTRL_TERMINATE;
44304435
4431− case ACPI_RESOURCE_TYPE_END_TAG:
4432− return AE_OK;
44334436 }
4434− return AE_CTRL_TERMINATE;
44354437 }
44364438
44374439 static int sony_pic_possible_resources(struct acpi_device *device)
drivers/platform/x86/thinkpad_acpi.c+125−21
@@ -79,7 +79,7 @@ · 78 unmodified lines
7979 #include <linux/jiffies.h>
8080 #include <linux/workqueue.h>
8181 #include <linux/acpi.h>
82−#include <linux/pci_ids.h>
82+#include <linux/pci.h>
8383 #include <linux/power_supply.h>
8484 #include <sound/core.h>
8585 #include <sound/control.h>
@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) · 4126 unmodified lines
42124212 known_ev = true;
42134213 break;
42144214 }
4215− /* fallthrough to default */
4215+ /* fallthrough - to default */
42164216 default:
42174217 known_ev = false;
42184218 }
@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void) · 282 unmodified lines
45014501 bluetooth_shutdown();
45024502 }
45034503
4504+static const struct dmi_system_id bt_fwbug_list[] __initconst = {
4505+ {
4506+ .ident = "ThinkPad E485",
4507+ .matches = {
4508+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4509+ DMI_MATCH(DMI_BOARD_NAME, "20KU"),
4510+ },
4511+ },
4512+ {
4513+ .ident = "ThinkPad E585",
4514+ .matches = {
4515+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4516+ DMI_MATCH(DMI_BOARD_NAME, "20KV"),
4517+ },
4518+ },
4519+ {
4520+ .ident = "ThinkPad A285 - 20MW",
4521+ .matches = {
4522+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4523+ DMI_MATCH(DMI_BOARD_NAME, "20MW"),
4524+ },
4525+ },
4526+ {
4527+ .ident = "ThinkPad A285 - 20MX",
4528+ .matches = {
4529+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4530+ DMI_MATCH(DMI_BOARD_NAME, "20MX"),
4531+ },
4532+ },
4533+ {
4534+ .ident = "ThinkPad A485 - 20MU",
4535+ .matches = {
4536+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4537+ DMI_MATCH(DMI_BOARD_NAME, "20MU"),
4538+ },
4539+ },
4540+ {
4541+ .ident = "ThinkPad A485 - 20MV",
4542+ .matches = {
4543+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
4544+ DMI_MATCH(DMI_BOARD_NAME, "20MV"),
4545+ },
4546+ },
4547+ {}
4548+};
4549+
4550+static const struct pci_device_id fwbug_cards_ids[] __initconst = {
4551+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) },
4552+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) },
4553+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2526) },
4554+ {}
4555+};
4556+
4557+
4558+static int __init have_bt_fwbug(void)
4559+{
4560+ /*
4561+ * Some AMD based ThinkPads have a firmware bug that calling
4562+ * "GBDC" will cause bluetooth on Intel wireless cards blocked
4563+ */
4564+ if (dmi_check_system(bt_fwbug_list) && pci_dev_present(fwbug_cards_ids)) {
4565+ vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
4566+ FW_BUG "disable bluetooth subdriver for Intel cards\n");
4567+ return 1;
4568+ } else
4569+ return 0;
4570+}
4571+
45044572 static int __init bluetooth_init(struct ibm_init_struct *iibm)
45054573 {
45064574 int res;
@@ -4513,7 +4581,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) · 6 unmodified lines
45134581
45144582 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
45154583 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
4516− tp_features.bluetooth = hkey_handle &&
4584+ tp_features.bluetooth = !have_bt_fwbug() && hkey_handle &&
45174585 acpi_evalf(hkey_handle, &status, "GBDC", "qd");
45184586
45194587 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led, · 1288 unmodified lines
58085876 return -EPERM;
58095877 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
58105878 (1 << led), led_sled_arg1[ledstatus]))
5811− rc = -EIO;
5879+ return -EIO;
58125880 break;
58135881 case TPACPI_LED_OLD:
58145882 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
@@ -5832,10 +5900,10 @@ static int led_set_status(const unsigned int led, · 17 unmodified lines
58325900 return -EPERM;
58335901 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
58345902 led, led_led_arg1[ledstatus]))
5835− rc = -EIO;
5903+ return -EIO;
58365904 break;
58375905 default:
5838− rc = -ENXIO;
5906+ return -ENXIO;
58395907 }
58405908
58415909 if (!rc)
@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value) · 407 unmodified lines
62496317 t = TP_EC_THERMAL_TMP8;
62506318 idx -= 8;
62516319 }
6252− /* fallthrough */
62536320 #endif
6321+ /* fallthrough */
62546322 case TPACPI_THERMAL_TPEC_8:
62556323 if (idx <= 7) {
62566324 if (!acpi_ec_read(t + idx, &tmp))
@@ -9890,6 +9958,37 @@ invalid: · 3633 unmodified lines
98909958 return '\0';
98919959 }
98929960
9961+static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
9962+{
9963+ char *ec_fw_string = (char *) private;
9964+ const char *dmi_data = (const char *)dm;
9965+ /*
9966+ * ThinkPad Embedded Controller Program Table on newer models
9967+ *
9968+ * Offset | Name | Width | Description
9969+ * ----------------------------------------------------
9970+ * 0x00 | Type | BYTE | 0x8C
9971+ * 0x01 | Length | BYTE |
9972+ * 0x02 | Handle | WORD | Varies
9973+ * 0x04 | Signature | BYTEx6 | ASCII for "LENOVO"
9974+ * 0x0A | OEM struct offset | BYTE | 0x0B
9975+ * 0x0B | OEM struct number | BYTE | 0x07, for this structure
9976+ * 0x0C | OEM struct revision | BYTE | 0x01, for this format
9977+ * 0x0D | ECP version ID | STR ID |
9978+ * 0x0E | ECP release date | STR ID |
9979+ */
9980+
9981+ /* Return if data structure not match */
9982+ if (dm->type != 140 || dm->length < 0x0F ||
9983+ memcmp(dmi_data + 4, "LENOVO", 6) != 0 ||
9984+ dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 ||
9985+ dmi_data[0x0C] != 0x01)
9986+ return;
9987+
9988+ /* fwstr is the first 8byte string */
9989+ strncpy(ec_fw_string, dmi_data + 0x0F, 8);
9990+}
9991+
98939992 /* returns 0 - probe ok, or < 0 - probe error.
98949993 * Probe ok doesn't mean thinkpad found.
98959994 * On error, kfree() cleanup on tp->* is not performed, caller must do it */
@@ -9897,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data( · 1 unmodified line
98979996 struct thinkpad_id_data *tp)
98989997 {
98999998 const struct dmi_device *dev = NULL;
9900− char ec_fw_string[18];
9999+ char ec_fw_string[18] = {0};
990110000 char const *s;
990210001 char t;
990310002
@@ -9937,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data( · 33 unmodified lines
993710036 ec_fw_string) == 1) {
993810037 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
993910038 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
10039+ break;
10040+ }
10041+ }
994010042
9941− tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
9942− if (!tp->ec_version_str)
9943− return -ENOMEM;
10043+ /* Newer ThinkPads have different EC program info table */
10044+ if (!ec_fw_string[0])
10045+ dmi_walk(find_new_ec_fwstr, &ec_fw_string);
994410046
9945− t = tpacpi_parse_fw_id(ec_fw_string,
9946− &tp->ec_model, &tp->ec_release);
9947− if (t != 'H') {
9948− pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
9949− ec_fw_string);
9950− pr_notice("please report this to %s\n",
9951− TPACPI_MAIL);
9952− }
9953− break;
10047+ if (ec_fw_string[0]) {
10048+ tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
10049+ if (!tp->ec_version_str)
10050+ return -ENOMEM;
10051+
10052+ t = tpacpi_parse_fw_id(ec_fw_string,
10053+ &tp->ec_model, &tp->ec_release);
10054+ if (t != 'H') {
10055+ pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
10056+ ec_fw_string);
10057+ pr_notice("please report this to %s\n", TPACPI_MAIL);
995410058 }
995510059 }
995610060
@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode, · 208 unmodified lines
1016510269
1016610270 module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
1016710271 MODULE_PARM_DESC(volume_capabilities,
10168− "Selects the mixer capabilites: 0=auto, 1=volume and mute, 2=mute only");
10272+ "Selects the mixer capabilities: 0=auto, 1=volume and mute, 2=mute only");
1016910273
1017010274 module_param_named(volume_control, volume_control_allowed, bool, 0444);
1017110275 MODULE_PARM_DESC(volume_control,
drivers/platform/x86/touchscreen_dmi.c+51−0
@@ -249,6 +249,21 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = { · 248 unmodified lines
249249 .properties = jumper_ezpad_6_pro_props,
250250 };
251251
252+static const struct property_entry jumper_ezpad_6_pro_b_props[] = {
253+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
254+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
255+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro-b.fw"),
256+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
257+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
258+ PROPERTY_ENTRY_BOOL("silead,home-button"),
259+ { }
260+};
261+
262+static const struct ts_dmi_data jumper_ezpad_6_pro_b_data = {
263+ .acpi_name = "MSSL1680:00",
264+ .properties = jumper_ezpad_6_pro_b_props,
265+};
266+
252267 static const struct property_entry jumper_ezpad_mini3_props[] = {
253268 PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
254269 PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = { · 10 unmodified lines
265280 .properties = jumper_ezpad_mini3_props,
266281 };
267282
283+static const struct property_entry myria_my8307_props[] = {
284+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1720),
285+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
286+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
287+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
288+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
289+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-myria-my8307.fw"),
290+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
291+ PROPERTY_ENTRY_BOOL("silead,home-button"),
292+ { }
293+};
294+
295+static const struct ts_dmi_data myria_my8307_data = {
296+ .acpi_name = "MSSL1680:00",
297+ .properties = myria_my8307_props,
298+};
299+
268300 static const struct property_entry onda_obook_20_plus_props[] = {
269301 PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
270302 PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { · 402 unmodified lines
673705 DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),
674706 },
675707 },
708+ {
709+ /* Jumper EZpad 6 Pro B */
710+ .driver_data = (void *)&jumper_ezpad_6_pro_b_data,
711+ .matches = {
712+ DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
713+ DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
714+ DMI_MATCH(DMI_BIOS_VERSION, "5.12"),
715+ /* Above matches are too generic, add bios-date match */
716+ DMI_MATCH(DMI_BIOS_DATE, "04/24/2018"),
717+ },
718+ },
676719 {
677720 /* Jumper EZpad mini3 */
678721 .driver_data = (void *)&jumper_ezpad_mini3_data,
@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { · 11 unmodified lines
690733 DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
691734 },
692735 },
736+ {
737+ /* Myria MY8307 */
738+ .driver_data = (void *)&myria_my8307_data,
739+ .matches = {
740+ DMI_MATCH(DMI_SYS_VENDOR, "Complet Electro Serv"),
741+ DMI_MATCH(DMI_PRODUCT_NAME, "MY8307"),
742+ },
743+ },
693744 {
694745 /* Onda oBook 20 Plus */
695746 .driver_data = (void *)&onda_obook_20_plus_data,
include/linux/platform_data/x86/asus-wmi.h+1−0
@@ -67,6 +67,7 @@ · 66 unmodified lines
6767 /* Input */
6868 #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
6969 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
70+#define ASUS_WMI_DEVID_FNLOCK 0x00100023
7071
7172 /* Fan, Thermal */
7273 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t