aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 23:19:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 23:19:31 -0400
commit07021b43597f506cc525d139ed1a94e79cf184f2 (patch)
tree888ab33ec69b397ae6f8a2c82d14197047ee827e /drivers/pci/hotplug
parentd1f5323370fceaed43a7ee38f4c7bfc7e70f28d0 (diff)
parentb7b7013cac55d794940bd9cb7b7c55c9dececac4 (diff)
Merge tag 'powerpc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman: "Highlights: - Major rework of Book3S 64-bit exception vectors (Nicholas Piggin) - Use gas sections for arranging exception vectors et. al. - Large set of TM cleanups and selftests (Cyril Bur) - Enable transactional memory (TM) lazily for userspace (Cyril Bur) - Support for XZ compression in the zImage wrapper (Oliver O'Halloran) - Add support for bpf constant blinding (Naveen N. Rao) - Beginnings of upstream support for PA Semi Nemo motherboards (Darren Stevens) Fixes: - Ensure .mem(init|exit).text are within _stext/_etext (Michael Ellerman) - xmon: Don't use ld on 32-bit (Michael Ellerman) - vdso64: Use double word compare on pointers (Anton Blanchard) - powerpc/nvram: Fix an incorrect partition merge (Pan Xinhui) - powerpc: Fix usage of _PAGE_RO in hugepage (Christophe Leroy) - powerpc/mm: Update FORCE_MAX_ZONEORDER range to allow hugetlb w/4K (Aneesh Kumar K.V) - Fix memory leak in queue_hotplug_event() error path (Andrew Donnellan) - Replay hypervisor maintenance interrupt first (Nicholas Piggin) Various performance optimisations (Anton Blanchard): - Align hot loops of memset() and backwards_memcpy() - During context switch, check before setting mm_cpumask - Remove static branch prediction in atomic{, 64}_add_unless - Only disable HAVE_EFFICIENT_UNALIGNED_ACCESS on POWER7 little endian - Set default CPU type to POWER8 for little endian builds Cleanups & features: - Sparse fixes/cleanups (Daniel Axtens) - Preserve CFAR value on SLB miss caused by access to bogus address (Paul Mackerras) - Radix MMU fixups for POWER9 (Aneesh Kumar K.V) - Support for setting used_(vsr|vr|spe) in sigreturn path (for CRIU) (Simon Guo) - Optimise syscall entry for virtual, relocatable case (Nicholas Piggin) - Optimise MSR handling in exception handling (Nicholas Piggin) - Support for kexec with Radix MMU (Benjamin Herrenschmidt) - powernv EEH fixes (Russell Currey) - Suprise PCI hotplug support for powernv (Gavin Shan) - Endian/sparse fixes for powernv PCI (Gavin Shan) - Defconfig updates (Anton Blanchard) - KVM: PPC: Book3S HV: Migrate pinned pages out of CMA (Balbir Singh) - cxl: Flush PSL cache before resetting the adapter (Frederic Barrat) - cxl: replace loop with for_each_child_of_node(), remove unneeded of_node_put() (Andrew Donnellan) - Fix HV facility unavailable to use correct handler (Nicholas Piggin) - Remove unnecessary syscall trampoline (Nicholas Piggin) - fadump: Fix build break when CONFIG_PROC_VMCORE=n (Michael Ellerman) - Quieten EEH message when no adapters are found (Anton Blanchard) - powernv: Add PHB register dump debugfs handle (Russell Currey) - Use kprobe blacklist for exception handlers & asm functions (Nicholas Piggin) - Document the syscall ABI (Nicholas Piggin) - MAINTAINERS: Update cxl maintainers (Michael Neuling) - powerpc: Remove all usages of NO_IRQ (Michael Ellerman) Minor cleanups: - Andrew Donnellan, Christophe Leroy, Colin Ian King, Cyril Bur, Frederic Barrat, Pan Xinhui, PrasannaKumar Muralidharan, Rui Teng, Simon Guo" * tag 'powerpc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (156 commits) powerpc/bpf: Add support for bpf constant blinding powerpc/bpf: Implement support for tail calls powerpc/bpf: Introduce accessors for using the tmp local stack space powerpc/fadump: Fix build break when CONFIG_PROC_VMCORE=n powerpc: tm: Enable transactional memory (TM) lazily for userspace powerpc/tm: Add TM Unavailable Exception powerpc: Remove do_load_up_transact_{fpu,altivec} powerpc: tm: Rename transct_(*) to ck(\1)_state powerpc: tm: Always use fp_state and vr_state to store live registers selftests/powerpc: Add checks for transactional VSXs in signal contexts selftests/powerpc: Add checks for transactional VMXs in signal contexts selftests/powerpc: Add checks for transactional FPUs in signal contexts selftests/powerpc: Add checks for transactional GPRs in signal contexts selftests/powerpc: Check that signals always get delivered selftests/powerpc: Add TM tcheck helpers in C selftests/powerpc: Allow tests to extend their kill timeout selftests/powerpc: Introduce GPR asm helper header file selftests/powerpc: Move VMX stack frame macros to header file selftests/powerpc: Rework FPU stack placement macros and move to header file selftests/powerpc: Check for VSX preservation across userspace preemption ...
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/pnv_php.c283
1 files changed, 249 insertions, 34 deletions
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index e6245b03f0a1..56efaf72d08e 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -22,6 +22,12 @@
22#define DRIVER_AUTHOR "Gavin Shan, IBM Corporation" 22#define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
23#define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver" 23#define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver"
24 24
25struct pnv_php_event {
26 bool added;
27 struct pnv_php_slot *php_slot;
28 struct work_struct work;
29};
30
25static LIST_HEAD(pnv_php_slot_list); 31static LIST_HEAD(pnv_php_slot_list);
26static DEFINE_SPINLOCK(pnv_php_lock); 32static DEFINE_SPINLOCK(pnv_php_lock);
27 33
@@ -29,12 +35,40 @@ static void pnv_php_register(struct device_node *dn);
29static void pnv_php_unregister_one(struct device_node *dn); 35static void pnv_php_unregister_one(struct device_node *dn);
30static void pnv_php_unregister(struct device_node *dn); 36static void pnv_php_unregister(struct device_node *dn);
31 37
38static void pnv_php_disable_irq(struct pnv_php_slot *php_slot)
39{
40 struct pci_dev *pdev = php_slot->pdev;
41 u16 ctrl;
42
43 if (php_slot->irq > 0) {
44 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
45 ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
46 PCI_EXP_SLTCTL_PDCE |
47 PCI_EXP_SLTCTL_DLLSCE);
48 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
49
50 free_irq(php_slot->irq, php_slot);
51 php_slot->irq = 0;
52 }
53
54 if (php_slot->wq) {
55 destroy_workqueue(php_slot->wq);
56 php_slot->wq = NULL;
57 }
58
59 if (pdev->msix_enabled)
60 pci_disable_msix(pdev);
61 else if (pdev->msi_enabled)
62 pci_disable_msi(pdev);
63}
64
32static void pnv_php_free_slot(struct kref *kref) 65static void pnv_php_free_slot(struct kref *kref)
33{ 66{
34 struct pnv_php_slot *php_slot = container_of(kref, 67 struct pnv_php_slot *php_slot = container_of(kref,
35 struct pnv_php_slot, kref); 68 struct pnv_php_slot, kref);
36 69
37 WARN_ON(!list_empty(&php_slot->children)); 70 WARN_ON(!list_empty(&php_slot->children));
71 pnv_php_disable_irq(php_slot);
38 kfree(php_slot->name); 72 kfree(php_slot->name);
39 kfree(php_slot); 73 kfree(php_slot);
40} 74}
@@ -122,7 +156,7 @@ static void pnv_php_detach_device_nodes(struct device_node *parent)
122 156
123 of_node_put(dn); 157 of_node_put(dn);
124 refcount = atomic_read(&dn->kobj.kref.refcount); 158 refcount = atomic_read(&dn->kobj.kref.refcount);
125 if (unlikely(refcount != 1)) 159 if (refcount != 1)
126 pr_warn("Invalid refcount %d on <%s>\n", 160 pr_warn("Invalid refcount %d on <%s>\n",
127 refcount, of_node_full_name(dn)); 161 refcount, of_node_full_name(dn));
128 162
@@ -184,11 +218,11 @@ static int pnv_php_populate_changeset(struct of_changeset *ocs,
184 218
185 for_each_child_of_node(dn, child) { 219 for_each_child_of_node(dn, child) {
186 ret = of_changeset_attach_node(ocs, child); 220 ret = of_changeset_attach_node(ocs, child);
187 if (unlikely(ret)) 221 if (ret)
188 break; 222 break;
189 223
190 ret = pnv_php_populate_changeset(ocs, child); 224 ret = pnv_php_populate_changeset(ocs, child);
191 if (unlikely(ret)) 225 if (ret)
192 break; 226 break;
193 } 227 }
194 228
@@ -201,7 +235,7 @@ static void *pnv_php_add_one_pdn(struct device_node *dn, void *data)
201 struct pci_dn *pdn; 235 struct pci_dn *pdn;
202 236
203 pdn = pci_add_device_node_info(hose, dn); 237 pdn = pci_add_device_node_info(hose, dn);
204 if (unlikely(!pdn)) 238 if (!pdn)
205 return ERR_PTR(-ENOMEM); 239 return ERR_PTR(-ENOMEM);
206 240
207 return NULL; 241 return NULL;
@@ -224,21 +258,21 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
224 * fits the real size. 258 * fits the real size.
225 */ 259 */
226 fdt1 = kzalloc(0x10000, GFP_KERNEL); 260 fdt1 = kzalloc(0x10000, GFP_KERNEL);
227 if (unlikely(!fdt1)) { 261 if (!fdt1) {
228 ret = -ENOMEM; 262 ret = -ENOMEM;
229 dev_warn(&php_slot->pdev->dev, "Cannot alloc FDT blob\n"); 263 dev_warn(&php_slot->pdev->dev, "Cannot alloc FDT blob\n");
230 goto out; 264 goto out;
231 } 265 }
232 266
233 ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000); 267 ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
234 if (unlikely(ret)) { 268 if (ret) {
235 dev_warn(&php_slot->pdev->dev, "Error %d getting FDT blob\n", 269 dev_warn(&php_slot->pdev->dev, "Error %d getting FDT blob\n",
236 ret); 270 ret);
237 goto free_fdt1; 271 goto free_fdt1;
238 } 272 }
239 273
240 fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL); 274 fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
241 if (unlikely(!fdt)) { 275 if (!fdt) {
242 ret = -ENOMEM; 276 ret = -ENOMEM;
243 dev_warn(&php_slot->pdev->dev, "Cannot %d bytes memory\n", 277 dev_warn(&php_slot->pdev->dev, "Cannot %d bytes memory\n",
244 fdt_totalsize(fdt1)); 278 fdt_totalsize(fdt1));
@@ -248,7 +282,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
248 /* Unflatten device tree blob */ 282 /* Unflatten device tree blob */
249 memcpy(fdt, fdt1, fdt_totalsize(fdt1)); 283 memcpy(fdt, fdt1, fdt_totalsize(fdt1));
250 dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL); 284 dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
251 if (unlikely(!dt)) { 285 if (!dt) {
252 ret = -EINVAL; 286 ret = -EINVAL;
253 dev_warn(&php_slot->pdev->dev, "Cannot unflatten FDT\n"); 287 dev_warn(&php_slot->pdev->dev, "Cannot unflatten FDT\n");
254 goto free_fdt; 288 goto free_fdt;
@@ -258,7 +292,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
258 of_changeset_init(&php_slot->ocs); 292 of_changeset_init(&php_slot->ocs);
259 pnv_php_reverse_nodes(php_slot->dn); 293 pnv_php_reverse_nodes(php_slot->dn);
260 ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn); 294 ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
261 if (unlikely(ret)) { 295 if (ret) {
262 pnv_php_reverse_nodes(php_slot->dn); 296 pnv_php_reverse_nodes(php_slot->dn);
263 dev_warn(&php_slot->pdev->dev, "Error %d populating changeset\n", 297 dev_warn(&php_slot->pdev->dev, "Error %d populating changeset\n",
264 ret); 298 ret);
@@ -267,7 +301,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
267 301
268 php_slot->dn->child = NULL; 302 php_slot->dn->child = NULL;
269 ret = of_changeset_apply(&php_slot->ocs); 303 ret = of_changeset_apply(&php_slot->ocs);
270 if (unlikely(ret)) { 304 if (ret) {
271 dev_warn(&php_slot->pdev->dev, "Error %d applying changeset\n", 305 dev_warn(&php_slot->pdev->dev, "Error %d applying changeset\n",
272 ret); 306 ret);
273 goto destroy_changeset; 307 goto destroy_changeset;
@@ -301,7 +335,7 @@ int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
301 int ret; 335 int ret;
302 336
303 ret = pnv_pci_set_power_state(php_slot->id, state, &msg); 337 ret = pnv_pci_set_power_state(php_slot->id, state, &msg);
304 if (likely(ret > 0)) { 338 if (ret > 0) {
305 if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle || 339 if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle ||
306 be64_to_cpu(msg.params[2]) != state || 340 be64_to_cpu(msg.params[2]) != state ||
307 be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) { 341 be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
@@ -311,7 +345,7 @@ int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
311 be64_to_cpu(msg.params[3])); 345 be64_to_cpu(msg.params[3]));
312 return -ENOMSG; 346 return -ENOMSG;
313 } 347 }
314 } else if (unlikely(ret < 0)) { 348 } else if (ret < 0) {
315 dev_warn(&php_slot->pdev->dev, "Error %d powering %s\n", 349 dev_warn(&php_slot->pdev->dev, "Error %d powering %s\n",
316 ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off"); 350 ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
317 return ret; 351 return ret;
@@ -338,7 +372,7 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
338 * be on. 372 * be on.
339 */ 373 */
340 ret = pnv_pci_get_power_state(php_slot->id, &power_state); 374 ret = pnv_pci_get_power_state(php_slot->id, &power_state);
341 if (unlikely(ret)) { 375 if (ret) {
342 dev_warn(&php_slot->pdev->dev, "Error %d getting power status\n", 376 dev_warn(&php_slot->pdev->dev, "Error %d getting power status\n",
343 ret); 377 ret);
344 } else { 378 } else {
@@ -360,7 +394,7 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
360 * get that, it will fail back to be empty. 394 * get that, it will fail back to be empty.
361 */ 395 */
362 ret = pnv_pci_get_presence_state(php_slot->id, &presence); 396 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
363 if (likely(ret >= 0)) { 397 if (ret >= 0) {
364 *state = presence; 398 *state = presence;
365 slot->info->adapter_status = presence; 399 slot->info->adapter_status = presence;
366 ret = 0; 400 ret = 0;
@@ -393,7 +427,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
393 427
394 /* Retrieve slot presence status */ 428 /* Retrieve slot presence status */
395 ret = pnv_php_get_adapter_state(slot, &presence); 429 ret = pnv_php_get_adapter_state(slot, &presence);
396 if (unlikely(ret)) 430 if (ret)
397 return ret; 431 return ret;
398 432
399 /* Proceed if there have nothing behind the slot */ 433 /* Proceed if there have nothing behind the slot */
@@ -414,7 +448,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
414 php_slot->power_state_check = true; 448 php_slot->power_state_check = true;
415 449
416 ret = pnv_php_get_power_state(slot, &power_status); 450 ret = pnv_php_get_power_state(slot, &power_status);
417 if (unlikely(ret)) 451 if (ret)
418 return ret; 452 return ret;
419 453
420 if (power_status != OPAL_PCI_SLOT_POWER_ON) 454 if (power_status != OPAL_PCI_SLOT_POWER_ON)
@@ -423,7 +457,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
423 457
424 /* Check the power status. Scan the slot if it is already on */ 458 /* Check the power status. Scan the slot if it is already on */
425 ret = pnv_php_get_power_state(slot, &power_status); 459 ret = pnv_php_get_power_state(slot, &power_status);
426 if (unlikely(ret)) 460 if (ret)
427 return ret; 461 return ret;
428 462
429 if (power_status == OPAL_PCI_SLOT_POWER_ON) 463 if (power_status == OPAL_PCI_SLOT_POWER_ON)
@@ -431,7 +465,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
431 465
432 /* Power is off, turn it on and then scan the slot */ 466 /* Power is off, turn it on and then scan the slot */
433 ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON); 467 ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
434 if (unlikely(ret)) 468 if (ret)
435 return ret; 469 return ret;
436 470
437scan: 471scan:
@@ -513,29 +547,30 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
513 struct pci_bus *bus; 547 struct pci_bus *bus;
514 const char *label; 548 const char *label;
515 uint64_t id; 549 uint64_t id;
550 int ret;
516 551
517 label = of_get_property(dn, "ibm,slot-label", NULL); 552 ret = of_property_read_string(dn, "ibm,slot-label", &label);
518 if (unlikely(!label)) 553 if (ret)
519 return NULL; 554 return NULL;
520 555
521 if (pnv_pci_get_slot_id(dn, &id)) 556 if (pnv_pci_get_slot_id(dn, &id))
522 return NULL; 557 return NULL;
523 558
524 bus = pci_find_bus_by_node(dn); 559 bus = pci_find_bus_by_node(dn);
525 if (unlikely(!bus)) 560 if (!bus)
526 return NULL; 561 return NULL;
527 562
528 php_slot = kzalloc(sizeof(*php_slot), GFP_KERNEL); 563 php_slot = kzalloc(sizeof(*php_slot), GFP_KERNEL);
529 if (unlikely(!php_slot)) 564 if (!php_slot)
530 return NULL; 565 return NULL;
531 566
532 php_slot->name = kstrdup(label, GFP_KERNEL); 567 php_slot->name = kstrdup(label, GFP_KERNEL);
533 if (unlikely(!php_slot->name)) { 568 if (!php_slot->name) {
534 kfree(php_slot); 569 kfree(php_slot);
535 return NULL; 570 return NULL;
536 } 571 }
537 572
538 if (likely(dn->child && PCI_DN(dn->child))) 573 if (dn->child && PCI_DN(dn->child))
539 php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn); 574 php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
540 else 575 else
541 php_slot->slot_no = -1; /* Placeholder slot */ 576 php_slot->slot_no = -1; /* Placeholder slot */
@@ -567,7 +602,7 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
567 602
568 /* Check if the slot is registered or not */ 603 /* Check if the slot is registered or not */
569 parent = pnv_php_find_slot(php_slot->dn); 604 parent = pnv_php_find_slot(php_slot->dn);
570 if (unlikely(parent)) { 605 if (parent) {
571 pnv_php_put_slot(parent); 606 pnv_php_put_slot(parent);
572 return -EEXIST; 607 return -EEXIST;
573 } 608 }
@@ -575,7 +610,7 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
575 /* Register PCI slot */ 610 /* Register PCI slot */
576 ret = pci_hp_register(&php_slot->slot, php_slot->bus, 611 ret = pci_hp_register(&php_slot->slot, php_slot->bus,
577 php_slot->slot_no, php_slot->name); 612 php_slot->slot_no, php_slot->name);
578 if (unlikely(ret)) { 613 if (ret) {
579 dev_warn(&php_slot->pdev->dev, "Error %d registering slot\n", 614 dev_warn(&php_slot->pdev->dev, "Error %d registering slot\n",
580 ret); 615 ret);
581 return ret; 616 return ret;
@@ -609,33 +644,213 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
609 return 0; 644 return 0;
610} 645}
611 646
647static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
648{
649 struct pci_dev *pdev = php_slot->pdev;
650 struct msix_entry entry;
651 int nr_entries, ret;
652 u16 pcie_flag;
653
654 /* Get total number of MSIx entries */
655 nr_entries = pci_msix_vec_count(pdev);
656 if (nr_entries < 0)
657 return nr_entries;
658
659 /* Check hotplug MSIx entry is in range */
660 pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
661 entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9;
662 if (entry.entry >= nr_entries)
663 return -ERANGE;
664
665 /* Enable MSIx */
666 ret = pci_enable_msix_exact(pdev, &entry, 1);
667 if (ret) {
668 dev_warn(&pdev->dev, "Error %d enabling MSIx\n", ret);
669 return ret;
670 }
671
672 return entry.vector;
673}
674
675static void pnv_php_event_handler(struct work_struct *work)
676{
677 struct pnv_php_event *event =
678 container_of(work, struct pnv_php_event, work);
679 struct pnv_php_slot *php_slot = event->php_slot;
680
681 if (event->added)
682 pnv_php_enable_slot(&php_slot->slot);
683 else
684 pnv_php_disable_slot(&php_slot->slot);
685
686 kfree(event);
687}
688
689static irqreturn_t pnv_php_interrupt(int irq, void *data)
690{
691 struct pnv_php_slot *php_slot = data;
692 struct pci_dev *pchild, *pdev = php_slot->pdev;
693 struct eeh_dev *edev;
694 struct eeh_pe *pe;
695 struct pnv_php_event *event;
696 u16 sts, lsts;
697 u8 presence;
698 bool added;
699 unsigned long flags;
700 int ret;
701
702 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
703 sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
704 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
705 if (sts & PCI_EXP_SLTSTA_DLLSC) {
706 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
707 added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
708 } else if (sts & PCI_EXP_SLTSTA_PDC) {
709 ret = pnv_pci_get_presence_state(php_slot->id, &presence);
710 if (!ret)
711 return IRQ_HANDLED;
712 added = !!(presence == OPAL_PCI_SLOT_PRESENT);
713 } else {
714 return IRQ_NONE;
715 }
716
717 /* Freeze the removed PE to avoid unexpected error reporting */
718 if (!added) {
719 pchild = list_first_entry_or_null(&php_slot->bus->devices,
720 struct pci_dev, bus_list);
721 edev = pchild ? pci_dev_to_eeh_dev(pchild) : NULL;
722 pe = edev ? edev->pe : NULL;
723 if (pe) {
724 eeh_serialize_lock(&flags);
725 eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
726 eeh_serialize_unlock(flags);
727 eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
728 }
729 }
730
731 /*
732 * The PE is left in frozen state if the event is missed. It's
733 * fine as the PCI devices (PE) aren't functional any more.
734 */
735 event = kzalloc(sizeof(*event), GFP_ATOMIC);
736 if (!event) {
737 dev_warn(&pdev->dev, "PCI slot [%s] missed hotplug event 0x%04x\n",
738 php_slot->name, sts);
739 return IRQ_HANDLED;
740 }
741
742 dev_info(&pdev->dev, "PCI slot [%s] %s (IRQ: %d)\n",
743 php_slot->name, added ? "added" : "removed", irq);
744 INIT_WORK(&event->work, pnv_php_event_handler);
745 event->added = added;
746 event->php_slot = php_slot;
747 queue_work(php_slot->wq, &event->work);
748
749 return IRQ_HANDLED;
750}
751
752static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
753{
754 struct pci_dev *pdev = php_slot->pdev;
755 u16 sts, ctrl;
756 int ret;
757
758 /* Allocate workqueue */
759 php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
760 if (!php_slot->wq) {
761 dev_warn(&pdev->dev, "Cannot alloc workqueue\n");
762 pnv_php_disable_irq(php_slot);
763 return;
764 }
765
766 /* Clear pending interrupts */
767 pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
768 sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
769 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
770
771 /* Request the interrupt */
772 ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
773 php_slot->name, php_slot);
774 if (ret) {
775 pnv_php_disable_irq(php_slot);
776 dev_warn(&pdev->dev, "Error %d enabling IRQ %d\n", ret, irq);
777 return;
778 }
779
780 /* Enable the interrupts */
781 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
782 ctrl |= (PCI_EXP_SLTCTL_HPIE |
783 PCI_EXP_SLTCTL_PDCE |
784 PCI_EXP_SLTCTL_DLLSCE);
785 pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
786
787 /* The interrupt is initialized successfully when @irq is valid */
788 php_slot->irq = irq;
789}
790
791static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
792{
793 struct pci_dev *pdev = php_slot->pdev;
794 int irq, ret;
795
796 ret = pci_enable_device(pdev);
797 if (ret) {
798 dev_warn(&pdev->dev, "Error %d enabling device\n", ret);
799 return;
800 }
801
802 pci_set_master(pdev);
803
804 /* Enable MSIx interrupt */
805 irq = pnv_php_enable_msix(php_slot);
806 if (irq > 0) {
807 pnv_php_init_irq(php_slot, irq);
808 return;
809 }
810
811 /*
812 * Use MSI if MSIx doesn't work. Fail back to legacy INTx
813 * if MSI doesn't work either
814 */
815 ret = pci_enable_msi(pdev);
816 if (!ret || pdev->irq) {
817 irq = pdev->irq;
818 pnv_php_init_irq(php_slot, irq);
819 }
820}
821
612static int pnv_php_register_one(struct device_node *dn) 822static int pnv_php_register_one(struct device_node *dn)
613{ 823{
614 struct pnv_php_slot *php_slot; 824 struct pnv_php_slot *php_slot;
615 const __be32 *prop32; 825 u32 prop32;
616 int ret; 826 int ret;
617 827
618 /* Check if it's hotpluggable slot */ 828 /* Check if it's hotpluggable slot */
619 prop32 = of_get_property(dn, "ibm,slot-pluggable", NULL); 829 ret = of_property_read_u32(dn, "ibm,slot-pluggable", &prop32);
620 if (!prop32 || !of_read_number(prop32, 1)) 830 if (ret || !prop32)
621 return -ENXIO; 831 return -ENXIO;
622 832
623 prop32 = of_get_property(dn, "ibm,reset-by-firmware", NULL); 833 ret = of_property_read_u32(dn, "ibm,reset-by-firmware", &prop32);
624 if (!prop32 || !of_read_number(prop32, 1)) 834 if (ret || !prop32)
625 return -ENXIO; 835 return -ENXIO;
626 836
627 php_slot = pnv_php_alloc_slot(dn); 837 php_slot = pnv_php_alloc_slot(dn);
628 if (unlikely(!php_slot)) 838 if (!php_slot)
629 return -ENODEV; 839 return -ENODEV;
630 840
631 ret = pnv_php_register_slot(php_slot); 841 ret = pnv_php_register_slot(php_slot);
632 if (unlikely(ret)) 842 if (ret)
633 goto free_slot; 843 goto free_slot;
634 844
635 ret = pnv_php_enable(php_slot, false); 845 ret = pnv_php_enable(php_slot, false);
636 if (unlikely(ret)) 846 if (ret)
637 goto unregister_slot; 847 goto unregister_slot;
638 848
849 /* Enable interrupt if the slot supports surprise hotplug */
850 ret = of_property_read_u32(dn, "ibm,slot-surprise-pluggable", &prop32);
851 if (!ret && prop32)
852 pnv_php_enable_irq(php_slot);
853
639 return 0; 854 return 0;
640 855
641unregister_slot: 856unregister_slot: