diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/drivers/pci/common.c | 51 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 2 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci.c | 51 | ||||
-rw-r--r-- | arch/sh/include/asm/pci.h | 12 |
4 files changed, 90 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 | ||
6 | static int __init | 6 | /* |
7 | early_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 | */ | ||
10 | static 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) \ | ||
33 | int __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 | |||
41 | EARLY_PCI_OP(read, byte, u8 *) | ||
42 | EARLY_PCI_OP(read, word, u16 *) | ||
43 | EARLY_PCI_OP(read, dword, u32 *) | ||
44 | EARLY_PCI_OP(write, byte, u8) | ||
45 | EARLY_PCI_OP(write, word, u16) | ||
46 | EARLY_PCI_OP(write, dword, u32) | ||
47 | |||
29 | int __init pci_is_66mhz_capable(struct pci_channel *hose, | 48 | int __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 | ||
206 | void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, | 206 | void 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 | ||
221 | void __devinit | 221 | void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, |
222 | pcibios_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 | ||
305 | static void __init | ||
306 | pcibios_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 | */ |
310 | static void pcibios_bus_report_status(struct pci_bus *bus, | 337 | static void __init_refok |
311 | unsigned int status_mask, int warn) | 338 | pcibios_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 | ||
344 | void pcibios_report_status(unsigned int status_mask, int warn) | 372 | void __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 | ||
352 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | 385 | 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 6d762cca2312..1042f7f0a48b 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); | |||
41 | extern void pcibios_report_status(unsigned int status_mask, int warn); | 41 | extern void pcibios_report_status(unsigned int status_mask, int warn); |
42 | 42 | ||
43 | /* arch/sh/drivers/pci/common.c */ | 43 | /* arch/sh/drivers/pci/common.c */ |
44 | extern int early_read_config_byte(struct pci_channel *hose, int top_bus, | ||
45 | int bus, int devfn, int offset, u8 *value); | ||
46 | extern int early_read_config_word(struct pci_channel *hose, int top_bus, | ||
47 | int bus, int devfn, int offset, u16 *value); | ||
48 | extern int early_read_config_dword(struct pci_channel *hose, int top_bus, | ||
49 | int bus, int devfn, int offset, u32 *value); | ||
50 | extern int early_write_config_byte(struct pci_channel *hose, int top_bus, | ||
51 | int bus, int devfn, int offset, u8 value); | ||
52 | extern int early_write_config_word(struct pci_channel *hose, int top_bus, | ||
53 | int bus, int devfn, int offset, u16 value); | ||
54 | extern int early_write_config_dword(struct pci_channel *hose, int top_bus, | ||
55 | int bus, int devfn, int offset, u32 value); | ||
44 | extern void pcibios_enable_timers(struct pci_channel *hose); | 56 | extern void pcibios_enable_timers(struct pci_channel *hose); |
45 | extern unsigned int pcibios_handle_status_errors(unsigned long addr, | 57 | extern unsigned int pcibios_handle_status_errors(unsigned long addr, |
46 | unsigned int status, struct pci_channel *hose); | 58 | unsigned int status, struct pci_channel *hose); |