octep_hp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (C) 2024 Marvell. */
  3. #include <linux/cleanup.h>
  4. #include <linux/container_of.h>
  5. #include <linux/delay.h>
  6. #include <linux/dev_printk.h>
  7. #include <linux/init.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/io-64-nonatomic-lo-hi.h>
  10. #include <linux/kernel.h>
  11. #include <linux/list.h>
  12. #include <linux/module.h>
  13. #include <linux/mutex.h>
  14. #include <linux/pci.h>
  15. #include <linux/pci_hotplug.h>
  16. #include <linux/slab.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/workqueue.h>
  19. #define OCTEP_HP_INTR_OFFSET(x) (0x20400 + ((x) << 4))
  20. #define OCTEP_HP_INTR_VECTOR(x) (16 + (x))
  21. #define OCTEP_HP_DRV_NAME "octep_hp"
  22. /*
  23. * Type of MSI-X interrupts. OCTEP_HP_INTR_VECTOR() and
  24. * OCTEP_HP_INTR_OFFSET() generate the vector and offset for an interrupt
  25. * type.
  26. */
  27. enum octep_hp_intr_type {
  28. OCTEP_HP_INTR_INVALID = -1,
  29. OCTEP_HP_INTR_ENA = 0,
  30. OCTEP_HP_INTR_DIS = 1,
  31. OCTEP_HP_INTR_MAX = 2,
  32. };
  33. struct octep_hp_cmd {
  34. struct list_head list;
  35. enum octep_hp_intr_type intr_type;
  36. u64 intr_val;
  37. };
  38. struct octep_hp_slot {
  39. struct list_head list;
  40. struct hotplug_slot slot;
  41. u16 slot_number;
  42. struct pci_dev *hp_pdev;
  43. unsigned int hp_devfn;
  44. struct octep_hp_controller *ctrl;
  45. };
  46. struct octep_hp_intr_info {
  47. enum octep_hp_intr_type type;
  48. int number;
  49. char name[16];
  50. };
  51. struct octep_hp_controller {
  52. void __iomem *base;
  53. struct pci_dev *pdev;
  54. struct octep_hp_intr_info intr[OCTEP_HP_INTR_MAX];
  55. struct work_struct work;
  56. struct list_head slot_list;
  57. struct mutex slot_lock; /* Protects slot_list */
  58. struct list_head hp_cmd_list;
  59. spinlock_t hp_cmd_lock; /* Protects hp_cmd_list */
  60. };
  61. static void octep_hp_enable_pdev(struct octep_hp_controller *hp_ctrl,
  62. struct octep_hp_slot *hp_slot)
  63. {
  64. guard(mutex)(&hp_ctrl->slot_lock);
  65. if (hp_slot->hp_pdev) {
  66. pci_dbg(hp_slot->hp_pdev, "Slot %s is already enabled\n",
  67. hotplug_slot_name(&hp_slot->slot));
  68. return;
  69. }
  70. /* Scan the device and add it to the bus */
  71. hp_slot->hp_pdev = pci_scan_single_device(hp_ctrl->pdev->bus,
  72. hp_slot->hp_devfn);
  73. pci_bus_assign_resources(hp_ctrl->pdev->bus);
  74. pci_bus_add_device(hp_slot->hp_pdev);
  75. dev_dbg(&hp_slot->hp_pdev->dev, "Enabled slot %s\n",
  76. hotplug_slot_name(&hp_slot->slot));
  77. }
  78. static void octep_hp_disable_pdev(struct octep_hp_controller *hp_ctrl,
  79. struct octep_hp_slot *hp_slot)
  80. {
  81. guard(mutex)(&hp_ctrl->slot_lock);
  82. if (!hp_slot->hp_pdev) {
  83. pci_dbg(hp_ctrl->pdev, "Slot %s is already disabled\n",
  84. hotplug_slot_name(&hp_slot->slot));
  85. return;
  86. }
  87. pci_dbg(hp_slot->hp_pdev, "Disabling slot %s\n",
  88. hotplug_slot_name(&hp_slot->slot));
  89. /* Remove the device from the bus */
  90. pci_stop_and_remove_bus_device_locked(hp_slot->hp_pdev);
  91. hp_slot->hp_pdev = NULL;
  92. }
  93. static int octep_hp_enable_slot(struct hotplug_slot *slot)
  94. {
  95. struct octep_hp_slot *hp_slot =
  96. container_of(slot, struct octep_hp_slot, slot);
  97. octep_hp_enable_pdev(hp_slot->ctrl, hp_slot);
  98. return 0;
  99. }
  100. static int octep_hp_disable_slot(struct hotplug_slot *slot)
  101. {
  102. struct octep_hp_slot *hp_slot =
  103. container_of(slot, struct octep_hp_slot, slot);
  104. octep_hp_disable_pdev(hp_slot->ctrl, hp_slot);
  105. return 0;
  106. }
  107. static struct hotplug_slot_ops octep_hp_slot_ops = {
  108. .enable_slot = octep_hp_enable_slot,
  109. .disable_slot = octep_hp_disable_slot,
  110. };
  111. #define SLOT_NAME_SIZE 16
  112. static struct octep_hp_slot *
  113. octep_hp_register_slot(struct octep_hp_controller *hp_ctrl,
  114. struct pci_dev *pdev, u16 slot_number)
  115. {
  116. char slot_name[SLOT_NAME_SIZE];
  117. struct octep_hp_slot *hp_slot;
  118. int ret;
  119. hp_slot = kzalloc_obj(*hp_slot);
  120. if (!hp_slot)
  121. return ERR_PTR(-ENOMEM);
  122. hp_slot->ctrl = hp_ctrl;
  123. hp_slot->hp_pdev = pdev;
  124. hp_slot->hp_devfn = pdev->devfn;
  125. hp_slot->slot_number = slot_number;
  126. hp_slot->slot.ops = &octep_hp_slot_ops;
  127. snprintf(slot_name, sizeof(slot_name), "octep_hp_%u", slot_number);
  128. ret = pci_hp_register(&hp_slot->slot, hp_ctrl->pdev->bus,
  129. PCI_SLOT(pdev->devfn), slot_name);
  130. if (ret) {
  131. kfree(hp_slot);
  132. return ERR_PTR(ret);
  133. }
  134. pci_info(pdev, "Registered slot %s for device %s\n",
  135. slot_name, pci_name(pdev));
  136. list_add_tail(&hp_slot->list, &hp_ctrl->slot_list);
  137. octep_hp_disable_pdev(hp_ctrl, hp_slot);
  138. return hp_slot;
  139. }
  140. static void octep_hp_deregister_slot(void *data)
  141. {
  142. struct octep_hp_slot *hp_slot = data;
  143. struct octep_hp_controller *hp_ctrl = hp_slot->ctrl;
  144. pci_hp_deregister(&hp_slot->slot);
  145. octep_hp_enable_pdev(hp_ctrl, hp_slot);
  146. list_del(&hp_slot->list);
  147. kfree(hp_slot);
  148. }
  149. static const char *octep_hp_cmd_name(enum octep_hp_intr_type type)
  150. {
  151. switch (type) {
  152. case OCTEP_HP_INTR_ENA:
  153. return "hotplug enable";
  154. case OCTEP_HP_INTR_DIS:
  155. return "hotplug disable";
  156. default:
  157. return "invalid";
  158. }
  159. }
  160. static void octep_hp_cmd_handler(struct octep_hp_controller *hp_ctrl,
  161. struct octep_hp_cmd *hp_cmd)
  162. {
  163. struct octep_hp_slot *hp_slot;
  164. /*
  165. * Enable or disable the slots based on the slot mask.
  166. * intr_val is a bit mask where each bit represents a slot.
  167. */
  168. list_for_each_entry(hp_slot, &hp_ctrl->slot_list, list) {
  169. if (!(hp_cmd->intr_val & BIT(hp_slot->slot_number)))
  170. continue;
  171. pci_info(hp_ctrl->pdev, "Received %s command for slot %s\n",
  172. octep_hp_cmd_name(hp_cmd->intr_type),
  173. hotplug_slot_name(&hp_slot->slot));
  174. switch (hp_cmd->intr_type) {
  175. case OCTEP_HP_INTR_ENA:
  176. octep_hp_enable_pdev(hp_ctrl, hp_slot);
  177. break;
  178. case OCTEP_HP_INTR_DIS:
  179. octep_hp_disable_pdev(hp_ctrl, hp_slot);
  180. break;
  181. default:
  182. break;
  183. }
  184. }
  185. }
  186. static void octep_hp_work_handler(struct work_struct *work)
  187. {
  188. struct octep_hp_controller *hp_ctrl;
  189. struct octep_hp_cmd *hp_cmd;
  190. unsigned long flags;
  191. hp_ctrl = container_of(work, struct octep_hp_controller, work);
  192. /* Process all the hotplug commands */
  193. spin_lock_irqsave(&hp_ctrl->hp_cmd_lock, flags);
  194. while (!list_empty(&hp_ctrl->hp_cmd_list)) {
  195. hp_cmd = list_first_entry(&hp_ctrl->hp_cmd_list,
  196. struct octep_hp_cmd, list);
  197. list_del(&hp_cmd->list);
  198. spin_unlock_irqrestore(&hp_ctrl->hp_cmd_lock, flags);
  199. octep_hp_cmd_handler(hp_ctrl, hp_cmd);
  200. kfree(hp_cmd);
  201. spin_lock_irqsave(&hp_ctrl->hp_cmd_lock, flags);
  202. }
  203. spin_unlock_irqrestore(&hp_ctrl->hp_cmd_lock, flags);
  204. }
  205. static enum octep_hp_intr_type octep_hp_intr_type(struct octep_hp_intr_info *intr,
  206. int irq)
  207. {
  208. enum octep_hp_intr_type type;
  209. for (type = OCTEP_HP_INTR_ENA; type < OCTEP_HP_INTR_MAX; type++) {
  210. if (intr[type].number == irq)
  211. return type;
  212. }
  213. return OCTEP_HP_INTR_INVALID;
  214. }
  215. static irqreturn_t octep_hp_intr_handler(int irq, void *data)
  216. {
  217. struct octep_hp_controller *hp_ctrl = data;
  218. struct pci_dev *pdev = hp_ctrl->pdev;
  219. enum octep_hp_intr_type type;
  220. struct octep_hp_cmd *hp_cmd;
  221. u64 intr_val;
  222. type = octep_hp_intr_type(hp_ctrl->intr, irq);
  223. if (type == OCTEP_HP_INTR_INVALID) {
  224. pci_err(pdev, "Invalid interrupt %d\n", irq);
  225. return IRQ_HANDLED;
  226. }
  227. /* Read and clear the interrupt */
  228. intr_val = readq(hp_ctrl->base + OCTEP_HP_INTR_OFFSET(type));
  229. writeq(intr_val, hp_ctrl->base + OCTEP_HP_INTR_OFFSET(type));
  230. hp_cmd = kzalloc_obj(*hp_cmd, GFP_ATOMIC);
  231. if (!hp_cmd)
  232. return IRQ_HANDLED;
  233. hp_cmd->intr_val = intr_val;
  234. hp_cmd->intr_type = type;
  235. /* Add the command to the list and schedule the work */
  236. spin_lock(&hp_ctrl->hp_cmd_lock);
  237. list_add_tail(&hp_cmd->list, &hp_ctrl->hp_cmd_list);
  238. spin_unlock(&hp_ctrl->hp_cmd_lock);
  239. schedule_work(&hp_ctrl->work);
  240. return IRQ_HANDLED;
  241. }
  242. static void octep_hp_irq_cleanup(void *data)
  243. {
  244. struct octep_hp_controller *hp_ctrl = data;
  245. pci_free_irq_vectors(hp_ctrl->pdev);
  246. flush_work(&hp_ctrl->work);
  247. }
  248. static int octep_hp_request_irq(struct octep_hp_controller *hp_ctrl,
  249. enum octep_hp_intr_type type)
  250. {
  251. struct pci_dev *pdev = hp_ctrl->pdev;
  252. struct octep_hp_intr_info *intr;
  253. int irq;
  254. irq = pci_irq_vector(pdev, OCTEP_HP_INTR_VECTOR(type));
  255. if (irq < 0)
  256. return irq;
  257. intr = &hp_ctrl->intr[type];
  258. intr->number = irq;
  259. intr->type = type;
  260. snprintf(intr->name, sizeof(intr->name), "octep_hp_%d", type);
  261. return devm_request_irq(&pdev->dev, irq, octep_hp_intr_handler,
  262. IRQF_SHARED, intr->name, hp_ctrl);
  263. }
  264. static int octep_hp_controller_setup(struct pci_dev *pdev,
  265. struct octep_hp_controller *hp_ctrl)
  266. {
  267. struct device *dev = &pdev->dev;
  268. enum octep_hp_intr_type type;
  269. int ret;
  270. ret = pcim_enable_device(pdev);
  271. if (ret)
  272. return dev_err_probe(dev, ret, "Failed to enable PCI device\n");
  273. hp_ctrl->base = pcim_iomap_region(pdev, 0, OCTEP_HP_DRV_NAME);
  274. if (IS_ERR(hp_ctrl->base))
  275. return dev_err_probe(dev, PTR_ERR(hp_ctrl->base),
  276. "Failed to map PCI device region\n");
  277. pci_set_master(pdev);
  278. pci_set_drvdata(pdev, hp_ctrl);
  279. INIT_LIST_HEAD(&hp_ctrl->slot_list);
  280. INIT_LIST_HEAD(&hp_ctrl->hp_cmd_list);
  281. mutex_init(&hp_ctrl->slot_lock);
  282. spin_lock_init(&hp_ctrl->hp_cmd_lock);
  283. INIT_WORK(&hp_ctrl->work, octep_hp_work_handler);
  284. hp_ctrl->pdev = pdev;
  285. ret = pci_alloc_irq_vectors(pdev, 1,
  286. OCTEP_HP_INTR_VECTOR(OCTEP_HP_INTR_MAX),
  287. PCI_IRQ_MSIX);
  288. if (ret < 0)
  289. return dev_err_probe(dev, ret, "Failed to alloc MSI-X vectors\n");
  290. ret = devm_add_action(&pdev->dev, octep_hp_irq_cleanup, hp_ctrl);
  291. if (ret)
  292. return dev_err_probe(&pdev->dev, ret, "Failed to add IRQ cleanup action\n");
  293. for (type = OCTEP_HP_INTR_ENA; type < OCTEP_HP_INTR_MAX; type++) {
  294. ret = octep_hp_request_irq(hp_ctrl, type);
  295. if (ret)
  296. return dev_err_probe(dev, ret,
  297. "Failed to request IRQ for vector %d\n",
  298. OCTEP_HP_INTR_VECTOR(type));
  299. }
  300. return 0;
  301. }
  302. static int octep_hp_pci_probe(struct pci_dev *pdev,
  303. const struct pci_device_id *id)
  304. {
  305. struct octep_hp_controller *hp_ctrl;
  306. struct pci_dev *tmp_pdev, *next;
  307. struct octep_hp_slot *hp_slot;
  308. u16 slot_number = 0;
  309. int ret;
  310. hp_ctrl = devm_kzalloc(&pdev->dev, sizeof(*hp_ctrl), GFP_KERNEL);
  311. if (!hp_ctrl)
  312. return -ENOMEM;
  313. ret = octep_hp_controller_setup(pdev, hp_ctrl);
  314. if (ret)
  315. return ret;
  316. /*
  317. * Register all hotplug slots. Hotplug controller is the first function
  318. * of the PCI device. The hotplug slots are the remaining functions of
  319. * the PCI device. The hotplug slot functions are logically removed from
  320. * the bus during probing and are re-enabled by the driver when a
  321. * hotplug event is received.
  322. */
  323. list_for_each_entry_safe(tmp_pdev, next, &pdev->bus->devices, bus_list) {
  324. if (tmp_pdev == pdev)
  325. continue;
  326. hp_slot = octep_hp_register_slot(hp_ctrl, tmp_pdev, slot_number);
  327. if (IS_ERR(hp_slot))
  328. return dev_err_probe(&pdev->dev, PTR_ERR(hp_slot),
  329. "Failed to register hotplug slot %u\n",
  330. slot_number);
  331. ret = devm_add_action(&pdev->dev, octep_hp_deregister_slot,
  332. hp_slot);
  333. if (ret)
  334. return dev_err_probe(&pdev->dev, ret,
  335. "Failed to add action for deregistering slot %u\n",
  336. slot_number);
  337. slot_number++;
  338. }
  339. return 0;
  340. }
  341. #define PCI_DEVICE_ID_CAVIUM_OCTEP_HP_CTLR 0xa0e3
  342. static struct pci_device_id octep_hp_pci_map[] = {
  343. { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_OCTEP_HP_CTLR) },
  344. { },
  345. };
  346. static struct pci_driver octep_hp = {
  347. .name = OCTEP_HP_DRV_NAME,
  348. .id_table = octep_hp_pci_map,
  349. .probe = octep_hp_pci_probe,
  350. };
  351. module_pci_driver(octep_hp);
  352. MODULE_LICENSE("GPL");
  353. MODULE_AUTHOR("Marvell");
  354. MODULE_DESCRIPTION("Marvell OCTEON PCI Hotplug driver");