hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/drivers/pci/hotplug/pnv_php.c
....@@ -18,6 +18,9 @@
1818 #define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
1919 #define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver"
2020
21
+#define SLOT_WARN(sl, x...) \
22
+ ((sl)->pdev ? pci_warn((sl)->pdev, x) : dev_warn(&(sl)->bus->dev, x))
23
+
2124 struct pnv_php_event {
2225 bool added;
2326 struct pnv_php_slot *php_slot;
....@@ -151,17 +154,11 @@
151154 static void pnv_php_detach_device_nodes(struct device_node *parent)
152155 {
153156 struct device_node *dn;
154
- int refcount;
155157
156158 for_each_child_of_node(parent, dn) {
157159 pnv_php_detach_device_nodes(dn);
158160
159161 of_node_put(dn);
160
- refcount = kref_read(&dn->kobj.kref);
161
- if (refcount != 1)
162
- pr_warn("Invalid refcount %d on <%pOF>\n",
163
- refcount, dn);
164
-
165162 of_detach_node(dn);
166163 }
167164 }
....@@ -271,22 +268,21 @@
271268
272269 ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
273270 if (ret) {
274
- pci_warn(php_slot->pdev, "Error %d getting FDT blob\n", ret);
271
+ SLOT_WARN(php_slot, "Error %d getting FDT blob\n", ret);
275272 goto free_fdt1;
276273 }
277274
278
- fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
275
+ fdt = kmemdup(fdt1, fdt_totalsize(fdt1), GFP_KERNEL);
279276 if (!fdt) {
280277 ret = -ENOMEM;
281278 goto free_fdt1;
282279 }
283280
284281 /* Unflatten device tree blob */
285
- memcpy(fdt, fdt1, fdt_totalsize(fdt1));
286282 dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
287283 if (!dt) {
288284 ret = -EINVAL;
289
- pci_warn(php_slot->pdev, "Cannot unflatten FDT\n");
285
+ SLOT_WARN(php_slot, "Cannot unflatten FDT\n");
290286 goto free_fdt;
291287 }
292288
....@@ -296,15 +292,15 @@
296292 ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
297293 if (ret) {
298294 pnv_php_reverse_nodes(php_slot->dn);
299
- pci_warn(php_slot->pdev, "Error %d populating changeset\n",
300
- ret);
295
+ SLOT_WARN(php_slot, "Error %d populating changeset\n",
296
+ ret);
301297 goto free_dt;
302298 }
303299
304300 php_slot->dn->child = NULL;
305301 ret = of_changeset_apply(&php_slot->ocs);
306302 if (ret) {
307
- pci_warn(php_slot->pdev, "Error %d applying changeset\n", ret);
303
+ SLOT_WARN(php_slot, "Error %d applying changeset\n", ret);
308304 goto destroy_changeset;
309305 }
310306
....@@ -328,28 +324,34 @@
328324 return ret;
329325 }
330326
327
+static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot)
328
+{
329
+ return container_of(slot, struct pnv_php_slot, slot);
330
+}
331
+
331332 int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
332333 uint8_t state)
333334 {
334
- struct pnv_php_slot *php_slot = slot->private;
335
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
335336 struct opal_msg msg;
336337 int ret;
337338
338339 ret = pnv_pci_set_power_state(php_slot->id, state, &msg);
339340 if (ret > 0) {
340341 if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle ||
341
- be64_to_cpu(msg.params[2]) != state ||
342
- be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
343
- pci_warn(php_slot->pdev, "Wrong msg (%lld, %lld, %lld)\n",
344
- be64_to_cpu(msg.params[1]),
345
- be64_to_cpu(msg.params[2]),
346
- be64_to_cpu(msg.params[3]));
342
+ be64_to_cpu(msg.params[2]) != state) {
343
+ SLOT_WARN(php_slot, "Wrong msg (%lld, %lld, %lld)\n",
344
+ be64_to_cpu(msg.params[1]),
345
+ be64_to_cpu(msg.params[2]),
346
+ be64_to_cpu(msg.params[3]));
347347 return -ENOMSG;
348348 }
349
+ if (be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
350
+ ret = -ENODEV;
351
+ goto error;
352
+ }
349353 } else if (ret < 0) {
350
- pci_warn(php_slot->pdev, "Error %d powering %s\n",
351
- ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
352
- return ret;
354
+ goto error;
353355 }
354356
355357 if (state == OPAL_PCI_SLOT_POWER_OFF || state == OPAL_PCI_SLOT_OFFLINE)
....@@ -358,12 +360,17 @@
358360 ret = pnv_php_add_devtree(php_slot);
359361
360362 return ret;
363
+
364
+error:
365
+ SLOT_WARN(php_slot, "Error %d powering %s\n",
366
+ ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
367
+ return ret;
361368 }
362369 EXPORT_SYMBOL_GPL(pnv_php_set_slot_power_state);
363370
364371 static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
365372 {
366
- struct pnv_php_slot *php_slot = slot->private;
373
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
367374 uint8_t power_state = OPAL_PCI_SLOT_POWER_ON;
368375 int ret;
369376
....@@ -374,11 +381,10 @@
374381 */
375382 ret = pnv_pci_get_power_state(php_slot->id, &power_state);
376383 if (ret) {
377
- pci_warn(php_slot->pdev, "Error %d getting power status\n",
378
- ret);
384
+ SLOT_WARN(php_slot, "Error %d getting power status\n",
385
+ ret);
379386 } else {
380387 *state = power_state;
381
- slot->info->power_status = power_state;
382388 }
383389
384390 return 0;
....@@ -386,7 +392,7 @@
386392
387393 static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
388394 {
389
- struct pnv_php_slot *php_slot = slot->private;
395
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
390396 uint8_t presence = OPAL_PCI_SLOT_EMPTY;
391397 int ret;
392398
....@@ -397,19 +403,40 @@
397403 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
398404 if (ret >= 0) {
399405 *state = presence;
400
- slot->info->adapter_status = presence;
401406 ret = 0;
402407 } else {
403
- pci_warn(php_slot->pdev, "Error %d getting presence\n", ret);
408
+ SLOT_WARN(php_slot, "Error %d getting presence\n", ret);
404409 }
405410
406411 return ret;
407412 }
408413
414
+static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
415
+{
416
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
417
+
418
+ *state = php_slot->attention_state;
419
+ return 0;
420
+}
421
+
409422 static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
410423 {
411
- /* FIXME: Make it real once firmware supports it */
412
- slot->info->attention_status = state;
424
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
425
+ struct pci_dev *bridge = php_slot->pdev;
426
+ u16 new, mask;
427
+
428
+ php_slot->attention_state = state;
429
+ if (!bridge)
430
+ return 0;
431
+
432
+ mask = PCI_EXP_SLTCTL_AIC;
433
+
434
+ if (state)
435
+ new = PCI_EXP_SLTCTL_ATTN_IND_ON;
436
+ else
437
+ new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
438
+
439
+ pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
413440
414441 return 0;
415442 }
....@@ -499,20 +526,56 @@
499526 return 0;
500527 }
501528
529
+static int pnv_php_reset_slot(struct hotplug_slot *slot, int probe)
530
+{
531
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
532
+ struct pci_dev *bridge = php_slot->pdev;
533
+ uint16_t sts;
534
+
535
+ /*
536
+ * The CAPI folks want pnv_php to drive OpenCAPI slots
537
+ * which don't have a bridge. Only claim to support
538
+ * reset_slot() if we have a bridge device (for now...)
539
+ */
540
+ if (probe)
541
+ return !bridge;
542
+
543
+ /* mask our interrupt while resetting the bridge */
544
+ if (php_slot->irq > 0)
545
+ disable_irq(php_slot->irq);
546
+
547
+ pci_bridge_secondary_bus_reset(bridge);
548
+
549
+ /* clear any state changes that happened due to the reset */
550
+ pcie_capability_read_word(php_slot->pdev, PCI_EXP_SLTSTA, &sts);
551
+ sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
552
+ pcie_capability_write_word(php_slot->pdev, PCI_EXP_SLTSTA, sts);
553
+
554
+ if (php_slot->irq > 0)
555
+ enable_irq(php_slot->irq);
556
+
557
+ return 0;
558
+}
559
+
502560 static int pnv_php_enable_slot(struct hotplug_slot *slot)
503561 {
504
- struct pnv_php_slot *php_slot = container_of(slot,
505
- struct pnv_php_slot, slot);
562
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
506563
507564 return pnv_php_enable(php_slot, true);
508565 }
509566
510567 static int pnv_php_disable_slot(struct hotplug_slot *slot)
511568 {
512
- struct pnv_php_slot *php_slot = slot->private;
569
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
513570 int ret;
514571
515
- if (php_slot->state != PNV_PHP_STATE_POPULATED)
572
+ /*
573
+ * Allow to disable a slot already in the registered state to
574
+ * cover cases where the slot couldn't be enabled and never
575
+ * reached the populated state
576
+ */
577
+ if (php_slot->state != PNV_PHP_STATE_POPULATED &&
578
+ php_slot->state != PNV_PHP_STATE_REGISTERED)
516579 return 0;
517580
518581 /* Remove all devices behind the slot */
....@@ -530,12 +593,14 @@
530593 return ret;
531594 }
532595
533
-static struct hotplug_slot_ops php_slot_ops = {
596
+static const struct hotplug_slot_ops php_slot_ops = {
534597 .get_power_status = pnv_php_get_power_state,
535598 .get_adapter_status = pnv_php_get_adapter_state,
599
+ .get_attention_status = pnv_php_get_attention_state,
536600 .set_attention_status = pnv_php_set_attention_state,
537601 .enable_slot = pnv_php_enable_slot,
538602 .disable_slot = pnv_php_disable_slot,
603
+ .reset_slot = pnv_php_reset_slot,
539604 };
540605
541606 static void pnv_php_release(struct pnv_php_slot *php_slot)
....@@ -594,8 +659,6 @@
594659 php_slot->id = id;
595660 php_slot->power_state_check = false;
596661 php_slot->slot.ops = &php_slot_ops;
597
- php_slot->slot.info = &php_slot->slot_info;
598
- php_slot->slot.private = php_slot;
599662
600663 INIT_LIST_HEAD(&php_slot->children);
601664 INIT_LIST_HEAD(&php_slot->link);
....@@ -621,7 +684,7 @@
621684 ret = pci_hp_register(&php_slot->slot, php_slot->bus,
622685 php_slot->slot_no, php_slot->name);
623686 if (ret) {
624
- pci_warn(php_slot->pdev, "Error %d registering slot\n", ret);
687
+ SLOT_WARN(php_slot, "Error %d registering slot\n", ret);
625688 return ret;
626689 }
627690
....@@ -674,7 +737,7 @@
674737 /* Enable MSIx */
675738 ret = pci_enable_msix_exact(pdev, &entry, 1);
676739 if (ret) {
677
- pci_warn(pdev, "Error %d enabling MSIx\n", ret);
740
+ SLOT_WARN(php_slot, "Error %d enabling MSIx\n", ret);
678741 return ret;
679742 }
680743
....@@ -711,6 +774,12 @@
711774 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
712775 sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
713776 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
777
+
778
+ pci_dbg(pdev, "PCI slot [%s]: HP int! DLAct: %d, PresDet: %d\n",
779
+ php_slot->name,
780
+ !!(sts & PCI_EXP_SLTSTA_DLLSC),
781
+ !!(sts & PCI_EXP_SLTSTA_PDC));
782
+
714783 if (sts & PCI_EXP_SLTSTA_DLLSC) {
715784 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
716785 added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
....@@ -718,13 +787,15 @@
718787 (sts & PCI_EXP_SLTSTA_PDC)) {
719788 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
720789 if (ret) {
721
- pci_warn(pdev, "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n",
722
- php_slot->name, ret, sts);
790
+ SLOT_WARN(php_slot,
791
+ "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n",
792
+ php_slot->name, ret, sts);
723793 return IRQ_HANDLED;
724794 }
725795
726796 added = !!(presence == OPAL_PCI_SLOT_PRESENT);
727797 } else {
798
+ pci_dbg(pdev, "PCI slot [%s]: Spurious IRQ?\n", php_slot->name);
728799 return IRQ_NONE;
729800 }
730801
....@@ -736,7 +807,7 @@
736807 pe = edev ? edev->pe : NULL;
737808 if (pe) {
738809 eeh_serialize_lock(&flags);
739
- eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
810
+ eeh_pe_mark_isolated(pe);
740811 eeh_serialize_unlock(flags);
741812 eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
742813 }
....@@ -748,8 +819,9 @@
748819 */
749820 event = kzalloc(sizeof(*event), GFP_ATOMIC);
750821 if (!event) {
751
- pci_warn(pdev, "PCI slot [%s] missed hotplug event 0x%04x\n",
752
- php_slot->name, sts);
822
+ SLOT_WARN(php_slot,
823
+ "PCI slot [%s] missed hotplug event 0x%04x\n",
824
+ php_slot->name, sts);
753825 return IRQ_HANDLED;
754826 }
755827
....@@ -773,7 +845,7 @@
773845 /* Allocate workqueue */
774846 php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
775847 if (!php_slot->wq) {
776
- pci_warn(pdev, "Cannot alloc workqueue\n");
848
+ SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
777849 pnv_php_disable_irq(php_slot, true);
778850 return;
779851 }
....@@ -797,7 +869,7 @@
797869 php_slot->name, php_slot);
798870 if (ret) {
799871 pnv_php_disable_irq(php_slot, true);
800
- pci_warn(pdev, "Error %d enabling IRQ %d\n", ret, irq);
872
+ SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
801873 return;
802874 }
803875
....@@ -833,7 +905,7 @@
833905
834906 ret = pci_enable_device(pdev);
835907 if (ret) {
836
- pci_warn(pdev, "Error %d enabling device\n", ret);
908
+ SLOT_WARN(php_slot, "Error %d enabling device\n", ret);
837909 return;
838910 }
839911
....@@ -945,6 +1017,11 @@
9451017 for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
9461018 pnv_php_register(dn);
9471019
1020
+ for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
1021
+ pnv_php_register(dn);
1022
+
1023
+ for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
1024
+ pnv_php_register_one(dn); /* slot directly under the PHB */
9481025 return 0;
9491026 }
9501027
....@@ -954,6 +1031,12 @@
9541031
9551032 for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
9561033 pnv_php_unregister(dn);
1034
+
1035
+ for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
1036
+ pnv_php_unregister(dn);
1037
+
1038
+ for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
1039
+ pnv_php_unregister_one(dn); /* slot directly under the PHB */
9571040 }
9581041
9591042 module_init(pnv_php_init);