diff options
Diffstat (limited to 'arch/mips/pci/ops-tx3927.c')
-rw-r--r-- | arch/mips/pci/ops-tx3927.c | 80 |
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 | ||
44 | static inline int mkaddr(unsigned char bus, unsigned char dev_fn, | 47 | static 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 | ||
61 | static inline int check_abort(void) | 63 | static 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 | ||
71 | static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, | 75 | static 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, | |||
97 | static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, | 100 | static 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 | |||
201 | static 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 | |||
223 | void __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 | } | ||