aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/ops-tx3927.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/ops-tx3927.c')
-rw-r--r--arch/mips/pci/ops-tx3927.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c
index 8a17a39e5bf2..31c150196595 100644
--- a/arch/mips/pci/ops-tx3927.c
+++ b/arch/mips/pci/ops-tx3927.c
@@ -37,45 +37,48 @@
37#include <linux/pci.h> 37#include <linux/pci.h>
38#include <linux/kernel.h> 38#include <linux/kernel.h>
39#include <linux/init.h> 39#include <linux/init.h>
40#include <linux/interrupt.h>
40 41
41#include <asm/addrspace.h> 42#include <asm/addrspace.h>
43#include <asm/txx9irq.h>
44#include <asm/txx9/pci.h>
42#include <asm/txx9/tx3927.h> 45#include <asm/txx9/tx3927.h>
43 46
44static inline int mkaddr(unsigned char bus, unsigned char dev_fn, 47static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where)
45 unsigned char where)
46{ 48{
47 if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0)) 49 if (bus->parent == NULL &&
48 return PCIBIOS_DEVICE_NOT_FOUND; 50 devfn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
49 51 return -1;
50 tx3927_pcicptr->ica = ((bus & 0xff) << 0x10) | 52 tx3927_pcicptr->ica =
51 ((dev_fn & 0xff) << 0x08) | 53 ((bus->number & 0xff) << 0x10) |
52 (where & 0xfc); 54 ((devfn & 0xff) << 0x08) |
55 (where & 0xfc) | (bus->parent ? 1 : 0);
53 56
54 /* clear M_ABORT and Disable M_ABORT Int. */ 57 /* clear M_ABORT and Disable M_ABORT Int. */
55 tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; 58 tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
56 tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT; 59 tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT;
57 60 return 0;
58 return PCIBIOS_SUCCESSFUL;
59} 61}
60 62
61static inline int check_abort(void) 63static inline int check_abort(void)
62{ 64{
63 if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) 65 if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) {
64 tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; 66 tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
65 tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; 67 tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
68 /* flush write buffer */
69 iob();
66 return PCIBIOS_DEVICE_NOT_FOUND; 70 return PCIBIOS_DEVICE_NOT_FOUND;
67 71 }
68 return PCIBIOS_SUCCESSFUL; 72 return PCIBIOS_SUCCESSFUL;
69} 73}
70 74
71static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, 75static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
72 int where, int size, u32 * val) 76 int where, int size, u32 * val)
73{ 77{
74 int ret; 78 if (mkaddr(bus, devfn, where)) {
75 79 *val = 0xffffffff;
76 ret = mkaddr(bus->number, devfn, where); 80 return PCIBIOS_DEVICE_NOT_FOUND;
77 if (ret) 81 }
78 return ret;
79 82
80 switch (size) { 83 switch (size) {
81 case 1: 84 case 1:
@@ -97,11 +100,8 @@ static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
97static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, 100static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
98 int where, int size, u32 val) 101 int where, int size, u32 val)
99{ 102{
100 int ret; 103 if (mkaddr(bus, devfn, where))
101 104 return PCIBIOS_DEVICE_NOT_FOUND;
102 ret = mkaddr(bus->number, devfn, where);
103 if (ret)
104 return ret;
105 105
106 switch (size) { 106 switch (size) {
107 case 1: 107 case 1:
@@ -117,11 +117,6 @@ static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
117 tx3927_pcicptr->icd = cpu_to_le32(val); 117 tx3927_pcicptr->icd = cpu_to_le32(val);
118 } 118 }
119 119
120 if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT)
121 tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
122 tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
123 return PCIBIOS_DEVICE_NOT_FOUND;
124
125 return check_abort(); 120 return check_abort();
126} 121}
127 122
@@ -202,3 +197,34 @@ void __init tx3927_pcic_setup(struct pci_controller *channel,
202 PCI_COMMAND_PARITY | PCI_COMMAND_SERR; 197 PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
203 local_irq_restore(flags); 198 local_irq_restore(flags);
204} 199}
200
201static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id)
202{
203 struct pt_regs *regs = get_irq_regs();
204
205 if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
206 printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n",
207 regs->cp0_epc);
208 printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
209 tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat);
210 }
211 if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
212 /* clear all pci errors */
213 tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL;
214 tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL;
215 tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL;
216 tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
217 return IRQ_HANDLED;
218 }
219 console_verbose();
220 panic("PCI error.");
221}
222
223void __init tx3927_setup_pcierr_irq(void)
224{
225 if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
226 tx3927_pcierr_interrupt,
227 IRQF_DISABLED, "PCI error",
228 (void *)TX3927_PCIC_REG))
229 printk(KERN_WARNING "Failed to request irq for PCIERR\n");
230}