> - /* > - * Setup the NPU context table for a particular GPU. These need to be > - * per-GPU as we need the tables to filter ATSDs when there are no > - * active contexts on a particular GPU. It is safe for these to be > - * called concurrently with destroy as the OPAL call takes appropriate > - * locks and refcounts on init/destroy. > - */ > - rc = opal_npu_init_context(nphb->opal_id, mm->context.id, flags, > - PCI_DEVID(gpdev->bus->number, gpdev->devfn)); > - if (rc < 0) > - return ERR_PTR(-ENOSPC); > - This will prevent any drivers from setting up contexts with different MSR values (which is what the flags argument is for) than a standard userspace context (MSR_DR | MSR_PR | MSR_HV). In practice this currently never happens and I'm unsure if that's ever likely to change. We should at least return an error if flags != (MSR_DR | MSR_PR | MSR_HV). > /* > * We store the npu pci device so we can more easily get at the > * associated npus. > @@ -755,9 +738,6 @@ struct npu_context *pnv_npu2_init_context(struct pci_dev > *gpdev, if (npu_context->release_cb != cb || > npu_context->priv != priv) { > spin_unlock(&npu_context_lock); > - opal_npu_destroy_context(nphb->opal_id, mm->context.id, > - PCI_DEVID(gpdev->bus->number, > - gpdev->devfn)); > return ERR_PTR(-EINVAL); > } > > @@ -783,9 +763,6 @@ struct npu_context *pnv_npu2_init_context(struct pci_dev > *gpdev, > > if (rc) { > kfree(npu_context); > - opal_npu_destroy_context(nphb->opal_id, mm->context.id, > - PCI_DEVID(gpdev->bus->number, > - gpdev->devfn)); > return ERR_PTR(rc); > } > > @@ -838,7 +815,6 @@ void pnv_npu2_destroy_context(struct npu_context > *npu_context, struct pci_dev *gpdev) > { > int removed; > - struct pnv_phb *nphb; > struct npu *npu; > struct pci_dev *npdev = pnv_pci_get_npu_dev(gpdev, 0); > struct device_node *nvlink_dn; > @@ -847,10 +823,6 @@ void pnv_npu2_destroy_context(struct npu_context > *npu_context, if (WARN_ON(!npdev)) > return; > > - if (!firmware_has_feature(FW_FEATURE_OPAL)) > - return; > - > - nphb = pci_bus_to_host(npdev->bus)->private_data; > npu = npdev_to_npu(npdev); > if (!npu) > return; > @@ -859,8 +831,6 @@ void pnv_npu2_destroy_context(struct npu_context > *npu_context, &nvlink_index))) > return; > WRITE_ONCE(npu_context->npdev[npu->index][nvlink_index], NULL); > - opal_npu_destroy_context(nphb->opal_id, npu_context->mm->context.id, > - PCI_DEVID(gpdev->bus->number, gpdev->devfn)); > spin_lock(&npu_context_lock); > removed = kref_put(&npu_context->kref, pnv_npu2_release_context); > spin_unlock(&npu_context_lock); > @@ -892,9 +862,6 @@ int pnv_npu2_handle_fault(struct npu_context *context, > uintptr_t *ea, /* mmap_sem should be held so the struct_mm must be present > */ > struct mm_struct *mm = context->mm; > > - if (!firmware_has_feature(FW_FEATURE_OPAL)) > - return -ENODEV; > - > WARN_ON(!rwsem_is_locked(&mm->mmap_sem)); > > for (i = 0; i < count; i++) { > @@ -923,15 +890,11 @@ int pnv_npu2_handle_fault(struct npu_context *context, > uintptr_t *ea, } > EXPORT_SYMBOL(pnv_npu2_handle_fault); > > -int pnv_npu2_init(struct pnv_phb *phb) > +int pnv_npu2_init(struct pci_controller *hose) > { > unsigned int i; > u64 mmio_atsd; > - struct device_node *dn; > - struct pci_dev *gpdev; > static int npu_index; > - uint64_t rc = 0; > - struct pci_controller *hose = phb->hose; > struct npu *npu; > int ret; > > @@ -940,18 +903,6 @@ int pnv_npu2_init(struct pnv_phb *phb) > return -ENOMEM; > > npu->nmmu_flush = of_property_read_bool(hose->dn, "ibm,nmmu-flush"); > - for_each_child_of_node(phb->hose->dn, dn) { > - gpdev = pnv_pci_get_gpu_dev(get_pci_dev(dn)); > - if (gpdev) { > - rc = opal_npu_map_lpar(phb->opal_id, > - PCI_DEVID(gpdev->bus->number, gpdev->devfn), > - 0, 0); > - if (rc) > - dev_err(&gpdev->dev, > - "Error %lld mapping device to LPAR\n", > - rc); > - } > - } > > for (i = 0; !of_property_read_u64_index(hose->dn, "ibm,mmio-atsd", > i, &mmio_atsd); i++) > @@ -981,3 +932,57 @@ int pnv_npu2_init(struct pnv_phb *phb) > > return ret; > } > + > +int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid, > + unsigned long msr) > +{ > + int ret; > + struct pci_dev *npdev = pnv_pci_get_npu_dev(gpdev, 0); > + struct pci_controller *hose; > + struct pnv_phb *nphb; > + > + if (!npdev) > + return -ENODEV; > + > + hose = pci_bus_to_host(npdev->bus); > + nphb = hose->private_data; > + > + dev_dbg(&gpdev->dev, "Map LPAR opalid=%llu lparid=%u\n", > + nphb->opal_id, lparid); > + /* > + * Currently we only support radix and non-zero LPCR only makes sense > + * for hash tables so skiboot expects the LPCR parameter to be a zero. > + */ > + ret = opal_npu_map_lpar(nphb->opal_id, > + PCI_DEVID(gpdev->bus->number, gpdev->devfn), lparid, > + 0 /* LPCR bits */); > + if (ret) { > + dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret); > + return ret; > + } > + > + dev_dbg(&gpdev->dev, "init context opalid=%llu msr=%lx\n", > + nphb->opal_id, msr); > + ret = opal_npu_init_context(nphb->opal_id, 0/*__unused*/, msr, > + PCI_DEVID(gpdev->bus->number, gpdev->devfn)); > + if (ret < 0) > + dev_err(&gpdev->dev, "Failed to init context: %d\n", ret); > + else > + ret = 0; > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(pnv_npu2_map_lpar_dev); > + > +void pnv_npu2_map_lpar(struct pnv_ioda_pe *gpe, unsigned long msr) > +{ > + int ret; > + struct pci_dev *gpdev; > + > + list_for_each_entry(gpdev, &gpe->pbus->devices, bus_list) { > + ret = pnv_npu2_map_lpar_dev(gpdev, 0, msr); > + if (ret < 0) > + dev_err(&gpdev->dev, "Failed to init context: %d\n", > + ret); > + } > +} > diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c > b/arch/powerpc/platforms/powernv/pci-ioda.c index c78c204..ec235ca 100644 > --- a/arch/powerpc/platforms/powernv/pci-ioda.c > +++ b/arch/powerpc/platforms/powernv/pci-ioda.c > @@ -1271,19 +1271,20 @@ static void pnv_ioda_setup_npu_PEs(struct pci_bus > *bus) > > static void pnv_pci_ioda_setup_PEs(void) > { > - struct pci_controller *hose, *tmp; > + struct pci_controller *hose; > struct pnv_phb *phb; > struct pci_bus *bus; > struct pci_dev *pdev; > + struct pnv_ioda_pe *pe; > > - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { > + list_for_each_entry(hose, &hose_list, list_node) { > phb = hose->private_data; > if (phb->type == PNV_PHB_NPU_NVLINK) { > /* PE#0 is needed for error reporting */ > pnv_ioda_reserve_pe(phb, 0); > pnv_ioda_setup_npu_PEs(hose->bus); > if (phb->model == PNV_PHB_MODEL_NPU2) > - pnv_npu2_init(phb); > + pnv_npu2_init(hose); > } > if (phb->type == PNV_PHB_NPU_OCAPI) { > bus = hose->bus; > @@ -1291,6 +1292,14 @@ static void pnv_pci_ioda_setup_PEs(void) > pnv_ioda_setup_dev_PE(pdev); > } > } > + list_for_each_entry(hose, &hose_list, list_node) { > + phb = hose->private_data; > + if (phb->type != PNV_PHB_IODA2) > + continue; > + > + list_for_each_entry(pe, &phb->ioda.pe_list, list) > + pnv_npu2_map_lpar(pe, MSR_DR | MSR_PR | MSR_HV); > + } > } > > #ifdef CONFIG_PCI_IOV