diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv')
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-powernv.c | 86 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal-irqchip.c | 66 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/setup.c | 21 |
4 files changed, 88 insertions, 87 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 3bb6acb76..e1c907255 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -43,17 +43,11 @@ static bool pnv_eeh_nb_init = false; static int eeh_event_irq = -EINVAL; -/** - * pnv_eeh_init - EEH platform dependent initialization - * - * EEH platform dependent initialization on powernv - */ static int pnv_eeh_init(void) { struct pci_controller *hose; struct pnv_phb *phb; - /* We require OPALv3 */ if (!firmware_has_feature(FW_FEATURE_OPALv3)) { pr_warn("%s: OPALv3 is required !\n", __func__); @@ -77,9 +71,9 @@ static int pnv_eeh_init(void) /* * PE#0 should be regarded as valid by EEH core * if it's not the reserved one. Currently, we - * have the reserved PE#0 and PE#127 for PHB3 + * have the reserved PE#255 and PE#127 for PHB3 * and P7IOC separately. So we should regard - * PE#0 as valid for P7IOC. + * PE#0 as valid for PHB3 and P7IOC. */ if (phb->ioda.reserved_pe != 0) eeh_add_flag(EEH_VALID_PE_ZERO); @@ -284,33 +278,23 @@ static int pnv_eeh_post_init(void) #endif /* CONFIG_DEBUG_FS */ } - return ret; } -static int pnv_eeh_cap_start(struct pci_dn *pdn) +static int pnv_eeh_find_cap(struct pci_dn *pdn, int cap) { - u32 status; + int pos = PCI_CAPABILITY_LIST; + int cnt = 48; /* Maximal number of capabilities */ + u32 status, id; if (!pdn) return 0; + /* Check if the device supports capabilities */ pnv_pci_cfg_read(pdn, PCI_STATUS, 2, &status); if (!(status & PCI_STATUS_CAP_LIST)) return 0; - return PCI_CAPABILITY_LIST; -} - -static int pnv_eeh_find_cap(struct pci_dn *pdn, int cap) -{ - int pos = pnv_eeh_cap_start(pdn); - int cnt = 48; /* Maximal number of capabilities */ - u32 id; - - if (!pos) - return 0; - while (cnt--) { pnv_pci_cfg_read(pdn, pos, 1, &pos); if (pos < 0x40) @@ -443,11 +427,14 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) * that PE to block its config space. * * Broadcom Austin 4-ports NICs (14e4:1657) + * Broadcom Shiner 4-ports 1G NICs (14e4:168a) * Broadcom Shiner 2-ports 10G NICs (14e4:168e) */ if ((pdn->vendor_id == PCI_VENDOR_ID_BROADCOM && pdn->device_id == 0x1657) || (pdn->vendor_id == PCI_VENDOR_ID_BROADCOM && + pdn->device_id == 0x168a) || + (pdn->vendor_id == PCI_VENDOR_ID_BROADCOM && pdn->device_id == 0x168e)) edev->pe->state |= EEH_PE_CFG_RESTRICTED; @@ -487,10 +474,9 @@ static int pnv_eeh_set_option(struct eeh_pe *pe, int option) struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; bool freeze_pe = false; - int opt, ret = 0; + int opt; s64 rc; - /* Sanity check on option */ switch (option) { case EEH_OPT_DISABLE: return -EPERM; @@ -511,38 +497,37 @@ static int pnv_eeh_set_option(struct eeh_pe *pe, int option) return -EINVAL; } - /* If PHB supports compound PE, to handle it */ + /* Freeze master and slave PEs if PHB supports compound PEs */ if (freeze_pe) { if (phb->freeze_pe) { phb->freeze_pe(phb, pe->addr); - } else { - rc = opal_pci_eeh_freeze_set(phb->opal_id, - pe->addr, opt); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld freezing " - "PHB#%x-PE#%x\n", - __func__, rc, - phb->hose->global_number, pe->addr); - ret = -EIO; - } + return 0; } - } else { - if (phb->unfreeze_pe) { - ret = phb->unfreeze_pe(phb, pe->addr, opt); - } else { - rc = opal_pci_eeh_freeze_clear(phb->opal_id, - pe->addr, opt); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld enable %d " - "for PHB#%x-PE#%x\n", - __func__, rc, option, - phb->hose->global_number, pe->addr); - ret = -EIO; - } + + rc = opal_pci_eeh_freeze_set(phb->opal_id, pe->addr, opt); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n", + __func__, rc, phb->hose->global_number, + pe->addr); + return -EIO; } + + return 0; } - return ret; + /* Unfreeze master and slave PEs if PHB supports */ + if (phb->unfreeze_pe) + return phb->unfreeze_pe(phb, pe->addr, opt); + + rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe->addr, opt); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n", + __func__, rc, option, phb->hose->global_number, + pe->addr); + return -EIO; + } + + return 0; } /** @@ -1065,7 +1050,6 @@ static int pnv_eeh_err_inject(struct eeh_pe *pe, int type, int func, struct pnv_phb *phb = hose->private_data; s64 rc; - /* Sanity check on error type */ if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR && type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) { pr_warn("%s: Invalid error type %d\n", diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index 2c91ee780..e505223b4 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -43,11 +43,34 @@ static unsigned int opal_irq_count; static unsigned int *opal_irqs; static void opal_handle_irq_work(struct irq_work *work); -static __be64 last_outstanding_events; +static u64 last_outstanding_events; static struct irq_work opal_event_irq_work = { .func = opal_handle_irq_work, }; +void opal_handle_events(uint64_t events) +{ + int virq, hwirq = 0; + u64 mask = opal_event_irqchip.mask; + + if (!in_irq() && (events & mask)) { + last_outstanding_events = events; + irq_work_queue(&opal_event_irq_work); + return; + } + + while (events & mask) { + hwirq = fls64(events) - 1; + if (BIT_ULL(hwirq) & mask) { + virq = irq_find_mapping(opal_event_irqchip.domain, + hwirq); + if (virq) + generic_handle_irq(virq); + } + events &= ~BIT_ULL(hwirq); + } +} + static void opal_event_mask(struct irq_data *d) { clear_bit(d->hwirq, &opal_event_irqchip.mask); @@ -55,9 +78,21 @@ static void opal_event_mask(struct irq_data *d) static void opal_event_unmask(struct irq_data *d) { + __be64 events; + set_bit(d->hwirq, &opal_event_irqchip.mask); - opal_poll_events(&last_outstanding_events); + opal_poll_events(&events); + last_outstanding_events = be64_to_cpu(events); + + /* + * We can't just handle the events now with opal_handle_events(). + * If we did we would deadlock when opal_event_unmask() is called from + * handle_level_irq() with the irq descriptor lock held, because + * calling opal_handle_events() would call generic_handle_irq() and + * then handle_level_irq() which would try to take the descriptor lock + * again. Instead queue the events for later. + */ if (last_outstanding_events & opal_event_irqchip.mask) /* Need to retrigger the interrupt */ irq_work_queue(&opal_event_irq_work); @@ -96,29 +131,6 @@ static int opal_event_map(struct irq_domain *d, unsigned int irq, return 0; } -void opal_handle_events(uint64_t events) -{ - int virq, hwirq = 0; - u64 mask = opal_event_irqchip.mask; - - if (!in_irq() && (events & mask)) { - last_outstanding_events = events; - irq_work_queue(&opal_event_irq_work); - return; - } - - while (events & mask) { - hwirq = fls64(events) - 1; - if (BIT_ULL(hwirq) & mask) { - virq = irq_find_mapping(opal_event_irqchip.domain, - hwirq); - if (virq) - generic_handle_irq(virq); - } - events &= ~BIT_ULL(hwirq); - } -} - static irqreturn_t opal_interrupt(int irq, void *data) { __be64 events; @@ -131,13 +143,13 @@ static irqreturn_t opal_interrupt(int irq, void *data) static void opal_handle_irq_work(struct irq_work *work) { - opal_handle_events(be64_to_cpu(last_outstanding_events)); + opal_handle_events(last_outstanding_events); } static int opal_event_match(struct irq_domain *h, struct device_node *node, enum irq_domain_bus_token bus_token) { - return h->of_node == node; + return irq_domain_get_of_node(h) == node; } static int opal_event_xlate(struct irq_domain *h, struct device_node *np, diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 4296d55e8..57cffb80b 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -278,7 +278,7 @@ static void opal_handle_message(void) /* Sanity check */ if (type >= OPAL_MSG_TYPE_MAX) { - pr_warning("%s: Unknown message type: %u\n", __func__, type); + pr_warn_once("%s: Unknown message type: %u\n", __func__, type); return; } opal_message_do_notify(type, (void *)&msg); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 685b3cbe1..a9a8fa37a 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -187,7 +187,7 @@ static void pnv_kexec_wait_secondaries_down(void) for_each_online_cpu(i) { uint8_t status; - int64_t rc; + int64_t rc, timeout = 1000; if (i == my_cpu) continue; @@ -204,6 +204,18 @@ static void pnv_kexec_wait_secondaries_down(void) i, paca[i].hw_cpu_id); notified = i; } + + /* + * On crash secondaries might be unreachable or hung, + * so timeout if we've waited too long + * */ + mdelay(1); + if (timeout-- == 0) { + printk(KERN_ERR "kexec: timed out waiting for " + "cpu %d (physical %d) to enter OPAL\n", + i, paca[i].hw_cpu_id); + break; + } } } } @@ -225,13 +237,6 @@ static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) /* Return the CPU to OPAL */ opal_return_cpu(); - } else if (crash_shutdown) { - /* - * On crash, we don't wait for secondaries to go - * down as they might be unreachable or hung, so - * instead we just wait a bit and move on. - */ - mdelay(1); } else { /* Primary waits for the secondaries to have reached OPAL */ pnv_kexec_wait_secondaries_down(); |