xlp_pci.c revision 245877
1225394Sjchandra/*- 2233563Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation 3233563Sjchandra * All Rights Reserved 4225394Sjchandra * 5225394Sjchandra * Redistribution and use in source and binary forms, with or without 6225394Sjchandra * modification, are permitted provided that the following conditions 7225394Sjchandra * are met: 8233563Sjchandra * 9225394Sjchandra * 1. Redistributions of source code must retain the above copyright 10225394Sjchandra * notice, this list of conditions and the following disclaimer. 11225394Sjchandra * 2. Redistributions in binary form must reproduce the above copyright 12233563Sjchandra * notice, this list of conditions and the following disclaimer in 13233563Sjchandra * the documentation and/or other materials provided with the 14233563Sjchandra * distribution. 15233563Sjchandra * 16233563Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 17233563Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18233563Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19233563Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 20233563Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21233563Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22233563Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23233563Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24233563Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25233563Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26233563Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27233563Sjchandra */ 28233563Sjchandra 29225394Sjchandra#include <sys/cdefs.h> 30225394Sjchandra__FBSDID("$FreeBSD: head/sys/mips/nlm/xlp_pci.c 245877 2013-01-24 11:42:16Z jchandra $"); 31225394Sjchandra 32225394Sjchandra#include <sys/param.h> 33225394Sjchandra#include <sys/systm.h> 34225394Sjchandra#include <sys/types.h> 35225394Sjchandra#include <sys/kernel.h> 36225394Sjchandra#include <sys/module.h> 37225394Sjchandra#include <sys/malloc.h> 38225394Sjchandra#include <sys/bus.h> 39225394Sjchandra#include <sys/endian.h> 40225394Sjchandra#include <sys/rman.h> 41233563Sjchandra#include <sys/pciio.h> 42225394Sjchandra 43225394Sjchandra#include <vm/vm.h> 44225394Sjchandra#include <vm/vm_param.h> 45225394Sjchandra#include <vm/pmap.h> 46225394Sjchandra 47225394Sjchandra#include <dev/pci/pcivar.h> 48225394Sjchandra#include <dev/pci/pcireg.h> 49233563Sjchandra#include <dev/pci/pci_private.h> 50233563Sjchandra 51225394Sjchandra#include <dev/uart/uart.h> 52225394Sjchandra#include <dev/uart/uart_bus.h> 53225394Sjchandra#include <dev/uart/uart_cpu.h> 54225394Sjchandra 55225394Sjchandra#include <machine/bus.h> 56225394Sjchandra#include <machine/md_var.h> 57225394Sjchandra#include <machine/intr_machdep.h> 58225394Sjchandra#include <machine/cpuregs.h> 59225394Sjchandra 60225394Sjchandra#include <mips/nlm/hal/haldefs.h> 61225394Sjchandra#include <mips/nlm/interrupt.h> 62225394Sjchandra#include <mips/nlm/hal/iomap.h> 63225394Sjchandra#include <mips/nlm/hal/mips-extns.h> 64225394Sjchandra#include <mips/nlm/hal/pic.h> 65233536Sjchandra#include <mips/nlm/hal/bridge.h> 66233556Sjchandra#include <mips/nlm/hal/gbu.h> 67225394Sjchandra#include <mips/nlm/hal/pcibus.h> 68225394Sjchandra#include <mips/nlm/hal/uart.h> 69225394Sjchandra#include <mips/nlm/xlp.h> 70225394Sjchandra 71225394Sjchandra#include "pcib_if.h" 72233563Sjchandra#include "pci_if.h" 73225394Sjchandra 74233563Sjchandra#define EMUL_MEM_START 0x16000000UL 75233563Sjchandra#define EMUL_MEM_END 0x18ffffffUL 76233563Sjchandra 77233563Sjchandra/* SoC device qurik handling */ 78233563Sjchandrastatic int irt_irq_map[4 * 256]; 79233563Sjchandrastatic int irq_irt_map[64]; 80233563Sjchandra 81233563Sjchandrastatic void 82233563Sjchandraxlp_add_irq(int node, int irt, int irq) 83233563Sjchandra{ 84233563Sjchandra int nodeirt = node * 256 + irt; 85233563Sjchandra 86233563Sjchandra irt_irq_map[nodeirt] = irq; 87233563Sjchandra irq_irt_map[irq] = nodeirt; 88233563Sjchandra} 89233563Sjchandra 90233563Sjchandraint 91233563Sjchandraxlp_irq_to_irt(int irq) 92233563Sjchandra{ 93233563Sjchandra return irq_irt_map[irq]; 94233563Sjchandra} 95233563Sjchandra 96233563Sjchandraint 97233563Sjchandraxlp_irt_to_irq(int nodeirt) 98233563Sjchandra{ 99233563Sjchandra return irt_irq_map[nodeirt]; 100233563Sjchandra} 101233563Sjchandra 102233563Sjchandra/* Override PCI a bit for SoC devices */ 103233563Sjchandra 104233563Sjchandraenum { 105233563Sjchandra INTERNAL_DEV = 0x1, /* internal device, skip on enumeration */ 106233563Sjchandra MEM_RES_EMUL = 0x2, /* no MEM or IO bar, custom res alloc */ 107233563Sjchandra SHARED_IRQ = 0x4, 108233563Sjchandra DEV_MMIO32 = 0x8, /* byte access not allowed to mmio */ 109225394Sjchandra}; 110225394Sjchandra 111233563Sjchandrastruct soc_dev_desc { 112233563Sjchandra u_int devid; /* device ID */ 113233563Sjchandra int irqbase; /* start IRQ */ 114233563Sjchandra u_int flags; /* flags */ 115233563Sjchandra int ndevs; /* to keep track of number of devices */ 116233563Sjchandra}; 117233563Sjchandra 118233563Sjchandrastruct soc_dev_desc xlp_dev_desc[] = { 119233563Sjchandra { PCI_DEVICE_ID_NLM_ICI, 0, INTERNAL_DEV }, 120233563Sjchandra { PCI_DEVICE_ID_NLM_PIC, 0, INTERNAL_DEV }, 121233563Sjchandra { PCI_DEVICE_ID_NLM_FMN, 0, INTERNAL_DEV }, 122233563Sjchandra { PCI_DEVICE_ID_NLM_UART, PIC_UART_0_IRQ, MEM_RES_EMUL | DEV_MMIO32}, 123233563Sjchandra { PCI_DEVICE_ID_NLM_I2C, 0, MEM_RES_EMUL | DEV_MMIO32 }, 124233563Sjchandra { PCI_DEVICE_ID_NLM_NOR, 0, MEM_RES_EMUL }, 125233563Sjchandra { PCI_DEVICE_ID_NLM_MMC, PIC_MMC_IRQ, MEM_RES_EMUL }, 126233563Sjchandra { PCI_DEVICE_ID_NLM_EHCI, PIC_EHCI_0_IRQ, 0 } 127233563Sjchandra}; 128233563Sjchandra 129233563Sjchandrastruct xlp_devinfo { 130233563Sjchandra struct pci_devinfo pcidev; 131233563Sjchandra int irq; 132233563Sjchandra int flags; 133233563Sjchandra u_long mem_res_start; 134233563Sjchandra}; 135233563Sjchandra 136233563Sjchandrastatic __inline struct soc_dev_desc * 137233563Sjchandraxlp_find_soc_desc(int devid) 138233563Sjchandra{ 139233563Sjchandra struct soc_dev_desc *p; 140233563Sjchandra int i, n; 141233563Sjchandra 142233563Sjchandra n = sizeof(xlp_dev_desc) / sizeof(xlp_dev_desc[0]); 143233563Sjchandra for (i = 0, p = xlp_dev_desc; i < n; i++, p++) 144233563Sjchandra if (p->devid == devid) 145233563Sjchandra return (p); 146233563Sjchandra return (NULL); 147233563Sjchandra} 148233563Sjchandra 149233563Sjchandrastatic struct resource * 150233563Sjchandraxlp_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 151233563Sjchandra u_long start, u_long end, u_long count, u_int flags) 152233563Sjchandra{ 153233563Sjchandra struct resource *r; 154233563Sjchandra struct xlp_devinfo *xlp_devinfo; 155233563Sjchandra int busno; 156233563Sjchandra 157233563Sjchandra /* 158233563Sjchandra * Do custom allocation for MEMORY resource for SoC device if 159233563Sjchandra * MEM_RES_EMUL flag is set 160233563Sjchandra */ 161233563Sjchandra busno = pci_get_bus(child); 162233563Sjchandra if ((type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) && busno == 0) { 163233563Sjchandra xlp_devinfo = (struct xlp_devinfo *)device_get_ivars(child); 164233563Sjchandra if ((xlp_devinfo->flags & MEM_RES_EMUL) != 0) { 165233563Sjchandra /* no emulation for IO ports */ 166233563Sjchandra if (type == SYS_RES_IOPORT) 167233563Sjchandra return (NULL); 168233564Sjchandra 169233563Sjchandra start = xlp_devinfo->mem_res_start; 170233563Sjchandra count = XLP_PCIE_CFG_SIZE - XLP_IO_PCI_HDRSZ; 171233564Sjchandra 172233564Sjchandra /* MMC needs to 2 slots with rids 16 and 20 and a 173233564Sjchandra * fixup for size */ 174233564Sjchandra if (pci_get_device(child) == PCI_DEVICE_ID_NLM_MMC) { 175233564Sjchandra count = 0x100; 176233564Sjchandra if (*rid == 16) 177233564Sjchandra ; /* first slot already setup */ 178233564Sjchandra else if (*rid == 20) 179233564Sjchandra start += 0x100; /* second slot */ 180233564Sjchandra else 181233564Sjchandra return (NULL); 182233564Sjchandra } 183233564Sjchandra 184233563Sjchandra end = start + count - 1; 185233563Sjchandra r = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 186233563Sjchandra type, rid, start, end, count, flags); 187233563Sjchandra if (r == NULL) 188233563Sjchandra return (NULL); 189233563Sjchandra if ((xlp_devinfo->flags & DEV_MMIO32) != 0) 190233563Sjchandra rman_set_bustag(r, rmi_uart_bus_space); 191233563Sjchandra return (r); 192233563Sjchandra } 193233563Sjchandra } 194233563Sjchandra 195233563Sjchandra /* Not custom alloc, use PCI code */ 196233563Sjchandra return (pci_alloc_resource(bus, child, type, rid, start, end, count, 197233563Sjchandra flags)); 198233563Sjchandra} 199233563Sjchandra 200233563Sjchandrastatic int 201233563Sjchandraxlp_pci_release_resource(device_t bus, device_t child, int type, int rid, 202233563Sjchandra struct resource *r) 203233563Sjchandra{ 204233563Sjchandra u_long start; 205233563Sjchandra 206233563Sjchandra /* If custom alloc, handle that */ 207233563Sjchandra start = rman_get_start(r); 208233563Sjchandra if (type == SYS_RES_MEMORY && pci_get_bus(child) == 0 && 209233563Sjchandra start >= EMUL_MEM_START && start <= EMUL_MEM_END) 210233563Sjchandra return (BUS_RELEASE_RESOURCE(device_get_parent(bus), child, 211233563Sjchandra type, rid, r)); 212233563Sjchandra 213233563Sjchandra /* use default PCI function */ 214233563Sjchandra return (bus_generic_rl_release_resource(bus, child, type, rid, r)); 215233563Sjchandra} 216233563Sjchandra 217233563Sjchandrastatic void 218233563Sjchandraxlp_add_soc_child(device_t pcib, device_t dev, int b, int s, int f) 219233563Sjchandra{ 220233563Sjchandra struct pci_devinfo *dinfo; 221233563Sjchandra struct xlp_devinfo *xlp_dinfo; 222233563Sjchandra struct soc_dev_desc *si; 223233563Sjchandra uint64_t pcibase; 224233563Sjchandra int domain, node, irt, irq, flags, devoffset, num; 225233563Sjchandra uint16_t devid; 226233563Sjchandra 227233563Sjchandra domain = pcib_get_domain(dev); 228233563Sjchandra node = s / 8; 229233563Sjchandra devoffset = XLP_HDR_OFFSET(node, 0, s % 8, f); 230233563Sjchandra if (!nlm_dev_exists(devoffset)) 231233563Sjchandra return; 232233563Sjchandra 233233563Sjchandra /* Find if there is a desc for the SoC device */ 234233563Sjchandra devid = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVICE, 2); 235233563Sjchandra si = xlp_find_soc_desc(devid); 236233563Sjchandra 237233563Sjchandra /* update flags and irq from desc if available */ 238233563Sjchandra irq = 0; 239233563Sjchandra flags = 0; 240233563Sjchandra if (si != NULL) { 241233563Sjchandra if (si->irqbase != 0) 242233563Sjchandra irq = si->irqbase + si->ndevs; 243233563Sjchandra flags = si->flags; 244233563Sjchandra si->ndevs++; 245233563Sjchandra } 246233563Sjchandra 247233563Sjchandra /* skip internal devices */ 248233563Sjchandra if ((flags & INTERNAL_DEV) != 0) 249233563Sjchandra return; 250233563Sjchandra 251233563Sjchandra /* PCIe interfaces are special, bug in Ax */ 252233563Sjchandra if (devid == PCI_DEVICE_ID_NLM_PCIE) { 253233563Sjchandra xlp_add_irq(node, xlp_pcie_link_irt(f), PIC_PCIE_0_IRQ + f); 254233563Sjchandra } else { 255233563Sjchandra /* Stash intline and pin in shadow reg for devices */ 256233563Sjchandra pcibase = nlm_pcicfg_base(devoffset); 257233563Sjchandra irt = nlm_irtstart(pcibase); 258233563Sjchandra num = nlm_irtnum(pcibase); 259233563Sjchandra if (irq != 0 && num > 0) { 260233563Sjchandra xlp_add_irq(node, irt, irq); 261233563Sjchandra nlm_write_reg(pcibase, XLP_PCI_DEVSCRATCH_REG0, 262233563Sjchandra (1 << 8) | irq); 263233563Sjchandra } 264233563Sjchandra } 265233563Sjchandra dinfo = pci_read_device(pcib, domain, b, s, f, sizeof(*xlp_dinfo)); 266233563Sjchandra if (dinfo == NULL) 267233563Sjchandra return; 268233563Sjchandra xlp_dinfo = (struct xlp_devinfo *)dinfo; 269233563Sjchandra xlp_dinfo->irq = irq; 270233563Sjchandra xlp_dinfo->flags = flags; 271233564Sjchandra 272233564Sjchandra /* memory resource from ecfg space, if MEM_RES_EMUL is set */ 273233563Sjchandra if ((flags & MEM_RES_EMUL) != 0) 274233563Sjchandra xlp_dinfo->mem_res_start = XLP_DEFAULT_IO_BASE + devoffset + 275233563Sjchandra XLP_IO_PCI_HDRSZ; 276233563Sjchandra pci_add_child(dev, dinfo); 277233563Sjchandra} 278233563Sjchandra 279233563Sjchandrastatic int 280233563Sjchandraxlp_pci_attach(device_t dev) 281233563Sjchandra{ 282233563Sjchandra device_t pcib = device_get_parent(dev); 283233563Sjchandra int maxslots, s, f, pcifunchigh; 284233563Sjchandra int busno; 285233563Sjchandra uint8_t hdrtype; 286233563Sjchandra 287233563Sjchandra /* 288233563Sjchandra * The on-chip devices are on a bus that is almost, but not 289233563Sjchandra * quite, completely like PCI. Add those things by hand. 290233563Sjchandra */ 291233563Sjchandra busno = pcib_get_bus(dev); 292233563Sjchandra maxslots = PCIB_MAXSLOTS(pcib); 293233563Sjchandra for (s = 0; s <= maxslots; s++) { 294233563Sjchandra pcifunchigh = 0; 295233563Sjchandra f = 0; 296233563Sjchandra hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); 297233563Sjchandra if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 298233563Sjchandra continue; 299233563Sjchandra if (hdrtype & PCIM_MFDEV) 300233563Sjchandra pcifunchigh = PCI_FUNCMAX; 301233563Sjchandra for (f = 0; f <= pcifunchigh; f++) 302233563Sjchandra xlp_add_soc_child(pcib, dev, busno, s, f); 303233563Sjchandra } 304233563Sjchandra return (bus_generic_attach(dev)); 305233563Sjchandra} 306233563Sjchandra 307233563Sjchandrastatic int 308233563Sjchandraxlp_pci_probe(device_t dev) 309233563Sjchandra{ 310233563Sjchandra device_t pcib; 311233563Sjchandra 312233563Sjchandra pcib = device_get_parent(dev); 313233563Sjchandra /* 314233563Sjchandra * Only the top level bus has SoC devices, leave the rest to 315233563Sjchandra * Generic PCI code 316233563Sjchandra */ 317233563Sjchandra if (strcmp(device_get_nameunit(pcib), "pcib0") != 0) 318233563Sjchandra return (ENXIO); 319233563Sjchandra device_set_desc(dev, "XLP SoCbus"); 320233563Sjchandra return (BUS_PROBE_DEFAULT); 321233563Sjchandra} 322233563Sjchandra 323233563Sjchandrastatic devclass_t pci_devclass; 324233563Sjchandrastatic device_method_t xlp_pci_methods[] = { 325233563Sjchandra /* Device interface */ 326233563Sjchandra DEVMETHOD(device_probe, xlp_pci_probe), 327233563Sjchandra DEVMETHOD(device_attach, xlp_pci_attach), 328233563Sjchandra DEVMETHOD(bus_alloc_resource, xlp_pci_alloc_resource), 329233563Sjchandra DEVMETHOD(bus_release_resource, xlp_pci_release_resource), 330233563Sjchandra 331233563Sjchandra DEVMETHOD_END 332233563Sjchandra}; 333233563Sjchandra 334233570SjchandraDEFINE_CLASS_1(pci, xlp_pci_driver, xlp_pci_methods, sizeof(struct pci_softc), 335233570Sjchandra pci_driver); 336233563SjchandraDRIVER_MODULE(xlp_pci, pcib, xlp_pci_driver, pci_devclass, 0, 0); 337233563Sjchandra 338225394Sjchandrastatic devclass_t pcib_devclass; 339225394Sjchandrastatic struct rman irq_rman, port_rman, mem_rman, emul_rman; 340225394Sjchandra 341225394Sjchandrastatic void 342233563Sjchandraxlp_pcib_init_resources(void) 343225394Sjchandra{ 344225394Sjchandra irq_rman.rm_start = 0; 345225394Sjchandra irq_rman.rm_end = 255; 346225394Sjchandra irq_rman.rm_type = RMAN_ARRAY; 347225394Sjchandra irq_rman.rm_descr = "PCI Mapped Interrupts"; 348225394Sjchandra if (rman_init(&irq_rman) 349225394Sjchandra || rman_manage_region(&irq_rman, 0, 255)) 350225394Sjchandra panic("pci_init_resources irq_rman"); 351225394Sjchandra 352225394Sjchandra port_rman.rm_start = 0; 353225394Sjchandra port_rman.rm_end = ~0ul; 354225394Sjchandra port_rman.rm_type = RMAN_ARRAY; 355225394Sjchandra port_rman.rm_descr = "I/O ports"; 356225394Sjchandra if (rman_init(&port_rman) 357233536Sjchandra || rman_manage_region(&port_rman, PCIE_IO_BASE, PCIE_IO_LIMIT)) 358225394Sjchandra panic("pci_init_resources port_rman"); 359225394Sjchandra 360225394Sjchandra mem_rman.rm_start = 0; 361225394Sjchandra mem_rman.rm_end = ~0ul; 362225394Sjchandra mem_rman.rm_type = RMAN_ARRAY; 363225394Sjchandra mem_rman.rm_descr = "I/O memory"; 364225394Sjchandra if (rman_init(&mem_rman) 365233536Sjchandra || rman_manage_region(&mem_rman, PCIE_MEM_BASE, PCIE_MEM_LIMIT)) 366225394Sjchandra panic("pci_init_resources mem_rman"); 367225394Sjchandra 368233536Sjchandra /* 369233536Sjchandra * This includes the GBU (nor flash) memory range and the PCIe 370233536Sjchandra * memory area. 371233536Sjchandra */ 372225394Sjchandra emul_rman.rm_start = 0; 373225394Sjchandra emul_rman.rm_end = ~0ul; 374225394Sjchandra emul_rman.rm_type = RMAN_ARRAY; 375225394Sjchandra emul_rman.rm_descr = "Emulated MEMIO"; 376225394Sjchandra if (rman_init(&emul_rman) 377233563Sjchandra || rman_manage_region(&emul_rman, EMUL_MEM_START, EMUL_MEM_END)) 378225394Sjchandra panic("pci_init_resources emul_rman"); 379225394Sjchandra} 380225394Sjchandra 381225394Sjchandrastatic int 382225394Sjchandraxlp_pcib_probe(device_t dev) 383225394Sjchandra{ 384225394Sjchandra 385225394Sjchandra device_set_desc(dev, "XLP PCI bus"); 386233563Sjchandra xlp_pcib_init_resources(); 387225394Sjchandra return (0); 388225394Sjchandra} 389225394Sjchandra 390225394Sjchandrastatic int 391225394Sjchandraxlp_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 392225394Sjchandra{ 393225394Sjchandra 394225394Sjchandra switch (which) { 395225394Sjchandra case PCIB_IVAR_DOMAIN: 396225394Sjchandra *result = 0; 397225394Sjchandra return (0); 398225394Sjchandra case PCIB_IVAR_BUS: 399225394Sjchandra *result = 0; 400225394Sjchandra return (0); 401225394Sjchandra } 402225394Sjchandra return (ENOENT); 403225394Sjchandra} 404225394Sjchandra 405225394Sjchandrastatic int 406225394Sjchandraxlp_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 407225394Sjchandra{ 408225394Sjchandra switch (which) { 409225394Sjchandra case PCIB_IVAR_DOMAIN: 410225394Sjchandra return (EINVAL); 411225394Sjchandra case PCIB_IVAR_BUS: 412225394Sjchandra return (EINVAL); 413225394Sjchandra } 414225394Sjchandra return (ENOENT); 415225394Sjchandra} 416225394Sjchandra 417225394Sjchandrastatic int 418225394Sjchandraxlp_pcib_maxslots(device_t dev) 419225394Sjchandra{ 420225394Sjchandra 421225394Sjchandra return (PCI_SLOTMAX); 422225394Sjchandra} 423225394Sjchandra 424225394Sjchandrastatic u_int32_t 425225394Sjchandraxlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, 426225394Sjchandra u_int reg, int width) 427225394Sjchandra{ 428225394Sjchandra uint32_t data = 0; 429225394Sjchandra uint64_t cfgaddr; 430225394Sjchandra int regindex = reg/sizeof(uint32_t); 431225394Sjchandra 432225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 433225394Sjchandra if ((width == 2) && (reg & 1)) 434225394Sjchandra return 0xFFFFFFFF; 435225394Sjchandra else if ((width == 4) && (reg & 3)) 436225394Sjchandra return 0xFFFFFFFF; 437225394Sjchandra 438225394Sjchandra /* 439233563Sjchandra * The intline and int pin of SoC devices are DOA, except 440233563Sjchandra * for bridges (slot %8 == 1). 441233563Sjchandra * use the values we stashed in a writable PCI scratch reg. 442225394Sjchandra */ 443233563Sjchandra if (b == 0 && regindex == 0xf && s % 8 > 1) 444233563Sjchandra regindex = XLP_PCI_DEVSCRATCH_REG0; 445225394Sjchandra 446233563Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 447225394Sjchandra if (width == 1) 448225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xff); 449225394Sjchandra else if (width == 2) 450225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xffff); 451225394Sjchandra else 452225394Sjchandra return (data); 453225394Sjchandra} 454225394Sjchandra 455225394Sjchandrastatic void 456225394Sjchandraxlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, 457225394Sjchandra u_int reg, u_int32_t val, int width) 458225394Sjchandra{ 459225394Sjchandra uint64_t cfgaddr; 460225394Sjchandra uint32_t data = 0; 461225394Sjchandra int regindex = reg / sizeof(uint32_t); 462225394Sjchandra 463225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 464225394Sjchandra if ((width == 2) && (reg & 1)) 465225394Sjchandra return; 466225394Sjchandra else if ((width == 4) && (reg & 3)) 467225394Sjchandra return; 468225394Sjchandra 469225394Sjchandra if (width == 1) { 470225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 471225394Sjchandra data = (data & ~(0xff << ((reg & 3) << 3))) | 472225394Sjchandra (val << ((reg & 3) << 3)); 473225394Sjchandra } else if (width == 2) { 474225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 475225394Sjchandra data = (data & ~(0xffff << ((reg & 3) << 3))) | 476225394Sjchandra (val << ((reg & 3) << 3)); 477225394Sjchandra } else { 478225394Sjchandra data = val; 479225394Sjchandra } 480225394Sjchandra 481233563Sjchandra /* 482233563Sjchandra * use shadow reg for intpin/intline which are dead 483233563Sjchandra */ 484233563Sjchandra if (b == 0 && regindex == 0xf && s % 8 > 1) 485233563Sjchandra regindex = XLP_PCI_DEVSCRATCH_REG0; 486225394Sjchandra nlm_write_pci_reg(cfgaddr, regindex, data); 487225394Sjchandra} 488225394Sjchandra 489233536Sjchandra/* 490245877Sjchandra * Enable byte swap in hardware when compiled big-endian. 491245877Sjchandra * Programs a link's PCIe SWAP regions from the link's IO and MEM address 492245877Sjchandra * ranges. 493233536Sjchandra */ 494233536Sjchandrastatic void 495233563Sjchandraxlp_pcib_hardware_swap_enable(int node, int link) 496233536Sjchandra{ 497245877Sjchandra#if BYTE_ORDER == BIG_ENDIAN 498233536Sjchandra uint64_t bbase, linkpcibase; 499233536Sjchandra uint32_t bar; 500233536Sjchandra int pcieoffset; 501233536Sjchandra 502233536Sjchandra pcieoffset = XLP_IO_PCIE_OFFSET(node, link); 503233536Sjchandra if (!nlm_dev_exists(pcieoffset)) 504233536Sjchandra return; 505233536Sjchandra 506233536Sjchandra bbase = nlm_get_bridge_regbase(node); 507233536Sjchandra linkpcibase = nlm_pcicfg_base(pcieoffset); 508233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_BASE0 + link); 509233536Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_BASE, bar); 510233536Sjchandra 511233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_LIMIT0 + link); 512238289Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_LIM, bar | 0xFFF); 513233536Sjchandra 514233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_BASE0 + link); 515233536Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_BASE, bar); 516233536Sjchandra 517233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_LIMIT0 + link); 518238289Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_LIM, bar | 0xFFF); 519245877Sjchandra#endif 520233536Sjchandra} 521233536Sjchandra 522225394Sjchandrastatic int 523225394Sjchandraxlp_pcib_attach(device_t dev) 524225394Sjchandra{ 525233536Sjchandra int node, link; 526225394Sjchandra 527233536Sjchandra /* enable hardware swap on all nodes/links */ 528233536Sjchandra for (node = 0; node < XLP_MAX_NODES; node++) 529233536Sjchandra for (link = 0; link < 4; link++) 530233563Sjchandra xlp_pcib_hardware_swap_enable(node, link); 531233536Sjchandra 532225394Sjchandra device_add_child(dev, "pci", 0); 533225394Sjchandra bus_generic_attach(dev); 534225394Sjchandra return (0); 535225394Sjchandra} 536225394Sjchandra 537225394Sjchandrastatic void 538225394Sjchandraxlp_pcib_identify(driver_t * driver, device_t parent) 539225394Sjchandra{ 540225394Sjchandra 541225394Sjchandra BUS_ADD_CHILD(parent, 0, "pcib", 0); 542225394Sjchandra} 543225394Sjchandra 544225394Sjchandra/* 545225394Sjchandra * XLS PCIe can have upto 4 links, and each link has its on IRQ 546225394Sjchandra * Find the link on which the device is on 547225394Sjchandra */ 548225394Sjchandrastatic int 549225394Sjchandraxlp_pcie_link(device_t pcib, device_t dev) 550225394Sjchandra{ 551225394Sjchandra device_t parent, tmp; 552225394Sjchandra 553225394Sjchandra /* find the lane on which the slot is connected to */ 554225394Sjchandra tmp = dev; 555225394Sjchandra while (1) { 556225394Sjchandra parent = device_get_parent(tmp); 557225394Sjchandra if (parent == NULL || parent == pcib) { 558225394Sjchandra device_printf(dev, "Cannot find parent bus\n"); 559225394Sjchandra return (-1); 560225394Sjchandra } 561225394Sjchandra if (strcmp(device_get_nameunit(parent), "pci0") == 0) 562225394Sjchandra break; 563225394Sjchandra tmp = parent; 564225394Sjchandra } 565225394Sjchandra return (pci_get_function(tmp)); 566225394Sjchandra} 567225394Sjchandra 568225394Sjchandrastatic int 569225394Sjchandraxlp_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 570225394Sjchandra{ 571225394Sjchandra int i, link; 572225394Sjchandra 573225394Sjchandra /* 574225394Sjchandra * Each link has 32 MSIs that can be allocated, but for now 575225394Sjchandra * we only support one device per link. 576225394Sjchandra * msi_alloc() equivalent is needed when we start supporting 577225394Sjchandra * bridges on the PCIe link. 578225394Sjchandra */ 579225394Sjchandra link = xlp_pcie_link(pcib, dev); 580225394Sjchandra if (link == -1) 581225394Sjchandra return (ENXIO); 582225394Sjchandra 583225394Sjchandra /* 584225394Sjchandra * encode the irq so that we know it is a MSI interrupt when we 585225394Sjchandra * setup interrupts 586225394Sjchandra */ 587225394Sjchandra for (i = 0; i < count; i++) 588225394Sjchandra irqs[i] = 64 + link * 32 + i; 589225394Sjchandra 590225394Sjchandra return (0); 591225394Sjchandra} 592225394Sjchandra 593225394Sjchandrastatic int 594225394Sjchandraxlp_release_msi(device_t pcib, device_t dev, int count, int *irqs) 595225394Sjchandra{ 596225394Sjchandra return (0); 597225394Sjchandra} 598225394Sjchandra 599225394Sjchandrastatic int 600225394Sjchandraxlp_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 601225394Sjchandra uint32_t *data) 602225394Sjchandra{ 603225394Sjchandra int msi, irt; 604225394Sjchandra 605225394Sjchandra if (irq >= 64) { 606225394Sjchandra msi = irq - 64; 607225394Sjchandra *addr = MIPS_MSI_ADDR(0); 608225394Sjchandra 609225394Sjchandra irt = xlp_pcie_link_irt(msi/32); 610225394Sjchandra if (irt != -1) 611225394Sjchandra *data = MIPS_MSI_DATA(xlp_irt_to_irq(irt)); 612225394Sjchandra return (0); 613225394Sjchandra } else { 614225394Sjchandra device_printf(dev, "%s: map_msi for irq %d - ignored", 615225394Sjchandra device_get_nameunit(pcib), irq); 616225394Sjchandra return (ENXIO); 617225394Sjchandra } 618225394Sjchandra} 619225394Sjchandra 620225394Sjchandrastatic void 621225394Sjchandrabridge_pcie_ack(int irq) 622225394Sjchandra{ 623225394Sjchandra uint32_t node,reg; 624225394Sjchandra uint64_t base; 625225394Sjchandra 626225394Sjchandra node = nlm_nodeid(); 627225394Sjchandra reg = PCIE_MSI_STATUS; 628225394Sjchandra 629227783Sjchandra switch (irq) { 630225394Sjchandra case PIC_PCIE_0_IRQ: 631225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE0_OFFSET(node)); 632225394Sjchandra break; 633225394Sjchandra case PIC_PCIE_1_IRQ: 634225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE1_OFFSET(node)); 635225394Sjchandra break; 636225394Sjchandra case PIC_PCIE_2_IRQ: 637225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE2_OFFSET(node)); 638225394Sjchandra break; 639225394Sjchandra case PIC_PCIE_3_IRQ: 640225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE3_OFFSET(node)); 641225394Sjchandra break; 642225394Sjchandra default: 643225394Sjchandra return; 644225394Sjchandra } 645225394Sjchandra 646225394Sjchandra nlm_write_pci_reg(base, reg, 0xFFFFFFFF); 647225394Sjchandra return; 648225394Sjchandra} 649225394Sjchandra 650225394Sjchandrastatic int 651233563Sjchandramips_platform_pcib_setup_intr(device_t dev, device_t child, 652225394Sjchandra struct resource *irq, int flags, driver_filter_t *filt, 653225394Sjchandra driver_intr_t *intr, void *arg, void **cookiep) 654225394Sjchandra{ 655225394Sjchandra int error = 0; 656225394Sjchandra int xlpirq; 657225394Sjchandra void *extra_ack; 658225394Sjchandra 659225394Sjchandra error = rman_activate_resource(irq); 660225394Sjchandra if (error) 661225394Sjchandra return error; 662225394Sjchandra if (rman_get_start(irq) != rman_get_end(irq)) { 663225394Sjchandra device_printf(dev, "Interrupt allocation %lu != %lu\n", 664225394Sjchandra rman_get_start(irq), rman_get_end(irq)); 665225394Sjchandra return (EINVAL); 666225394Sjchandra } 667225394Sjchandra xlpirq = rman_get_start(irq); 668233563Sjchandra if (xlpirq == 0) 669233563Sjchandra return (0); 670225394Sjchandra 671233563Sjchandra if (strcmp(device_get_name(dev), "pcib") != 0) 672225394Sjchandra return (0); 673225394Sjchandra 674225394Sjchandra /* 675225394Sjchandra * temporary hack for MSI, we support just one device per 676225394Sjchandra * link, and assign the link interrupt to the device interrupt 677225394Sjchandra */ 678225394Sjchandra if (xlpirq >= 64) { 679227783Sjchandra int node, val, link; 680227783Sjchandra uint64_t base; 681227783Sjchandra 682225394Sjchandra xlpirq -= 64; 683225394Sjchandra if (xlpirq % 32 != 0) 684225394Sjchandra return (0); 685225394Sjchandra 686225394Sjchandra node = nlm_nodeid(); 687233536Sjchandra link = xlpirq / 32; 688225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node,link)); 689225394Sjchandra 690225394Sjchandra /* MSI Interrupt Vector enable at bridge's configuration */ 691225394Sjchandra nlm_write_pci_reg(base, PCIE_MSI_EN, PCIE_MSI_VECTOR_INT_EN); 692225394Sjchandra 693225394Sjchandra val = nlm_read_pci_reg(base, PCIE_INT_EN0); 694225394Sjchandra /* MSI Interrupt enable at bridge's configuration */ 695225394Sjchandra nlm_write_pci_reg(base, PCIE_INT_EN0, 696233536Sjchandra (val | PCIE_MSI_INT_EN)); 697225394Sjchandra 698225394Sjchandra /* legacy interrupt disable at bridge */ 699225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_CMD); 700225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_CMD, 701233536Sjchandra (val | PCIM_CMD_INTxDIS)); 702225394Sjchandra 703225394Sjchandra /* MSI address update at bridge */ 704225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL, 705233536Sjchandra MSI_MIPS_ADDR_BASE); 706233536Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRH, 0); 707225394Sjchandra 708225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_CAP); 709225394Sjchandra /* MSI capability enable at bridge */ 710225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_CAP, 711233536Sjchandra (val | (PCIM_MSICTRL_MSI_ENABLE << 16) | 712233536Sjchandra (PCIM_MSICTRL_MMC_32 << 16))); 713225394Sjchandra 714225394Sjchandra xlpirq = xlp_pcie_link_irt(xlpirq / 32); 715225394Sjchandra if (xlpirq == -1) 716225394Sjchandra return (EINVAL); 717225394Sjchandra xlpirq = xlp_irt_to_irq(xlpirq); 718225394Sjchandra } 719225394Sjchandra /* Set all irqs to CPU 0 for now */ 720225394Sjchandra nlm_pic_write_irt_direct(xlp_pic_base, xlp_irq_to_irt(xlpirq), 1, 0, 721233536Sjchandra PIC_LOCAL_SCHEDULING, xlpirq, 0); 722225394Sjchandra extra_ack = NULL; 723233536Sjchandra if (xlpirq >= PIC_PCIE_0_IRQ && xlpirq <= PIC_PCIE_3_IRQ) 724225394Sjchandra extra_ack = bridge_pcie_ack; 725225394Sjchandra xlp_establish_intr(device_get_name(child), filt, 726225394Sjchandra intr, arg, xlpirq, flags, cookiep, extra_ack); 727225394Sjchandra 728225394Sjchandra return (0); 729225394Sjchandra} 730225394Sjchandra 731225394Sjchandrastatic int 732233563Sjchandramips_platform_pcib_teardown_intr(device_t dev, device_t child, 733225394Sjchandra struct resource *irq, void *cookie) 734225394Sjchandra{ 735225394Sjchandra if (strcmp(device_get_name(child), "pci") == 0) { 736225394Sjchandra /* if needed reprogram the pic to clear pcix related entry */ 737225394Sjchandra device_printf(dev, "teardown intr\n"); 738225394Sjchandra } 739225394Sjchandra return (bus_generic_teardown_intr(dev, child, irq, cookie)); 740225394Sjchandra} 741225394Sjchandra 742225394Sjchandrastatic struct resource * 743233563Sjchandraxlp_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid, 744225394Sjchandra u_long start, u_long end, u_long count, u_int flags) 745225394Sjchandra{ 746225394Sjchandra struct rman *rm = NULL; 747225394Sjchandra struct resource *rv; 748233563Sjchandra void *va; 749225394Sjchandra int needactivate = flags & RF_ACTIVE; 750225394Sjchandra 751233563Sjchandra switch (type) { 752233563Sjchandra case SYS_RES_IRQ: 753233563Sjchandra rm = &irq_rman; 754233563Sjchandra break; 755225394Sjchandra 756233563Sjchandra case SYS_RES_IOPORT: 757233563Sjchandra rm = &port_rman; 758233563Sjchandra break; 759225394Sjchandra 760233563Sjchandra case SYS_RES_MEMORY: 761233563Sjchandra if (start >= EMUL_MEM_START && start <= EMUL_MEM_END) 762233563Sjchandra rm = &emul_rman; 763233563Sjchandra else 764225394Sjchandra rm = &mem_rman; 765225394Sjchandra break; 766225394Sjchandra 767233563Sjchandra default: 768233563Sjchandra return (0); 769225394Sjchandra } 770225394Sjchandra 771225394Sjchandra rv = rman_reserve_resource(rm, start, end, count, flags, child); 772233563Sjchandra if (rv == NULL) 773233563Sjchandra return (NULL); 774225394Sjchandra 775225394Sjchandra rman_set_rid(rv, *rid); 776225394Sjchandra 777225394Sjchandra if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 778233563Sjchandra va = pmap_mapdev(start, count); 779233563Sjchandra rman_set_bushandle(rv, (bus_space_handle_t)va); 780233563Sjchandra rman_set_bustag(rv, rmi_bus_space); 781225394Sjchandra } 782225394Sjchandra if (needactivate) { 783225394Sjchandra if (bus_activate_resource(child, type, *rid, rv)) { 784225394Sjchandra rman_release_resource(rv); 785225394Sjchandra return (NULL); 786225394Sjchandra } 787225394Sjchandra } 788225394Sjchandra return (rv); 789225394Sjchandra} 790225394Sjchandra 791225394Sjchandrastatic int 792233563Sjchandraxlp_pcib_release_resource(device_t bus, device_t child, int type, int rid, 793225394Sjchandra struct resource *r) 794225394Sjchandra{ 795225394Sjchandra 796225394Sjchandra return (rman_release_resource(r)); 797225394Sjchandra} 798225394Sjchandra 799225394Sjchandrastatic int 800233563Sjchandraxlp_pcib_activate_resource(device_t bus, device_t child, int type, int rid, 801225394Sjchandra struct resource *r) 802225394Sjchandra{ 803225394Sjchandra 804225394Sjchandra return (rman_activate_resource(r)); 805225394Sjchandra} 806225394Sjchandra 807225394Sjchandrastatic int 808233563Sjchandraxlp_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid, 809225394Sjchandra struct resource *r) 810225394Sjchandra{ 811225394Sjchandra 812225394Sjchandra return (rman_deactivate_resource(r)); 813225394Sjchandra} 814225394Sjchandra 815225394Sjchandrastatic int 816233563Sjchandramips_pcib_route_interrupt(device_t bus, device_t dev, int pin) 817225394Sjchandra{ 818225394Sjchandra int irt, link; 819225394Sjchandra 820225394Sjchandra /* 821225394Sjchandra * Validate requested pin number. 822225394Sjchandra */ 823225394Sjchandra if ((pin < 1) || (pin > 4)) 824225394Sjchandra return (255); 825225394Sjchandra 826227783Sjchandra if (pci_get_bus(dev) == 0 && 827227783Sjchandra pci_get_vendor(dev) == PCI_VENDOR_NETLOGIC) { 828227783Sjchandra /* SoC devices */ 829227783Sjchandra uint64_t pcibase; 830227783Sjchandra int f, n, d, num; 831227783Sjchandra 832227783Sjchandra f = pci_get_function(dev); 833227783Sjchandra n = pci_get_slot(dev) / 8; 834227783Sjchandra d = pci_get_slot(dev) % 8; 835227783Sjchandra 836227783Sjchandra /* 837227783Sjchandra * For PCIe links, return link IRT, for other SoC devices 838227783Sjchandra * get the IRT from its PCIe header 839227783Sjchandra */ 840227783Sjchandra if (d == 1) { 841227783Sjchandra irt = xlp_pcie_link_irt(f); 842227783Sjchandra } else { 843227783Sjchandra pcibase = nlm_pcicfg_base(XLP_HDR_OFFSET(n, 0, d, f)); 844227783Sjchandra irt = nlm_irtstart(pcibase); 845227783Sjchandra num = nlm_irtnum(pcibase); 846227783Sjchandra if (num != 1) 847227783Sjchandra device_printf(bus, "[%d:%d:%d] Error %d IRQs\n", 848227783Sjchandra n, d, f, num); 849227783Sjchandra } 850227783Sjchandra } else { 851227783Sjchandra /* Regular PCI devices */ 852227783Sjchandra link = xlp_pcie_link(bus, dev); 853227783Sjchandra irt = xlp_pcie_link_irt(link); 854227783Sjchandra } 855227783Sjchandra 856225394Sjchandra if (irt != -1) 857225394Sjchandra return (xlp_irt_to_irq(irt)); 858225394Sjchandra 859225394Sjchandra return (255); 860225394Sjchandra} 861225394Sjchandra 862225394Sjchandrastatic device_method_t xlp_pcib_methods[] = { 863225394Sjchandra /* Device interface */ 864225394Sjchandra DEVMETHOD(device_identify, xlp_pcib_identify), 865225394Sjchandra DEVMETHOD(device_probe, xlp_pcib_probe), 866225394Sjchandra DEVMETHOD(device_attach, xlp_pcib_attach), 867225394Sjchandra 868225394Sjchandra /* Bus interface */ 869225394Sjchandra DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar), 870225394Sjchandra DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar), 871233563Sjchandra DEVMETHOD(bus_alloc_resource, xlp_pcib_alloc_resource), 872233563Sjchandra DEVMETHOD(bus_release_resource, xlp_pcib_release_resource), 873233563Sjchandra DEVMETHOD(bus_activate_resource, xlp_pcib_activate_resource), 874233563Sjchandra DEVMETHOD(bus_deactivate_resource, xlp_pcib_deactivate_resource), 875233563Sjchandra DEVMETHOD(bus_setup_intr, mips_platform_pcib_setup_intr), 876233563Sjchandra DEVMETHOD(bus_teardown_intr, mips_platform_pcib_teardown_intr), 877225394Sjchandra 878225394Sjchandra /* pcib interface */ 879225394Sjchandra DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots), 880225394Sjchandra DEVMETHOD(pcib_read_config, xlp_pcib_read_config), 881225394Sjchandra DEVMETHOD(pcib_write_config, xlp_pcib_write_config), 882233563Sjchandra DEVMETHOD(pcib_route_interrupt, mips_pcib_route_interrupt), 883225394Sjchandra 884225394Sjchandra DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi), 885225394Sjchandra DEVMETHOD(pcib_release_msi, xlp_release_msi), 886225394Sjchandra DEVMETHOD(pcib_map_msi, xlp_map_msi), 887225394Sjchandra 888227843Smarius DEVMETHOD_END 889225394Sjchandra}; 890225394Sjchandra 891225394Sjchandrastatic driver_t xlp_pcib_driver = { 892225394Sjchandra "pcib", 893225394Sjchandra xlp_pcib_methods, 894233563Sjchandra 1, /* no softc */ 895225394Sjchandra}; 896225394Sjchandra 897225394SjchandraDRIVER_MODULE(pcib, nexus, xlp_pcib_driver, pcib_devclass, 0, 0); 898