common_bridge.c revision 4f5e7dd7
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 324f5e7dd7Smrg#include "config.h" 334f5e7dd7Smrg#include <stdio.h> 344f5e7dd7Smrg#include <stdlib.h> 354f5e7dd7Smrg#include <ctype.h> 364f5e7dd7Smrg#include <errno.h> 374f5e7dd7Smrg 384f5e7dd7Smrg#if defined(HAVE_STRING_H) 394f5e7dd7Smrg# include <string.h> 404f5e7dd7Smrg#elif defined(HAVE_STRINGS_H) 414f5e7dd7Smrg# include <strings.h> 424f5e7dd7Smrg#endif 434f5e7dd7Smrg 444f5e7dd7Smrg#if defined(HAVE_INTTYPES_H) 454f5e7dd7Smrg# include <inttypes.h> 464f5e7dd7Smrg#elif defined(HAVE_STDINT_H) 474f5e7dd7Smrg# include <stdint.h> 484f5e7dd7Smrg#endif 494f5e7dd7Smrg 504f5e7dd7Smrg#include "pciaccess.h" 514f5e7dd7Smrg#include "pciaccess_private.h" 524f5e7dd7Smrg 534f5e7dd7Smrgstatic int 544f5e7dd7Smrgread_bridge_info( struct pci_device_private * priv ) 554f5e7dd7Smrg{ 564f5e7dd7Smrg uint8_t buf[0x40]; 574f5e7dd7Smrg pciaddr_t bytes; 584f5e7dd7Smrg int err; 594f5e7dd7Smrg 604f5e7dd7Smrg 614f5e7dd7Smrg /* Make sure the device has been probed. If not, header_type won't be 624f5e7dd7Smrg * set and the rest of this function will fail. 634f5e7dd7Smrg */ 644f5e7dd7Smrg err = pci_device_probe(& priv->base); 654f5e7dd7Smrg if (err) { 664f5e7dd7Smrg return err; 674f5e7dd7Smrg } 684f5e7dd7Smrg 694f5e7dd7Smrg switch ( priv->header_type & 0x7f ) { 704f5e7dd7Smrg case 0x00: 714f5e7dd7Smrg break; 724f5e7dd7Smrg 734f5e7dd7Smrg case 0x01: { 744f5e7dd7Smrg struct pci_bridge_info *info; 754f5e7dd7Smrg 764f5e7dd7Smrg info = malloc(sizeof(*info)); 774f5e7dd7Smrg if (info != NULL) { 784f5e7dd7Smrg pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 794f5e7dd7Smrg 0x40 - 0x18, & bytes ); 804f5e7dd7Smrg 814f5e7dd7Smrg info->primary_bus = buf[0x18]; 824f5e7dd7Smrg info->secondary_bus = buf[0x19]; 834f5e7dd7Smrg info->subordinate_bus = buf[0x1a]; 844f5e7dd7Smrg info->secondary_latency_timer = buf[0x1b]; 854f5e7dd7Smrg 864f5e7dd7Smrg info->io_type = buf[0x1c] & 0x0f; 874f5e7dd7Smrg info->io_base = (((uint32_t) (buf[0x1c] & 0x0f0)) << 8) 884f5e7dd7Smrg + (((uint32_t) buf[0x30]) << 16) 894f5e7dd7Smrg + (((uint32_t) buf[0x31]) << 24); 904f5e7dd7Smrg 914f5e7dd7Smrg info->io_limit = 0x00000fff 924f5e7dd7Smrg + (((uint32_t) (buf[0x1d] & 0x0f0)) << 8) 934f5e7dd7Smrg + (((uint32_t) buf[0x32]) << 16) 944f5e7dd7Smrg + (((uint32_t) buf[0x33]) << 24); 954f5e7dd7Smrg 964f5e7dd7Smrg info->mem_type = buf[0x20] & 0x0f; 974f5e7dd7Smrg info->mem_base = (((uint32_t) (buf[0x20] & 0x0f0)) << 16) 984f5e7dd7Smrg + (((uint32_t) buf[0x21]) << 24); 994f5e7dd7Smrg 1004f5e7dd7Smrg info->mem_limit = 0x0000ffff 1014f5e7dd7Smrg + (((uint32_t) (buf[0x22] & 0x0f0)) << 16) 1024f5e7dd7Smrg + (((uint32_t) buf[0x23]) << 24); 1034f5e7dd7Smrg 1044f5e7dd7Smrg info->prefetch_mem_type = buf[0x24] & 0x0f; 1054f5e7dd7Smrg info->prefetch_mem_base = (((uint64_t) (buf[0x24] & 0x0f0)) << 16) 1064f5e7dd7Smrg + (((uint64_t) buf[0x25]) << 24) 1074f5e7dd7Smrg + (((uint64_t) buf[0x28]) << 32) 1084f5e7dd7Smrg + (((uint64_t) buf[0x29]) << 40) 1094f5e7dd7Smrg + (((uint64_t) buf[0x2a]) << 48) 1104f5e7dd7Smrg + (((uint64_t) buf[0x2b]) << 56); 1114f5e7dd7Smrg 1124f5e7dd7Smrg info->prefetch_mem_limit = 0x0000ffff 1134f5e7dd7Smrg + (((uint64_t) (buf[0x26] & 0x0f0)) << 16) 1144f5e7dd7Smrg + (((uint64_t) buf[0x27]) << 24) 1154f5e7dd7Smrg + (((uint64_t) buf[0x2c]) << 32) 1164f5e7dd7Smrg + (((uint64_t) buf[0x2d]) << 40) 1174f5e7dd7Smrg + (((uint64_t) buf[0x2e]) << 48) 1184f5e7dd7Smrg + (((uint64_t) buf[0x2f]) << 56); 1194f5e7dd7Smrg 1204f5e7dd7Smrg info->bridge_control = ((uint16_t) buf[0x3e]) 1214f5e7dd7Smrg + (((uint16_t) buf[0x3f]) << 8); 1224f5e7dd7Smrg 1234f5e7dd7Smrg info->secondary_status = ((uint16_t) buf[0x1e]) 1244f5e7dd7Smrg + (((uint16_t) buf[0x1f]) << 8); 1254f5e7dd7Smrg } 1264f5e7dd7Smrg 1274f5e7dd7Smrg priv->bridge.pci = info; 1284f5e7dd7Smrg break; 1294f5e7dd7Smrg } 1304f5e7dd7Smrg 1314f5e7dd7Smrg case 0x02: { 1324f5e7dd7Smrg struct pci_pcmcia_bridge_info *info; 1334f5e7dd7Smrg 1344f5e7dd7Smrg info = malloc(sizeof(*info)); 1354f5e7dd7Smrg if (info != NULL) { 1364f5e7dd7Smrg pci_device_cfg_read( (struct pci_device *) priv, buf + 0x16, 0x16, 1374f5e7dd7Smrg 0x40 - 0x16, & bytes ); 1384f5e7dd7Smrg 1394f5e7dd7Smrg info->primary_bus = buf[0x18]; 1404f5e7dd7Smrg info->card_bus = buf[0x19]; 1414f5e7dd7Smrg info->subordinate_bus = buf[0x1a]; 1424f5e7dd7Smrg info->cardbus_latency_timer = buf[0x1b]; 1434f5e7dd7Smrg 1444f5e7dd7Smrg info->mem[0].base = (((uint32_t) buf[0x1c])) 1454f5e7dd7Smrg + (((uint32_t) buf[0x1d]) << 8) 1464f5e7dd7Smrg + (((uint32_t) buf[0x1e]) << 16) 1474f5e7dd7Smrg + (((uint32_t) buf[0x1f]) << 24); 1484f5e7dd7Smrg 1494f5e7dd7Smrg info->mem[0].limit = (((uint32_t) buf[0x20])) 1504f5e7dd7Smrg + (((uint32_t) buf[0x21]) << 8) 1514f5e7dd7Smrg + (((uint32_t) buf[0x22]) << 16) 1524f5e7dd7Smrg + (((uint32_t) buf[0x23]) << 24); 1534f5e7dd7Smrg 1544f5e7dd7Smrg info->mem[1].base = (((uint32_t) buf[0x24])) 1554f5e7dd7Smrg + (((uint32_t) buf[0x25]) << 8) 1564f5e7dd7Smrg + (((uint32_t) buf[0x26]) << 16) 1574f5e7dd7Smrg + (((uint32_t) buf[0x27]) << 24); 1584f5e7dd7Smrg 1594f5e7dd7Smrg info->mem[1].limit = (((uint32_t) buf[0x28])) 1604f5e7dd7Smrg + (((uint32_t) buf[0x29]) << 8) 1614f5e7dd7Smrg + (((uint32_t) buf[0x2a]) << 16) 1624f5e7dd7Smrg + (((uint32_t) buf[0x2b]) << 24); 1634f5e7dd7Smrg 1644f5e7dd7Smrg info->io[0].base = (((uint32_t) buf[0x2c])) 1654f5e7dd7Smrg + (((uint32_t) buf[0x2d]) << 8) 1664f5e7dd7Smrg + (((uint32_t) buf[0x2e]) << 16) 1674f5e7dd7Smrg + (((uint32_t) buf[0x2f]) << 24); 1684f5e7dd7Smrg 1694f5e7dd7Smrg info->io[0].limit = (((uint32_t) buf[0x30])) 1704f5e7dd7Smrg + (((uint32_t) buf[0x31]) << 8) 1714f5e7dd7Smrg + (((uint32_t) buf[0x32]) << 16) 1724f5e7dd7Smrg + (((uint32_t) buf[0x33]) << 24); 1734f5e7dd7Smrg 1744f5e7dd7Smrg info->io[1].base = (((uint32_t) buf[0x34])) 1754f5e7dd7Smrg + (((uint32_t) buf[0x35]) << 8) 1764f5e7dd7Smrg + (((uint32_t) buf[0x36]) << 16) 1774f5e7dd7Smrg + (((uint32_t) buf[0x37]) << 24); 1784f5e7dd7Smrg 1794f5e7dd7Smrg info->io[1].limit = (((uint32_t) buf[0x38])) 1804f5e7dd7Smrg + (((uint32_t) buf[0x39]) << 8) 1814f5e7dd7Smrg + (((uint32_t) buf[0x3a]) << 16) 1824f5e7dd7Smrg + (((uint32_t) buf[0x3b]) << 24); 1834f5e7dd7Smrg 1844f5e7dd7Smrg info->secondary_status = ((uint16_t) buf[0x16]) 1854f5e7dd7Smrg + (((uint16_t) buf[0x17]) << 8); 1864f5e7dd7Smrg 1874f5e7dd7Smrg info->bridge_control = ((uint16_t) buf[0x3e]) 1884f5e7dd7Smrg + (((uint16_t) buf[0x3f]) << 8); 1894f5e7dd7Smrg } 1904f5e7dd7Smrg 1914f5e7dd7Smrg priv->bridge.pcmcia = info; 1924f5e7dd7Smrg break; 1934f5e7dd7Smrg } 1944f5e7dd7Smrg } 1954f5e7dd7Smrg 1964f5e7dd7Smrg return 0; 1974f5e7dd7Smrg} 1984f5e7dd7Smrg 1994f5e7dd7Smrg 2004f5e7dd7Smrg/** 2014f5e7dd7Smrg * Get the PCI bridge information for a device 2024f5e7dd7Smrg * 2034f5e7dd7Smrg * \returns 2044f5e7dd7Smrg * If \c dev is a PCI-to-PCI bridge, a pointer to a \c pci_bridge_info 2054f5e7dd7Smrg * structure. Otherwise, \c NULL is returned. 2064f5e7dd7Smrg */ 2074f5e7dd7Smrgconst struct pci_bridge_info * 2084f5e7dd7Smrgpci_device_get_bridge_info( struct pci_device * dev ) 2094f5e7dd7Smrg{ 2104f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2114f5e7dd7Smrg 2124f5e7dd7Smrg if (priv->bridge.pci == NULL) { 2134f5e7dd7Smrg read_bridge_info(priv); 2144f5e7dd7Smrg } 2154f5e7dd7Smrg 2164f5e7dd7Smrg return (priv->header_type == 1) ? priv->bridge.pci : NULL; 2174f5e7dd7Smrg} 2184f5e7dd7Smrg 2194f5e7dd7Smrg 2204f5e7dd7Smrg/** 2214f5e7dd7Smrg * Get the PCMCIA bridge information for a device 2224f5e7dd7Smrg * 2234f5e7dd7Smrg * \returns 2244f5e7dd7Smrg * If \c dev is a PCI-to-PCMCIA bridge, a pointer to a 2254f5e7dd7Smrg * \c pci_pcmcia_bridge_info structure. Otherwise, \c NULL is returned. 2264f5e7dd7Smrg */ 2274f5e7dd7Smrgconst struct pci_pcmcia_bridge_info * 2284f5e7dd7Smrgpci_device_get_pcmcia_bridge_info( struct pci_device * dev ) 2294f5e7dd7Smrg{ 2304f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2314f5e7dd7Smrg 2324f5e7dd7Smrg if (priv->bridge.pcmcia == NULL) { 2334f5e7dd7Smrg read_bridge_info(priv); 2344f5e7dd7Smrg } 2354f5e7dd7Smrg 2364f5e7dd7Smrg return (priv->header_type == 2) ? priv->bridge.pcmcia : NULL; 2374f5e7dd7Smrg} 2384f5e7dd7Smrg 2394f5e7dd7Smrg 2404f5e7dd7Smrg/** 2414f5e7dd7Smrg * Determine the primary, secondary, and subordinate buses for a bridge 2424f5e7dd7Smrg * 2434f5e7dd7Smrg * Determines the IDs of the primary, secondary, and subordinate buses for 2444f5e7dd7Smrg * a specified bridge. Not all bridges directly store this information 2454f5e7dd7Smrg * (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but 2464f5e7dd7Smrg * -1 is stored in the bus IDs that don't make sense. 2474f5e7dd7Smrg * 2484f5e7dd7Smrg * For example, for a PCI-to-ISA bridge, \c primary_bus will be set to the ID 2494f5e7dd7Smrg * of the bus containing the device and both \c secondary_bus and 2504f5e7dd7Smrg * \c subordinate_bus will be set to -1. 2514f5e7dd7Smrg * 2524f5e7dd7Smrg * \return 2534f5e7dd7Smrg * On success, zero is returned. If \c dev is not a bridge, \c ENODEV is 2544f5e7dd7Smrg * returned. 2554f5e7dd7Smrg * 2564f5e7dd7Smrg * \bug 2574f5e7dd7Smrg * Host bridges are handled the same way as PCI-to-ISA bridges. This is 2584f5e7dd7Smrg * almost certainly not correct. 2594f5e7dd7Smrg */ 2604f5e7dd7Smrgint 2614f5e7dd7Smrgpci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus, 2624f5e7dd7Smrg int *secondary_bus, int *subordinate_bus) 2634f5e7dd7Smrg{ 2644f5e7dd7Smrg struct pci_device_private * priv = (struct pci_device_private *) dev; 2654f5e7dd7Smrg 2664f5e7dd7Smrg /* If the device isn't a bridge, return an error. 2674f5e7dd7Smrg */ 2684f5e7dd7Smrg 2694f5e7dd7Smrg if (((dev->device_class >> 16) & 0x0ff) != 0x06) { 2704f5e7dd7Smrg return ENODEV; 2714f5e7dd7Smrg } 2724f5e7dd7Smrg 2734f5e7dd7Smrg switch ((dev->device_class >> 8) & 0x0ff) { 2744f5e7dd7Smrg case 0x00: 2754f5e7dd7Smrg /* What to do for host bridges? I'm pretty sure this isn't right. 2764f5e7dd7Smrg */ 2774f5e7dd7Smrg *primary_bus = dev->bus; 2784f5e7dd7Smrg *secondary_bus = -1; 2794f5e7dd7Smrg *subordinate_bus = -1; 2804f5e7dd7Smrg break; 2814f5e7dd7Smrg 2824f5e7dd7Smrg case 0x01: 2834f5e7dd7Smrg case 0x02: 2844f5e7dd7Smrg case 0x03: 2854f5e7dd7Smrg *primary_bus = dev->bus; 2864f5e7dd7Smrg *secondary_bus = -1; 2874f5e7dd7Smrg *subordinate_bus = -1; 2884f5e7dd7Smrg break; 2894f5e7dd7Smrg 2904f5e7dd7Smrg case 0x04: 2914f5e7dd7Smrg if (priv->bridge.pci == NULL) 2924f5e7dd7Smrg read_bridge_info(priv); 2934f5e7dd7Smrg if (priv->header_type == 0x01) { 2944f5e7dd7Smrg *primary_bus = priv->bridge.pci->primary_bus; 2954f5e7dd7Smrg *secondary_bus = priv->bridge.pci->secondary_bus; 2964f5e7dd7Smrg *subordinate_bus = priv->bridge.pci->subordinate_bus; 2974f5e7dd7Smrg } else { 2984f5e7dd7Smrg *primary_bus = dev->bus; 2994f5e7dd7Smrg *secondary_bus = -1; 3004f5e7dd7Smrg *subordinate_bus = -1; 3014f5e7dd7Smrg } 3024f5e7dd7Smrg break; 3034f5e7dd7Smrg 3044f5e7dd7Smrg case 0x07: 3054f5e7dd7Smrg if (priv->bridge.pcmcia == NULL) 3064f5e7dd7Smrg read_bridge_info(priv); 3074f5e7dd7Smrg if (priv->header_type == 0x02) { 3084f5e7dd7Smrg *primary_bus = priv->bridge.pcmcia->primary_bus; 3094f5e7dd7Smrg *secondary_bus = priv->bridge.pcmcia->card_bus; 3104f5e7dd7Smrg *subordinate_bus = priv->bridge.pcmcia->subordinate_bus; 3114f5e7dd7Smrg } else { 3124f5e7dd7Smrg *primary_bus = dev->bus; 3134f5e7dd7Smrg *secondary_bus = -1; 3144f5e7dd7Smrg *subordinate_bus = -1; 3154f5e7dd7Smrg } 3164f5e7dd7Smrg break; 3174f5e7dd7Smrg } 3184f5e7dd7Smrg 3194f5e7dd7Smrg return 0; 3204f5e7dd7Smrg} 321