0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/libfdt.h>
0009 #include <linux/module.h>
0010 #include <linux/pci.h>
0011 #include <linux/pci_hotplug.h>
0012 #include <linux/of_fdt.h>
0013
0014 #include <asm/opal.h>
0015 #include <asm/pnv-pci.h>
0016 #include <asm/ppc-pci.h>
0017
0018 #define DRIVER_VERSION "0.1"
0019 #define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
0020 #define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver"
0021
0022 #define SLOT_WARN(sl, x...) \
0023 ((sl)->pdev ? pci_warn((sl)->pdev, x) : dev_warn(&(sl)->bus->dev, x))
0024
0025 struct pnv_php_event {
0026 bool added;
0027 struct pnv_php_slot *php_slot;
0028 struct work_struct work;
0029 };
0030
0031 static LIST_HEAD(pnv_php_slot_list);
0032 static DEFINE_SPINLOCK(pnv_php_lock);
0033
0034 static void pnv_php_register(struct device_node *dn);
0035 static void pnv_php_unregister_one(struct device_node *dn);
0036 static void pnv_php_unregister(struct device_node *dn);
0037
0038 static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
0039 bool disable_device)
0040 {
0041 struct pci_dev *pdev = php_slot->pdev;
0042 int irq = php_slot->irq;
0043 u16 ctrl;
0044
0045 if (php_slot->irq > 0) {
0046 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
0047 ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
0048 PCI_EXP_SLTCTL_PDCE |
0049 PCI_EXP_SLTCTL_DLLSCE);
0050 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
0051
0052 free_irq(php_slot->irq, php_slot);
0053 php_slot->irq = 0;
0054 }
0055
0056 if (php_slot->wq) {
0057 destroy_workqueue(php_slot->wq);
0058 php_slot->wq = NULL;
0059 }
0060
0061 if (disable_device || irq > 0) {
0062 if (pdev->msix_enabled)
0063 pci_disable_msix(pdev);
0064 else if (pdev->msi_enabled)
0065 pci_disable_msi(pdev);
0066
0067 pci_disable_device(pdev);
0068 }
0069 }
0070
0071 static void pnv_php_free_slot(struct kref *kref)
0072 {
0073 struct pnv_php_slot *php_slot = container_of(kref,
0074 struct pnv_php_slot, kref);
0075
0076 WARN_ON(!list_empty(&php_slot->children));
0077 pnv_php_disable_irq(php_slot, false);
0078 kfree(php_slot->name);
0079 kfree(php_slot);
0080 }
0081
0082 static inline void pnv_php_put_slot(struct pnv_php_slot *php_slot)
0083 {
0084
0085 if (!php_slot)
0086 return;
0087
0088 kref_put(&php_slot->kref, pnv_php_free_slot);
0089 }
0090
0091 static struct pnv_php_slot *pnv_php_match(struct device_node *dn,
0092 struct pnv_php_slot *php_slot)
0093 {
0094 struct pnv_php_slot *target, *tmp;
0095
0096 if (php_slot->dn == dn) {
0097 kref_get(&php_slot->kref);
0098 return php_slot;
0099 }
0100
0101 list_for_each_entry(tmp, &php_slot->children, link) {
0102 target = pnv_php_match(dn, tmp);
0103 if (target)
0104 return target;
0105 }
0106
0107 return NULL;
0108 }
0109
0110 struct pnv_php_slot *pnv_php_find_slot(struct device_node *dn)
0111 {
0112 struct pnv_php_slot *php_slot, *tmp;
0113 unsigned long flags;
0114
0115 spin_lock_irqsave(&pnv_php_lock, flags);
0116 list_for_each_entry(tmp, &pnv_php_slot_list, link) {
0117 php_slot = pnv_php_match(dn, tmp);
0118 if (php_slot) {
0119 spin_unlock_irqrestore(&pnv_php_lock, flags);
0120 return php_slot;
0121 }
0122 }
0123 spin_unlock_irqrestore(&pnv_php_lock, flags);
0124
0125 return NULL;
0126 }
0127 EXPORT_SYMBOL_GPL(pnv_php_find_slot);
0128
0129
0130
0131
0132
0133 static void pnv_php_rmv_pdns(struct device_node *dn)
0134 {
0135 struct device_node *child;
0136
0137 for_each_child_of_node(dn, child) {
0138 pnv_php_rmv_pdns(child);
0139
0140 pci_remove_device_node_info(child);
0141 }
0142 }
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 static void pnv_php_detach_device_nodes(struct device_node *parent)
0156 {
0157 struct device_node *dn;
0158
0159 for_each_child_of_node(parent, dn) {
0160 pnv_php_detach_device_nodes(dn);
0161
0162 of_node_put(dn);
0163 of_detach_node(dn);
0164 }
0165 }
0166
0167 static void pnv_php_rmv_devtree(struct pnv_php_slot *php_slot)
0168 {
0169 pnv_php_rmv_pdns(php_slot->dn);
0170
0171
0172
0173
0174
0175 if (php_slot->fdt)
0176 of_changeset_destroy(&php_slot->ocs);
0177 pnv_php_detach_device_nodes(php_slot->dn);
0178
0179 if (php_slot->fdt) {
0180 kfree(php_slot->dt);
0181 kfree(php_slot->fdt);
0182 php_slot->dt = NULL;
0183 php_slot->dn->child = NULL;
0184 php_slot->fdt = NULL;
0185 }
0186 }
0187
0188
0189
0190
0191
0192
0193 static void pnv_php_reverse_nodes(struct device_node *parent)
0194 {
0195 struct device_node *child, *next;
0196
0197
0198 for_each_child_of_node(parent, child)
0199 pnv_php_reverse_nodes(child);
0200
0201
0202 child = parent->child;
0203 parent->child = NULL;
0204 while (child) {
0205 next = child->sibling;
0206
0207 child->sibling = parent->child;
0208 parent->child = child;
0209 child = next;
0210 }
0211 }
0212
0213 static int pnv_php_populate_changeset(struct of_changeset *ocs,
0214 struct device_node *dn)
0215 {
0216 struct device_node *child;
0217 int ret = 0;
0218
0219 for_each_child_of_node(dn, child) {
0220 ret = of_changeset_attach_node(ocs, child);
0221 if (ret) {
0222 of_node_put(child);
0223 break;
0224 }
0225
0226 ret = pnv_php_populate_changeset(ocs, child);
0227 if (ret) {
0228 of_node_put(child);
0229 break;
0230 }
0231 }
0232
0233 return ret;
0234 }
0235
0236 static void *pnv_php_add_one_pdn(struct device_node *dn, void *data)
0237 {
0238 struct pci_controller *hose = (struct pci_controller *)data;
0239 struct pci_dn *pdn;
0240
0241 pdn = pci_add_device_node_info(hose, dn);
0242 if (!pdn)
0243 return ERR_PTR(-ENOMEM);
0244
0245 return NULL;
0246 }
0247
0248 static void pnv_php_add_pdns(struct pnv_php_slot *slot)
0249 {
0250 struct pci_controller *hose = pci_bus_to_host(slot->bus);
0251
0252 pci_traverse_device_nodes(slot->dn, pnv_php_add_one_pdn, hose);
0253 }
0254
0255 static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
0256 {
0257 void *fdt, *fdt1, *dt;
0258 int ret;
0259
0260
0261
0262
0263
0264 fdt1 = kzalloc(0x10000, GFP_KERNEL);
0265 if (!fdt1) {
0266 ret = -ENOMEM;
0267 goto out;
0268 }
0269
0270 ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
0271 if (ret) {
0272 SLOT_WARN(php_slot, "Error %d getting FDT blob\n", ret);
0273 goto free_fdt1;
0274 }
0275
0276 fdt = kmemdup(fdt1, fdt_totalsize(fdt1), GFP_KERNEL);
0277 if (!fdt) {
0278 ret = -ENOMEM;
0279 goto free_fdt1;
0280 }
0281
0282
0283 dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
0284 if (!dt) {
0285 ret = -EINVAL;
0286 SLOT_WARN(php_slot, "Cannot unflatten FDT\n");
0287 goto free_fdt;
0288 }
0289
0290
0291 of_changeset_init(&php_slot->ocs);
0292 pnv_php_reverse_nodes(php_slot->dn);
0293 ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
0294 if (ret) {
0295 pnv_php_reverse_nodes(php_slot->dn);
0296 SLOT_WARN(php_slot, "Error %d populating changeset\n",
0297 ret);
0298 goto free_dt;
0299 }
0300
0301 php_slot->dn->child = NULL;
0302 ret = of_changeset_apply(&php_slot->ocs);
0303 if (ret) {
0304 SLOT_WARN(php_slot, "Error %d applying changeset\n", ret);
0305 goto destroy_changeset;
0306 }
0307
0308
0309 pnv_php_add_pdns(php_slot);
0310 php_slot->fdt = fdt;
0311 php_slot->dt = dt;
0312 kfree(fdt1);
0313 goto out;
0314
0315 destroy_changeset:
0316 of_changeset_destroy(&php_slot->ocs);
0317 free_dt:
0318 kfree(dt);
0319 php_slot->dn->child = NULL;
0320 free_fdt:
0321 kfree(fdt);
0322 free_fdt1:
0323 kfree(fdt1);
0324 out:
0325 return ret;
0326 }
0327
0328 static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot)
0329 {
0330 return container_of(slot, struct pnv_php_slot, slot);
0331 }
0332
0333 int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
0334 uint8_t state)
0335 {
0336 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0337 struct opal_msg msg;
0338 int ret;
0339
0340 ret = pnv_pci_set_power_state(php_slot->id, state, &msg);
0341 if (ret > 0) {
0342 if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle ||
0343 be64_to_cpu(msg.params[2]) != state) {
0344 SLOT_WARN(php_slot, "Wrong msg (%lld, %lld, %lld)\n",
0345 be64_to_cpu(msg.params[1]),
0346 be64_to_cpu(msg.params[2]),
0347 be64_to_cpu(msg.params[3]));
0348 return -ENOMSG;
0349 }
0350 if (be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
0351 ret = -ENODEV;
0352 goto error;
0353 }
0354 } else if (ret < 0) {
0355 goto error;
0356 }
0357
0358 if (state == OPAL_PCI_SLOT_POWER_OFF || state == OPAL_PCI_SLOT_OFFLINE)
0359 pnv_php_rmv_devtree(php_slot);
0360 else
0361 ret = pnv_php_add_devtree(php_slot);
0362
0363 return ret;
0364
0365 error:
0366 SLOT_WARN(php_slot, "Error %d powering %s\n",
0367 ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
0368 return ret;
0369 }
0370 EXPORT_SYMBOL_GPL(pnv_php_set_slot_power_state);
0371
0372 static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
0373 {
0374 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0375 uint8_t power_state = OPAL_PCI_SLOT_POWER_ON;
0376 int ret;
0377
0378
0379
0380
0381
0382
0383 ret = pnv_pci_get_power_state(php_slot->id, &power_state);
0384 if (ret) {
0385 SLOT_WARN(php_slot, "Error %d getting power status\n",
0386 ret);
0387 } else {
0388 *state = power_state;
0389 }
0390
0391 return 0;
0392 }
0393
0394 static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
0395 {
0396 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0397 uint8_t presence = OPAL_PCI_SLOT_EMPTY;
0398 int ret;
0399
0400
0401
0402
0403
0404 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
0405 if (ret >= 0) {
0406 *state = presence;
0407 ret = 0;
0408 } else {
0409 SLOT_WARN(php_slot, "Error %d getting presence\n", ret);
0410 }
0411
0412 return ret;
0413 }
0414
0415 static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
0416 {
0417 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0418
0419 *state = php_slot->attention_state;
0420 return 0;
0421 }
0422
0423 static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
0424 {
0425 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0426 struct pci_dev *bridge = php_slot->pdev;
0427 u16 new, mask;
0428
0429 php_slot->attention_state = state;
0430 if (!bridge)
0431 return 0;
0432
0433 mask = PCI_EXP_SLTCTL_AIC;
0434
0435 if (state)
0436 new = PCI_EXP_SLTCTL_ATTN_IND_ON;
0437 else
0438 new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
0439
0440 pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
0441
0442 return 0;
0443 }
0444
0445 static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
0446 {
0447 struct hotplug_slot *slot = &php_slot->slot;
0448 uint8_t presence = OPAL_PCI_SLOT_EMPTY;
0449 uint8_t power_status = OPAL_PCI_SLOT_POWER_ON;
0450 int ret;
0451
0452
0453 if (php_slot->state != PNV_PHP_STATE_REGISTERED)
0454 return 0;
0455
0456
0457 ret = pnv_php_get_adapter_state(slot, &presence);
0458 if (ret)
0459 return ret;
0460
0461
0462
0463
0464
0465
0466
0467 if (presence == OPAL_PCI_SLOT_EMPTY) {
0468 if (!php_slot->power_state_check) {
0469 php_slot->power_state_check = true;
0470
0471 return 0;
0472 }
0473
0474 goto scan;
0475 }
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487 if (!php_slot->power_state_check) {
0488 php_slot->power_state_check = true;
0489
0490 ret = pnv_php_get_power_state(slot, &power_status);
0491 if (ret)
0492 return ret;
0493
0494 if (power_status != OPAL_PCI_SLOT_POWER_ON)
0495 return 0;
0496 }
0497
0498
0499 ret = pnv_php_get_power_state(slot, &power_status);
0500 if (ret)
0501 return ret;
0502
0503 if (power_status == OPAL_PCI_SLOT_POWER_ON)
0504 goto scan;
0505
0506
0507 ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
0508 if (ret)
0509 return ret;
0510
0511 scan:
0512 if (presence == OPAL_PCI_SLOT_PRESENT) {
0513 if (rescan) {
0514 pci_lock_rescan_remove();
0515 pci_hp_add_devices(php_slot->bus);
0516 pci_unlock_rescan_remove();
0517 }
0518
0519
0520 php_slot->state = PNV_PHP_STATE_POPULATED;
0521 if (rescan)
0522 pnv_php_register(php_slot->dn);
0523 } else {
0524 php_slot->state = PNV_PHP_STATE_POPULATED;
0525 }
0526
0527 return 0;
0528 }
0529
0530 static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
0531 {
0532 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0533 struct pci_dev *bridge = php_slot->pdev;
0534 uint16_t sts;
0535
0536
0537
0538
0539
0540
0541 if (probe)
0542 return !bridge;
0543
0544
0545 if (php_slot->irq > 0)
0546 disable_irq(php_slot->irq);
0547
0548 pci_bridge_secondary_bus_reset(bridge);
0549
0550
0551 pcie_capability_read_word(php_slot->pdev, PCI_EXP_SLTSTA, &sts);
0552 sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
0553 pcie_capability_write_word(php_slot->pdev, PCI_EXP_SLTSTA, sts);
0554
0555 if (php_slot->irq > 0)
0556 enable_irq(php_slot->irq);
0557
0558 return 0;
0559 }
0560
0561 static int pnv_php_enable_slot(struct hotplug_slot *slot)
0562 {
0563 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0564
0565 return pnv_php_enable(php_slot, true);
0566 }
0567
0568 static int pnv_php_disable_slot(struct hotplug_slot *slot)
0569 {
0570 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
0571 int ret;
0572
0573
0574
0575
0576
0577
0578 if (php_slot->state != PNV_PHP_STATE_POPULATED &&
0579 php_slot->state != PNV_PHP_STATE_REGISTERED)
0580 return 0;
0581
0582
0583 pci_lock_rescan_remove();
0584 pci_hp_remove_devices(php_slot->bus);
0585 pci_unlock_rescan_remove();
0586
0587
0588 pnv_php_unregister(php_slot->dn);
0589
0590
0591 ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_OFF);
0592
0593 php_slot->state = PNV_PHP_STATE_REGISTERED;
0594 return ret;
0595 }
0596
0597 static const struct hotplug_slot_ops php_slot_ops = {
0598 .get_power_status = pnv_php_get_power_state,
0599 .get_adapter_status = pnv_php_get_adapter_state,
0600 .get_attention_status = pnv_php_get_attention_state,
0601 .set_attention_status = pnv_php_set_attention_state,
0602 .enable_slot = pnv_php_enable_slot,
0603 .disable_slot = pnv_php_disable_slot,
0604 .reset_slot = pnv_php_reset_slot,
0605 };
0606
0607 static void pnv_php_release(struct pnv_php_slot *php_slot)
0608 {
0609 unsigned long flags;
0610
0611
0612 spin_lock_irqsave(&pnv_php_lock, flags);
0613 list_del(&php_slot->link);
0614 spin_unlock_irqrestore(&pnv_php_lock, flags);
0615
0616
0617 pnv_php_put_slot(php_slot);
0618 pnv_php_put_slot(php_slot->parent);
0619 }
0620
0621 static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
0622 {
0623 struct pnv_php_slot *php_slot;
0624 struct pci_bus *bus;
0625 const char *label;
0626 uint64_t id;
0627 int ret;
0628
0629 ret = of_property_read_string(dn, "ibm,slot-label", &label);
0630 if (ret)
0631 return NULL;
0632
0633 if (pnv_pci_get_slot_id(dn, &id))
0634 return NULL;
0635
0636 bus = pci_find_bus_by_node(dn);
0637 if (!bus)
0638 return NULL;
0639
0640 php_slot = kzalloc(sizeof(*php_slot), GFP_KERNEL);
0641 if (!php_slot)
0642 return NULL;
0643
0644 php_slot->name = kstrdup(label, GFP_KERNEL);
0645 if (!php_slot->name) {
0646 kfree(php_slot);
0647 return NULL;
0648 }
0649
0650 if (dn->child && PCI_DN(dn->child))
0651 php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
0652 else
0653 php_slot->slot_no = -1;
0654
0655 kref_init(&php_slot->kref);
0656 php_slot->state = PNV_PHP_STATE_INITIALIZED;
0657 php_slot->dn = dn;
0658 php_slot->pdev = bus->self;
0659 php_slot->bus = bus;
0660 php_slot->id = id;
0661 php_slot->power_state_check = false;
0662 php_slot->slot.ops = &php_slot_ops;
0663
0664 INIT_LIST_HEAD(&php_slot->children);
0665 INIT_LIST_HEAD(&php_slot->link);
0666
0667 return php_slot;
0668 }
0669
0670 static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
0671 {
0672 struct pnv_php_slot *parent;
0673 struct device_node *dn = php_slot->dn;
0674 unsigned long flags;
0675 int ret;
0676
0677
0678 parent = pnv_php_find_slot(php_slot->dn);
0679 if (parent) {
0680 pnv_php_put_slot(parent);
0681 return -EEXIST;
0682 }
0683
0684
0685 ret = pci_hp_register(&php_slot->slot, php_slot->bus,
0686 php_slot->slot_no, php_slot->name);
0687 if (ret) {
0688 SLOT_WARN(php_slot, "Error %d registering slot\n", ret);
0689 return ret;
0690 }
0691
0692
0693 while ((dn = of_get_parent(dn))) {
0694 if (!PCI_DN(dn)) {
0695 of_node_put(dn);
0696 break;
0697 }
0698
0699 parent = pnv_php_find_slot(dn);
0700 if (parent) {
0701 of_node_put(dn);
0702 break;
0703 }
0704
0705 of_node_put(dn);
0706 }
0707
0708 spin_lock_irqsave(&pnv_php_lock, flags);
0709 php_slot->parent = parent;
0710 if (parent)
0711 list_add_tail(&php_slot->link, &parent->children);
0712 else
0713 list_add_tail(&php_slot->link, &pnv_php_slot_list);
0714 spin_unlock_irqrestore(&pnv_php_lock, flags);
0715
0716 php_slot->state = PNV_PHP_STATE_REGISTERED;
0717 return 0;
0718 }
0719
0720 static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
0721 {
0722 struct pci_dev *pdev = php_slot->pdev;
0723 struct msix_entry entry;
0724 int nr_entries, ret;
0725 u16 pcie_flag;
0726
0727
0728 nr_entries = pci_msix_vec_count(pdev);
0729 if (nr_entries < 0)
0730 return nr_entries;
0731
0732
0733 pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
0734 entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9;
0735 if (entry.entry >= nr_entries)
0736 return -ERANGE;
0737
0738
0739 ret = pci_enable_msix_exact(pdev, &entry, 1);
0740 if (ret) {
0741 SLOT_WARN(php_slot, "Error %d enabling MSIx\n", ret);
0742 return ret;
0743 }
0744
0745 return entry.vector;
0746 }
0747
0748 static void pnv_php_event_handler(struct work_struct *work)
0749 {
0750 struct pnv_php_event *event =
0751 container_of(work, struct pnv_php_event, work);
0752 struct pnv_php_slot *php_slot = event->php_slot;
0753
0754 if (event->added)
0755 pnv_php_enable_slot(&php_slot->slot);
0756 else
0757 pnv_php_disable_slot(&php_slot->slot);
0758
0759 kfree(event);
0760 }
0761
0762 static irqreturn_t pnv_php_interrupt(int irq, void *data)
0763 {
0764 struct pnv_php_slot *php_slot = data;
0765 struct pci_dev *pchild, *pdev = php_slot->pdev;
0766 struct eeh_dev *edev;
0767 struct eeh_pe *pe;
0768 struct pnv_php_event *event;
0769 u16 sts, lsts;
0770 u8 presence;
0771 bool added;
0772 unsigned long flags;
0773 int ret;
0774
0775 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
0776 sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
0777 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
0778
0779 pci_dbg(pdev, "PCI slot [%s]: HP int! DLAct: %d, PresDet: %d\n",
0780 php_slot->name,
0781 !!(sts & PCI_EXP_SLTSTA_DLLSC),
0782 !!(sts & PCI_EXP_SLTSTA_PDC));
0783
0784 if (sts & PCI_EXP_SLTSTA_DLLSC) {
0785 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
0786 added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
0787 } else if (!(php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) &&
0788 (sts & PCI_EXP_SLTSTA_PDC)) {
0789 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
0790 if (ret) {
0791 SLOT_WARN(php_slot,
0792 "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n",
0793 php_slot->name, ret, sts);
0794 return IRQ_HANDLED;
0795 }
0796
0797 added = !!(presence == OPAL_PCI_SLOT_PRESENT);
0798 } else {
0799 pci_dbg(pdev, "PCI slot [%s]: Spurious IRQ?\n", php_slot->name);
0800 return IRQ_NONE;
0801 }
0802
0803
0804 if (!added) {
0805 pchild = list_first_entry_or_null(&php_slot->bus->devices,
0806 struct pci_dev, bus_list);
0807 edev = pchild ? pci_dev_to_eeh_dev(pchild) : NULL;
0808 pe = edev ? edev->pe : NULL;
0809 if (pe) {
0810 eeh_serialize_lock(&flags);
0811 eeh_pe_mark_isolated(pe);
0812 eeh_serialize_unlock(flags);
0813 eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
0814 }
0815 }
0816
0817
0818
0819
0820
0821 event = kzalloc(sizeof(*event), GFP_ATOMIC);
0822 if (!event) {
0823 SLOT_WARN(php_slot,
0824 "PCI slot [%s] missed hotplug event 0x%04x\n",
0825 php_slot->name, sts);
0826 return IRQ_HANDLED;
0827 }
0828
0829 pci_info(pdev, "PCI slot [%s] %s (IRQ: %d)\n",
0830 php_slot->name, added ? "added" : "removed", irq);
0831 INIT_WORK(&event->work, pnv_php_event_handler);
0832 event->added = added;
0833 event->php_slot = php_slot;
0834 queue_work(php_slot->wq, &event->work);
0835
0836 return IRQ_HANDLED;
0837 }
0838
0839 static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
0840 {
0841 struct pci_dev *pdev = php_slot->pdev;
0842 u32 broken_pdc = 0;
0843 u16 sts, ctrl;
0844 int ret;
0845
0846
0847 php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
0848 if (!php_slot->wq) {
0849 SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
0850 pnv_php_disable_irq(php_slot, true);
0851 return;
0852 }
0853
0854
0855 ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
0856 &broken_pdc);
0857 if (!ret && broken_pdc)
0858 php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
0859
0860
0861 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
0862 if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
0863 sts |= PCI_EXP_SLTSTA_DLLSC;
0864 else
0865 sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
0866 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
0867
0868
0869 ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
0870 php_slot->name, php_slot);
0871 if (ret) {
0872 pnv_php_disable_irq(php_slot, true);
0873 SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
0874 return;
0875 }
0876
0877
0878 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
0879 if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
0880 ctrl &= ~PCI_EXP_SLTCTL_PDCE;
0881 ctrl |= (PCI_EXP_SLTCTL_HPIE |
0882 PCI_EXP_SLTCTL_DLLSCE);
0883 } else {
0884 ctrl |= (PCI_EXP_SLTCTL_HPIE |
0885 PCI_EXP_SLTCTL_PDCE |
0886 PCI_EXP_SLTCTL_DLLSCE);
0887 }
0888 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
0889
0890
0891 php_slot->irq = irq;
0892 }
0893
0894 static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
0895 {
0896 struct pci_dev *pdev = php_slot->pdev;
0897 int irq, ret;
0898
0899
0900
0901
0902
0903
0904 if (pci_dev_msi_enabled(pdev))
0905 return;
0906
0907 ret = pci_enable_device(pdev);
0908 if (ret) {
0909 SLOT_WARN(php_slot, "Error %d enabling device\n", ret);
0910 return;
0911 }
0912
0913 pci_set_master(pdev);
0914
0915
0916 irq = pnv_php_enable_msix(php_slot);
0917 if (irq > 0) {
0918 pnv_php_init_irq(php_slot, irq);
0919 return;
0920 }
0921
0922
0923
0924
0925
0926 ret = pci_enable_msi(pdev);
0927 if (!ret || pdev->irq) {
0928 irq = pdev->irq;
0929 pnv_php_init_irq(php_slot, irq);
0930 }
0931 }
0932
0933 static int pnv_php_register_one(struct device_node *dn)
0934 {
0935 struct pnv_php_slot *php_slot;
0936 u32 prop32;
0937 int ret;
0938
0939
0940 ret = of_property_read_u32(dn, "ibm,slot-pluggable", &prop32);
0941 if (ret || !prop32)
0942 return -ENXIO;
0943
0944 ret = of_property_read_u32(dn, "ibm,reset-by-firmware", &prop32);
0945 if (ret || !prop32)
0946 return -ENXIO;
0947
0948 php_slot = pnv_php_alloc_slot(dn);
0949 if (!php_slot)
0950 return -ENODEV;
0951
0952 ret = pnv_php_register_slot(php_slot);
0953 if (ret)
0954 goto free_slot;
0955
0956 ret = pnv_php_enable(php_slot, false);
0957 if (ret)
0958 goto unregister_slot;
0959
0960
0961 ret = of_property_read_u32(dn, "ibm,slot-surprise-pluggable", &prop32);
0962 if (!ret && prop32)
0963 pnv_php_enable_irq(php_slot);
0964
0965 return 0;
0966
0967 unregister_slot:
0968 pnv_php_unregister_one(php_slot->dn);
0969 free_slot:
0970 pnv_php_put_slot(php_slot);
0971 return ret;
0972 }
0973
0974 static void pnv_php_register(struct device_node *dn)
0975 {
0976 struct device_node *child;
0977
0978
0979
0980
0981
0982 for_each_child_of_node(dn, child) {
0983 pnv_php_register_one(child);
0984 pnv_php_register(child);
0985 }
0986 }
0987
0988 static void pnv_php_unregister_one(struct device_node *dn)
0989 {
0990 struct pnv_php_slot *php_slot;
0991
0992 php_slot = pnv_php_find_slot(dn);
0993 if (!php_slot)
0994 return;
0995
0996 php_slot->state = PNV_PHP_STATE_OFFLINE;
0997 pci_hp_deregister(&php_slot->slot);
0998 pnv_php_release(php_slot);
0999 pnv_php_put_slot(php_slot);
1000 }
1001
1002 static void pnv_php_unregister(struct device_node *dn)
1003 {
1004 struct device_node *child;
1005
1006
1007 for_each_child_of_node(dn, child) {
1008 pnv_php_unregister(child);
1009 pnv_php_unregister_one(child);
1010 }
1011 }
1012
1013 static int __init pnv_php_init(void)
1014 {
1015 struct device_node *dn;
1016
1017 pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
1018 for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
1019 pnv_php_register(dn);
1020
1021 for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
1022 pnv_php_register(dn);
1023
1024 for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
1025 pnv_php_register_one(dn);
1026 return 0;
1027 }
1028
1029 static void __exit pnv_php_exit(void)
1030 {
1031 struct device_node *dn;
1032
1033 for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
1034 pnv_php_unregister(dn);
1035
1036 for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
1037 pnv_php_unregister(dn);
1038
1039 for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
1040 pnv_php_unregister_one(dn);
1041 }
1042
1043 module_init(pnv_php_init);
1044 module_exit(pnv_php_exit);
1045
1046 MODULE_VERSION(DRIVER_VERSION);
1047 MODULE_LICENSE("GPL v2");
1048 MODULE_AUTHOR(DRIVER_AUTHOR);
1049 MODULE_DESCRIPTION(DRIVER_DESC);