ofw_pci.c revision 86231
186231Stmm/* 286231Stmm * Copyright (c) 1999, 2000 Matthew R. Green 386231Stmm * All rights reserved. 486231Stmm * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 586231Stmm * 686231Stmm * Redistribution and use in source and binary forms, with or without 786231Stmm * modification, are permitted provided that the following conditions 886231Stmm * are met: 986231Stmm * 1. Redistributions of source code must retain the above copyright 1086231Stmm * notice, this list of conditions and the following disclaimer. 1186231Stmm * 2. Redistributions in binary form must reproduce the above copyright 1286231Stmm * notice, this list of conditions and the following disclaimer in the 1386231Stmm * documentation and/or other materials provided with the distribution. 1486231Stmm * 3. The name of the author may not be used to endorse or promote products 1586231Stmm * derived from this software without specific prior written permission. 1686231Stmm * 1786231Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1886231Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1986231Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2086231Stmm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2186231Stmm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2286231Stmm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2386231Stmm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2486231Stmm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2586231Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2686231Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2786231Stmm * SUCH DAMAGE. 2886231Stmm * 2986231Stmm * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp 3086231Stmm * 3186231Stmm * $FreeBSD: head/sys/sparc64/pci/ofw_pci.c 86231 2001-11-09 20:19:58Z tmm $ 3286231Stmm */ 3386231Stmm 3486231Stmm#include "opt_ofw_pci.h" 3586231Stmm 3686231Stmm#include <sys/param.h> 3786231Stmm#include <sys/kernel.h> 3886231Stmm#include <sys/systm.h> 3986231Stmm#include <sys/bus.h> 4086231Stmm 4186231Stmm#include <dev/pci/pcivar.h> 4286231Stmm#include <dev/pci/pcireg.h> 4386231Stmm 4486231Stmm#include <dev/ofw/ofw_pci.h> 4586231Stmm#include <dev/ofw/openfirm.h> 4686231Stmm 4786231Stmm#include <sparc64/pci/ofw_pci.h> 4886231Stmm 4986231Stmm#include <machine/ofw_bus.h> 5086231Stmm 5186231Stmm#include "pcib_if.h" 5286231Stmm 5386231Stmm/* 5486231Stmm * Find the interrupt-map properties for a node. This might not be a property 5586231Stmm * of the parent, because there may be bridges in between, so go up through the 5686231Stmm * tree to find it. 5786231Stmm * This seems to be only needed for PCI systems, so it has not been moved to 5886231Stmm * ofw_bus.c 5986231Stmm */ 6086231Stmmint 6186231Stmmofw_pci_find_imap(phandle_t node, struct ofw_pci_imap **imap, 6286231Stmm struct ofw_pci_imap_msk *imapmsk) 6386231Stmm{ 6486231Stmm int nimap; 6586231Stmm 6686231Stmm nimap = -1; 6786231Stmm while ((node = OF_parent(node)) != 0) { 6886231Stmm if ((nimap = OF_getprop_alloc(node, "interrupt-map", 6986231Stmm sizeof(**imap), (void **)imap)) == -1 || 7086231Stmm OF_getprop(node, "interrupt-map-mask", 7186231Stmm imapmsk, sizeof(*imapmsk)) == -1) { 7286231Stmm if (*imap != NULL) { 7386231Stmm free(*imap, M_OFWPROP); 7486231Stmm *imap = NULL; 7586231Stmm } 7686231Stmm nimap = -1; 7786231Stmm } else 7886231Stmm break; 7986231Stmm } 8086231Stmm return (nimap); 8186231Stmm} 8286231Stmm 8386231Stmm/* 8486231Stmm * Route an interrupt using the firmware nodes. Returns 255 for interrupts 8586231Stmm * that cannot be routed (suitable for the PCI code). 8686231Stmm */ 8786231Stmmint 8886231Stmmofw_pci_route_intr2(int intr, struct ofw_pci_register *pcir, 8986231Stmm struct ofw_pci_imap *imap, int nimap, struct ofw_pci_imap_msk *imapmsk) 9086231Stmm{ 9186231Stmm char regm[12]; 9286231Stmm int cintr; 9386231Stmm 9486231Stmm cintr = ofw_bus_route_intr(intr, pcir, sizeof(*pcir), 12, 1, imap, 9586231Stmm nimap, imapmsk, regm); 9686231Stmm if (cintr == -1) 9786231Stmm return (255); 9886231Stmm else 9986231Stmm return (cintr); 10086231Stmm} 10186231Stmm 10286231Stmmint 10386231Stmmofw_pci_route_intr(phandle_t node, struct ofw_pci_register *pcir, 10486231Stmm struct ofw_pci_imap *intrmap, int nintrmap, 10586231Stmm struct ofw_pci_imap_msk *intrmapmsk) 10686231Stmm{ 10786231Stmm int intr; 10886231Stmm 10986231Stmm if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1) 11086231Stmm return (255); 11186231Stmm 11286231Stmm return (ofw_pci_route_intr2(intr, pcir, intrmap, nintrmap, intrmapmsk)); 11386231Stmm} 11486231Stmm 11586231Stmm#define OFW_PCI_PCIBUS "pci" 11686231Stmm/* 11786231Stmm * Walk the PCI bus hierarchy, starting with the root PCI bus and descending 11886231Stmm * through bridges, and initialize the interrupt line configuration registers 11986231Stmm * of attached devices using firmware information. 12086231Stmm */ 12186231Stmmvoid 12286231Stmmofw_pci_init_intr(device_t dev, phandle_t bus, struct ofw_pci_imap *intrmap, 12386231Stmm int nintrmap, struct ofw_pci_imap_msk *intrmapmsk) 12486231Stmm{ 12586231Stmm struct ofw_pci_imap_msk lintrmapmsk; 12686231Stmm struct ofw_pci_register pcir; 12786231Stmm phandle_t node; 12886231Stmm char type[32]; 12986231Stmm int intr; 13086231Stmm int freemap; 13186231Stmm 13286231Stmm if ((node = OF_child(bus)) == 0) 13386231Stmm return; 13486231Stmm freemap = 0; 13586231Stmm do { 13686231Stmm if (node == -1) 13786231Stmm panic("ofw_pci_init_intr: OF_child failed"); 13886231Stmm if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) 13986231Stmm type[0] = '\0'; 14086231Stmm else 14186231Stmm type[sizeof(type) - 1] = '\0'; 14286231Stmm if (strcmp(type, OFW_PCI_PCIBUS) == 0) { 14386231Stmm /* 14486231Stmm * This is a pci-pci bridge, recurse to initialize the 14586231Stmm * child bus. The hierarchy is usually at most 2 levels 14686231Stmm * deep, so recursion is feasible. 14786231Stmm */ 14886231Stmm#ifdef OFW_PCI_DEBUG 14986231Stmm device_printf(dev, __func__": descending to " 15086231Stmm "subordinate PCI bus\n"); 15186231Stmm#endif 15286231Stmm ofw_pci_init_intr(dev, node, NULL, 0, NULL); 15386231Stmm } else { 15486231Stmm if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 15586231Stmm panic("ofw_pci_route_intr: OF_getprop failed"); 15686231Stmm /* 15786231Stmm * If we didn't get interrupt map properties passed, 15886231Stmm * try to find them now. On some systems, buses that 15986231Stmm * have no non-bridge children have no such properties, 16086231Stmm * so only try to find them at need. 16186231Stmm */ 16286231Stmm if (intrmap == NULL) { 16386231Stmm nintrmap = OF_getprop_alloc(bus, 16486231Stmm "interrupt-map", sizeof(*intrmap), 16586231Stmm (void **)&intrmap); 16686231Stmm if (nintrmap == -1 || 16786231Stmm OF_getprop(bus, "interrupt-map-mask", 16886231Stmm &lintrmapmsk, sizeof(lintrmapmsk)) == -1) { 16986231Stmm panic("ofw_pci_init_intr: could not get " 17086231Stmm "interrupt map properties"); 17186231Stmm } 17286231Stmm intrmapmsk = &lintrmapmsk; 17386231Stmm freemap = 1; 17486231Stmm } 17586231Stmm if ((intr = ofw_pci_route_intr(node, &pcir, intrmap, 17686231Stmm nintrmap, intrmapmsk)) != 255) { 17786231Stmm#ifdef OFW_PCI_DEBUG 17886231Stmm device_printf(dev, __func__": mapping intr for " 17986231Stmm "%d/%d/%d to %d (preset was %d)\n", 18086231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 18186231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 18286231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 18386231Stmm intr, 18486231Stmm (int)PCIB_READ_CONFIG(dev, 18586231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 18686231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 18786231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 18886231Stmm PCIR_INTLINE, 1)); 18986231Stmm 19086231Stmm#endif /* OFW_PCI_DEBUG */ 19186231Stmm PCIB_WRITE_CONFIG(dev, 19286231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 19386231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 19486231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 19586231Stmm PCIR_INTLINE, intr, 1); 19686231Stmm } else { 19786231Stmm#ifdef OFW_PCI_DEBUG 19886231Stmm device_printf(dev, __func__": no interrupt " 19986231Stmm "mapping found for %d/%d/%d (preset %d)\n", 20086231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 20186231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 20286231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 20386231Stmm (int)PCIB_READ_CONFIG(dev, 20486231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 20586231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 20686231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 20786231Stmm PCIR_INTLINE, 1)); 20886231Stmm#endif /* OFW_PCI_DEBUG */ 20986231Stmm /* The firmware initializes to 0 instead 255 */ 21086231Stmm PCIB_WRITE_CONFIG(dev, 21186231Stmm OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 21286231Stmm OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 21386231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 21486231Stmm PCIR_INTLINE, 255, 1); 21586231Stmm } 21686231Stmm } 21786231Stmm } while ((node = OF_peer(node)) != 0); 21886231Stmm if (freemap) 21986231Stmm free(intrmap, M_OFWPROP); 22086231Stmm} 22186231Stmm 22286231Stmmphandle_t 22386231Stmmofw_pci_find_node(int bus, int slot, int func) 22486231Stmm{ 22586231Stmm phandle_t node, bnode, parent; 22686231Stmm struct ofw_pci_register pcir; 22786231Stmm int br[2]; 22886231Stmm char name[16]; 22986231Stmm 23086231Stmm /* 1. Try to find the bus in question. */ 23186231Stmm bnode = 0; 23286231Stmm name[sizeof(name) - 1] = '\0'; 23386231Stmm parent = OF_peer(0); 23486231Stmm node = OF_child(parent); 23586231Stmm while (node != 0 && node != -1) { 23686231Stmm if (OF_getprop(node, "name", name, sizeof(name) - 1) != -1 && 23786231Stmm strcmp(name, "pci") == 0 && 23886231Stmm OF_getprop(node, "bus-range", br, sizeof(br)) != -1) { 23986231Stmm /* Found the bus? */ 24086231Stmm if (bus == br[0]) { 24186231Stmm bnode = node; 24286231Stmm break; 24386231Stmm } 24486231Stmm /* Need to descend? */ 24586231Stmm if (bus > br[0] && bus <= br[1]) { 24686231Stmm parent = node; 24786231Stmm node = OF_child(node); 24886231Stmm continue; 24986231Stmm } 25086231Stmm } 25186231Stmm node = OF_peer(node); 25286231Stmm } 25386231Stmm if (bnode == 0) 25486231Stmm return (0); 25586231Stmm for (node = OF_child(bnode); node != 0 && node != -1; 25686231Stmm node = OF_peer(node)) { 25786231Stmm if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 25886231Stmm continue; 25986231Stmm if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot && 26086231Stmm OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func) { 26186231Stmm if (OFW_PCI_PHYS_HI_BUS(pcir.phys_hi) != bus) 26286231Stmm panic("ofw_pci_find_node: bus number mismatch"); 26386231Stmm return (node); 26486231Stmm } 26586231Stmm } 26686231Stmm return (0); 26786231Stmm} 268