struct npu_link { struct list_head list; int domain; int bus; int dev;
u16 fn_desired_actags[8]; struct actag_range fn_actags[8]; bool assignment_done;
}; staticstruct list_head links_list = LIST_HEAD_INIT(links_list); static DEFINE_MUTEX(links_list_lock);
/* * opencapi actags handling: * * When sending commands, the opencapi device references the memory * context it's targeting with an 'actag', which is really an alias * for a (BDF, pasid) combination. When it receives a command, the NPU * must do a lookup of the actag to identify the memory context. The * hardware supports a finite number of actags per link (64 for * POWER9). * * The device can carry multiple functions, and each function can have * multiple AFUs. Each AFU advertises in its config space the number * of desired actags. The host must configure in the config space of * the AFU how many actags the AFU is really allowed to use (which can * be less than what the AFU desires). * * When a PCI function is probed by the driver, it has no visibility * about the other PCI functions and how many actags they'd like, * which makes it impossible to distribute actags fairly among AFUs. * * Unfortunately, the only way to know how many actags a function * desires is by looking at the data for each AFU in the config space * and add them up. Similarly, the only way to know how many actags * all the functions of the physical device desire is by adding the * previously computed function counts. Then we can match that against * what the hardware supports. * * To get a comprehensive view, we use a 'pci fixup': at the end of * PCI enumeration, each function counts how many actags its AFUs * desire and we save it in a 'npu_link' structure, shared between all * the PCI functions of a same device. Therefore, when the first * function is probed by the driver, we can get an idea of the total * count of desired actags for the device, and assign the actags to * the AFUs, by pro-rating if needed.
*/
staticint find_dvsec_from_pos(struct pci_dev *dev, int dvsec_id, int pos)
{ int vsec = pos;
u16 vendor, id;
list_for_each_entry(link, &links_list, list) { /* The functions of a device all share the same link */ if (link->domain == pci_domain_nr(dev->bus) &&
link->bus == dev->bus->number &&
link->dev == PCI_SLOT(dev->devfn)) { return link;
}
}
/* link doesn't exist yet. Allocate one */
link = kzalloc(sizeof(struct npu_link), GFP_KERNEL); if (!link) return NULL;
link->domain = pci_domain_nr(dev->bus);
link->bus = dev->bus->number;
link->dev = PCI_SLOT(dev->devfn);
list_add(&link->list, &links_list); return link;
}
link = find_link(dev); if (!link) {
dev_warn(&dev->dev, "couldn't update actag information\n"); return;
}
/* * Check how many actags are desired for the AFUs under that * function and add it to the count for the link
*/
rc = get_max_afu_index(dev, &afu_idx); if (rc) { /* Most likely an invalid config space */
dev_dbg(&dev->dev, "couldn't find AFU information\n");
afu_idx = -1;
}
link->fn_desired_actags[PCI_FUNC(dev->devfn)] = 0; for (i = 0; i <= afu_idx; i++) { /* * AFU index 'holes' are allowed. So don't fail if we * can't read the actag info for an index
*/
rc = get_actag_count(dev, i, &actag); if (rc) continue;
link->fn_desired_actags[PCI_FUNC(dev->devfn)] += actag;
}
dev_dbg(&dev->dev, "total actags for function: %d\n",
link->fn_desired_actags[PCI_FUNC(dev->devfn)]);
link = find_link(dev); if (!link) {
dev_err(&dev->dev, "actag information not found\n"); return -ENODEV;
} /* * On p9, we only have 64 actags per link, so they must be * shared by all the functions of the same adapter. We counted * the desired actag counts during PCI enumeration, so that we * can allocate a pro-rated number of actags to each function.
*/ if (!link->assignment_done)
assign_actags(link);
int pnv_ocxl_get_pasid_count(struct pci_dev *dev, int *count)
{ struct npu_link *link; int i, rc = -EINVAL;
/* * The number of PASIDs (process address space ID) which can * be used by a function depends on how many functions exist * on the device. The NPU needs to be configured to know how * many bits are available to PASIDs and how many are to be * used by the function BDF identifier. * * We only support one AFU-carrying function for now.
*/
guard(mutex)(&links_list_lock);
link = find_link(dev); if (!link) {
dev_err(&dev->dev, "actag information not found\n"); return -ENODEV;
}
for (i = 0; i < 8; i++) if (link->fn_desired_actags[i] && (i == PCI_FUNC(dev->devfn))) {
*count = PNV_OCXL_PASID_MAX;
rc = 0; break;
}
dev_dbg(&dev->dev, "%d PASIDs available for function\n",
rc ? 0 : *count); return rc;
}
EXPORT_SYMBOL_GPL(pnv_ocxl_get_pasid_count);
int pnv_ocxl_get_tl_cap(struct pci_dev *dev, long *cap, char *rate_buf, int rate_buf_size)
{ if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) return -EINVAL; /* * The TL capabilities are a characteristic of the NPU, so * we go with hard-coded values. * * The receiving rate of each template is encoded on 4 bits. * * On P9: * - templates 0 -> 3 are supported * - templates 0, 1 and 3 have a 0 receiving rate * - template 2 has receiving rate of 1 (extra cycle)
*/
memset(rate_buf, 0, rate_buf_size);
set_templ_rate(2, 1, rate_buf);
*cap = PNV_OCXL_TL_P9_RECV_CAP; return 0;
}
EXPORT_SYMBOL_GPL(pnv_ocxl_get_tl_cap);
int pnv_ocxl_set_tl_conf(struct pci_dev *dev, long cap,
uint64_t rate_buf_phys, int rate_buf_size)
{ struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; int rc;
if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) return -EINVAL;
/* ATSD physical address. * ATSD LAUNCH register: write access initiates a shoot down to * initiate the TLB Invalidate command.
*/
rc = of_property_read_u64_index(hose->dn, "ibm,mmio-atsd",
0, &mmio_atsd); if (rc) {
dev_info(&dev->dev, "No available ATSD found\n"); return rc;
}
/* Assign a register set to a Logical Partition and MMIO ATSD * LPARID register to the required value.
*/
rc = opal_npu_map_lpar(phb->opal_id, pci_dev_id(dev),
lparid, lpcr); if (rc) {
dev_err(&dev->dev, "Error mapping device to LPAR: %d\n", rc); return rc;
}
if (addr) { /* load Abbreviated Virtual Address register with * the necessary value
*/
val |= FIELD_PREP(PNV_OCXL_ATSD_AVA_AVA, addr >> (63-51));
out_be64(arva + PNV_OCXL_ATSD_AVA, val);
}
/* Write access initiates a shoot down to initiate the * TLB Invalidate command
*/
val = PNV_OCXL_ATSD_LNCH_R;
val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_RIC, 0b10); if (addr)
val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_IS, 0b00); else {
val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_IS, 0b01);
val |= PNV_OCXL_ATSD_LNCH_OCAPI_SINGLETON;
}
val |= PNV_OCXL_ATSD_LNCH_PRS; /* Actual Page Size to be invalidated * 000 4KB * 101 64KB * 001 2MB * 010 1GB
*/
size = 0b101; if (page_size == 0x1000)
size = 0b000; if (page_size == 0x200000)
size = 0b001; if (page_size == 0x40000000)
size = 0b010;
val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_AP, size);
val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_PID, pid);
out_be64(arva + PNV_OCXL_ATSD_LNCH, val);
/* Poll the ATSD status register to determine when the * TLB Invalidate has been completed.
*/
val = in_be64(arva + PNV_OCXL_ATSD_STAT);
pend = val >> 63;
while (pend) { if (time_after_eq(jiffies, timeout)) {
pr_err("%s - Timeout while reading XTS MMIO ATSD status register (val=%#llx, pidr=0x%lx)\n",
__func__, val, pid); return;
}
cpu_relax();
val = in_be64(arva + PNV_OCXL_ATSD_STAT);
pend = val >> 63;
}
}
EXPORT_SYMBOL_GPL(pnv_ocxl_tlb_invalidate);
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.