aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-02-03 02:46:20 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-02-03 02:46:20 -0500
commit9ad62ec4f752c82b39aa5927f23d894b46ae10b9 (patch)
tree546f4572329478e849408fe129e44625881f9992 /arch/sh/drivers
parent37feecb0ae8c29b713b957c053b05ad10c42c73b (diff)
sh: Fix up early PCI PERR/SERR IRQ handling.
This adds support for handling early PERR/SERR triggering in between controller registration and the initial bus scan. Buggy cards end up asserting these as soon as the M66EN scan is undertaken, resulting in an early crash. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers')
-rw-r--r--arch/sh/drivers/pci/common.c51
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c2
-rw-r--r--arch/sh/drivers/pci/pci.c51
3 files changed, 78 insertions, 26 deletions
diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c
index 25aec005da18..dbf138199871 100644
--- a/arch/sh/drivers/pci/common.c
+++ b/arch/sh/drivers/pci/common.c
@@ -3,29 +3,48 @@
3#include <linux/timer.h> 3#include <linux/timer.h>
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5 5
6static int __init 6/*
7early_read_config_word(struct pci_channel *hose, 7 * These functions are used early on before PCI scanning is done
8 int top_bus, int bus, int devfn, int offset, u16 *value) 8 * and all of the pci_dev and pci_bus structures have been created.
9 */
10static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
11 int top_bus, int busnr, int devfn)
9{ 12{
10 struct pci_dev fake_dev; 13 static struct pci_dev dev;
11 struct pci_bus fake_bus; 14 static struct pci_bus bus;
12 15
13 fake_dev.bus = &fake_bus; 16 dev.bus = &bus;
14 fake_dev.sysdata = hose; 17 dev.sysdata = hose;
15 fake_dev.devfn = devfn; 18 dev.devfn = devfn;
16 fake_bus.number = bus; 19 bus.number = busnr;
17 fake_bus.sysdata = hose; 20 bus.sysdata = hose;
18 fake_bus.ops = hose->pci_ops; 21 bus.ops = hose->pci_ops;
19 22
20 if (bus != top_bus) 23 if(busnr != top_bus)
21 /* Fake a parent bus structure. */ 24 /* Fake a parent bus structure. */
22 fake_bus.parent = &fake_bus; 25 bus.parent = &bus;
23 else 26 else
24 fake_bus.parent = NULL; 27 bus.parent = NULL;
25 28
26 return pci_read_config_word(&fake_dev, offset, value); 29 return &dev;
27} 30}
28 31
32#define EARLY_PCI_OP(rw, size, type) \
33int __init early_##rw##_config_##size(struct pci_channel *hose, \
34 int top_bus, int bus, int devfn, int offset, type value) \
35{ \
36 return pci_##rw##_config_##size( \
37 fake_pci_dev(hose, top_bus, bus, devfn), \
38 offset, value); \
39}
40
41EARLY_PCI_OP(read, byte, u8 *)
42EARLY_PCI_OP(read, word, u16 *)
43EARLY_PCI_OP(read, dword, u32 *)
44EARLY_PCI_OP(write, byte, u8)
45EARLY_PCI_OP(write, word, u16)
46EARLY_PCI_OP(write, dword, u32)
47
29int __init pci_is_66mhz_capable(struct pci_channel *hose, 48int __init pci_is_66mhz_capable(struct pci_channel *hose,
30 int top_bus, int current_bus) 49 int top_bus, int current_bus)
31{ 50{
@@ -133,7 +152,7 @@ unsigned int pcibios_handle_status_errors(unsigned long addr,
133 152
134 /* Now back off of the IRQ for awhile */ 153 /* Now back off of the IRQ for awhile */
135 if (hose->err_irq) { 154 if (hose->err_irq) {
136 disable_irq(hose->err_irq); 155 disable_irq_nosync(hose->err_irq);
137 hose->err_timer.expires = jiffies + HZ; 156 hose->err_timer.expires = jiffies + HZ;
138 add_timer(&hose->err_timer); 157 add_timer(&hose->err_timer);
139 } 158 }
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index 472f67aec337..1e147f445c1a 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -150,7 +150,7 @@ static irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id)
150 __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); 150 __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM);
151 151
152 /* Back off the IRQ for awhile */ 152 /* Back off the IRQ for awhile */
153 disable_irq(irq); 153 disable_irq_nosync(irq);
154 hose->serr_timer.expires = jiffies + HZ; 154 hose->serr_timer.expires = jiffies + HZ;
155 add_timer(&hose->serr_timer); 155 add_timer(&hose->serr_timer);
156 156
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index f4a69833fce2..41d8f014f1df 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -204,7 +204,7 @@ void pcibios_align_resource(void *data, struct resource *res,
204} 204}
205 205
206void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, 206void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
207 struct resource *res) 207 struct resource *res)
208{ 208{
209 struct pci_channel *hose = dev->sysdata; 209 struct pci_channel *hose = dev->sysdata;
210 unsigned long offset = 0; 210 unsigned long offset = 0;
@@ -218,9 +218,8 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
218 region->end = res->end - offset; 218 region->end = res->end - offset;
219} 219}
220 220
221void __devinit 221void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
222pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, 222 struct pci_bus_region *region)
223 struct pci_bus_region *region)
224{ 223{
225 struct pci_channel *hose = dev->sysdata; 224 struct pci_channel *hose = dev->sysdata;
226 unsigned long offset = 0; 225 unsigned long offset = 0;
@@ -303,12 +302,41 @@ char * __devinit pcibios_setup(char *str)
303 return str; 302 return str;
304} 303}
305 304
305static void __init
306pcibios_bus_report_status_early(struct pci_channel *hose,
307 int top_bus, int current_bus,
308 unsigned int status_mask, int warn)
309{
310 unsigned int pci_devfn;
311 u16 status;
312 int ret;
313
314 for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
315 if (PCI_FUNC(pci_devfn))
316 continue;
317 ret = early_read_config_word(hose, top_bus, current_bus,
318 pci_devfn, PCI_STATUS, &status);
319 if (ret != PCIBIOS_SUCCESSFUL)
320 continue;
321 if (status == 0xffff)
322 continue;
323
324 early_write_config_word(hose, top_bus, current_bus,
325 pci_devfn, PCI_STATUS,
326 status & status_mask);
327 if (warn)
328 printk("(%02x:%02x: %04X) ", current_bus,
329 pci_devfn, status);
330 }
331}
332
306/* 333/*
307 * We can't use pci_find_device() here since we are 334 * We can't use pci_find_device() here since we are
308 * called from interrupt context. 335 * called from interrupt context.
309 */ 336 */
310static void pcibios_bus_report_status(struct pci_bus *bus, 337static void __init_refok
311 unsigned int status_mask, int warn) 338pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
339 int warn)
312{ 340{
313 struct pci_dev *dev; 341 struct pci_dev *dev;
314 342
@@ -341,12 +369,17 @@ static void pcibios_bus_report_status(struct pci_bus *bus,
341 pcibios_bus_report_status(dev->subordinate, status_mask, warn); 369 pcibios_bus_report_status(dev->subordinate, status_mask, warn);
342} 370}
343 371
344void pcibios_report_status(unsigned int status_mask, int warn) 372void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
345{ 373{
346 struct pci_channel *hose; 374 struct pci_channel *hose;
347 375
348 for (hose = hose_head; hose; hose = hose->next) 376 for (hose = hose_head; hose; hose = hose->next) {
349 pcibios_bus_report_status(hose->bus, status_mask, warn); 377 if (unlikely(!hose->bus))
378 pcibios_bus_report_status_early(hose, hose_head->index,
379 hose->index, status_mask, warn);
380 else
381 pcibios_bus_report_status(hose->bus, status_mask, warn);
382 }
350} 383}
351 384
352int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, 385int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,