1 /* 2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2003, Marcus Overhagen. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <KernelExport.h> 10 #include <PCI.h> 11 12 #include "util/kernel_cpp.h" 13 #include "pci_priv.h" 14 #include "pci.h" 15 16 17 bool gIrqRouterAvailable = false; 18 spinlock gConfigLock = 0; 19 20 static PCI *sPCI; 21 22 23 status_t 24 pci_init(void) 25 { 26 if (pci_io_init() != B_OK) { 27 TRACE(("PCI: pci_io_init failed\n")); 28 return B_ERROR; 29 } 30 31 if (pci_config_init() != B_OK) { 32 TRACE(("PCI: pci_config_init failed\n")); 33 return B_ERROR; 34 } 35 36 if (pci_irq_init() != B_OK) 37 TRACE(("PCI: IRQ router not available\n")); 38 else 39 gIrqRouterAvailable = true; 40 41 sPCI = new PCI; 42 43 return B_OK; 44 } 45 46 47 void 48 pci_uninit(void) 49 { 50 delete sPCI; 51 } 52 53 54 long 55 pci_get_nth_pci_info(long index, pci_info *outInfo) 56 { 57 return sPCI->GetNthPciInfo(index, outInfo); 58 } 59 60 61 PCI::PCI() 62 { 63 fRootBus.parent = 0; 64 fRootBus.bus = 0; 65 fRootBus.child = 0; 66 67 DiscoverBus(&fRootBus); 68 69 RefreshDeviceInfo(&fRootBus); 70 } 71 72 73 PCI::~PCI() 74 { 75 } 76 77 78 status_t 79 PCI::GetNthPciInfo(long index, pci_info *outInfo) 80 { 81 long curindex = 0; 82 return GetNthPciInfo(&fRootBus, &curindex, index, outInfo); 83 } 84 85 86 status_t 87 PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo) 88 { 89 // maps tree structure to linear indexed view 90 PCIDev *dev = bus->child; 91 while (dev) { 92 if (*curindex == wantindex) { 93 *outInfo = dev->info; 94 return B_OK; 95 } 96 *curindex += 1; 97 if (dev->child && B_OK == GetNthPciInfo(dev->child, curindex, wantindex, outInfo)) 98 return B_OK; 99 dev = dev->next; 100 } 101 return B_ERROR; 102 } 103 104 105 void 106 PCI::DiscoverBus(PCIBus *bus) 107 { 108 TRACE(("PCI: DiscoverBus, bus %u\n", bus->bus)); 109 110 for (int dev = 0; dev < gMaxBusDevices; dev++) { 111 uint16 vendor_id = pci_read_config(bus->bus, dev, 0, PCI_vendor_id, 2); 112 if (vendor_id == 0xffff) 113 continue; 114 115 uint8 type = pci_read_config(bus->bus, dev, 0, PCI_header_type, 1); 116 int nfunc = (type & PCI_multifunction) ? 8 : 1; 117 for (int func = 0; func < nfunc; func++) 118 DiscoverDevice(bus, dev, func); 119 } 120 } 121 122 123 void 124 PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func) 125 { 126 TRACE(("PCI: DiscoverDevice, bus %u, dev %u, func %u\n", bus->bus, dev, func)); 127 128 uint16 device_id = pci_read_config(bus->bus, dev, func, PCI_device_id, 2); 129 if (device_id == 0xffff) 130 return; 131 132 PCIDev *newdev = CreateDevice(bus, dev, func); 133 134 uint8 base_class = pci_read_config(bus->bus, dev, func, PCI_class_base, 1); 135 uint8 sub_class = pci_read_config(bus->bus, dev, func, PCI_class_sub, 1); 136 if (base_class == PCI_bridge && sub_class == PCI_pci) { 137 uint8 secondary_bus = pci_read_config(bus->bus, dev, func, PCI_secondary_bus, 1); 138 PCIBus *newbus = CreateBus(newdev, secondary_bus); 139 DiscoverBus(newbus); 140 } 141 } 142 143 144 PCIBus * 145 PCI::CreateBus(PCIDev *parent, uint8 bus) 146 { 147 PCIBus *newbus = new PCIBus; 148 newbus->parent = parent; 149 newbus->bus = bus; 150 newbus->child = 0; 151 152 // append 153 parent->child = newbus; 154 155 return newbus; 156 } 157 158 159 PCIDev * 160 PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func) 161 { 162 TRACE(("PCI: CreateDevice, bus %u, dev %u, func %u:\n", parent->bus, dev, func)); 163 164 PCIDev *newdev = new PCIDev; 165 newdev->next = 0; 166 newdev->parent = parent; 167 newdev->child = 0; 168 newdev->bus = parent->bus; 169 newdev->dev = dev; 170 newdev->func = func; 171 172 ReadPciBasicInfo(newdev); 173 174 TRACE(("PCI: vendor 0x%04x, device 0x%04x, class_base 0x%02x, class_sub 0x%02x\n", 175 newdev->info.vendor_id, newdev->info.device_id, newdev->info.class_base, newdev->info.class_sub)); 176 177 // append 178 if (parent->child == 0) { 179 parent->child = newdev; 180 } else { 181 PCIDev *sub = parent->child; 182 while (sub->next) 183 sub = sub->next; 184 sub->next = newdev; 185 } 186 187 return newdev; 188 } 189 190 191 uint32 192 PCI::BarSize(uint32 bits, uint32 mask) 193 { 194 bits &= mask; 195 if (!bits) 196 return 0; 197 uint32 size = 1; 198 while (!(bits & size)) 199 size <<= 1; 200 return size; 201 } 202 203 204 void 205 PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags) 206 { 207 uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); 208 pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff); 209 uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); 210 pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue); 211 212 *address = oldvalue & PCI_address_memory_32_mask; 213 if (size) 214 *size = BarSize(newvalue, PCI_address_memory_32_mask); 215 if (flags) 216 *flags = newvalue & 0xf; 217 } 218 219 220 void 221 PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags) 222 { 223 uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); 224 pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0 225 uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); 226 pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue); 227 228 *address = oldvalue & PCI_rom_address_mask; 229 if (size) 230 *size = BarSize(newvalue, PCI_rom_address_mask); 231 if (flags) 232 *flags = newvalue & 0xf; 233 } 234 235 236 void 237 PCI::ReadPciBasicInfo(PCIDev *dev) 238 { 239 dev->info.vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_vendor_id, 2); 240 dev->info.device_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_device_id, 2); 241 dev->info.bus = dev->bus; 242 dev->info.device = dev->dev; 243 dev->info.function = dev->func; 244 dev->info.revision = pci_read_config(dev->bus, dev->dev, dev->func, PCI_revision, 1); 245 dev->info.class_api = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_api, 1); 246 dev->info.class_sub = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_sub, 1); 247 dev->info.class_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_base, 1); 248 dev->info.line_size = pci_read_config(dev->bus, dev->dev, dev->func, PCI_line_size, 1); 249 dev->info.latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_latency, 1); 250 // BeOS does not mask off the multifunction bit, developer must use (header_type & PCI_header_type_mask) 251 dev->info.header_type = pci_read_config(dev->bus, dev->dev, dev->func, PCI_header_type, 1); 252 dev->info.bist = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bist, 1); 253 dev->info.reserved = 0; 254 } 255 256 257 void 258 PCI::ReadPciHeaderInfo(PCIDev *dev) 259 { 260 switch (dev->info.header_type & PCI_header_type_mask) { 261 case 0: 262 { 263 // disable PCI device address decoding (io and memory) while BARs are modified 264 uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2); 265 pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory)); 266 267 // get BAR size infos 268 GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, &dev->info.u.h0.rom_size); 269 for (int i = 0; i < 6; i++) { 270 GetBarInfo(dev, PCI_base_registers + 4*i, 271 &dev->info.u.h0.base_registers_pci[i], 272 &dev->info.u.h0.base_register_sizes[i], 273 &dev->info.u.h0.base_register_flags[i]); 274 } 275 276 // restore PCI device address decoding 277 pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd); 278 279 dev->info.u.h0.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h0.rom_base_pci); 280 for (int i = 0; i < 6; i++) { 281 dev->info.u.h0.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h0.base_registers_pci[i]); 282 } 283 284 dev->info.u.h0.cardbus_cis = pci_read_config(dev->bus, dev->dev, dev->func, PCI_cardbus_cis, 4); 285 dev->info.u.h0.subsystem_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_id, 2); 286 dev->info.u.h0.subsystem_vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_vendor_id, 2); 287 dev->info.u.h0.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1); 288 dev->info.u.h0.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1); 289 dev->info.u.h0.min_grant = pci_read_config(dev->bus, dev->dev, dev->func, PCI_min_grant, 1); 290 dev->info.u.h0.max_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_max_latency, 1); 291 break; 292 } 293 294 case 1: 295 { 296 // disable PCI device address decoding (io and memory) while BARs are modified 297 uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2); 298 pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory)); 299 300 GetRomBarInfo(dev, PCI_bridge_rom_base, &dev->info.u.h1.rom_base_pci); 301 for (int i = 0; i < 2; i++) { 302 GetBarInfo(dev, PCI_base_registers + 4*i, 303 &dev->info.u.h1.base_registers_pci[i], 304 &dev->info.u.h1.base_register_sizes[i], 305 &dev->info.u.h1.base_register_flags[i]); 306 } 307 308 // restore PCI device address decoding 309 pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd); 310 311 dev->info.u.h1.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h1.rom_base_pci); 312 for (int i = 0; i < 2; i++) { 313 dev->info.u.h1.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h1.base_registers_pci[i]); 314 } 315 316 dev->info.u.h1.primary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_primary_bus, 1); 317 dev->info.u.h1.secondary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_bus, 1); 318 dev->info.u.h1.subordinate_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 1); 319 dev->info.u.h1.secondary_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_latency, 1); 320 dev->info.u.h1.io_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base, 1); 321 dev->info.u.h1.io_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit, 1); 322 dev->info.u.h1.secondary_status = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_status, 2); 323 dev->info.u.h1.memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_base, 2); 324 dev->info.u.h1.memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_limit, 2); 325 dev->info.u.h1.prefetchable_memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base, 2); 326 dev->info.u.h1.prefetchable_memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2); 327 dev->info.u.h1.prefetchable_memory_base_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base_upper32, 4); 328 dev->info.u.h1.prefetchable_memory_limit_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4); 329 dev->info.u.h1.io_base_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base_upper16, 2); 330 dev->info.u.h1.io_limit_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2); 331 dev->info.u.h1.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1); 332 dev->info.u.h1.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1); 333 dev->info.u.h1.bridge_control = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bridge_control, 2); 334 break; 335 } 336 337 default: 338 TRACE(("PCI: Header type unknown (%d)\n", dev->info.header_type)); 339 break; 340 } 341 } 342 343 344 void 345 PCI::RefreshDeviceInfo(PCIBus *bus) 346 { 347 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 348 ReadPciBasicInfo(dev); 349 ReadPciHeaderInfo(dev); 350 if (dev->child) 351 RefreshDeviceInfo(dev->child); 352 } 353 } 354