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