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