00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <agnix/agnix.h>
00019 #include <agnix/adi/adi.h>
00020 #include <agnix/memory.h>
00021 #include <agnix/spinlock.h>
00022 #include <agnix/console.h>
00023
00024 #define MOD_NAME "PCI: \t\t"
00025 #define PCI_DEBUG 1
00026
00027 extern struct list_head pcibus_list;
00028 extern struct list_head pcidev_list;
00029 extern spinlock_t pcibus_list_lock;
00030 extern spinlock_t pcidev_list_lock;
00031
00032 struct pcibus_s *pcibus_primary;
00033 extern struct pcibus_ops_s pcibus_primary_ops;
00034 extern int pcibus_disable;
00035
00036 void pcibus_add_device(struct pcidev_s *pcidev)
00037 {
00038 u32 flags;
00039
00040 spin_lock_irqsave(&pcidev_list_lock, flags);
00041 list_add_tail(&(pcidev->dev_list), &pcidev_list);
00042 spin_unlock_irqrestore(&pcidev_list_lock, flags);
00043 }
00044
00045 void pcibus_add_bus(struct pcibus_s *pcibus)
00046 {
00047 u32 flags;
00048
00049 spin_lock_irqsave(&pcibus_list_lock, flags);
00050 list_add_tail(&(pcibus->bus_list), &pcibus_list);
00051 spin_unlock_irqrestore(&pcibus_list_lock, flags);
00052 }
00053
00054 struct pcidev_s *pcibus_find_device_by_id(u16 vendor_id, u16 device_id)
00055 {
00056 u32 flags;
00057 struct list_head *tmp;
00058 struct pcidev_s *pcidev;
00059
00060 spin_lock_irqsave(&pcidev_list_lock, flags);
00061
00062 list_for_each(tmp, &pcidev_list) {
00063 pcidev = list_entry(tmp, struct pcidev_s, dev_list);
00064
00065 if (pcidev->dev_vendor_id == vendor_id &&
00066 pcidev->dev_device_id == device_id)
00067 goto pcidev_found;
00068 }
00069
00070 pcidev = NULL;
00071
00072 pcidev_found:
00073 spin_unlock_irqrestore(&pcidev_list_lock, flags);
00074
00075 return pcidev;
00076 }
00077
00078 struct pcidev_s *pcibus_find_device_by_fn(u8 bus_nr, int function)
00079 {
00080 u32 flags;
00081 struct list_head *tmp;
00082 struct pcidev_s *pcidev;
00083
00084 spin_lock_irqsave(&pcidev_list_lock, flags);
00085
00086 list_for_each(tmp, &pcidev_list) {
00087 pcidev = list_entry(tmp, struct pcidev_s, dev_list);
00088
00089 if (pcidev->dev_fn == function && pcidev->dev_bus->bus_nr == bus_nr)
00090 goto pcidev_found;
00091 }
00092
00093 pcidev = NULL;
00094
00095 pcidev_found:
00096 spin_unlock_irqrestore(&pcidev_list_lock, flags);
00097
00098 return pcidev;
00099 }
00100
00101 int pcibus_find_capability_pos(struct pcidev_s *pcidev, int cap_req_id)
00102 {
00103 u16 dev_status;
00104 u8 cap_next;
00105 u8 cap_pos;
00106 u8 cap_id;
00107 int cap_max_entries = 48;
00108
00109 pci_read_config_word(pcidev, PCI_STATUS, &dev_status);
00110
00111 if (!(dev_status & PCI_STATUS_CAP_LIST))
00112 return -1;
00113
00114 switch(pcidev->dev_header_type) {
00115 case PCIDEV_HDR_TYPE_NORMAL:
00116 case PCIDEV_HDR_TYPE_BRIDGE:
00117 cap_pos = PCI_CAPABILITY_LIST;
00118 case PCIDEV_HDR_TYPE_CB:
00119 cap_pos = PCI_CB_CAPABILITY_LIST;
00120 default:
00121 return -1;
00122 }
00123
00124 for(cap_max_entries = 48; cap_max_entries > 0; cap_max_entries--) {
00125 pci_read_config_byte(pcidev, cap_pos + PCI_CAP_LIST_ID, &cap_id);
00126
00127 if (cap_id == cap_req_id)
00128 return cap_pos;
00129
00130 if (cap_id == 0xff)
00131 break;
00132
00133 pci_read_config_byte(pcidev, cap_pos + PCI_CAP_LIST_NEXT, &cap_next);
00134
00135 if (cap_pos <= 0x40)
00136 return -1;
00137
00138 cap_pos = cap_next;
00139 }
00140
00141 return -1;
00142 }
00143
00144 int pcibus_power_change_delay(struct pcidev_s *pcidev, int power_1, int power_2)
00145 {
00146 return 0;
00147 }
00148
00149 int pcibus_set_power_state(struct pcidev_s *pcidev, int power_state)
00150 {
00151 int cap_pos;
00152 u16 pm_caps;
00153 u16 pm_ctrl;
00154
00155 if (power_state < 0 || power_state > 3)
00156 return -1;
00157
00158 if ((cap_pos = pcibus_find_capability_pos(pcidev, PCI_CAP_ID_PM)) < 0)
00159 return -1;
00160
00161 if (power_state == 1 || power_state == 2) {
00162 pci_read_config_word(pcidev, cap_pos + PCI_PM_PMC, &pm_caps);
00163 if (!(pm_caps & (PCI_PM_CAP_D1 << (power_state - 1))))
00164 return -1;
00165 }
00166
00167 pci_read_config_word(pcidev, cap_pos + PCI_PM_CTRL, &pm_ctrl);
00168 pm_ctrl = (pm_ctrl & (~PCI_PM_CTRL_STATE_MASK)) | power_state;
00169 pci_write_config_word(pcidev, cap_pos + PCI_PM_CTRL, pm_ctrl);
00170
00171 pcibus_power_change_delay(pcidev, 0, 0);
00172
00173 return 0;
00174 }
00175
00176 int pcibus_enable_device(struct pcidev_s *pcidev)
00177 {
00178 u16 pcidev_cmd_tmp;
00179 u16 pcidev_cmd;
00180 int i;
00181
00182 pcibus_set_power_state(pcidev, 0);
00183
00184 pci_read_config_word(pcidev, PCI_COMMAND, &pcidev_cmd);
00185 pcidev_cmd_tmp = pcidev_cmd;
00186
00187 for (i = 0; i < pcidev->dev_max_resources; i++) {
00188 if (pcidev->dev_resources[i].res_flags & ADI_RES_FLAG_IO)
00189 pcidev_cmd |= PCI_COMMAND_IO;
00190 else
00191 if (pcidev->dev_resources[i].res_flags & ADI_RES_FLAG_MEM)
00192 pcidev_cmd |= PCI_COMMAND_MEMORY;
00193 }
00194
00195 if (pcidev_cmd != pcidev_cmd_tmp)
00196 pci_write_config_word(pcidev, PCI_COMMAND, pcidev_cmd);
00197
00198 return 0;
00199 }
00200
00201 struct pcibus_s *pcibus_allocate_primary_bus(int bus_nr, struct pcibus_ops_s *bus_ops)
00202 {
00203 struct pcibus_s *pcibus;
00204
00205 if (bus_ops == NULL || bus_ops->pcibus_read_config == NULL
00206 || bus_ops->pcibus_write_config == NULL) {
00207 printk(MOD_NAME "invalid bus_ops\n");
00208 return NULL;
00209 }
00210
00211 pcibus = (struct pcibus_s *)get_free_pages(0);
00212 pcibus->bus_nr = bus_nr;
00213 pcibus->bus_ops = bus_ops;
00214
00215 pcibus_add_bus(pcibus);
00216
00217 return pcibus;
00218 }
00219
00220 struct pcibus_s *pcibus_allocate_child_bus(struct pcibus_s *parent, int child_bus_nr)
00221 {
00222 struct pcibus_s *child;
00223
00224 child = (struct pcibus_s *)get_free_pages(0);
00225
00226 child->bus_nr = child_bus_nr;
00227 child->bus_ops = parent->bus_ops;
00228
00229 return child;
00230 }
00231
00232 int pcibus_scan_card_memory(struct pcidev_s *pcidev, unsigned int res_nr)
00233 {
00234 u32 start;
00235 u32 size;
00236 u32 value;
00237 unsigned int i;
00238 unsigned int offset = 0;
00239 struct adi_resource_s *adi_resource;
00240
00241 for (i = 0; i < res_nr; i++) {
00242
00243
00244 offset = PCIDEV_BASE_ADDRESS_0 + (i << 2);
00245 pci_read_config_dword (pcidev, offset, &value);
00246 pci_write_config_dword(pcidev, offset, 0xFFFFFFFF);
00247 pci_read_config_dword (pcidev, offset, &size);
00248 pci_write_config_dword(pcidev, offset, value);
00249
00250 if (size == 0x00000000 || size == 0xFFFFFFFF)
00251 continue;
00252
00253 if (value == 0xFFFFFFFF) value = 0;
00254
00255 adi_resource = &pcidev->dev_resources[i];
00256
00257 if ((value & PCIDEV_BASE_ADDRESS_MASK) == PCIDEV_BASE_ADDRESS_MEMORY) {
00258 start = value & PCIDEV_BASE_ADDRESS_START_MASK_MEM;
00259 size &= PCIDEV_BASE_ADDRESS_START_MASK_MEM;
00260 size = size & (~(size - 1));
00261 size--;
00262
00263 adi_resource->res_flags = ADI_RES_FLAG_MEM;
00264 } else
00265 if ((value & PCIDEV_BASE_ADDRESS_MASK) == PCIDEV_BASE_ADDRESS_IO) {
00266 start = value & PCIDEV_BASE_ADDRESS_START_MASK_IO;
00267 size &= PCIDEV_BASE_ADDRESS_START_MASK_IO;
00268 size = size & (~(size - 1));
00269 size--;
00270
00271 adi_resource->res_flags = ADI_RES_FLAG_IO;
00272 }
00273
00274 adi_resource->res_name = pcidev->dev_name;
00275 adi_resource->res_start = start;
00276 adi_resource->res_end = start + size;
00277
00278 INIT_LIST_HEAD(&(adi_resource->res_list));
00279 if (adi_register_resource(adi_resource) < 0) {
00280 printk(MOD_NAME "Can not register resource\n");
00281 }
00282 }
00283
00284 return 0;
00285 }
00286
00287 int pcibus_scan_card_function(struct pcidev_s *pcidev)
00288 {
00289 u32 dev_class;
00290 u8 dev_irq_pin;
00291 u8 dev_irq;
00292 u16 dev_subvendor_id;
00293 u16 dev_subdevice_id;
00294
00295 pci_read_config_dword(pcidev, PCIDEV_CLASS_REVISION, &dev_class);
00296 pci_read_config_byte (pcidev, PCIDEV_INTERRUPT_PIN, &dev_irq_pin);
00297 pci_read_config_byte (pcidev, PCIDEV_INTERRUPT_LINE, &dev_irq);
00298 pci_read_config_word (pcidev, PCIDEV_SUBSYSTEM_ID, &dev_subdevice_id);
00299 pci_read_config_word (pcidev, PCIDEV_SUBSYSTEM_VENDOR_ID, &dev_subvendor_id);
00300
00301 pcidev->dev_class = dev_class >> 8;
00302 pcidev->dev_irq_pin = dev_irq_pin;
00303 pcidev->dev_irq = dev_irq;
00304 pcidev->dev_subvendor_id = dev_subvendor_id;
00305 pcidev->dev_subdevice_id = dev_subdevice_id;
00306
00307 if ((u16)(pcidev->dev_class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
00308 #if PCI_DEBUG
00309 printk(MOD_NAME "%s cardbus legacy mode base\n", pcidev->dev_name);
00310 #endif
00311 pci_write_config_dword(pcidev, PCIDEV_CB_LEGACY_MODE_BASE, 0);
00312 }
00313
00314 switch (pcidev->dev_header_type) {
00315 case PCIDEV_HDR_TYPE_NORMAL:
00316 pcibus_scan_card_memory(pcidev, PCIDEV_MAX_RESOURCES);
00317 break;
00318
00319 case PCIDEV_HDR_TYPE_BRIDGE:
00320 pcibus_scan_card_memory(pcidev, PCIDEV_BRIDGE_RESOURCES);
00321 break;
00322
00323 case PCIDEV_HDR_TYPE_CB:
00324 pcibus_scan_card_memory(pcidev, PCIDEV_CB_RESOURCES);
00325 break;
00326
00327 default:
00328 printk(MOD_NAME "%s wrong header type\n", pcidev->dev_name);
00329 return -1;
00330 }
00331
00332 return 0;
00333 }
00334
00335 int pcibus_scan_card(struct pcidev_s *pcidev)
00336 {
00337 u8 dev_fn;
00338 u8 dev_fn_cur = 0;
00339 int dev_multi = 0;
00340 struct pcidev_s *detected_dev;
00341 u16 dev_vendor_id;
00342 u16 dev_device_id;
00343 u8 dev_header_type;
00344
00345 for (dev_fn = pcidev->dev_fn; dev_fn_cur < 8; dev_fn++, dev_fn_cur++) {
00346 if ((!dev_multi) && dev_fn_cur)
00347 break;
00348
00349 pcidev->dev_fn = dev_fn;
00350
00351 pci_read_config_byte(pcidev, PCIDEV_HEADER_TYPE, &dev_header_type);
00352 pci_read_config_word(pcidev, PCIDEV_VENDOR_ID, &dev_vendor_id);
00353 pci_read_config_word(pcidev, PCIDEV_DEVICE_ID, &dev_device_id);
00354
00355 if ((dev_vendor_id == 0x0000 && ((dev_device_id == 0xFFFF) || (dev_device_id == 0x0000))) ||
00356 (dev_vendor_id == 0xffff))
00357 return -1;
00358
00359 detected_dev = (struct pcidev_s *)get_free_pages(0);
00360
00361 if (detected_dev == NULL) {
00362 #if PCI_DEBUG
00363 printk(MOD_NAME "can not allocate memory for PCI dev\n");
00364 #endif
00365 return -1;
00366 }
00367
00368 memcpy(detected_dev, pcidev, sizeof(struct pcidev_s));
00369
00370 if ((dev_header_type & 0x80) && (!dev_fn_cur))
00371 dev_multi = 1;
00372
00373 detected_dev->dev_header_type = dev_header_type & 0x7F;
00374 detected_dev->dev_vendor_id = dev_vendor_id;
00375 detected_dev->dev_device_id = dev_device_id;
00376 detected_dev->dev_name = pcibus_device_name(dev_vendor_id, dev_device_id);
00377 detected_dev->dev_multi = dev_multi;
00378
00379 pcibus_scan_card_function(detected_dev);
00380
00381 #if PCI_DEBUG
00382 printk(MOD_NAME "detected %s (%04x, %04x)\n", detected_dev->dev_name, dev_vendor_id, dev_device_id);
00383 #endif
00384
00385 pcibus_add_device(detected_dev);
00386 }
00387
00388 return 0;
00389 }
00390
00391 int pcibus_scan(int bus_nr)
00392 {
00393 printk(MOD_NAME "scanning PCI bus %d\n", bus_nr);
00394
00395 return 0;
00396 }
00397
00398 int pcibus_scan_all(void)
00399 {
00400 struct pcidev_s pcidev;
00401 u8 dev_fn;
00402 int i;
00403
00404 printk(MOD_NAME "scanning all PCI buses\n");
00405
00406 pcibus_primary = pcibus_allocate_primary_bus(0, &pcibus_primary_ops);
00407
00408 if (pcibus_primary == NULL) {
00409 printk(MOD_NAME "can not allocate memory for primary PCI bus, disabling PCI subsystem\n");
00410 pcibus_disable = 1;
00411 return 0;
00412 }
00413
00414 pcidev.dev_bus = pcibus_primary;
00415
00416 for (i = 0, dev_fn = 0; i < 32; dev_fn += 8, i++) {
00417 pcidev.dev_fn = dev_fn;
00418
00419 pcibus_scan_card(&pcidev);
00420 }
00421
00422
00423
00424
00425 return 0;
00426 }
00427
00428 void pcibus_print_all(void)
00429 {
00430 struct list_head *tmp;
00431 struct pcidev_s *dev;
00432 u32 flags;
00433
00434 printf("\n");
00435
00436 spin_lock_irqsave(&pcidev_list_lock, flags);
00437
00438 list_for_each(tmp, &pcidev_list) {
00439 dev = list_entry(tmp, struct pcidev_s, dev_list);
00440 if (dev->dev_irq == 0)
00441 printf("%02x:%02x.%x [no irq] %s\n", PCIDEV_BUS(dev), PCIDEV_SLOT(dev), PCIDEV_FN(dev), dev->dev_name);
00442 else
00443 printf("%02x:%02x.%x [irq %d] %s\n", PCIDEV_BUS(dev), PCIDEV_SLOT(dev), PCIDEV_FN(dev), dev->dev_irq, dev->dev_name);
00444 };
00445
00446 spin_unlock_irqrestore(&pcidev_list_lock, flags);
00447 }