common_bridge.c revision 9266c31d
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#ifdef 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 switch ((dev->device_class >> 8) & 0x0ff) { 277 case 0x00: 278 /* What to do for host bridges? I'm pretty sure this isn't right. 279 */ 280 *primary_bus = dev->bus; 281 *secondary_bus = -1; 282 *subordinate_bus = -1; 283 break; 284 285 case 0x01: 286 case 0x02: 287 case 0x03: 288 *primary_bus = dev->bus; 289 *secondary_bus = -1; 290 *subordinate_bus = -1; 291 break; 292 293 case 0x04: 294 if (priv->bridge.pci == NULL) 295 read_bridge_info(priv); 296 if ((priv->header_type & 0x7f) == 0x01) { 297 *primary_bus = priv->bridge.pci->primary_bus; 298 *secondary_bus = priv->bridge.pci->secondary_bus; 299 *subordinate_bus = priv->bridge.pci->subordinate_bus; 300 } else { 301 *primary_bus = dev->bus; 302 *secondary_bus = -1; 303 *subordinate_bus = -1; 304 } 305 break; 306 307 case 0x07: 308 if (priv->bridge.pcmcia == NULL) 309 read_bridge_info(priv); 310 if ((priv->header_type & 0x7f) == 0x02) { 311 *primary_bus = priv->bridge.pcmcia->primary_bus; 312 *secondary_bus = priv->bridge.pcmcia->card_bus; 313 *subordinate_bus = priv->bridge.pcmcia->subordinate_bus; 314 } else { 315 *primary_bus = dev->bus; 316 *secondary_bus = -1; 317 *subordinate_bus = -1; 318 } 319 break; 320 } 321 322 return 0; 323} 324 325#define PCI_CLASS_BRIDGE 0x06 326#define PCI_SUBCLASS_BRIDGE_PCI 0x04 327#define PCI_CLASS_MASK 0xFF 328#define PCI_SUBCLASS_MASK 0xFF 329 330struct pci_device * 331pci_device_get_parent_bridge(struct pci_device *dev) 332{ 333 struct pci_id_match bridge_match = { 334 PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 335 (PCI_CLASS_BRIDGE << 16) | (PCI_SUBCLASS_BRIDGE_PCI << 8), 336 (PCI_CLASS_MASK << 16) | (PCI_SUBCLASS_MASK << 8) 337 }; 338 339 struct pci_device *bridge; 340 struct pci_device_iterator *iter; 341 342 if (dev == NULL) 343 return NULL; 344 345 iter = pci_id_match_iterator_create(& bridge_match); 346 if (iter == NULL) 347 return NULL; 348 349 while ((bridge = pci_device_next(iter)) != NULL) { 350 if (bridge->domain == dev->domain) { 351 const struct pci_bridge_info *info = 352 pci_device_get_bridge_info(bridge); 353 354 if (info != NULL) { 355 if (info->secondary_bus == dev->bus) { 356 break; 357 } 358 } 359 } 360 } 361 362 pci_iterator_destroy(iter); 363 364 return bridge; 365} 366