common_bridge.c revision 447862d0
14f5e7dd7Smrg/* 24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006 34f5e7dd7Smrg * All Rights Reserved. 44f5e7dd7Smrg * 54f5e7dd7Smrg * Permission is hereby granted, free of charge, to any person obtaining a 64f5e7dd7Smrg * copy of this software and associated documentation files (the "Software"), 74f5e7dd7Smrg * to deal in the Software without restriction, including without limitation 84f5e7dd7Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 94f5e7dd7Smrg * license, and/or sell copies of the Software, and to permit persons to whom 104f5e7dd7Smrg * the Software is furnished to do so, subject to the following conditions: 114f5e7dd7Smrg * 124f5e7dd7Smrg * The above copyright notice and this permission notice (including the next 134f5e7dd7Smrg * paragraph) shall be included in all copies or substantial portions of the 144f5e7dd7Smrg * Software. 154f5e7dd7Smrg * 164f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 174f5e7dd7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 184f5e7dd7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 194f5e7dd7Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 204f5e7dd7Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 214f5e7dd7Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 224f5e7dd7Smrg * DEALINGS IN THE SOFTWARE. 234f5e7dd7Smrg */ 244f5e7dd7Smrg 254f5e7dd7Smrg/** 264f5e7dd7Smrg * \file common_bridge.c 274f5e7dd7Smrg * Support routines used to process PCI header information for bridges. 284f5e7dd7Smrg * 294f5e7dd7Smrg * \author Ian Romanick <idr@us.ibm.com> 304f5e7dd7Smrg */ 314f5e7dd7Smrg 3247fd271eSmrg#if defined(HAVE_CONFIG_H) 334f5e7dd7Smrg#include "config.h" 3447fd271eSmrg#endif 3547fd271eSmrg 364f5e7dd7Smrg#include <stdio.h> 374f5e7dd7Smrg#include <stdlib.h> 384f5e7dd7Smrg#include <ctype.h> 394f5e7dd7Smrg#include <errno.h> 404f5e7dd7Smrg 414f5e7dd7Smrg#if defined(HAVE_STRING_H) 424f5e7dd7Smrg# include <string.h> 434f5e7dd7Smrg#elif defined(HAVE_STRINGS_H) 444f5e7dd7Smrg# include <strings.h> 454f5e7dd7Smrg#endif 464f5e7dd7Smrg 474f5e7dd7Smrg#if defined(HAVE_INTTYPES_H) 484f5e7dd7Smrg# include <inttypes.h> 494f5e7dd7Smrg#elif defined(HAVE_STDINT_H) 504f5e7dd7Smrg# include <stdint.h> 514f5e7dd7Smrg#endif 524f5e7dd7Smrg 534f5e7dd7Smrg#include "pciaccess.h" 544f5e7dd7Smrg#include "pciaccess_private.h" 554f5e7dd7Smrg 564f5e7dd7Smrgstatic int 574f5e7dd7Smrgread_bridge_info( struct pci_device_private * priv ) 584f5e7dd7Smrg{ 594f5e7dd7Smrg uint8_t buf[0x40]; 604f5e7dd7Smrg pciaddr_t bytes; 614f5e7dd7Smrg int err; 624f5e7dd7Smrg 634f5e7dd7Smrg 644f5e7dd7Smrg /* Make sure the device has been probed. If not, header_type won't be 654f5e7dd7Smrg * set and the rest of this function will fail. 664f5e7dd7Smrg */ 674f5e7dd7Smrg err = pci_device_probe(& priv->base); 684f5e7dd7Smrg if (err) { 694f5e7dd7Smrg return err; 704f5e7dd7Smrg } 714f5e7dd7Smrg 724f5e7dd7Smrg switch ( priv->header_type & 0x7f ) { 734f5e7dd7Smrg case 0x00: 744f5e7dd7Smrg break; 754f5e7dd7Smrg 764f5e7dd7Smrg case 0x01: { 774f5e7dd7Smrg struct pci_bridge_info *info; 784f5e7dd7Smrg 794f5e7dd7Smrg info = malloc(sizeof(*info)); 804f5e7dd7Smrg if (info != NULL) { 814f5e7dd7Smrg pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 824f5e7dd7Smrg 0x40 - 0x18, & bytes ); 834f5e7dd7Smrg 844f5e7dd7Smrg info->primary_bus = buf[0x18]; 854f5e7dd7Smrg info->secondary_bus = buf[0x19]; 864f5e7dd7Smrg info->subordinate_bus = buf[0x1a]; 874f5e7dd7Smrg info->secondary_latency_timer = buf[0x1b]; 884f5e7dd7Smrg 894f5e7dd7Smrg info->io_type = buf[0x1c] & 0x0f; 904f5e7dd7Smrg info->io_base = (((uint32_t) (buf[0x1c] & 0x0f0)) << 8) 914f5e7dd7Smrg + (((uint32_t) buf[0x30]) << 16) 924f5e7dd7Smrg + (((uint32_t) buf[0x31]) << 24); 934f5e7dd7Smrg 944f5e7dd7Smrg info->io_limit = 0x00000fff 954f5e7dd7Smrg + (((uint32_t) (buf[0x1d] & 0x0f0)) << 8) 964f5e7dd7Smrg + (((uint32_t) buf[0x32]) << 16) 974f5e7dd7Smrg + (((uint32_t) buf[0x33]) << 24); 984f5e7dd7Smrg 994f5e7dd7Smrg info->mem_type = buf[0x20] & 0x0f; 1004f5e7dd7Smrg info->mem_base = (((uint32_t) (buf[0x20] & 0x0f0)) << 16) 1014f5e7dd7Smrg + (((uint32_t) buf[0x21]) << 24); 1024f5e7dd7Smrg 1034f5e7dd7Smrg info->mem_limit = 0x0000ffff 1044f5e7dd7Smrg + (((uint32_t) (buf[0x22] & 0x0f0)) << 16) 1054f5e7dd7Smrg + (((uint32_t) buf[0x23]) << 24); 1064f5e7dd7Smrg 1074f5e7dd7Smrg info->prefetch_mem_type = buf[0x24] & 0x0f; 1084f5e7dd7Smrg info->prefetch_mem_base = (((uint64_t) (buf[0x24] & 0x0f0)) << 16) 1094f5e7dd7Smrg + (((uint64_t) buf[0x25]) << 24) 1104f5e7dd7Smrg + (((uint64_t) buf[0x28]) << 32) 1114f5e7dd7Smrg + (((uint64_t) buf[0x29]) << 40) 1124f5e7dd7Smrg + (((uint64_t) buf[0x2a]) << 48) 1134f5e7dd7Smrg + (((uint64_t) buf[0x2b]) << 56); 1144f5e7dd7Smrg 1154f5e7dd7Smrg info->prefetch_mem_limit = 0x0000ffff 1164f5e7dd7Smrg + (((uint64_t) (buf[0x26] & 0x0f0)) << 16) 1174f5e7dd7Smrg + (((uint64_t) buf[0x27]) << 24) 1184f5e7dd7Smrg + (((uint64_t) buf[0x2c]) << 32) 1194f5e7dd7Smrg + (((uint64_t) buf[0x2d]) << 40) 1204f5e7dd7Smrg + (((uint64_t) buf[0x2e]) << 48) 1214f5e7dd7Smrg + (((uint64_t) buf[0x2f]) << 56); 1224f5e7dd7Smrg 1234f5e7dd7Smrg info->bridge_control = ((uint16_t) buf[0x3e]) 1244f5e7dd7Smrg + (((uint16_t) buf[0x3f]) << 8); 1254f5e7dd7Smrg 1264f5e7dd7Smrg info->secondary_status = ((uint16_t) buf[0x1e]) 1274f5e7dd7Smrg + (((uint16_t) buf[0x1f]) << 8); 1284f5e7dd7Smrg } 1294f5e7dd7Smrg 1304f5e7dd7Smrg priv->bridge.pci = info; 1314f5e7dd7Smrg break; 1324f5e7dd7Smrg } 1334f5e7dd7Smrg 1344f5e7dd7Smrg case 0x02: { 1354f5e7dd7Smrg struct pci_pcmcia_bridge_info *info; 1364f5e7dd7Smrg 1374f5e7dd7Smrg info = malloc(sizeof(*info)); 1384f5e7dd7Smrg if (info != NULL) { 1394f5e7dd7Smrg pci_device_cfg_read( (struct pci_device *) priv, buf + 0x16, 0x16, 1404f5e7dd7Smrg 0x40 - 0x16, & bytes ); 1414f5e7dd7Smrg 1424f5e7dd7Smrg info->primary_bus = buf[0x18]; 1434f5e7dd7Smrg info->card_bus = buf[0x19]; 1444f5e7dd7Smrg info->subordinate_bus = buf[0x1a]; 1454f5e7dd7Smrg info->cardbus_latency_timer = buf[0x1b]; 1464f5e7dd7Smrg 1474f5e7dd7Smrg info->mem[0].base = (((uint32_t) buf[0x1c])) 1484f5e7dd7Smrg + (((uint32_t) buf[0x1d]) << 8) 1494f5e7dd7Smrg + (((uint32_t) buf[0x1e]) << 16) 1504f5e7dd7Smrg + (((uint32_t) buf[0x1f]) << 24); 1514f5e7dd7Smrg 1524f5e7dd7Smrg info->mem[0].limit = (((uint32_t) buf[0x20])) 1534f5e7dd7Smrg + (((uint32_t) buf[0x21]) << 8) 1544f5e7dd7Smrg + (((uint32_t) buf[0x22]) << 16) 1554f5e7dd7Smrg + (((uint32_t) buf[0x23]) << 24); 1564f5e7dd7Smrg 1574f5e7dd7Smrg info->mem[1].base = (((uint32_t) buf[0x24])) 1584f5e7dd7Smrg + (((uint32_t) buf[0x25]) << 8) 1594f5e7dd7Smrg + (((uint32_t) buf[0x26]) << 16) 1604f5e7dd7Smrg + (((uint32_t) buf[0x27]) << 24); 1614f5e7dd7Smrg 1624f5e7dd7Smrg info->mem[1].limit = (((uint32_t) buf[0x28])) 1634f5e7dd7Smrg + (((uint32_t) buf[0x29]) << 8) 1644f5e7dd7Smrg + (((uint32_t) buf[0x2a]) << 16) 1654f5e7dd7Smrg + (((uint32_t) buf[0x2b]) << 24); 1664f5e7dd7Smrg 1674f5e7dd7Smrg info->io[0].base = (((uint32_t) buf[0x2c])) 1684f5e7dd7Smrg + (((uint32_t) buf[0x2d]) << 8) 1694f5e7dd7Smrg + (((uint32_t) buf[0x2e]) << 16) 1704f5e7dd7Smrg + (((uint32_t) buf[0x2f]) << 24); 1714f5e7dd7Smrg 1724f5e7dd7Smrg info->io[0].limit = (((uint32_t) buf[0x30])) 1734f5e7dd7Smrg + (((uint32_t) buf[0x31]) << 8) 1744f5e7dd7Smrg + (((uint32_t) buf[0x32]) << 16) 1754f5e7dd7Smrg + (((uint32_t) buf[0x33]) << 24); 1764f5e7dd7Smrg 1774f5e7dd7Smrg info->io[1].base = (((uint32_t) buf[0x34])) 1784f5e7dd7Smrg + (((uint32_t) buf[0x35]) << 8) 1794f5e7dd7Smrg + (((uint32_t) buf[0x36]) << 16) 1804f5e7dd7Smrg + (((uint32_t) buf[0x37]) << 24); 1814f5e7dd7Smrg 1824f5e7dd7Smrg info->io[1].limit = (((uint32_t) buf[0x38])) 1834f5e7dd7Smrg + (((uint32_t) buf[0x39]) << 8) 1844f5e7dd7Smrg + (((uint32_t) buf[0x3a]) << 16) 1854f5e7dd7Smrg + (((uint32_t) buf[0x3b]) << 24); 1864f5e7dd7Smrg 1874f5e7dd7Smrg info->secondary_status = ((uint16_t) buf[0x16]) 1884f5e7dd7Smrg + (((uint16_t) buf[0x17]) << 8); 1894f5e7dd7Smrg 1904f5e7dd7Smrg info->bridge_control = ((uint16_t) buf[0x3e]) 1914f5e7dd7Smrg + (((uint16_t) buf[0x3f]) << 8); 1924f5e7dd7Smrg } 1934f5e7dd7Smrg 1944f5e7dd7Smrg priv->bridge.pcmcia = info; 1954f5e7dd7Smrg break; 1964f5e7dd7Smrg } 1974f5e7dd7Smrg } 1984f5e7dd7Smrg 1994f5e7dd7Smrg return 0; 2004f5e7dd7Smrg} 2014f5e7dd7Smrg 2024f5e7dd7Smrg 2034f5e7dd7Smrg/** 2044f5e7dd7Smrg * Get the PCI bridge information for a device 2054f5e7dd7Smrg * 2064f5e7dd7Smrg * \returns 2074f5e7dd7Smrg * If \c dev is a PCI-to-PCI bridge, a pointer to a \c pci_bridge_info 2084f5e7dd7Smrg * structure. Otherwise, \c NULL is returned. 2094f5e7dd7Smrg */ 2104f5e7dd7Smrgconst struct pci_bridge_info * 2114f5e7dd7Smrgpci_device_get_bridge_info( struct pci_device * dev ) 2124f5e7dd7Smrg{ 2134f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2144f5e7dd7Smrg 2154f5e7dd7Smrg if (priv->bridge.pci == NULL) { 2164f5e7dd7Smrg read_bridge_info(priv); 2174f5e7dd7Smrg } 2184f5e7dd7Smrg 2194f5e7dd7Smrg return (priv->header_type == 1) ? priv->bridge.pci : NULL; 2204f5e7dd7Smrg} 2214f5e7dd7Smrg 2224f5e7dd7Smrg 2234f5e7dd7Smrg/** 2244f5e7dd7Smrg * Get the PCMCIA bridge information for a device 2254f5e7dd7Smrg * 2264f5e7dd7Smrg * \returns 2274f5e7dd7Smrg * If \c dev is a PCI-to-PCMCIA bridge, a pointer to a 2284f5e7dd7Smrg * \c pci_pcmcia_bridge_info structure. Otherwise, \c NULL is returned. 2294f5e7dd7Smrg */ 2304f5e7dd7Smrgconst struct pci_pcmcia_bridge_info * 2314f5e7dd7Smrgpci_device_get_pcmcia_bridge_info( struct pci_device * dev ) 2324f5e7dd7Smrg{ 2334f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2344f5e7dd7Smrg 2354f5e7dd7Smrg if (priv->bridge.pcmcia == NULL) { 2364f5e7dd7Smrg read_bridge_info(priv); 2374f5e7dd7Smrg } 2384f5e7dd7Smrg 2394f5e7dd7Smrg return (priv->header_type == 2) ? priv->bridge.pcmcia : NULL; 2404f5e7dd7Smrg} 2414f5e7dd7Smrg 2424f5e7dd7Smrg 2434f5e7dd7Smrg/** 2444f5e7dd7Smrg * Determine the primary, secondary, and subordinate buses for a bridge 2454f5e7dd7Smrg * 2464f5e7dd7Smrg * Determines the IDs of the primary, secondary, and subordinate buses for 2474f5e7dd7Smrg * a specified bridge. Not all bridges directly store this information 2484f5e7dd7Smrg * (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but 2494f5e7dd7Smrg * -1 is stored in the bus IDs that don't make sense. 2504f5e7dd7Smrg * 2514f5e7dd7Smrg * For example, for a PCI-to-ISA bridge, \c primary_bus will be set to the ID 2524f5e7dd7Smrg * of the bus containing the device and both \c secondary_bus and 2534f5e7dd7Smrg * \c subordinate_bus will be set to -1. 2544f5e7dd7Smrg * 2554f5e7dd7Smrg * \return 2564f5e7dd7Smrg * On success, zero is returned. If \c dev is not a bridge, \c ENODEV is 2574f5e7dd7Smrg * returned. 2584f5e7dd7Smrg * 2594f5e7dd7Smrg * \bug 2604f5e7dd7Smrg * Host bridges are handled the same way as PCI-to-ISA bridges. This is 2614f5e7dd7Smrg * almost certainly not correct. 2624f5e7dd7Smrg */ 2634f5e7dd7Smrgint 2644f5e7dd7Smrgpci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus, 2654f5e7dd7Smrg int *secondary_bus, int *subordinate_bus) 2664f5e7dd7Smrg{ 2674f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2684f5e7dd7Smrg 2694f5e7dd7Smrg /* If the device isn't a bridge, return an error. 2704f5e7dd7Smrg */ 2714f5e7dd7Smrg 2724f5e7dd7Smrg if (((dev->device_class >> 16) & 0x0ff) != 0x06) { 2734f5e7dd7Smrg return ENODEV; 2744f5e7dd7Smrg } 2754f5e7dd7Smrg 2764f5e7dd7Smrg switch ((dev->device_class >> 8) & 0x0ff) { 2774f5e7dd7Smrg case 0x00: 2784f5e7dd7Smrg /* What to do for host bridges? I'm pretty sure this isn't right. 2794f5e7dd7Smrg */ 2804f5e7dd7Smrg *primary_bus = dev->bus; 2814f5e7dd7Smrg *secondary_bus = -1; 2824f5e7dd7Smrg *subordinate_bus = -1; 2834f5e7dd7Smrg break; 2844f5e7dd7Smrg 2854f5e7dd7Smrg case 0x01: 2864f5e7dd7Smrg case 0x02: 2874f5e7dd7Smrg case 0x03: 2884f5e7dd7Smrg *primary_bus = dev->bus; 2894f5e7dd7Smrg *secondary_bus = -1; 2904f5e7dd7Smrg *subordinate_bus = -1; 2914f5e7dd7Smrg break; 2924f5e7dd7Smrg 2934f5e7dd7Smrg case 0x04: 2944f5e7dd7Smrg if (priv->bridge.pci == NULL) 2954f5e7dd7Smrg read_bridge_info(priv); 296447862d0Smrg if ((priv->header_type & 0x7f) == 0x01) { 2974f5e7dd7Smrg *primary_bus = priv->bridge.pci->primary_bus; 2984f5e7dd7Smrg *secondary_bus = priv->bridge.pci->secondary_bus; 2994f5e7dd7Smrg *subordinate_bus = priv->bridge.pci->subordinate_bus; 3004f5e7dd7Smrg } else { 3014f5e7dd7Smrg *primary_bus = dev->bus; 3024f5e7dd7Smrg *secondary_bus = -1; 3034f5e7dd7Smrg *subordinate_bus = -1; 3044f5e7dd7Smrg } 3054f5e7dd7Smrg break; 3064f5e7dd7Smrg 3074f5e7dd7Smrg case 0x07: 3084f5e7dd7Smrg if (priv->bridge.pcmcia == NULL) 3094f5e7dd7Smrg read_bridge_info(priv); 310447862d0Smrg if ((priv->header_type & 0x7f) == 0x02) { 3114f5e7dd7Smrg *primary_bus = priv->bridge.pcmcia->primary_bus; 3124f5e7dd7Smrg *secondary_bus = priv->bridge.pcmcia->card_bus; 3134f5e7dd7Smrg *subordinate_bus = priv->bridge.pcmcia->subordinate_bus; 3144f5e7dd7Smrg } else { 3154f5e7dd7Smrg *primary_bus = dev->bus; 3164f5e7dd7Smrg *secondary_bus = -1; 3174f5e7dd7Smrg *subordinate_bus = -1; 3184f5e7dd7Smrg } 3194f5e7dd7Smrg break; 3204f5e7dd7Smrg } 3214f5e7dd7Smrg 3224f5e7dd7Smrg return 0; 3234f5e7dd7Smrg} 3241b2ce5a6Smrg 3251b2ce5a6Smrg#define PCI_CLASS_BRIDGE 0x06 3261b2ce5a6Smrg#define PCI_SUBCLASS_BRIDGE_PCI 0x04 3271b2ce5a6Smrg 3281b2ce5a6Smrgstruct pci_device * 3291b2ce5a6Smrgpci_device_get_parent_bridge(struct pci_device *dev) 3301b2ce5a6Smrg{ 3311b2ce5a6Smrg struct pci_id_match bridge_match = { 3321b2ce5a6Smrg PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 3331b2ce5a6Smrg (PCI_CLASS_BRIDGE << 16) | (PCI_SUBCLASS_BRIDGE_PCI << 8), 3341b2ce5a6Smrg 0 3351b2ce5a6Smrg }; 3361b2ce5a6Smrg 3371b2ce5a6Smrg struct pci_device *bridge; 3381b2ce5a6Smrg struct pci_device_iterator *iter; 3391b2ce5a6Smrg 3401b2ce5a6Smrg if (dev == NULL) 3411b2ce5a6Smrg return NULL; 3421b2ce5a6Smrg 3431b2ce5a6Smrg iter = pci_id_match_iterator_create(& bridge_match); 3441b2ce5a6Smrg if (iter == NULL) 3451b2ce5a6Smrg return NULL; 3461b2ce5a6Smrg 3471b2ce5a6Smrg while ((bridge = pci_device_next(iter)) != NULL) { 3481b2ce5a6Smrg if (bridge->domain == dev->domain) { 3491b2ce5a6Smrg const struct pci_bridge_info *info = 3501b2ce5a6Smrg pci_device_get_bridge_info(bridge); 3511b2ce5a6Smrg 3521b2ce5a6Smrg if (info != NULL) { 3531b2ce5a6Smrg if (info->secondary_bus == dev->bus) { 3541b2ce5a6Smrg break; 3551b2ce5a6Smrg } 3561b2ce5a6Smrg } 3571b2ce5a6Smrg } 3581b2ce5a6Smrg } 3591b2ce5a6Smrg 3601b2ce5a6Smrg pci_iterator_destroy(iter); 3611b2ce5a6Smrg 3621b2ce5a6Smrg return bridge; 3631b2ce5a6Smrg} 364