vphb.c (7315B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright 2014 IBM Corp. 4 */ 5 6#include <linux/pci.h> 7#include <misc/cxl.h> 8#include "cxl.h" 9 10static int cxl_pci_probe_mode(struct pci_bus *bus) 11{ 12 return PCI_PROBE_NORMAL; 13} 14 15static int cxl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 16{ 17 return -ENODEV; 18} 19 20static void cxl_teardown_msi_irqs(struct pci_dev *pdev) 21{ 22 /* 23 * MSI should never be set but need still need to provide this call 24 * back. 25 */ 26} 27 28static bool cxl_pci_enable_device_hook(struct pci_dev *dev) 29{ 30 struct pci_controller *phb; 31 struct cxl_afu *afu; 32 struct cxl_context *ctx; 33 34 phb = pci_bus_to_host(dev->bus); 35 afu = (struct cxl_afu *)phb->private_data; 36 37 if (!cxl_ops->link_ok(afu->adapter, afu)) { 38 dev_warn(&dev->dev, "%s: Device link is down, refusing to enable AFU\n", __func__); 39 return false; 40 } 41 42 dev->dev.archdata.dma_offset = PAGE_OFFSET; 43 44 /* 45 * Allocate a context to do cxl things too. If we eventually do real 46 * DMA ops, we'll need a default context to attach them to 47 */ 48 ctx = cxl_dev_context_init(dev); 49 if (IS_ERR(ctx)) 50 return false; 51 dev->dev.archdata.cxl_ctx = ctx; 52 53 return (cxl_ops->afu_check_and_enable(afu) == 0); 54} 55 56static void cxl_pci_disable_device(struct pci_dev *dev) 57{ 58 struct cxl_context *ctx = cxl_get_context(dev); 59 60 if (ctx) { 61 if (ctx->status == STARTED) { 62 dev_err(&dev->dev, "Default context started\n"); 63 return; 64 } 65 dev->dev.archdata.cxl_ctx = NULL; 66 cxl_release_context(ctx); 67 } 68} 69 70static resource_size_t cxl_pci_window_alignment(struct pci_bus *bus, 71 unsigned long type) 72{ 73 return 1; 74} 75 76static void cxl_pci_reset_secondary_bus(struct pci_dev *dev) 77{ 78 /* Should we do an AFU reset here ? */ 79} 80 81static int cxl_pcie_cfg_record(u8 bus, u8 devfn) 82{ 83 return (bus << 8) + devfn; 84} 85 86static inline struct cxl_afu *pci_bus_to_afu(struct pci_bus *bus) 87{ 88 struct pci_controller *phb = bus ? pci_bus_to_host(bus) : NULL; 89 90 return phb ? phb->private_data : NULL; 91} 92 93static void cxl_afu_configured_put(struct cxl_afu *afu) 94{ 95 atomic_dec_if_positive(&afu->configured_state); 96} 97 98static bool cxl_afu_configured_get(struct cxl_afu *afu) 99{ 100 return atomic_inc_unless_negative(&afu->configured_state); 101} 102 103static inline int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn, 104 struct cxl_afu *afu, int *_record) 105{ 106 int record; 107 108 record = cxl_pcie_cfg_record(bus->number, devfn); 109 if (record > afu->crs_num) 110 return PCIBIOS_DEVICE_NOT_FOUND; 111 112 *_record = record; 113 return 0; 114} 115 116static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn, 117 int offset, int len, u32 *val) 118{ 119 int rc, record; 120 struct cxl_afu *afu; 121 u8 val8; 122 u16 val16; 123 u32 val32; 124 125 afu = pci_bus_to_afu(bus); 126 /* Grab a reader lock on afu. */ 127 if (afu == NULL || !cxl_afu_configured_get(afu)) 128 return PCIBIOS_DEVICE_NOT_FOUND; 129 130 rc = cxl_pcie_config_info(bus, devfn, afu, &record); 131 if (rc) 132 goto out; 133 134 switch (len) { 135 case 1: 136 rc = cxl_ops->afu_cr_read8(afu, record, offset, &val8); 137 *val = val8; 138 break; 139 case 2: 140 rc = cxl_ops->afu_cr_read16(afu, record, offset, &val16); 141 *val = val16; 142 break; 143 case 4: 144 rc = cxl_ops->afu_cr_read32(afu, record, offset, &val32); 145 *val = val32; 146 break; 147 default: 148 WARN_ON(1); 149 } 150 151out: 152 cxl_afu_configured_put(afu); 153 return rc ? PCIBIOS_DEVICE_NOT_FOUND : 0; 154} 155 156static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn, 157 int offset, int len, u32 val) 158{ 159 int rc, record; 160 struct cxl_afu *afu; 161 162 afu = pci_bus_to_afu(bus); 163 /* Grab a reader lock on afu. */ 164 if (afu == NULL || !cxl_afu_configured_get(afu)) 165 return PCIBIOS_DEVICE_NOT_FOUND; 166 167 rc = cxl_pcie_config_info(bus, devfn, afu, &record); 168 if (rc) 169 goto out; 170 171 switch (len) { 172 case 1: 173 rc = cxl_ops->afu_cr_write8(afu, record, offset, val & 0xff); 174 break; 175 case 2: 176 rc = cxl_ops->afu_cr_write16(afu, record, offset, val & 0xffff); 177 break; 178 case 4: 179 rc = cxl_ops->afu_cr_write32(afu, record, offset, val); 180 break; 181 default: 182 WARN_ON(1); 183 } 184 185out: 186 cxl_afu_configured_put(afu); 187 return rc ? PCIBIOS_SET_FAILED : 0; 188} 189 190static struct pci_ops cxl_pcie_pci_ops = 191{ 192 .read = cxl_pcie_read_config, 193 .write = cxl_pcie_write_config, 194}; 195 196 197static struct pci_controller_ops cxl_pci_controller_ops = 198{ 199 .probe_mode = cxl_pci_probe_mode, 200 .enable_device_hook = cxl_pci_enable_device_hook, 201 .disable_device = cxl_pci_disable_device, 202 .release_device = cxl_pci_disable_device, 203 .window_alignment = cxl_pci_window_alignment, 204 .reset_secondary_bus = cxl_pci_reset_secondary_bus, 205 .setup_msi_irqs = cxl_setup_msi_irqs, 206 .teardown_msi_irqs = cxl_teardown_msi_irqs, 207}; 208 209int cxl_pci_vphb_add(struct cxl_afu *afu) 210{ 211 struct pci_controller *phb; 212 struct device_node *vphb_dn; 213 struct device *parent; 214 215 /* 216 * If there are no AFU configuration records we won't have anything to 217 * expose under the vPHB, so skip creating one, returning success since 218 * this is still a valid case. This will also opt us out of EEH 219 * handling since we won't have anything special to do if there are no 220 * kernel drivers attached to the vPHB, and EEH handling is not yet 221 * supported in the peer model. 222 */ 223 if (!afu->crs_num) 224 return 0; 225 226 /* The parent device is the adapter. Reuse the device node of 227 * the adapter. 228 * We don't seem to care what device node is used for the vPHB, 229 * but tools such as lsvpd walk up the device parents looking 230 * for a valid location code, so we might as well show devices 231 * attached to the adapter as being located on that adapter. 232 */ 233 parent = afu->adapter->dev.parent; 234 vphb_dn = parent->of_node; 235 236 /* Alloc and setup PHB data structure */ 237 phb = pcibios_alloc_controller(vphb_dn); 238 if (!phb) 239 return -ENODEV; 240 241 /* Setup parent in sysfs */ 242 phb->parent = parent; 243 244 /* Setup the PHB using arch provided callback */ 245 phb->ops = &cxl_pcie_pci_ops; 246 phb->cfg_addr = NULL; 247 phb->cfg_data = NULL; 248 phb->private_data = afu; 249 phb->controller_ops = cxl_pci_controller_ops; 250 251 /* Scan the bus */ 252 pcibios_scan_phb(phb); 253 if (phb->bus == NULL) 254 return -ENXIO; 255 256 /* Set release hook on root bus */ 257 pci_set_host_bridge_release(to_pci_host_bridge(phb->bus->bridge), 258 pcibios_free_controller_deferred, 259 (void *) phb); 260 261 /* Claim resources. This might need some rework as well depending 262 * whether we are doing probe-only or not, like assigning unassigned 263 * resources etc... 264 */ 265 pcibios_claim_one_bus(phb->bus); 266 267 /* Add probed PCI devices to the device model */ 268 pci_bus_add_devices(phb->bus); 269 270 afu->phb = phb; 271 272 return 0; 273} 274 275void cxl_pci_vphb_remove(struct cxl_afu *afu) 276{ 277 struct pci_controller *phb; 278 279 /* If there is no configuration record we won't have one of these */ 280 if (!afu || !afu->phb) 281 return; 282 283 phb = afu->phb; 284 afu->phb = NULL; 285 286 pci_remove_root_bus(phb->bus); 287 /* 288 * We don't free phb here - that's handled by 289 * pcibios_free_controller_deferred() 290 */ 291} 292 293bool cxl_pci_is_vphb_device(struct pci_dev *dev) 294{ 295 struct pci_controller *phb; 296 297 phb = pci_bus_to_host(dev->bus); 298 299 return (phb->ops == &cxl_pcie_pci_ops); 300} 301 302struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev) 303{ 304 struct pci_controller *phb; 305 306 phb = pci_bus_to_host(dev->bus); 307 308 return (struct cxl_afu *)phb->private_data; 309} 310EXPORT_SYMBOL_GPL(cxl_pci_to_afu); 311 312unsigned int cxl_pci_to_cfg_record(struct pci_dev *dev) 313{ 314 return cxl_pcie_cfg_record(dev->bus->number, dev->devfn); 315} 316EXPORT_SYMBOL_GPL(cxl_pci_to_cfg_record);