diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-02-01 02:39:46 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-02-01 02:39:46 -0500 |
commit | ef407beefbd9928792ccc93857e408e0057bc17b (patch) | |
tree | f98fc1e6eaa7d00b578d759f612d815cd7a7391a /arch/sh/drivers/pci/common.c | |
parent | bcf39352eb9e9026f7a1028d4bce3707b65f104b (diff) |
sh: Hook up ERR/PERR/SERR detection for SH7780 PCI host controllers.
These were never handled before, so implement some common infrastructure
to support them, then make use of that in the SH7780-specific code. In
practice there is little here that can not be generalized for SH4 parts,
which will be an incremental change as the 7780/7751 code is gradually
unified.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers/pci/common.c')
-rw-r--r-- | arch/sh/drivers/pci/common.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c index f67c946a8612..25aec005da18 100644 --- a/arch/sh/drivers/pci/common.c +++ b/arch/sh/drivers/pci/common.c | |||
@@ -1,4 +1,6 @@ | |||
1 | #include <linux/pci.h> | 1 | #include <linux/pci.h> |
2 | #include <linux/interrupt.h> | ||
3 | #include <linux/timer.h> | ||
2 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
3 | 5 | ||
4 | static int __init | 6 | static int __init |
@@ -62,3 +64,80 @@ int __init pci_is_66mhz_capable(struct pci_channel *hose, | |||
62 | 64 | ||
63 | return cap66 > 0; | 65 | return cap66 > 0; |
64 | } | 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 | } | ||