15ef3166eSFrederic Barrat // SPDX-License-Identifier: GPL-2.0+ 25ef3166eSFrederic Barrat // Copyright 2017 IBM Corp. 35ef3166eSFrederic Barrat #include <linux/sched/mm.h> 45ef3166eSFrederic Barrat #include <linux/mutex.h> 55f686eeaSChristophe Lombard #include <linux/mm.h> 650a7ca3cSSouptick Joarder #include <linux/mm_types.h> 75ef3166eSFrederic Barrat #include <linux/mmu_context.h> 85f686eeaSChristophe Lombard #include <linux/mmu_notifier.h> 9*d8d2af70SChristophe Leroy #include <linux/irqdomain.h> 105ef3166eSFrederic Barrat #include <asm/copro.h> 115ef3166eSFrederic Barrat #include <asm/pnv-ocxl.h> 12dde6f18aSFrederic Barrat #include <asm/xive.h> 13280b983cSFrederic Barrat #include <misc/ocxl.h> 145ef3166eSFrederic Barrat #include "ocxl_internal.h" 1592add22eSFrederic Barrat #include "trace.h" 165ef3166eSFrederic Barrat 175ef3166eSFrederic Barrat 185ef3166eSFrederic Barrat #define SPA_PASID_BITS 15 195ef3166eSFrederic Barrat #define SPA_PASID_MAX ((1 << SPA_PASID_BITS) - 1) 205ef3166eSFrederic Barrat #define SPA_PE_MASK SPA_PASID_MAX 215ef3166eSFrederic Barrat #define SPA_SPA_SIZE_LOG 22 /* Each SPA is 4 Mb */ 225ef3166eSFrederic Barrat 235ef3166eSFrederic Barrat #define SPA_CFG_SF (1ull << (63-0)) 245ef3166eSFrederic Barrat #define SPA_CFG_TA (1ull << (63-1)) 255ef3166eSFrederic Barrat #define SPA_CFG_HV (1ull << (63-3)) 265ef3166eSFrederic Barrat #define SPA_CFG_UV (1ull << (63-4)) 275ef3166eSFrederic Barrat #define SPA_CFG_XLAT_hpt (0ull << (63-6)) /* Hashed page table (HPT) mode */ 285ef3166eSFrederic Barrat #define SPA_CFG_XLAT_roh (2ull << (63-6)) /* Radix on HPT mode */ 295ef3166eSFrederic Barrat #define SPA_CFG_XLAT_ror (3ull << (63-6)) /* Radix on Radix mode */ 305ef3166eSFrederic Barrat #define SPA_CFG_PR (1ull << (63-49)) 315ef3166eSFrederic Barrat #define SPA_CFG_TC (1ull << (63-54)) 325ef3166eSFrederic Barrat #define SPA_CFG_DR (1ull << (63-59)) 335ef3166eSFrederic Barrat 345ef3166eSFrederic Barrat #define SPA_XSL_TF (1ull << (63-3)) /* Translation fault */ 355ef3166eSFrederic Barrat #define SPA_XSL_S (1ull << (63-38)) /* Store operation */ 365ef3166eSFrederic Barrat 375ef3166eSFrederic Barrat #define SPA_PE_VALID 0x80000000 385ef3166eSFrederic Barrat 395f686eeaSChristophe Lombard struct ocxl_link; 405ef3166eSFrederic Barrat 415ef3166eSFrederic Barrat struct pe_data { 425ef3166eSFrederic Barrat struct mm_struct *mm; 435ef3166eSFrederic Barrat /* callback to trigger when a translation fault occurs */ 445ef3166eSFrederic Barrat void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr); 455ef3166eSFrederic Barrat /* opaque pointer to be passed to the above callback */ 465ef3166eSFrederic Barrat void *xsl_err_data; 475ef3166eSFrederic Barrat struct rcu_head rcu; 485f686eeaSChristophe Lombard struct ocxl_link *link; 495f686eeaSChristophe Lombard struct mmu_notifier mmu_notifier; 505ef3166eSFrederic Barrat }; 515ef3166eSFrederic Barrat 525ef3166eSFrederic Barrat struct spa { 535ef3166eSFrederic Barrat struct ocxl_process_element *spa_mem; 545ef3166eSFrederic Barrat int spa_order; 555ef3166eSFrederic Barrat struct mutex spa_lock; 565ef3166eSFrederic Barrat struct radix_tree_root pe_tree; /* Maps PE handles to pe_data */ 575ef3166eSFrederic Barrat char *irq_name; 585ef3166eSFrederic Barrat int virq; 595ef3166eSFrederic Barrat void __iomem *reg_dsisr; 605ef3166eSFrederic Barrat void __iomem *reg_dar; 615ef3166eSFrederic Barrat void __iomem *reg_tfc; 625ef3166eSFrederic Barrat void __iomem *reg_pe_handle; 635ef3166eSFrederic Barrat /* 645ef3166eSFrederic Barrat * The following field are used by the memory fault 655ef3166eSFrederic Barrat * interrupt handler. We can only have one interrupt at a 665ef3166eSFrederic Barrat * time. The NPU won't raise another interrupt until the 675ef3166eSFrederic Barrat * previous one has been ack'd by writing to the TFC register 685ef3166eSFrederic Barrat */ 695ef3166eSFrederic Barrat struct xsl_fault { 705ef3166eSFrederic Barrat struct work_struct fault_work; 715ef3166eSFrederic Barrat u64 pe; 725ef3166eSFrederic Barrat u64 dsisr; 735ef3166eSFrederic Barrat u64 dar; 745ef3166eSFrederic Barrat struct pe_data pe_data; 755ef3166eSFrederic Barrat } xsl_fault; 765ef3166eSFrederic Barrat }; 775ef3166eSFrederic Barrat 785ef3166eSFrederic Barrat /* 795ef3166eSFrederic Barrat * A opencapi link can be used be by several PCI functions. We have 805ef3166eSFrederic Barrat * one link per device slot. 815ef3166eSFrederic Barrat * 825ef3166eSFrederic Barrat * A linked list of opencapi links should suffice, as there's a 835ef3166eSFrederic Barrat * limited number of opencapi slots on a system and lookup is only 845ef3166eSFrederic Barrat * done when the device is probed 855ef3166eSFrederic Barrat */ 869c4ae064SAlastair D'Silva struct ocxl_link { 875ef3166eSFrederic Barrat struct list_head list; 885ef3166eSFrederic Barrat struct kref ref; 895ef3166eSFrederic Barrat int domain; 905ef3166eSFrederic Barrat int bus; 915ef3166eSFrederic Barrat int dev; 925f686eeaSChristophe Lombard void __iomem *arva; /* ATSD register virtual address */ 935f686eeaSChristophe Lombard spinlock_t atsd_lock; /* to serialize shootdowns */ 945ef3166eSFrederic Barrat atomic_t irq_available; 955ef3166eSFrederic Barrat struct spa *spa; 965ef3166eSFrederic Barrat void *platform_data; 975ef3166eSFrederic Barrat }; 984044fe55SCai Huoqing static LIST_HEAD(links_list); 995ef3166eSFrederic Barrat static DEFINE_MUTEX(links_list_lock); 1005ef3166eSFrederic Barrat 1015ef3166eSFrederic Barrat enum xsl_response { 1025ef3166eSFrederic Barrat CONTINUE, 1035ef3166eSFrederic Barrat ADDRESS_ERROR, 1045ef3166eSFrederic Barrat RESTART, 1055ef3166eSFrederic Barrat }; 1065ef3166eSFrederic Barrat 1075ef3166eSFrederic Barrat 1085ef3166eSFrederic Barrat static void read_irq(struct spa *spa, u64 *dsisr, u64 *dar, u64 *pe) 1095ef3166eSFrederic Barrat { 1105ef3166eSFrederic Barrat u64 reg; 1115ef3166eSFrederic Barrat 1125ef3166eSFrederic Barrat *dsisr = in_be64(spa->reg_dsisr); 1135ef3166eSFrederic Barrat *dar = in_be64(spa->reg_dar); 1145ef3166eSFrederic Barrat reg = in_be64(spa->reg_pe_handle); 1155ef3166eSFrederic Barrat *pe = reg & SPA_PE_MASK; 1165ef3166eSFrederic Barrat } 1175ef3166eSFrederic Barrat 1185ef3166eSFrederic Barrat static void ack_irq(struct spa *spa, enum xsl_response r) 1195ef3166eSFrederic Barrat { 1205ef3166eSFrederic Barrat u64 reg = 0; 1215ef3166eSFrederic Barrat 1225ef3166eSFrederic Barrat /* continue is not supported */ 1235ef3166eSFrederic Barrat if (r == RESTART) 1245ef3166eSFrederic Barrat reg = PPC_BIT(31); 1255ef3166eSFrederic Barrat else if (r == ADDRESS_ERROR) 1265ef3166eSFrederic Barrat reg = PPC_BIT(30); 1275ef3166eSFrederic Barrat else 1285ef3166eSFrederic Barrat WARN(1, "Invalid irq response %d\n", r); 1295ef3166eSFrederic Barrat 13092add22eSFrederic Barrat if (reg) { 13192add22eSFrederic Barrat trace_ocxl_fault_ack(spa->spa_mem, spa->xsl_fault.pe, 13292add22eSFrederic Barrat spa->xsl_fault.dsisr, spa->xsl_fault.dar, reg); 1335ef3166eSFrederic Barrat out_be64(spa->reg_tfc, reg); 1345ef3166eSFrederic Barrat } 13592add22eSFrederic Barrat } 1365ef3166eSFrederic Barrat 1375ef3166eSFrederic Barrat static void xsl_fault_handler_bh(struct work_struct *fault_work) 1385ef3166eSFrederic Barrat { 13950a7ca3cSSouptick Joarder vm_fault_t flt = 0; 1405ef3166eSFrederic Barrat unsigned long access, flags, inv_flags = 0; 1415ef3166eSFrederic Barrat enum xsl_response r; 1425ef3166eSFrederic Barrat struct xsl_fault *fault = container_of(fault_work, struct xsl_fault, 1435ef3166eSFrederic Barrat fault_work); 1445ef3166eSFrederic Barrat struct spa *spa = container_of(fault, struct spa, xsl_fault); 1455ef3166eSFrederic Barrat 1465ef3166eSFrederic Barrat int rc; 1475ef3166eSFrederic Barrat 1485ef3166eSFrederic Barrat /* 149d497ebf5SFrederic Barrat * We must release a reference on mm_users whenever exiting this 1505ef3166eSFrederic Barrat * function (taken in the memory fault interrupt handler) 1515ef3166eSFrederic Barrat */ 1525ef3166eSFrederic Barrat rc = copro_handle_mm_fault(fault->pe_data.mm, fault->dar, fault->dsisr, 1535ef3166eSFrederic Barrat &flt); 1545ef3166eSFrederic Barrat if (rc) { 1555ef3166eSFrederic Barrat pr_debug("copro_handle_mm_fault failed: %d\n", rc); 1565ef3166eSFrederic Barrat if (fault->pe_data.xsl_err_cb) { 1575ef3166eSFrederic Barrat fault->pe_data.xsl_err_cb( 1585ef3166eSFrederic Barrat fault->pe_data.xsl_err_data, 1595ef3166eSFrederic Barrat fault->dar, fault->dsisr); 1605ef3166eSFrederic Barrat } 1615ef3166eSFrederic Barrat r = ADDRESS_ERROR; 1625ef3166eSFrederic Barrat goto ack; 1635ef3166eSFrederic Barrat } 1645ef3166eSFrederic Barrat 1655ef3166eSFrederic Barrat if (!radix_enabled()) { 1665ef3166eSFrederic Barrat /* 1675ef3166eSFrederic Barrat * update_mmu_cache() will not have loaded the hash 1685ef3166eSFrederic Barrat * since current->trap is not a 0x400 or 0x300, so 1695ef3166eSFrederic Barrat * just call hash_page_mm() here. 1705ef3166eSFrederic Barrat */ 1715ef3166eSFrederic Barrat access = _PAGE_PRESENT | _PAGE_READ; 1725ef3166eSFrederic Barrat if (fault->dsisr & SPA_XSL_S) 1735ef3166eSFrederic Barrat access |= _PAGE_WRITE; 1745ef3166eSFrederic Barrat 1750034d395SAneesh Kumar K.V if (get_region_id(fault->dar) != USER_REGION_ID) 1765ef3166eSFrederic Barrat access |= _PAGE_PRIVILEGED; 1775ef3166eSFrederic Barrat 1785ef3166eSFrederic Barrat local_irq_save(flags); 1795ef3166eSFrederic Barrat hash_page_mm(fault->pe_data.mm, fault->dar, access, 0x300, 1805ef3166eSFrederic Barrat inv_flags); 1815ef3166eSFrederic Barrat local_irq_restore(flags); 1825ef3166eSFrederic Barrat } 1835ef3166eSFrederic Barrat r = RESTART; 1845ef3166eSFrederic Barrat ack: 185d497ebf5SFrederic Barrat mmput(fault->pe_data.mm); 1865ef3166eSFrederic Barrat ack_irq(spa, r); 1875ef3166eSFrederic Barrat } 1885ef3166eSFrederic Barrat 1895ef3166eSFrederic Barrat static irqreturn_t xsl_fault_handler(int irq, void *data) 1905ef3166eSFrederic Barrat { 1919c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) data; 1925ef3166eSFrederic Barrat struct spa *spa = link->spa; 1935ef3166eSFrederic Barrat u64 dsisr, dar, pe_handle; 1945ef3166eSFrederic Barrat struct pe_data *pe_data; 1955ef3166eSFrederic Barrat struct ocxl_process_element *pe; 19632eeb561SYueHaibing int pid; 197d497ebf5SFrederic Barrat bool schedule = false; 1985ef3166eSFrederic Barrat 1995ef3166eSFrederic Barrat read_irq(spa, &dsisr, &dar, &pe_handle); 20092add22eSFrederic Barrat trace_ocxl_fault(spa->spa_mem, pe_handle, dsisr, dar, -1); 2015ef3166eSFrederic Barrat 2025ef3166eSFrederic Barrat WARN_ON(pe_handle > SPA_PE_MASK); 2035ef3166eSFrederic Barrat pe = spa->spa_mem + pe_handle; 2045ef3166eSFrederic Barrat pid = be32_to_cpu(pe->pid); 2055ef3166eSFrederic Barrat /* We could be reading all null values here if the PE is being 2065ef3166eSFrederic Barrat * removed while an interrupt kicks in. It's not supposed to 2075ef3166eSFrederic Barrat * happen if the driver notified the AFU to terminate the 2085ef3166eSFrederic Barrat * PASID, and the AFU waited for pending operations before 2095ef3166eSFrederic Barrat * acknowledging. But even if it happens, we won't find a 2105ef3166eSFrederic Barrat * memory context below and fail silently, so it should be ok. 2115ef3166eSFrederic Barrat */ 2125ef3166eSFrederic Barrat if (!(dsisr & SPA_XSL_TF)) { 2135ef3166eSFrederic Barrat WARN(1, "Invalid xsl interrupt fault register %#llx\n", dsisr); 2145ef3166eSFrederic Barrat ack_irq(spa, ADDRESS_ERROR); 2155ef3166eSFrederic Barrat return IRQ_HANDLED; 2165ef3166eSFrederic Barrat } 2175ef3166eSFrederic Barrat 2185ef3166eSFrederic Barrat rcu_read_lock(); 2195ef3166eSFrederic Barrat pe_data = radix_tree_lookup(&spa->pe_tree, pe_handle); 2205ef3166eSFrederic Barrat if (!pe_data) { 2215ef3166eSFrederic Barrat /* 2225ef3166eSFrederic Barrat * Could only happen if the driver didn't notify the 2235ef3166eSFrederic Barrat * AFU about PASID termination before removing the PE, 2245ef3166eSFrederic Barrat * or the AFU didn't wait for all memory access to 2255ef3166eSFrederic Barrat * have completed. 2265ef3166eSFrederic Barrat * 2275ef3166eSFrederic Barrat * Either way, we fail early, but we shouldn't log an 2285ef3166eSFrederic Barrat * error message, as it is a valid (if unexpected) 2295ef3166eSFrederic Barrat * scenario 2305ef3166eSFrederic Barrat */ 2315ef3166eSFrederic Barrat rcu_read_unlock(); 2325ef3166eSFrederic Barrat pr_debug("Unknown mm context for xsl interrupt\n"); 2335ef3166eSFrederic Barrat ack_irq(spa, ADDRESS_ERROR); 2345ef3166eSFrederic Barrat return IRQ_HANDLED; 2355ef3166eSFrederic Barrat } 23660e8523eSAlastair D'Silva 23760e8523eSAlastair D'Silva if (!pe_data->mm) { 23860e8523eSAlastair D'Silva /* 23960e8523eSAlastair D'Silva * translation fault from a kernel context - an OpenCAPI 24060e8523eSAlastair D'Silva * device tried to access a bad kernel address 24160e8523eSAlastair D'Silva */ 24260e8523eSAlastair D'Silva rcu_read_unlock(); 24360e8523eSAlastair D'Silva pr_warn("Unresolved OpenCAPI xsl fault in kernel context\n"); 24460e8523eSAlastair D'Silva ack_irq(spa, ADDRESS_ERROR); 24560e8523eSAlastair D'Silva return IRQ_HANDLED; 24660e8523eSAlastair D'Silva } 2475ef3166eSFrederic Barrat WARN_ON(pe_data->mm->context.id != pid); 2485ef3166eSFrederic Barrat 249d497ebf5SFrederic Barrat if (mmget_not_zero(pe_data->mm)) { 2505ef3166eSFrederic Barrat spa->xsl_fault.pe = pe_handle; 2515ef3166eSFrederic Barrat spa->xsl_fault.dar = dar; 2525ef3166eSFrederic Barrat spa->xsl_fault.dsisr = dsisr; 2535ef3166eSFrederic Barrat spa->xsl_fault.pe_data = *pe_data; 254d497ebf5SFrederic Barrat schedule = true; 255d497ebf5SFrederic Barrat /* mm_users count released by bottom half */ 256d497ebf5SFrederic Barrat } 2575ef3166eSFrederic Barrat rcu_read_unlock(); 258d497ebf5SFrederic Barrat if (schedule) 2595ef3166eSFrederic Barrat schedule_work(&spa->xsl_fault.fault_work); 260d497ebf5SFrederic Barrat else 261d497ebf5SFrederic Barrat ack_irq(spa, ADDRESS_ERROR); 2625ef3166eSFrederic Barrat return IRQ_HANDLED; 2635ef3166eSFrederic Barrat } 2645ef3166eSFrederic Barrat 2655ef3166eSFrederic Barrat static void unmap_irq_registers(struct spa *spa) 2665ef3166eSFrederic Barrat { 2675ef3166eSFrederic Barrat pnv_ocxl_unmap_xsl_regs(spa->reg_dsisr, spa->reg_dar, spa->reg_tfc, 2685ef3166eSFrederic Barrat spa->reg_pe_handle); 2695ef3166eSFrederic Barrat } 2705ef3166eSFrederic Barrat 2715ef3166eSFrederic Barrat static int map_irq_registers(struct pci_dev *dev, struct spa *spa) 2725ef3166eSFrederic Barrat { 2735ef3166eSFrederic Barrat return pnv_ocxl_map_xsl_regs(dev, &spa->reg_dsisr, &spa->reg_dar, 2745ef3166eSFrederic Barrat &spa->reg_tfc, &spa->reg_pe_handle); 2755ef3166eSFrederic Barrat } 2765ef3166eSFrederic Barrat 2779c4ae064SAlastair D'Silva static int setup_xsl_irq(struct pci_dev *dev, struct ocxl_link *link) 2785ef3166eSFrederic Barrat { 2795ef3166eSFrederic Barrat struct spa *spa = link->spa; 2805ef3166eSFrederic Barrat int rc; 2815ef3166eSFrederic Barrat int hwirq; 2825ef3166eSFrederic Barrat 2835ef3166eSFrederic Barrat rc = pnv_ocxl_get_xsl_irq(dev, &hwirq); 2845ef3166eSFrederic Barrat if (rc) 2855ef3166eSFrederic Barrat return rc; 2865ef3166eSFrederic Barrat 2875ef3166eSFrederic Barrat rc = map_irq_registers(dev, spa); 2885ef3166eSFrederic Barrat if (rc) 2895ef3166eSFrederic Barrat return rc; 2905ef3166eSFrederic Barrat 2915ef3166eSFrederic Barrat spa->irq_name = kasprintf(GFP_KERNEL, "ocxl-xsl-%x-%x-%x", 2925ef3166eSFrederic Barrat link->domain, link->bus, link->dev); 2935ef3166eSFrederic Barrat if (!spa->irq_name) { 2945ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't allocate name for xsl interrupt\n"); 295759bc015SGreg Kurz rc = -ENOMEM; 296759bc015SGreg Kurz goto err_xsl; 2975ef3166eSFrederic Barrat } 2985ef3166eSFrederic Barrat /* 2995ef3166eSFrederic Barrat * At some point, we'll need to look into allowing a higher 3005ef3166eSFrederic Barrat * number of interrupts. Could we have an IRQ domain per link? 3015ef3166eSFrederic Barrat */ 3025ef3166eSFrederic Barrat spa->virq = irq_create_mapping(NULL, hwirq); 3035ef3166eSFrederic Barrat if (!spa->virq) { 3045ef3166eSFrederic Barrat dev_err(&dev->dev, 3055ef3166eSFrederic Barrat "irq_create_mapping failed for translation interrupt\n"); 306759bc015SGreg Kurz rc = -EINVAL; 307759bc015SGreg Kurz goto err_name; 3085ef3166eSFrederic Barrat } 3095ef3166eSFrederic Barrat 3105ef3166eSFrederic Barrat dev_dbg(&dev->dev, "hwirq %d mapped to virq %d\n", hwirq, spa->virq); 3115ef3166eSFrederic Barrat 3125ef3166eSFrederic Barrat rc = request_irq(spa->virq, xsl_fault_handler, 0, spa->irq_name, 3135ef3166eSFrederic Barrat link); 3145ef3166eSFrederic Barrat if (rc) { 3155ef3166eSFrederic Barrat dev_err(&dev->dev, 3165ef3166eSFrederic Barrat "request_irq failed for translation interrupt: %d\n", 3175ef3166eSFrederic Barrat rc); 318759bc015SGreg Kurz rc = -EINVAL; 319759bc015SGreg Kurz goto err_mapping; 3205ef3166eSFrederic Barrat } 3215ef3166eSFrederic Barrat return 0; 322759bc015SGreg Kurz 323759bc015SGreg Kurz err_mapping: 324759bc015SGreg Kurz irq_dispose_mapping(spa->virq); 325759bc015SGreg Kurz err_name: 326759bc015SGreg Kurz kfree(spa->irq_name); 327759bc015SGreg Kurz err_xsl: 328759bc015SGreg Kurz unmap_irq_registers(spa); 329759bc015SGreg Kurz return rc; 3305ef3166eSFrederic Barrat } 3315ef3166eSFrederic Barrat 3329c4ae064SAlastair D'Silva static void release_xsl_irq(struct ocxl_link *link) 3335ef3166eSFrederic Barrat { 3345ef3166eSFrederic Barrat struct spa *spa = link->spa; 3355ef3166eSFrederic Barrat 3365ef3166eSFrederic Barrat if (spa->virq) { 3375ef3166eSFrederic Barrat free_irq(spa->virq, link); 3385ef3166eSFrederic Barrat irq_dispose_mapping(spa->virq); 3395ef3166eSFrederic Barrat } 3405ef3166eSFrederic Barrat kfree(spa->irq_name); 3415ef3166eSFrederic Barrat unmap_irq_registers(spa); 3425ef3166eSFrederic Barrat } 3435ef3166eSFrederic Barrat 3449c4ae064SAlastair D'Silva static int alloc_spa(struct pci_dev *dev, struct ocxl_link *link) 3455ef3166eSFrederic Barrat { 3465ef3166eSFrederic Barrat struct spa *spa; 3475ef3166eSFrederic Barrat 3485ef3166eSFrederic Barrat spa = kzalloc(sizeof(struct spa), GFP_KERNEL); 3495ef3166eSFrederic Barrat if (!spa) 3505ef3166eSFrederic Barrat return -ENOMEM; 3515ef3166eSFrederic Barrat 3525ef3166eSFrederic Barrat mutex_init(&spa->spa_lock); 3535ef3166eSFrederic Barrat INIT_RADIX_TREE(&spa->pe_tree, GFP_KERNEL); 3545ef3166eSFrederic Barrat INIT_WORK(&spa->xsl_fault.fault_work, xsl_fault_handler_bh); 3555ef3166eSFrederic Barrat 3565ef3166eSFrederic Barrat spa->spa_order = SPA_SPA_SIZE_LOG - PAGE_SHIFT; 3575ef3166eSFrederic Barrat spa->spa_mem = (struct ocxl_process_element *) 3585ef3166eSFrederic Barrat __get_free_pages(GFP_KERNEL | __GFP_ZERO, spa->spa_order); 3595ef3166eSFrederic Barrat if (!spa->spa_mem) { 3605ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't allocate Shared Process Area\n"); 3615ef3166eSFrederic Barrat kfree(spa); 3625ef3166eSFrederic Barrat return -ENOMEM; 3635ef3166eSFrederic Barrat } 3645ef3166eSFrederic Barrat pr_debug("Allocated SPA for %x:%x:%x at %p\n", link->domain, link->bus, 3655ef3166eSFrederic Barrat link->dev, spa->spa_mem); 3665ef3166eSFrederic Barrat 3675ef3166eSFrederic Barrat link->spa = spa; 3685ef3166eSFrederic Barrat return 0; 3695ef3166eSFrederic Barrat } 3705ef3166eSFrederic Barrat 3719c4ae064SAlastair D'Silva static void free_spa(struct ocxl_link *link) 3725ef3166eSFrederic Barrat { 3735ef3166eSFrederic Barrat struct spa *spa = link->spa; 3745ef3166eSFrederic Barrat 3755ef3166eSFrederic Barrat pr_debug("Freeing SPA for %x:%x:%x\n", link->domain, link->bus, 3765ef3166eSFrederic Barrat link->dev); 3775ef3166eSFrederic Barrat 3785ef3166eSFrederic Barrat if (spa && spa->spa_mem) { 3795ef3166eSFrederic Barrat free_pages((unsigned long) spa->spa_mem, spa->spa_order); 3805ef3166eSFrederic Barrat kfree(spa); 3815ef3166eSFrederic Barrat link->spa = NULL; 3825ef3166eSFrederic Barrat } 3835ef3166eSFrederic Barrat } 3845ef3166eSFrederic Barrat 3859c4ae064SAlastair D'Silva static int alloc_link(struct pci_dev *dev, int PE_mask, struct ocxl_link **out_link) 3865ef3166eSFrederic Barrat { 3879c4ae064SAlastair D'Silva struct ocxl_link *link; 3885ef3166eSFrederic Barrat int rc; 3895ef3166eSFrederic Barrat 3909c4ae064SAlastair D'Silva link = kzalloc(sizeof(struct ocxl_link), GFP_KERNEL); 3915ef3166eSFrederic Barrat if (!link) 3925ef3166eSFrederic Barrat return -ENOMEM; 3935ef3166eSFrederic Barrat 3945ef3166eSFrederic Barrat kref_init(&link->ref); 3955ef3166eSFrederic Barrat link->domain = pci_domain_nr(dev->bus); 3965ef3166eSFrederic Barrat link->bus = dev->bus->number; 3975ef3166eSFrederic Barrat link->dev = PCI_SLOT(dev->devfn); 3985ef3166eSFrederic Barrat atomic_set(&link->irq_available, MAX_IRQ_PER_LINK); 3995f686eeaSChristophe Lombard spin_lock_init(&link->atsd_lock); 4005ef3166eSFrederic Barrat 4015ef3166eSFrederic Barrat rc = alloc_spa(dev, link); 4025ef3166eSFrederic Barrat if (rc) 4035ef3166eSFrederic Barrat goto err_free; 4045ef3166eSFrederic Barrat 4055ef3166eSFrederic Barrat rc = setup_xsl_irq(dev, link); 4065ef3166eSFrederic Barrat if (rc) 4075ef3166eSFrederic Barrat goto err_spa; 4085ef3166eSFrederic Barrat 4095ef3166eSFrederic Barrat /* platform specific hook */ 4105ef3166eSFrederic Barrat rc = pnv_ocxl_spa_setup(dev, link->spa->spa_mem, PE_mask, 4115ef3166eSFrederic Barrat &link->platform_data); 4125ef3166eSFrederic Barrat if (rc) 4135ef3166eSFrederic Barrat goto err_xsl_irq; 4145ef3166eSFrederic Barrat 4155f686eeaSChristophe Lombard /* if link->arva is not defeined, MMIO registers are not used to 4165f686eeaSChristophe Lombard * generate TLB invalidate. PowerBus snooping is enabled. 4175f686eeaSChristophe Lombard * Otherwise, PowerBus snooping is disabled. TLB Invalidates are 4185f686eeaSChristophe Lombard * initiated using MMIO registers. 4195f686eeaSChristophe Lombard */ 4205f686eeaSChristophe Lombard pnv_ocxl_map_lpar(dev, mfspr(SPRN_LPID), 0, &link->arva); 4215f686eeaSChristophe Lombard 4225ef3166eSFrederic Barrat *out_link = link; 4235ef3166eSFrederic Barrat return 0; 4245ef3166eSFrederic Barrat 4255ef3166eSFrederic Barrat err_xsl_irq: 4265ef3166eSFrederic Barrat release_xsl_irq(link); 4275ef3166eSFrederic Barrat err_spa: 4285ef3166eSFrederic Barrat free_spa(link); 4295ef3166eSFrederic Barrat err_free: 4305ef3166eSFrederic Barrat kfree(link); 4315ef3166eSFrederic Barrat return rc; 4325ef3166eSFrederic Barrat } 4335ef3166eSFrederic Barrat 4349c4ae064SAlastair D'Silva static void free_link(struct ocxl_link *link) 4355ef3166eSFrederic Barrat { 4365ef3166eSFrederic Barrat release_xsl_irq(link); 4375ef3166eSFrederic Barrat free_spa(link); 4385ef3166eSFrederic Barrat kfree(link); 4395ef3166eSFrederic Barrat } 4405ef3166eSFrederic Barrat 4415ef3166eSFrederic Barrat int ocxl_link_setup(struct pci_dev *dev, int PE_mask, void **link_handle) 4425ef3166eSFrederic Barrat { 4435ef3166eSFrederic Barrat int rc = 0; 4449c4ae064SAlastair D'Silva struct ocxl_link *link; 4455ef3166eSFrederic Barrat 4465ef3166eSFrederic Barrat mutex_lock(&links_list_lock); 4475ef3166eSFrederic Barrat list_for_each_entry(link, &links_list, list) { 4485ef3166eSFrederic Barrat /* The functions of a device all share the same link */ 4495ef3166eSFrederic Barrat if (link->domain == pci_domain_nr(dev->bus) && 4505ef3166eSFrederic Barrat link->bus == dev->bus->number && 4515ef3166eSFrederic Barrat link->dev == PCI_SLOT(dev->devfn)) { 4525ef3166eSFrederic Barrat kref_get(&link->ref); 4535ef3166eSFrederic Barrat *link_handle = link; 4545ef3166eSFrederic Barrat goto unlock; 4555ef3166eSFrederic Barrat } 4565ef3166eSFrederic Barrat } 4575ef3166eSFrederic Barrat rc = alloc_link(dev, PE_mask, &link); 4585ef3166eSFrederic Barrat if (rc) 4595ef3166eSFrederic Barrat goto unlock; 4605ef3166eSFrederic Barrat 4615ef3166eSFrederic Barrat list_add(&link->list, &links_list); 4625ef3166eSFrederic Barrat *link_handle = link; 4635ef3166eSFrederic Barrat unlock: 4645ef3166eSFrederic Barrat mutex_unlock(&links_list_lock); 4655ef3166eSFrederic Barrat return rc; 4665ef3166eSFrederic Barrat } 467280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_setup); 4685ef3166eSFrederic Barrat 4695ef3166eSFrederic Barrat static void release_xsl(struct kref *ref) 4705ef3166eSFrederic Barrat { 4719c4ae064SAlastair D'Silva struct ocxl_link *link = container_of(ref, struct ocxl_link, ref); 4725ef3166eSFrederic Barrat 4735f686eeaSChristophe Lombard if (link->arva) { 4745f686eeaSChristophe Lombard pnv_ocxl_unmap_lpar(link->arva); 4755f686eeaSChristophe Lombard link->arva = NULL; 4765f686eeaSChristophe Lombard } 4775f686eeaSChristophe Lombard 4785ef3166eSFrederic Barrat list_del(&link->list); 4795ef3166eSFrederic Barrat /* call platform code before releasing data */ 4805ef3166eSFrederic Barrat pnv_ocxl_spa_release(link->platform_data); 4815ef3166eSFrederic Barrat free_link(link); 4825ef3166eSFrederic Barrat } 4835ef3166eSFrederic Barrat 4845ef3166eSFrederic Barrat void ocxl_link_release(struct pci_dev *dev, void *link_handle) 4855ef3166eSFrederic Barrat { 4869c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 4875ef3166eSFrederic Barrat 4885ef3166eSFrederic Barrat mutex_lock(&links_list_lock); 4895ef3166eSFrederic Barrat kref_put(&link->ref, release_xsl); 4905ef3166eSFrederic Barrat mutex_unlock(&links_list_lock); 4915ef3166eSFrederic Barrat } 492280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_release); 4935ef3166eSFrederic Barrat 4945f686eeaSChristophe Lombard static void invalidate_range(struct mmu_notifier *mn, 4955f686eeaSChristophe Lombard struct mm_struct *mm, 4965f686eeaSChristophe Lombard unsigned long start, unsigned long end) 4975f686eeaSChristophe Lombard { 4985f686eeaSChristophe Lombard struct pe_data *pe_data = container_of(mn, struct pe_data, mmu_notifier); 4995f686eeaSChristophe Lombard struct ocxl_link *link = pe_data->link; 5005f686eeaSChristophe Lombard unsigned long addr, pid, page_size = PAGE_SIZE; 5015f686eeaSChristophe Lombard 5025f686eeaSChristophe Lombard pid = mm->context.id; 50398f5559aSChristophe Lombard trace_ocxl_mmu_notifier_range(start, end, pid); 5045f686eeaSChristophe Lombard 5055f686eeaSChristophe Lombard spin_lock(&link->atsd_lock); 5065f686eeaSChristophe Lombard for (addr = start; addr < end; addr += page_size) 5075f686eeaSChristophe Lombard pnv_ocxl_tlb_invalidate(link->arva, pid, addr, page_size); 5085f686eeaSChristophe Lombard spin_unlock(&link->atsd_lock); 5095f686eeaSChristophe Lombard } 5105f686eeaSChristophe Lombard 5115f686eeaSChristophe Lombard static const struct mmu_notifier_ops ocxl_mmu_notifier_ops = { 5125f686eeaSChristophe Lombard .invalidate_range = invalidate_range, 5135f686eeaSChristophe Lombard }; 5145f686eeaSChristophe Lombard 5155ef3166eSFrederic Barrat static u64 calculate_cfg_state(bool kernel) 5165ef3166eSFrederic Barrat { 5175ef3166eSFrederic Barrat u64 state; 5185ef3166eSFrederic Barrat 5195ef3166eSFrederic Barrat state = SPA_CFG_DR; 5205ef3166eSFrederic Barrat if (mfspr(SPRN_LPCR) & LPCR_TC) 5215ef3166eSFrederic Barrat state |= SPA_CFG_TC; 5225ef3166eSFrederic Barrat if (radix_enabled()) 5235ef3166eSFrederic Barrat state |= SPA_CFG_XLAT_ror; 5245ef3166eSFrederic Barrat else 5255ef3166eSFrederic Barrat state |= SPA_CFG_XLAT_hpt; 5265ef3166eSFrederic Barrat state |= SPA_CFG_HV; 5275ef3166eSFrederic Barrat if (kernel) { 5285ef3166eSFrederic Barrat if (mfmsr() & MSR_SF) 5295ef3166eSFrederic Barrat state |= SPA_CFG_SF; 5305ef3166eSFrederic Barrat } else { 5315ef3166eSFrederic Barrat state |= SPA_CFG_PR; 5325ef3166eSFrederic Barrat if (!test_tsk_thread_flag(current, TIF_32BIT)) 5335ef3166eSFrederic Barrat state |= SPA_CFG_SF; 5345ef3166eSFrederic Barrat } 5355ef3166eSFrederic Barrat return state; 5365ef3166eSFrederic Barrat } 5375ef3166eSFrederic Barrat 5385ef3166eSFrederic Barrat int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr, 539d731feeaSChristophe Lombard u64 amr, u16 bdf, struct mm_struct *mm, 5405ef3166eSFrederic Barrat void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr), 5415ef3166eSFrederic Barrat void *xsl_err_data) 5425ef3166eSFrederic Barrat { 5439c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 5445ef3166eSFrederic Barrat struct spa *spa = link->spa; 5455ef3166eSFrederic Barrat struct ocxl_process_element *pe; 5465ef3166eSFrederic Barrat int pe_handle, rc = 0; 5475ef3166eSFrederic Barrat struct pe_data *pe_data; 5485ef3166eSFrederic Barrat 5495ef3166eSFrederic Barrat BUILD_BUG_ON(sizeof(struct ocxl_process_element) != 128); 5505ef3166eSFrederic Barrat if (pasid > SPA_PASID_MAX) 5515ef3166eSFrederic Barrat return -EINVAL; 5525ef3166eSFrederic Barrat 5535ef3166eSFrederic Barrat mutex_lock(&spa->spa_lock); 5545ef3166eSFrederic Barrat pe_handle = pasid & SPA_PE_MASK; 5555ef3166eSFrederic Barrat pe = spa->spa_mem + pe_handle; 5565ef3166eSFrederic Barrat 5575ef3166eSFrederic Barrat if (pe->software_state) { 5585ef3166eSFrederic Barrat rc = -EBUSY; 5595ef3166eSFrederic Barrat goto unlock; 5605ef3166eSFrederic Barrat } 5615ef3166eSFrederic Barrat 5625ef3166eSFrederic Barrat pe_data = kmalloc(sizeof(*pe_data), GFP_KERNEL); 5635ef3166eSFrederic Barrat if (!pe_data) { 5645ef3166eSFrederic Barrat rc = -ENOMEM; 5655ef3166eSFrederic Barrat goto unlock; 5665ef3166eSFrederic Barrat } 5675ef3166eSFrederic Barrat 5685ef3166eSFrederic Barrat pe_data->mm = mm; 5695ef3166eSFrederic Barrat pe_data->xsl_err_cb = xsl_err_cb; 5705ef3166eSFrederic Barrat pe_data->xsl_err_data = xsl_err_data; 5715f686eeaSChristophe Lombard pe_data->link = link; 5725f686eeaSChristophe Lombard pe_data->mmu_notifier.ops = &ocxl_mmu_notifier_ops; 5735ef3166eSFrederic Barrat 5745ef3166eSFrederic Barrat memset(pe, 0, sizeof(struct ocxl_process_element)); 5755ef3166eSFrederic Barrat pe->config_state = cpu_to_be64(calculate_cfg_state(pidr == 0)); 576d731feeaSChristophe Lombard pe->pasid = cpu_to_be32(pasid << (31 - 19)); 577d731feeaSChristophe Lombard pe->bdf = cpu_to_be16(bdf); 5785ef3166eSFrederic Barrat pe->lpid = cpu_to_be32(mfspr(SPRN_LPID)); 5795ef3166eSFrederic Barrat pe->pid = cpu_to_be32(pidr); 5805ef3166eSFrederic Barrat pe->tid = cpu_to_be32(tidr); 5815ef3166eSFrederic Barrat pe->amr = cpu_to_be64(amr); 5825ef3166eSFrederic Barrat pe->software_state = cpu_to_be32(SPA_PE_VALID); 5835ef3166eSFrederic Barrat 58460e8523eSAlastair D'Silva /* 58560e8523eSAlastair D'Silva * For user contexts, register a copro so that TLBIs are seen 58660e8523eSAlastair D'Silva * by the nest MMU. If we have a kernel context, TLBIs are 58760e8523eSAlastair D'Silva * already global. 58860e8523eSAlastair D'Silva */ 5895f686eeaSChristophe Lombard if (mm) { 5905ef3166eSFrederic Barrat mm_context_add_copro(mm); 5915f686eeaSChristophe Lombard if (link->arva) { 5925f686eeaSChristophe Lombard /* Use MMIO registers for the TLB Invalidate 5935f686eeaSChristophe Lombard * operations. 5945f686eeaSChristophe Lombard */ 59598f5559aSChristophe Lombard trace_ocxl_init_mmu_notifier(pasid, mm->context.id); 5965f686eeaSChristophe Lombard mmu_notifier_register(&pe_data->mmu_notifier, mm); 5975f686eeaSChristophe Lombard } 5985f686eeaSChristophe Lombard } 5995f686eeaSChristophe Lombard 6005ef3166eSFrederic Barrat /* 6015ef3166eSFrederic Barrat * Barrier is to make sure PE is visible in the SPA before it 6025ef3166eSFrederic Barrat * is used by the device. It also helps with the global TLBI 6035ef3166eSFrederic Barrat * invalidation 6045ef3166eSFrederic Barrat */ 6055ef3166eSFrederic Barrat mb(); 6065ef3166eSFrederic Barrat radix_tree_insert(&spa->pe_tree, pe_handle, pe_data); 6075ef3166eSFrederic Barrat 6085ef3166eSFrederic Barrat /* 6095ef3166eSFrederic Barrat * The mm must stay valid for as long as the device uses it. We 6105ef3166eSFrederic Barrat * lower the count when the context is removed from the SPA. 6115ef3166eSFrederic Barrat * 6125ef3166eSFrederic Barrat * We grab mm_count (and not mm_users), as we don't want to 6135ef3166eSFrederic Barrat * end up in a circular dependency if a process mmaps its 6145ef3166eSFrederic Barrat * mmio, therefore incrementing the file ref count when 6155ef3166eSFrederic Barrat * calling mmap(), and forgets to unmap before exiting. In 6165ef3166eSFrederic Barrat * that scenario, when the kernel handles the death of the 6175ef3166eSFrederic Barrat * process, the file is not cleaned because unmap was not 6185ef3166eSFrederic Barrat * called, and the mm wouldn't be freed because we would still 6195ef3166eSFrederic Barrat * have a reference on mm_users. Incrementing mm_count solves 6205ef3166eSFrederic Barrat * the problem. 6215ef3166eSFrederic Barrat */ 62260e8523eSAlastair D'Silva if (mm) 6235ef3166eSFrederic Barrat mmgrab(mm); 62492add22eSFrederic Barrat trace_ocxl_context_add(current->pid, spa->spa_mem, pasid, pidr, tidr); 6255ef3166eSFrederic Barrat unlock: 6265ef3166eSFrederic Barrat mutex_unlock(&spa->spa_lock); 6275ef3166eSFrederic Barrat return rc; 6285ef3166eSFrederic Barrat } 629280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_add_pe); 6305ef3166eSFrederic Barrat 631e948e06fSAlastair D'Silva int ocxl_link_update_pe(void *link_handle, int pasid, __u16 tid) 632e948e06fSAlastair D'Silva { 6339c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 634e948e06fSAlastair D'Silva struct spa *spa = link->spa; 635e948e06fSAlastair D'Silva struct ocxl_process_element *pe; 636e948e06fSAlastair D'Silva int pe_handle, rc; 637e948e06fSAlastair D'Silva 638e948e06fSAlastair D'Silva if (pasid > SPA_PASID_MAX) 639e948e06fSAlastair D'Silva return -EINVAL; 640e948e06fSAlastair D'Silva 641e948e06fSAlastair D'Silva pe_handle = pasid & SPA_PE_MASK; 642e948e06fSAlastair D'Silva pe = spa->spa_mem + pe_handle; 643e948e06fSAlastair D'Silva 644e948e06fSAlastair D'Silva mutex_lock(&spa->spa_lock); 645e948e06fSAlastair D'Silva 646e1e71e20SGreg Kurz pe->tid = cpu_to_be32(tid); 647e948e06fSAlastair D'Silva 648e948e06fSAlastair D'Silva /* 649e948e06fSAlastair D'Silva * The barrier makes sure the PE is updated 650e948e06fSAlastair D'Silva * before we clear the NPU context cache below, so that the 651e948e06fSAlastair D'Silva * old PE cannot be reloaded erroneously. 652e948e06fSAlastair D'Silva */ 653e948e06fSAlastair D'Silva mb(); 654e948e06fSAlastair D'Silva 655e948e06fSAlastair D'Silva /* 656e948e06fSAlastair D'Silva * hook to platform code 657e948e06fSAlastair D'Silva * On powerpc, the entry needs to be cleared from the context 658e948e06fSAlastair D'Silva * cache of the NPU. 659e948e06fSAlastair D'Silva */ 660e948e06fSAlastair D'Silva rc = pnv_ocxl_spa_remove_pe_from_cache(link->platform_data, pe_handle); 661e948e06fSAlastair D'Silva WARN_ON(rc); 662e948e06fSAlastair D'Silva 663e948e06fSAlastair D'Silva mutex_unlock(&spa->spa_lock); 664e948e06fSAlastair D'Silva return rc; 665e948e06fSAlastair D'Silva } 666e948e06fSAlastair D'Silva 6675ef3166eSFrederic Barrat int ocxl_link_remove_pe(void *link_handle, int pasid) 6685ef3166eSFrederic Barrat { 6699c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 6705ef3166eSFrederic Barrat struct spa *spa = link->spa; 6715ef3166eSFrederic Barrat struct ocxl_process_element *pe; 6725ef3166eSFrederic Barrat struct pe_data *pe_data; 6735ef3166eSFrederic Barrat int pe_handle, rc; 6745ef3166eSFrederic Barrat 6755ef3166eSFrederic Barrat if (pasid > SPA_PASID_MAX) 6765ef3166eSFrederic Barrat return -EINVAL; 6775ef3166eSFrederic Barrat 6785ef3166eSFrederic Barrat /* 6795ef3166eSFrederic Barrat * About synchronization with our memory fault handler: 6805ef3166eSFrederic Barrat * 6815ef3166eSFrederic Barrat * Before removing the PE, the driver is supposed to have 6825ef3166eSFrederic Barrat * notified the AFU, which should have cleaned up and make 6835ef3166eSFrederic Barrat * sure the PASID is no longer in use, including pending 6845ef3166eSFrederic Barrat * interrupts. However, there's no way to be sure... 6855ef3166eSFrederic Barrat * 6865ef3166eSFrederic Barrat * We clear the PE and remove the context from our radix 6875ef3166eSFrederic Barrat * tree. From that point on, any new interrupt for that 6885ef3166eSFrederic Barrat * context will fail silently, which is ok. As mentioned 6895ef3166eSFrederic Barrat * above, that's not expected, but it could happen if the 6905ef3166eSFrederic Barrat * driver or AFU didn't do the right thing. 6915ef3166eSFrederic Barrat * 6925ef3166eSFrederic Barrat * There could still be a bottom half running, but we don't 6935ef3166eSFrederic Barrat * need to wait/flush, as it is managing a reference count on 6945ef3166eSFrederic Barrat * the mm it reads from the radix tree. 6955ef3166eSFrederic Barrat */ 6965ef3166eSFrederic Barrat pe_handle = pasid & SPA_PE_MASK; 6975ef3166eSFrederic Barrat pe = spa->spa_mem + pe_handle; 6985ef3166eSFrederic Barrat 6995ef3166eSFrederic Barrat mutex_lock(&spa->spa_lock); 7005ef3166eSFrederic Barrat 7015ef3166eSFrederic Barrat if (!(be32_to_cpu(pe->software_state) & SPA_PE_VALID)) { 7025ef3166eSFrederic Barrat rc = -EINVAL; 7035ef3166eSFrederic Barrat goto unlock; 7045ef3166eSFrederic Barrat } 7055ef3166eSFrederic Barrat 70692add22eSFrederic Barrat trace_ocxl_context_remove(current->pid, spa->spa_mem, pasid, 70792add22eSFrederic Barrat be32_to_cpu(pe->pid), be32_to_cpu(pe->tid)); 70892add22eSFrederic Barrat 7095ef3166eSFrederic Barrat memset(pe, 0, sizeof(struct ocxl_process_element)); 7105ef3166eSFrederic Barrat /* 7115ef3166eSFrederic Barrat * The barrier makes sure the PE is removed from the SPA 7125ef3166eSFrederic Barrat * before we clear the NPU context cache below, so that the 7135ef3166eSFrederic Barrat * old PE cannot be reloaded erroneously. 7145ef3166eSFrederic Barrat */ 7155ef3166eSFrederic Barrat mb(); 7165ef3166eSFrederic Barrat 7175ef3166eSFrederic Barrat /* 7185ef3166eSFrederic Barrat * hook to platform code 7195ef3166eSFrederic Barrat * On powerpc, the entry needs to be cleared from the context 7205ef3166eSFrederic Barrat * cache of the NPU. 7215ef3166eSFrederic Barrat */ 72219df3958SAlastair D'Silva rc = pnv_ocxl_spa_remove_pe_from_cache(link->platform_data, pe_handle); 7235ef3166eSFrederic Barrat WARN_ON(rc); 7245ef3166eSFrederic Barrat 7255ef3166eSFrederic Barrat pe_data = radix_tree_delete(&spa->pe_tree, pe_handle); 7265ef3166eSFrederic Barrat if (!pe_data) { 7275ef3166eSFrederic Barrat WARN(1, "Couldn't find pe data when removing PE\n"); 7285ef3166eSFrederic Barrat } else { 72960e8523eSAlastair D'Silva if (pe_data->mm) { 7305f686eeaSChristophe Lombard if (link->arva) { 73198f5559aSChristophe Lombard trace_ocxl_release_mmu_notifier(pasid, 73298f5559aSChristophe Lombard pe_data->mm->context.id); 7335f686eeaSChristophe Lombard mmu_notifier_unregister(&pe_data->mmu_notifier, 7345f686eeaSChristophe Lombard pe_data->mm); 7355f686eeaSChristophe Lombard spin_lock(&link->atsd_lock); 7365f686eeaSChristophe Lombard pnv_ocxl_tlb_invalidate(link->arva, 7375f686eeaSChristophe Lombard pe_data->mm->context.id, 7385f686eeaSChristophe Lombard 0ull, 7395f686eeaSChristophe Lombard PAGE_SIZE); 7405f686eeaSChristophe Lombard spin_unlock(&link->atsd_lock); 7415f686eeaSChristophe Lombard } 7425ef3166eSFrederic Barrat mm_context_remove_copro(pe_data->mm); 7435ef3166eSFrederic Barrat mmdrop(pe_data->mm); 74460e8523eSAlastair D'Silva } 7455ef3166eSFrederic Barrat kfree_rcu(pe_data, rcu); 7465ef3166eSFrederic Barrat } 7475ef3166eSFrederic Barrat unlock: 7485ef3166eSFrederic Barrat mutex_unlock(&spa->spa_lock); 7495ef3166eSFrederic Barrat return rc; 7505ef3166eSFrederic Barrat } 751280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_remove_pe); 752aeddad17SFrederic Barrat 753dde6f18aSFrederic Barrat int ocxl_link_irq_alloc(void *link_handle, int *hw_irq) 754aeddad17SFrederic Barrat { 7559c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 756dde6f18aSFrederic Barrat int irq; 757aeddad17SFrederic Barrat 758aeddad17SFrederic Barrat if (atomic_dec_if_positive(&link->irq_available) < 0) 759aeddad17SFrederic Barrat return -ENOSPC; 760aeddad17SFrederic Barrat 761dde6f18aSFrederic Barrat irq = xive_native_alloc_irq(); 762dde6f18aSFrederic Barrat if (!irq) { 763aeddad17SFrederic Barrat atomic_inc(&link->irq_available); 764dde6f18aSFrederic Barrat return -ENXIO; 765aeddad17SFrederic Barrat } 766aeddad17SFrederic Barrat 767aeddad17SFrederic Barrat *hw_irq = irq; 768aeddad17SFrederic Barrat return 0; 769aeddad17SFrederic Barrat } 770280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_irq_alloc); 771aeddad17SFrederic Barrat 772aeddad17SFrederic Barrat void ocxl_link_free_irq(void *link_handle, int hw_irq) 773aeddad17SFrederic Barrat { 7749c4ae064SAlastair D'Silva struct ocxl_link *link = (struct ocxl_link *) link_handle; 775aeddad17SFrederic Barrat 776dde6f18aSFrederic Barrat xive_native_free_irq(hw_irq); 777aeddad17SFrederic Barrat atomic_inc(&link->irq_available); 778aeddad17SFrederic Barrat } 779280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_link_free_irq); 780