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