npem.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  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. #include <linux/acpi.h>
  25. #include <linux/bitops.h>
  26. #include <linux/errno.h>
  27. #include <linux/iopoll.h>
  28. #include <linux/leds.h>
  29. #include <linux/mutex.h>
  30. #include <linux/pci.h>
  31. #include <linux/pci_regs.h>
  32. #include <linux/types.h>
  33. #include <linux/uleds.h>
  34. #include "pci.h"
  35. struct indication {
  36. u32 bit;
  37. const char *name;
  38. };
  39. static const struct indication npem_indications[] = {
  40. {PCI_NPEM_IND_OK, "enclosure:ok"},
  41. {PCI_NPEM_IND_LOCATE, "enclosure:locate"},
  42. {PCI_NPEM_IND_FAIL, "enclosure:fail"},
  43. {PCI_NPEM_IND_REBUILD, "enclosure:rebuild"},
  44. {PCI_NPEM_IND_PFA, "enclosure:pfa"},
  45. {PCI_NPEM_IND_HOTSPARE, "enclosure:hotspare"},
  46. {PCI_NPEM_IND_ICA, "enclosure:ica"},
  47. {PCI_NPEM_IND_IFA, "enclosure:ifa"},
  48. {PCI_NPEM_IND_IDT, "enclosure:idt"},
  49. {PCI_NPEM_IND_DISABLED, "enclosure:disabled"},
  50. {PCI_NPEM_IND_SPEC_0, "enclosure:specific_0"},
  51. {PCI_NPEM_IND_SPEC_1, "enclosure:specific_1"},
  52. {PCI_NPEM_IND_SPEC_2, "enclosure:specific_2"},
  53. {PCI_NPEM_IND_SPEC_3, "enclosure:specific_3"},
  54. {PCI_NPEM_IND_SPEC_4, "enclosure:specific_4"},
  55. {PCI_NPEM_IND_SPEC_5, "enclosure:specific_5"},
  56. {PCI_NPEM_IND_SPEC_6, "enclosure:specific_6"},
  57. {PCI_NPEM_IND_SPEC_7, "enclosure:specific_7"},
  58. {0, NULL}
  59. };
  60. /* _DSM PCIe SSD LED States correspond to NPEM register values */
  61. static const struct indication dsm_indications[] = {
  62. {PCI_NPEM_IND_OK, "enclosure:ok"},
  63. {PCI_NPEM_IND_LOCATE, "enclosure:locate"},
  64. {PCI_NPEM_IND_FAIL, "enclosure:fail"},
  65. {PCI_NPEM_IND_REBUILD, "enclosure:rebuild"},
  66. {PCI_NPEM_IND_PFA, "enclosure:pfa"},
  67. {PCI_NPEM_IND_HOTSPARE, "enclosure:hotspare"},
  68. {PCI_NPEM_IND_ICA, "enclosure:ica"},
  69. {PCI_NPEM_IND_IFA, "enclosure:ifa"},
  70. {PCI_NPEM_IND_IDT, "enclosure:idt"},
  71. {PCI_NPEM_IND_DISABLED, "enclosure:disabled"},
  72. {0, NULL}
  73. };
  74. #define for_each_indication(ind, inds) \
  75. for (ind = inds; ind->bit; ind++)
  76. /*
  77. * The driver has internal list of supported indications. Ideally, the driver
  78. * should not touch bits that are not defined and for which LED devices are
  79. * not exposed but in reality, it needs to turn them off.
  80. *
  81. * Otherwise, there will be no possibility to turn off indications turned on by
  82. * other utilities or turned on by default and it leads to bad user experience.
  83. *
  84. * Additionally, it excludes NPEM commands like RESET or ENABLE.
  85. */
  86. static u32 reg_to_indications(u32 caps, const struct indication *inds)
  87. {
  88. const struct indication *ind;
  89. u32 supported_indications = 0;
  90. for_each_indication(ind, inds)
  91. supported_indications |= ind->bit;
  92. return caps & supported_indications;
  93. }
  94. /**
  95. * struct npem_led - LED details
  96. * @indication: indication details
  97. * @npem: NPEM device
  98. * @name: LED name
  99. * @led: LED device
  100. */
  101. struct npem_led {
  102. const struct indication *indication;
  103. struct npem *npem;
  104. char name[LED_MAX_NAME_SIZE];
  105. struct led_classdev led;
  106. };
  107. /**
  108. * struct npem_ops - backend specific callbacks
  109. * @get_active_indications: get active indications
  110. * npem: NPEM device
  111. * inds: response buffer
  112. * @set_active_indications: set new indications
  113. * npem: npem device
  114. * inds: bit mask to set
  115. * @inds: supported indications array, set of indications is backend specific
  116. * @name: backend name
  117. */
  118. struct npem_ops {
  119. int (*get_active_indications)(struct npem *npem, u32 *inds);
  120. int (*set_active_indications)(struct npem *npem, u32 inds);
  121. const struct indication *inds;
  122. const char *name;
  123. };
  124. /**
  125. * struct npem - NPEM device properties
  126. * @dev: PCI device this driver is attached to
  127. * @ops: backend specific callbacks
  128. * @lock: serializes concurrent access to NPEM device by multiple LED devices
  129. * @pos: cached offset of NPEM Capability Register in Configuration Space;
  130. * only used if NPEM registers are accessed directly and not through _DSM
  131. * @supported_indications: cached bit mask of supported indications;
  132. * non-indication and reserved bits in the NPEM Capability Register are
  133. * cleared in this bit mask
  134. * @active_indications: cached bit mask of active indications;
  135. * non-indication and reserved bits in the NPEM Control Register are
  136. * cleared in this bit mask
  137. * @active_inds_initialized: whether @active_indications has been initialized;
  138. * On Dell platforms, it is required that IPMI drivers are loaded before
  139. * the GET_STATE_DSM method is invoked: They use an IPMI OpRegion to
  140. * get/set the active LEDs. By initializing @active_indications lazily
  141. * (on first access to an LED), IPMI drivers are given a chance to load.
  142. * If they are not loaded in time, users will see various errors on LED
  143. * access in dmesg. Once they are loaded, the errors go away and LED
  144. * access becomes possible.
  145. * @led_cnt: size of @leds array
  146. * @leds: array containing LED class devices of all supported LEDs
  147. */
  148. struct npem {
  149. struct pci_dev *dev;
  150. const struct npem_ops *ops;
  151. struct mutex lock;
  152. u16 pos;
  153. u32 supported_indications;
  154. u32 active_indications;
  155. unsigned int active_inds_initialized:1;
  156. int led_cnt;
  157. struct npem_led leds[];
  158. };
  159. static int npem_read_reg(struct npem *npem, u16 reg, u32 *val)
  160. {
  161. int ret = pci_read_config_dword(npem->dev, npem->pos + reg, val);
  162. return pcibios_err_to_errno(ret);
  163. }
  164. static int npem_write_ctrl(struct npem *npem, u32 reg)
  165. {
  166. int pos = npem->pos + PCI_NPEM_CTRL;
  167. int ret = pci_write_config_dword(npem->dev, pos, reg);
  168. return pcibios_err_to_errno(ret);
  169. }
  170. static int npem_get_active_indications(struct npem *npem, u32 *inds)
  171. {
  172. u32 ctrl;
  173. int ret;
  174. ret = npem_read_reg(npem, PCI_NPEM_CTRL, &ctrl);
  175. if (ret)
  176. return ret;
  177. /* If PCI_NPEM_CTRL_ENABLE is not set then no indication should blink */
  178. if (!(ctrl & PCI_NPEM_CTRL_ENABLE)) {
  179. *inds = 0;
  180. return 0;
  181. }
  182. *inds = ctrl & npem->supported_indications;
  183. return 0;
  184. }
  185. static int npem_set_active_indications(struct npem *npem, u32 inds)
  186. {
  187. int ctrl, ret, ret_val;
  188. u32 cc_status;
  189. lockdep_assert_held(&npem->lock);
  190. /* This bit is always required */
  191. ctrl = inds | PCI_NPEM_CTRL_ENABLE;
  192. ret = npem_write_ctrl(npem, ctrl);
  193. if (ret)
  194. return ret;
  195. /*
  196. * For the case where a NPEM command has not completed immediately,
  197. * it is recommended that software not continuously "spin" on polling
  198. * the status register, but rather poll under interrupt at a reduced
  199. * rate; for example at 10 ms intervals.
  200. *
  201. * PCIe r6.1 sec 6.28 "Implementation Note: Software Polling of NPEM
  202. * Command Completed"
  203. */
  204. ret = read_poll_timeout(npem_read_reg, ret_val,
  205. ret_val || (cc_status & PCI_NPEM_STATUS_CC),
  206. 10 * USEC_PER_MSEC, USEC_PER_SEC, false, npem,
  207. PCI_NPEM_STATUS, &cc_status);
  208. if (ret)
  209. return ret;
  210. if (ret_val)
  211. return ret_val;
  212. /*
  213. * All writes to control register, including writes that do not change
  214. * the register value, are NPEM commands and should eventually result
  215. * in a command completion indication in the NPEM Status Register.
  216. *
  217. * PCIe Base Specification r6.1 sec 7.9.19.3
  218. *
  219. * Register may not be updated, or other conflicting bits may be
  220. * cleared. Spec is not strict here. Read NPEM Control register after
  221. * write to keep cache in-sync.
  222. */
  223. return npem_get_active_indications(npem, &npem->active_indications);
  224. }
  225. static const struct npem_ops npem_ops = {
  226. .get_active_indications = npem_get_active_indications,
  227. .set_active_indications = npem_set_active_indications,
  228. .name = "Native PCIe Enclosure Management",
  229. .inds = npem_indications,
  230. };
  231. #define DSM_GUID GUID_INIT(0x5d524d9d, 0xfff9, 0x4d4b, 0x8c, 0xb7, 0x74, 0x7e,\
  232. 0xd5, 0x1e, 0x19, 0x4d)
  233. #define GET_SUPPORTED_STATES_DSM 1
  234. #define GET_STATE_DSM 2
  235. #define SET_STATE_DSM 3
  236. static const guid_t dsm_guid = DSM_GUID;
  237. static bool npem_has_dsm(struct pci_dev *pdev)
  238. {
  239. acpi_handle handle;
  240. handle = ACPI_HANDLE(&pdev->dev);
  241. if (!handle)
  242. return false;
  243. return acpi_check_dsm(handle, &dsm_guid, 0x1,
  244. BIT(GET_SUPPORTED_STATES_DSM) |
  245. BIT(GET_STATE_DSM) | BIT(SET_STATE_DSM));
  246. }
  247. struct dsm_output {
  248. u16 status;
  249. u8 function_specific_err;
  250. u8 vendor_specific_err;
  251. u32 state;
  252. };
  253. /**
  254. * dsm_evaluate() - send DSM PCIe SSD Status LED command
  255. * @pdev: PCI device
  256. * @dsm_func: DSM LED Function
  257. * @output: buffer to copy DSM Response
  258. * @value_to_set: value for SET_STATE_DSM function
  259. *
  260. * To not bother caller with ACPI context, the returned _DSM Output Buffer is
  261. * copied.
  262. */
  263. static int dsm_evaluate(struct pci_dev *pdev, u64 dsm_func,
  264. struct dsm_output *output, u32 value_to_set)
  265. {
  266. acpi_handle handle = ACPI_HANDLE(&pdev->dev);
  267. union acpi_object *out_obj, arg3[2];
  268. union acpi_object *arg3_p = NULL;
  269. if (dsm_func == SET_STATE_DSM) {
  270. arg3[0].type = ACPI_TYPE_PACKAGE;
  271. arg3[0].package.count = 1;
  272. arg3[0].package.elements = &arg3[1];
  273. arg3[1].type = ACPI_TYPE_BUFFER;
  274. arg3[1].buffer.length = 4;
  275. arg3[1].buffer.pointer = (u8 *)&value_to_set;
  276. arg3_p = arg3;
  277. }
  278. out_obj = acpi_evaluate_dsm_typed(handle, &dsm_guid, 0x1, dsm_func,
  279. arg3_p, ACPI_TYPE_BUFFER);
  280. if (!out_obj)
  281. return -EIO;
  282. if (out_obj->buffer.length < sizeof(struct dsm_output)) {
  283. ACPI_FREE(out_obj);
  284. return -EIO;
  285. }
  286. memcpy(output, out_obj->buffer.pointer, sizeof(struct dsm_output));
  287. ACPI_FREE(out_obj);
  288. return 0;
  289. }
  290. static int dsm_get(struct pci_dev *pdev, u64 dsm_func, u32 *buf)
  291. {
  292. struct dsm_output output;
  293. int ret = dsm_evaluate(pdev, dsm_func, &output, 0);
  294. if (ret)
  295. return ret;
  296. if (output.status != 0)
  297. return -EIO;
  298. *buf = output.state;
  299. return 0;
  300. }
  301. static int dsm_get_active_indications(struct npem *npem, u32 *buf)
  302. {
  303. int ret = dsm_get(npem->dev, GET_STATE_DSM, buf);
  304. /* Filter out not supported indications in response */
  305. *buf &= npem->supported_indications;
  306. return ret;
  307. }
  308. static int dsm_set_active_indications(struct npem *npem, u32 value)
  309. {
  310. struct dsm_output output;
  311. int ret = dsm_evaluate(npem->dev, SET_STATE_DSM, &output, value);
  312. if (ret)
  313. return ret;
  314. switch (output.status) {
  315. case 4:
  316. /*
  317. * Not all bits are set. If this bit is set, the platform
  318. * disregarded some or all of the request state changes. OSPM
  319. * should check the resulting PCIe SSD Status LED States to see
  320. * what, if anything, has changed.
  321. *
  322. * PCI Firmware Specification, r3.3 Table 4-19.
  323. */
  324. if (output.function_specific_err != 1)
  325. return -EIO;
  326. fallthrough;
  327. case 0:
  328. break;
  329. default:
  330. return -EIO;
  331. }
  332. npem->active_indications = output.state;
  333. return 0;
  334. }
  335. static const struct npem_ops dsm_ops = {
  336. .get_active_indications = dsm_get_active_indications,
  337. .set_active_indications = dsm_set_active_indications,
  338. .name = "_DSM PCIe SSD Status LED Management",
  339. .inds = dsm_indications,
  340. };
  341. static int npem_initialize_active_indications(struct npem *npem)
  342. {
  343. int ret;
  344. lockdep_assert_held(&npem->lock);
  345. if (npem->active_inds_initialized)
  346. return 0;
  347. ret = npem->ops->get_active_indications(npem,
  348. &npem->active_indications);
  349. if (ret)
  350. return ret;
  351. npem->active_inds_initialized = true;
  352. return 0;
  353. }
  354. /*
  355. * The status of each indicator is cached on first brightness_ get/set time
  356. * and updated at write time. brightness_get() is only responsible for
  357. * reflecting the last written/cached value.
  358. */
  359. static enum led_brightness brightness_get(struct led_classdev *led)
  360. {
  361. struct npem_led *nled = container_of(led, struct npem_led, led);
  362. struct npem *npem = nled->npem;
  363. int ret, val = 0;
  364. ret = mutex_lock_interruptible(&npem->lock);
  365. if (ret)
  366. return ret;
  367. ret = npem_initialize_active_indications(npem);
  368. if (ret)
  369. goto out;
  370. if (npem->active_indications & nled->indication->bit)
  371. val = 1;
  372. out:
  373. mutex_unlock(&npem->lock);
  374. return val;
  375. }
  376. static int brightness_set(struct led_classdev *led,
  377. enum led_brightness brightness)
  378. {
  379. struct npem_led *nled = container_of(led, struct npem_led, led);
  380. struct npem *npem = nled->npem;
  381. u32 indications;
  382. int ret;
  383. ret = mutex_lock_interruptible(&npem->lock);
  384. if (ret)
  385. return ret;
  386. ret = npem_initialize_active_indications(npem);
  387. if (ret)
  388. goto out;
  389. if (brightness == 0)
  390. indications = npem->active_indications & ~(nled->indication->bit);
  391. else
  392. indications = npem->active_indications | nled->indication->bit;
  393. ret = npem->ops->set_active_indications(npem, indications);
  394. out:
  395. mutex_unlock(&npem->lock);
  396. return ret;
  397. }
  398. static void npem_free(struct npem *npem)
  399. {
  400. struct npem_led *nled;
  401. int cnt;
  402. if (!npem)
  403. return;
  404. for (cnt = 0; cnt < npem->led_cnt; cnt++) {
  405. nled = &npem->leds[cnt];
  406. if (nled->name[0])
  407. led_classdev_unregister(&nled->led);
  408. }
  409. mutex_destroy(&npem->lock);
  410. kfree(npem);
  411. }
  412. static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled)
  413. {
  414. struct led_classdev *led = &nled->led;
  415. struct led_init_data init_data = {};
  416. char *name = nled->name;
  417. int ret;
  418. init_data.devicename = pci_name(npem->dev);
  419. init_data.default_label = nled->indication->name;
  420. ret = led_compose_name(&npem->dev->dev, &init_data, name);
  421. if (ret)
  422. return ret;
  423. led->name = name;
  424. led->brightness_set_blocking = brightness_set;
  425. led->brightness_get = brightness_get;
  426. led->max_brightness = 1;
  427. led->default_trigger = "none";
  428. led->flags = 0;
  429. ret = led_classdev_register(&npem->dev->dev, led);
  430. if (ret)
  431. /* Clear the name to indicate that it is not registered. */
  432. name[0] = 0;
  433. return ret;
  434. }
  435. static int pci_npem_init(struct pci_dev *dev, const struct npem_ops *ops,
  436. int pos, u32 caps)
  437. {
  438. u32 supported = reg_to_indications(caps, ops->inds);
  439. int supported_cnt = hweight32(supported);
  440. const struct indication *indication;
  441. struct npem_led *nled;
  442. struct npem *npem;
  443. int led_idx = 0;
  444. int ret;
  445. npem = kzalloc(struct_size(npem, leds, supported_cnt), GFP_KERNEL);
  446. if (!npem)
  447. return -ENOMEM;
  448. npem->supported_indications = supported;
  449. npem->led_cnt = supported_cnt;
  450. npem->pos = pos;
  451. npem->dev = dev;
  452. npem->ops = ops;
  453. mutex_init(&npem->lock);
  454. for_each_indication(indication, npem_indications) {
  455. if (!(npem->supported_indications & indication->bit))
  456. continue;
  457. nled = &npem->leds[led_idx++];
  458. nled->indication = indication;
  459. nled->npem = npem;
  460. ret = pci_npem_set_led_classdev(npem, nled);
  461. if (ret) {
  462. npem_free(npem);
  463. return ret;
  464. }
  465. }
  466. dev->npem = npem;
  467. return 0;
  468. }
  469. void pci_npem_remove(struct pci_dev *dev)
  470. {
  471. npem_free(dev->npem);
  472. }
  473. void pci_npem_create(struct pci_dev *dev)
  474. {
  475. const struct npem_ops *ops = &npem_ops;
  476. int pos = 0, ret;
  477. u32 cap;
  478. if (npem_has_dsm(dev)) {
  479. /*
  480. * OS should use the DSM for LED control if it is available
  481. * PCI Firmware Spec r3.3 sec 4.7.
  482. */
  483. ret = dsm_get(dev, GET_SUPPORTED_STATES_DSM, &cap);
  484. if (ret)
  485. return;
  486. ops = &dsm_ops;
  487. } else {
  488. pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_NPEM);
  489. if (pos == 0)
  490. return;
  491. if (pci_read_config_dword(dev, pos + PCI_NPEM_CAP, &cap) != 0 ||
  492. (cap & PCI_NPEM_CAP_CAPABLE) == 0)
  493. return;
  494. }
  495. pci_info(dev, "Configuring %s\n", ops->name);
  496. ret = pci_npem_init(dev, ops, pos, cap);
  497. if (ret)
  498. pci_err(dev, "Failed to register %s, err: %d\n", ops->name,
  499. ret);
  500. }