common_bridge.c revision 1b2ce5a6
1/* 2 * (C) Copyright IBM Corporation 2006 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file common_bridge.c 27 * Support routines used to process PCI header information for bridges. 28 * 29 * \author Ian Romanick <idr@us.ibm.com> 30 */ 31 32#if defined(HAVE_CONFIG_H) 33#include "config.h" 34#endif 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <ctype.h> 39#include <errno.h> 40 41#if defined(HAVE_STRING_H) 42# include <string.h> 43#elif defined(HAVE_STRINGS_H) 44# include <strings.h> 45#endif 46 47#if defined(HAVE_INTTYPES_H) 48# include <inttypes.h> 49#elif defined(HAVE_STDINT_H) 50# include <stdint.h> 51#endif 52 53#include "pciaccess.h" 54#include "pciaccess_private.h" 55 56static int 57read_bridge_info( struct pci_device_private * priv ) 58{ 59 uint8_t buf[0x40]; 60 pciaddr_t bytes; 61 int err; 62 63 64 /* Make sure the device has been probed. If not, header_type won't be 65 * set and the rest of this function will fail. 66 */ 67 err = pci_device_probe(& priv->base); 68 if (err) { 69 return err; 70 } 71 72 switch ( priv->header_type & 0x7f ) { 73 case 0x00: 74 break; 75 76 case 0x01: { 77 struct pci_bridge_info *info; 78 79 info = malloc(sizeof(*info)); 80 if (info != NULL) { 81 pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 82 0x40 - 0x18, & bytes ); 83 84 info->primary_bus = buf[0x18]; 85 info->secondary_bus = buf[0x19]; 86 info->subordinate_bus = buf[0x1a]; 87 info->secondary_latency_timer = buf[0x1b]; 88 89 info->io_type = buf[0x1c] & 0x0f; 90 info->io_base = (((uint32_t) (buf[0x1c] & 0x0f0)) << 8) 91 + (((uint32_t) buf[0x30]) << 16) 92 + (((uint32_t) buf[0x31]) << 24); 93 94 info->io_limit = 0x00000fff 95 + (((uint32_t) (buf[0x1d] & 0x0f0)) << 8) 96 + (((uint32_t) buf[0x32]) << 16) 97 + (((uint32_t) buf[0x33]) << 24); 98 99 info->mem_type = buf[0x20] & 0x0f; 100 info->mem_base = (((uint32_t) (buf[0x20] & 0x0f0)) << 16) 101 + (((uint32_t) buf[0x21]) << 24); 102 103 info->mem_limit = 0x0000ffff 104 + (((uint32_t) (buf[0x22] & 0x0f0)) << 16) 105 + (((uint32_t) buf[0x23]) << 24); 106 107 info->prefetch_mem_type = buf[0x24] & 0x0f; 108 info->prefetch_mem_base = (((uint64_t) (buf[0x24] & 0x0f0)) << 16) 109 + (((uint64_t) buf[0x25]) << 24) 110 + (((uint64_t) buf[0x28]) << 32) 111 + (((uint64_t) buf[0x29]) << 40) 112 + (((uint64_t) buf[0x2a]) << 48) 113 + (((uint64_t) buf[0x2b]) << 56); 114 115 info->prefetch_mem_limit = 0x0000ffff 116 + (((uint64_t) (buf[0x26] & 0x0f0)) << 16) 117 + (((uint64_t) buf[0x27]) << 24) 118 + (((uint64_t) buf[0x2c]) << 32) 119 + (((uint64_t) buf[0x2d]) << 40) 120 + (((uint64_t) buf[0x2e]) << 48) 121 + (((uint64_t) buf[0x2f]) << 56); 122 123 info->bridge_control = ((uint16_t) buf[0x3e]) 124 + (((uint16_t) buf[0x3f]) << 8); 125 126 info->secondary_status = ((uint16_t) buf[0x1e]) 127 + (((uint16_t) buf[0x1f]) << 8); 128 } 129 130 priv->bridge.pci = info; 131 break; 132 } 133 134 case 0x02: { 135 struct pci_pcmcia_bridge_info *info; 136 137 info = malloc(sizeof(*info)); 138 if (info != NULL) { 139 pci_device_cfg_read( (struct pci_device *) priv, buf + 0x16, 0x16, 140 0x40 - 0x16, & bytes ); 141 142 info->primary_bus = buf[0x18]; 143 info->card_bus = buf[0x19]; 144 info->subordinate_bus = buf[0x1a]; 145 info->cardbus_latency_timer = buf[0x1b]; 146 147 info->mem[0].base = (((uint32_t) buf[0x1c])) 148 + (((uint32_t) buf[0x1d]) << 8) 149 + (((uint32_t) buf[0x1e]) << 16) 150 + (((uint32_t) buf[0x1f]) << 24); 151 152 info->mem[0].limit = (((uint32_t) buf[0x20])) 153 + (((uint32_t) buf[0x21]) << 8) 154 + (((uint32_t) buf[0x22]) << 16) 155 + (((uint32_t) buf[0x23]) << 24); 156 157 info->mem[1].base = (((uint32_t) buf[0x24])) 158 + (((uint32_t) buf[0x25]) << 8) 159 + (((uint32_t) buf[0x26]) << 16) 160 + (((uint32_t) buf[0x27]) << 24); 161 162 info->mem[1].limit = (((uint32_t) buf[0x28])) 163 + (((uint32_t) buf[0x29]) << 8) 164 + (((uint32_t) buf[0x2a]) << 16) 165 + (((uint32_t) buf[0x2b]) << 24); 166 167 info->io[0].base = (((uint32_t) buf[0x2c])) 168 + (((uint32_t) buf[0x2d]) << 8) 169 + (((uint32_t) buf[0x2e]) << 16) 170 + (((uint32_t) buf[0x2f]) << 24); 171 172 info->io[0].limit = (((uint32_t) buf[0x30])) 173 + (((uint32_t) buf[0x31]) << 8) 174 + (((uint32_t) buf[0x32]) << 16) 175 + (((uint32_t) buf[0x33]) << 24); 176 177 info->io[1].base = (((uint32_t) buf[0x34])) 178 + (((uint32_t) buf[0x35]) << 8) 179 + (((uint32_t) buf[0x36]) << 16) 180 + (((uint32_t) buf[0x37]) << 24); 181 182 info->io[1].limit = (((uint32_t) buf[0x38])) 183 + (((uint32_t) buf[0x39]) << 8) 184 + (((uint32_t) buf[0x3a]) << 16) 185 + (((uint32_t) buf[0x3b]) << 24); 186 187 info->secondary_status = ((uint16_t) buf[0x16]) 188 + (((uint16_t) buf[0x17]) << 8); 189 190 info->bridge_control = ((uint16_t) buf[0x3e]) 191 + (((uint16_t) buf[0x3f]) << 8); 192 } 193 194 priv->bridge.pcmcia = info; 195 break; 196 } 197 } 198 199 return 0; 200} 201 202 203/** 204 * Get the PCI bridge information for a device 205 * 206 * \returns 207 * If \c dev is a PCI-to-PCI bridge, a pointer to a \c pci_bridge_info 208 * structure. Otherwise, \c NULL is returned. 209 */ 210const struct pci_bridge_info * 211pci_device_get_bridge_info( struct pci_device * dev ) 212{ 213 struct pci_device_private * priv = (struct pci_device_private *) dev; 214 215 if (priv->bridge.pci == NULL) { 216 read_bridge_info(priv); 217 } 218 219 return (priv->header_type == 1) ? priv->bridge.pci : NULL; 220} 221 222 223/** 224 * Get the PCMCIA bridge information for a device 225 * 226 * \returns 227 * If \c dev is a PCI-to-PCMCIA bridge, a pointer to a 228 * \c pci_pcmcia_bridge_info structure. Otherwise, \c NULL is returned. 229 */ 230const struct pci_pcmcia_bridge_info * 231pci_device_get_pcmcia_bridge_info( struct pci_device * dev ) 232{ 233 struct pci_device_private * priv = (struct pci_device_private *) dev; 234 235 if (priv->bridge.pcmcia == NULL) { 236 read_bridge_info(priv); 237 } 238 239 return (priv->header_type == 2) ? priv->bridge.pcmcia : NULL; 240} 241 242 243/** 244 * Determine the primary, secondary, and subordinate buses for a bridge 245 * 246 * Determines the IDs of the primary, secondary, and subordinate buses for 247 * a specified bridge. Not all bridges directly store this information 248 * (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but 249 * -1 is stored in the bus IDs that don't make sense. 250 * 251 * For example, for a PCI-to-ISA bridge, \c primary_bus will be set to the ID 252 * of the bus containing the device and both \c secondary_bus and 253 * \c subordinate_bus will be set to -1. 254 * 255 * \return 256 * On success, zero is returned. If \c dev is not a bridge, \c ENODEV is 257 * returned. 258 * 259 * \bug 260 * Host bridges are handled the same way as PCI-to-ISA bridges. This is 261 * almost certainly not correct. 262 */ 263int 264pci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus, 265 int *secondary_bus, int *subordinate_bus) 266{ 267 struct pci_device_private * priv = (struct pci_device_private *) dev; 268 269 /* If the device isn't a bridge, return an error. 270 */ 271 272 if (((dev->device_class >> 16) & 0x0ff) != 0x06) { 273 return ENODEV; 274 } 275 276 if (!priv->bridge.pci) { 277 return ENODEV; 278 } 279 280 switch ((dev->device_class >> 8) & 0x0ff) { 281 case 0x00: 282 /* What to do for host bridges? I'm pretty sure this isn't right. 283 */ 284 *primary_bus = dev->bus; 285 *secondary_bus = -1; 286 *subordinate_bus = -1; 287 break; 288 289 case 0x01: 290 case 0x02: 291 case 0x03: 292 *primary_bus = dev->bus; 293 *secondary_bus = -1; 294 *subordinate_bus = -1; 295 break; 296 297 case 0x04: 298 if (priv->bridge.pci == NULL) 299 read_bridge_info(priv); 300 if (priv->header_type == 0x01) { 301 *primary_bus = priv->bridge.pci->primary_bus; 302 *secondary_bus = priv->bridge.pci->secondary_bus; 303 *subordinate_bus = priv->bridge.pci->subordinate_bus; 304 } else { 305 *primary_bus = dev->bus; 306 *secondary_bus = -1; 307 *subordinate_bus = -1; 308 } 309 break; 310 311 case 0x07: 312 if (priv->bridge.pcmcia == NULL) 313 read_bridge_info(priv); 314 if (priv->header_type == 0x02) { 315 *primary_bus = priv->bridge.pcmcia->primary_bus; 316 *secondary_bus = priv->bridge.pcmcia->card_bus; 317 *subordinate_bus = priv->bridge.pcmcia->subordinate_bus; 318 } else { 319 *primary_bus = dev->bus; 320 *secondary_bus = -1; 321 *subordinate_bus = -1; 322 } 323 break; 324 } 325 326 return 0; 327} 328 329#define PCI_CLASS_BRIDGE 0x06 330#define PCI_SUBCLASS_BRIDGE_PCI 0x04 331 332struct pci_device * 333pci_device_get_parent_bridge(struct pci_device *dev) 334{ 335 struct pci_id_match bridge_match = { 336 PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 337 (PCI_CLASS_BRIDGE << 16) | (PCI_SUBCLASS_BRIDGE_PCI << 8), 338 0 339 }; 340 341 struct pci_device *bridge; 342 struct pci_device_iterator *iter; 343 344 if (dev == NULL) 345 return NULL; 346 347 iter = pci_id_match_iterator_create(& bridge_match); 348 if (iter == NULL) 349 return NULL; 350 351 while ((bridge = pci_device_next(iter)) != NULL) { 352 if (bridge->domain == dev->domain) { 353 const struct pci_bridge_info *info = 354 pci_device_get_bridge_info(bridge); 355 356 if (info != NULL) { 357 if (info->secondary_bus == dev->bus) { 358 break; 359 } 360 } 361 } 362 } 363 364 pci_iterator_destroy(iter); 365 366 return bridge; 367} 368