This source file includes following definitions.
- pci_addr_fixup
- pciaddr_resource_reserve
- pciaddr_resource_reserve_disabled
- pciaddr_resource_allocate
- pciaddr_resource_manage
- pciaddr_do_resource_allocate
- pciaddr_do_resource_reserve
- pciaddr_do_resource_reserve_disabled
- pciaddr_ioaddr
- pciaddr_print_devid
- pciaddr_device_is_agp
- pciaddr_search
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/kernel.h>
34 #include <sys/device.h>
35 #include <sys/extent.h>
36
37 #include <uvm/uvm_extern.h>
38
39 #include <machine/bus.h>
40
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcidevs.h>
44
45 #include <i386/pci/pcibiosvar.h>
46
47 typedef int (*pciaddr_resource_manage_func_t)(struct pcibios_softc *, pci_chipset_tag_t, pcitag_t, int,
48 struct extent *, int, bus_addr_t *, bus_size_t);
49 void pciaddr_resource_manage(struct pcibios_softc *,
50 pci_chipset_tag_t, pcitag_t, pciaddr_resource_manage_func_t);
51 void pciaddr_resource_reserve(struct pcibios_softc *,
52 pci_chipset_tag_t, pcitag_t);
53 void pciaddr_resource_reserve_disabled(struct pcibios_softc *,
54 pci_chipset_tag_t, pcitag_t);
55 int pciaddr_do_resource_reserve(struct pcibios_softc *,
56 pci_chipset_tag_t, pcitag_t, int, struct extent *, int,
57 bus_addr_t *, bus_size_t);
58 int pciaddr_do_resource_reserve_disabled(struct pcibios_softc *,
59 pci_chipset_tag_t, pcitag_t, int, struct extent *, int, u_long *,
60 bus_size_t);
61 void pciaddr_resource_allocate(struct pcibios_softc *,
62 pci_chipset_tag_t, pcitag_t);
63 int pciaddr_do_resource_allocate(struct pcibios_softc *,
64 pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *,
65 bus_size_t);
66 bus_addr_t pciaddr_ioaddr(u_int32_t);
67 void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t);
68
69 int pciaddr_device_is_agp(pci_chipset_tag_t, pcitag_t);
70
71 #define PCIADDR_MEM_START 0x0
72 #define PCIADDR_MEM_END 0xffffffff
73 #define PCIADDR_PORT_START 0x0
74 #define PCIADDR_PORT_END 0xffff
75
76
77 #define PCIADDR_ISAPORT_RESERVE 0x5800
78 #define PCIADDR_ISAMEM_RESERVE (16 * 1024 * 1024)
79
80 void
81 pci_addr_fixup(struct pcibios_softc *sc, pci_chipset_tag_t pc, int maxbus)
82 {
83 extern paddr_t avail_end;
84 const char *verbose_header =
85 "[%s]-----------------------\n"
86 " device vendor product\n"
87 " register space address size\n"
88 "--------------------------------------------\n";
89 const char *verbose_footer =
90 "--------------------------[%3d devices bogus]\n";
91
92 const struct {
93 bus_addr_t start;
94 bus_size_t size;
95 char *name;
96 } system_reserve [] = {
97 { 0xfec00000, 0x100000, "I/O APIC" },
98 { 0xfee00000, 0x100000, "Local APIC" },
99 { 0xfffe0000, 0x20000, "BIOS PROM" },
100 { 0, 0, 0 },
101 }, *srp;
102 paddr_t start;
103 int error;
104
105 sc->extent_mem = extent_create("PCI I/O memory space",
106 PCIADDR_MEM_START, PCIADDR_MEM_END, M_DEVBUF, 0, 0, EX_NOWAIT);
107 KASSERT(sc->extent_mem);
108 sc->extent_port = extent_create("PCI I/O port space",
109 PCIADDR_PORT_START, PCIADDR_PORT_END, M_DEVBUF, 0, 0, EX_NOWAIT);
110 KASSERT(sc->extent_port);
111
112
113
114
115 PCIBIOS_PRINTV((verbose_header, "System BIOS Setting"));
116 pci_device_foreach(sc, pc, maxbus, pciaddr_resource_reserve);
117 pci_device_foreach(sc, pc, maxbus, pciaddr_resource_reserve_disabled);
118 PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
119
120
121
122
123 for (srp = system_reserve; srp->size; srp++) {
124 error = extent_alloc_region(sc->extent_mem, srp->start,
125 srp->size, EX_NOWAIT| EX_MALLOCOK);
126 if (error != 0)
127 printf("WARNING: can't reserve area for %s.\n",
128 srp->name);
129 }
130
131
132
133
134 start = round_page(avail_end + 1);
135 if (start < PCIADDR_ISAMEM_RESERVE)
136 start = PCIADDR_ISAMEM_RESERVE;
137 sc->mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1);
138 sc->port_alloc_start = PCIADDR_ISAPORT_RESERVE;
139 PCIBIOS_PRINTV((" Physical memory end: 0x%08x\n PCI memory mapped I/O "
140 "space start: 0x%08x\n", avail_end, sc->mem_alloc_start));
141
142
143
144
145 PCIBIOS_PRINTV((verbose_header, "PCIBIOS fixup stage"));
146 sc->nbogus = 0;
147 pci_device_foreach(sc, pc, maxbus, pciaddr_resource_allocate);
148 PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
149
150 }
151
152 void
153 pciaddr_resource_reserve(struct pcibios_softc *sc, pci_chipset_tag_t pc,
154 pcitag_t tag)
155 {
156 if (pcibios_flags & PCIBIOS_VERBOSE)
157 pciaddr_print_devid(pc, tag);
158 pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_reserve);
159 }
160
161 void
162 pciaddr_resource_reserve_disabled(struct pcibios_softc *sc,
163 pci_chipset_tag_t pc, pcitag_t tag)
164 {
165 if (pcibios_flags & PCIBIOS_VERBOSE)
166 pciaddr_print_devid(pc, tag);
167 pciaddr_resource_manage(sc, pc, tag,
168 pciaddr_do_resource_reserve_disabled);
169 }
170
171 void
172 pciaddr_resource_allocate(struct pcibios_softc *sc, pci_chipset_tag_t pc,
173 pcitag_t tag)
174 {
175 if (pcibios_flags & PCIBIOS_VERBOSE)
176 pciaddr_print_devid(pc, tag);
177 pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_allocate);
178 }
179
180 void
181 pciaddr_resource_manage(struct pcibios_softc *sc, pci_chipset_tag_t pc,
182 pcitag_t tag, pciaddr_resource_manage_func_t func)
183 {
184 struct extent *ex;
185 pcireg_t val, mask;
186 bus_addr_t addr;
187 bus_size_t size;
188 int error, mapreg, type, reg_start, reg_end, width;
189
190 val = pci_conf_read(pc, tag, PCI_BHLC_REG);
191 switch (PCI_HDRTYPE_TYPE(val)) {
192 default:
193 printf("WARNING: unknown PCI device header 0x%x.\n",
194 PCI_HDRTYPE_TYPE(val));
195 sc->nbogus++;
196 return;
197 case 0:
198 reg_start = PCI_MAPREG_START;
199 reg_end = PCI_MAPREG_END;
200 break;
201 case 1:
202 reg_start = PCI_MAPREG_START;
203 reg_end = PCI_MAPREG_PPB_END;
204 break;
205 case 2:
206 reg_start = PCI_MAPREG_START;
207 reg_end = PCI_MAPREG_PCB_END;
208 break;
209 }
210 error = 0;
211
212 for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
213
214 val = pci_conf_read(pc, tag, mapreg);
215 pci_conf_write(pc, tag, mapreg, ~0);
216
217 mask = pci_conf_read(pc, tag, mapreg);
218 pci_conf_write(pc, tag, mapreg, val);
219
220 type = PCI_MAPREG_TYPE(val);
221 width = 4;
222 if (type == PCI_MAPREG_TYPE_MEM) {
223 if (PCI_MAPREG_MEM_TYPE(val) ==
224 PCI_MAPREG_MEM_TYPE_64BIT) {
225
226
227
228
229
230
231
232
233
234 width = 8;
235 }
236 addr = PCI_MAPREG_MEM_ADDR(val);
237 size = PCI_MAPREG_MEM_SIZE(mask);
238 ex = sc->extent_mem;
239 } else {
240
241 addr = PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END;
242 size = PCI_MAPREG_IO_SIZE(mask);
243 ex = sc->extent_port;
244 }
245
246 if (!size)
247 continue;
248
249
250 error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size);
251
252 PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n",
253 mapreg, type ? "port" : "mem ",
254 (unsigned int)addr, (unsigned int)size));
255 }
256
257 if (error)
258 sc->nbogus++;
259
260 PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK"));
261 }
262
263 int
264 pciaddr_do_resource_allocate(struct pcibios_softc *sc, pci_chipset_tag_t pc,
265 pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
266 bus_size_t size)
267 {
268 bus_addr_t start;
269 int error;
270
271 if (*addr)
272 return (0);
273
274
275 if (pciaddr_device_is_agp(pc, tag))
276 return (0);
277
278 start = (type == PCI_MAPREG_TYPE_MEM ? sc->mem_alloc_start
279 : sc->port_alloc_start);
280 if (start < ex->ex_start || start + size - 1 >= ex->ex_end) {
281 PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
282 return (1);
283 }
284 error = extent_alloc_subregion(ex, start, ex->ex_end, size, size, 0, 0,
285 EX_FAST|EX_NOWAIT|EX_MALLOCOK, addr);
286 if (error) {
287 PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
288 return (1);
289 }
290
291
292 pci_conf_write(pc, tag, mapreg, *addr);
293
294 if (pcibios_flags & PCIBIOS_VERBOSE) {
295 printf("pci_addr_fixup: ");
296 pciaddr_print_devid(pc, tag);
297 }
298
299 if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
300 pci_conf_write(pc, tag, mapreg, 0);
301 PCIBIOS_PRINTV(("fixup failed. (new address=%#x)\n", *addr));
302 return (1);
303 }
304 PCIBIOS_PRINTV(("new address 0x%08x\n", *addr));
305
306 return (0);
307 }
308
309 int
310 pciaddr_do_resource_reserve(struct pcibios_softc *sc, pci_chipset_tag_t pc,
311 pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
312 bus_size_t size)
313 {
314 pcireg_t val;
315 int error;
316
317 if (*addr == 0)
318 return (0);
319
320 val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
321 if (type == PCI_MAPREG_TYPE_MEM &&
322 (val & PCI_COMMAND_MEM_ENABLE) != PCI_COMMAND_MEM_ENABLE)
323 return (0);
324 if (type == PCI_MAPREG_TYPE_IO &&
325 (val & PCI_COMMAND_IO_ENABLE) != PCI_COMMAND_IO_ENABLE)
326 return (0);
327
328 error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
329 if (error) {
330 PCIBIOS_PRINTV(("Resource conflict.\n"));
331 pci_conf_write(pc, tag, mapreg, 0);
332 return (1);
333 }
334
335 return (0);
336 }
337
338 int
339 pciaddr_do_resource_reserve_disabled(struct pcibios_softc *sc,
340 pci_chipset_tag_t pc, pcitag_t tag, int mapreg, struct extent *ex, int type,
341 u_long *addr, bus_size_t size)
342 {
343 pcireg_t val;
344 int error;
345
346 if (*addr == 0)
347 return (0);
348
349 val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
350 if (type == PCI_MAPREG_TYPE_MEM &&
351 (val & PCI_COMMAND_MEM_ENABLE) == PCI_COMMAND_MEM_ENABLE)
352 return (0);
353 if (type == PCI_MAPREG_TYPE_IO &&
354 (val & PCI_COMMAND_IO_ENABLE) == PCI_COMMAND_IO_ENABLE)
355 return (0);
356
357 PCIBIOS_PRINTV(("disabled %s space at addr 0x%x size 0x%x\n",
358 type == PCI_MAPREG_TYPE_MEM ? "mem" : "io", *addr, size));
359
360 error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
361 if (error) {
362 PCIBIOS_PRINTV(("Resource conflict.\n"));
363 pci_conf_write(pc, tag, mapreg, 0);
364 return (1);
365 }
366
367 return (0);
368 }
369
370 bus_addr_t
371 pciaddr_ioaddr(u_int32_t val)
372 {
373 return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM)
374 ? PCI_MAPREG_MEM_ADDR(val)
375 : (PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END));
376 }
377
378 void
379 pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
380 {
381 int bus, device, function;
382 pcireg_t id;
383
384 id = pci_conf_read(pc, tag, PCI_ID_REG);
385 pci_decompose_tag(pc, tag, &bus, &device, &function);
386 printf("%03d:%02d:%d %04x:%04x\n", bus, device, function,
387 PCI_VENDOR(id), PCI_PRODUCT(id));
388 }
389
390 int
391 pciaddr_device_is_agp(pci_chipset_tag_t pc, pcitag_t tag)
392 {
393 pcireg_t class, status, rval;
394 int off;
395
396
397 class = pci_conf_read(pc, tag, PCI_CLASS_REG);
398 if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
399 status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
400 if (status & PCI_STATUS_CAPLIST_SUPPORT) {
401 rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG);
402 for (off = PCI_CAPLIST_PTR(rval);
403 off != 0;
404 off = PCI_CAPLIST_NEXT(rval) ) {
405 rval = pci_conf_read(pc, tag, off);
406 if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP)
407 return (1);
408 }
409 }
410 }
411 return (0);
412 }
413
414
415 struct extent *
416 pciaddr_search(int mem_port, bus_addr_t *startp, bus_size_t size)
417 {
418 extern struct cfdriver pcibios_cd;
419 struct pcibios_softc *sc;
420
421 sc = (struct pcibios_softc *)device_lookup(&pcibios_cd, 0);
422 if (sc && !(pcibios_flags & PCIBIOS_ADDR_FIXUP)) {
423 struct extent_region *rp;
424 struct extent *ex = mem_port? sc->extent_mem : sc->extent_port;
425
426
427
428
429
430
431
432
433
434 for (rp = LIST_FIRST(&ex->ex_regions);
435 rp && *startp + size > rp->er_start;
436 rp = LIST_NEXT(rp, er_link)) {
437 bus_addr_t new_start;
438
439 new_start = (rp->er_end - 1 + size) & ~(size - 1);
440 if (new_start > *startp)
441 *startp = new_start;
442 }
443
444 return (ex);
445 }
446
447 return (NULL);
448 }