ofw_pcibus.c revision 330938
1279377Simp/*- 2279377Simp * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3279377Simp * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4279377Simp * Copyright (c) 2000, BSDi 5279377Simp * Copyright (c) 2003, Thomas Moestl <tmm@FreeBSD.org> 6279377Simp * All rights reserved. 7279377Simp * 8279377Simp * Redistribution and use in source and binary forms, with or without 9279377Simp * modification, are permitted provided that the following conditions 10279377Simp * are met: 11279377Simp * 1. Redistributions of source code must retain the above copyright 12279377Simp * notice unmodified, this list of conditions, and the following 13279377Simp * disclaimer. 14279377Simp * 2. Redistributions in binary form must reproduce the above copyright 15279377Simp * notice, this list of conditions and the following disclaimer in the 16279377Simp * documentation and/or other materials provided with the distribution. 17279377Simp * 18279377Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19279377Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20279377Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21279377Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22279377Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23279377Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24279377Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25279377Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26279377Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27279377Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28279377Simp */ 29279377Simp 30279377Simp#include <sys/cdefs.h> 31279377Simp__FBSDID("$FreeBSD: stable/10/sys/powerpc/ofw/ofw_pcibus.c 330938 2018-03-14 19:04:40Z jhb $"); 32279377Simp 33279377Simp#include <sys/param.h> 34279377Simp#include <sys/bus.h> 35279377Simp#include <sys/kernel.h> 36279377Simp#include <sys/libkern.h> 37279377Simp#include <sys/module.h> 38279377Simp#include <sys/pciio.h> 39279377Simp 40279377Simp#include <dev/ofw/ofw_bus.h> 41279377Simp#include <dev/ofw/ofw_bus_subr.h> 42279377Simp#include <dev/ofw/ofw_pci.h> 43279377Simp#include <dev/ofw/openfirm.h> 44279377Simp 45279377Simp#include <machine/bus.h> 46279377Simp#include <machine/intr_machdep.h> 47279377Simp#include <machine/resource.h> 48279377Simp 49279377Simp#include <dev/pci/pcireg.h> 50279377Simp#include <dev/pci/pcivar.h> 51279377Simp#include <dev/pci/pci_private.h> 52279377Simp 53279377Simp#include "ofw_pcibus.h" 54279377Simp#include "pcib_if.h" 55279377Simp#include "pci_if.h" 56279377Simp 57279377Simptypedef uint32_t ofw_pci_intr_t; 58279377Simp 59279377Simp/* Methods */ 60279377Simpstatic device_probe_t ofw_pcibus_probe; 61279377Simpstatic device_attach_t ofw_pcibus_attach; 62279377Simpstatic pci_assign_interrupt_t ofw_pcibus_assign_interrupt; 63279377Simpstatic ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo; 64279377Simpstatic bus_child_deleted_t ofw_pcibus_child_deleted; 65279377Simpstatic int ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, 66279377Simp char *buf, size_t buflen); 67279377Simp 68279377Simpstatic void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno); 69279377Simpstatic void ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno); 70279377Simp 71279377Simpstatic device_method_t ofw_pcibus_methods[] = { 72279377Simp /* Device interface */ 73279377Simp DEVMETHOD(device_probe, ofw_pcibus_probe), 74279377Simp DEVMETHOD(device_attach, ofw_pcibus_attach), 75279377Simp 76279377Simp /* Bus interface */ 77279377Simp DEVMETHOD(bus_child_deleted, ofw_pcibus_child_deleted), 78279377Simp DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method), 79279377Simp 80279377Simp /* PCI interface */ 81279377Simp DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), 82279377Simp 83279377Simp /* ofw_bus interface */ 84279377Simp DEVMETHOD(ofw_bus_get_devinfo, ofw_pcibus_get_devinfo), 85279377Simp DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 86279377Simp DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 87279377Simp DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 88279377Simp DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 89279377Simp DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 90279377Simp 91279377Simp DEVMETHOD_END 92279377Simp}; 93279377Simp 94279377Simpstatic devclass_t pci_devclass; 95279377Simp 96279377SimpDEFINE_CLASS_1(pci, ofw_pcibus_driver, ofw_pcibus_methods, 97279377Simp sizeof(struct pci_softc), pci_driver); 98279377SimpDRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0); 99279377SimpMODULE_VERSION(ofw_pcibus, 1); 100279377SimpMODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1); 101279377Simp 102279377Simpstatic int ofw_devices_only = 0; 103279377SimpTUNABLE_INT("hw.pci.ofw_devices_only", &ofw_devices_only); 104279377Simp 105279377Simpstatic int 106279377Simpofw_pcibus_probe(device_t dev) 107279377Simp{ 108279377Simp 109279377Simp if (ofw_bus_get_node(dev) == -1) 110279377Simp return (ENXIO); 111279377Simp device_set_desc(dev, "OFW PCI bus"); 112279377Simp 113279377Simp return (BUS_PROBE_DEFAULT); 114279377Simp} 115279377Simp 116279377Simpstatic int 117279377Simpofw_pcibus_attach(device_t dev) 118279377Simp{ 119279377Simp u_int busno, domain; 120279377Simp int error; 121279377Simp 122279377Simp error = pci_attach_common(dev); 123279377Simp if (error) 124279377Simp return (error); 125279377Simp domain = pcib_get_domain(dev); 126279377Simp busno = pcib_get_bus(dev); 127279377Simp 128279377Simp /* 129279377Simp * Attach those children represented in the device tree. 130279377Simp */ 131279377Simp 132279377Simp ofw_pcibus_enum_devtree(dev, domain, busno); 133279377Simp 134279377Simp /* 135279377Simp * We now attach any laggard devices. FDT, for instance, allows 136279377Simp * the device tree to enumerate only some PCI devices. Apple's 137279377Simp * OF device tree on some Grackle-based hardware can also miss 138279377Simp * functions on multi-function cards. 139279377Simp */ 140279377Simp 141279377Simp if (!ofw_devices_only) 142279377Simp ofw_pcibus_enum_bus(dev, domain, busno); 143279377Simp 144279377Simp return (bus_generic_attach(dev)); 145279377Simp} 146279377Simp 147279377Simpstatic void 148279377Simpofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno) 149279377Simp{ 150279377Simp device_t pcib; 151279377Simp struct ofw_pci_register pcir; 152279377Simp struct ofw_pcibus_devinfo *dinfo; 153279377Simp phandle_t node, child; 154279377Simp u_int func, slot; 155279377Simp int intline; 156279377Simp 157279377Simp pcib = device_get_parent(dev); 158279377Simp node = ofw_bus_get_node(dev); 159279377Simp 160279377Simp for (child = OF_child(node); child != 0; child = OF_peer(child)) { 161279377Simp if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) 162279377Simp continue; 163279377Simp slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); 164279377Simp func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); 165279377Simp 166279377Simp /* Some OFW device trees contain dupes. */ 167279377Simp if (pci_find_dbsf(domain, busno, slot, func) != NULL) 168279377Simp continue; 169279377Simp 170279377Simp /* 171279377Simp * The preset in the intline register is usually bogus. Reset 172279377Simp * it such that the PCI code will reroute the interrupt if 173279377Simp * needed. 174279377Simp */ 175279377Simp 176279377Simp intline = PCI_INVALID_IRQ; 177279377Simp if (OF_getproplen(child, "interrupts") > 0) 178279377Simp intline = 0; 179279377Simp PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE, 180279377Simp intline, 1); 181279377Simp 182279377Simp /* 183279377Simp * Now set up the PCI and OFW bus layer devinfo and add it 184279377Simp * to the PCI bus. 185279377Simp */ 186279377Simp 187279377Simp dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, 188279377Simp domain, busno, slot, func, sizeof(*dinfo)); 189279377Simp if (dinfo == NULL) 190279377Simp continue; 191279377Simp if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 192279377Simp 0) { 193279377Simp pci_freecfg((struct pci_devinfo *)dinfo); 194279377Simp continue; 195279377Simp } 196279377Simp dinfo->opd_dma_tag = NULL; 197279377Simp pci_add_child(dev, (struct pci_devinfo *)dinfo); 198279377Simp 199279377Simp /* 200279377Simp * Some devices don't have an intpin set, but do have 201279377Simp * interrupts. These are fully specified, and set in the 202279377Simp * interrupts property, so add that value to the device's 203279377Simp * resource list. 204279377Simp */ 205279377Simp if (dinfo->opd_dinfo.cfg.intpin == 0) 206279377Simp ofw_bus_intr_to_rl(dev, child, &dinfo->opd_dinfo.resources); 207279377Simp } 208279377Simp} 209279377Simp 210279377Simp/* 211279377Simp * The following is an almost exact clone of pci_add_children(), with the 212279377Simp * addition that it (a) will not add children that have already been added, 213279377Simp * and (b) will set up the OFW devinfo to point to invalid values. This is 214279377Simp * to handle non-enumerated PCI children as exist in FDT and on the second 215279377Simp * function of the Rage 128 in my Blue & White G3. 216279377Simp */ 217279377Simp 218279377Simpstatic void 219279377Simpofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno) 220279377Simp{ 221279377Simp device_t pcib; 222279377Simp struct ofw_pcibus_devinfo *dinfo; 223279377Simp int maxslots; 224279377Simp int s, f, pcifunchigh; 225279377Simp uint8_t hdrtype; 226279377Simp 227279377Simp pcib = device_get_parent(dev); 228279377Simp 229279377Simp maxslots = PCIB_MAXSLOTS(pcib); 230279377Simp for (s = 0; s <= maxslots; s++) { 231279377Simp pcifunchigh = 0; 232279377Simp f = 0; 233279377Simp DELAY(1); 234279377Simp hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); 235279377Simp if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 236279377Simp continue; 237279377Simp if (hdrtype & PCIM_MFDEV) 238279377Simp pcifunchigh = PCI_FUNCMAX; 239279377Simp for (f = 0; f <= pcifunchigh; f++) { 240279377Simp /* Filter devices we have already added */ 241279377Simp if (pci_find_dbsf(domain, busno, s, f) != NULL) 242279377Simp continue; 243279377Simp 244279377Simp dinfo = (struct ofw_pcibus_devinfo *)pci_read_device( 245279377Simp pcib, domain, busno, s, f, sizeof(*dinfo)); 246279377Simp if (dinfo == NULL) 247279377Simp continue; 248279377Simp 249279377Simp dinfo->opd_dma_tag = NULL; 250279377Simp dinfo->opd_obdinfo.obd_node = -1; 251279377Simp 252279377Simp dinfo->opd_obdinfo.obd_name = NULL; 253279377Simp dinfo->opd_obdinfo.obd_compat = NULL; 254279377Simp dinfo->opd_obdinfo.obd_type = NULL; 255279377Simp dinfo->opd_obdinfo.obd_model = NULL; 256279377Simp 257279377Simp /* 258279377Simp * For non OFW-devices, don't believe 0 259279377Simp * for an interrupt. 260279377Simp */ 261279377Simp if (dinfo->opd_dinfo.cfg.intline == 0) { 262279377Simp dinfo->opd_dinfo.cfg.intline = PCI_INVALID_IRQ; 263279377Simp PCIB_WRITE_CONFIG(pcib, busno, s, f, 264279377Simp PCIR_INTLINE, PCI_INVALID_IRQ, 1); 265279377Simp } 266279377Simp 267279377Simp pci_add_child(dev, (struct pci_devinfo *)dinfo); 268279377Simp } 269279377Simp } 270279377Simp} 271279377Simp 272279377Simpstatic void 273279377Simpofw_pcibus_child_deleted(device_t dev, device_t child) 274279377Simp{ 275279377Simp struct ofw_pcibus_devinfo *dinfo; 276279377Simp 277279377Simp dinfo = device_get_ivars(dev); 278279377Simp ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); 279279377Simp pci_child_deleted(dev, child); 280279377Simp} 281279377Simp 282279377Simpstatic int 283279377Simpofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, 284279377Simp size_t buflen) 285279377Simp{ 286279377Simp pci_child_pnpinfo_str_method(cbdev, child, buf, buflen); 287279377Simp 288279377Simp if (ofw_bus_get_node(child) != -1) { 289279377Simp strlcat(buf, " ", buflen); /* Separate info */ 290279377Simp ofw_bus_gen_child_pnpinfo_str(cbdev, child, buf, buflen); 291279377Simp } 292279377Simp 293279377Simp return (0); 294279377Simp} 295279377Simp 296279377Simpstatic int 297279377Simpofw_pcibus_assign_interrupt(device_t dev, device_t child) 298279377Simp{ 299279377Simp ofw_pci_intr_t intr[2]; 300279377Simp phandle_t node, iparent; 301279377Simp int isz, icells; 302279377Simp 303279377Simp node = ofw_bus_get_node(child); 304279377Simp 305279377Simp if (node == -1) { 306279377Simp /* Non-firmware enumerated child, use standard routing */ 307279377Simp 308279377Simp intr[0] = pci_get_intpin(child); 309279377Simp return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, 310279377Simp intr[0])); 311279377Simp } 312279377Simp 313279377Simp /* 314279377Simp * Try to determine the node's interrupt parent so we know which 315279377Simp * PIC to use. 316279377Simp */ 317279377Simp 318279377Simp iparent = -1; 319279377Simp if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0) 320279377Simp iparent = -1; 321279377Simp icells = 1; 322279377Simp if (iparent != -1) 323279377Simp OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", 324279377Simp &icells, sizeof(icells)); 325279377Simp 326279377Simp /* 327279377Simp * Any AAPL,interrupts property gets priority and is 328279377Simp * fully specified (i.e. does not need routing) 329279377Simp */ 330279377Simp 331279377Simp isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr)); 332279377Simp if (isz == sizeof(intr[0])*icells) 333279377Simp return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev, 334279377Simp iparent, icells, intr)); 335279377Simp 336279377Simp isz = OF_getprop(node, "interrupts", intr, sizeof(intr)); 337279377Simp if (isz == sizeof(intr[0])*icells) { 338279377Simp if (iparent != -1) 339279377Simp intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr); 340279377Simp } else { 341279377Simp /* No property: our best guess is the intpin. */ 342279377Simp intr[0] = pci_get_intpin(child); 343279377Simp } 344279377Simp 345279377Simp /* 346279377Simp * If we got intr from a property, it may or may not be an intpin. 347279377Simp * For on-board devices, it frequently is not, and is completely out 348279377Simp * of the valid intpin range. For PCI slots, it hopefully is, 349279377Simp * otherwise we will have trouble interfacing with non-OFW buses 350279377Simp * such as cardbus. 351279377Simp * Since we cannot tell which it is without violating layering, we 352279377Simp * will always use the route_interrupt method, and treat exceptions 353279377Simp * on the level they become apparent. 354279377Simp */ 355279377Simp return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0])); 356279377Simp} 357279377Simp 358279377Simpstatic const struct ofw_bus_devinfo * 359279377Simpofw_pcibus_get_devinfo(device_t bus, device_t dev) 360279377Simp{ 361279377Simp struct ofw_pcibus_devinfo *dinfo; 362279377Simp 363279377Simp dinfo = device_get_ivars(dev); 364279377Simp return (&dinfo->opd_obdinfo); 365279377Simp} 366279377Simp 367279377Simp