162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// Copyright 2017 IBM Corp. 362306a36Sopenharmony_ci#include <asm/pnv-ocxl.h> 462306a36Sopenharmony_ci#include <asm/opal.h> 562306a36Sopenharmony_ci#include <misc/ocxl-config.h> 662306a36Sopenharmony_ci#include "pci.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define PNV_OCXL_TL_P9_RECV_CAP 0x000000000000000Full 962306a36Sopenharmony_ci#define PNV_OCXL_ACTAG_MAX 64 1062306a36Sopenharmony_ci/* PASIDs are 20-bit, but on P9, NPU can only handle 15 bits */ 1162306a36Sopenharmony_ci#define PNV_OCXL_PASID_BITS 15 1262306a36Sopenharmony_ci#define PNV_OCXL_PASID_MAX ((1 << PNV_OCXL_PASID_BITS) - 1) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define AFU_PRESENT (1 << 31) 1562306a36Sopenharmony_ci#define AFU_INDEX_MASK 0x3F000000 1662306a36Sopenharmony_ci#define AFU_INDEX_SHIFT 24 1762306a36Sopenharmony_ci#define ACTAG_MASK 0xFFF 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct actag_range { 2162306a36Sopenharmony_ci u16 start; 2262306a36Sopenharmony_ci u16 count; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct npu_link { 2662306a36Sopenharmony_ci struct list_head list; 2762306a36Sopenharmony_ci int domain; 2862306a36Sopenharmony_ci int bus; 2962306a36Sopenharmony_ci int dev; 3062306a36Sopenharmony_ci u16 fn_desired_actags[8]; 3162306a36Sopenharmony_ci struct actag_range fn_actags[8]; 3262306a36Sopenharmony_ci bool assignment_done; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_cistatic struct list_head links_list = LIST_HEAD_INIT(links_list); 3562306a36Sopenharmony_cistatic DEFINE_MUTEX(links_list_lock); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * opencapi actags handling: 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * When sending commands, the opencapi device references the memory 4262306a36Sopenharmony_ci * context it's targeting with an 'actag', which is really an alias 4362306a36Sopenharmony_ci * for a (BDF, pasid) combination. When it receives a command, the NPU 4462306a36Sopenharmony_ci * must do a lookup of the actag to identify the memory context. The 4562306a36Sopenharmony_ci * hardware supports a finite number of actags per link (64 for 4662306a36Sopenharmony_ci * POWER9). 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * The device can carry multiple functions, and each function can have 4962306a36Sopenharmony_ci * multiple AFUs. Each AFU advertises in its config space the number 5062306a36Sopenharmony_ci * of desired actags. The host must configure in the config space of 5162306a36Sopenharmony_ci * the AFU how many actags the AFU is really allowed to use (which can 5262306a36Sopenharmony_ci * be less than what the AFU desires). 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * When a PCI function is probed by the driver, it has no visibility 5562306a36Sopenharmony_ci * about the other PCI functions and how many actags they'd like, 5662306a36Sopenharmony_ci * which makes it impossible to distribute actags fairly among AFUs. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Unfortunately, the only way to know how many actags a function 5962306a36Sopenharmony_ci * desires is by looking at the data for each AFU in the config space 6062306a36Sopenharmony_ci * and add them up. Similarly, the only way to know how many actags 6162306a36Sopenharmony_ci * all the functions of the physical device desire is by adding the 6262306a36Sopenharmony_ci * previously computed function counts. Then we can match that against 6362306a36Sopenharmony_ci * what the hardware supports. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * To get a comprehensive view, we use a 'pci fixup': at the end of 6662306a36Sopenharmony_ci * PCI enumeration, each function counts how many actags its AFUs 6762306a36Sopenharmony_ci * desire and we save it in a 'npu_link' structure, shared between all 6862306a36Sopenharmony_ci * the PCI functions of a same device. Therefore, when the first 6962306a36Sopenharmony_ci * function is probed by the driver, we can get an idea of the total 7062306a36Sopenharmony_ci * count of desired actags for the device, and assign the actags to 7162306a36Sopenharmony_ci * the AFUs, by pro-rating if needed. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int find_dvsec_from_pos(struct pci_dev *dev, int dvsec_id, int pos) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int vsec = pos; 7762306a36Sopenharmony_ci u16 vendor, id; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci while ((vsec = pci_find_next_ext_capability(dev, vsec, 8062306a36Sopenharmony_ci OCXL_EXT_CAP_ID_DVSEC))) { 8162306a36Sopenharmony_ci pci_read_config_word(dev, vsec + OCXL_DVSEC_VENDOR_OFFSET, 8262306a36Sopenharmony_ci &vendor); 8362306a36Sopenharmony_ci pci_read_config_word(dev, vsec + OCXL_DVSEC_ID_OFFSET, &id); 8462306a36Sopenharmony_ci if (vendor == PCI_VENDOR_ID_IBM && id == dvsec_id) 8562306a36Sopenharmony_ci return vsec; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int find_dvsec_afu_ctrl(struct pci_dev *dev, u8 afu_idx) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci int vsec = 0; 9362306a36Sopenharmony_ci u8 idx; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci while ((vsec = find_dvsec_from_pos(dev, OCXL_DVSEC_AFU_CTRL_ID, 9662306a36Sopenharmony_ci vsec))) { 9762306a36Sopenharmony_ci pci_read_config_byte(dev, vsec + OCXL_DVSEC_AFU_CTRL_AFU_IDX, 9862306a36Sopenharmony_ci &idx); 9962306a36Sopenharmony_ci if (idx == afu_idx) 10062306a36Sopenharmony_ci return vsec; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int get_max_afu_index(struct pci_dev *dev, int *afu_idx) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int pos; 10862306a36Sopenharmony_ci u32 val; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci pos = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_IBM, 11162306a36Sopenharmony_ci OCXL_DVSEC_FUNC_ID); 11262306a36Sopenharmony_ci if (!pos) 11362306a36Sopenharmony_ci return -ESRCH; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci pci_read_config_dword(dev, pos + OCXL_DVSEC_FUNC_OFF_INDEX, &val); 11662306a36Sopenharmony_ci if (val & AFU_PRESENT) 11762306a36Sopenharmony_ci *afu_idx = (val & AFU_INDEX_MASK) >> AFU_INDEX_SHIFT; 11862306a36Sopenharmony_ci else 11962306a36Sopenharmony_ci *afu_idx = -1; 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int get_actag_count(struct pci_dev *dev, int afu_idx, int *actag) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int pos; 12662306a36Sopenharmony_ci u16 actag_sup; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci pos = find_dvsec_afu_ctrl(dev, afu_idx); 12962306a36Sopenharmony_ci if (!pos) 13062306a36Sopenharmony_ci return -ESRCH; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci pci_read_config_word(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_SUP, 13362306a36Sopenharmony_ci &actag_sup); 13462306a36Sopenharmony_ci *actag = actag_sup & ACTAG_MASK; 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic struct npu_link *find_link(struct pci_dev *dev) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct npu_link *link; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci list_for_each_entry(link, &links_list, list) { 14362306a36Sopenharmony_ci /* The functions of a device all share the same link */ 14462306a36Sopenharmony_ci if (link->domain == pci_domain_nr(dev->bus) && 14562306a36Sopenharmony_ci link->bus == dev->bus->number && 14662306a36Sopenharmony_ci link->dev == PCI_SLOT(dev->devfn)) { 14762306a36Sopenharmony_ci return link; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* link doesn't exist yet. Allocate one */ 15262306a36Sopenharmony_ci link = kzalloc(sizeof(struct npu_link), GFP_KERNEL); 15362306a36Sopenharmony_ci if (!link) 15462306a36Sopenharmony_ci return NULL; 15562306a36Sopenharmony_ci link->domain = pci_domain_nr(dev->bus); 15662306a36Sopenharmony_ci link->bus = dev->bus->number; 15762306a36Sopenharmony_ci link->dev = PCI_SLOT(dev->devfn); 15862306a36Sopenharmony_ci list_add(&link->list, &links_list); 15962306a36Sopenharmony_ci return link; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void pnv_ocxl_fixup_actag(struct pci_dev *dev) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(dev->bus); 16562306a36Sopenharmony_ci struct pnv_phb *phb = hose->private_data; 16662306a36Sopenharmony_ci struct npu_link *link; 16762306a36Sopenharmony_ci int rc, afu_idx = -1, i, actag; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!machine_is(powernv)) 17062306a36Sopenharmony_ci return; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (phb->type != PNV_PHB_NPU_OCAPI) 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci mutex_lock(&links_list_lock); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci link = find_link(dev); 17862306a36Sopenharmony_ci if (!link) { 17962306a36Sopenharmony_ci dev_warn(&dev->dev, "couldn't update actag information\n"); 18062306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 18162306a36Sopenharmony_ci return; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* 18562306a36Sopenharmony_ci * Check how many actags are desired for the AFUs under that 18662306a36Sopenharmony_ci * function and add it to the count for the link 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci rc = get_max_afu_index(dev, &afu_idx); 18962306a36Sopenharmony_ci if (rc) { 19062306a36Sopenharmony_ci /* Most likely an invalid config space */ 19162306a36Sopenharmony_ci dev_dbg(&dev->dev, "couldn't find AFU information\n"); 19262306a36Sopenharmony_ci afu_idx = -1; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci link->fn_desired_actags[PCI_FUNC(dev->devfn)] = 0; 19662306a36Sopenharmony_ci for (i = 0; i <= afu_idx; i++) { 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * AFU index 'holes' are allowed. So don't fail if we 19962306a36Sopenharmony_ci * can't read the actag info for an index 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci rc = get_actag_count(dev, i, &actag); 20262306a36Sopenharmony_ci if (rc) 20362306a36Sopenharmony_ci continue; 20462306a36Sopenharmony_ci link->fn_desired_actags[PCI_FUNC(dev->devfn)] += actag; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci dev_dbg(&dev->dev, "total actags for function: %d\n", 20762306a36Sopenharmony_ci link->fn_desired_actags[PCI_FUNC(dev->devfn)]); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pnv_ocxl_fixup_actag); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic u16 assign_fn_actags(u16 desired, u16 total) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci u16 count; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (total <= PNV_OCXL_ACTAG_MAX) 21862306a36Sopenharmony_ci count = desired; 21962306a36Sopenharmony_ci else 22062306a36Sopenharmony_ci count = PNV_OCXL_ACTAG_MAX * desired / total; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return count; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void assign_actags(struct npu_link *link) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci u16 actag_count, range_start = 0, total_desired = 0; 22862306a36Sopenharmony_ci int i; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci for (i = 0; i < 8; i++) 23162306a36Sopenharmony_ci total_desired += link->fn_desired_actags[i]; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 23462306a36Sopenharmony_ci if (link->fn_desired_actags[i]) { 23562306a36Sopenharmony_ci actag_count = assign_fn_actags( 23662306a36Sopenharmony_ci link->fn_desired_actags[i], 23762306a36Sopenharmony_ci total_desired); 23862306a36Sopenharmony_ci link->fn_actags[i].start = range_start; 23962306a36Sopenharmony_ci link->fn_actags[i].count = actag_count; 24062306a36Sopenharmony_ci range_start += actag_count; 24162306a36Sopenharmony_ci WARN_ON(range_start >= PNV_OCXL_ACTAG_MAX); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci pr_debug("link %x:%x:%x fct %d actags: start=%d count=%d (desired=%d)\n", 24462306a36Sopenharmony_ci link->domain, link->bus, link->dev, i, 24562306a36Sopenharmony_ci link->fn_actags[i].start, link->fn_actags[i].count, 24662306a36Sopenharmony_ci link->fn_desired_actags[i]); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci link->assignment_done = true; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ciint pnv_ocxl_get_actag(struct pci_dev *dev, u16 *base, u16 *enabled, 25262306a36Sopenharmony_ci u16 *supported) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct npu_link *link; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci mutex_lock(&links_list_lock); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci link = find_link(dev); 25962306a36Sopenharmony_ci if (!link) { 26062306a36Sopenharmony_ci dev_err(&dev->dev, "actag information not found\n"); 26162306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 26262306a36Sopenharmony_ci return -ENODEV; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * On p9, we only have 64 actags per link, so they must be 26662306a36Sopenharmony_ci * shared by all the functions of the same adapter. We counted 26762306a36Sopenharmony_ci * the desired actag counts during PCI enumeration, so that we 26862306a36Sopenharmony_ci * can allocate a pro-rated number of actags to each function. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci if (!link->assignment_done) 27162306a36Sopenharmony_ci assign_actags(link); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci *base = link->fn_actags[PCI_FUNC(dev->devfn)].start; 27462306a36Sopenharmony_ci *enabled = link->fn_actags[PCI_FUNC(dev->devfn)].count; 27562306a36Sopenharmony_ci *supported = link->fn_desired_actags[PCI_FUNC(dev->devfn)]; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_get_actag); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint pnv_ocxl_get_pasid_count(struct pci_dev *dev, int *count) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct npu_link *link; 28562306a36Sopenharmony_ci int i, rc = -EINVAL; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * The number of PASIDs (process address space ID) which can 28962306a36Sopenharmony_ci * be used by a function depends on how many functions exist 29062306a36Sopenharmony_ci * on the device. The NPU needs to be configured to know how 29162306a36Sopenharmony_ci * many bits are available to PASIDs and how many are to be 29262306a36Sopenharmony_ci * used by the function BDF identifier. 29362306a36Sopenharmony_ci * 29462306a36Sopenharmony_ci * We only support one AFU-carrying function for now. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci mutex_lock(&links_list_lock); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci link = find_link(dev); 29962306a36Sopenharmony_ci if (!link) { 30062306a36Sopenharmony_ci dev_err(&dev->dev, "actag information not found\n"); 30162306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 30262306a36Sopenharmony_ci return -ENODEV; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (i = 0; i < 8; i++) 30662306a36Sopenharmony_ci if (link->fn_desired_actags[i] && (i == PCI_FUNC(dev->devfn))) { 30762306a36Sopenharmony_ci *count = PNV_OCXL_PASID_MAX; 30862306a36Sopenharmony_ci rc = 0; 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mutex_unlock(&links_list_lock); 31362306a36Sopenharmony_ci dev_dbg(&dev->dev, "%d PASIDs available for function\n", 31462306a36Sopenharmony_ci rc ? 0 : *count); 31562306a36Sopenharmony_ci return rc; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_get_pasid_count); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void set_templ_rate(unsigned int templ, unsigned int rate, char *buf) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci int shift, idx; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci WARN_ON(templ > PNV_OCXL_TL_MAX_TEMPLATE); 32462306a36Sopenharmony_ci idx = (PNV_OCXL_TL_MAX_TEMPLATE - templ) / 2; 32562306a36Sopenharmony_ci shift = 4 * (1 - ((PNV_OCXL_TL_MAX_TEMPLATE - templ) % 2)); 32662306a36Sopenharmony_ci buf[idx] |= rate << shift; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciint pnv_ocxl_get_tl_cap(struct pci_dev *dev, long *cap, 33062306a36Sopenharmony_ci char *rate_buf, int rate_buf_size) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) 33362306a36Sopenharmony_ci return -EINVAL; 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * The TL capabilities are a characteristic of the NPU, so 33662306a36Sopenharmony_ci * we go with hard-coded values. 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * The receiving rate of each template is encoded on 4 bits. 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * On P9: 34162306a36Sopenharmony_ci * - templates 0 -> 3 are supported 34262306a36Sopenharmony_ci * - templates 0, 1 and 3 have a 0 receiving rate 34362306a36Sopenharmony_ci * - template 2 has receiving rate of 1 (extra cycle) 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci memset(rate_buf, 0, rate_buf_size); 34662306a36Sopenharmony_ci set_templ_rate(2, 1, rate_buf); 34762306a36Sopenharmony_ci *cap = PNV_OCXL_TL_P9_RECV_CAP; 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_get_tl_cap); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciint pnv_ocxl_set_tl_conf(struct pci_dev *dev, long cap, 35362306a36Sopenharmony_ci uint64_t rate_buf_phys, int rate_buf_size) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(dev->bus); 35662306a36Sopenharmony_ci struct pnv_phb *phb = hose->private_data; 35762306a36Sopenharmony_ci int rc; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci rc = opal_npu_tl_set(phb->opal_id, dev->devfn, cap, 36362306a36Sopenharmony_ci rate_buf_phys, rate_buf_size); 36462306a36Sopenharmony_ci if (rc) { 36562306a36Sopenharmony_ci dev_err(&dev->dev, "Can't configure host TL: %d\n", rc); 36662306a36Sopenharmony_ci return -EINVAL; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_set_tl_conf); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciint pnv_ocxl_get_xsl_irq(struct pci_dev *dev, int *hwirq) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int rc; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci rc = of_property_read_u32(dev->dev.of_node, "ibm,opal-xsl-irq", hwirq); 37762306a36Sopenharmony_ci if (rc) { 37862306a36Sopenharmony_ci dev_err(&dev->dev, 37962306a36Sopenharmony_ci "Can't get translation interrupt for device\n"); 38062306a36Sopenharmony_ci return rc; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_get_xsl_irq); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_civoid pnv_ocxl_unmap_xsl_regs(void __iomem *dsisr, void __iomem *dar, 38762306a36Sopenharmony_ci void __iomem *tfc, void __iomem *pe_handle) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci iounmap(dsisr); 39062306a36Sopenharmony_ci iounmap(dar); 39162306a36Sopenharmony_ci iounmap(tfc); 39262306a36Sopenharmony_ci iounmap(pe_handle); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_unmap_xsl_regs); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciint pnv_ocxl_map_xsl_regs(struct pci_dev *dev, void __iomem **dsisr, 39762306a36Sopenharmony_ci void __iomem **dar, void __iomem **tfc, 39862306a36Sopenharmony_ci void __iomem **pe_handle) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u64 reg; 40162306a36Sopenharmony_ci int i, j, rc = 0; 40262306a36Sopenharmony_ci void __iomem *regs[4]; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * opal stores the mmio addresses of the DSISR, DAR, TFC and 40662306a36Sopenharmony_ci * PE_HANDLE registers in a device tree property, in that 40762306a36Sopenharmony_ci * order 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 41062306a36Sopenharmony_ci rc = of_property_read_u64_index(dev->dev.of_node, 41162306a36Sopenharmony_ci "ibm,opal-xsl-mmio", i, ®); 41262306a36Sopenharmony_ci if (rc) 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci regs[i] = ioremap(reg, 8); 41562306a36Sopenharmony_ci if (!regs[i]) { 41662306a36Sopenharmony_ci rc = -EINVAL; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci if (rc) { 42162306a36Sopenharmony_ci dev_err(&dev->dev, "Can't map translation mmio registers\n"); 42262306a36Sopenharmony_ci for (j = i - 1; j >= 0; j--) 42362306a36Sopenharmony_ci iounmap(regs[j]); 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci *dsisr = regs[0]; 42662306a36Sopenharmony_ci *dar = regs[1]; 42762306a36Sopenharmony_ci *tfc = regs[2]; 42862306a36Sopenharmony_ci *pe_handle = regs[3]; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci return rc; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_map_xsl_regs); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistruct spa_data { 43562306a36Sopenharmony_ci u64 phb_opal_id; 43662306a36Sopenharmony_ci u32 bdfn; 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciint pnv_ocxl_spa_setup(struct pci_dev *dev, void *spa_mem, int PE_mask, 44062306a36Sopenharmony_ci void **platform_data) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(dev->bus); 44362306a36Sopenharmony_ci struct pnv_phb *phb = hose->private_data; 44462306a36Sopenharmony_ci struct spa_data *data; 44562306a36Sopenharmony_ci u32 bdfn; 44662306a36Sopenharmony_ci int rc; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 44962306a36Sopenharmony_ci if (!data) 45062306a36Sopenharmony_ci return -ENOMEM; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci bdfn = pci_dev_id(dev); 45362306a36Sopenharmony_ci rc = opal_npu_spa_setup(phb->opal_id, bdfn, virt_to_phys(spa_mem), 45462306a36Sopenharmony_ci PE_mask); 45562306a36Sopenharmony_ci if (rc) { 45662306a36Sopenharmony_ci dev_err(&dev->dev, "Can't setup Shared Process Area: %d\n", rc); 45762306a36Sopenharmony_ci kfree(data); 45862306a36Sopenharmony_ci return rc; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci data->phb_opal_id = phb->opal_id; 46162306a36Sopenharmony_ci data->bdfn = bdfn; 46262306a36Sopenharmony_ci *platform_data = (void *) data; 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_spa_setup); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_civoid pnv_ocxl_spa_release(void *platform_data) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct spa_data *data = (struct spa_data *) platform_data; 47062306a36Sopenharmony_ci int rc; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci rc = opal_npu_spa_setup(data->phb_opal_id, data->bdfn, 0, 0); 47362306a36Sopenharmony_ci WARN_ON(rc); 47462306a36Sopenharmony_ci kfree(data); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_spa_release); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciint pnv_ocxl_spa_remove_pe_from_cache(void *platform_data, int pe_handle) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct spa_data *data = (struct spa_data *) platform_data; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return opal_npu_spa_clear_cache(data->phb_opal_id, data->bdfn, pe_handle); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe_from_cache); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ciint pnv_ocxl_map_lpar(struct pci_dev *dev, uint64_t lparid, 48762306a36Sopenharmony_ci uint64_t lpcr, void __iomem **arva) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(dev->bus); 49062306a36Sopenharmony_ci struct pnv_phb *phb = hose->private_data; 49162306a36Sopenharmony_ci u64 mmio_atsd; 49262306a36Sopenharmony_ci int rc; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* ATSD physical address. 49562306a36Sopenharmony_ci * ATSD LAUNCH register: write access initiates a shoot down to 49662306a36Sopenharmony_ci * initiate the TLB Invalidate command. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci rc = of_property_read_u64_index(hose->dn, "ibm,mmio-atsd", 49962306a36Sopenharmony_ci 0, &mmio_atsd); 50062306a36Sopenharmony_ci if (rc) { 50162306a36Sopenharmony_ci dev_info(&dev->dev, "No available ATSD found\n"); 50262306a36Sopenharmony_ci return rc; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Assign a register set to a Logical Partition and MMIO ATSD 50662306a36Sopenharmony_ci * LPARID register to the required value. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci rc = opal_npu_map_lpar(phb->opal_id, pci_dev_id(dev), 50962306a36Sopenharmony_ci lparid, lpcr); 51062306a36Sopenharmony_ci if (rc) { 51162306a36Sopenharmony_ci dev_err(&dev->dev, "Error mapping device to LPAR: %d\n", rc); 51262306a36Sopenharmony_ci return rc; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci *arva = ioremap(mmio_atsd, 24); 51662306a36Sopenharmony_ci if (!(*arva)) { 51762306a36Sopenharmony_ci dev_warn(&dev->dev, "ioremap failed - mmio_atsd: %#llx\n", mmio_atsd); 51862306a36Sopenharmony_ci rc = -ENOMEM; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return rc; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_map_lpar); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_civoid pnv_ocxl_unmap_lpar(void __iomem *arva) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci iounmap(arva); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_unmap_lpar); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_civoid pnv_ocxl_tlb_invalidate(void __iomem *arva, 53262306a36Sopenharmony_ci unsigned long pid, 53362306a36Sopenharmony_ci unsigned long addr, 53462306a36Sopenharmony_ci unsigned long page_size) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci unsigned long timeout = jiffies + (HZ * PNV_OCXL_ATSD_TIMEOUT); 53762306a36Sopenharmony_ci u64 val = 0ull; 53862306a36Sopenharmony_ci int pend; 53962306a36Sopenharmony_ci u8 size; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (!(arva)) 54262306a36Sopenharmony_ci return; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (addr) { 54562306a36Sopenharmony_ci /* load Abbreviated Virtual Address register with 54662306a36Sopenharmony_ci * the necessary value 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_AVA_AVA, addr >> (63-51)); 54962306a36Sopenharmony_ci out_be64(arva + PNV_OCXL_ATSD_AVA, val); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Write access initiates a shoot down to initiate the 55362306a36Sopenharmony_ci * TLB Invalidate command 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci val = PNV_OCXL_ATSD_LNCH_R; 55662306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_RIC, 0b10); 55762306a36Sopenharmony_ci if (addr) 55862306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_IS, 0b00); 55962306a36Sopenharmony_ci else { 56062306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_IS, 0b01); 56162306a36Sopenharmony_ci val |= PNV_OCXL_ATSD_LNCH_OCAPI_SINGLETON; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci val |= PNV_OCXL_ATSD_LNCH_PRS; 56462306a36Sopenharmony_ci /* Actual Page Size to be invalidated 56562306a36Sopenharmony_ci * 000 4KB 56662306a36Sopenharmony_ci * 101 64KB 56762306a36Sopenharmony_ci * 001 2MB 56862306a36Sopenharmony_ci * 010 1GB 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci size = 0b101; 57162306a36Sopenharmony_ci if (page_size == 0x1000) 57262306a36Sopenharmony_ci size = 0b000; 57362306a36Sopenharmony_ci if (page_size == 0x200000) 57462306a36Sopenharmony_ci size = 0b001; 57562306a36Sopenharmony_ci if (page_size == 0x40000000) 57662306a36Sopenharmony_ci size = 0b010; 57762306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_AP, size); 57862306a36Sopenharmony_ci val |= FIELD_PREP(PNV_OCXL_ATSD_LNCH_PID, pid); 57962306a36Sopenharmony_ci out_be64(arva + PNV_OCXL_ATSD_LNCH, val); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Poll the ATSD status register to determine when the 58262306a36Sopenharmony_ci * TLB Invalidate has been completed. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci val = in_be64(arva + PNV_OCXL_ATSD_STAT); 58562306a36Sopenharmony_ci pend = val >> 63; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci while (pend) { 58862306a36Sopenharmony_ci if (time_after_eq(jiffies, timeout)) { 58962306a36Sopenharmony_ci pr_err("%s - Timeout while reading XTS MMIO ATSD status register (val=%#llx, pidr=0x%lx)\n", 59062306a36Sopenharmony_ci __func__, val, pid); 59162306a36Sopenharmony_ci return; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci cpu_relax(); 59462306a36Sopenharmony_ci val = in_be64(arva + PNV_OCXL_ATSD_STAT); 59562306a36Sopenharmony_ci pend = val >> 63; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pnv_ocxl_tlb_invalidate); 599