Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/kernel.h> /* * These functions are used early on before PCI scanning is done * and all of the pci_dev and pci_bus structures have been created. */ static struct pci_dev *fake_pci_dev(struct pci_channel *hose, int top_bus, int busnr, int devfn) { static struct pci_dev dev; static struct pci_bus bus; dev.bus = &bus; dev.sysdata = hose; dev.devfn = devfn; bus.number = busnr; bus.sysdata = hose; bus.ops = hose->pci_ops; if(busnr != top_bus) /* Fake a parent bus structure. */ bus.parent = &bus; else bus.parent = NULL; return &dev; } #define EARLY_PCI_OP(rw, size, type) \ int __init early_##rw##_config_##size(struct pci_channel *hose, \ int top_bus, int bus, int devfn, int offset, type value) \ { \ return pci_##rw##_config_##size( \ fake_pci_dev(hose, top_bus, bus, devfn), \ offset, value); \ } EARLY_PCI_OP(read, byte, u8 *) EARLY_PCI_OP(read, word, u16 *) EARLY_PCI_OP(read, dword, u32 *) EARLY_PCI_OP(write, byte, u8) EARLY_PCI_OP(write, word, u16) EARLY_PCI_OP(write, dword, u32) int __init pci_is_66mhz_capable(struct pci_channel *hose, int top_bus, int current_bus) { u32 pci_devfn; unsigned short vid; int cap66 = -1; u16 stat; printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n"); for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { if (PCI_FUNC(pci_devfn)) continue; if (early_read_config_word(hose, top_bus, current_bus, pci_devfn, PCI_VENDOR_ID, &vid) != PCIBIOS_SUCCESSFUL) continue; if (vid == 0xffff) continue; /* check 66MHz capability */ if (cap66 < 0) cap66 = 1; if (cap66) { early_read_config_word(hose, top_bus, current_bus, pci_devfn, PCI_STATUS, &stat); if (!(stat & PCI_STATUS_66MHZ)) { printk(KERN_DEBUG "PCI: %02x:%02x not 66MHz capable.\n", current_bus, pci_devfn); cap66 = 0; break; } } } return cap66 > 0; } static void pcibios_enable_err(unsigned long __data) { struct pci_channel *hose = (struct pci_channel *)__data; del_timer(&hose->err_timer); printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n"); enable_irq(hose->err_irq); } static void pcibios_enable_serr(unsigned long __data) { struct pci_channel *hose = (struct pci_channel *)__data; del_timer(&hose->serr_timer); printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n"); enable_irq(hose->serr_irq); } void pcibios_enable_timers(struct pci_channel *hose) { if (hose->err_irq) { init_timer(&hose->err_timer); hose->err_timer.data = (unsigned long)hose; hose->err_timer.function = pcibios_enable_err; } if (hose->serr_irq) { init_timer(&hose->serr_timer); hose->serr_timer.data = (unsigned long)hose; hose->serr_timer.function = pcibios_enable_serr; } } /* * A simple handler for the regular PCI status errors, called from IRQ * context. */ unsigned int pcibios_handle_status_errors(unsigned long addr, unsigned int status, struct pci_channel *hose) { unsigned int cmd = 0; if (status & PCI_STATUS_REC_MASTER_ABORT) { printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr); cmd |= PCI_STATUS_REC_MASTER_ABORT; } if (status & PCI_STATUS_REC_TARGET_ABORT) { printk(KERN_DEBUG "PCI: target abort: "); pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT, 1); printk("\n"); cmd |= PCI_STATUS_REC_TARGET_ABORT; } if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) { printk(KERN_DEBUG "PCI: parity error detected: "); pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); printk("\n"); cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY; /* Now back off of the IRQ for awhile */ if (hose->err_irq) { disable_irq_nosync(hose->err_irq); hose->err_timer.expires = jiffies + HZ; add_timer(&hose->err_timer); } } return cmd; } |