1*f456834aSIan Munsie /* 2*f456834aSIan Munsie * Copyright 2014-2016 IBM Corp. 3*f456834aSIan Munsie * 4*f456834aSIan Munsie * This program is free software; you can redistribute it and/or 5*f456834aSIan Munsie * modify it under the terms of the GNU General Public License 6*f456834aSIan Munsie * as published by the Free Software Foundation; either version 7*f456834aSIan Munsie * 2 of the License, or (at your option) any later version. 8*f456834aSIan Munsie */ 9*f456834aSIan Munsie 10*f456834aSIan Munsie #include <asm/pnv-pci.h> 11*f456834aSIan Munsie #include <asm/opal.h> 12*f456834aSIan Munsie 13*f456834aSIan Munsie #include "pci.h" 14*f456834aSIan Munsie 15*f456834aSIan Munsie struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev) 16*f456834aSIan Munsie { 17*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 18*f456834aSIan Munsie 19*f456834aSIan Munsie return of_node_get(hose->dn); 20*f456834aSIan Munsie } 21*f456834aSIan Munsie EXPORT_SYMBOL(pnv_pci_get_phb_node); 22*f456834aSIan Munsie 23*f456834aSIan Munsie int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode) 24*f456834aSIan Munsie { 25*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 26*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 27*f456834aSIan Munsie struct pnv_ioda_pe *pe; 28*f456834aSIan Munsie int rc; 29*f456834aSIan Munsie 30*f456834aSIan Munsie pe = pnv_ioda_get_pe(dev); 31*f456834aSIan Munsie if (!pe) 32*f456834aSIan Munsie return -ENODEV; 33*f456834aSIan Munsie 34*f456834aSIan Munsie pe_info(pe, "Switching PHB to CXL\n"); 35*f456834aSIan Munsie 36*f456834aSIan Munsie rc = opal_pci_set_phb_cxl_mode(phb->opal_id, mode, pe->pe_number); 37*f456834aSIan Munsie if (rc == OPAL_UNSUPPORTED) 38*f456834aSIan Munsie dev_err(&dev->dev, "Required cxl mode not supported by firmware - update skiboot\n"); 39*f456834aSIan Munsie else if (rc) 40*f456834aSIan Munsie dev_err(&dev->dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc); 41*f456834aSIan Munsie 42*f456834aSIan Munsie return rc; 43*f456834aSIan Munsie } 44*f456834aSIan Munsie EXPORT_SYMBOL(pnv_phb_to_cxl_mode); 45*f456834aSIan Munsie 46*f456834aSIan Munsie /* Find PHB for cxl dev and allocate MSI hwirqs? 47*f456834aSIan Munsie * Returns the absolute hardware IRQ number 48*f456834aSIan Munsie */ 49*f456834aSIan Munsie int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num) 50*f456834aSIan Munsie { 51*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 52*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 53*f456834aSIan Munsie int hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, num); 54*f456834aSIan Munsie 55*f456834aSIan Munsie if (hwirq < 0) { 56*f456834aSIan Munsie dev_warn(&dev->dev, "Failed to find a free MSI\n"); 57*f456834aSIan Munsie return -ENOSPC; 58*f456834aSIan Munsie } 59*f456834aSIan Munsie 60*f456834aSIan Munsie return phb->msi_base + hwirq; 61*f456834aSIan Munsie } 62*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs); 63*f456834aSIan Munsie 64*f456834aSIan Munsie void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num) 65*f456834aSIan Munsie { 66*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 67*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 68*f456834aSIan Munsie 69*f456834aSIan Munsie msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, num); 70*f456834aSIan Munsie } 71*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_release_hwirqs); 72*f456834aSIan Munsie 73*f456834aSIan Munsie void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, 74*f456834aSIan Munsie struct pci_dev *dev) 75*f456834aSIan Munsie { 76*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 77*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 78*f456834aSIan Munsie int i, hwirq; 79*f456834aSIan Munsie 80*f456834aSIan Munsie for (i = 1; i < CXL_IRQ_RANGES; i++) { 81*f456834aSIan Munsie if (!irqs->range[i]) 82*f456834aSIan Munsie continue; 83*f456834aSIan Munsie pr_devel("cxl release irq range 0x%x: offset: 0x%lx limit: %ld\n", 84*f456834aSIan Munsie i, irqs->offset[i], 85*f456834aSIan Munsie irqs->range[i]); 86*f456834aSIan Munsie hwirq = irqs->offset[i] - phb->msi_base; 87*f456834aSIan Munsie msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 88*f456834aSIan Munsie irqs->range[i]); 89*f456834aSIan Munsie } 90*f456834aSIan Munsie } 91*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_release_hwirq_ranges); 92*f456834aSIan Munsie 93*f456834aSIan Munsie int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, 94*f456834aSIan Munsie struct pci_dev *dev, int num) 95*f456834aSIan Munsie { 96*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 97*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 98*f456834aSIan Munsie int i, hwirq, try; 99*f456834aSIan Munsie 100*f456834aSIan Munsie memset(irqs, 0, sizeof(struct cxl_irq_ranges)); 101*f456834aSIan Munsie 102*f456834aSIan Munsie /* 0 is reserved for the multiplexed PSL DSI interrupt */ 103*f456834aSIan Munsie for (i = 1; i < CXL_IRQ_RANGES && num; i++) { 104*f456834aSIan Munsie try = num; 105*f456834aSIan Munsie while (try) { 106*f456834aSIan Munsie hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, try); 107*f456834aSIan Munsie if (hwirq >= 0) 108*f456834aSIan Munsie break; 109*f456834aSIan Munsie try /= 2; 110*f456834aSIan Munsie } 111*f456834aSIan Munsie if (!try) 112*f456834aSIan Munsie goto fail; 113*f456834aSIan Munsie 114*f456834aSIan Munsie irqs->offset[i] = phb->msi_base + hwirq; 115*f456834aSIan Munsie irqs->range[i] = try; 116*f456834aSIan Munsie pr_devel("cxl alloc irq range 0x%x: offset: 0x%lx limit: %li\n", 117*f456834aSIan Munsie i, irqs->offset[i], irqs->range[i]); 118*f456834aSIan Munsie num -= try; 119*f456834aSIan Munsie } 120*f456834aSIan Munsie if (num) 121*f456834aSIan Munsie goto fail; 122*f456834aSIan Munsie 123*f456834aSIan Munsie return 0; 124*f456834aSIan Munsie fail: 125*f456834aSIan Munsie pnv_cxl_release_hwirq_ranges(irqs, dev); 126*f456834aSIan Munsie return -ENOSPC; 127*f456834aSIan Munsie } 128*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_alloc_hwirq_ranges); 129*f456834aSIan Munsie 130*f456834aSIan Munsie int pnv_cxl_get_irq_count(struct pci_dev *dev) 131*f456834aSIan Munsie { 132*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 133*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 134*f456834aSIan Munsie 135*f456834aSIan Munsie return phb->msi_bmp.irq_count; 136*f456834aSIan Munsie } 137*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_get_irq_count); 138*f456834aSIan Munsie 139*f456834aSIan Munsie int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, 140*f456834aSIan Munsie unsigned int virq) 141*f456834aSIan Munsie { 142*f456834aSIan Munsie struct pci_controller *hose = pci_bus_to_host(dev->bus); 143*f456834aSIan Munsie struct pnv_phb *phb = hose->private_data; 144*f456834aSIan Munsie unsigned int xive_num = hwirq - phb->msi_base; 145*f456834aSIan Munsie struct pnv_ioda_pe *pe; 146*f456834aSIan Munsie int rc; 147*f456834aSIan Munsie 148*f456834aSIan Munsie if (!(pe = pnv_ioda_get_pe(dev))) 149*f456834aSIan Munsie return -ENODEV; 150*f456834aSIan Munsie 151*f456834aSIan Munsie /* Assign XIVE to PE */ 152*f456834aSIan Munsie rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num); 153*f456834aSIan Munsie if (rc) { 154*f456834aSIan Munsie pe_warn(pe, "%s: OPAL error %d setting msi_base 0x%x " 155*f456834aSIan Munsie "hwirq 0x%x XIVE 0x%x PE\n", 156*f456834aSIan Munsie pci_name(dev), rc, phb->msi_base, hwirq, xive_num); 157*f456834aSIan Munsie return -EIO; 158*f456834aSIan Munsie } 159*f456834aSIan Munsie pnv_set_msi_irq_chip(phb, virq); 160*f456834aSIan Munsie 161*f456834aSIan Munsie return 0; 162*f456834aSIan Munsie } 163*f456834aSIan Munsie EXPORT_SYMBOL(pnv_cxl_ioda_msi_setup); 164