diff options
Diffstat (limited to 'arch/sh/drivers/pci/pci.c')
-rw-r--r-- | arch/sh/drivers/pci/pci.c | 167 |
1 files changed, 135 insertions, 32 deletions
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 96213fd172ce..953af139e230 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c | |||
@@ -33,15 +33,22 @@ static int pci_initialized; | |||
33 | static void __devinit pcibios_scanbus(struct pci_channel *hose) | 33 | static void __devinit pcibios_scanbus(struct pci_channel *hose) |
34 | { | 34 | { |
35 | static int next_busno; | 35 | static int next_busno; |
36 | static int need_domain_info; | ||
36 | struct pci_bus *bus; | 37 | struct pci_bus *bus; |
37 | 38 | ||
38 | bus = pci_scan_bus(next_busno, hose->pci_ops, hose); | 39 | bus = pci_scan_bus(next_busno, hose->pci_ops, hose); |
40 | hose->bus = bus; | ||
41 | |||
42 | need_domain_info = need_domain_info || hose->index; | ||
43 | hose->need_domain_info = need_domain_info; | ||
39 | if (bus) { | 44 | if (bus) { |
40 | next_busno = bus->subordinate + 1; | 45 | next_busno = bus->subordinate + 1; |
41 | /* Don't allow 8-bit bus number overflow inside the hose - | 46 | /* Don't allow 8-bit bus number overflow inside the hose - |
42 | reserve some space for bridges. */ | 47 | reserve some space for bridges. */ |
43 | if (next_busno > 224) | 48 | if (next_busno > 224) { |
44 | next_busno = 0; | 49 | next_busno = 0; |
50 | need_domain_info = 1; | ||
51 | } | ||
45 | 52 | ||
46 | pci_bus_size_bridges(bus); | 53 | pci_bus_size_bridges(bus); |
47 | pci_bus_assign_resources(bus); | 54 | pci_bus_assign_resources(bus); |
@@ -51,10 +58,21 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose) | |||
51 | 58 | ||
52 | static DEFINE_MUTEX(pci_scan_mutex); | 59 | static DEFINE_MUTEX(pci_scan_mutex); |
53 | 60 | ||
54 | void __devinit register_pci_controller(struct pci_channel *hose) | 61 | int __devinit register_pci_controller(struct pci_channel *hose) |
55 | { | 62 | { |
56 | request_resource(&iomem_resource, hose->mem_resource); | 63 | int i; |
57 | request_resource(&ioport_resource, hose->io_resource); | 64 | |
65 | for (i = 0; i < hose->nr_resources; i++) { | ||
66 | struct resource *res = hose->resources + i; | ||
67 | |||
68 | if (res->flags & IORESOURCE_IO) { | ||
69 | if (request_resource(&ioport_resource, res) < 0) | ||
70 | goto out; | ||
71 | } else { | ||
72 | if (request_resource(&iomem_resource, res) < 0) | ||
73 | goto out; | ||
74 | } | ||
75 | } | ||
58 | 76 | ||
59 | *hose_tail = hose; | 77 | *hose_tail = hose; |
60 | hose_tail = &hose->next; | 78 | hose_tail = &hose->next; |
@@ -68,6 +86,11 @@ void __devinit register_pci_controller(struct pci_channel *hose) | |||
68 | } | 86 | } |
69 | 87 | ||
70 | /* | 88 | /* |
89 | * Setup the ERR/PERR and SERR timers, if available. | ||
90 | */ | ||
91 | pcibios_enable_timers(hose); | ||
92 | |||
93 | /* | ||
71 | * Scan the bus if it is register after the PCI subsystem | 94 | * Scan the bus if it is register after the PCI subsystem |
72 | * initialization. | 95 | * initialization. |
73 | */ | 96 | */ |
@@ -76,6 +99,15 @@ void __devinit register_pci_controller(struct pci_channel *hose) | |||
76 | pcibios_scanbus(hose); | 99 | pcibios_scanbus(hose); |
77 | mutex_unlock(&pci_scan_mutex); | 100 | mutex_unlock(&pci_scan_mutex); |
78 | } | 101 | } |
102 | |||
103 | return 0; | ||
104 | |||
105 | out: | ||
106 | for (--i; i >= 0; i--) | ||
107 | release_resource(&hose->resources[i]); | ||
108 | |||
109 | printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); | ||
110 | return -1; | ||
79 | } | 111 | } |
80 | 112 | ||
81 | static int __init pcibios_init(void) | 113 | static int __init pcibios_init(void) |
@@ -127,11 +159,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) | |||
127 | { | 159 | { |
128 | struct pci_dev *dev = bus->self; | 160 | struct pci_dev *dev = bus->self; |
129 | struct list_head *ln; | 161 | struct list_head *ln; |
130 | struct pci_channel *chan = bus->sysdata; | 162 | struct pci_channel *hose = bus->sysdata; |
131 | 163 | ||
132 | if (!dev) { | 164 | if (!dev) { |
133 | bus->resource[0] = chan->io_resource; | 165 | int i; |
134 | bus->resource[1] = chan->mem_resource; | 166 | |
167 | for (i = 0; i < hose->nr_resources; i++) | ||
168 | bus->resource[i] = hose->resources + i; | ||
135 | } | 169 | } |
136 | 170 | ||
137 | for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { | 171 | for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { |
@@ -152,30 +186,25 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, | |||
152 | resource_size_t size, resource_size_t align) | 186 | resource_size_t size, resource_size_t align) |
153 | { | 187 | { |
154 | struct pci_dev *dev = data; | 188 | struct pci_dev *dev = data; |
155 | struct pci_channel *chan = dev->sysdata; | 189 | struct pci_channel *hose = dev->sysdata; |
156 | resource_size_t start = res->start; | 190 | resource_size_t start = res->start; |
157 | 191 | ||
158 | if (res->flags & IORESOURCE_IO) { | 192 | if (res->flags & IORESOURCE_IO) { |
159 | if (start < PCIBIOS_MIN_IO + chan->io_resource->start) | 193 | if (start < PCIBIOS_MIN_IO + hose->resources[0].start) |
160 | start = PCIBIOS_MIN_IO + chan->io_resource->start; | 194 | start = PCIBIOS_MIN_IO + hose->resources[0].start; |
161 | 195 | ||
162 | /* | 196 | /* |
163 | * Put everything into 0x00-0xff region modulo 0x400. | 197 | * Put everything into 0x00-0xff region modulo 0x400. |
164 | */ | 198 | */ |
165 | if (start & 0x300) { | 199 | if (start & 0x300) |
166 | start = (start + 0x3ff) & ~0x3ff; | 200 | start = (start + 0x3ff) & ~0x3ff; |
167 | res->start = start; | ||
168 | } | ||
169 | } else if (res->flags & IORESOURCE_MEM) { | ||
170 | if (start < PCIBIOS_MIN_MEM + chan->mem_resource->start) | ||
171 | start = PCIBIOS_MIN_MEM + chan->mem_resource->start; | ||
172 | } | 201 | } |
173 | 202 | ||
174 | return start; | 203 | return start; |
175 | } | 204 | } |
176 | 205 | ||
177 | 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, |
178 | struct resource *res) | 207 | struct resource *res) |
179 | { | 208 | { |
180 | struct pci_channel *hose = dev->sysdata; | 209 | struct pci_channel *hose = dev->sysdata; |
181 | unsigned long offset = 0; | 210 | unsigned long offset = 0; |
@@ -189,9 +218,8 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, | |||
189 | region->end = res->end - offset; | 218 | region->end = res->end - offset; |
190 | } | 219 | } |
191 | 220 | ||
192 | void __devinit | 221 | void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, |
193 | pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, | 222 | struct pci_bus_region *region) |
194 | struct pci_bus_region *region) | ||
195 | { | 223 | { |
196 | struct pci_channel *hose = dev->sysdata; | 224 | struct pci_channel *hose = dev->sysdata; |
197 | unsigned long offset = 0; | 225 | unsigned long offset = 0; |
@@ -274,6 +302,86 @@ char * __devinit pcibios_setup(char *str) | |||
274 | return str; | 302 | return str; |
275 | } | 303 | } |
276 | 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 | |||
333 | /* | ||
334 | * We can't use pci_find_device() here since we are | ||
335 | * called from interrupt context. | ||
336 | */ | ||
337 | static void __init_refok | ||
338 | pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask, | ||
339 | int warn) | ||
340 | { | ||
341 | struct pci_dev *dev; | ||
342 | |||
343 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
344 | u16 status; | ||
345 | |||
346 | /* | ||
347 | * ignore host bridge - we handle | ||
348 | * that separately | ||
349 | */ | ||
350 | if (dev->bus->number == 0 && dev->devfn == 0) | ||
351 | continue; | ||
352 | |||
353 | pci_read_config_word(dev, PCI_STATUS, &status); | ||
354 | if (status == 0xffff) | ||
355 | continue; | ||
356 | |||
357 | if ((status & status_mask) == 0) | ||
358 | continue; | ||
359 | |||
360 | /* clear the status errors */ | ||
361 | pci_write_config_word(dev, PCI_STATUS, status & status_mask); | ||
362 | |||
363 | if (warn) | ||
364 | printk("(%s: %04X) ", pci_name(dev), status); | ||
365 | } | ||
366 | |||
367 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
368 | if (dev->subordinate) | ||
369 | pcibios_bus_report_status(dev->subordinate, status_mask, warn); | ||
370 | } | ||
371 | |||
372 | void __init_refok pcibios_report_status(unsigned int status_mask, int warn) | ||
373 | { | ||
374 | struct pci_channel *hose; | ||
375 | |||
376 | for (hose = hose_head; hose; hose = hose->next) { | ||
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 | } | ||
383 | } | ||
384 | |||
277 | 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, |
278 | enum pci_mmap_state mmap_state, int write_combine) | 386 | enum pci_mmap_state mmap_state, int write_combine) |
279 | { | 387 | { |
@@ -302,9 +410,15 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev, | |||
302 | { | 410 | { |
303 | struct pci_channel *chan = dev->sysdata; | 411 | struct pci_channel *chan = dev->sysdata; |
304 | 412 | ||
305 | if (!chan->io_map_base) | 413 | if (unlikely(!chan->io_map_base)) { |
306 | chan->io_map_base = generic_io_base; | 414 | chan->io_map_base = generic_io_base; |
307 | 415 | ||
416 | if (pci_domains_supported) | ||
417 | panic("To avoid data corruption io_map_base MUST be " | ||
418 | "set with multiple PCI domains."); | ||
419 | } | ||
420 | |||
421 | |||
308 | return (void __iomem *)(chan->io_map_base + port); | 422 | return (void __iomem *)(chan->io_map_base + port); |
309 | } | 423 | } |
310 | 424 | ||
@@ -321,20 +435,9 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | |||
321 | 435 | ||
322 | if (flags & IORESOURCE_IO) | 436 | if (flags & IORESOURCE_IO) |
323 | return ioport_map_pci(dev, start, len); | 437 | return ioport_map_pci(dev, start, len); |
324 | |||
325 | /* | ||
326 | * Presently the IORESOURCE_MEM case is a bit special, most | ||
327 | * SH7751 style PCI controllers have PCI memory at a fixed | ||
328 | * location in the address space where no remapping is desired. | ||
329 | * With the IORESOURCE_MEM case more care has to be taken | ||
330 | * to inhibit page table mapping for legacy cores, but this is | ||
331 | * punted off to __ioremap(). | ||
332 | * -- PFM. | ||
333 | */ | ||
334 | if (flags & IORESOURCE_MEM) { | 438 | if (flags & IORESOURCE_MEM) { |
335 | if (flags & IORESOURCE_CACHEABLE) | 439 | if (flags & IORESOURCE_CACHEABLE) |
336 | return ioremap(start, len); | 440 | return ioremap(start, len); |
337 | |||
338 | return ioremap_nocache(start, len); | 441 | return ioremap_nocache(start, len); |
339 | } | 442 | } |
340 | 443 | ||