]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/sparc64/kernel/pci_common.c
[SPARC64]: Consolidate PCI mem/io resource determination.
[linux-2.6-omap-h63xx.git] / arch / sparc64 / kernel / pci_common.c
1 /* pci_common.c: PCI controller common support.
2  *
3  * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
4  */
5
6 #include <linux/string.h>
7 #include <linux/slab.h>
8 #include <linux/init.h>
9 #include <linux/pci.h>
10 #include <linux/device.h>
11
12 #include <asm/pbm.h>
13 #include <asm/prom.h>
14 #include <asm/of_device.h>
15
16 #include "pci_impl.h"
17
18 static void pci_register_legacy_regions(struct resource *io_res,
19                                         struct resource *mem_res)
20 {
21         struct resource *p;
22
23         /* VGA Video RAM. */
24         p = kzalloc(sizeof(*p), GFP_KERNEL);
25         if (!p)
26                 return;
27
28         p->name = "Video RAM area";
29         p->start = mem_res->start + 0xa0000UL;
30         p->end = p->start + 0x1ffffUL;
31         p->flags = IORESOURCE_BUSY;
32         request_resource(mem_res, p);
33
34         p = kzalloc(sizeof(*p), GFP_KERNEL);
35         if (!p)
36                 return;
37
38         p->name = "System ROM";
39         p->start = mem_res->start + 0xf0000UL;
40         p->end = p->start + 0xffffUL;
41         p->flags = IORESOURCE_BUSY;
42         request_resource(mem_res, p);
43
44         p = kzalloc(sizeof(*p), GFP_KERNEL);
45         if (!p)
46                 return;
47
48         p->name = "Video ROM";
49         p->start = mem_res->start + 0xc0000UL;
50         p->end = p->start + 0x7fffUL;
51         p->flags = IORESOURCE_BUSY;
52         request_resource(mem_res, p);
53 }
54
55 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
56 {
57         u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
58
59         if (vdma) {
60                 struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
61
62                 if (!rp) {
63                         prom_printf("Cannot allocate IOMMU resource.\n");
64                         prom_halt();
65                 }
66                 rp->name = "IOMMU";
67                 rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
68                 rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
69                 rp->flags = IORESOURCE_BUSY;
70                 request_resource(&pbm->mem_space, rp);
71         }
72 }
73
74 void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
75 {
76         int i, saw_mem, saw_io;
77
78         saw_mem = saw_io = 0;
79         for (i = 0; i < pbm->num_pbm_ranges; i++) {
80                 struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
81                 unsigned long a;
82                 int type;
83
84                 type = (pr->child_phys_hi >> 24) & 0x3;
85                 a = (((unsigned long)pr->parent_phys_hi << 32UL) |
86                      ((unsigned long)pr->parent_phys_lo  <<  0UL));
87
88                 switch (type) {
89                 case 0:
90                         /* PCI config space, 16MB */
91                         pbm->config_space = a;
92                         break;
93
94                 case 1:
95                         /* 16-bit IO space, 16MB */
96                         pbm->io_space.start = a;
97                         pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
98                         pbm->io_space.flags = IORESOURCE_IO;
99                         saw_io = 1;
100                         break;
101
102                 case 2:
103                         /* 32-bit MEM space, 2GB */
104                         pbm->mem_space.start = a;
105                         pbm->mem_space.end = a + (0x80000000UL - 1UL);
106                         pbm->mem_space.flags = IORESOURCE_MEM;
107                         saw_mem = 1;
108                         break;
109
110                 case 3:
111                         /* XXX 64-bit MEM handling XXX */
112
113                 default:
114                         break;
115                 };
116         }
117
118         if (!saw_io || !saw_mem) {
119                 prom_printf("%s: Fatal error, missing %s PBM range.\n",
120                             pbm->name,
121                             (!saw_io ? "IO" : "MEM"));
122                 prom_halt();
123         }
124
125         printk("%s: PCI IO[%lx] MEM[%lx]\n",
126                pbm->name,
127                pbm->io_space.start,
128                pbm->mem_space.start);
129
130         pbm->io_space.name = pbm->mem_space.name = pbm->name;
131
132         request_resource(&ioport_resource, &pbm->io_space);
133         request_resource(&iomem_resource, &pbm->mem_space);
134
135         pci_register_legacy_regions(&pbm->io_space,
136                                     &pbm->mem_space);
137         pci_register_iommu_region(pbm);
138 }
139
140 /* Generic helper routines for PCI error reporting. */
141 void pci_scan_for_target_abort(struct pci_controller_info *p,
142                                struct pci_pbm_info *pbm,
143                                struct pci_bus *pbus)
144 {
145         struct pci_dev *pdev;
146         struct pci_bus *bus;
147
148         list_for_each_entry(pdev, &pbus->devices, bus_list) {
149                 u16 status, error_bits;
150
151                 pci_read_config_word(pdev, PCI_STATUS, &status);
152                 error_bits =
153                         (status & (PCI_STATUS_SIG_TARGET_ABORT |
154                                    PCI_STATUS_REC_TARGET_ABORT));
155                 if (error_bits) {
156                         pci_write_config_word(pdev, PCI_STATUS, error_bits);
157                         printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
158                                p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
159                                pci_name(pdev), status);
160                 }
161         }
162
163         list_for_each_entry(bus, &pbus->children, node)
164                 pci_scan_for_target_abort(p, pbm, bus);
165 }
166
167 void pci_scan_for_master_abort(struct pci_controller_info *p,
168                                struct pci_pbm_info *pbm,
169                                struct pci_bus *pbus)
170 {
171         struct pci_dev *pdev;
172         struct pci_bus *bus;
173
174         list_for_each_entry(pdev, &pbus->devices, bus_list) {
175                 u16 status, error_bits;
176
177                 pci_read_config_word(pdev, PCI_STATUS, &status);
178                 error_bits =
179                         (status & (PCI_STATUS_REC_MASTER_ABORT));
180                 if (error_bits) {
181                         pci_write_config_word(pdev, PCI_STATUS, error_bits);
182                         printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
183                                p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
184                                pci_name(pdev), status);
185                 }
186         }
187
188         list_for_each_entry(bus, &pbus->children, node)
189                 pci_scan_for_master_abort(p, pbm, bus);
190 }
191
192 void pci_scan_for_parity_error(struct pci_controller_info *p,
193                                struct pci_pbm_info *pbm,
194                                struct pci_bus *pbus)
195 {
196         struct pci_dev *pdev;
197         struct pci_bus *bus;
198
199         list_for_each_entry(pdev, &pbus->devices, bus_list) {
200                 u16 status, error_bits;
201
202                 pci_read_config_word(pdev, PCI_STATUS, &status);
203                 error_bits =
204                         (status & (PCI_STATUS_PARITY |
205                                    PCI_STATUS_DETECTED_PARITY));
206                 if (error_bits) {
207                         pci_write_config_word(pdev, PCI_STATUS, error_bits);
208                         printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
209                                p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
210                                pci_name(pdev), status);
211                 }
212         }
213
214         list_for_each_entry(bus, &pbus->children, node)
215                 pci_scan_for_parity_error(p, pbm, bus);
216 }