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.
6  *
7  * The driver name refers to Native PCIe Enclosure Management. It is
8  * first indication oriented standard with specification.
9  *
10  * Native PCIe Enclosure Management (NPEM)
11  *	PCIe Base Specification r6.1 sec 6.28, 7.9.19
12  *
13  * _DSM Definitions for PCIe SSD Status LED
14  *	 PCI Firmware Specification, r3.3 sec 4.7
15  *
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.
19  *
20  * Copyright (c) 2021-2022 Dell Inc.
21  * Copyright (c) 2023-2024 Intel Corporation
22  *	Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
23  */
24 
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>
35 
36 #include "pci.h"
37 
38 struct indication {
39 	u32 bit;
40 	const char *name;
41 };
42 
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}
63 };
64 
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}
78 };
79 
80 #define for_each_indication(ind, inds) \
81 	for (ind = inds; ind->bit; ind++)
82 
83 /*
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.
87  *
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.
90  *
91  * Additionally, it excludes NPEM commands like RESET or ENABLE.
92  */
reg_to_indications(u32 caps,const struct indication * inds)93 static u32 reg_to_indications(u32 caps, const struct indication *inds)
94 {
95 	const struct indication *ind;
96 	u32 supported_indications = 0;
97 
98 	for_each_indication(ind, inds)
99 		supported_indications |= ind->bit;
100 
101 	return caps & supported_indications;
102 }
103 
104 /**
105  * struct npem_led - LED details
106  * @indication: indication details
107  * @npem: NPEM device
108  * @name: LED name
109  * @led: LED device
110  */
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;
116 };
117 
118 /**
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
128  */
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;
134 };
135 
136 /**
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
159  */
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[];
170 };
171 
npem_read_reg(struct npem * npem,u16 reg,u32 * val)172 static int npem_read_reg(struct npem *npem, u16 reg, u32 *val)
173 {
174 	int ret = pci_read_config_dword(npem->dev, npem->pos + reg, val);
175 
176 	return pcibios_err_to_errno(ret);
177 }
178 
npem_write_ctrl(struct npem * npem,u32 reg)179 static int npem_write_ctrl(struct npem *npem, u32 reg)
180 {
181 	int pos = npem->pos + PCI_NPEM_CTRL;
182 	int ret = pci_write_config_dword(npem->dev, pos, reg);
183 
184 	return pcibios_err_to_errno(ret);
185 }
186 
npem_get_active_indications(struct npem * npem,u32 * inds)187 static int npem_get_active_indications(struct npem *npem, u32 *inds)
188 {
189 	u32 ctrl;
190 	int ret;
191 
192 	ret = npem_read_reg(npem, PCI_NPEM_CTRL, &ctrl);
193 	if (ret)
194 		return ret;
195 
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;
200 	}
201 
202 	*inds = ctrl & npem->supported_indications;
203 
204 	return 0;
205 }
206 
npem_set_active_indications(struct npem * npem,u32 inds)207 static int npem_set_active_indications(struct npem *npem, u32 inds)
208 {
209 	int ctrl, ret, ret_val;
210 	u32 cc_status;
211 
212 	lockdep_assert_held(&npem->lock);
213 
214 	/* This bit is always required */
215 	ctrl = inds | PCI_NPEM_CTRL_ENABLE;
216 
217 	ret = npem_write_ctrl(npem, ctrl);
218 	if (ret)
219 		return ret;
220 
221 	/*
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.
226 	 *
227 	 * PCIe r6.1 sec 6.28 "Implementation Note: Software Polling of NPEM
228 	 * Command Completed"
229 	 */
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;
238 
239 	/*
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.
243 	 *
244 	 * PCIe Base Specification r6.1 sec 7.9.19.3
245 	 *
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.
249 	 */
250 	return npem_get_active_indications(npem, &npem->active_indications);
251 }
252 
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,
258 };
259 
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
265 
266 static const guid_t dsm_guid = DSM_GUID;
267 
npem_has_dsm(struct pci_dev * pdev)268 static bool npem_has_dsm(struct pci_dev *pdev)
269 {
270 	acpi_handle handle;
271 
272 	handle = ACPI_HANDLE(&pdev->dev);
273 	if (!handle)
274 		return false;
275 
276 	return acpi_check_dsm(handle, &dsm_guid, 0x1,
277 			      BIT(GET_SUPPORTED_STATES_DSM) |
278 			      BIT(GET_STATE_DSM) | BIT(SET_STATE_DSM));
279 }
280 
281 struct dsm_output {
282 	u16 status;
283 	u8 function_specific_err;
284 	u8 vendor_specific_err;
285 	u32 state;
286 };
287 
288 /**
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
294  *
295  * To not bother caller with ACPI context, the returned _DSM Output Buffer is
296  * copied.
297  */
dsm_evaluate(struct pci_dev * pdev,u64 dsm_func,struct dsm_output * output,u32 value_to_set)298 static int dsm_evaluate(struct pci_dev *pdev, u64 dsm_func,
299 			struct dsm_output *output, u32 value_to_set)
300 {
301 	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
302 	union acpi_object *out_obj, arg3[2];
303 	union acpi_object *arg3_p = NULL;
304 
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];
309 
310 		arg3[1].type = ACPI_TYPE_BUFFER;
311 		arg3[1].buffer.length = 4;
312 		arg3[1].buffer.pointer = (u8 *)&value_to_set;
313 
314 		arg3_p = arg3;
315 	}
316 
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;
321 
322 	if (out_obj->buffer.length < sizeof(struct dsm_output)) {
323 		ACPI_FREE(out_obj);
324 		return -EIO;
325 	}
326 
327 	memcpy(output, out_obj->buffer.pointer, sizeof(struct dsm_output));
328 
329 	ACPI_FREE(out_obj);
330 	return 0;
331 }
332 
dsm_get(struct pci_dev * pdev,u64 dsm_func,u32 * buf)333 static int dsm_get(struct pci_dev *pdev, u64 dsm_func, u32 *buf)
334 {
335 	struct dsm_output output;
336 	int ret = dsm_evaluate(pdev, dsm_func, &output, 0);
337 
338 	if (ret)
339 		return ret;
340 
341 	if (output.status != 0)
342 		return -EIO;
343 
344 	*buf = output.state;
345 	return 0;
346 }
347 
dsm_get_active_indications(struct npem * npem,u32 * buf)348 static int dsm_get_active_indications(struct npem *npem, u32 *buf)
349 {
350 	int ret = dsm_get(npem->dev, GET_STATE_DSM, buf);
351 
352 	/* Filter out not supported indications in response */
353 	*buf &= npem->supported_indications;
354 	return ret;
355 }
356 
dsm_set_active_indications(struct npem * npem,u32 value)357 static int dsm_set_active_indications(struct npem *npem, u32 value)
358 {
359 	struct dsm_output output;
360 	int ret = dsm_evaluate(npem->dev, SET_STATE_DSM, &output, value);
361 
362 	if (ret)
363 		return ret;
364 
365 	switch (output.status) {
366 	case 4:
367 		/*
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.
372 		 *
373 		 * PCI Firmware Specification, r3.3 Table 4-19.
374 		 */
375 		if (output.function_specific_err != 1)
376 			return -EIO;
377 		fallthrough;
378 	case 0:
379 		break;
380 	default:
381 		return -EIO;
382 	}
383 
384 	npem->active_indications = output.state;
385 
386 	return 0;
387 }
388 
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,
394 };
395 
npem_initialize_active_indications(struct npem * npem)396 static int npem_initialize_active_indications(struct npem *npem)
397 {
398 	int ret;
399 
400 	lockdep_assert_held(&npem->lock);
401 
402 	if (npem->active_inds_initialized)
403 		return 0;
404 
405 	ret = npem->ops->get_active_indications(npem,
406 						&npem->active_indications);
407 	if (ret)
408 		return ret;
409 
410 	npem->active_inds_initialized = true;
411 	return 0;
412 }
413 
414 /*
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.
418  */
brightness_get(struct led_classdev * led)419 static enum led_brightness brightness_get(struct led_classdev *led)
420 {
421 	struct npem_led *nled = container_of(led, struct npem_led, led);
422 	struct npem *npem = nled->npem;
423 	int ret, val = 0;
424 
425 	ret = mutex_lock_interruptible(&npem->lock);
426 	if (ret)
427 		return ret;
428 
429 	ret = npem_initialize_active_indications(npem);
430 	if (ret)
431 		goto out;
432 
433 	if (npem->active_indications & nled->indication->bit)
434 		val = 1;
435 
436 out:
437 	mutex_unlock(&npem->lock);
438 	return val;
439 }
440 
brightness_set(struct led_classdev * led,enum led_brightness brightness)441 static int brightness_set(struct led_classdev *led,
442 			  enum led_brightness brightness)
443 {
444 	struct npem_led *nled = container_of(led, struct npem_led, led);
445 	struct npem *npem = nled->npem;
446 	u32 indications;
447 	int ret;
448 
449 	ret = mutex_lock_interruptible(&npem->lock);
450 	if (ret)
451 		return ret;
452 
453 	ret = npem_initialize_active_indications(npem);
454 	if (ret)
455 		goto out;
456 
457 	if (brightness == 0)
458 		indications = npem->active_indications & ~(nled->indication->bit);
459 	else
460 		indications = npem->active_indications | nled->indication->bit;
461 
462 	ret = npem->ops->set_active_indications(npem, indications);
463 
464 out:
465 	mutex_unlock(&npem->lock);
466 	return ret;
467 }
468 
npem_free(struct npem * npem)469 static void npem_free(struct npem *npem)
470 {
471 	struct npem_led *nled;
472 	int cnt;
473 
474 	if (!npem)
475 		return;
476 
477 	for (cnt = 0; cnt < npem->led_cnt; cnt++) {
478 		nled = &npem->leds[cnt];
479 
480 		if (nled->name[0])
481 			led_classdev_unregister(&nled->led);
482 	}
483 
484 	mutex_destroy(&npem->lock);
485 	kfree(npem);
486 }
487 
pci_npem_set_led_classdev(struct npem * npem,struct npem_led * nled)488 static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled)
489 {
490 	struct led_classdev *led = &nled->led;
491 	struct led_init_data init_data = {};
492 	char *name = nled->name;
493 	int ret;
494 
495 	init_data.devicename = pci_name(npem->dev);
496 	init_data.default_label = nled->indication->name;
497 
498 	ret = led_compose_name(&npem->dev->dev, &init_data, name);
499 	if (ret)
500 		return ret;
501 
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;
508 
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;
514 }
515 
pci_npem_init(struct pci_dev * dev,const struct npem_ops * ops,int pos,u32 caps)516 static int pci_npem_init(struct pci_dev *dev, const struct npem_ops *ops,
517 			 int pos, u32 caps)
518 {
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;
526 
527 	npem = kzalloc(struct_size(npem, leds, supported_cnt), GFP_KERNEL);
528 	if (!npem)
529 		return -ENOMEM;
530 
531 	npem->supported_indications = supported;
532 	npem->led_cnt = supported_cnt;
533 	npem->pos = pos;
534 	npem->dev = dev;
535 	npem->ops = ops;
536 
537 	mutex_init(&npem->lock);
538 
539 	for_each_indication(indication, npem_indications) {
540 		if (!(npem->supported_indications & indication->bit))
541 			continue;
542 
543 		nled = &npem->leds[led_idx++];
544 		nled->indication = indication;
545 		nled->npem = npem;
546 
547 		ret = pci_npem_set_led_classdev(npem, nled);
548 		if (ret) {
549 			npem_free(npem);
550 			return ret;
551 		}
552 	}
553 
554 	dev->npem = npem;
555 	return 0;
556 }
557 
pci_npem_remove(struct pci_dev * dev)558 void pci_npem_remove(struct pci_dev *dev)
559 {
560 	npem_free(dev->npem);
561 }
562 
pci_npem_create(struct pci_dev * dev)563 void pci_npem_create(struct pci_dev *dev)
564 {
565 	const struct npem_ops *ops = &npem_ops;
566 	int pos = 0, ret;
567 	u32 cap;
568 
569 	if (npem_has_dsm(dev)) {
570 		/*
571 		 * OS should use the DSM for LED control if it is available
572 		 * PCI Firmware Spec r3.3 sec 4.7.
573 		 */
574 		ret = dsm_get(dev, GET_SUPPORTED_STATES_DSM, &cap);
575 		if (ret)
576 			return;
577 
578 		ops = &dsm_ops;
579 	} else {
580 		pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_NPEM);
581 		if (pos == 0)
582 			return;
583 
584 		if (pci_read_config_dword(dev, pos + PCI_NPEM_CAP, &cap) != 0 ||
585 		    (cap & PCI_NPEM_CAP_CAPABLE) == 0)
586 			return;
587 	}
588 
589 	pci_info(dev, "Configuring %s\n", ops->name);
590 
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);
595 }
596