Skip to content

Commit

Permalink
powerpc/powernv/npu: Add release_ownership hook
Browse files Browse the repository at this point in the history
In order to make ATS work and translate addresses for arbitrary
LPID and PID, we need to program an NPU with LPID and allow PID wildcard
matching with a specific MSR mask.

This implements a helper to assign a GPU to LPAR and program the NPU
with a wildcard for PID and a helper to do clean-up. The helper takes
MSR (only DR/HV/PR/SF bits are allowed) to program them into NPU2 for
ATS checkout requests support.

This exports pnv_npu2_unmap_lpar_dev() as following patches will use it
from the VFIO driver.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
  • Loading branch information
aik authored and mpe committed Dec 21, 2018
1 parent 0bd9716 commit 1b78561
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions arch/powerpc/platforms/powernv/npu-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ static void pnv_npu_take_ownership(struct iommu_table_group *table_group)
table_group);
struct pnv_phb *phb = npe->phb;
int64_t rc;
struct pci_dev *gpdev = NULL;

/*
* Note: NPU has just a single TVE in the hardware which means that
Expand All @@ -320,12 +321,28 @@ static void pnv_npu_take_ownership(struct iommu_table_group *table_group)
return;
}
pnv_pci_ioda2_tce_invalidate_entire(npe->phb, false);

get_gpu_pci_dev_and_pe(npe, &gpdev);
if (gpdev)
pnv_npu2_unmap_lpar_dev(gpdev);
}

static void pnv_npu_release_ownership(struct iommu_table_group *table_group)
{
struct pnv_ioda_pe *npe = container_of(table_group, struct pnv_ioda_pe,
table_group);
struct pci_dev *gpdev = NULL;

get_gpu_pci_dev_and_pe(npe, &gpdev);
if (gpdev)
pnv_npu2_map_lpar_dev(gpdev, 0, MSR_DR | MSR_PR | MSR_HV);
}

static struct iommu_table_group_ops pnv_pci_npu_ops = {
.set_window = pnv_npu_set_window,
.unset_window = pnv_npu_unset_window,
.take_ownership = pnv_npu_take_ownership,
.release_ownership = pnv_npu_release_ownership,
};
#endif /* !CONFIG_IOMMU_API */

Expand Down Expand Up @@ -1236,3 +1253,37 @@ void pnv_npu2_map_lpar(struct pnv_ioda_pe *gpe, unsigned long msr)
list_for_each_entry(gpdev, &gpe->pbus->devices, bus_list)
pnv_npu2_map_lpar_dev(gpdev, 0, msr);
}

int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev)
{
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, "destroy context opalid=%llu\n",
nphb->opal_id);
ret = opal_npu_destroy_context(nphb->opal_id, 0/*__unused*/,
PCI_DEVID(gpdev->bus->number, gpdev->devfn));
if (ret < 0) {
dev_err(&gpdev->dev, "Failed to destroy context: %d\n", ret);
return ret;
}

/* Set LPID to 0 anyway, just to be safe */
dev_dbg(&gpdev->dev, "Map LPAR opalid=%llu lparid=0\n", nphb->opal_id);
ret = opal_npu_map_lpar(nphb->opal_id,
PCI_DEVID(gpdev->bus->number, gpdev->devfn), 0 /*LPID*/,
0 /* LPCR bits */);
if (ret)
dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret);

return ret;
}
EXPORT_SYMBOL_GPL(pnv_npu2_unmap_lpar_dev);

0 comments on commit 1b78561

Please sign in to comment.