]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/fdt/fdt_pci.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / fdt / fdt_pci.c
1 /*-
2  * Copyright (c) 2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Semihalf under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/ktr.h>
36 #include <sys/kernel.h>
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <sys/malloc.h>
40
41 #include <dev/fdt/fdt_common.h>
42 #include <dev/pci/pcireg.h>
43
44 #include <machine/fdt.h>
45
46 #include "ofw_bus_if.h"
47 #include "pcib_if.h"
48
49 #define DEBUG
50 #undef DEBUG
51
52 #ifdef DEBUG
53 #define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
54     printf(fmt,##args); } while (0)
55 #else
56 #define debugf(fmt, args...)
57 #endif
58
59 #define FDT_RANGES_CELLS        ((3 + 3 + 2) * 2)
60
61 static void
62 fdt_pci_range_dump(struct fdt_pci_range *range)
63 {
64 #ifdef DEBUG
65         printf("\n");
66         printf("  base_pci = 0x%08lx\n", range->base_pci);
67         printf("  base_par = 0x%08lx\n", range->base_parent);
68         printf("  len      = 0x%08lx\n", range->len);
69 #endif
70 }
71
72 int
73 fdt_pci_ranges_decode(phandle_t node, struct fdt_pci_range *io_space,
74     struct fdt_pci_range *mem_space)
75 {
76         pcell_t ranges[FDT_RANGES_CELLS];
77         struct fdt_pci_range *pci_space;
78         pcell_t addr_cells, size_cells, par_addr_cells;
79         pcell_t *rangesptr;
80         pcell_t cell0, cell1, cell2;
81         int tuple_size, tuples, i, rv, offset_cells, len;
82
83         /*
84          * Retrieve 'ranges' property.
85          */
86         if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
87                 return (EINVAL);
88         if (addr_cells != 3 || size_cells != 2)
89                 return (ERANGE);
90
91         par_addr_cells = fdt_parent_addr_cells(node);
92         if (par_addr_cells > 3)
93                 return (ERANGE);
94
95         len = OF_getproplen(node, "ranges");
96         if (len > sizeof(ranges))
97                 return (ENOMEM);
98
99         if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
100                 return (EINVAL);
101
102         tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
103             size_cells);
104         tuples = len / tuple_size;
105
106         rangesptr = &ranges[0];
107         offset_cells = 0;
108         for (i = 0; i < tuples; i++) {
109                 cell0 = fdt_data_get((void *)rangesptr, 1);
110                 rangesptr++;
111                 cell1 = fdt_data_get((void *)rangesptr, 1);
112                 rangesptr++;
113                 cell2 = fdt_data_get((void *)rangesptr, 1);
114                 rangesptr++;
115
116                 if (cell0 & 0x02000000) {
117                         pci_space = mem_space;
118                 } else if (cell0 & 0x01000000) {
119                         pci_space = io_space;
120                 } else {
121                         rv = ERANGE;
122                         goto out;
123                 }
124
125                 if (par_addr_cells == 3) {
126                         /*
127                          * This is a PCI subnode 'ranges'. Skip cell0 and
128                          * cell1 of this entry and only use cell2.
129                          */
130                         offset_cells = 2;
131                         rangesptr += offset_cells;
132                 }
133
134                 if (fdt_data_verify((void *)rangesptr, par_addr_cells -
135                     offset_cells)) {
136                         rv = ERANGE;
137                         goto out;
138                 }
139                 pci_space->base_parent = fdt_data_get((void *)rangesptr,
140                     par_addr_cells - offset_cells);
141                 rangesptr += par_addr_cells - offset_cells;
142
143                 if (fdt_data_verify((void *)rangesptr, size_cells)) {
144                         rv = ERANGE;
145                         goto out;
146                 }
147                 pci_space->len = fdt_data_get((void *)rangesptr, size_cells);
148                 rangesptr += size_cells;
149
150                 pci_space->base_pci = cell2;
151         }
152         rv = 0;
153 out:
154         return (rv);
155 }
156
157 int
158 fdt_pci_ranges(phandle_t node, struct fdt_pci_range *io_space,
159     struct fdt_pci_range *mem_space)
160 {
161         int err;
162
163         debugf("Processing PCI node: %x\n", node);
164         if ((err = fdt_pci_ranges_decode(node, io_space, mem_space)) != 0) {
165                 debugf("could not decode parent PCI node 'ranges'\n");
166                 return (err);
167         }
168
169         debugf("Post fixup dump:\n");
170         fdt_pci_range_dump(io_space);
171         fdt_pci_range_dump(mem_space);
172         return (0);
173 }
174
175 static int
176 fdt_addr_cells(phandle_t node, int *addr_cells)
177 {
178         pcell_t cell;
179         int cell_size;
180
181         cell_size = sizeof(cell);
182         if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size)
183                 return (EINVAL);
184         *addr_cells = fdt32_to_cpu((int)cell);
185
186         if (*addr_cells > 3)
187                 return (ERANGE);
188         return (0);
189 }
190
191 static int
192 fdt_interrupt_cells(phandle_t node)
193 {
194         pcell_t intr_cells;
195
196         if (OF_getprop(node, "#interrupt-cells", &intr_cells,
197             sizeof(intr_cells)) <= 0) {
198                 debugf("no intr-cells defined, defaulting to 1\n");
199                 intr_cells = 1;
200         }
201         intr_cells = fdt32_to_cpu(intr_cells);
202
203         return ((int)intr_cells);
204 }
205
206 int
207 fdt_pci_intr_info(phandle_t node, struct fdt_pci_intr *intr_info)
208 {
209         void *map, *mask;
210         int acells, icells;
211         int error, len;
212
213         error = fdt_addr_cells(node, &acells);
214         if (error)
215                 return (error);
216
217         icells = fdt_interrupt_cells(node);
218
219         /*
220          * Retrieve the interrupt map and mask properties.
221          */
222         len = OF_getprop_alloc(node, "interrupt-map-mask", 1, &mask);
223         if (len / sizeof(pcell_t) != (acells + icells)) {
224                 debugf("bad mask len = %d\n", len);
225                 goto err;
226         }
227
228         len = OF_getprop_alloc(node, "interrupt-map", 1, &map);
229         if (len <= 0) {
230                 debugf("bad map len = %d\n", len);
231                 goto err;
232         }
233
234         intr_info->map_len = len;
235         intr_info->map = map;
236         intr_info->mask = mask;
237         intr_info->addr_cells = acells;
238         intr_info->intr_cells = icells;
239
240         debugf("acells=%u, icells=%u, map_len=%u\n", acells, icells, len);
241         return (0);
242
243 err:
244         free(mask, M_OFWPROP);
245         return (ENXIO);
246 }
247
248 int
249 fdt_pci_route_intr(int bus, int slot, int func, int pin,
250     struct fdt_pci_intr *intr_info, int *interrupt)
251 {
252         pcell_t child_spec[4], masked[4];
253         ihandle_t iph;
254         pcell_t intr_par;
255         pcell_t *map_ptr;
256         uint32_t addr;
257         int i, j, map_len;
258         int par_intr_cells, par_addr_cells, child_spec_cells, row_cells;
259         int par_idx, spec_idx, err, trig, pol;
260
261         child_spec_cells = intr_info->addr_cells + intr_info->intr_cells;
262         if (child_spec_cells > sizeof(child_spec) / sizeof(pcell_t))
263                 return (ENOMEM);
264
265         addr = (bus << 16) | (slot << 11) | (func << 8);
266         child_spec[0] = addr;
267         child_spec[1] = 0;
268         child_spec[2] = 0;
269         child_spec[3] = pin;
270
271         map_len = intr_info->map_len;
272         map_ptr = intr_info->map;
273
274         par_idx = child_spec_cells;
275         i = 0;
276         while (i < map_len) {
277                 iph = fdt32_to_cpu(map_ptr[par_idx]);
278                 intr_par = OF_instance_to_package(iph);
279
280                 err = fdt_addr_cells(intr_par, &par_addr_cells);
281                 if (err != 0) {
282                         debugf("could not retrieve intr parent #addr-cells\n");
283                         return (err);
284                 }
285                 par_intr_cells = fdt_interrupt_cells(intr_par);
286
287                 row_cells = child_spec_cells + 1 + par_addr_cells +
288                     par_intr_cells;
289
290                 /*
291                  * Apply mask and look up the entry in interrupt map.
292                  */
293                 for (j = 0; j < child_spec_cells; j++) {
294                         masked[j] = child_spec[j] &
295                             fdt32_to_cpu(intr_info->mask[j]);
296
297                         if (masked[j] != fdt32_to_cpu(map_ptr[j]))
298                                 goto next;
299                 }
300
301                 /*
302                  * Decode interrupt of the parent intr controller.
303                  */
304                 spec_idx = child_spec_cells + 1 + par_addr_cells;
305                 err = fdt_intr_decode(intr_par, &map_ptr[spec_idx],
306                     interrupt, &trig, &pol);
307                 if (err != 0) {
308                         debugf("could not decode interrupt\n");
309                         return (err);
310                 }
311                 debugf("decoded intr = %d, trig = %d, pol = %d\n", *interrupt,
312                     trig, pol);
313
314 #if defined(__powerpc__)
315                 powerpc_config_intr(FDT_MAP_IRQ(intr_par, *interrupt), trig,
316                     pol);
317 #endif
318                 return (0);
319
320 next:
321                 map_ptr += row_cells;
322                 i += (row_cells * sizeof(pcell_t));
323         }
324
325         return (ENXIO);
326 }
327
328 #if defined(__arm__)
329 int
330 fdt_pci_devmap(phandle_t node, struct pmap_devmap *devmap, vm_offset_t io_va,
331     vm_offset_t mem_va)
332 {
333         struct fdt_pci_range io_space, mem_space;
334         int error;
335
336         if ((error = fdt_pci_ranges_decode(node, &io_space, &mem_space)) != 0)
337                 return (error);
338
339         devmap->pd_va = io_va;
340         devmap->pd_pa = io_space.base_parent;
341         devmap->pd_size = io_space.len;
342         devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
343         devmap->pd_cache = PTE_NOCACHE;
344         devmap++;
345
346         devmap->pd_va = mem_va;
347         devmap->pd_pa = mem_space.base_parent;
348         devmap->pd_size = mem_space.len;
349         devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
350         devmap->pd_cache = PTE_NOCACHE;
351         return (0);
352 }
353 #endif
354
355 #if 0
356 static int
357 fdt_pci_config_bar(device_t dev, int bus, int slot, int func, int bar)
358 {
359 }
360
361 static int
362 fdt_pci_config_normal(device_t dev, int bus, int slot, int func)
363 {
364         int bar;
365         uint8_t command, intline, intpin;
366
367         command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1);
368         command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
369         PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
370
371         /* Program the base address registers. */
372         bar = 0;
373         while (bar <= PCIR_MAX_BAR_0)
374                 bar += fdt_pci_config_bar(dev, bus, slot, func, bar);
375
376         /* Perform interrupt routing. */
377         intpin = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_INTPIN, 1);
378         intline = fsl_pcib_route_int(dev, bus, slot, func, intpin);
379         PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_INTLINE, intline, 1);
380
381         command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
382         PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
383 }
384
385 static int
386 fdt_pci_config_bridge(device_t dev, int bus, int secbus, int slot, int func)
387 {
388         int maxbar;
389         uint8_t command;
390
391         command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1);
392         command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
393         PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
394
395         /* Program the base address registers. */
396                         maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6;
397                         bar = 0;
398                         while (bar < maxbar)
399                                 bar += fsl_pcib_init_bar(sc, bus, slot, func,
400                                     bar);
401
402                         /* Perform interrupt routing. */
403                         intpin = fsl_pcib_read_config(sc->sc_dev, bus, slot,
404                             func, PCIR_INTPIN, 1);
405                         intline = fsl_pcib_route_int(sc, bus, slot, func,
406                             intpin);
407                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
408                             PCIR_INTLINE, intline, 1);
409
410                         command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
411                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
412                             PCIR_COMMAND, command, 1);
413
414                         /*
415                          * Handle PCI-PCI bridges
416                          */
417                         class = fsl_pcib_read_config(sc->sc_dev, bus, slot,
418                             func, PCIR_CLASS, 1);
419                         subclass = fsl_pcib_read_config(sc->sc_dev, bus, slot,
420                             func, PCIR_SUBCLASS, 1);
421
422                         /* Allow only proper PCI-PCI briges */
423                         if (class != PCIC_BRIDGE)
424                                 continue;
425                         if (subclass != PCIS_BRIDGE_PCI)
426                                 continue;
427
428                         secbus++;
429
430                         /* Program I/O decoder. */
431                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
432                             PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1);
433                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
434                             PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1);
435                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
436                             PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2);
437                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
438                             PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2);
439
440                         /* Program (non-prefetchable) memory decoder. */
441                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
442                             PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2);
443                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
444                             PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2);
445
446                         /* Program prefetchable memory decoder. */
447                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
448                             PCIR_PMBASEL_1, 0x0010, 2);
449                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
450                             PCIR_PMLIMITL_1, 0x000f, 2);
451                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
452                             PCIR_PMBASEH_1, 0x00000000, 4);
453                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
454                             PCIR_PMLIMITH_1, 0x00000000, 4);
455
456                         /* Read currect bus register configuration */
457                         old_pribus = fsl_pcib_read_config(sc->sc_dev, bus,
458                             slot, func, PCIR_PRIBUS_1, 1);
459                         old_secbus = fsl_pcib_read_config(sc->sc_dev, bus,
460                             slot, func, PCIR_SECBUS_1, 1);
461                         old_subbus = fsl_pcib_read_config(sc->sc_dev, bus,
462                             slot, func, PCIR_SUBBUS_1, 1);
463
464                         if (bootverbose)
465                                 printf("PCI: reading firmware bus numbers for "
466                                     "secbus = %d (bus/sec/sub) = (%d/%d/%d)\n",
467                                     secbus, old_pribus, old_secbus, old_subbus);
468
469                         new_pribus = bus;
470                         new_secbus = secbus;
471
472                         secbus = fsl_pcib_init(sc, secbus,
473                             (subclass == PCIS_BRIDGE_PCI) ? PCI_SLOTMAX : 0);
474
475                         new_subbus = secbus;
476
477                         if (bootverbose)
478                                 printf("PCI: translate firmware bus numbers "
479                                     "for secbus %d (%d/%d/%d) -> (%d/%d/%d)\n",
480                                     secbus, old_pribus, old_secbus, old_subbus,
481                                     new_pribus, new_secbus, new_subbus);
482
483                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
484                             PCIR_PRIBUS_1, new_pribus, 1);
485                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
486                             PCIR_SECBUS_1, new_secbus, 1);
487                         fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
488                             PCIR_SUBBUS_1, new_subbus, 1);
489
490 }
491
492 static int
493 fdt_pci_config_slot(device_t dev, int bus, int secbus, int slot)
494 {
495         int func, maxfunc;
496         uint16_t vendor;
497         uint8_t hdrtype;
498
499         maxfunc = 0;
500         for (func = 0; func <= maxfunc; func++) {
501                 hdrtype = PCIB_READ_CONFIG(dev, bus, slot, func,
502                     PCIR_HDRTYPE, 1);
503                 if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
504                         continue;
505                 if (func == 0 && (hdrtype & PCIM_MFDEV))
506                         maxfunc = PCI_FUNCMAX;
507
508                 vendor = PCIB_READ_CONFIG(dev, bus, slot, func,
509                     PCIR_VENDOR, 2);
510                 if (vendor == 0xffff)
511                         continue;
512
513                 if ((hdrtype & PCIM_HDRTYPE) == PCIM_HDRTYPE_NORMAL)
514                         fdt_pci_config_normal(dev, bus, slot, func);
515                 else
516                         secbus = fdt_pci_config_bridge(dev, bus, secbus,
517                             slot, func);
518         }
519
520         return (secbus);
521 }
522
523 static int
524 fdt_pci_config_bus(device_t dev, int bus, int maxslot)
525 {
526         int func, maxfunc, secbus, slot;
527
528         secbus = bus;
529         for (slot = 0; slot <= maxslot; slot++)
530                 secbus = fdt_pci_config_slot(dev, bus, secbus, slot);
531
532         return (secbus);
533 }
534
535 int
536 fdt_pci_config_domain(device_t dev)
537 {
538         pcell_t bus_range[2];
539         phandle_t root;
540         int bus, error, maxslot;
541
542         root = ofw_bus_get_node(dev);
543         if (root == 0)
544                 return (EINVAL);
545         if (!fdt_is_type(root, "pci"))
546                 return (EINVAL);
547
548         /*
549          * Determine the bus number of the root in this domain.
550          * Lacking any information, this will be bus 0.
551          * Write the bus number to the bus device, using the IVAR.
552          */
553         if ((OF_getprop(root, "bus-range", bus_range, sizeof(bus_range)) <= 0)
554                 bus = 0;
555         else
556                 bus = fdt32_to_cpu(bus_range[0]);
557
558         error = BUS_WRITE_IVAR(dev, NULL, PCIB_IVAR_BUS, bus);
559         if (error)
560                 return (error);
561
562         /* Get the maximum slot number for bus-enumeration. */
563         maxslot = PCIB_MAXSLOTS(dev);
564
565         bus = fdt_pci_config_bus(dev, bus, maxslot);
566         return (0);
567 }
568 #endif