ofw_pcibus.c revision 133774
1117119Stmm/*- 2117119Stmm * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3117119Stmm * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4117119Stmm * Copyright (c) 2000, BSDi 5117119Stmm * Copyright (c) 2003, Thomas Moestl <tmm@FreeBSD.org> 6117119Stmm * All rights reserved. 7117119Stmm * 8117119Stmm * Redistribution and use in source and binary forms, with or without 9117119Stmm * modification, are permitted provided that the following conditions 10117119Stmm * are met: 11117119Stmm * 1. Redistributions of source code must retain the above copyright 12117119Stmm * notice unmodified, this list of conditions, and the following 13117119Stmm * disclaimer. 14117119Stmm * 2. Redistributions in binary form must reproduce the above copyright 15117119Stmm * notice, this list of conditions and the following disclaimer in the 16117119Stmm * documentation and/or other materials provided with the distribution. 17117119Stmm * 18117119Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19117119Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20117119Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21117119Stmm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22117119Stmm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23117119Stmm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24117119Stmm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25117119Stmm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26117119Stmm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27117119Stmm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28117119Stmm * 29117119Stmm * $FreeBSD: head/sys/sparc64/pci/ofw_pcibus.c 133774 2004-08-15 21:37:52Z marius $ 30117119Stmm */ 31117119Stmm 32117119Stmm#include "opt_ofw_pci.h" 33133589Smarius 34117119Stmm#include <sys/param.h> 35117119Stmm#include <sys/bus.h> 36117119Stmm#include <sys/kernel.h> 37117119Stmm#include <sys/libkern.h> 38117119Stmm#include <sys/module.h> 39117119Stmm#include <sys/pciio.h> 40117119Stmm 41133589Smarius#include <dev/ofw/ofw_bus.h> 42133589Smarius#include <dev/ofw/ofw_pci.h> 43117119Stmm#include <dev/ofw/openfirm.h> 44117119Stmm 45117119Stmm#include <machine/bus.h> 46117119Stmm#include <machine/bus_common.h> 47117119Stmm#include <machine/cache.h> 48117119Stmm#include <machine/iommureg.h> 49117119Stmm#include <machine/resource.h> 50117119Stmm 51117119Stmm#include <dev/pci/pcireg.h> 52117119Stmm#include <dev/pci/pcivar.h> 53117119Stmm#include <dev/pci/pci_private.h> 54117119Stmm 55117119Stmm#include <sparc64/pci/ofw_pci.h> 56117119Stmm 57117119Stmm#include "pcib_if.h" 58117119Stmm#include "pci_if.h" 59117119Stmm 60117119Stmm/* Helper functions. */ 61117119Stmmstatic void ofw_pcibus_setup_device(device_t, u_int, u_int, u_int); 62117119Stmm 63117119Stmm/* Methods. */ 64117119Stmmstatic device_probe_t ofw_pcibus_probe; 65117119Stmmstatic device_attach_t ofw_pcibus_attach; 66117119Stmmstatic pci_assign_interrupt_t ofw_pcibus_assign_interrupt; 67133589Smariusstatic ofw_bus_get_compat_t ofw_pcibus_get_compat; 68133589Smariusstatic ofw_bus_get_model_t ofw_pcibus_get_model; 69133589Smariusstatic ofw_bus_get_name_t ofw_pcibus_get_name; 70133589Smariusstatic ofw_bus_get_node_t ofw_pcibus_get_node; 71133589Smariusstatic ofw_bus_get_type_t ofw_pcibus_get_type; 72117119Stmm 73117119Stmmstatic device_method_t ofw_pcibus_methods[] = { 74117119Stmm /* Device interface */ 75117119Stmm DEVMETHOD(device_probe, ofw_pcibus_probe), 76117119Stmm DEVMETHOD(device_attach, ofw_pcibus_attach), 77117119Stmm DEVMETHOD(device_shutdown, bus_generic_shutdown), 78117119Stmm DEVMETHOD(device_suspend, bus_generic_suspend), 79117119Stmm DEVMETHOD(device_resume, bus_generic_resume), 80117119Stmm 81117119Stmm /* Bus interface */ 82117119Stmm DEVMETHOD(bus_print_child, pci_print_child), 83117119Stmm DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), 84117119Stmm DEVMETHOD(bus_read_ivar, pci_read_ivar), 85117119Stmm DEVMETHOD(bus_write_ivar, pci_write_ivar), 86117119Stmm DEVMETHOD(bus_driver_added, bus_generic_driver_added), 87117119Stmm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 88117119Stmm DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 89117119Stmm 90117119Stmm DEVMETHOD(bus_get_resource_list, pci_get_resource_list), 91117119Stmm DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 92117119Stmm DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 93117119Stmm DEVMETHOD(bus_delete_resource, pci_delete_resource), 94117119Stmm DEVMETHOD(bus_alloc_resource, pci_alloc_resource), 95117119Stmm DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 96117119Stmm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 97117119Stmm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 98117119Stmm DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), 99117119Stmm DEVMETHOD(bus_child_location_str, pci_child_location_str_method), 100117119Stmm 101117119Stmm /* PCI interface */ 102117119Stmm DEVMETHOD(pci_read_config, pci_read_config_method), 103117119Stmm DEVMETHOD(pci_write_config, pci_write_config_method), 104117119Stmm DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), 105117119Stmm DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), 106117119Stmm DEVMETHOD(pci_enable_io, pci_enable_io_method), 107117119Stmm DEVMETHOD(pci_disable_io, pci_disable_io_method), 108117119Stmm DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), 109117119Stmm DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), 110117119Stmm DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), 111117119Stmm 112133589Smarius /* ofw_bus interface */ 113133589Smarius DEVMETHOD(ofw_bus_get_compat, ofw_pcibus_get_compat), 114133589Smarius DEVMETHOD(ofw_bus_get_model, ofw_pcibus_get_model), 115133589Smarius DEVMETHOD(ofw_bus_get_name, ofw_pcibus_get_name), 116133589Smarius DEVMETHOD(ofw_bus_get_node, ofw_pcibus_get_node), 117133589Smarius DEVMETHOD(ofw_bus_get_type, ofw_pcibus_get_type), 118117119Stmm 119117119Stmm { 0, 0 } 120117119Stmm}; 121117119Stmm 122117119Stmmstruct ofw_pcibus_devinfo { 123117119Stmm struct pci_devinfo opd_dinfo; 124133589Smarius char *opd_compat; 125133589Smarius char *opd_model; 126133589Smarius char *opd_name; 127133589Smarius char *opd_type; 128117119Stmm phandle_t opd_node; 129117119Stmm}; 130117119Stmm 131117119Stmmstruct ofw_pcibus_softc { 132117119Stmm phandle_t ops_node; 133117119Stmm}; 134117119Stmm 135117119Stmmstatic driver_t ofw_pcibus_driver = { 136117119Stmm "pci", 137117119Stmm ofw_pcibus_methods, 138117119Stmm sizeof(struct ofw_pcibus_softc), 139117119Stmm}; 140117119Stmm 141117119StmmDRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0); 142117119StmmMODULE_VERSION(ofw_pcibus, 1); 143117119StmmMODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1); 144117119Stmm 145117119Stmmstatic int 146117119Stmmofw_pcibus_probe(device_t dev) 147117119Stmm{ 148117119Stmm 149133589Smarius if (ofw_bus_get_node(dev) == 0) 150117119Stmm return (ENXIO); 151117119Stmm device_set_desc(dev, "OFW PCI bus"); 152117119Stmm 153117119Stmm return (0); 154117119Stmm} 155117119Stmm 156117119Stmm/* 157117119Stmm * Perform miscellaneous setups the firmware usually does not do for us. 158117119Stmm */ 159117119Stmmstatic void 160117119Stmmofw_pcibus_setup_device(device_t bridge, u_int busno, u_int slot, u_int func) 161117119Stmm{ 162117119Stmm u_int lat, clnsz; 163117119Stmm 164117119Stmm /* 165117119Stmm * Initialize the latency timer register for busmaster devices to work 166117119Stmm * properly. This is another task which the firmware does not always 167117119Stmm * perform. The Min_Gnt register can be used to compute it's recommended 168117119Stmm * value: it contains the desired latency in units of 1/4 us. To 169117119Stmm * calculate the correct latency timer value, a bus clock of 33MHz and 170117119Stmm * no wait states should be assumed. 171117119Stmm */ 172117119Stmm lat = PCIB_READ_CONFIG(bridge, busno, slot, func, PCIR_MINGNT, 1) * 173117119Stmm 33 / 4; 174117119Stmm if (lat != 0) { 175117119Stmm#ifdef OFW_PCI_DEBUG 176117119Stmm device_printf(bridge, "device %d/%d/%d: latency timer %d -> " 177117119Stmm "%d\n", busno, slot, func, 178117119Stmm PCIB_READ_CONFIG(bridge, busno, slot, func, 179117119Stmm PCIR_LATTIMER, 1), lat); 180117119Stmm#endif /* OFW_PCI_DEBUG */ 181117119Stmm PCIB_WRITE_CONFIG(bridge, busno, slot, func, 182133774Smarius PCIR_LATTIMER, min(lat, 255), 1); 183117119Stmm } 184117119Stmm 185117119Stmm /* 186117119Stmm * Compute a value to write into the cache line size register. 187117119Stmm * The role of the streaming cache is unclear in write invalidate 188117119Stmm * transfers, so it is made sure that it's line size is always reached. 189117119Stmm */ 190133774Smarius clnsz = max(cache.ec_linesize, STRBUF_LINESZ); 191117119Stmm KASSERT((clnsz / STRBUF_LINESZ) * STRBUF_LINESZ == clnsz && 192117119Stmm (clnsz / cache.ec_linesize) * cache.ec_linesize == clnsz && 193117119Stmm (clnsz / 4) * 4 == clnsz, ("bogus cache line size %d", clnsz)); 194117119Stmm PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_CACHELNSZ, 195117119Stmm clnsz / 4, 1); 196117119Stmm 197117119Stmm /* 198117119Stmm * The preset in the intline register is usually wrong. Reset it to 255, 199117119Stmm * so that the PCI code will reroute the interrupt if needed. 200117119Stmm */ 201117119Stmm PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_INTLINE, 202117119Stmm PCI_INVALID_IRQ, 1); 203117119Stmm} 204117119Stmm 205117119Stmmstatic int 206117119Stmmofw_pcibus_attach(device_t dev) 207117119Stmm{ 208117119Stmm device_t pcib = device_get_parent(dev); 209117119Stmm struct ofw_pci_register pcir; 210117119Stmm struct ofw_pcibus_devinfo *dinfo; 211117119Stmm phandle_t node, child; 212117119Stmm u_int slot, busno, func; 213117119Stmm 214117119Stmm /* 215117119Stmm * Ask the bridge for the bus number - in some cases, we need to 216117119Stmm * renumber buses, so the firmware information cannot be trusted. 217117119Stmm */ 218117119Stmm busno = pcib_get_bus(dev); 219117119Stmm if (bootverbose) 220117119Stmm device_printf(dev, "physical bus=%d\n", busno); 221117119Stmm 222133589Smarius node = ofw_bus_get_node(dev); 223117119Stmm for (child = OF_child(node); child != 0; child = OF_peer(child)) { 224117119Stmm if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) 225117119Stmm panic("ofw_pci_attach: OF_getprop failed"); 226117119Stmm slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); 227117119Stmm func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); 228117119Stmm ofw_pcibus_setup_device(pcib, busno, slot, func); 229117119Stmm dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, 230117119Stmm busno, slot, func, sizeof(*dinfo)); 231117119Stmm if (dinfo != NULL) { 232117119Stmm dinfo->opd_node = child; 233133589Smarius OF_getprop_alloc(child, "compatible", 1, 234133589Smarius (void **)&dinfo->opd_compat); 235133589Smarius OF_getprop_alloc(child, "device_type", 1, 236133589Smarius (void **)&dinfo->opd_type); 237133589Smarius OF_getprop_alloc(child, "model", 1, 238133589Smarius (void **)&dinfo->opd_model); 239133589Smarius OF_getprop_alloc(child, "name", 1, 240133589Smarius (void **)&dinfo->opd_name); 241117119Stmm pci_add_child(dev, (struct pci_devinfo *)dinfo); 242117119Stmm } 243117119Stmm } 244117119Stmm 245117119Stmm return (bus_generic_attach(dev)); 246117119Stmm} 247117119Stmm 248117119Stmmstatic int 249117119Stmmofw_pcibus_assign_interrupt(device_t dev, device_t child) 250117119Stmm{ 251117119Stmm struct ofw_pcibus_devinfo *dinfo = device_get_ivars(child); 252117119Stmm pcicfgregs *cfg = &dinfo->opd_dinfo.cfg; 253117119Stmm ofw_pci_intr_t intr; 254117119Stmm int isz; 255117119Stmm 256133589Smarius isz = OF_getprop(dinfo->opd_node, "interrupts", &intr, sizeof(intr)); 257117119Stmm if (isz != sizeof(intr)) { 258117119Stmm /* No property; our best guess is the intpin. */ 259117119Stmm intr = cfg->intpin; 260117119Stmm } else if (intr >= 255) { 261117119Stmm /* 262117119Stmm * A fully specified interrupt (including IGN), as present on 263117119Stmm * SPARCengine Ultra AX and e450. Extract the INO and return it. 264117119Stmm */ 265117119Stmm return (INTINO(intr)); 266117119Stmm } 267117119Stmm /* 268117119Stmm * If we got intr from a property, it may or may not be an intpin. 269117119Stmm * For on-board devices, it frequently is not, and is completely out 270117119Stmm * of the valid intpin range. For PCI slots, it hopefully is, otherwise 271117119Stmm * we will have trouble interfacing with non-OFW buses such as cardbus. 272117119Stmm * Since we cannot tell which it is without violating layering, we 273117119Stmm * will always use the route_interrupt method, and treat exceptions on 274117119Stmm * the level they become apparent. 275117119Stmm */ 276117119Stmm return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); 277117119Stmm} 278117119Stmm 279133589Smariusstatic const char * 280133589Smariusofw_pcibus_get_compat(device_t bus, device_t dev) 281133589Smarius{ 282133589Smarius struct ofw_pcibus_devinfo *dinfo; 283133589Smarius 284133589Smarius dinfo = device_get_ivars(dev); 285133589Smarius return (dinfo->opd_compat); 286133589Smarius} 287133589Smarius 288133589Smariusstatic const char * 289133589Smariusofw_pcibus_get_model(device_t bus, device_t dev) 290133589Smarius{ 291133589Smarius struct ofw_pcibus_devinfo *dinfo; 292133589Smarius 293133589Smarius dinfo = device_get_ivars(dev); 294133589Smarius return (dinfo->opd_model); 295133589Smarius} 296133589Smarius 297133589Smariusstatic const char * 298133589Smariusofw_pcibus_get_name(device_t bus, device_t dev) 299133589Smarius{ 300133589Smarius struct ofw_pcibus_devinfo *dinfo; 301133589Smarius 302133589Smarius dinfo = device_get_ivars(dev); 303133589Smarius return (dinfo->opd_name); 304133589Smarius} 305133589Smarius 306117119Stmmstatic phandle_t 307117119Stmmofw_pcibus_get_node(device_t bus, device_t dev) 308117119Stmm{ 309133589Smarius struct ofw_pcibus_devinfo *dinfo; 310117119Stmm 311133589Smarius dinfo = device_get_ivars(dev); 312117119Stmm return (dinfo->opd_node); 313117119Stmm} 314133589Smarius 315133589Smariusstatic const char * 316133589Smariusofw_pcibus_get_type(device_t bus, device_t dev) 317133589Smarius{ 318133589Smarius struct ofw_pcibus_devinfo *dinfo; 319133589Smarius 320133589Smarius dinfo = device_get_ivars(dev); 321133589Smarius return (dinfo->opd_type); 322133589Smarius} 323