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
5 5
6menuconfig MELLANOX_PLATFORM6menuconfig MELLANOX_PLATFORM
7 bool "Platform support for Mellanox hardware"7 bool "Platform support for Mellanox hardware"
8 depends on X86 || ARM || COMPILE_TEST8 depends on X86 || ARM || ARM64 || COMPILE_TEST
9 ---help---9 ---help---
10 Say Y here to get to see options for platform support for10 Say Y here to get to see options for platform support for
11 Mellanox systems. This option alone does not add any kernel code.11 Mellanox systems. This option alone does not add any kernel code.
@@ -34,4 +34,14 @@ config MLXREG_IO · 22 unmodified lines
34 to system resets operation, system reset causes monitoring and some34 to system resets operation, system reset causes monitoring and some
35 kinds of mux selection.35 kinds of mux selection.
36 36
37config 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
37endif # MELLANOX_PLATFORM47endif # MELLANOX_PLATFORM
drivers/platform/mellanox/Makefile+1−0
@@ -3,5 +3,6 @@ · 2 unmodified lines
3# Makefile for linux/drivers/platform/mellanox3# Makefile for linux/drivers/platform/mellanox
4# Mellanox Platform-Specific Drivers4# Mellanox Platform-Specific Drivers
5#5#
6obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
6obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o7obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
7obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o8obj-$(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
50struct 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 */
69struct 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. */
87enum {
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). */
96enum {
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 */
115struct 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 */
133struct 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 */
155struct 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 */
179struct 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 */
190static 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. */
195static 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. */
208static 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. */
230static 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. */
264static 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. */
276static 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. */
287static struct vring_desc *
288mlxbf_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. */
308static 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. */
330static 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
348static 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
369static 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. */
380static struct vring_desc *
381mlxbf_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. */
396static 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. */
411static 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. */
444static 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. */
468static 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. */
477static 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). */
495static 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. */
559static 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 */
605static 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 */
671static 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
739mlxbf_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. */
747static 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. */
790static 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. */
812static 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. */
834static 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. */
874static 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. */
882static 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(). */
892static 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. */
914static 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
957error:
958 mlxbf_tmfifo_virtio_del_vqs(vdev);
959 return ret;
960}
961
962/* Read the status byte. */
963static 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. */
971static 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. */
980static 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. */
988static 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. */
1002static 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
1015static 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. */
1025static 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. */
1038static 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
1093vdev_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);
1100fail:
1101 mutex_unlock(&fifo->lock);
1102 return ret;
1103}
1104
1105/* Delete vdev for the FIFO. */
1106static 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. */
1126static 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. */
1141static 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
1168static 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. */
1181static 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
1247fail:
1248 mlxbf_tmfifo_cleanup(fifo);
1249 return rc;
1250}
1251
1252/* Device remove function. */
1253static 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
1262static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = {
1263 { "MLNXBF01", 0 },
1264 {}
1265};
1266MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);
1267
1268static 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
1277module_platform_driver(mlxbf_tmfifo_driver);
1278
1279MODULE_DESCRIPTION("Mellanox BlueField SoC TmFifo Driver");
1280MODULE_LICENSE("GPL v2");
1281MODULE_AUTHOR("Mellanox Technologies");
drivers/platform/x86/Kconfig+11−0
@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN · 1262 unmodified lines
1263 To compile this driver as a module, choose M here: the module1263 To compile this driver as a module, choose M here: the module
1264 will be called intel_chtdc_ti_pwrbtn.1264 will be called intel_chtdc_ti_pwrbtn.
1265 1265
1266config 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
1266config I2C_MULTI_INSTANTIATE1277config I2C_MULTI_INSTANTIATE
1267 tristate "I2C multi instantiate pseudo device driver"1278 tristate "I2C multi instantiate pseudo device driver"
1268 depends on I2C && ACPI1279 depends on I2C && ACPI
drivers/platform/x86/Makefile+1−0
@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o · 93 unmodified lines
94obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o94obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
95obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o95obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
96obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o96obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
97obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
97obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o98obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
98obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o99obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
99obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o100obj-$(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
522 522
523 input.length = (acpi_size) sizeof(*in_args);523 input.length = (acpi_size) sizeof(*in_args);
524 input.pointer = in_args;524 input.pointer = in_args;
525 if (out_data != NULL) {525 if (out_data) {
526 output.length = ACPI_ALLOCATE_BUFFER;526 output.length = ACPI_ALLOCATE_BUFFER;
527 output.pointer = NULL;527 output.pointer = NULL;
528 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,528 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
529 command, &input, &output);529 command, &input, &output);
530 } else530 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 {
531 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,537 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
532 command, &input, NULL);538 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;
538 }539 }
539 kfree(output.pointer);
540 return status;540 return status;
541
542}541}
543 542
544/*543/*
@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev, · 43 unmodified lines
588 return scnprintf(buf, PAGE_SIZE,587 return scnprintf(buf, PAGE_SIZE,
589 "input [gpu] unknown\n");588 "input [gpu] unknown\n");
590 }589 }
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);
592 return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");591 return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
593}592}
594 593
drivers/platform/x86/asus-wmi.c+37−0
@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL"); · 65 unmodified lines
66#define NOTIFY_BRNUP_MAX 0x1f66#define NOTIFY_BRNUP_MAX 0x1f
67#define NOTIFY_BRNDOWN_MIN 0x2067#define NOTIFY_BRNDOWN_MIN 0x20
68#define NOTIFY_BRNDOWN_MAX 0x2e68#define NOTIFY_BRNDOWN_MAX 0x2e
69#define NOTIFY_FNLOCK_TOGGLE 0x4e
69#define NOTIFY_KBD_BRTUP 0xc470#define NOTIFY_KBD_BRTUP 0xc4
70#define NOTIFY_KBD_BRTDWN 0xc571#define NOTIFY_KBD_BRTDWN 0xc5
71#define NOTIFY_KBD_BRTTOGGLE 0xc772#define NOTIFY_KBD_BRTTOGGLE 0xc7
72 73
74#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
75
73#define ASUS_FAN_DESC "cpu_fan"76#define ASUS_FAN_DESC "cpu_fan"
74#define ASUS_FAN_MFUN 0x1377#define ASUS_FAN_MFUN 0x13
75#define ASUS_FAN_SFUN_READ 0x0678#define ASUS_FAN_SFUN_READ 0x06
@@ -177,6 +180,8 @@ struct asus_wmi { · 101 unmodified lines
177 struct workqueue_struct *hotplug_workqueue;180 struct workqueue_struct *hotplug_workqueue;
178 struct work_struct hotplug_work;181 struct work_struct hotplug_work;
179 182
183 bool fnlock_locked;
184
180 struct asus_wmi_debug debug;185 struct asus_wmi_debug debug;
181 186
182 struct asus_wmi_driver *driver;187 struct asus_wmi_driver *driver;
@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code) · 1436 unmodified lines
1619 return 0;1624 return 0;
1620}1625}
1621 1626
1627static 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
1637static 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
1622static void asus_wmi_notify(u32 value, void *context)1644static void asus_wmi_notify(u32 value, void *context)
1623{1645{
1624 struct asus_wmi *asus = context;1646 struct asus_wmi *asus = context;
@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context) · 55 unmodified lines
1680 goto exit;1702 goto exit;
1681 }1703 }
1682 1704
1705 if (code == NOTIFY_FNLOCK_TOGGLE) {
1706 asus->fnlock_locked = !asus->fnlock_locked;
1707 asus_wmi_fnlock_update(asus);
1708 goto exit;
1709 }
1710
1683 if (is_display_toggle(code) &&1711 if (is_display_toggle(code) &&
1684 asus->driver->quirks->no_display_toggle)1712 asus->driver->quirks->no_display_toggle)
1685 goto exit;1713 goto exit;
@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev) · 448 unmodified lines
2134 } else2162 } else
2135 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);2163 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
2136 2164
2165 if (asus_wmi_has_fnlock_key(asus)) {
2166 asus->fnlock_locked = true;
2167 asus_wmi_fnlock_update(asus);
2168 }
2169
2137 status = wmi_install_notify_handler(asus->driver->event_guid,2170 status = wmi_install_notify_handler(asus->driver->event_guid,
2138 asus_wmi_notify, asus);2171 asus_wmi_notify, asus);
2139 if (ACPI_FAILURE(status)) {2172 if (ACPI_FAILURE(status)) {
@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device) · 73 unmodified lines
2213 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))2246 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
2214 kbd_led_update(asus);2247 kbd_led_update(asus);
2215 2248
2249 if (asus_wmi_has_fnlock_key(asus))
2250 asus_wmi_fnlock_update(asus);
2216 return 0;2251 return 0;
2217}2252}
2218 2253
@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device) · 30 unmodified lines
2249 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))2284 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
2250 kbd_led_update(asus);2285 kbd_led_update(asus);
2251 2286
2287 if (asus_wmi_has_fnlock_key(asus))
2288 asus_wmi_fnlock_update(asus);
2252 return 0;2289 return 0;
2253}2290}
2254 2291
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
531 return;531 return;
532 }532 }
533 533
534 dell_fill_request(&buffer, 0, 0x2, 0, 0);534 dell_fill_request(&buffer, 0x2, 0, 0, 0);
535 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);535 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
536 hwswitch = buffer.output[1];536 hwswitch = buffer.output[1];
537 537
@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) · 24 unmodified lines
562 return ret;562 return ret;
563 status = buffer.output[1];563 status = buffer.output[1];
564 564
565 dell_fill_request(&buffer, 0, 0x2, 0, 0);565 dell_fill_request(&buffer, 0x2, 0, 0, 0);
566 hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);566 hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
567 if (hwswitch_ret)567 if (hwswitch_ret)
568 return hwswitch_ret;568 return hwswitch_ret;
@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored) · 78 unmodified lines
647 if (ret != 0)647 if (ret != 0)
648 return;648 return;
649 649
650 dell_fill_request(&buffer, 0, 0x2, 0, 0);650 dell_fill_request(&buffer, 0x2, 0, 0, 0);
651 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);651 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
652 652
653 if (ret == 0 && (status & BIT(0)))653 if (ret == 0 && (status & BIT(0)))
drivers/platform/x86/dell-rbtn.c+2−0
@@ -18,6 +18,8 @@ · 17 unmodified lines
18#include <linux/rfkill.h>18#include <linux/rfkill.h>
19#include <linux/input.h>19#include <linux/input.h>
20 20
21#include "dell-rbtn.h"
22
21enum rbtn_type {23enum rbtn_type {
22 RBTN_UNKNOWN,24 RBTN_UNKNOWN,
23 RBTN_TOGGLE,25 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
980#endif980#endif
981 981
982/*982/*
983 * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF983 * Some ideapads have a hardware rfkill switch, but most do not have one.
984 * always results in 0 on these models, causing ideapad_laptop to wrongly984 * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
985 * report all radios as hardware-blocked.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.
986 */996 */
987static const struct dmi_system_id no_hw_rfkill_list[] = {997static const struct dmi_system_id 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 },
1289 {}998 {}
1290};999};
1291 1000
@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) · 19 unmodified lines
1311 priv->cfg = cfg;1020 priv->cfg = cfg;
1312 priv->adev = adev;1021 priv->adev = adev;
1313 priv->platform_device = pdev;1022 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);
1315 1024
1316 ret = ideapad_sysfs_init(priv);1025 ret = ideapad_sysfs_init(priv);
1317 if (ret)1026 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
22static 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
42static 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
81static 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
90static const struct platform_device_id mrfld_pwrbtn_id_table[] = {
91 { .name = "mrfld_bcove_pwrbtn" },
92 {}
93};
94MODULE_DEVICE_TABLE(platform, mrfld_pwrbtn_id_table);
95
96static 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};
104module_platform_driver(mrfld_pwrbtn_driver);
105
106MODULE_DESCRIPTION("Power-button driver for Basin Cove PMIC");
107MODULE_LICENSE("GPL v2");
drivers/platform/x86/intel_pmc_core.c+163−9
@@ -19,6 +19,8 @@ · 18 unmodified lines
19#include <linux/io.h>19#include <linux/io.h>
20#include <linux/module.h>20#include <linux/module.h>
21#include <linux/pci.h>21#include <linux/pci.h>
22#include <linux/platform_device.h>
23#include <linux/suspend.h>
22#include <linux/uaccess.h>24#include <linux/uaccess.h>
23 25
24#include <asm/cpu_device_id.h>26#include <asm/cpu_device_id.h>
@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = { · 803 unmodified lines
828 * the platform BIOS enforces 24Mhx Crystal to shutdown830 * the platform BIOS enforces 24Mhx Crystal to shutdown
829 * before PMC can assert SLP_S0#.831 * before PMC can assert SLP_S0#.
830 */832 */
831int quirk_xtal_ignore(const struct dmi_system_id *id)833static int quirk_xtal_ignore(const struct dmi_system_id *id)
832{834{
833 struct pmc_dev *pmcdev = &pmc;835 struct pmc_dev *pmcdev = &pmc;
834 u32 value;836 u32 value;
@@ -854,13 +856,17 @@ static const struct dmi_system_id pmc_core_dmi_table[] = { · 19 unmodified lines
854 {}856 {}
855};857};
856 858
857static int __init pmc_core_probe(void)859static int pmc_core_probe(struct platform_device *pdev)
858{860{
861 static bool device_initialized;
859 struct pmc_dev *pmcdev = &pmc;862 struct pmc_dev *pmcdev = &pmc;
860 const struct x86_cpu_id *cpu_id;863 const struct x86_cpu_id *cpu_id;
861 u64 slp_s0_addr;864 u64 slp_s0_addr;
862 int err;865 int err;
863 866
867 if (device_initialized)
868 return -ENODEV;
869
864 cpu_id = x86_match_cpu(intel_pmc_core_ids);870 cpu_id = x86_match_cpu(intel_pmc_core_ids);
865 if (!cpu_id)871 if (!cpu_id)
866 return -ENODEV;872 return -ENODEV;
@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void) · 19 unmodified lines
886 return -ENOMEM;892 return -ENOMEM;
887 893
888 mutex_init(&pmcdev->lock);894 mutex_init(&pmcdev->lock);
895 platform_set_drvdata(pdev, pmcdev);
889 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();896 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
897 dmi_check_system(pmc_core_dmi_table);
890 898
891 err = pmc_core_dbgfs_register(pmcdev);899 err = pmc_core_dbgfs_register(pmcdev);
892 if (err < 0) {900 if (err < 0) {
893 pr_warn(" debugfs register failed.\n");901 dev_warn(&pdev->dev, "debugfs register failed.\n");
894 iounmap(pmcdev->regbase);902 iounmap(pmcdev->regbase);
895 return err;903 return err;
896 }904 }
897 905
898 dmi_check_system(pmc_core_dmi_table);906 device_initialized = true;
899 pr_info(" initialized\n");907 dev_info(&pdev->dev, " initialized\n");
908
900 return 0;909 return 0;
901}910}
902module_init(pmc_core_probe)
903 911
904static void __exit pmc_core_remove(void)912static int pmc_core_remove(struct platform_device *pdev)
905{913{
906 struct pmc_dev *pmcdev = &pmc;914 struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
907 915
908 pmc_core_dbgfs_unregister(pmcdev);916 pmc_core_dbgfs_unregister(pmcdev);
917 platform_set_drvdata(pdev, NULL);
909 mutex_destroy(&pmcdev->lock);918 mutex_destroy(&pmcdev->lock);
910 iounmap(pmcdev->regbase);919 iounmap(pmcdev->regbase);
920 return 0;
911}921}
912module_exit(pmc_core_remove)922
923#ifdef CONFIG_PM_SLEEP
924
925static bool warn_on_s0ix_failures;
926module_param(warn_on_s0ix_failures, bool, 0644);
927MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
928
929static 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
955static 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
968static 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
981static 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
1022static const struct dev_pm_ops pmc_core_pm_ops = {
1023 SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume)
1024};
1025
1026static 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
1035static struct platform_device pmc_core_device = {
1036 .name = "intel_pmc_core",
1037};
1038
1039static 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
1059static void __exit pmc_core_exit(void)
1060{
1061 platform_device_unregister(&pmc_core_device);
1062 platform_driver_unregister(&pmc_core_driver);
1063}
1064
1065module_init(pmc_core_init)
1066module_exit(pmc_core_exit)
913 1067
914MODULE_LICENSE("GPL v2");1068MODULE_LICENSE("GPL v2");
915MODULE_DESCRIPTION("Intel PMC Core Driver");1069MODULE_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
241 * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers241 * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
242 * used to read MPHY PG and PLL status are available242 * used to read MPHY PG and PLL status are available
243 * @mutex_lock: mutex to complete one transcation243 * @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)
244 *247 *
245 * pmc_dev contains info about power management controller device.248 * pmc_dev contains info about power management controller device.
246 */249 */
@@ -253,6 +256,10 @@ struct pmc_dev { · 6 unmodified lines
253#endif /* CONFIG_DEBUG_FS */256#endif /* CONFIG_DEBUG_FS */
254 int pmc_xram_read_bit;257 int pmc_xram_read_bit;
255 struct mutex lock; /* generic mutex lock for PMC Core */258 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;
256};263};
257 264
258#endif /* PMC_CORE_H */265#endif /* PMC_CORE_H */
drivers/platform/x86/intel_pmc_ipc.c+24−22
@@ -40,14 +40,14 @@ · 39 unmodified lines
40 * The ARC handles the interrupt and services it, writing optional data to40 * The ARC handles the interrupt and services it, writing optional data to
41 * the IPC1 registers, updates the IPC_STS response register with the status.41 * the IPC1 registers, updates the IPC_STS response register with the status.
42 */42 */
43#define IPC_CMD 0x043#define IPC_CMD 0x00
44#define IPC_CMD_MSI 0x10044#define IPC_CMD_MSI BIT(8)
45#define IPC_CMD_SIZE 1645#define IPC_CMD_SIZE 16
46#define IPC_CMD_SUBCMD 1246#define IPC_CMD_SUBCMD 12
47#define IPC_STATUS 0x0447#define IPC_STATUS 0x04
48#define IPC_STATUS_IRQ 0x448#define IPC_STATUS_IRQ BIT(2)
49#define IPC_STATUS_ERR 0x249#define IPC_STATUS_ERR BIT(1)
50#define IPC_STATUS_BUSY 0x150#define IPC_STATUS_BUSY BIT(0)
51#define IPC_SPTR 0x0851#define IPC_SPTR 0x08
52#define IPC_DPTR 0x0C52#define IPC_DPTR 0x0C
53#define IPC_WRITE_BUFFER 0x8053#define IPC_WRITE_BUFFER 0x80
@@ -101,13 +101,13 @@ · 47 unmodified lines
101#define TELEM_SSRAM_SIZE 240101#define TELEM_SSRAM_SIZE 240
102#define TELEM_PMC_SSRAM_OFFSET 0x1B00102#define TELEM_PMC_SSRAM_OFFSET 0x1B00
103#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00103#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00
104#define TCO_PMC_OFFSET 0x8104#define TCO_PMC_OFFSET 0x08
105#define TCO_PMC_SIZE 0x4105#define TCO_PMC_SIZE 0x04
106 106
107/* PMC register bit definitions */107/* PMC register bit definitions */
108 108
109/* PMC_CFG_REG bit masks */109/* PMC_CFG_REG bit masks */
110#define PMC_CFG_NO_REBOOT_MASK (1 << 4)110#define PMC_CFG_NO_REBOOT_MASK BIT_MASK(4)
111#define PMC_CFG_NO_REBOOT_EN (1 << 4)111#define PMC_CFG_NO_REBOOT_EN (1 << 4)
112#define PMC_CFG_NO_REBOOT_DIS (0 << 4)112#define PMC_CFG_NO_REBOOT_DIS (0 << 4)
113 113
@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev { · 17 unmodified lines
131 131
132 /* punit */132 /* punit */
133 struct platform_device *punit_dev;133 struct platform_device *punit_dev;
134 unsigned int punit_res_count;
134 135
135 /* Telemetry */136 /* Telemetry */
136 resource_size_t telem_pmc_ssram_base;137 resource_size_t telem_pmc_ssram_base;
@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void) · 545 unmodified lines
682 .name = PUNIT_DEVICE_NAME,683 .name = PUNIT_DEVICE_NAME,
683 .id = -1,684 .id = -1,
684 .res = punit_res_array,685 .res = punit_res_array,
685 .num_res = ARRAY_SIZE(punit_res_array),686 .num_res = ipcdev.punit_res_count,
686 };687 };
687 688
688 pdev = platform_device_register_full(&pdevinfo);689 pdev = platform_device_register_full(&pdevinfo);
@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void) · 82 unmodified lines
771 if (ret) {772 if (ret) {
772 dev_err(ipcdev.dev, "Failed to add punit platform device\n");773 dev_err(ipcdev.dev, "Failed to add punit platform device\n");
773 platform_device_unregister(ipcdev.tco_dev);774 platform_device_unregister(ipcdev.tco_dev);
775 return ret;
774 }776 }
775 777
776 if (!ipcdev.telem_res_inval) {778 if (!ipcdev.telem_res_inval) {
777 ret = ipc_create_telemetry_device();779 ret = ipc_create_telemetry_device();
778 if (ret)780 if (ret) {
779 dev_warn(ipcdev.dev,781 dev_warn(ipcdev.dev,
780 "Failed to add telemetry platform device\n");782 "Failed to add telemetry platform device\n");
783 platform_device_unregister(ipcdev.punit_dev);
784 platform_device_unregister(ipcdev.tco_dev);
785 }
781 }786 }
782 787
783 return ret;788 return ret;
@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void) · 1 unmodified line
785 790
786static int ipc_plat_get_res(struct platform_device *pdev)791static int ipc_plat_get_res(struct platform_device *pdev)
787{792{
788 struct resource *res, *punit_res;793 struct resource *res, *punit_res = punit_res_array;
789 void __iomem *addr;794 void __iomem *addr;
790 int size;795 int size;
791 796
@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev) · 8 unmodified lines
800 ipcdev.acpi_io_size = size;805 ipcdev.acpi_io_size = size;
801 dev_info(&pdev->dev, "io res: %pR\n", res);806 dev_info(&pdev->dev, "io res: %pR\n", res);
802 807
803 punit_res = punit_res_array;808 ipcdev.punit_res_count = 0;
809
804 /* This is index 0 to cover BIOS data register */810 /* This is index 0 to cover BIOS data register */
805 res = platform_get_resource(pdev, IORESOURCE_MEM,811 res = platform_get_resource(pdev, IORESOURCE_MEM,
806 PLAT_RESOURCE_BIOS_DATA_INDEX);812 PLAT_RESOURCE_BIOS_DATA_INDEX);
@@ -808,7 +814,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) · 1 unmodified line
808 dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");814 dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
809 return -ENXIO;815 return -ENXIO;
810 }816 }
811 *punit_res = *res;817 punit_res[ipcdev.punit_res_count++] = *res;
812 dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);818 dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
813 819
814 /* This is index 1 to cover BIOS interface register */820 /* 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
818 dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");824 dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
819 return -ENXIO;825 return -ENXIO;
820 }826 }
821 *++punit_res = *res;827 punit_res[ipcdev.punit_res_count++] = *res;
822 dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);828 dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
823 829
824 /* This is index 2 to cover ISP data register, optional */830 /* This is index 2 to cover ISP data register, optional */
825 res = platform_get_resource(pdev, IORESOURCE_MEM,831 res = platform_get_resource(pdev, IORESOURCE_MEM,
826 PLAT_RESOURCE_ISP_DATA_INDEX);832 PLAT_RESOURCE_ISP_DATA_INDEX);
827 ++punit_res;
828 if (res) {833 if (res) {
829 *punit_res = *res;834 punit_res[ipcdev.punit_res_count++] = *res;
830 dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);835 dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
831 }836 }
832 837
833 /* This is index 3 to cover ISP interface register, optional */838 /* This is index 3 to cover ISP interface register, optional */
834 res = platform_get_resource(pdev, IORESOURCE_MEM,839 res = platform_get_resource(pdev, IORESOURCE_MEM,
835 PLAT_RESOURCE_ISP_IFACE_INDEX);840 PLAT_RESOURCE_ISP_IFACE_INDEX);
836 ++punit_res;
837 if (res) {841 if (res) {
838 *punit_res = *res;842 punit_res[ipcdev.punit_res_count++] = *res;
839 dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);843 dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
840 }844 }
841 845
842 /* This is index 4 to cover GTD data register, optional */846 /* This is index 4 to cover GTD data register, optional */
843 res = platform_get_resource(pdev, IORESOURCE_MEM,847 res = platform_get_resource(pdev, IORESOURCE_MEM,
844 PLAT_RESOURCE_GTD_DATA_INDEX);848 PLAT_RESOURCE_GTD_DATA_INDEX);
845 ++punit_res;
846 if (res) {849 if (res) {
847 *punit_res = *res;850 punit_res[ipcdev.punit_res_count++] = *res;
848 dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);851 dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
849 }852 }
850 853
851 /* This is index 5 to cover GTD interface register, optional */854 /* This is index 5 to cover GTD interface register, optional */
852 res = platform_get_resource(pdev, IORESOURCE_MEM,855 res = platform_get_resource(pdev, IORESOURCE_MEM,
853 PLAT_RESOURCE_GTD_IFACE_INDEX);856 PLAT_RESOURCE_GTD_IFACE_INDEX);
854 ++punit_res;
855 if (res) {857 if (res) {
856 *punit_res = *res;858 punit_res[ipcdev.punit_res_count++] = *res;
857 dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);859 dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
858 }860 }
859 861
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
252 * - GTDRIVER_IPC BASE_IFACE252 * - GTDRIVER_IPC BASE_IFACE
253 */253 */
254 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);254 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
255 if (res && resource_size(res) > 1) {255 if (res) {
256 addr = devm_ioremap_resource(&pdev->dev, res);256 addr = devm_ioremap_resource(&pdev->dev, res);
257 if (!IS_ERR(addr))257 if (!IS_ERR(addr))
258 punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;258 punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
259 }259 }
260 260
261 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);261 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
262 if (res && resource_size(res) > 1) {262 if (res) {
263 addr = devm_ioremap_resource(&pdev->dev, res);263 addr = devm_ioremap_resource(&pdev->dev, res);
264 if (!IS_ERR(addr))264 if (!IS_ERR(addr))
265 punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;265 punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
266 }266 }
267 267
268 res = platform_get_resource(pdev, IORESOURCE_MEM, 4);268 res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
269 if (res && resource_size(res) > 1) {269 if (res) {
270 addr = devm_ioremap_resource(&pdev->dev, res);270 addr = devm_ioremap_resource(&pdev->dev, res);
271 if (!IS_ERR(addr))271 if (!IS_ERR(addr))
272 punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;272 punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
273 }273 }
274 274
275 res = platform_get_resource(pdev, IORESOURCE_MEM, 5);275 res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
276 if (res && resource_size(res) > 1) {276 if (res) {
277 addr = devm_ioremap_resource(&pdev->dev, res);277 addr = devm_ioremap_resource(&pdev->dev, res);
278 if (!IS_ERR(addr))278 if (!IS_ERR(addr))
279 punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;279 punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
drivers/platform/x86/mlx-platform.c+226−2
@@ -56,6 +56,16 @@ · 55 unmodified lines
56#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x8856#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
57#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x8957#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
58#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a58#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
59#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe369#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3
60#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe470#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4
61#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe571#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5
@@ -72,6 +82,7 @@ · 10 unmodified lines
72#define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf582#define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5
73#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf683#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6
74#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf784#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7
85#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8
75#define MLXPLAT_CPLD_LPC_IO_RANGE 0x10086#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
76#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb87#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
77#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda88#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -128,6 +139,18 @@ · 50 unmodified lines
128#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13139#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
129#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14140#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
130 141
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
131/* mlxplat_priv - platform private data154/* mlxplat_priv - platform private data
132 * @pdev_i2c - i2c controller platform device155 * @pdev_i2c - i2c controller platform device
133 * @pdev_mux - array of mux platform devices156 * @pdev_mux - array of mux platform devices
@@ -135,6 +158,7 @@ · 1 unmodified line
135 * @pdev_led - led platform devices158 * @pdev_led - led platform devices
136 * @pdev_io_regs - register access platform devices159 * @pdev_io_regs - register access platform devices
137 * @pdev_fan - FAN platform devices160 * @pdev_fan - FAN platform devices
161 * @pdev_wd - array of watchdog platform devices
138 */162 */
139struct mlxplat_priv {163struct mlxplat_priv {
140 struct platform_device *pdev_i2c;164 struct platform_device *pdev_i2c;
@@ -143,6 +167,7 @@ struct mlxplat_priv { · 2 unmodified lines
143 struct platform_device *pdev_led;167 struct platform_device *pdev_led;
144 struct platform_device *pdev_io_regs;168 struct platform_device *pdev_io_regs;
145 struct platform_device *pdev_fan;169 struct platform_device *pdev_fan;
170 struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
146};171};
147 172
148/* Regions for LPC I2C controller and LPC base register space */173/* 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
1339 .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,1364 .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
1340 .bit = BIT(3),1365 .bit = BIT(3),
1341 },1366 },
1367 {
1368 .label = "conf",
1369 .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET,
1370 },
1342};1371};
1343 1372
1344static struct mlxreg_core_platform_data mlxplat_default_fan_data = {1373static 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
1346 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data),1375 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data),
1347};1376};
1348 1377
1378/* Watchdog type1: hardware implementation version1
1379 * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems).
1380 */
1381static 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
1408static 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
1429static 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 */
1447static 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
1479static 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
1505static 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
1349static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)1520static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
1350{1521{
1351 switch (reg) {1522 switch (reg) {
@@ -1368,6 +1539,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) · 16 unmodified lines
1368 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:1539 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
1369 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:1540 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
1370 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:1541 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:
1371 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:1550 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
1372 case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:1551 case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:
1373 return true;1552 return true;
@@ -1411,6 +1590,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) · 37 unmodified lines
1411 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:1590 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
1412 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:1591 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
1413 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:1592 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:
1414 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:1603 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
1415 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:1604 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
1416 case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:1605 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
1428 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:1617 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
1429 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:1618 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
1430 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:1619 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
1620 case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
1431 return true;1621 return true;
1432 }1622 }
1433 return false;1623 return false;
@@ -1467,6 +1657,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) · 33 unmodified lines
1467 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:1657 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
1468 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:1658 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
1469 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:1659 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:
1470 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:1664 case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
1471 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:1665 case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
1472 case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:1666 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
1484 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:1678 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
1485 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:1679 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
1486 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:1680 case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
1681 case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
1487 return true;1682 return true;
1488 }1683 }
1489 return false;1684 return false;
@@ -1493,6 +1688,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { · 3 unmodified lines
1493 { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 },1688 { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 },
1494 { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 },1689 { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 },
1495 { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },1690 { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
1691 { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
1496};1692};
1497 1693
1498struct mlxplat_mlxcpld_regmap_context {1694struct mlxplat_mlxcpld_regmap_context {
@@ -1542,6 +1738,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; · 43 unmodified lines
1542static struct mlxreg_core_platform_data *mlxplat_led;1738static struct mlxreg_core_platform_data *mlxplat_led;
1543static struct mlxreg_core_platform_data *mlxplat_regs_io;1739static struct mlxreg_core_platform_data *mlxplat_regs_io;
1544static struct mlxreg_core_platform_data *mlxplat_fan;1740static struct mlxreg_core_platform_data *mlxplat_fan;
1741static struct mlxreg_core_platform_data
1742 *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
1545 1743
1546static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)1744static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
1547{1745{
@@ -1557,6 +1755,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) · 9 unmodified lines
1557 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];1755 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
1558 mlxplat_led = &mlxplat_default_led_data;1756 mlxplat_led = &mlxplat_default_led_data;
1559 mlxplat_regs_io = &mlxplat_default_regs_io_data;1757 mlxplat_regs_io = &mlxplat_default_regs_io_data;
1758 mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
1560 1759
1561 return 1;1760 return 1;
1562};1761};
@@ -1575,6 +1774,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
1575 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];1774 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
1576 mlxplat_led = &mlxplat_msn21xx_led_data;1775 mlxplat_led = &mlxplat_msn21xx_led_data;
1577 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;1776 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1777 mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
1578 1778
1579 return 1;1779 return 1;
1580};1780};
@@ -1593,6 +1793,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
1593 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];1793 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
1594 mlxplat_led = &mlxplat_default_led_data;1794 mlxplat_led = &mlxplat_default_led_data;
1595 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;1795 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1796 mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
1596 1797
1597 return 1;1798 return 1;
1598};1799};
@@ -1611,6 +1812,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) · 12 unmodified lines
1611 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];1812 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
1612 mlxplat_led = &mlxplat_msn21xx_led_data;1813 mlxplat_led = &mlxplat_msn21xx_led_data;
1613 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;1814 mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
1815 mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
1614 1816
1615 return 1;1817 return 1;
1616};1818};
@@ -1630,6 +1832,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) · 13 unmodified lines
1630 mlxplat_led = &mlxplat_default_ng_led_data;1832 mlxplat_led = &mlxplat_default_ng_led_data;
1631 mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;1833 mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
1632 mlxplat_fan = &mlxplat_default_fan_data;1834 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];
1633 1837
1634 return 1;1838 return 1;
1635};1839};
@@ -1912,15 +2116,33 @@ static int __init mlxplat_init(void) · 276 unmodified lines
1912 }2116 }
1913 }2117 }
1914 2118
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
1915 /* Sync registers with hardware. */2135 /* Sync registers with hardware. */
1916 regcache_mark_dirty(mlxplat_hotplug->regmap);2136 regcache_mark_dirty(mlxplat_hotplug->regmap);
1917 err = regcache_sync(mlxplat_hotplug->regmap);2137 err = regcache_sync(mlxplat_hotplug->regmap);
1918 if (err)2138 if (err)
1919 goto fail_platform_fan_register;2139 goto fail_platform_wd_register;
1920 2140
1921 return 0;2141 return 0;
1922 2142
1923fail_platform_fan_register:2143fail_platform_wd_register:
2144 while (--j >= 0)
2145 platform_device_unregister(priv->pdev_wd[j]);
1924 if (mlxplat_fan)2146 if (mlxplat_fan)
1925 platform_device_unregister(priv->pdev_fan);2147 platform_device_unregister(priv->pdev_fan);
1926fail_platform_io_regs_register:2148fail_platform_io_regs_register:
@@ -1946,6 +2168,8 @@ static void __exit mlxplat_exit(void) · 19 unmodified lines
1946 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);2168 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
1947 int i;2169 int i;
1948 2170
2171 for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--)
2172 platform_device_unregister(priv->pdev_wd[i]);
1949 if (priv->pdev_fan)2173 if (priv->pdev_fan)
1950 platform_device_unregister(priv->pdev_fan);2174 platform_device_unregister(priv->pdev_fan);
1951 if (priv->pdev_io_regs)2175 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
4424 }4424 }
4425 return AE_OK;4425 return AE_OK;
4426 }4426 }
4427
4428 case ACPI_RESOURCE_TYPE_END_TAG:
4429 return AE_OK;
4430
4427 default:4431 default:
4428 dprintk("Resource %d isn't an IRQ nor an IO port\n",4432 dprintk("Resource %d isn't an IRQ nor an IO port\n",
4429 resource->type);4433 resource->type);
4434 return AE_CTRL_TERMINATE;
4430 4435
4431 case ACPI_RESOURCE_TYPE_END_TAG:
4432 return AE_OK;
4433 }4436 }
4434 return AE_CTRL_TERMINATE;
4435}4437}
4436 4438
4437static int sony_pic_possible_resources(struct acpi_device *device)4439static int sony_pic_possible_resources(struct acpi_device *device)
drivers/platform/x86/thinkpad_acpi.c+125−21
@@ -79,7 +79,7 @@ · 78 unmodified lines
79#include <linux/jiffies.h>79#include <linux/jiffies.h>
80#include <linux/workqueue.h>80#include <linux/workqueue.h>
81#include <linux/acpi.h>81#include <linux/acpi.h>
82#include <linux/pci_ids.h>82#include <linux/pci.h>
83#include <linux/power_supply.h>83#include <linux/power_supply.h>
84#include <sound/core.h>84#include <sound/core.h>
85#include <sound/control.h>85#include <sound/control.h>
@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) · 4126 unmodified lines
4212 known_ev = true;4212 known_ev = true;
4213 break;4213 break;
4214 }4214 }
4215 /* fallthrough to default */4215 /* fallthrough - to default */
4216 default:4216 default:
4217 known_ev = false;4217 known_ev = false;
4218 }4218 }
@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void) · 282 unmodified lines
4501 bluetooth_shutdown();4501 bluetooth_shutdown();
4502}4502}
4503 4503
4504static 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
4550static 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
4558static 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
4504static int __init bluetooth_init(struct ibm_init_struct *iibm)4572static int __init bluetooth_init(struct ibm_init_struct *iibm)
4505{4573{
4506 int res;4574 int res;
@@ -4513,7 +4581,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) · 6 unmodified lines
4513 4581
4514 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,4582 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
4515 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */4583 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
4516 tp_features.bluetooth = hkey_handle &&4584 tp_features.bluetooth = !have_bt_fwbug() && hkey_handle &&
4517 acpi_evalf(hkey_handle, &status, "GBDC", "qd");4585 acpi_evalf(hkey_handle, &status, "GBDC", "qd");
4518 4586
4519 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,4587 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led, · 1288 unmodified lines
5808 return -EPERM;5876 return -EPERM;
5809 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",5877 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
5810 (1 << led), led_sled_arg1[ledstatus]))5878 (1 << led), led_sled_arg1[ledstatus]))
5811 rc = -EIO;5879 return -EIO;
5812 break;5880 break;
5813 case TPACPI_LED_OLD:5881 case TPACPI_LED_OLD:
5814 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */5882 /* 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
5832 return -EPERM;5900 return -EPERM;
5833 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",5901 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
5834 led, led_led_arg1[ledstatus]))5902 led, led_led_arg1[ledstatus]))
5835 rc = -EIO;5903 return -EIO;
5836 break;5904 break;
5837 default:5905 default:
5838 rc = -ENXIO;5906 return -ENXIO;
5839 }5907 }
5840 5908
5841 if (!rc)5909 if (!rc)
@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value) · 407 unmodified lines
6249 t = TP_EC_THERMAL_TMP8;6317 t = TP_EC_THERMAL_TMP8;
6250 idx -= 8;6318 idx -= 8;
6251 }6319 }
6252 /* fallthrough */
6253#endif6320#endif
6321 /* fallthrough */
6254 case TPACPI_THERMAL_TPEC_8:6322 case TPACPI_THERMAL_TPEC_8:
6255 if (idx <= 7) {6323 if (idx <= 7) {
6256 if (!acpi_ec_read(t + idx, &tmp))6324 if (!acpi_ec_read(t + idx, &tmp))
@@ -9890,6 +9958,37 @@ invalid: · 3633 unmodified lines
9890 return '\0';9958 return '\0';
9891}9959}
9892 9960
9961static 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
9893/* returns 0 - probe ok, or < 0 - probe error.9992/* returns 0 - probe ok, or < 0 - probe error.
9894 * Probe ok doesn't mean thinkpad found.9993 * Probe ok doesn't mean thinkpad found.
9895 * On error, kfree() cleanup on tp->* is not performed, caller must do it */9994 * 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
9897 struct thinkpad_id_data *tp)9996 struct thinkpad_id_data *tp)
9898{9997{
9899 const struct dmi_device *dev = NULL;9998 const struct dmi_device *dev = NULL;
9900 char ec_fw_string[18];9999 char ec_fw_string[18] = {0};
9901 char const *s;10000 char const *s;
9902 char t;10001 char t;
9903 10002
@@ -9937,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data( · 33 unmodified lines
9937 ec_fw_string) == 1) {10036 ec_fw_string) == 1) {
9938 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;10037 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
9939 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;10038 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
10039 break;
10040 }
10041 }
9940 10042
9941 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);10043 /* Newer ThinkPads have different EC program info table */
9942 if (!tp->ec_version_str)10044 if (!ec_fw_string[0])
9943 return -ENOMEM;10045 dmi_walk(find_new_ec_fwstr, &ec_fw_string);
9944 10046
9945 t = tpacpi_parse_fw_id(ec_fw_string,10047 if (ec_fw_string[0]) {
9946 &tp->ec_model, &tp->ec_release);10048 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
9947 if (t != 'H') {10049 if (!tp->ec_version_str)
9948 pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",10050 return -ENOMEM;
9949 ec_fw_string);10051
9950 pr_notice("please report this to %s\n",10052 t = tpacpi_parse_fw_id(ec_fw_string,
9951 TPACPI_MAIL);10053 &tp->ec_model, &tp->ec_release);
9952 }10054 if (t != 'H') {
9953 break;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);
9954 }10058 }
9955 }10059 }
9956 10060
@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode, · 208 unmodified lines
10165 10269
10166module_param_named(volume_capabilities, volume_capabilities, uint, 0444);10270module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
10167MODULE_PARM_DESC(volume_capabilities,10271MODULE_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");
10169 10273
10170module_param_named(volume_control, volume_control_allowed, bool, 0444);10274module_param_named(volume_control, volume_control_allowed, bool, 0444);
10171MODULE_PARM_DESC(volume_control,10275MODULE_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
249 .properties = jumper_ezpad_6_pro_props,249 .properties = jumper_ezpad_6_pro_props,
250};250};
251 251
252static 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
262static 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
252static const struct property_entry jumper_ezpad_mini3_props[] = {267static const struct property_entry jumper_ezpad_mini3_props[] = {
253 PROPERTY_ENTRY_U32("touchscreen-min-x", 23),268 PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
254 PROPERTY_ENTRY_U32("touchscreen-min-y", 16),269 PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = { · 10 unmodified lines
265 .properties = jumper_ezpad_mini3_props,280 .properties = jumper_ezpad_mini3_props,
266};281};
267 282
283static 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
295static const struct ts_dmi_data myria_my8307_data = {
296 .acpi_name = "MSSL1680:00",
297 .properties = myria_my8307_props,
298};
299
268static const struct property_entry onda_obook_20_plus_props[] = {300static const struct property_entry onda_obook_20_plus_props[] = {
269 PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),301 PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
270 PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),302 PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { · 402 unmodified lines
673 DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),705 DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),
674 },706 },
675 },707 },
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 },
676 {719 {
677 /* Jumper EZpad mini3 */720 /* Jumper EZpad mini3 */
678 .driver_data = (void *)&jumper_ezpad_mini3_data,721 .driver_data = (void *)&jumper_ezpad_mini3_data,
@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { · 11 unmodified lines
690 DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),733 DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
691 },734 },
692 },735 },
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 },
693 {744 {
694 /* Onda oBook 20 Plus */745 /* Onda oBook 20 Plus */
695 .driver_data = (void *)&onda_obook_20_plus_data,746 .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
67/* Input */67/* Input */
68#define ASUS_WMI_DEVID_TOUCHPAD 0x0010001168#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
69#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x0010001269#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
70#define ASUS_WMI_DEVID_FNLOCK 0x00100023
70 71
71/* Fan, Thermal */72/* Fan, Thermal */
72#define ASUS_WMI_DEVID_THERMAL_CTRL 0x0011001173#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