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