xref: /openbmc/linux/arch/sh/drivers/pci/common.c (revision 601bf18b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
285b59f5bSPaul Mundt #include <linux/pci.h>
3ef407beeSPaul Mundt #include <linux/interrupt.h>
4ef407beeSPaul Mundt #include <linux/timer.h>
585b59f5bSPaul Mundt #include <linux/kernel.h>
685b59f5bSPaul Mundt 
79ad62ec4SPaul Mundt /*
89ad62ec4SPaul Mundt  * These functions are used early on before PCI scanning is done
99ad62ec4SPaul Mundt  * and all of the pci_dev and pci_bus structures have been created.
109ad62ec4SPaul Mundt  */
fake_pci_dev(struct pci_channel * hose,int top_bus,int busnr,int devfn)119ad62ec4SPaul Mundt static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
129ad62ec4SPaul Mundt 	int top_bus, int busnr, int devfn)
1385b59f5bSPaul Mundt {
149ad62ec4SPaul Mundt 	static struct pci_dev dev;
159ad62ec4SPaul Mundt 	static struct pci_bus bus;
1685b59f5bSPaul Mundt 
179ad62ec4SPaul Mundt 	dev.bus = &bus;
189ad62ec4SPaul Mundt 	dev.sysdata = hose;
199ad62ec4SPaul Mundt 	dev.devfn = devfn;
209ad62ec4SPaul Mundt 	bus.number = busnr;
219ad62ec4SPaul Mundt 	bus.sysdata = hose;
229ad62ec4SPaul Mundt 	bus.ops = hose->pci_ops;
2385b59f5bSPaul Mundt 
249ad62ec4SPaul Mundt 	if(busnr != top_bus)
2585b59f5bSPaul Mundt 		/* Fake a parent bus structure. */
269ad62ec4SPaul Mundt 		bus.parent = &bus;
2785b59f5bSPaul Mundt 	else
289ad62ec4SPaul Mundt 		bus.parent = NULL;
2985b59f5bSPaul Mundt 
309ad62ec4SPaul Mundt 	return &dev;
3185b59f5bSPaul Mundt }
3285b59f5bSPaul Mundt 
339ad62ec4SPaul Mundt #define EARLY_PCI_OP(rw, size, type)					\
349ad62ec4SPaul Mundt int __init early_##rw##_config_##size(struct pci_channel *hose,		\
359ad62ec4SPaul Mundt 	int top_bus, int bus, int devfn, int offset, type value)	\
369ad62ec4SPaul Mundt {									\
379ad62ec4SPaul Mundt 	return pci_##rw##_config_##size(				\
389ad62ec4SPaul Mundt 		fake_pci_dev(hose, top_bus, bus, devfn),		\
399ad62ec4SPaul Mundt 		offset, value);						\
409ad62ec4SPaul Mundt }
419ad62ec4SPaul Mundt 
EARLY_PCI_OP(read,byte,u8 *)429ad62ec4SPaul Mundt EARLY_PCI_OP(read, byte, u8 *)
439ad62ec4SPaul Mundt EARLY_PCI_OP(read, word, u16 *)
449ad62ec4SPaul Mundt EARLY_PCI_OP(read, dword, u32 *)
459ad62ec4SPaul Mundt EARLY_PCI_OP(write, byte, u8)
469ad62ec4SPaul Mundt EARLY_PCI_OP(write, word, u16)
479ad62ec4SPaul Mundt EARLY_PCI_OP(write, dword, u32)
489ad62ec4SPaul Mundt 
4985b59f5bSPaul Mundt int __init pci_is_66mhz_capable(struct pci_channel *hose,
5085b59f5bSPaul Mundt 				int top_bus, int current_bus)
5185b59f5bSPaul Mundt {
5285b59f5bSPaul Mundt 	u32 pci_devfn;
5385b59f5bSPaul Mundt 	unsigned short vid;
5485b59f5bSPaul Mundt 	int cap66 = -1;
5585b59f5bSPaul Mundt 	u16 stat;
5685b59f5bSPaul Mundt 
57601bf18bSGeert Uytterhoeven 	pr_info("PCI: Checking 66MHz capabilities...\n");
5885b59f5bSPaul Mundt 
5985b59f5bSPaul Mundt 	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
6085b59f5bSPaul Mundt 		if (PCI_FUNC(pci_devfn))
6185b59f5bSPaul Mundt 			continue;
6285b59f5bSPaul Mundt 		if (early_read_config_word(hose, top_bus, current_bus,
6385b59f5bSPaul Mundt 					   pci_devfn, PCI_VENDOR_ID, &vid) !=
6485b59f5bSPaul Mundt 		    PCIBIOS_SUCCESSFUL)
6585b59f5bSPaul Mundt 			continue;
6685b59f5bSPaul Mundt 		if (vid == 0xffff)
6785b59f5bSPaul Mundt 			continue;
6885b59f5bSPaul Mundt 
6985b59f5bSPaul Mundt 		/* check 66MHz capability */
7085b59f5bSPaul Mundt 		if (cap66 < 0)
7185b59f5bSPaul Mundt 			cap66 = 1;
7285b59f5bSPaul Mundt 		if (cap66) {
7385b59f5bSPaul Mundt 			early_read_config_word(hose, top_bus, current_bus,
7485b59f5bSPaul Mundt 					       pci_devfn, PCI_STATUS, &stat);
7585b59f5bSPaul Mundt 			if (!(stat & PCI_STATUS_66MHZ)) {
7685b59f5bSPaul Mundt 				printk(KERN_DEBUG
7785b59f5bSPaul Mundt 				       "PCI: %02x:%02x not 66MHz capable.\n",
7885b59f5bSPaul Mundt 				       current_bus, pci_devfn);
7985b59f5bSPaul Mundt 				cap66 = 0;
8085b59f5bSPaul Mundt 				break;
8185b59f5bSPaul Mundt 			}
8285b59f5bSPaul Mundt 		}
8385b59f5bSPaul Mundt 	}
8485b59f5bSPaul Mundt 
8585b59f5bSPaul Mundt 	return cap66 > 0;
8685b59f5bSPaul Mundt }
87ef407beeSPaul Mundt 
pcibios_enable_err(struct timer_list * t)88e99e88a9SKees Cook static void pcibios_enable_err(struct timer_list *t)
89ef407beeSPaul Mundt {
90e99e88a9SKees Cook 	struct pci_channel *hose = from_timer(hose, t, err_timer);
91ef407beeSPaul Mundt 
92ef407beeSPaul Mundt 	del_timer(&hose->err_timer);
93ef407beeSPaul Mundt 	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
94ef407beeSPaul Mundt 	enable_irq(hose->err_irq);
95ef407beeSPaul Mundt }
96ef407beeSPaul Mundt 
pcibios_enable_serr(struct timer_list * t)97e99e88a9SKees Cook static void pcibios_enable_serr(struct timer_list *t)
98ef407beeSPaul Mundt {
99e99e88a9SKees Cook 	struct pci_channel *hose = from_timer(hose, t, serr_timer);
100ef407beeSPaul Mundt 
101ef407beeSPaul Mundt 	del_timer(&hose->serr_timer);
102ef407beeSPaul Mundt 	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
103ef407beeSPaul Mundt 	enable_irq(hose->serr_irq);
104ef407beeSPaul Mundt }
105ef407beeSPaul Mundt 
pcibios_enable_timers(struct pci_channel * hose)106ef407beeSPaul Mundt void pcibios_enable_timers(struct pci_channel *hose)
107ef407beeSPaul Mundt {
108ef407beeSPaul Mundt 	if (hose->err_irq) {
109e99e88a9SKees Cook 		timer_setup(&hose->err_timer, pcibios_enable_err, 0);
110ef407beeSPaul Mundt 	}
111ef407beeSPaul Mundt 
112ef407beeSPaul Mundt 	if (hose->serr_irq) {
113e99e88a9SKees Cook 		timer_setup(&hose->serr_timer, pcibios_enable_serr, 0);
114ef407beeSPaul Mundt 	}
115ef407beeSPaul Mundt }
116ef407beeSPaul Mundt 
117ef407beeSPaul Mundt /*
118ef407beeSPaul Mundt  * A simple handler for the regular PCI status errors, called from IRQ
119ef407beeSPaul Mundt  * context.
120ef407beeSPaul Mundt  */
pcibios_handle_status_errors(unsigned long addr,unsigned int status,struct pci_channel * hose)121ef407beeSPaul Mundt unsigned int pcibios_handle_status_errors(unsigned long addr,
122ef407beeSPaul Mundt 					  unsigned int status,
123ef407beeSPaul Mundt 					  struct pci_channel *hose)
124ef407beeSPaul Mundt {
125ef407beeSPaul Mundt 	unsigned int cmd = 0;
126ef407beeSPaul Mundt 
127ef407beeSPaul Mundt 	if (status & PCI_STATUS_REC_MASTER_ABORT) {
128ef407beeSPaul Mundt 		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
129ef407beeSPaul Mundt 		cmd |= PCI_STATUS_REC_MASTER_ABORT;
130ef407beeSPaul Mundt 	}
131ef407beeSPaul Mundt 
132ef407beeSPaul Mundt 	if (status & PCI_STATUS_REC_TARGET_ABORT) {
133ef407beeSPaul Mundt 		printk(KERN_DEBUG "PCI: target abort: ");
134ef407beeSPaul Mundt 		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
135ef407beeSPaul Mundt 				      PCI_STATUS_SIG_TARGET_ABORT |
136ef407beeSPaul Mundt 				      PCI_STATUS_REC_MASTER_ABORT, 1);
137601bf18bSGeert Uytterhoeven 		pr_cont("\n");
138ef407beeSPaul Mundt 
139ef407beeSPaul Mundt 		cmd |= PCI_STATUS_REC_TARGET_ABORT;
140ef407beeSPaul Mundt 	}
141ef407beeSPaul Mundt 
142ef407beeSPaul Mundt 	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
143ef407beeSPaul Mundt 		printk(KERN_DEBUG "PCI: parity error detected: ");
144ef407beeSPaul Mundt 		pcibios_report_status(PCI_STATUS_PARITY |
145ef407beeSPaul Mundt 				      PCI_STATUS_DETECTED_PARITY, 1);
146601bf18bSGeert Uytterhoeven 		pr_cont("\n");
147ef407beeSPaul Mundt 
148ef407beeSPaul Mundt 		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
149ef407beeSPaul Mundt 
150ef407beeSPaul Mundt 		/* Now back off of the IRQ for awhile */
151ef407beeSPaul Mundt 		if (hose->err_irq) {
1529ad62ec4SPaul Mundt 			disable_irq_nosync(hose->err_irq);
153ef407beeSPaul Mundt 			hose->err_timer.expires = jiffies + HZ;
154ef407beeSPaul Mundt 			add_timer(&hose->err_timer);
155ef407beeSPaul Mundt 		}
156ef407beeSPaul Mundt 	}
157ef407beeSPaul Mundt 
158ef407beeSPaul Mundt 	return cmd;
159ef407beeSPaul Mundt }
160