Revert "unicode: Don't special case ignorable code points"
[linux.git] / drivers / pci / npem.c
blob97507e0df769b708c3da8803bc17bf49ef977235
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * PCIe Enclosure management driver created for LED interfaces based on
4 * indications. It says *what indications* blink but does not specify *how*
5 * they blink - it is hardware defined.
7 * The driver name refers to Native PCIe Enclosure Management. It is
8 * first indication oriented standard with specification.
10 * Native PCIe Enclosure Management (NPEM)
11 * PCIe Base Specification r6.1 sec 6.28, 7.9.19
13 * _DSM Definitions for PCIe SSD Status LED
14 * PCI Firmware Specification, r3.3 sec 4.7
16 * Two backends are supported to manipulate indications: Direct NPEM register
17 * access (npem_ops) and indirect access through the ACPI _DSM (dsm_ops).
18 * _DSM is used if supported, else NPEM.
20 * Copyright (c) 2021-2022 Dell Inc.
21 * Copyright (c) 2023-2024 Intel Corporation
22 * Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
25 #include <linux/acpi.h>
26 #include <linux/bitops.h>
27 #include <linux/errno.h>
28 #include <linux/iopoll.h>
29 #include <linux/leds.h>
30 #include <linux/mutex.h>
31 #include <linux/pci.h>
32 #include <linux/pci_regs.h>
33 #include <linux/types.h>
34 #include <linux/uleds.h>
36 #include "pci.h"
38 struct indication {
39 u32 bit;
40 const char *name;
43 static const struct indication npem_indications[] = {
44 {PCI_NPEM_IND_OK, "enclosure:ok"},
45 {PCI_NPEM_IND_LOCATE, "enclosure:locate"},
46 {PCI_NPEM_IND_FAIL, "enclosure:fail"},
47 {PCI_NPEM_IND_REBUILD, "enclosure:rebuild"},
48 {PCI_NPEM_IND_PFA, "enclosure:pfa"},
49 {PCI_NPEM_IND_HOTSPARE, "enclosure:hotspare"},
50 {PCI_NPEM_IND_ICA, "enclosure:ica"},
51 {PCI_NPEM_IND_IFA, "enclosure:ifa"},
52 {PCI_NPEM_IND_IDT, "enclosure:idt"},
53 {PCI_NPEM_IND_DISABLED, "enclosure:disabled"},
54 {PCI_NPEM_IND_SPEC_0, "enclosure:specific_0"},
55 {PCI_NPEM_IND_SPEC_1, "enclosure:specific_1"},
56 {PCI_NPEM_IND_SPEC_2, "enclosure:specific_2"},
57 {PCI_NPEM_IND_SPEC_3, "enclosure:specific_3"},
58 {PCI_NPEM_IND_SPEC_4, "enclosure:specific_4"},
59 {PCI_NPEM_IND_SPEC_5, "enclosure:specific_5"},
60 {PCI_NPEM_IND_SPEC_6, "enclosure:specific_6"},
61 {PCI_NPEM_IND_SPEC_7, "enclosure:specific_7"},
62 {0, NULL}
65 /* _DSM PCIe SSD LED States correspond to NPEM register values */
66 static const struct indication dsm_indications[] = {
67 {PCI_NPEM_IND_OK, "enclosure:ok"},
68 {PCI_NPEM_IND_LOCATE, "enclosure:locate"},
69 {PCI_NPEM_IND_FAIL, "enclosure:fail"},
70 {PCI_NPEM_IND_REBUILD, "enclosure:rebuild"},
71 {PCI_NPEM_IND_PFA, "enclosure:pfa"},
72 {PCI_NPEM_IND_HOTSPARE, "enclosure:hotspare"},
73 {PCI_NPEM_IND_ICA, "enclosure:ica"},
74 {PCI_NPEM_IND_IFA, "enclosure:ifa"},
75 {PCI_NPEM_IND_IDT, "enclosure:idt"},
76 {PCI_NPEM_IND_DISABLED, "enclosure:disabled"},
77 {0, NULL}
80 #define for_each_indication(ind, inds) \
81 for (ind = inds; ind->bit; ind++)
84 * The driver has internal list of supported indications. Ideally, the driver
85 * should not touch bits that are not defined and for which LED devices are
86 * not exposed but in reality, it needs to turn them off.
88 * Otherwise, there will be no possibility to turn off indications turned on by
89 * other utilities or turned on by default and it leads to bad user experience.
91 * Additionally, it excludes NPEM commands like RESET or ENABLE.
93 static u32 reg_to_indications(u32 caps, const struct indication *inds)
95 const struct indication *ind;
96 u32 supported_indications = 0;
98 for_each_indication(ind, inds)
99 supported_indications |= ind->bit;
101 return caps & supported_indications;
105 * struct npem_led - LED details
106 * @indication: indication details
107 * @npem: NPEM device
108 * @name: LED name
109 * @led: LED device
111 struct npem_led {
112 const struct indication *indication;
113 struct npem *npem;
114 char name[LED_MAX_NAME_SIZE];
115 struct led_classdev led;
119 * struct npem_ops - backend specific callbacks
120 * @get_active_indications: get active indications
121 * npem: NPEM device
122 * inds: response buffer
123 * @set_active_indications: set new indications
124 * npem: npem device
125 * inds: bit mask to set
126 * @inds: supported indications array, set of indications is backend specific
127 * @name: backend name
129 struct npem_ops {
130 int (*get_active_indications)(struct npem *npem, u32 *inds);
131 int (*set_active_indications)(struct npem *npem, u32 inds);
132 const struct indication *inds;
133 const char *name;
137 * struct npem - NPEM device properties
138 * @dev: PCI device this driver is attached to
139 * @ops: backend specific callbacks
140 * @lock: serializes concurrent access to NPEM device by multiple LED devices
141 * @pos: cached offset of NPEM Capability Register in Configuration Space;
142 * only used if NPEM registers are accessed directly and not through _DSM
143 * @supported_indications: cached bit mask of supported indications;
144 * non-indication and reserved bits in the NPEM Capability Register are
145 * cleared in this bit mask
146 * @active_indications: cached bit mask of active indications;
147 * non-indication and reserved bits in the NPEM Control Register are
148 * cleared in this bit mask
149 * @active_inds_initialized: whether @active_indications has been initialized;
150 * On Dell platforms, it is required that IPMI drivers are loaded before
151 * the GET_STATE_DSM method is invoked: They use an IPMI OpRegion to
152 * get/set the active LEDs. By initializing @active_indications lazily
153 * (on first access to an LED), IPMI drivers are given a chance to load.
154 * If they are not loaded in time, users will see various errors on LED
155 * access in dmesg. Once they are loaded, the errors go away and LED
156 * access becomes possible.
157 * @led_cnt: size of @leds array
158 * @leds: array containing LED class devices of all supported LEDs
160 struct npem {
161 struct pci_dev *dev;
162 const struct npem_ops *ops;
163 struct mutex lock;
164 u16 pos;
165 u32 supported_indications;
166 u32 active_indications;
167 unsigned int active_inds_initialized:1;
168 int led_cnt;
169 struct npem_led leds[];
172 static int npem_read_reg(struct npem *npem, u16 reg, u32 *val)
174 int ret = pci_read_config_dword(npem->dev, npem->pos + reg, val);
176 return pcibios_err_to_errno(ret);
179 static int npem_write_ctrl(struct npem *npem, u32 reg)
181 int pos = npem->pos + PCI_NPEM_CTRL;
182 int ret = pci_write_config_dword(npem->dev, pos, reg);
184 return pcibios_err_to_errno(ret);
187 static int npem_get_active_indications(struct npem *npem, u32 *inds)
189 u32 ctrl;
190 int ret;
192 ret = npem_read_reg(npem, PCI_NPEM_CTRL, &ctrl);
193 if (ret)
194 return ret;
196 /* If PCI_NPEM_CTRL_ENABLE is not set then no indication should blink */
197 if (!(ctrl & PCI_NPEM_CTRL_ENABLE)) {
198 *inds = 0;
199 return 0;
202 *inds = ctrl & npem->supported_indications;
204 return 0;
207 static int npem_set_active_indications(struct npem *npem, u32 inds)
209 int ctrl, ret, ret_val;
210 u32 cc_status;
212 lockdep_assert_held(&npem->lock);
214 /* This bit is always required */
215 ctrl = inds | PCI_NPEM_CTRL_ENABLE;
217 ret = npem_write_ctrl(npem, ctrl);
218 if (ret)
219 return ret;
222 * For the case where a NPEM command has not completed immediately,
223 * it is recommended that software not continuously "spin" on polling
224 * the status register, but rather poll under interrupt at a reduced
225 * rate; for example at 10 ms intervals.
227 * PCIe r6.1 sec 6.28 "Implementation Note: Software Polling of NPEM
228 * Command Completed"
230 ret = read_poll_timeout(npem_read_reg, ret_val,
231 ret_val || (cc_status & PCI_NPEM_STATUS_CC),
232 10 * USEC_PER_MSEC, USEC_PER_SEC, false, npem,
233 PCI_NPEM_STATUS, &cc_status);
234 if (ret)
235 return ret;
236 if (ret_val)
237 return ret_val;
240 * All writes to control register, including writes that do not change
241 * the register value, are NPEM commands and should eventually result
242 * in a command completion indication in the NPEM Status Register.
244 * PCIe Base Specification r6.1 sec 7.9.19.3
246 * Register may not be updated, or other conflicting bits may be
247 * cleared. Spec is not strict here. Read NPEM Control register after
248 * write to keep cache in-sync.
250 return npem_get_active_indications(npem, &npem->active_indications);
253 static const struct npem_ops npem_ops = {
254 .get_active_indications = npem_get_active_indications,
255 .set_active_indications = npem_set_active_indications,
256 .name = "Native PCIe Enclosure Management",
257 .inds = npem_indications,
260 #define DSM_GUID GUID_INIT(0x5d524d9d, 0xfff9, 0x4d4b, 0x8c, 0xb7, 0x74, 0x7e,\
261 0xd5, 0x1e, 0x19, 0x4d)
262 #define GET_SUPPORTED_STATES_DSM 1
263 #define GET_STATE_DSM 2
264 #define SET_STATE_DSM 3
266 static const guid_t dsm_guid = DSM_GUID;
268 static bool npem_has_dsm(struct pci_dev *pdev)
270 acpi_handle handle;
272 handle = ACPI_HANDLE(&pdev->dev);
273 if (!handle)
274 return false;
276 return acpi_check_dsm(handle, &dsm_guid, 0x1,
277 BIT(GET_SUPPORTED_STATES_DSM) |
278 BIT(GET_STATE_DSM) | BIT(SET_STATE_DSM));
281 struct dsm_output {
282 u16 status;
283 u8 function_specific_err;
284 u8 vendor_specific_err;
285 u32 state;
289 * dsm_evaluate() - send DSM PCIe SSD Status LED command
290 * @pdev: PCI device
291 * @dsm_func: DSM LED Function
292 * @output: buffer to copy DSM Response
293 * @value_to_set: value for SET_STATE_DSM function
295 * To not bother caller with ACPI context, the returned _DSM Output Buffer is
296 * copied.
298 static int dsm_evaluate(struct pci_dev *pdev, u64 dsm_func,
299 struct dsm_output *output, u32 value_to_set)
301 acpi_handle handle = ACPI_HANDLE(&pdev->dev);
302 union acpi_object *out_obj, arg3[2];
303 union acpi_object *arg3_p = NULL;
305 if (dsm_func == SET_STATE_DSM) {
306 arg3[0].type = ACPI_TYPE_PACKAGE;
307 arg3[0].package.count = 1;
308 arg3[0].package.elements = &arg3[1];
310 arg3[1].type = ACPI_TYPE_BUFFER;
311 arg3[1].buffer.length = 4;
312 arg3[1].buffer.pointer = (u8 *)&value_to_set;
314 arg3_p = arg3;
317 out_obj = acpi_evaluate_dsm_typed(handle, &dsm_guid, 0x1, dsm_func,
318 arg3_p, ACPI_TYPE_BUFFER);
319 if (!out_obj)
320 return -EIO;
322 if (out_obj->buffer.length < sizeof(struct dsm_output)) {
323 ACPI_FREE(out_obj);
324 return -EIO;
327 memcpy(output, out_obj->buffer.pointer, sizeof(struct dsm_output));
329 ACPI_FREE(out_obj);
330 return 0;
333 static int dsm_get(struct pci_dev *pdev, u64 dsm_func, u32 *buf)
335 struct dsm_output output;
336 int ret = dsm_evaluate(pdev, dsm_func, &output, 0);
338 if (ret)
339 return ret;
341 if (output.status != 0)
342 return -EIO;
344 *buf = output.state;
345 return 0;
348 static int dsm_get_active_indications(struct npem *npem, u32 *buf)
350 int ret = dsm_get(npem->dev, GET_STATE_DSM, buf);
352 /* Filter out not supported indications in response */
353 *buf &= npem->supported_indications;
354 return ret;
357 static int dsm_set_active_indications(struct npem *npem, u32 value)
359 struct dsm_output output;
360 int ret = dsm_evaluate(npem->dev, SET_STATE_DSM, &output, value);
362 if (ret)
363 return ret;
365 switch (output.status) {
366 case 4:
368 * Not all bits are set. If this bit is set, the platform
369 * disregarded some or all of the request state changes. OSPM
370 * should check the resulting PCIe SSD Status LED States to see
371 * what, if anything, has changed.
373 * PCI Firmware Specification, r3.3 Table 4-19.
375 if (output.function_specific_err != 1)
376 return -EIO;
377 fallthrough;
378 case 0:
379 break;
380 default:
381 return -EIO;
384 npem->active_indications = output.state;
386 return 0;
389 static const struct npem_ops dsm_ops = {
390 .get_active_indications = dsm_get_active_indications,
391 .set_active_indications = dsm_set_active_indications,
392 .name = "_DSM PCIe SSD Status LED Management",
393 .inds = dsm_indications,
396 static int npem_initialize_active_indications(struct npem *npem)
398 int ret;
400 lockdep_assert_held(&npem->lock);
402 if (npem->active_inds_initialized)
403 return 0;
405 ret = npem->ops->get_active_indications(npem,
406 &npem->active_indications);
407 if (ret)
408 return ret;
410 npem->active_inds_initialized = true;
411 return 0;
415 * The status of each indicator is cached on first brightness_ get/set time
416 * and updated at write time. brightness_get() is only responsible for
417 * reflecting the last written/cached value.
419 static enum led_brightness brightness_get(struct led_classdev *led)
421 struct npem_led *nled = container_of(led, struct npem_led, led);
422 struct npem *npem = nled->npem;
423 int ret, val = 0;
425 ret = mutex_lock_interruptible(&npem->lock);
426 if (ret)
427 return ret;
429 ret = npem_initialize_active_indications(npem);
430 if (ret)
431 goto out;
433 if (npem->active_indications & nled->indication->bit)
434 val = 1;
436 out:
437 mutex_unlock(&npem->lock);
438 return val;
441 static int brightness_set(struct led_classdev *led,
442 enum led_brightness brightness)
444 struct npem_led *nled = container_of(led, struct npem_led, led);
445 struct npem *npem = nled->npem;
446 u32 indications;
447 int ret;
449 ret = mutex_lock_interruptible(&npem->lock);
450 if (ret)
451 return ret;
453 ret = npem_initialize_active_indications(npem);
454 if (ret)
455 goto out;
457 if (brightness == 0)
458 indications = npem->active_indications & ~(nled->indication->bit);
459 else
460 indications = npem->active_indications | nled->indication->bit;
462 ret = npem->ops->set_active_indications(npem, indications);
464 out:
465 mutex_unlock(&npem->lock);
466 return ret;
469 static void npem_free(struct npem *npem)
471 struct npem_led *nled;
472 int cnt;
474 if (!npem)
475 return;
477 for (cnt = 0; cnt < npem->led_cnt; cnt++) {
478 nled = &npem->leds[cnt];
480 if (nled->name[0])
481 led_classdev_unregister(&nled->led);
484 mutex_destroy(&npem->lock);
485 kfree(npem);
488 static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled)
490 struct led_classdev *led = &nled->led;
491 struct led_init_data init_data = {};
492 char *name = nled->name;
493 int ret;
495 init_data.devicename = pci_name(npem->dev);
496 init_data.default_label = nled->indication->name;
498 ret = led_compose_name(&npem->dev->dev, &init_data, name);
499 if (ret)
500 return ret;
502 led->name = name;
503 led->brightness_set_blocking = brightness_set;
504 led->brightness_get = brightness_get;
505 led->max_brightness = 1;
506 led->default_trigger = "none";
507 led->flags = 0;
509 ret = led_classdev_register(&npem->dev->dev, led);
510 if (ret)
511 /* Clear the name to indicate that it is not registered. */
512 name[0] = 0;
513 return ret;
516 static int pci_npem_init(struct pci_dev *dev, const struct npem_ops *ops,
517 int pos, u32 caps)
519 u32 supported = reg_to_indications(caps, ops->inds);
520 int supported_cnt = hweight32(supported);
521 const struct indication *indication;
522 struct npem_led *nled;
523 struct npem *npem;
524 int led_idx = 0;
525 int ret;
527 npem = kzalloc(struct_size(npem, leds, supported_cnt), GFP_KERNEL);
528 if (!npem)
529 return -ENOMEM;
531 npem->supported_indications = supported;
532 npem->led_cnt = supported_cnt;
533 npem->pos = pos;
534 npem->dev = dev;
535 npem->ops = ops;
537 mutex_init(&npem->lock);
539 for_each_indication(indication, npem_indications) {
540 if (!(npem->supported_indications & indication->bit))
541 continue;
543 nled = &npem->leds[led_idx++];
544 nled->indication = indication;
545 nled->npem = npem;
547 ret = pci_npem_set_led_classdev(npem, nled);
548 if (ret) {
549 npem_free(npem);
550 return ret;
554 dev->npem = npem;
555 return 0;
558 void pci_npem_remove(struct pci_dev *dev)
560 npem_free(dev->npem);
563 void pci_npem_create(struct pci_dev *dev)
565 const struct npem_ops *ops = &npem_ops;
566 int pos = 0, ret;
567 u32 cap;
569 if (npem_has_dsm(dev)) {
571 * OS should use the DSM for LED control if it is available
572 * PCI Firmware Spec r3.3 sec 4.7.
574 ret = dsm_get(dev, GET_SUPPORTED_STATES_DSM, &cap);
575 if (ret)
576 return;
578 ops = &dsm_ops;
579 } else {
580 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_NPEM);
581 if (pos == 0)
582 return;
584 if (pci_read_config_dword(dev, pos + PCI_NPEM_CAP, &cap) != 0 ||
585 (cap & PCI_NPEM_CAP_CAPABLE) == 0)
586 return;
589 pci_info(dev, "Configuring %s\n", ops->name);
591 ret = pci_npem_init(dev, ops, pos, cap);
592 if (ret)
593 pci_err(dev, "Failed to register %s, err: %d\n", ops->name,
594 ret);