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