| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: pci_addr_fixup.c,v 1.7 2011/08/28 05:32:41 dyoung Exp $ */ | | 1 | /* $NetBSD: pci_addr_fixup.c,v 1.8 2011/08/28 06:08:15 dyoung Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2000 UCHIYAMA Yasushi. All rights reserved. | | 4 | * Copyright (c) 2000 UCHIYAMA Yasushi. All rights reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. The name of the author may not be used to endorse or promote products | | 14 | * 3. The name of the author may not be used to endorse or promote products |
| @@ -17,27 +17,27 @@ | | | @@ -17,27 +17,27 @@ |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | | 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: pci_addr_fixup.c,v 1.7 2011/08/28 05:32:41 dyoung Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: pci_addr_fixup.c,v 1.8 2011/08/28 06:08:15 dyoung Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/systm.h> | | 33 | #include <sys/systm.h> |
34 | #include <sys/malloc.h> | | 34 | #include <sys/malloc.h> |
35 | #include <sys/kernel.h> | | 35 | #include <sys/kernel.h> |
36 | #include <sys/device.h> | | 36 | #include <sys/device.h> |
37 | #include <sys/extent.h> | | 37 | #include <sys/extent.h> |
38 | | | 38 | |
39 | #include <sys/bus.h> | | 39 | #include <sys/bus.h> |
40 | | | 40 | |
41 | #include <dev/pci/pcireg.h> | | 41 | #include <dev/pci/pcireg.h> |
42 | #include <dev/pci/pcivar.h> | | 42 | #include <dev/pci/pcivar.h> |
43 | #include <dev/pci/pcidevs.h> | | 43 | #include <dev/pci/pcidevs.h> |
| @@ -57,117 +57,117 @@ static int device_is_agp(pci_chipset_tag | | | @@ -57,117 +57,117 @@ static int device_is_agp(pci_chipset_tag |
57 | #define PCIADDR_MEM_START 0x0 | | 57 | #define PCIADDR_MEM_START 0x0 |
58 | #define PCIADDR_MEM_END 0xffffffff | | 58 | #define PCIADDR_MEM_END 0xffffffff |
59 | #define PCIADDR_PORT_START 0x0 | | 59 | #define PCIADDR_PORT_START 0x0 |
60 | #define PCIADDR_PORT_END 0xffff | | 60 | #define PCIADDR_PORT_END 0xffff |
61 | | | 61 | |
62 | /* for ISA devices */ | | 62 | /* for ISA devices */ |
63 | #define PCIADDR_ISAPORT_RESERVE 0x5800 /* empirical value */ | | 63 | #define PCIADDR_ISAPORT_RESERVE 0x5800 /* empirical value */ |
64 | #define PCIADDR_ISAMEM_RESERVE (16 * 1024 * 1024) | | 64 | #define PCIADDR_ISAMEM_RESERVE (16 * 1024 * 1024) |
65 | | | 65 | |
66 | void | | 66 | void |
67 | pci_addr_fixup(pci_chipset_tag_t pc, int maxbus) | | 67 | pci_addr_fixup(pci_chipset_tag_t pc, int maxbus) |
68 | { | | 68 | { |
69 | extern paddr_t avail_end; | | 69 | extern paddr_t avail_end; |
70 | const char *verbose_header = | | 70 | const char *verbose_header = |
71 | "[%s]-----------------------\n" | | 71 | "[%s]-----------------------\n" |
72 | " device vendor product\n" | | 72 | " device vendor product\n" |
73 | " register space address size\n" | | 73 | " register space address size\n" |
74 | "--------------------------------------------\n"; | | 74 | "--------------------------------------------\n"; |
75 | const char *verbose_footer = | | 75 | const char *verbose_footer = |
76 | "--------------------------[%3d devices bogus]\n"; | | 76 | "--------------------------[%3d devices bogus]\n"; |
77 | const struct { | | 77 | const struct { |
78 | bus_addr_t start; | | 78 | bus_addr_t start; |
79 | bus_size_t size; | | 79 | bus_size_t size; |
80 | const char *name; | | 80 | const char *name; |
81 | } system_reserve [] = { | | 81 | } system_reserve [] = { |
82 | { 0xfec00000, 0x100000, "I/O APIC" }, | | 82 | { 0xfec00000, 0x100000, "I/O APIC" }, |
83 | { 0xfee00000, 0x100000, "Local APIC" }, | | 83 | { 0xfee00000, 0x100000, "Local APIC" }, |
84 | { 0xfffe0000, 0x20000, "BIOS PROM" }, | | 84 | { 0xfffe0000, 0x20000, "BIOS PROM" }, |
85 | { 0, 0, 0 }, /* terminator */ | | 85 | { 0, 0, 0 }, /* terminator */ |
86 | }, *srp; | | 86 | }, *srp; |
87 | paddr_t start; | | 87 | paddr_t start; |
88 | int error; | | 88 | int error; |
89 | | | 89 | |
90 | pciaddr.extent_mem = extent_create("PCI I/O memory space", | | 90 | pciaddr.extent_mem = extent_create("PCI I/O memory space", |
91 | PCIADDR_MEM_START, | | 91 | PCIADDR_MEM_START, |
92 | PCIADDR_MEM_END, | | 92 | PCIADDR_MEM_END, |
93 | M_DEVBUF, 0, 0, EX_NOWAIT); | | 93 | M_DEVBUF, 0, 0, EX_NOWAIT); |
94 | KASSERT(pciaddr.extent_mem); | | 94 | KASSERT(pciaddr.extent_mem); |
95 | pciaddr.extent_port = extent_create("PCI I/O port space", | | 95 | pciaddr.extent_port = extent_create("PCI I/O port space", |
96 | PCIADDR_PORT_START, | | 96 | PCIADDR_PORT_START, |
97 | PCIADDR_PORT_END, | | 97 | PCIADDR_PORT_END, |
98 | M_DEVBUF, 0, 0, EX_NOWAIT); | | 98 | M_DEVBUF, 0, 0, EX_NOWAIT); |
99 | KASSERT(pciaddr.extent_port); | | 99 | KASSERT(pciaddr.extent_port); |
100 | | | 100 | |
101 | /* | | 101 | /* |
102 | * 1. check & reserve system BIOS setting. | | 102 | * 1. check & reserve system BIOS setting. |
103 | */ | | 103 | */ |
104 | aprint_debug(verbose_header, "System BIOS Setting"); | | 104 | aprint_debug(verbose_header, "System BIOS Setting"); |
105 | pci_device_foreach(pc, maxbus, pciaddr_resource_reserve, NULL); | | 105 | pci_device_foreach(pc, maxbus, pciaddr_resource_reserve, NULL); |
106 | aprint_debug(verbose_footer, pciaddr.nbogus); | | 106 | aprint_debug(verbose_footer, pciaddr.nbogus); |
107 | | | 107 | |
108 | /* | | 108 | /* |
109 | * 2. reserve non-PCI area. | | 109 | * 2. reserve non-PCI area. |
110 | */ | | 110 | */ |
111 | for (srp = system_reserve; srp->size; srp++) { | | 111 | for (srp = system_reserve; srp->size; srp++) { |
112 | error = extent_alloc_region(pciaddr.extent_mem, srp->start, | | 112 | error = extent_alloc_region(pciaddr.extent_mem, srp->start, |
113 | srp->size, | | 113 | srp->size, |
114 | EX_NOWAIT| EX_MALLOCOK); | | 114 | EX_NOWAIT| EX_MALLOCOK); |
115 | if (error != 0) { | | 115 | if (error != 0) { |
116 | aprint_error("WARNING: can't reserve area for %s.\n", | | 116 | aprint_error("WARNING: can't reserve area for %s.\n", |
117 | srp->name); | | 117 | srp->name); |
118 | } | | 118 | } |
119 | } | | 119 | } |
120 | | | 120 | |
121 | /* | | 121 | /* |
122 | * 3. determine allocation space | | 122 | * 3. determine allocation space |
123 | */ | | 123 | */ |
124 | start = x86_round_page(avail_end + 1); | | 124 | start = x86_round_page(avail_end + 1); |
125 | if (start < PCIADDR_ISAMEM_RESERVE) | | 125 | if (start < PCIADDR_ISAMEM_RESERVE) |
126 | start = PCIADDR_ISAMEM_RESERVE; | | 126 | start = PCIADDR_ISAMEM_RESERVE; |
127 | pciaddr.mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1); | | 127 | pciaddr.mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1); |
128 | pciaddr.port_alloc_start = PCIADDR_ISAPORT_RESERVE; | | 128 | pciaddr.port_alloc_start = PCIADDR_ISAPORT_RESERVE; |
129 | aprint_debug(" Physical memory end: 0x%08x\n PCI memory mapped I/O " | | 129 | aprint_debug(" Physical memory end: 0x%08x\n PCI memory mapped I/O " |
130 | "space start: 0x%08x\n", (unsigned)avail_end, | | 130 | "space start: 0x%08x\n", (unsigned)avail_end, |
131 | (unsigned)pciaddr.mem_alloc_start); | | 131 | (unsigned)pciaddr.mem_alloc_start); |
132 | | | 132 | |
133 | if (pciaddr.nbogus == 0) | | 133 | if (pciaddr.nbogus == 0) |
134 | return; /* no need to fixup */ | | 134 | return; /* no need to fixup */ |
135 | | | 135 | |
136 | /* | | 136 | /* |
137 | * 4. do fixup | | 137 | * 4. do fixup |
138 | */ | | 138 | */ |
139 | aprint_debug(verbose_header, "PCIBIOS fixup stage"); | | 139 | aprint_debug(verbose_header, "PCIBIOS fixup stage"); |
140 | pciaddr.nbogus = 0; | | 140 | pciaddr.nbogus = 0; |
141 | pci_device_foreach_min(pc, 0, maxbus, pciaddr_resource_allocate, NULL); | | 141 | pci_device_foreach_min(pc, 0, maxbus, pciaddr_resource_allocate, NULL); |
142 | aprint_debug(verbose_footer, pciaddr.nbogus); | | 142 | aprint_debug(verbose_footer, pciaddr.nbogus); |
143 | | | 143 | |
144 | } | | 144 | } |
145 | | | 145 | |
146 | static void | | 146 | static void |
147 | pciaddr_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag, | | 147 | pciaddr_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag, |
148 | void *context) | | 148 | void *context) |
149 | { | | 149 | { |
150 | pciaddr_print_devid(pc, tag); | | 150 | pciaddr_print_devid(pc, tag); |
151 | pciaddr_resource_manage(pc, tag, | | 151 | pciaddr_resource_manage(pc, tag, |
152 | pciaddr_do_resource_reserve, | | 152 | pciaddr_do_resource_reserve, |
153 | &pciaddr); | | 153 | &pciaddr); |
154 | } | | 154 | } |
155 | | | 155 | |
156 | static void | | 156 | static void |
157 | pciaddr_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, | | 157 | pciaddr_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, |
158 | void *context) | | 158 | void *context) |
159 | { | | 159 | { |
160 | pciaddr_print_devid(pc, tag); | | 160 | pciaddr_print_devid(pc, tag); |
161 | pciaddr_resource_manage(pc, tag, | | 161 | pciaddr_resource_manage(pc, tag, |
162 | pciaddr_do_resource_allocate, | | 162 | pciaddr_do_resource_allocate, |
163 | &pciaddr); | | 163 | &pciaddr); |
164 | } | | 164 | } |
165 | | | 165 | |
166 | void | | 166 | void |
167 | pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag, | | 167 | pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag, |
168 | pciaddr_resource_manage_func_t func, void *ctx) | | 168 | pciaddr_resource_manage_func_t func, void *ctx) |
169 | { | | 169 | { |
170 | pcireg_t val, mask; | | 170 | pcireg_t val, mask; |
171 | bus_addr_t addr; | | 171 | bus_addr_t addr; |
172 | bus_size_t size; | | 172 | bus_size_t size; |
173 | int error, useport, usemem, mapreg, type, reg_start, reg_end, width; | | 173 | int error, useport, usemem, mapreg, type, reg_start, reg_end, width; |
| @@ -182,193 +182,193 @@ pciaddr_resource_manage(pci_chipset_tag_ | | | @@ -182,193 +182,193 @@ pciaddr_resource_manage(pci_chipset_tag_ |
182 | reg_start = PCI_MAPREG_START; | | 182 | reg_start = PCI_MAPREG_START; |
183 | reg_end = PCI_MAPREG_END; | | 183 | reg_end = PCI_MAPREG_END; |
184 | break; | | 184 | break; |
185 | case PCI_HDRTYPE_PPB: /* PCI-PCI bridge */ | | 185 | case PCI_HDRTYPE_PPB: /* PCI-PCI bridge */ |
186 | reg_start = PCI_MAPREG_START; | | 186 | reg_start = PCI_MAPREG_START; |
187 | reg_end = PCI_MAPREG_PPB_END; | | 187 | reg_end = PCI_MAPREG_PPB_END; |
188 | break; | | 188 | break; |
189 | case PCI_HDRTYPE_PCB: /* PCI-CardBus bridge */ | | 189 | case PCI_HDRTYPE_PCB: /* PCI-CardBus bridge */ |
190 | reg_start = PCI_MAPREG_START; | | 190 | reg_start = PCI_MAPREG_START; |
191 | reg_end = PCI_MAPREG_PCB_END; | | 191 | reg_end = PCI_MAPREG_PCB_END; |
192 | break; | | 192 | break; |
193 | } | | 193 | } |
194 | error = useport = usemem = 0; | | 194 | error = useport = usemem = 0; |
195 | | | 195 | |
196 | for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { | | 196 | for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { |
197 | /* inquire PCI device bus space requirement */ | | 197 | /* inquire PCI device bus space requirement */ |
198 | val = pci_conf_read(pc, tag, mapreg); | | 198 | val = pci_conf_read(pc, tag, mapreg); |
199 | pci_conf_write(pc, tag, mapreg, ~0); | | 199 | pci_conf_write(pc, tag, mapreg, ~0); |
200 | | | 200 | |
201 | mask = pci_conf_read(pc, tag, mapreg); | | 201 | mask = pci_conf_read(pc, tag, mapreg); |
202 | pci_conf_write(pc, tag, mapreg, val); | | 202 | pci_conf_write(pc, tag, mapreg, val); |
203 | | | 203 | |
204 | type = PCI_MAPREG_TYPE(val); | | 204 | type = PCI_MAPREG_TYPE(val); |
205 | width = 4; | | 205 | width = 4; |
206 | if (type == PCI_MAPREG_TYPE_MEM) { | | 206 | if (type == PCI_MAPREG_TYPE_MEM) { |
207 | if (PCI_MAPREG_MEM_TYPE(val) == | | 207 | if (PCI_MAPREG_MEM_TYPE(val) == |
208 | PCI_MAPREG_MEM_TYPE_64BIT) { | | 208 | PCI_MAPREG_MEM_TYPE_64BIT) { |
209 | /* XXX We could examine the upper 32 bits | | 209 | /* XXX We could examine the upper 32 bits |
210 | * XXX of the BAR here, but we are totally | | 210 | * XXX of the BAR here, but we are totally |
211 | * XXX unprepared to handle a non-zero value, | | 211 | * XXX unprepared to handle a non-zero value, |
212 | * XXX either here or anywhere else in | | 212 | * XXX either here or anywhere else in |
213 | * XXX i386-land. | | 213 | * XXX i386-land. |
214 | * XXX So just arrange to not look at the | | 214 | * XXX So just arrange to not look at the |
215 | * XXX upper 32 bits, lest we misinterpret | | 215 | * XXX upper 32 bits, lest we misinterpret |
216 | * XXX it as a 32-bit BAR set to zero. | | 216 | * XXX it as a 32-bit BAR set to zero. |
217 | */ | | 217 | */ |
218 | width = 8; | | 218 | width = 8; |
219 | } | | 219 | } |
220 | size = PCI_MAPREG_MEM_SIZE(mask); | | 220 | size = PCI_MAPREG_MEM_SIZE(mask); |
221 | } else { | | 221 | } else { |
222 | size = PCI_MAPREG_IO_SIZE(mask); | | 222 | size = PCI_MAPREG_IO_SIZE(mask); |
223 | } | | 223 | } |
224 | addr = pciaddr_ioaddr(val); | | 224 | addr = pciaddr_ioaddr(val); |
225 | | | 225 | |
226 | if (size == 0) /* unused register */ | | 226 | if (size == 0) /* unused register */ |
227 | continue; | | 227 | continue; |
228 | | | 228 | |
229 | if (type == PCI_MAPREG_TYPE_MEM) | | 229 | if (type == PCI_MAPREG_TYPE_MEM) |
230 | ++usemem; | | 230 | ++usemem; |
231 | else | | 231 | else |
232 | ++useport; | | 232 | ++useport; |
233 | | | 233 | |
234 | /* reservation/allocation phase */ | | 234 | /* reservation/allocation phase */ |
235 | error += (*func) (pc, tag, mapreg, ctx, type, &addr, size); | | 235 | error += (*func) (pc, tag, mapreg, ctx, type, &addr, size); |
236 | | | 236 | |
237 | aprint_debug("\n\t%02xh %s 0x%08x 0x%08x", | | 237 | aprint_debug("\n\t%02xh %s 0x%08x 0x%08x", |
238 | mapreg, type ? "port" : "mem ", | | 238 | mapreg, type ? "port" : "mem ", |
239 | (unsigned int)addr, (unsigned int)size); | | 239 | (unsigned int)addr, (unsigned int)size); |
240 | } | | 240 | } |
241 | | | 241 | |
242 | /* enable/disable PCI device */ | | 242 | /* enable/disable PCI device */ |
243 | val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 243 | val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
244 | if (error == 0) | | 244 | if (error == 0) |
245 | val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | | | 245 | val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | |
246 | PCI_COMMAND_MASTER_ENABLE); | | 246 | PCI_COMMAND_MASTER_ENABLE); |
247 | else | | 247 | else |
248 | val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | | | 248 | val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | |
249 | PCI_COMMAND_MASTER_ENABLE); | | 249 | PCI_COMMAND_MASTER_ENABLE); |
250 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); | | 250 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); |
251 | | | 251 | |
252 | if (error != 0) | | 252 | if (error != 0) |
253 | pciaddr.nbogus++; | | 253 | pciaddr.nbogus++; |
254 | | | 254 | |
255 | aprint_debug("\n\t\t[%s]\n", error ? "NG" : "OK"); | | 255 | aprint_debug("\n\t\t[%s]\n", error ? "NG" : "OK"); |
256 | } | | 256 | } |
257 | | | 257 | |
258 | static int | | 258 | static int |
259 | pciaddr_do_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, | | 259 | pciaddr_do_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, |
260 | int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size) | | 260 | int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size) |
261 | { | | 261 | { |
262 | struct pciaddr *pciaddrmap = (struct pciaddr *)ctx; | | 262 | struct pciaddr *pciaddrmap = (struct pciaddr *)ctx; |
263 | bus_addr_t start; | | 263 | bus_addr_t start; |
264 | int error; | | 264 | int error; |
265 | struct extent *ex; | | 265 | struct extent *ex; |
266 | | | 266 | |
267 | if (*addr != 0) /* no need to allocate */ | | 267 | if (*addr != 0) /* no need to allocate */ |
268 | return 0; | | 268 | return 0; |
269 | | | 269 | |
270 | ex = (type == PCI_MAPREG_TYPE_MEM ? | | 270 | ex = (type == PCI_MAPREG_TYPE_MEM ? |
271 | pciaddrmap->extent_mem : pciaddrmap->extent_port); | | 271 | pciaddrmap->extent_mem : pciaddrmap->extent_port); |
272 | | | 272 | |
273 | /* XXX Don't allocate if device is AGP device to avoid conflict. */ | | 273 | /* XXX Don't allocate if device is AGP device to avoid conflict. */ |
274 | if (device_is_agp(pc, tag)) | | 274 | if (device_is_agp(pc, tag)) |
275 | return 0; | | 275 | return 0; |
276 | | | 276 | |
277 | start = (type == PCI_MAPREG_TYPE_MEM ? | | 277 | start = (type == PCI_MAPREG_TYPE_MEM ? |
278 | pciaddrmap->mem_alloc_start : pciaddrmap->port_alloc_start); | | 278 | pciaddrmap->mem_alloc_start : pciaddrmap->port_alloc_start); |
279 | | | 279 | |
280 | if (start < ex->ex_start || start + size - 1 >= ex->ex_end) { | | 280 | if (start < ex->ex_start || start + size - 1 >= ex->ex_end) { |
281 | aprint_debug("No available resources. fixup failed\n"); | | 281 | aprint_debug("No available resources. fixup failed\n"); |
282 | return 1; | | 282 | return 1; |
283 | } | | 283 | } |
284 | error = extent_alloc_subregion(ex, start, ex->ex_end, size, | | 284 | error = extent_alloc_subregion(ex, start, ex->ex_end, size, |
285 | size, 0, | | 285 | size, 0, |
286 | EX_FAST|EX_NOWAIT|EX_MALLOCOK, | | 286 | EX_FAST|EX_NOWAIT|EX_MALLOCOK, |
287 | (u_long *)addr); | | 287 | (u_long *)addr); |
288 | if (error) { | | 288 | if (error) { |
289 | aprint_debug("No available resources. fixup failed\n"); | | 289 | aprint_debug("No available resources. fixup failed\n"); |
290 | return 1; | | 290 | return 1; |
291 | } | | 291 | } |
292 | | | 292 | |
293 | /* write new address to PCI device configuration header */ | | 293 | /* write new address to PCI device configuration header */ |
294 | pci_conf_write(pc, tag, mapreg, *addr); | | 294 | pci_conf_write(pc, tag, mapreg, *addr); |
295 | /* check */ | | 295 | /* check */ |
296 | aprint_debug("pci_addr_fixup: "); | | 296 | aprint_debug("pci_addr_fixup: "); |
297 | pciaddr_print_devid(pc, tag); | | 297 | pciaddr_print_devid(pc, tag); |
298 | if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) { | | 298 | if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) { |
299 | pci_conf_write(pc, tag, mapreg, 0); /* clear */ | | 299 | pci_conf_write(pc, tag, mapreg, 0); /* clear */ |
300 | aprint_error("fixup failed. (new address=%#x)\n", (unsigned)*addr); | | 300 | aprint_error("fixup failed. (new address=%#x)\n", (unsigned)*addr); |
301 | return 1; | | 301 | return 1; |
302 | } | | 302 | } |
303 | aprint_debug("new address 0x%08x\n", (unsigned)*addr); | | 303 | aprint_debug("new address 0x%08x\n", (unsigned)*addr); |
304 | | | 304 | |
305 | return 0; | | 305 | return 0; |
306 | } | | 306 | } |
307 | | | 307 | |
308 | int | | 308 | int |
309 | pciaddr_do_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag, | | 309 | pciaddr_do_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag, |
310 | int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size) | | 310 | int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size) |
311 | { | | 311 | { |
312 | struct extent *ex; | | 312 | struct extent *ex; |
313 | struct pciaddr *pciaddrmap = (struct pciaddr *)ctx; | | 313 | struct pciaddr *pciaddrmap = (struct pciaddr *)ctx; |
314 | int error; | | 314 | int error; |
315 | | | 315 | |
316 | if (*addr == 0) | | 316 | if (*addr == 0) |
317 | return 1; | | 317 | return 1; |
318 | | | 318 | |
319 | ex = (type == PCI_MAPREG_TYPE_MEM ? | | 319 | ex = (type == PCI_MAPREG_TYPE_MEM ? |
320 | pciaddrmap->extent_mem : pciaddrmap->extent_port); | | 320 | pciaddrmap->extent_mem : pciaddrmap->extent_port); |
321 | | | 321 | |
322 | error = extent_alloc_region(ex, *addr, size, EX_NOWAIT| EX_MALLOCOK); | | 322 | error = extent_alloc_region(ex, *addr, size, EX_NOWAIT| EX_MALLOCOK); |
323 | if (error) { | | 323 | if (error) { |
324 | aprint_debug("Resource conflict.\n"); | | 324 | aprint_debug("Resource conflict.\n"); |
325 | pci_conf_write(pc, tag, mapreg, 0); /* clear */ | | 325 | pci_conf_write(pc, tag, mapreg, 0); /* clear */ |
326 | return 1; | | 326 | return 1; |
327 | } | | 327 | } |
328 | | | 328 | |
329 | return 0; | | 329 | return 0; |
330 | } | | 330 | } |
331 | | | 331 | |
332 | bus_addr_t | | 332 | bus_addr_t |
333 | pciaddr_ioaddr(uint32_t val) | | 333 | pciaddr_ioaddr(uint32_t val) |
334 | { | | 334 | { |
335 | return (PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) | | 335 | return (PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) |
336 | ? PCI_MAPREG_MEM_ADDR(val) | | 336 | ? PCI_MAPREG_MEM_ADDR(val) |
337 | : PCI_MAPREG_IO_ADDR(val); | | 337 | : PCI_MAPREG_IO_ADDR(val); |
338 | } | | 338 | } |
339 | | | 339 | |
340 | void | | 340 | void |
341 | pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag) | | 341 | pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag) |
342 | { | | 342 | { |
343 | int bus, device, function; | | 343 | int bus, device, function; |
344 | pcireg_t id; | | 344 | pcireg_t id; |
345 | | | 345 | |
346 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 346 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
347 | pci_decompose_tag(pc, tag, &bus, &device, &function); | | 347 | pci_decompose_tag(pc, tag, &bus, &device, &function); |
348 | aprint_debug("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function, | | 348 | aprint_debug("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function, |
349 | PCI_VENDOR(id), PCI_PRODUCT(id)); | | 349 | PCI_VENDOR(id), PCI_PRODUCT(id)); |
350 | } | | 350 | } |
351 | | | 351 | |
352 | static int | | 352 | static int |
353 | device_is_agp(pci_chipset_tag_t pc, pcitag_t tag) | | 353 | device_is_agp(pci_chipset_tag_t pc, pcitag_t tag) |
354 | { | | 354 | { |
355 | pcireg_t class, status, rval; | | 355 | pcireg_t class, status, rval; |
356 | int off; | | 356 | int off; |
357 | | | 357 | |
358 | /* Check AGP device. */ | | 358 | /* Check AGP device. */ |
359 | class = pci_conf_read(pc, tag, PCI_CLASS_REG); | | 359 | class = pci_conf_read(pc, tag, PCI_CLASS_REG); |
360 | if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) { | | 360 | if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) { |
361 | status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 361 | status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
362 | if (status & PCI_STATUS_CAPLIST_SUPPORT) { | | 362 | if (status & PCI_STATUS_CAPLIST_SUPPORT) { |
363 | rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG); | | 363 | rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG); |
364 | for (off = PCI_CAPLIST_PTR(rval); | | 364 | for (off = PCI_CAPLIST_PTR(rval); |
365 | off != 0; | | 365 | off != 0; |
366 | off = PCI_CAPLIST_NEXT(rval) ) { | | 366 | off = PCI_CAPLIST_NEXT(rval) ) { |
367 | rval = pci_conf_read(pc, tag, off); | | 367 | rval = pci_conf_read(pc, tag, off); |
368 | if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP) | | 368 | if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP) |
369 | return 1; | | 369 | return 1; |
370 | } | | 370 | } |
371 | } | | 371 | } |
372 | } | | 372 | } |
373 | return 0; | | 373 | return 0; |
374 | } | | 374 | } |