Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 1 | // Initialize PCI devices (on emulators) |
| 2 | // |
| 3 | // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> |
| 4 | // Copyright (C) 2006 Fabrice Bellard |
| 5 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 7 | |
| 8 | #include "util.h" // dprintf |
Kevin O'Connor | be19cdc | 2008-11-09 15:33:47 -0500 | [diff] [blame] | 9 | #include "pci.h" // pci_config_readl |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 10 | #include "biosvar.h" // GET_EBDA |
Kevin O'Connor | 2ed2f58 | 2008-11-08 15:53:36 -0500 | [diff] [blame] | 11 | #include "pci_ids.h" // PCI_VENDOR_ID_INTEL |
| 12 | #include "pci_regs.h" // PCI_COMMAND |
Ian Campbell | 74c7878 | 2011-06-01 11:00:29 +0100 | [diff] [blame] | 13 | #include "xen.h" // usingXen |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 14 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 15 | #define PCI_IO_INDEX_SHIFT 2 |
| 16 | #define PCI_MEM_INDEX_SHIFT 12 |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 17 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 18 | #define PCI_BRIDGE_IO_MIN 0x1000 |
| 19 | #define PCI_BRIDGE_MEM_MIN 0x100000 |
Isaku Yamahata | af0963d | 2010-06-22 17:57:53 +0900 | [diff] [blame] | 20 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 21 | enum pci_region_type { |
| 22 | PCI_REGION_TYPE_IO, |
| 23 | PCI_REGION_TYPE_MEM, |
| 24 | PCI_REGION_TYPE_PREFMEM, |
| 25 | PCI_REGION_TYPE_COUNT, |
| 26 | }; |
| 27 | |
| 28 | static const char *region_type_name[] = { |
| 29 | [ PCI_REGION_TYPE_IO ] = "io", |
| 30 | [ PCI_REGION_TYPE_MEM ] = "mem", |
| 31 | [ PCI_REGION_TYPE_PREFMEM ] = "prefmem", |
| 32 | }; |
| 33 | |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 34 | struct pci_bus { |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 35 | struct { |
| 36 | /* pci region stats */ |
| 37 | u32 count[32 - PCI_MEM_INDEX_SHIFT]; |
| 38 | u32 sum, max; |
| 39 | /* seconday bus region sizes */ |
| 40 | u32 size; |
| 41 | /* pci region assignments */ |
| 42 | u32 bases[32 - PCI_MEM_INDEX_SHIFT]; |
| 43 | u32 base; |
| 44 | } r[PCI_REGION_TYPE_COUNT]; |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 45 | struct pci_device *bus_dev; |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 46 | }; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 47 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 48 | static int pci_size_to_index(u32 size, enum pci_region_type type) |
| 49 | { |
| 50 | int index = __fls(size); |
| 51 | int shift = (type == PCI_REGION_TYPE_IO) ? |
| 52 | PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; |
| 53 | |
| 54 | if (index < shift) |
| 55 | index = shift; |
| 56 | index -= shift; |
| 57 | return index; |
| 58 | } |
| 59 | |
| 60 | static u32 pci_index_to_size(int index, enum pci_region_type type) |
| 61 | { |
| 62 | int shift = (type == PCI_REGION_TYPE_IO) ? |
| 63 | PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; |
| 64 | |
| 65 | return 0x1 << (index + shift); |
| 66 | } |
| 67 | |
| 68 | static enum pci_region_type pci_addr_to_type(u32 addr) |
| 69 | { |
| 70 | if (addr & PCI_BASE_ADDRESS_SPACE_IO) |
| 71 | return PCI_REGION_TYPE_IO; |
| 72 | if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH) |
| 73 | return PCI_REGION_TYPE_PREFMEM; |
| 74 | return PCI_REGION_TYPE_MEM; |
| 75 | } |
| 76 | |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 77 | static u32 pci_bar(struct pci_device *pci, int region_num) |
Isaku Yamahata | a65821d | 2010-06-22 17:57:50 +0900 | [diff] [blame] | 78 | { |
| 79 | if (region_num != PCI_ROM_SLOT) { |
| 80 | return PCI_BASE_ADDRESS_0 + region_num * 4; |
| 81 | } |
Isaku Yamahata | 5d0de15 | 2010-06-22 17:57:51 +0900 | [diff] [blame] | 82 | |
| 83 | #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 84 | u8 type = pci->header_type & ~PCI_HEADER_TYPE_MULTI_FUNCTION; |
Isaku Yamahata | 5d0de15 | 2010-06-22 17:57:51 +0900 | [diff] [blame] | 85 | return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; |
Isaku Yamahata | a65821d | 2010-06-22 17:57:50 +0900 | [diff] [blame] | 86 | } |
| 87 | |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 88 | static void |
| 89 | pci_set_io_region_addr(struct pci_device *pci, int region_num, u32 addr) |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 90 | { |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 91 | pci_config_writel(pci->bdf, pci_bar(pci, region_num), addr); |
Isaku Yamahata | b9e4721 | 2010-06-22 17:57:47 +0900 | [diff] [blame] | 92 | } |
| 93 | |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 94 | |
| 95 | /**************************************************************** |
| 96 | * Misc. device init |
| 97 | ****************************************************************/ |
| 98 | |
| 99 | /* host irqs corresponding to PCI irqs A-D */ |
| 100 | const u8 pci_irqs[4] = { |
| 101 | 10, 10, 11, 11 |
| 102 | }; |
| 103 | |
Kevin O'Connor | 0ce2138 | 2011-10-01 14:52:35 -0400 | [diff] [blame] | 104 | // Return the global irq number corresponding to a host bus device irq pin. |
| 105 | static int pci_slot_get_irq(u16 bdf, int pin) |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 106 | { |
Kevin O'Connor | be19cdc | 2008-11-09 15:33:47 -0500 | [diff] [blame] | 107 | int slot_addend = pci_bdf_to_dev(bdf) - 1; |
Kevin O'Connor | 0ce2138 | 2011-10-01 14:52:35 -0400 | [diff] [blame] | 108 | return pci_irqs[(pin - 1 + slot_addend) & 3]; |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 109 | } |
| 110 | |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 111 | /* PIIX3/PIIX4 PCI to ISA bridge */ |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 112 | static void piix_isa_bridge_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 113 | { |
| 114 | int i, irq; |
| 115 | u8 elcr[2]; |
| 116 | |
| 117 | elcr[0] = 0x00; |
| 118 | elcr[1] = 0x00; |
| 119 | for (i = 0; i < 4; i++) { |
| 120 | irq = pci_irqs[i]; |
| 121 | /* set to trigger level */ |
| 122 | elcr[irq >> 3] |= (1 << (irq & 7)); |
| 123 | /* activate irq remapping in PIIX */ |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 124 | pci_config_writeb(pci->bdf, 0x60 + i, irq); |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 125 | } |
| 126 | outb(elcr[0], 0x4d0); |
| 127 | outb(elcr[1], 0x4d1); |
| 128 | dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]); |
| 129 | } |
| 130 | |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 131 | static const struct pci_device_id pci_isa_bridge_tbl[] = { |
| 132 | /* PIIX3/PIIX4 PCI to ISA bridge */ |
| 133 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, |
| 134 | piix_isa_bridge_init), |
| 135 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, |
| 136 | piix_isa_bridge_init), |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 137 | |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 138 | PCI_DEVICE_END |
| 139 | }; |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 140 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 141 | static void storage_ide_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 142 | { |
| 143 | /* IDE: we map it as in ISA mode */ |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 144 | pci_set_io_region_addr(pci, 0, PORT_ATA1_CMD_BASE); |
| 145 | pci_set_io_region_addr(pci, 1, PORT_ATA1_CTRL_BASE); |
| 146 | pci_set_io_region_addr(pci, 2, PORT_ATA2_CMD_BASE); |
| 147 | pci_set_io_region_addr(pci, 3, PORT_ATA2_CTRL_BASE); |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 148 | } |
| 149 | |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 150 | /* PIIX3/PIIX4 IDE */ |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 151 | static void piix_ide_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 152 | { |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 153 | u16 bdf = pci->bdf; |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 154 | pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0 |
| 155 | pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1 |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 156 | } |
| 157 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 158 | static void pic_ibm_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 159 | { |
| 160 | /* PIC, IBM, MPIC & MPIC2 */ |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 161 | pci_set_io_region_addr(pci, 0, 0x80800000 + 0x00040000); |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 162 | } |
| 163 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 164 | static void apple_macio_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 165 | { |
| 166 | /* macio bridge */ |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 167 | pci_set_io_region_addr(pci, 0, 0x80800000); |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | static const struct pci_device_id pci_class_tbl[] = { |
| 171 | /* STORAGE IDE */ |
| 172 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, |
| 173 | PCI_CLASS_STORAGE_IDE, piix_ide_init), |
| 174 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, |
| 175 | PCI_CLASS_STORAGE_IDE, piix_ide_init), |
| 176 | PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, |
| 177 | storage_ide_init), |
| 178 | |
| 179 | /* PIC, IBM, MIPC & MPIC2 */ |
| 180 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC, |
| 181 | pic_ibm_init), |
| 182 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC, |
| 183 | pic_ibm_init), |
| 184 | |
| 185 | /* 0xff00 */ |
| 186 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init), |
| 187 | PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init), |
| 188 | |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 189 | PCI_DEVICE_END, |
| 190 | }; |
| 191 | |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 192 | /* PIIX4 Power Management device (for ACPI) */ |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 193 | static void piix4_pm_init(struct pci_device *pci, void *arg) |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 194 | { |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 195 | u16 bdf = pci->bdf; |
Kevin O'Connor | 6e4583c | 2011-06-19 10:09:26 -0400 | [diff] [blame] | 196 | // acpi sci is hardwired to 9 |
| 197 | pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9); |
| 198 | |
| 199 | pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1); |
| 200 | pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */ |
| 201 | pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1); |
| 202 | pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */ |
| 203 | } |
| 204 | |
Kevin O'Connor | 0d6b8d5 | 2010-07-10 13:12:37 -0400 | [diff] [blame] | 205 | static const struct pci_device_id pci_device_tbl[] = { |
| 206 | /* PIIX4 Power Management device (for ACPI) */ |
| 207 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, |
| 208 | piix4_pm_init), |
| 209 | |
| 210 | PCI_DEVICE_END, |
| 211 | }; |
| 212 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 213 | static void pci_bios_init_device(struct pci_device *pci) |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 214 | { |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 215 | u16 bdf = pci->bdf; |
Kevin O'Connor | 99e37c4 | 2011-10-01 10:47:21 -0400 | [diff] [blame] | 216 | dprintf(1, "PCI: init bdf=%02x:%02x.%x id=%04x:%04x\n" |
| 217 | , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf) |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 218 | , pci->vendor, pci->device); |
Kevin O'Connor | 0ce2138 | 2011-10-01 14:52:35 -0400 | [diff] [blame] | 219 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 220 | pci_init_device(pci_class_tbl, pci, NULL); |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 221 | |
Kevin O'Connor | b82a1e4 | 2009-10-12 10:34:51 -0400 | [diff] [blame] | 222 | /* enable memory mappings */ |
| 223 | pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); |
| 224 | |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 225 | /* map the interrupt */ |
Kevin O'Connor | 0ce2138 | 2011-10-01 14:52:35 -0400 | [diff] [blame] | 226 | int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN); |
| 227 | if (pin != 0) |
| 228 | pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pci_slot_get_irq(bdf, pin)); |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 229 | |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 230 | pci_init_device(pci_device_tbl, pci, NULL); |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 231 | } |
| 232 | |
Kevin O'Connor | 3f2288f | 2011-10-15 12:02:14 -0400 | [diff] [blame^] | 233 | static void pci_bios_init_devices(void) |
Isaku Yamahata | af0963d | 2010-06-22 17:57:53 +0900 | [diff] [blame] | 234 | { |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 235 | struct pci_device *pci; |
| 236 | foreachpci(pci) { |
Kevin O'Connor | 3f2288f | 2011-10-15 12:02:14 -0400 | [diff] [blame^] | 237 | if (pci_bdf_to_bus(pci->bdf) != 0) |
| 238 | // Only init devices on host bus. |
Kevin O'Connor | 278b19f | 2011-06-21 22:41:15 -0400 | [diff] [blame] | 239 | break; |
| 240 | pci_bios_init_device(pci); |
Isaku Yamahata | af0963d | 2010-06-22 17:57:53 +0900 | [diff] [blame] | 241 | } |
Kevin O'Connor | 3f2288f | 2011-10-15 12:02:14 -0400 | [diff] [blame^] | 242 | |
| 243 | foreachpci(pci) { |
| 244 | pci_init_device(pci_isa_bridge_tbl, pci, NULL); |
| 245 | } |
Isaku Yamahata | af0963d | 2010-06-22 17:57:53 +0900 | [diff] [blame] | 246 | } |
| 247 | |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 248 | |
| 249 | /**************************************************************** |
| 250 | * Bus initialization |
| 251 | ****************************************************************/ |
| 252 | |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 253 | static void |
| 254 | pci_bios_init_bus_rec(int bus, u8 *pci_bus) |
| 255 | { |
Kevin O'Connor | 2b333e4 | 2011-07-02 14:49:41 -0400 | [diff] [blame] | 256 | int bdf; |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 257 | u16 class; |
| 258 | |
| 259 | dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus); |
| 260 | |
| 261 | /* prevent accidental access to unintended devices */ |
Kevin O'Connor | 2b333e4 | 2011-07-02 14:49:41 -0400 | [diff] [blame] | 262 | foreachbdf(bdf, bus) { |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 263 | class = pci_config_readw(bdf, PCI_CLASS_DEVICE); |
| 264 | if (class == PCI_CLASS_BRIDGE_PCI) { |
| 265 | pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255); |
| 266 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0); |
| 267 | } |
| 268 | } |
| 269 | |
Kevin O'Connor | 2b333e4 | 2011-07-02 14:49:41 -0400 | [diff] [blame] | 270 | foreachbdf(bdf, bus) { |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 271 | class = pci_config_readw(bdf, PCI_CLASS_DEVICE); |
| 272 | if (class != PCI_CLASS_BRIDGE_PCI) { |
| 273 | continue; |
| 274 | } |
| 275 | dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf); |
| 276 | |
| 277 | u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS); |
| 278 | if (pribus != bus) { |
| 279 | dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus); |
| 280 | pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus); |
| 281 | } else { |
| 282 | dprintf(1, "PCI: primary bus = 0x%x\n", pribus); |
| 283 | } |
| 284 | |
| 285 | u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); |
| 286 | (*pci_bus)++; |
| 287 | if (*pci_bus != secbus) { |
| 288 | dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n", |
| 289 | secbus, *pci_bus); |
| 290 | secbus = *pci_bus; |
| 291 | pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus); |
| 292 | } else { |
| 293 | dprintf(1, "PCI: secondary bus = 0x%x\n", secbus); |
| 294 | } |
| 295 | |
| 296 | /* set to max for access to all subordinate buses. |
| 297 | later set it to accurate value */ |
| 298 | u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS); |
| 299 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255); |
| 300 | |
| 301 | pci_bios_init_bus_rec(secbus, pci_bus); |
| 302 | |
| 303 | if (subbus != *pci_bus) { |
| 304 | dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", |
| 305 | subbus, *pci_bus); |
| 306 | subbus = *pci_bus; |
| 307 | } else { |
| 308 | dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); |
| 309 | } |
| 310 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | static void |
| 315 | pci_bios_init_bus(void) |
| 316 | { |
| 317 | u8 pci_bus = 0; |
| 318 | pci_bios_init_bus_rec(0 /* host bus */, &pci_bus); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 319 | } |
| 320 | |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 321 | |
| 322 | /**************************************************************** |
| 323 | * Bus sizing |
| 324 | ****************************************************************/ |
| 325 | |
| 326 | static u32 pci_size_roundup(u32 size) |
| 327 | { |
| 328 | int index = __fls(size-1)+1; |
| 329 | return 0x1 << index; |
| 330 | } |
| 331 | |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 332 | static void |
| 333 | pci_bios_get_bar(struct pci_device *pci, int bar, u32 *val, u32 *size) |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 334 | { |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 335 | u32 ofs = pci_bar(pci, bar); |
| 336 | u16 bdf = pci->bdf; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 337 | u32 old = pci_config_readl(bdf, ofs); |
| 338 | u32 mask; |
| 339 | |
| 340 | if (bar == PCI_ROM_SLOT) { |
| 341 | mask = PCI_ROM_ADDRESS_MASK; |
| 342 | pci_config_writel(bdf, ofs, mask); |
| 343 | } else { |
| 344 | if (old & PCI_BASE_ADDRESS_SPACE_IO) |
| 345 | mask = PCI_BASE_ADDRESS_IO_MASK; |
| 346 | else |
| 347 | mask = PCI_BASE_ADDRESS_MEM_MASK; |
| 348 | pci_config_writel(bdf, ofs, ~0); |
| 349 | } |
| 350 | *val = pci_config_readl(bdf, ofs); |
| 351 | pci_config_writel(bdf, ofs, old); |
| 352 | *size = (~(*val & mask)) + 1; |
| 353 | } |
| 354 | |
| 355 | static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size) |
| 356 | { |
| 357 | u32 index; |
| 358 | |
| 359 | index = pci_size_to_index(size, type); |
| 360 | size = pci_index_to_size(index, type); |
| 361 | bus->r[type].count[index]++; |
| 362 | bus->r[type].sum += size; |
| 363 | if (bus->r[type].max < size) |
| 364 | bus->r[type].max = size; |
| 365 | } |
| 366 | |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 367 | static void pci_bios_check_devices(struct pci_bus *busses) |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 368 | { |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 369 | dprintf(1, "PCI: check devices\n"); |
| 370 | |
| 371 | // Calculate resources needed for regular (non-bus) devices. |
| 372 | struct pci_device *pci; |
| 373 | foreachpci(pci) { |
| 374 | if (pci->class == PCI_CLASS_BRIDGE_PCI) { |
| 375 | busses[pci->secondary_bus].bus_dev = pci; |
| 376 | continue; |
| 377 | } |
| 378 | struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)]; |
| 379 | int i; |
| 380 | for (i = 0; i < PCI_NUM_REGIONS; i++) { |
| 381 | u32 val, size; |
| 382 | pci_bios_get_bar(pci, i, &val, &size); |
| 383 | if (val == 0) |
| 384 | continue; |
| 385 | |
| 386 | pci_bios_bus_reserve(bus, pci_addr_to_type(val), size); |
| 387 | pci->bars[i].addr = val; |
| 388 | pci->bars[i].size = size; |
| 389 | pci->bars[i].is64 = (!(val & PCI_BASE_ADDRESS_SPACE_IO) && |
| 390 | (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) |
| 391 | == PCI_BASE_ADDRESS_MEM_TYPE_64); |
| 392 | |
| 393 | if (pci->bars[i].is64) |
| 394 | i++; |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | // Propagate required bus resources to parent busses. |
| 399 | int secondary_bus; |
| 400 | for (secondary_bus=MaxPCIBus; secondary_bus>0; secondary_bus--) { |
| 401 | struct pci_bus *s = &busses[secondary_bus]; |
| 402 | if (!s->bus_dev) |
| 403 | continue; |
| 404 | struct pci_bus *parent = &busses[pci_bdf_to_bus(s->bus_dev->bdf)]; |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 405 | int type; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 406 | for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 407 | u32 limit = (type == PCI_REGION_TYPE_IO) ? |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 408 | PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; |
| 409 | s->r[type].size = s->r[type].sum; |
| 410 | if (s->r[type].size < limit) |
| 411 | s->r[type].size = limit; |
| 412 | s->r[type].size = pci_size_roundup(s->r[type].size); |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 413 | pci_bios_bus_reserve(parent, type, s->r[type].size); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 414 | } |
| 415 | dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem %x\n", |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 416 | secondary_bus, |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 417 | s->r[PCI_REGION_TYPE_IO].size, |
| 418 | s->r[PCI_REGION_TYPE_MEM].size, |
| 419 | s->r[PCI_REGION_TYPE_PREFMEM].size); |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 420 | } |
| 421 | } |
| 422 | |
| 423 | #define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1) |
| 424 | |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 425 | static int pci_bios_init_root_regions(struct pci_bus *bus, u32 start, u32 end) |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 426 | { |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 427 | bus->r[PCI_REGION_TYPE_IO].base = 0xc000; |
| 428 | |
| 429 | if (bus->r[PCI_REGION_TYPE_MEM].sum < bus->r[PCI_REGION_TYPE_PREFMEM].sum) { |
| 430 | bus->r[PCI_REGION_TYPE_MEM].base = |
| 431 | ROOT_BASE(end, |
| 432 | bus->r[PCI_REGION_TYPE_MEM].sum, |
| 433 | bus->r[PCI_REGION_TYPE_MEM].max); |
| 434 | bus->r[PCI_REGION_TYPE_PREFMEM].base = |
| 435 | ROOT_BASE(bus->r[PCI_REGION_TYPE_MEM].base, |
| 436 | bus->r[PCI_REGION_TYPE_PREFMEM].sum, |
| 437 | bus->r[PCI_REGION_TYPE_PREFMEM].max); |
| 438 | if (bus->r[PCI_REGION_TYPE_PREFMEM].base >= start) { |
| 439 | return 0; |
| 440 | } |
| 441 | } else { |
| 442 | bus->r[PCI_REGION_TYPE_PREFMEM].base = |
| 443 | ROOT_BASE(end, |
| 444 | bus->r[PCI_REGION_TYPE_PREFMEM].sum, |
| 445 | bus->r[PCI_REGION_TYPE_PREFMEM].max); |
| 446 | bus->r[PCI_REGION_TYPE_MEM].base = |
| 447 | ROOT_BASE(bus->r[PCI_REGION_TYPE_PREFMEM].base, |
| 448 | bus->r[PCI_REGION_TYPE_MEM].sum, |
| 449 | bus->r[PCI_REGION_TYPE_MEM].max); |
| 450 | if (bus->r[PCI_REGION_TYPE_MEM].base >= start) { |
| 451 | return 0; |
| 452 | } |
| 453 | } |
| 454 | return -1; |
| 455 | } |
| 456 | |
| 457 | |
| 458 | /**************************************************************** |
| 459 | * BAR assignment |
| 460 | ****************************************************************/ |
| 461 | |
| 462 | static void pci_bios_init_bus_bases(struct pci_bus *bus) |
| 463 | { |
| 464 | u32 base, newbase, size; |
| 465 | int type, i; |
| 466 | |
| 467 | for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { |
| 468 | dprintf(1, " type %s max %x sum %x base %x\n", region_type_name[type], |
| 469 | bus->r[type].max, bus->r[type].sum, bus->r[type].base); |
| 470 | base = bus->r[type].base; |
| 471 | for (i = ARRAY_SIZE(bus->r[type].count)-1; i >= 0; i--) { |
| 472 | size = pci_index_to_size(i, type); |
| 473 | if (!bus->r[type].count[i]) |
| 474 | continue; |
| 475 | newbase = base + size * bus->r[type].count[i]; |
| 476 | dprintf(1, " size %8x: %d bar(s), %8x -> %8x\n", |
| 477 | size, bus->r[type].count[i], base, newbase - 1); |
| 478 | bus->r[type].bases[i] = base; |
| 479 | base = newbase; |
| 480 | } |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size) |
| 485 | { |
| 486 | u32 index, addr; |
| 487 | |
| 488 | index = pci_size_to_index(size, type); |
| 489 | addr = bus->r[type].bases[index]; |
| 490 | bus->r[type].bases[index] += pci_index_to_size(index, type); |
| 491 | return addr; |
| 492 | } |
| 493 | |
| 494 | #define PCI_IO_SHIFT 8 |
| 495 | #define PCI_MEMORY_SHIFT 16 |
| 496 | #define PCI_PREF_MEMORY_SHIFT 16 |
| 497 | |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 498 | static void pci_bios_map_devices(struct pci_bus *busses) |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 499 | { |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 500 | // Setup bases for root bus. |
| 501 | dprintf(1, "PCI: init bases bus 0 (primary)\n"); |
| 502 | pci_bios_init_bus_bases(&busses[0]); |
| 503 | |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 504 | // Map regions on each secondary bus. |
| 505 | int secondary_bus; |
| 506 | for (secondary_bus=1; secondary_bus<=MaxPCIBus; secondary_bus++) { |
| 507 | struct pci_bus *s = &busses[secondary_bus]; |
| 508 | if (!s->bus_dev) |
| 509 | continue; |
| 510 | u16 bdf = s->bus_dev->bdf; |
| 511 | struct pci_bus *parent = &busses[pci_bdf_to_bus(bdf)]; |
Kevin O'Connor | cbbdcf2 | 2011-10-01 13:13:29 -0400 | [diff] [blame] | 512 | int type; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 513 | for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 514 | s->r[type].base = pci_bios_bus_get_addr( |
| 515 | parent, type, s->r[type].size); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 516 | } |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 517 | dprintf(1, "PCI: init bases bus %d (secondary)\n", secondary_bus); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 518 | pci_bios_init_bus_bases(s); |
Gerd Hoffmann | 01a5c88 | 2011-07-11 09:20:29 +0200 | [diff] [blame] | 519 | |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 520 | u32 base = s->r[PCI_REGION_TYPE_IO].base; |
| 521 | u32 limit = base + s->r[PCI_REGION_TYPE_IO].size - 1; |
Gerd Hoffmann | 01a5c88 | 2011-07-11 09:20:29 +0200 | [diff] [blame] | 522 | pci_config_writeb(bdf, PCI_IO_BASE, base >> PCI_IO_SHIFT); |
| 523 | pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0); |
| 524 | pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT); |
| 525 | pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0); |
| 526 | |
| 527 | base = s->r[PCI_REGION_TYPE_MEM].base; |
| 528 | limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1; |
| 529 | pci_config_writew(bdf, PCI_MEMORY_BASE, base >> PCI_MEMORY_SHIFT); |
| 530 | pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT); |
| 531 | |
| 532 | base = s->r[PCI_REGION_TYPE_PREFMEM].base; |
| 533 | limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1; |
| 534 | pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base >> PCI_PREF_MEMORY_SHIFT); |
| 535 | pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT); |
| 536 | pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0); |
| 537 | pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 538 | } |
| 539 | |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 540 | // Map regions on each device. |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 541 | struct pci_device *pci; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 542 | foreachpci(pci) { |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 543 | if (pci->class == PCI_CLASS_BRIDGE_PCI) |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 544 | continue; |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 545 | u16 bdf = pci->bdf; |
Kevin O'Connor | 99e37c4 | 2011-10-01 10:47:21 -0400 | [diff] [blame] | 546 | dprintf(1, "PCI: map device bdf=%02x:%02x.%x\n" |
| 547 | , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)); |
Kevin O'Connor | 2c4c211 | 2011-10-15 11:42:48 -0400 | [diff] [blame] | 548 | struct pci_bus *bus = &busses[pci_bdf_to_bus(bdf)]; |
| 549 | int i; |
| 550 | for (i = 0; i < PCI_NUM_REGIONS; i++) { |
| 551 | if (pci->bars[i].addr == 0) |
| 552 | continue; |
| 553 | |
| 554 | int type = pci_addr_to_type(pci->bars[i].addr); |
| 555 | u32 addr = pci_bios_bus_get_addr(bus, type, pci->bars[i].size); |
| 556 | dprintf(1, " bar %d, addr %x, size %x [%s]\n", |
| 557 | i, addr, pci->bars[i].size, region_type_name[type]); |
| 558 | pci_set_io_region_addr(pci, i, addr); |
| 559 | |
| 560 | if (pci->bars[i].is64) |
| 561 | i++; |
| 562 | } |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 563 | } |
| 564 | } |
| 565 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 566 | |
Kevin O'Connor | 5bab7e6 | 2011-10-01 11:33:31 -0400 | [diff] [blame] | 567 | /**************************************************************** |
| 568 | * Main setup code |
| 569 | ****************************************************************/ |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 570 | |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 571 | void |
Kevin O'Connor | 40f5b5a | 2009-09-13 10:46:57 -0400 | [diff] [blame] | 572 | pci_setup(void) |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 573 | { |
Kevin O'Connor | 37956dd | 2011-06-21 22:22:58 -0400 | [diff] [blame] | 574 | if (CONFIG_COREBOOT || usingXen()) { |
| 575 | // PCI setup already done by coreboot or Xen - just do probe. |
Jan Kiszka | 58e6b3f | 2011-09-21 08:16:21 +0200 | [diff] [blame] | 576 | pci_probe_devices(); |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 577 | return; |
Kevin O'Connor | 37956dd | 2011-06-21 22:22:58 -0400 | [diff] [blame] | 578 | } |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 579 | |
Kevin O'Connor | 40f5b5a | 2009-09-13 10:46:57 -0400 | [diff] [blame] | 580 | dprintf(3, "pci setup\n"); |
| 581 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 582 | u32 start = BUILD_PCIMEM_START; |
Gerd Hoffmann | 60a348b | 2011-07-11 09:20:31 +0200 | [diff] [blame] | 583 | u32 end = BUILD_PCIMEM_END; |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 584 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 585 | dprintf(1, "=== PCI bus & bridge init ===\n"); |
Jan Kiszka | 58e6b3f | 2011-09-21 08:16:21 +0200 | [diff] [blame] | 586 | if (pci_probe_host() != 0) { |
| 587 | return; |
| 588 | } |
Isaku Yamahata | f441666 | 2010-06-22 17:57:52 +0900 | [diff] [blame] | 589 | pci_bios_init_bus(); |
| 590 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 591 | dprintf(1, "=== PCI device probing ===\n"); |
Jan Kiszka | 58e6b3f | 2011-09-21 08:16:21 +0200 | [diff] [blame] | 592 | pci_probe_devices(); |
Kevin O'Connor | 37956dd | 2011-06-21 22:22:58 -0400 | [diff] [blame] | 593 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 594 | dprintf(1, "=== PCI new allocation pass #1 ===\n"); |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 595 | struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1)); |
Kevin O'Connor | 28a20e1 | 2011-10-15 11:07:30 -0400 | [diff] [blame] | 596 | if (!busses) { |
| 597 | warn_noalloc(); |
| 598 | return; |
| 599 | } |
| 600 | memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1)); |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 601 | pci_bios_check_devices(busses); |
| 602 | if (pci_bios_init_root_regions(&busses[0], start, end) != 0) { |
Gerd Hoffmann | 01a5c88 | 2011-07-11 09:20:29 +0200 | [diff] [blame] | 603 | panic("PCI: out of address space\n"); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 604 | } |
| 605 | |
| 606 | dprintf(1, "=== PCI new allocation pass #2 ===\n"); |
Kevin O'Connor | b725dcb | 2011-10-15 11:53:38 -0400 | [diff] [blame] | 607 | pci_bios_map_devices(busses); |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 608 | |
Kevin O'Connor | 3f2288f | 2011-10-15 12:02:14 -0400 | [diff] [blame^] | 609 | pci_bios_init_devices(); |
Gerd Hoffmann | 8e30147 | 2011-08-09 17:22:42 +0200 | [diff] [blame] | 610 | |
Gerd Hoffmann | 82b39b2 | 2011-07-11 09:20:28 +0200 | [diff] [blame] | 611 | free(busses); |
Kevin O'Connor | 0525d29 | 2008-07-04 06:18:30 -0400 | [diff] [blame] | 612 | } |