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