1/* 2 * Copyright 2006, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include <KernelExport.h> 7#include <driver_settings.h> 8#include <string.h> 9#include "pci_irq.h" 10#include "pci_bios.h" 11#include "pci_private.h" 12#include "pci_controller.h" 13#include "arch_cpu.h" 14 15#define PCI_MECH1_REQ_PORT 0xCF8 16#define PCI_MECH1_DATA_PORT 0xCFC 17#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \ 18 (0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3)) 19 20#define PCI_MECH2_ENABLE_PORT 0x0cf8 21#define PCI_MECH2_FORWARD_PORT 0x0cfa 22#define PCI_MECH2_CONFIG_PORT(dev, offset) \ 23 (uint16)(0xC00 | (dev << 8) | offset) 24 25#define PCI_LOCK_CONFIG(cpu_status) \ 26{ \ 27 cpu_status = disable_interrupts(); \ 28 acquire_spinlock(&sConfigLock); \ 29} 30 31#define PCI_UNLOCK_CONFIG(cpu_status) \ 32{ \ 33 release_spinlock(&sConfigLock); \ 34 restore_interrupts(cpu_status); \ 35} 36 37spinlock sConfigLock = B_SPINLOCK_INITIALIZER; 38 39static status_t 40pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, 41 uint8 offset, uint8 size, uint32 *value) 42{ 43 cpu_status cpu; 44 status_t status = B_OK; 45 46 PCI_LOCK_CONFIG(cpu); 47 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); 48 switch (size) { 49 case 1: 50 *value = in8(PCI_MECH1_DATA_PORT + (offset & 3)); 51 break; 52 case 2: 53 *value = in16(PCI_MECH1_DATA_PORT + (offset & 3)); 54 break; 55 case 4: 56 *value = in32(PCI_MECH1_DATA_PORT); 57 break; 58 default: 59 status = B_ERROR; 60 break; 61 } 62 PCI_UNLOCK_CONFIG(cpu); 63 64 return status; 65} 66 67 68static status_t 69pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, 70 uint8 offset, uint8 size, uint32 value) 71{ 72 cpu_status cpu; 73 status_t status = B_OK; 74 75 PCI_LOCK_CONFIG(cpu); 76 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); 77 switch (size) { 78 case 1: 79 out8(value, PCI_MECH1_DATA_PORT + (offset & 3)); 80 break; 81 case 2: 82 out16(value, PCI_MECH1_DATA_PORT + (offset & 3)); 83 break; 84 case 4: 85 out32(value, PCI_MECH1_DATA_PORT); 86 break; 87 default: 88 status = B_ERROR; 89 break; 90 } 91 PCI_UNLOCK_CONFIG(cpu); 92 93 return status; 94} 95 96 97static status_t 98pci_mech1_get_max_bus_devices(void *cookie, int32 *count) 99{ 100 *count = 32; 101 return B_OK; 102} 103 104 105static status_t 106pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, 107 uint8 offset, uint8 size, uint32 *value) 108{ 109 cpu_status cpu; 110 status_t status = B_OK; 111 112 PCI_LOCK_CONFIG(cpu); 113 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); 114 out8(bus, PCI_MECH2_FORWARD_PORT); 115 switch (size) { 116 case 1: 117 *value = in8(PCI_MECH2_CONFIG_PORT(device, offset)); 118 break; 119 case 2: 120 *value = in16(PCI_MECH2_CONFIG_PORT(device, offset)); 121 break; 122 case 4: 123 *value = in32(PCI_MECH2_CONFIG_PORT(device, offset)); 124 break; 125 default: 126 status = B_ERROR; 127 break; 128 } 129 out8(0, PCI_MECH2_ENABLE_PORT); 130 PCI_UNLOCK_CONFIG(cpu); 131 132 return status; 133} 134 135 136static status_t 137pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, 138 uint8 offset, uint8 size, uint32 value) 139{ 140 cpu_status cpu; 141 status_t status = B_OK; 142 143 PCI_LOCK_CONFIG(cpu); 144 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); 145 out8(bus, PCI_MECH2_FORWARD_PORT); 146 switch (size) { 147 case 1: 148 out8(value, PCI_MECH2_CONFIG_PORT(device, offset)); 149 break; 150 case 2: 151 out16(value, PCI_MECH2_CONFIG_PORT(device, offset)); 152 break; 153 case 4: 154 out32(value, PCI_MECH2_CONFIG_PORT(device, offset)); 155 break; 156 default: 157 status = B_ERROR; 158 break; 159 } 160 out8(0, PCI_MECH2_ENABLE_PORT); 161 PCI_UNLOCK_CONFIG(cpu); 162 163 return status; 164} 165 166 167static status_t 168pci_mech2_get_max_bus_devices(void *cookie, int32 *count) 169{ 170 *count = 16; 171 return B_OK; 172} 173 174 175void * 176pci_ram_address(const void *physical_address_in_system_memory) 177{ 178 return (void *)physical_address_in_system_memory; 179} 180 181 182pci_controller pci_controller_x86_mech1 = 183{ 184 pci_mech1_read_config, 185 pci_mech1_write_config, 186 pci_mech1_get_max_bus_devices, 187 pci_x86_irq_read, 188 pci_x86_irq_write, 189}; 190 191pci_controller pci_controller_x86_mech2 = 192{ 193 pci_mech2_read_config, 194 pci_mech2_write_config, 195 pci_mech2_get_max_bus_devices, 196 pci_x86_irq_read, 197 pci_x86_irq_write, 198}; 199 200pci_controller pci_controller_x86_bios = 201{ 202 pci_bios_read_config, 203 pci_bios_write_config, 204 pci_bios_get_max_bus_devices, 205 pci_x86_irq_read, 206 pci_x86_irq_write, 207}; 208 209 210status_t 211pci_controller_init(void) 212{ 213 bool search_mech1 = true; 214 bool search_mech2 = true; 215 bool search_bios = true; 216 void *config = NULL; 217 status_t status; 218 219 status = pci_x86_irq_init(); 220 if (status != B_OK) 221 return status; 222 223 config = load_driver_settings("pci"); 224 if (config) { 225 const char *mech = get_driver_parameter(config, "mechanism", 226 NULL, NULL); 227 if (mech) { 228 search_mech1 = search_mech2 = search_bios = false; 229 if (strcmp(mech, "1") == 0) 230 search_mech1 = true; 231 else if (strcmp(mech, "2") == 0) 232 search_mech2 = true; 233 else if (strcmp(mech, "bios") == 0) 234 search_bios = true; 235 else 236 panic("Unknown pci config mechanism setting %s\n", mech); 237 } 238 unload_driver_settings(config); 239 } 240 241 // TODO: check safemode "don't call the BIOS" setting and unset search_bios! 242 243 // PCI configuration mechanism 1 is the preferred one. 244 // If it doesn't work, try mechanism 2. 245 // Finally, try to fallback to PCI BIOS 246 247 if (search_mech1) { 248 // check for mechanism 1 249 out32(0x80000000, PCI_MECH1_REQ_PORT); 250 if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) { 251 dprintf("PCI: mechanism 1 controller found\n"); 252 return pci_controller_add(&pci_controller_x86_mech1, NULL); 253 } 254 } 255 256 if (search_mech2) { 257 // check for mechanism 2 258 out8(0x00, 0xCFB); 259 out8(0x00, 0xCF8); 260 out8(0x00, 0xCFA); 261 if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) { 262 dprintf("PCI: mechanism 2 controller found\n"); 263 return pci_controller_add(&pci_controller_x86_mech2, NULL); 264 } 265 } 266 267 if (search_bios) { 268 // check for PCI BIOS 269 if (pci_bios_init() == B_OK) { 270 dprintf("PCI: BIOS support found\n"); 271 return pci_controller_add(&pci_controller_x86_bios, NULL); 272 } 273 } 274 275 dprintf("PCI: no configuration mechanism found\n"); 276 return B_ERROR; 277} 278 279 280