2 * Copyright 2006, Marcus Overhagen. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 #include <KernelExport.h>
8 #include <driver_settings.h>
14 #include "pci_controller.h"
16 #include "pci_private.h"
21 #define PCI_MECH1_REQ_PORT 0xCF8
22 #define PCI_MECH1_DATA_PORT 0xCFC
23 #define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
24 (0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
26 #define PCI_MECH2_ENABLE_PORT 0x0cf8
27 #define PCI_MECH2_FORWARD_PORT 0x0cfa
28 #define PCI_MECH2_CONFIG_PORT(dev, offset) \
29 (uint16)(0xC00 | (dev << 8) | offset)
31 #define PCI_LOCK_CONFIG(cpu_status) \
33 cpu_status = disable_interrupts(); \
34 acquire_spinlock(&sConfigLock); \
37 #define PCI_UNLOCK_CONFIG(cpu_status) \
39 release_spinlock(&sConfigLock); \
40 restore_interrupts(cpu_status); \
43 spinlock sConfigLock
= B_SPINLOCK_INITIALIZER
;
46 pci_mech1_read_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
47 uint16 offset
, uint8 size
, uint32
*value
)
50 status_t status
= B_OK
;
56 out32(PCI_MECH1_REQ_DATA(bus
, device
, function
, offset
), PCI_MECH1_REQ_PORT
);
59 *value
= in8(PCI_MECH1_DATA_PORT
+ (offset
& 3));
62 *value
= in16(PCI_MECH1_DATA_PORT
+ (offset
& 3));
65 *value
= in32(PCI_MECH1_DATA_PORT
);
71 PCI_UNLOCK_CONFIG(cpu
);
78 pci_mech1_write_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
79 uint16 offset
, uint8 size
, uint32 value
)
82 status_t status
= B_OK
;
88 out32(PCI_MECH1_REQ_DATA(bus
, device
, function
, offset
), PCI_MECH1_REQ_PORT
);
91 out8(value
, PCI_MECH1_DATA_PORT
+ (offset
& 3));
94 out16(value
, PCI_MECH1_DATA_PORT
+ (offset
& 3));
97 out32(value
, PCI_MECH1_DATA_PORT
);
103 PCI_UNLOCK_CONFIG(cpu
);
110 pci_mech1_get_max_bus_devices(void *cookie
, int32
*count
)
118 pci_mech2_read_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
119 uint16 offset
, uint8 size
, uint32
*value
)
122 status_t status
= B_OK
;
127 PCI_LOCK_CONFIG(cpu
);
128 out8((uint8
)(0xf0 | (function
<< 1)), PCI_MECH2_ENABLE_PORT
);
129 out8(bus
, PCI_MECH2_FORWARD_PORT
);
132 *value
= in8(PCI_MECH2_CONFIG_PORT(device
, offset
));
135 *value
= in16(PCI_MECH2_CONFIG_PORT(device
, offset
));
138 *value
= in32(PCI_MECH2_CONFIG_PORT(device
, offset
));
144 out8(0, PCI_MECH2_ENABLE_PORT
);
145 PCI_UNLOCK_CONFIG(cpu
);
152 pci_mech2_write_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
153 uint16 offset
, uint8 size
, uint32 value
)
156 status_t status
= B_OK
;
161 PCI_LOCK_CONFIG(cpu
);
162 out8((uint8
)(0xf0 | (function
<< 1)), PCI_MECH2_ENABLE_PORT
);
163 out8(bus
, PCI_MECH2_FORWARD_PORT
);
166 out8(value
, PCI_MECH2_CONFIG_PORT(device
, offset
));
169 out16(value
, PCI_MECH2_CONFIG_PORT(device
, offset
));
172 out32(value
, PCI_MECH2_CONFIG_PORT(device
, offset
));
178 out8(0, PCI_MECH2_ENABLE_PORT
);
179 PCI_UNLOCK_CONFIG(cpu
);
186 pci_mech2_get_max_bus_devices(void *cookie
, int32
*count
)
193 addr_t sPCIeBase
= 0;
194 uint8 sStartBusNumber
;
196 #define PCIE_VADDR(base, bus, slot, func, reg) ((base) + \
197 ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) | \
198 (((func) & 0x7) << 12) | ((reg) & 0xfff)))
201 pci_mechpcie_read_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
202 uint16 offset
, uint8 size
, uint32
*value
)
204 // fallback to mechanism 1 for out of range busses
205 if (bus
< sStartBusNumber
|| bus
> sEndBusNumber
) {
206 return pci_mech1_read_config(cookie
, bus
, device
, function
, offset
,
210 status_t status
= B_OK
;
212 addr_t address
= PCIE_VADDR(sPCIeBase
, bus
, device
, function
, offset
);
216 *value
= *(uint8
*)address
;
219 *value
= *(uint16
*)address
;
222 *value
= *(uint32
*)address
;
233 pci_mechpcie_write_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
234 uint16 offset
, uint8 size
, uint32 value
)
236 // fallback to mechanism 1 for out of range busses
237 if (bus
< sStartBusNumber
|| bus
> sEndBusNumber
) {
238 return pci_mech1_write_config(cookie
, bus
, device
, function
, offset
,
242 status_t status
= B_OK
;
244 addr_t address
= PCIE_VADDR(sPCIeBase
, bus
, device
, function
, offset
);
247 *(uint8
*)address
= value
;
250 *(uint16
*)address
= value
;
253 *(uint32
*)address
= value
;
265 pci_mechpcie_get_max_bus_devices(void *cookie
, int32
*count
)
273 pci_ram_address(phys_addr_t physical_address_in_system_memory
)
275 return physical_address_in_system_memory
;
279 pci_controller pci_controller_x86_mech1
=
281 pci_mech1_read_config
,
282 pci_mech1_write_config
,
283 pci_mech1_get_max_bus_devices
,
288 pci_controller pci_controller_x86_mech2
=
290 pci_mech2_read_config
,
291 pci_mech2_write_config
,
292 pci_mech2_get_max_bus_devices
,
297 pci_controller pci_controller_x86_mechpcie
=
299 pci_mechpcie_read_config
,
300 pci_mechpcie_write_config
,
301 pci_mechpcie_get_max_bus_devices
,
306 pci_controller pci_controller_x86_bios
=
308 pci_bios_read_config
,
309 pci_bios_write_config
,
310 pci_bios_get_max_bus_devices
,
317 pci_controller_init(void)
319 bool search_mech1
= true;
320 bool search_mech2
= true;
321 bool search_mechpcie
= true;
322 bool search_bios
= true;
326 status
= pci_x86_irq_init();
330 config
= load_driver_settings("pci");
332 const char *mech
= get_driver_parameter(config
, "mechanism",
335 search_mech1
= search_mech2
= search_mechpcie
= search_bios
= false;
336 if (strcmp(mech
, "1") == 0)
338 else if (strcmp(mech
, "2") == 0)
340 else if (strcmp(mech
, "pcie") == 0)
341 search_mechpcie
= true;
342 else if (strcmp(mech
, "bios") == 0)
345 panic("Unknown pci config mechanism setting %s\n", mech
);
347 unload_driver_settings(config
);
350 // TODO: check safemode "don't call the BIOS" setting and unset search_bios!
352 // PCI configuration mechanism PCIe is the preferred one.
353 // If it doesn't work, try mechanism 1.
354 // If it doesn't work, try mechanism 2.
355 // Finally, try to fallback to PCI BIOS
357 if (search_mechpcie
) {
359 struct acpi_table_mcfg
* mcfg
=
360 (struct acpi_table_mcfg
*)acpi_find_table("MCFG");
362 struct acpi_mcfg_allocation
* end
= (struct acpi_mcfg_allocation
*)
363 ((char*)mcfg
+ mcfg
->Header
.Length
);
364 struct acpi_mcfg_allocation
* alloc
= (struct acpi_mcfg_allocation
*)
366 for (; alloc
< end
; alloc
++) {
367 dprintf("PCI: mechanism addr: %" B_PRIx64
", seg: %x, start: "
368 "%x, end: %x\n", alloc
->Address
, alloc
->PciSegment
,
369 alloc
->StartBusNumber
, alloc
->EndBusNumber
);
370 if (alloc
->PciSegment
== 0) {
371 area_id mcfgArea
= map_physical_memory("acpi mcfg",
372 alloc
->Address
, (alloc
->EndBusNumber
+ 1) << 20,
373 B_ANY_KERNEL_ADDRESS
, B_KERNEL_READ_AREA
374 | B_KERNEL_WRITE_AREA
, (void **)&sPCIeBase
);
377 sStartBusNumber
= alloc
->StartBusNumber
;
378 sEndBusNumber
= alloc
->EndBusNumber
;
379 dprintf("PCI: mechanism pcie controller found\n");
380 return pci_controller_add(&pci_controller_x86_mechpcie
,
388 // check for mechanism 1
389 out32(0x80000000, PCI_MECH1_REQ_PORT
);
390 if (0x80000000 == in32(PCI_MECH1_REQ_PORT
)) {
391 dprintf("PCI: mechanism 1 controller found\n");
392 return pci_controller_add(&pci_controller_x86_mech1
, NULL
);
397 // check for mechanism 2
401 if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
402 dprintf("PCI: mechanism 2 controller found\n");
403 return pci_controller_add(&pci_controller_x86_mech2
, NULL
);
408 // check for PCI BIOS
409 if (pci_bios_init() == B_OK
) {
410 dprintf("PCI: BIOS support found\n");
411 return pci_controller_add(&pci_controller_x86_bios
, NULL
);
415 dprintf("PCI: no configuration mechanism found\n");