diff options
Diffstat (limited to 'hw/npu.c')
-rw-r--r-- | hw/npu.c | 202 |
1 files changed, 131 insertions, 71 deletions
@@ -18,6 +18,7 @@ #include <timebase.h> #include <pci.h> #include <pci-cfg.h> +#include <pci-slot.h> #include <interrupts.h> #include <opal.h> #include <opal-api.h> @@ -28,7 +29,6 @@ #include <affinity.h> #include <npu-regs.h> #include <npu.h> -#include <lock.h> #include <xscom.h> /* @@ -197,20 +197,6 @@ static uint64_t get_bar_size(uint64_t bar) return (1 << GETFIELD(NX_MMIO_BAR_SIZE, bar)) * 0x10000; } -static void npu_lock(struct phb *phb) -{ - struct npu *p = phb_to_npu(phb); - - lock(&p->lock); -} - -static void npu_unlock(struct phb *phb) -{ - struct npu *p = phb_to_npu(phb); - - unlock(&p->lock); -} - /* Update the changes of the device BAR to link BARs */ static void npu_dev_bar_update(uint32_t gcid, struct npu_dev_bar *bar, bool enable) @@ -556,7 +542,7 @@ static void npu_dev_bind_pci_dev(struct npu_dev *dev) if (!phb) continue; - dev->pd = pci_walk_dev(phb, __npu_dev_bind_pci_dev, dev); + dev->pd = pci_walk_dev(phb, NULL, __npu_dev_bind_pci_dev, dev); if (dev->pd) { dev->phb = phb; /* Found the device, set the bit in config space */ @@ -566,6 +552,11 @@ static void npu_dev_bind_pci_dev(struct npu_dev *dev) } } + /** + * @fwts-label NPUNotBound + * @fwts-advice Start debugging why we didn't find the right device. + * End result is that NVLink will not function properly + */ prlog(PR_ERR, "%s: NPU device %04x:00:%02x.0 not binding to PCI device\n", __func__, dev->npu->phb.opal_id, dev->index); } @@ -600,7 +591,9 @@ static void npu_append_pci_phandle(struct dt_node *dn, u32 phandle) unlock(&pci_npu_phandle_lock); } -static void npu_dn_fixup(struct phb *phb, struct pci_device *pd) +static int npu_dn_fixup(struct phb *phb, + struct pci_device *pd, + void *data __unused) { struct npu *p = phb_to_npu(phb); struct npu_dev *dev; @@ -609,7 +602,7 @@ static void npu_dn_fixup(struct phb *phb, struct pci_device *pd) assert(dev); if (dev->phb || dev->pd) - return; + return 0; /* Bind the emulated PCI device with the real one, which can't * be done until the PCI devices are populated. Once the real @@ -625,6 +618,13 @@ static void npu_dn_fixup(struct phb *phb, struct pci_device *pd) dt_add_property_cells(pd->dn, "ibm,gpu", dev->pd->dn->phandle); } + + return 0; +} + +static void npu_phb_final_fixup(struct phb *phb) +{ + pci_walk_dev(phb, NULL, npu_dn_fixup, NULL); } static void npu_ioda_init(struct npu *p) @@ -688,19 +688,22 @@ static int npu_isn_valid(struct npu *p, uint32_t isn) if (p->chip_id != p8_irq_to_chip(isn) || p->index != 0 || NPU_IRQ_NUM(isn) < NPU_LSI_IRQ_MIN || NPU_IRQ_NUM(isn) > NPU_LSI_IRQ_MAX) { - NPUERR(p, "isn 0x%x not valid for this NPU\n", isn); + /** + * @fwts-label NPUisnInvalid + * @fwts-advice NVLink not functional + */ + prlog(PR_ERR, "NPU%d: isn 0x%x not valid for this NPU\n", + p->phb.opal_id, isn); return false; } return true; } -static int64_t npu_lsi_get_xive(void *data, - uint32_t isn, - uint16_t *server, - uint8_t *prio) +static int64_t npu_lsi_get_xive(struct irq_source *is, uint32_t isn, + uint16_t *server, uint8_t *prio) { - struct npu *p = data; + struct npu *p = is->data; uint32_t irq = NPU_IRQ_NUM(isn); uint64_t lxive; @@ -719,12 +722,10 @@ static int64_t npu_lsi_get_xive(void *data, return OPAL_SUCCESS; } -static int64_t npu_lsi_set_xive(void *data, - uint32_t isn, - uint16_t server, - uint8_t prio) +static int64_t npu_lsi_set_xive(struct irq_source *is, uint32_t isn, + uint16_t server, uint8_t prio) { - struct npu *p = data; + struct npu *p = is->data; uint32_t irq = NPU_IRQ_NUM(isn); uint64_t lxive; @@ -749,9 +750,9 @@ static int64_t npu_lsi_set_xive(void *data, return OPAL_SUCCESS; } -static void npu_err_interrupt(void *data, uint32_t isn) +static void npu_err_interrupt(struct irq_source *is, uint32_t isn) { - struct npu *p = data; + struct npu *p = is->data; uint32_t irq = NPU_IRQ_NUM(isn); if (!npu_isn_valid(p, isn)) @@ -978,27 +979,29 @@ static int64_t npu_set_pe(struct phb *phb, return OPAL_SUCCESS; } -static int64_t npu_link_state(struct phb *phb __unused) +static int64_t npu_get_link_state(struct pci_slot *slot __unused, uint8_t *val) { /* As we're emulating all PCI stuff, the link bandwidth * isn't big deal anyway. */ - return OPAL_SHPC_LINK_UP_x1; + *val = OPAL_SHPC_LINK_UP_x1; + return OPAL_SUCCESS; } -static int64_t npu_power_state(struct phb *phb __unused) +static int64_t npu_get_power_state(struct pci_slot *slot __unused, uint8_t *val) { - return OPAL_SHPC_POWER_ON; + *val = PCI_SLOT_POWER_ON; + return OPAL_SUCCESS; } -static int64_t npu_hreset(struct phb *phb __unused) +static int64_t npu_hreset(struct pci_slot *slot __unused) { prlog(PR_DEBUG, "NPU: driver should call reset procedure here\n"); return OPAL_SUCCESS; } -static int64_t npu_freset(struct phb *phb __unused) +static int64_t npu_freset(struct pci_slot *slot __unused) { /* FIXME: PHB fundamental reset, which need to be * figured out later. It's used by EEH recovery @@ -1007,6 +1010,33 @@ static int64_t npu_freset(struct phb *phb __unused) return OPAL_SUCCESS; } +static struct pci_slot *npu_slot_create(struct phb *phb) +{ + struct pci_slot *slot; + + slot = pci_slot_alloc(phb, NULL); + if (!slot) + return slot; + + /* Elementary functions */ + slot->ops.get_presence_state = NULL; + slot->ops.get_link_state = npu_get_link_state; + slot->ops.get_power_state = npu_get_power_state; + slot->ops.get_attention_state = NULL; + slot->ops.get_latch_state = NULL; + slot->ops.set_power_state = NULL; + slot->ops.set_attention_state = NULL; + + slot->ops.prepare_link_change = NULL; + slot->ops.poll_link = NULL; + slot->ops.hreset = npu_hreset; + slot->ops.freset = npu_freset; + slot->ops.pfreset = NULL; + slot->ops.creset = NULL; + + return slot; +} + static int64_t npu_freeze_status(struct phb *phb, uint64_t pe_number __unused, uint8_t *freeze_state, @@ -1059,6 +1089,17 @@ static int64_t npu_eeh_next_error(struct phb *phb, return OPAL_SUCCESS; } +/* For use in error injection and handling. */ +void npu_set_fence_state(struct npu *p, bool fence) { + p->fenced = fence; + + if (fence) + prlog(PR_ERR, "NPU: Chip %x is fenced, reboot required.\n", + p->chip_id); + else + prlog(PR_WARNING, "NPU: un-fencing is dangerous and should \ + only be used for development purposes."); +} /* Sets the NPU to trigger an error when a DMA occurs */ static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num, @@ -1092,9 +1133,12 @@ static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num, return OPAL_PARAMETER; } else if (type == 1) { /* Emulate fence mode. */ - p->fenced = true; + npu_set_fence_state(p, true); } else { - /* Cause a freeze with an invalid MMIO write. */ + /* Cause a freeze with an invalid MMIO read. If the BAR is not + * enabled, this will checkstop the machine. + */ + npu_dev_bar_update(p->chip_id, &dev->bar, true); in_be64((void *)dev->bar.base); } @@ -1102,8 +1146,6 @@ static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num, } static const struct phb_ops npu_ops = { - .lock = npu_lock, - .unlock = npu_unlock, .cfg_read8 = npu_dev_cfg_read8, .cfg_read16 = npu_dev_cfg_read16, .cfg_read32 = npu_dev_cfg_read32, @@ -1111,9 +1153,9 @@ static const struct phb_ops npu_ops = { .cfg_write16 = npu_dev_cfg_write16, .cfg_write32 = npu_dev_cfg_write32, .choose_bus = NULL, + .get_reserved_pe_number = NULL, .device_init = NULL, - .device_node_fixup = npu_dn_fixup, - .presence_detect = NULL, + .phb_final_fixup = npu_phb_final_fixup, .ioda_reset = npu_ioda_reset, .papr_errinjct_reset = NULL, .pci_reinit = NULL, @@ -1128,14 +1170,6 @@ static const struct phb_ops npu_ops = { .get_msi_64 = NULL, .set_pe = npu_set_pe, .set_peltv = NULL, - .link_state = npu_link_state, - .power_state = npu_power_state, - .slot_power_off = NULL, - .slot_power_on = NULL, - .hot_reset = npu_hreset, - .fundamental_reset = npu_freset, - .complete_reset = NULL, - .poll = NULL, .eeh_freeze_status = npu_freeze_status, .eeh_freeze_clear = NULL, .eeh_freeze_set = NULL, @@ -1262,6 +1296,10 @@ static void npu_probe_phb(struct dt_node *dn) xscom_read(gcid, npu_link_scom_base(dn, xscom, 1) + NX_MMIO_BAR_1, &val); if (!(val & NX_MMIO_BAR_ENABLE)) { + /** + * @fwts-label NPUATBARDisabled + * @fwts-advice NVLink not functional + */ prlog(PR_ERR, " AT BAR disabled!\n"); return; } @@ -1274,6 +1312,12 @@ static void npu_probe_phb(struct dt_node *dn) /* Create PCI root device node */ np = dt_new_addr(dt_root, "pciex", at_bar[0]); if (!np) { + /** + * @fwts-label NPUPHBDeviceNodeFailure + * @fwts-advice Error adding the PHB device node. The + * only real reason for this is that firmware may have + * run out of memory. + */ prlog(PR_ERR, "%s: Cannot create PHB device node\n", __func__); return; @@ -1496,7 +1540,7 @@ static void npu_dev_create_cfg(struct npu_dev *dev) /* 0x10 - BARs, always 64-bits non-prefetchable * * Each emulated device represents one link and therefore - * there is one BAR for the assocaited DLTL region. + * there is one BAR for the associated DLTL region. */ /* Low 32-bits */ @@ -1691,11 +1735,19 @@ static void npu_add_phb_properties(struct npu *p) uint32_t icsp = get_ics_phandle(); uint64_t tkill, mm_base, mm_size; uint32_t base_lsi = p->base_lsi; - uint32_t map[] = { 0x0, 0x0, 0x0, 0x1, icsp, base_lsi, - 0x0, 0x0, 0x0, 0x2, icsp, base_lsi + 1, - 0x800, 0x0, 0x0, 0x1, icsp, base_lsi + 2, - 0x800, 0x0, 0x0, 0x2, icsp, base_lsi + 3 }; + uint32_t map[] = { + /* Dev 0 INT#A (used by fn0) */ + 0x0000, 0x0, 0x0, 0x1, icsp, base_lsi + NPU_LSI_INT_DL0, 1, + /* Dev 0 INT#B (used by fn1) */ + 0x0000, 0x0, 0x0, 0x2, icsp, base_lsi + NPU_LSI_INT_DL1, 1, + /* Dev 1 INT#A (used by fn0) */ + 0x0800, 0x0, 0x0, 0x1, icsp, base_lsi + NPU_LSI_INT_DL2, 1, + /* Dev 1 INT#B (used by fn1) */ + 0x0800, 0x0, 0x0, 0x2, icsp, base_lsi + NPU_LSI_INT_DL3, 1, + }; + /* Mask is bus, device and INT# */ uint32_t mask[] = {0xf800, 0x0, 0x0, 0x7}; + char slotbuf[32]; /* Add various properties that HB doesn't have to * add, some of them simply because they result from @@ -1710,21 +1762,8 @@ static void npu_add_phb_properties(struct npu *p) dt_add_property_cells(np, "clock-frequency", 0x200, 0); dt_add_property_cells(np, "interrupt-parent", icsp); - /* DLPL Interrupts */ - p->phb.lstate.int_size = 1; - p->phb.lstate.int_val[0][0] = p->base_lsi + NPU_LSI_INT_DL0; - p->phb.lstate.int_val[1][0] = p->base_lsi + NPU_LSI_INT_DL1; - p->phb.lstate.int_val[2][0] = p->base_lsi + NPU_LSI_INT_DL2; - p->phb.lstate.int_val[3][0] = p->base_lsi + NPU_LSI_INT_DL3; - p->phb.lstate.int_parent[0] = icsp; - p->phb.lstate.int_parent[1] = icsp; - p->phb.lstate.int_parent[2] = icsp; - p->phb.lstate.int_parent[3] = icsp; - - /* Due to the way the emulated PCI devices are structured in - * the device tree the core PCI layer doesn't do this for - * us. Besides the swizzling wouldn't suit our needs even if it - * did. */ + /* DLPL Interrupts, we don't use the standard swizzle */ + p->phb.lstate.int_size = 0; dt_add_property(np, "interrupt-map", map, sizeof(map)); dt_add_property(np, "interrupt-map-mask", mask, sizeof(mask)); @@ -1750,12 +1789,20 @@ static void npu_add_phb_properties(struct npu *p) hi32(mm_base), lo32(mm_base), hi32(mm_base), lo32(mm_base), hi32(mm_size), lo32(mm_size)); + + /* Set the slot location on the NPU PHB. This PHB can contain + * devices that correlate with multiple physical slots, so + * present the chip ID instead. + */ + snprintf(slotbuf, sizeof(slotbuf), "NPU Chip %d", p->chip_id); + dt_add_property_string(np, "ibm,io-base-loc-code", slotbuf); } static void npu_create_phb(struct dt_node *dn) { const struct dt_property *prop; struct npu *p; + struct pci_slot *slot; uint32_t links; void *pmem; @@ -1800,6 +1847,18 @@ static void npu_create_phb(struct dt_node *dn) /* Populate extra properties */ npu_add_phb_properties(p); + /* Create PHB slot */ + slot = npu_slot_create(&p->phb); + if (!slot) + { + /** + * @fwts-label NPUCannotCreatePHBSlot + * @fwts-advice Firmware probably ran out of memory creating + * NPU slot. NVLink functionality could be broken. + */ + prlog(PR_ERR, "NPU: Cannot create PHB slot\n"); + } + /* Register PHB */ pci_register_phb(&p->phb, OPAL_DYNAMIC_PHB_ID); @@ -1825,3 +1884,4 @@ void probe_npu(void) dt_for_each_compatible(dt_root, np, "ibm,power8-npu-pciex") npu_create_phb(np); } + |