summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--arch/sh/include/asm/pci.h12
4 files changed, 90 insertions, 26 deletions
diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c
index 25aec005da1..dbf13819987 100644
--- a/arch/sh/drivers/pci/common.c
+++ b/arch/sh/drivers/pci/common.c
@@ -3,29 +3,48 @@
#include <linux/timer.h>
#include <linux/kernel.h>
-static int __init
-early_read_config_word(struct pci_channel *hose,
- int top_bus, int bus, int devfn, int offset, u16 *value)
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
+ int top_bus, int busnr, int devfn)
{
- struct pci_dev fake_dev;
- struct pci_bus fake_bus;
+ static struct pci_dev dev;
+ static struct pci_bus bus;
- fake_dev.bus = &fake_bus;
- fake_dev.sysdata = hose;
- fake_dev.devfn = devfn;
- fake_bus.number = bus;
- fake_bus.sysdata = hose;
- fake_bus.ops = hose->pci_ops;
+ dev.bus = &bus;
+ dev.sysdata = hose;
+ dev.devfn = devfn;
+ bus.number = busnr;
+ bus.sysdata = hose;
+ bus.ops = hose->pci_ops;
- if (bus != top_bus)
+ if(busnr != top_bus)
/* Fake a parent bus structure. */
- fake_bus.parent = &fake_bus;
+ bus.parent = &bus;
else
- fake_bus.parent = NULL;
+ bus.parent = NULL;
- return pci_read_config_word(&fake_dev, offset, value);
+ return &dev;
}
+#define EARLY_PCI_OP(rw, size, type) \
+int __init early_##rw##_config_##size(struct pci_channel *hose, \
+ int top_bus, int bus, int devfn, int offset, type value) \
+{ \
+ return pci_##rw##_config_##size( \
+ fake_pci_dev(hose, top_bus, bus, devfn), \
+ offset, value); \
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
int __init pci_is_66mhz_capable(struct pci_channel *hose,
int top_bus, int current_bus)
{
@@ -133,7 +152,7 @@ unsigned int pcibios_handle_status_errors(unsigned long addr,
/* Now back off of the IRQ for awhile */
if (hose->err_irq) {
- disable_irq(hose->err_irq);
+ disable_irq_nosync(hose->err_irq);
hose->err_timer.expires = jiffies + HZ;
add_timer(&hose->err_timer);
}
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index 472f67aec33..1e147f445c1 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)
__raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM);
/* Back off the IRQ for awhile */
- disable_irq(irq);
+ disable_irq_nosync(irq);
hose->serr_timer.expires = jiffies + HZ;
add_timer(&hose->serr_timer);
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index f4a69833fce..41d8f014f1d 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,
}
void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
+ struct resource *res)
{
struct pci_channel *hose = dev->sysdata;
unsigned long offset = 0;
@@ -218,9 +218,8 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
region->end = res->end - offset;
}
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
{
struct pci_channel *hose = dev->sysdata;
unsigned long offset = 0;
@@ -303,12 +302,41 @@ char * __devinit pcibios_setup(char *str)
return str;
}
+static void __init
+pcibios_bus_report_status_early(struct pci_channel *hose,
+ int top_bus, int current_bus,
+ unsigned int status_mask, int warn)
+{
+ unsigned int pci_devfn;
+ u16 status;
+ int ret;
+
+ for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+ if (PCI_FUNC(pci_devfn))
+ continue;
+ ret = early_read_config_word(hose, top_bus, current_bus,
+ pci_devfn, PCI_STATUS, &status);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ continue;
+ if (status == 0xffff)
+ continue;
+
+ early_write_config_word(hose, top_bus, current_bus,
+ pci_devfn, PCI_STATUS,
+ status & status_mask);
+ if (warn)
+ printk("(%02x:%02x: %04X) ", current_bus,
+ pci_devfn, status);
+ }
+}
+
/*
* We can't use pci_find_device() here since we are
* called from interrupt context.
*/
-static void pcibios_bus_report_status(struct pci_bus *bus,
- unsigned int status_mask, int warn)
+static void __init_refok
+pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
+ int warn)
{
struct pci_dev *dev;
@@ -341,12 +369,17 @@ static void pcibios_bus_report_status(struct pci_bus *bus,
pcibios_bus_report_status(dev->subordinate, status_mask, warn);
}
-void pcibios_report_status(unsigned int status_mask, int warn)
+void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
{
struct pci_channel *hose;
- for (hose = hose_head; hose; hose = hose->next)
- pcibios_bus_report_status(hose->bus, status_mask, warn);
+ for (hose = hose_head; hose; hose = hose->next) {
+ if (unlikely(!hose->bus))
+ pcibios_bus_report_status_early(hose, hose_head->index,
+ hose->index, status_mask, warn);
+ else
+ pcibios_bus_report_status(hose->bus, status_mask, warn);
+ }
}
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 6d762cca231..1042f7f0a48 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -41,6 +41,18 @@ extern int register_pci_controller(struct pci_channel *hose);
extern void pcibios_report_status(unsigned int status_mask, int warn);
/* arch/sh/drivers/pci/common.c */
+extern int early_read_config_byte(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u8 *value);
+extern int early_read_config_word(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u16 *value);
+extern int early_read_config_dword(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u32 *value);
+extern int early_write_config_byte(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u8 value);
+extern int early_write_config_word(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u16 value);
+extern int early_write_config_dword(struct pci_channel *hose, int top_bus,
+ int bus, int devfn, int offset, u32 value);
extern void pcibios_enable_timers(struct pci_channel *hose);
extern unsigned int pcibios_handle_status_errors(unsigned long addr,
unsigned int status, struct pci_channel *hose);