common_bridge.c revision 4f5e7dd7
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#include "config.h" 33#include <stdio.h> 34#include <stdlib.h> 35#include <ctype.h> 36#include <errno.h> 37 38#if defined(HAVE_STRING_H) 39# include <string.h> 40#elif defined(HAVE_STRINGS_H) 41# include <strings.h> 42#endif 43 44#if defined(HAVE_INTTYPES_H) 45# include <inttypes.h> 46#elif defined(HAVE_STDINT_H) 47# include <stdint.h> 48#endif 49 50#include "pciaccess.h" 51#include "pciaccess_private.h" 52 53static int 54read_bridge_info( struct pci_device_private * priv ) 55{ 56 uint8_t buf[0x40]; 57 pciaddr_t bytes; 58 int err; 59 60 61 /* Make sure the device has been probed. If not, header_type won't be 62 * set and the rest of this function will fail. 63 */ 64 err = pci_device_probe(& priv->base); 65 if (err) { 66 return err; 67 } 68 69 switch ( priv->header_type & 0x7f ) { 70 case 0x00: 71 break; 72 73 case 0x01: { 74 struct pci_bridge_info *info; 75 76 info = malloc(sizeof(*info)); 77 if (info != NULL) { 78 pci_device_cfg_read( (struct pci_device *) priv, buf + 0x18, 0x18, 79 0x40 - 0x18, & bytes ); 80 81 info->primary_bus = buf[0x18]; 82 info->secondary_bus = buf[0x19]; 83 info->subordinate_bus = buf[0x1a]; 84 info->secondary_latency_timer = buf[0x1b]; 85 86 info->io_type = buf[0x1c] & 0x0f; 87 info->io_base = (((uint32_t) (buf[0x1c] & 0x0f0)) << 8) 88 + (((uint32_t) buf[0x30]) << 16) 89 + (((uint32_t) buf[0x31]) << 24); 90 91 info->io_limit = 0x00000fff 92 + (((uint32_t) (buf[0x1d] & 0x0f0)) << 8) 93 + (((uint32_t) buf[0x32]) << 16) 94 + (((uint32_t) buf[0x33]) << 24); 95 96 info->mem_type = buf[0x20] & 0x0f; 97 info->mem_base = (((uint32_t) (buf[0x20] & 0x0f0)) << 16) 98 + (((uint32_t) buf[0x21]) << 24); 99 100 info->mem_limit = 0x0000ffff 101 + (((uint32_t) (buf[0x22] & 0x0f0)) << 16) 102 + (((uint32_t) buf[0x23]) << 24); 103 104 info->prefetch_mem_type = buf[0x24] & 0x0f; 105 info->prefetch_mem_base = (((uint64_t) (buf[0x24] & 0x0f0)) << 16) 106 + (((uint64_t) buf[0x25]) << 24) 107 + (((uint64_t) buf[0x28]) << 32) 108 + (((uint64_t) buf[0x29]) << 40) 109 + (((uint64_t) buf[0x2a]) << 48) 110 + (((uint64_t) buf[0x2b]) << 56); 111 112 info->prefetch_mem_limit = 0x0000ffff 113 + (((uint64_t) (buf[0x26] & 0x0f0)) << 16) 114 + (((uint64_t) buf[0x27]) << 24) 115 + (((uint64_t) buf[0x2c]) << 32) 116 + (((uint64_t) buf[0x2d]) << 40) 117 + (((uint64_t) buf[0x2e]) << 48) 118 + (((uint64_t) buf[0x2f]) << 56); 119 120 info->bridge_control = ((uint16_t) buf[0x3e]) 121 + (((uint16_t) buf[0x3f]) << 8); 122 123 info->secondary_status = ((uint16_t) buf[0x1e]) 124 + (((uint16_t) buf[0x1f]) << 8); 125 } 126 127 priv->bridge.pci = info; 128 break; 129 } 130 131 case 0x02: { 132 struct pci_pcmcia_bridge_info *info; 133 134 info = malloc(sizeof(*info)); 135 if (info != NULL) { 136 pci_device_cfg_read( (struct pci_device *) priv, buf + 0x16, 0x16, 137 0x40 - 0x16, & bytes ); 138 139 info->primary_bus = buf[0x18]; 140 info->card_bus = buf[0x19]; 141 info->subordinate_bus = buf[0x1a]; 142 info->cardbus_latency_timer = buf[0x1b]; 143 144 info->mem[0].base = (((uint32_t) buf[0x1c])) 145 + (((uint32_t) buf[0x1d]) << 8) 146 + (((uint32_t) buf[0x1e]) << 16) 147 + (((uint32_t) buf[0x1f]) << 24); 148 149 info->mem[0].limit = (((uint32_t) buf[0x20])) 150 + (((uint32_t) buf[0x21]) << 8) 151 + (((uint32_t) buf[0x22]) << 16) 152 + (((uint32_t) buf[0x23]) << 24); 153 154 info->mem[1].base = (((uint32_t) buf[0x24])) 155 + (((uint32_t) buf[0x25]) << 8) 156 + (((uint32_t) buf[0x26]) << 16) 157 + (((uint32_t) buf[0x27]) << 24); 158 159 info->mem[1].limit = (((uint32_t) buf[0x28])) 160 + (((uint32_t) buf[0x29]) << 8) 161 + (((uint32_t) buf[0x2a]) << 16) 162 + (((uint32_t) buf[0x2b]) << 24); 163 164 info->io[0].base = (((uint32_t) buf[0x2c])) 165 + (((uint32_t) buf[0x2d]) << 8) 166 + (((uint32_t) buf[0x2e]) << 16) 167 + (((uint32_t) buf[0x2f]) << 24); 168 169 info->io[0].limit = (((uint32_t) buf[0x30])) 170 + (((uint32_t) buf[0x31]) << 8) 171 + (((uint32_t) buf[0x32]) << 16) 172 + (((uint32_t) buf[0x33]) << 24); 173 174 info->io[1].base = (((uint32_t) buf[0x34])) 175 + (((uint32_t) buf[0x35]) << 8) 176 + (((uint32_t) buf[0x36]) << 16) 177 + (((uint32_t) buf[0x37]) << 24); 178 179 info->io[1].limit = (((uint32_t) buf[0x38])) 180 + (((uint32_t) buf[0x39]) << 8) 181 + (((uint32_t) buf[0x3a]) << 16) 182 + (((uint32_t) buf[0x3b]) << 24); 183 184 info->secondary_status = ((uint16_t) buf[0x16]) 185 + (((uint16_t) buf[0x17]) << 8); 186 187 info->bridge_control = ((uint16_t) buf[0x3e]) 188 + (((uint16_t) buf[0x3f]) << 8); 189 } 190 191 priv->bridge.pcmcia = info; 192 break; 193 } 194 } 195 196 return 0; 197} 198 199 200/** 201 * Get the PCI bridge information for a device 202 * 203 * \returns 204 * If \c dev is a PCI-to-PCI bridge, a pointer to a \c pci_bridge_info 205 * structure. Otherwise, \c NULL is returned. 206 */ 207const struct pci_bridge_info * 208pci_device_get_bridge_info( struct pci_device * dev ) 209{ 210 struct pci_device_private * priv = (struct pci_device_private *) dev; 211 212 if (priv->bridge.pci == NULL) { 213 read_bridge_info(priv); 214 } 215 216 return (priv->header_type == 1) ? priv->bridge.pci : NULL; 217} 218 219 220/** 221 * Get the PCMCIA bridge information for a device 222 * 223 * \returns 224 * If \c dev is a PCI-to-PCMCIA bridge, a pointer to a 225 * \c pci_pcmcia_bridge_info structure. Otherwise, \c NULL is returned. 226 */ 227const struct pci_pcmcia_bridge_info * 228pci_device_get_pcmcia_bridge_info( struct pci_device * dev ) 229{ 230 struct pci_device_private * priv = (struct pci_device_private *) dev; 231 232 if (priv->bridge.pcmcia == NULL) { 233 read_bridge_info(priv); 234 } 235 236 return (priv->header_type == 2) ? priv->bridge.pcmcia : NULL; 237} 238 239 240/** 241 * Determine the primary, secondary, and subordinate buses for a bridge 242 * 243 * Determines the IDs of the primary, secondary, and subordinate buses for 244 * a specified bridge. Not all bridges directly store this information 245 * (e.g., PCI-to-ISA bridges). For those bridges, no error is returned, but 246 * -1 is stored in the bus IDs that don't make sense. 247 * 248 * For example, for a PCI-to-ISA bridge, \c primary_bus will be set to the ID 249 * of the bus containing the device and both \c secondary_bus and 250 * \c subordinate_bus will be set to -1. 251 * 252 * \return 253 * On success, zero is returned. If \c dev is not a bridge, \c ENODEV is 254 * returned. 255 * 256 * \bug 257 * Host bridges are handled the same way as PCI-to-ISA bridges. This is 258 * almost certainly not correct. 259 */ 260int 261pci_device_get_bridge_buses(struct pci_device * dev, int *primary_bus, 262 int *secondary_bus, int *subordinate_bus) 263{ 264 struct pci_device_private * priv = (struct pci_device_private *) dev; 265 266 /* If the device isn't a bridge, return an error. 267 */ 268 269 if (((dev->device_class >> 16) & 0x0ff) != 0x06) { 270 return ENODEV; 271 } 272 273 switch ((dev->device_class >> 8) & 0x0ff) { 274 case 0x00: 275 /* What to do for host bridges? I'm pretty sure this isn't right. 276 */ 277 *primary_bus = dev->bus; 278 *secondary_bus = -1; 279 *subordinate_bus = -1; 280 break; 281 282 case 0x01: 283 case 0x02: 284 case 0x03: 285 *primary_bus = dev->bus; 286 *secondary_bus = -1; 287 *subordinate_bus = -1; 288 break; 289 290 case 0x04: 291 if (priv->bridge.pci == NULL) 292 read_bridge_info(priv); 293 if (priv->header_type == 0x01) { 294 *primary_bus = priv->bridge.pci->primary_bus; 295 *secondary_bus = priv->bridge.pci->secondary_bus; 296 *subordinate_bus = priv->bridge.pci->subordinate_bus; 297 } else { 298 *primary_bus = dev->bus; 299 *secondary_bus = -1; 300 *subordinate_bus = -1; 301 } 302 break; 303 304 case 0x07: 305 if (priv->bridge.pcmcia == NULL) 306 read_bridge_info(priv); 307 if (priv->header_type == 0x02) { 308 *primary_bus = priv->bridge.pcmcia->primary_bus; 309 *secondary_bus = priv->bridge.pcmcia->card_bus; 310 *subordinate_bus = priv->bridge.pcmcia->subordinate_bus; 311 } else { 312 *primary_bus = dev->bus; 313 *secondary_bus = -1; 314 *subordinate_bus = -1; 315 } 316 break; 317 } 318 319 return 0; 320} 321