1109001Sbenno/*- 2109001Sbenno * Copyright (c) 2000 Michael Smith 3109001Sbenno * Copyright (c) 2000 BSDi 4109001Sbenno * All rights reserved. 5109001Sbenno * 6109001Sbenno * Redistribution and use in source and binary forms, with or without 7109001Sbenno * modification, are permitted provided that the following conditions 8109001Sbenno * are met: 9109001Sbenno * 1. Redistributions of source code must retain the above copyright 10109001Sbenno * notice, this list of conditions and the following disclaimer. 11109001Sbenno * 2. Redistributions in binary form must reproduce the above copyright 12109001Sbenno * notice, this list of conditions and the following disclaimer in the 13109001Sbenno * documentation and/or other materials provided with the distribution. 14109001Sbenno * 15109001Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16109001Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17109001Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18109001Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19109001Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20109001Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21109001Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22109001Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23109001Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24109001Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25109001Sbenno * SUCH DAMAGE. 26109001Sbenno */ 27109001Sbenno 28227843Smarius#include <sys/cdefs.h> 29227843Smarius__FBSDID("$FreeBSD$"); 30227843Smarius 31109001Sbenno#include <sys/param.h> 32256816Snwhitehorn#include <sys/systm.h> 33131102Sgrehan#include <sys/module.h> 34109001Sbenno#include <sys/bus.h> 35109001Sbenno#include <sys/malloc.h> 36109001Sbenno#include <sys/kernel.h> 37109001Sbenno 38109001Sbenno#include <dev/ofw/openfirm.h> 39109001Sbenno#include <dev/ofw/ofw_pci.h> 40183882Snwhitehorn#include <dev/ofw/ofw_bus.h> 41186128Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 42109001Sbenno 43119291Simp#include <dev/pci/pcivar.h> 44119291Simp#include <dev/pci/pcireg.h> 45119291Simp#include <dev/pci/pcib_private.h> 46109001Sbenno 47209298Snwhitehorn#include <machine/intr_machdep.h> 48209298Snwhitehorn 49109001Sbenno#include "pcib_if.h" 50109001Sbenno 51109001Sbennostatic int ofw_pcib_pci_probe(device_t bus); 52109001Sbennostatic int ofw_pcib_pci_attach(device_t bus); 53183882Snwhitehornstatic phandle_t ofw_pcib_pci_get_node(device_t bus, device_t dev); 54186128Snwhitehornstatic int ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, 55186128Snwhitehorn int intpin); 56109001Sbenno 57109001Sbennostatic device_method_t ofw_pcib_pci_methods[] = { 58109001Sbenno /* Device interface */ 59109001Sbenno DEVMETHOD(device_probe, ofw_pcib_pci_probe), 60231046Snwhitehorn DEVMETHOD(device_attach, ofw_pcib_pci_attach), 61109001Sbenno 62109001Sbenno /* pcib interface */ 63186128Snwhitehorn DEVMETHOD(pcib_route_interrupt, ofw_pcib_pci_route_interrupt), 64109001Sbenno 65183882Snwhitehorn /* ofw_bus interface */ 66227843Smarius DEVMETHOD(ofw_bus_get_node, ofw_pcib_pci_get_node), 67183882Snwhitehorn 68227843Smarius DEVMETHOD_END 69109001Sbenno}; 70109001Sbenno 71154079Sjhbstatic devclass_t pcib_devclass; 72109001Sbenno 73186128Snwhitehornstruct ofw_pcib_softc { 74186128Snwhitehorn /* 75186128Snwhitehorn * This is here so that we can use pci bridge methods, too - the 76186128Snwhitehorn * generic routines only need the dev, secbus and subbus members 77186128Snwhitehorn * filled. 78186128Snwhitehorn */ 79186128Snwhitehorn struct pcib_softc ops_pcib_sc; 80186128Snwhitehorn phandle_t ops_node; 81186128Snwhitehorn struct ofw_bus_iinfo ops_iinfo; 82186128Snwhitehorn}; 83186128Snwhitehorn 84231046SnwhitehornDEFINE_CLASS_1(pcib, ofw_pcib_pci_driver, ofw_pcib_pci_methods, 85231046Snwhitehorn sizeof(struct ofw_pcib_softc), pcib_driver); 86109001SbennoDRIVER_MODULE(ofw_pcib, pci, ofw_pcib_pci_driver, pcib_devclass, 0, 0); 87109001Sbenno 88109001Sbennostatic int 89109001Sbennoofw_pcib_pci_probe(device_t dev) 90109001Sbenno{ 91109001Sbenno 92109001Sbenno if ((pci_get_class(dev) != PCIC_BRIDGE) || 93109001Sbenno (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) { 94109001Sbenno return (ENXIO); 95109001Sbenno } 96183882Snwhitehorn 97233018Snwhitehorn if (ofw_bus_get_node(dev) == -1) 98109001Sbenno return (ENXIO); 99109001Sbenno 100183882Snwhitehorn device_set_desc(dev, "OFW PCI-PCI bridge"); 101183882Snwhitehorn return (0); 102109001Sbenno} 103109001Sbenno 104109001Sbennostatic int 105109001Sbennoofw_pcib_pci_attach(device_t dev) 106109001Sbenno{ 107186128Snwhitehorn struct ofw_pcib_softc *sc; 108186128Snwhitehorn 109186128Snwhitehorn sc = device_get_softc(dev); 110186128Snwhitehorn sc->ops_pcib_sc.dev = dev; 111186128Snwhitehorn sc->ops_node = ofw_bus_get_node(dev); 112186128Snwhitehorn 113186128Snwhitehorn ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo, 114186128Snwhitehorn sizeof(cell_t)); 115186128Snwhitehorn 116109001Sbenno pcib_attach_common(dev); 117298711Sjhb return (pcib_attach_child(dev)); 118109001Sbenno} 119183882Snwhitehorn 120186128Snwhitehornstatic phandle_t 121183882Snwhitehornofw_pcib_pci_get_node(device_t bridge, device_t dev) 122183882Snwhitehorn{ 123183882Snwhitehorn /* We have only one child, the PCI bus, so pass it our node */ 124183882Snwhitehorn 125183882Snwhitehorn return (ofw_bus_get_node(bridge)); 126183882Snwhitehorn} 127183882Snwhitehorn 128186128Snwhitehornstatic int 129186128Snwhitehornofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin) 130186128Snwhitehorn{ 131186128Snwhitehorn struct ofw_pcib_softc *sc; 132186128Snwhitehorn struct ofw_bus_iinfo *ii; 133186128Snwhitehorn struct ofw_pci_register reg; 134259516Snwhitehorn cell_t pintr, mintr[2]; 135259516Snwhitehorn int intrcells; 136209298Snwhitehorn phandle_t iparent; 137186128Snwhitehorn 138186128Snwhitehorn sc = device_get_softc(bridge); 139186128Snwhitehorn ii = &sc->ops_iinfo; 140186128Snwhitehorn if (ii->opi_imapsz > 0) { 141186128Snwhitehorn pintr = intpin; 142256816Snwhitehorn 143256816Snwhitehorn /* Fabricate imap information if this isn't an OFW device */ 144256816Snwhitehorn bzero(®, sizeof(reg)); 145256816Snwhitehorn reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | 146256816Snwhitehorn (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | 147256816Snwhitehorn (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); 148256816Snwhitehorn 149259516Snwhitehorn intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, 150259516Snwhitehorn sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr), 151259516Snwhitehorn &iparent); 152259516Snwhitehorn if (intrcells) { 153186128Snwhitehorn /* 154186128Snwhitehorn * If we've found a mapping, return it and don't map 155186128Snwhitehorn * it again on higher levels - that causes problems 156186128Snwhitehorn * in some cases, and never seems to be required. 157186128Snwhitehorn */ 158261351Snwhitehorn mintr[0] = ofw_bus_map_intr(dev, iparent, intrcells, 159261351Snwhitehorn mintr); 160259516Snwhitehorn return (mintr[0]); 161186128Snwhitehorn } 162186128Snwhitehorn } else if (intpin >= 1 && intpin <= 4) { 163186128Snwhitehorn /* 164186128Snwhitehorn * When an interrupt map is missing, we need to do the 165186128Snwhitehorn * standard PCI swizzle and continue mapping at the parent. 166186128Snwhitehorn */ 167186128Snwhitehorn return (pcib_route_interrupt(bridge, dev, intpin)); 168186128Snwhitehorn } 169186128Snwhitehorn return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent( 170186128Snwhitehorn bridge)), bridge, intpin)); 171186128Snwhitehorn} 172186128Snwhitehorn 173