]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/hv_pci.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sun4v / sun4v / hv_pci.c
1 /*-
2  * Copyright 2006 John-Mark Gurney.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33  * Support for the Hypervisor PCI bus.
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/pcpu.h>
42 #include <sys/endian.h>
43 #include <sys/rman.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcivar.h>
46
47 #include <machine/bus.h>
48
49 #include <machine/hypervisorvar.h>
50 #include <machine/hv_api.h>
51
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 #include <dev/ofw/ofw_pci.h>
55 #include <dev/ofw/openfirm.h>
56 #include <sparc64/pci/ofw_pci.h>
57
58 #include <machine/hv_pcivar.h>
59 #include <machine/hviommu.h>
60 #include <machine/vmparam.h>
61 #include <machine/tlb.h>
62 #include <machine/nexusvar.h>
63
64 #include "pcib_if.h"
65
66 /*
67  * XXX - should get this through the bus, but Sun overloaded the reg OFW
68  * property, so there isn't normal resources associated w/ this device.
69  */
70 extern struct bus_space_tag nexus_bustag;
71 /*
72  * Methods
73  */
74 static device_probe_t hvpci_probe;
75 static device_attach_t hvpci_attach;
76 static bus_read_ivar_t hvpci_read_ivar;
77 static bus_write_ivar_t hvpci_write_ivar;
78 static bus_alloc_resource_t hvpci_alloc_resource;
79 static bus_activate_resource_t hvpci_activate_resource;
80 static bus_deactivate_resource_t hvpci_deactivate_resource;
81 static bus_release_resource_t hvpci_release_resource;
82 static bus_get_dma_tag_t hvpci_get_dma_tag;
83 static pcib_maxslots_t hvpci_maxslots;
84 static pcib_read_config_t hvpci_read_config;
85 static pcib_write_config_t hvpci_write_config;
86 static pcib_route_interrupt_t hvpci_route_interrupt;
87 static ofw_bus_get_node_t hvpci_get_node;
88
89 static device_method_t hv_pcib_methods[] = {
90         /* Device interface */
91         DEVMETHOD(device_probe,         hvpci_probe),
92         DEVMETHOD(device_attach,        hvpci_attach),
93         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
94         DEVMETHOD(device_suspend,       bus_generic_suspend),
95         DEVMETHOD(device_resume,        bus_generic_resume),
96
97         /* Bus interface */
98         DEVMETHOD(bus_print_child,      bus_generic_print_child),
99         DEVMETHOD(bus_read_ivar,        hvpci_read_ivar),
100         DEVMETHOD(bus_write_ivar,       hvpci_write_ivar),
101         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
102         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
103         DEVMETHOD(bus_alloc_resource,   hvpci_alloc_resource),
104         DEVMETHOD(bus_activate_resource,        hvpci_activate_resource),
105         DEVMETHOD(bus_deactivate_resource,      hvpci_deactivate_resource),
106         DEVMETHOD(bus_release_resource, hvpci_release_resource),
107         DEVMETHOD(bus_get_dma_tag,      hvpci_get_dma_tag),
108
109         /* pcib interface */
110         DEVMETHOD(pcib_maxslots,        hvpci_maxslots),
111         DEVMETHOD(pcib_read_config,     hvpci_read_config),
112         DEVMETHOD(pcib_write_config,    hvpci_write_config),
113         DEVMETHOD(pcib_route_interrupt, hvpci_route_interrupt),
114
115         /* ofw_bus interface */
116         DEVMETHOD(ofw_bus_get_node,     hvpci_get_node),
117
118         { 0, 0 }
119 };
120
121 static driver_t hvpci_driver = {
122         "pcib",
123         hv_pcib_methods,
124         sizeof(struct hvpci_softc),
125 };
126
127 static devclass_t hvpci_devclass;
128
129 DRIVER_MODULE(hvpci, nexus, hvpci_driver, hvpci_devclass, 0, 0);
130
131 static int
132 hvpci_probe(device_t dev)
133 {
134
135         if (strcmp(ofw_bus_get_name(dev), "pci") != 0)
136                 return (ENXIO);
137
138         device_set_desc(dev, "Hypervisor PCI Bridge");
139         return (0);
140 }
141
142 static int
143 hvpci_attach(device_t dev)
144 {
145         struct ofw_pci_ranges *range;
146         struct rman *rmanp;
147         struct hvpci_softc *sc;
148         struct hviommu *himp;
149         bus_space_tag_t *btp;
150         phandle_t node;
151         uint32_t *dvma;
152         int br[2];
153         int n, type;
154         int i, nrange;
155
156         sc = device_get_softc(dev);
157
158         node = ofw_bus_get_node(dev);
159         if (node == -1)
160                 panic("%s: ofw_bus_get_node failed.", __func__);
161
162         sc->hs_node = node;
163
164         /* Setup the root bus number for this bus */
165         n = OF_getprop(node, "bus-range", &br[0], sizeof br);
166         if (n == -1)
167                 panic("%s: could not get bus-range", __func__);
168         if (n != sizeof br)
169                 panic("%s: broken bus-range (%d)", __func__, n);
170         sc->hs_busnum = br[0];
171
172         /* Setup the HyperVisor devhandle for this bus */
173         sc->hs_devhandle = nexus_get_devhandle(dev);
174
175         /* Pull in the ra addresses out of OFW */
176         nrange = OF_getprop_alloc(node, "ranges", sizeof *range,
177             (void **)&range);
178
179         /* Initialize memory and I/O rmans. */
180         for (i = 0; i < nrange; i++) {
181 /* XXX - from sun4v/io/px/px_lib4v.c: px_ranges_phi_mask */
182 #define PHYS_MASK       ((1ll << (28 + 32)) - 1)
183                 switch (OFW_PCI_RANGE_CS(&range[i])) {
184                 case OFW_PCI_CS_IO:
185                         rmanp = &sc->hs_pci_io_rman;
186                         rmanp->rm_descr = "HyperVisor PCI I/O Ports";
187                         btp = &sc->hs_pci_iot;
188                         sc->hs_pci_ioh = OFW_PCI_RANGE_PHYS(&range[i]) &
189                             PHYS_MASK;
190                         type = PCI_IO_BUS_SPACE;
191 #ifdef DEBUG
192                         printf("io handle: %#lx\n", sc->hs_pci_ioh);
193 #endif
194                         break;
195
196                 case OFW_PCI_CS_MEM32:
197                         rmanp = &sc->hs_pci_mem_rman;
198                         rmanp->rm_descr = "HyperVisor PCI Memory";
199                         btp = &sc->hs_pci_memt;
200                         sc->hs_pci_memh = OFW_PCI_RANGE_PHYS(&range[i]) &
201                             PHYS_MASK;
202                         type = PCI_MEMORY_BUS_SPACE;
203                         break;
204
205                 case OFW_PCI_CS_MEM64:
206                         continue;
207
208                 default:
209                         panic("%s: unknown range type: %d", __func__,
210                             OFW_PCI_RANGE_CS(&range[i]));
211                 }
212                 rmanp->rm_type = RMAN_ARRAY;
213                 if (rman_init(rmanp) != 0 || rman_manage_region(rmanp, 0,
214                     OFW_PCI_RANGE_SIZE(&range[i])) != 0)
215                         panic("%s: failed to set up rman type: %d", __func__,
216                             OFW_PCI_RANGE_CS(&range[i]));
217
218                 *btp = (bus_space_tag_t)malloc(sizeof **btp, M_DEVBUF,
219                     M_WAITOK|M_ZERO);
220                 (*btp)->bst_parent = &nexus_bustag;
221                 (*btp)->bst_type = type;
222         }
223         free(range, M_OFWPROP);
224
225         nrange = OF_getprop_alloc(node, "virtual-dma", sizeof *dvma,
226             (void **)&dvma);
227         KASSERT(nrange == 2, ("virtual-dma propery invalid"));
228
229         /* Setup bus_dma_tag */
230         himp = hviommu_init(sc->hs_devhandle, dvma[0], dvma[1]);
231         sc->hs_dmatag.dt_cookie = himp;
232         sc->hs_dmatag.dt_mt = &hviommu_dma_methods;
233         sc->hs_dmatag.dt_lowaddr = ~0;
234         sc->hs_dmatag.dt_highaddr = ~0;
235         sc->hs_dmatag.dt_boundary = BUS_SPACE_MAXADDR_32BIT + 1;
236
237         free(dvma, M_OFWPROP);
238
239         /* Setup ofw imap */
240         ofw_bus_setup_iinfo(node, &sc->hs_pci_iinfo, sizeof(ofw_pci_intr_t));
241
242         device_add_child(dev, "pci", -1);
243
244         return (bus_generic_attach(dev));
245 }
246
247 static int
248 hvpci_maxslots(device_t dev)
249 {
250
251         return (0);
252 }
253
254 #define HVPCI_BDF(b, d, f)      \
255                 ((b & 0xff) << 16) | ((d & 0x1f) << 11) | ((f & 0x7) << 8)
256 static uint32_t
257 hvpci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
258     int width)
259 {
260         struct hvpci_softc *sc;
261         uint32_t data = -1;
262         uint64_t r;
263         uint32_t ret;
264
265         sc = device_get_softc(dev);
266
267         r = hv_pci_config_get(sc->hs_devhandle, HVPCI_BDF(bus, slot, func),
268                             reg, width, (pci_cfg_data_t *)&data);
269                 
270         if (r == H_EOK) {
271                 switch (width) {
272                 case 1:
273                         ret = data & 0xff;
274                         if (ret == 0 && reg == PCIR_INTLINE)
275                                 ret = PCI_INVALID_IRQ;
276                         break;
277                 case 2:
278                         ret = data & 0xffff;
279                         break;
280                 case 4:
281                         ret = data;
282                         break;
283                 default:
284                         ret = -1;
285                 }
286                 return ret;
287         }
288
289         return -1;
290 }
291
292 static void
293 hvpci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
294      uint32_t val, int width)
295 {
296         struct hvpci_softc *sc;
297         pci_cfg_data_t data = { 0 };
298         uint64_t r;
299
300         sc = device_get_softc(dev);
301         switch (width) {
302         case 1:
303                 data.qw = (uint8_t)val;
304                 break;
305         case 2:
306                 data.qw = (uint16_t)(val & 0xffff);
307                 break;
308         case 4:
309                 data.qw = (uint32_t)val;
310                 break;
311         default:
312                 panic("unsupported width: %d", width);
313         }
314
315         r = hv_pci_config_put(sc->hs_devhandle, HVPCI_BDF(bus, slot, func), 
316                             reg, width, (pci_cfg_data_t)data);
317
318         if (r)
319                 printf("put failed with: %ld\n", r);
320 }
321
322 static int
323 hvpci_route_interrupt(device_t bridge, device_t dev, int pin)
324 {
325         struct hvpci_softc *sc;
326         struct ofw_pci_register reg;
327         phandle_t node;
328         ofw_pci_intr_t pintr, mintr;
329         int obli;
330         uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
331
332         sc = device_get_softc(bridge);
333         node = ofw_bus_get_node(dev);
334         pintr = pin;
335         obli = ofw_bus_lookup_imap(node, &sc->hs_pci_iinfo, &reg, sizeof(reg),
336             &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf);
337         device_printf(dev, "called hvpci_route_intr: %d, got: mintr: %#x\n",
338             obli, mintr);
339         if (obli)
340                 return (mintr);
341
342         panic("pin %d not found in imap of %s", pin, device_get_nameunit(bridge));
343 }
344
345 static phandle_t
346 hvpci_get_node(device_t bus, device_t dev)
347 {
348         struct hvpci_softc *sc;
349
350         sc = device_get_softc(bus);
351
352         return (sc->hs_node);
353 }
354
355 static int
356 hvpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
357 {
358         struct hvpci_softc *sc;
359
360         sc = device_get_softc(dev);
361
362         switch (which) {
363         case PCIB_IVAR_DOMAIN:
364                 *result = 0;
365                 return (0);
366         case PCIB_IVAR_BUS:
367                 *result = sc->hs_busnum;
368                 return (0);
369         }
370
371         return (ENOENT);
372 }
373
374 static int
375 hvpci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
376 {
377         struct hvpci_softc *sc;
378
379         sc = device_get_softc(dev);
380         switch (which) {
381         case PCIB_IVAR_DOMAIN:
382                 return (EINVAL);
383         case PCIB_IVAR_BUS:
384                 sc->hs_busnum = value;
385                 return (0);
386         }
387
388         return (ENOENT);
389 }
390
391 static struct resource *
392 hvpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
393     u_long start, u_long end, u_long count, u_int flags)
394 {
395         struct hvpci_softc *sc;
396         struct resource *rv;
397         struct rman *rm;
398         bus_space_tag_t bt;
399         bus_space_handle_t bh;
400         int needactivate;
401
402         sc = device_get_softc(bus);
403
404         needactivate = flags & RF_ACTIVE;
405         flags &= ~RF_ACTIVE;
406
407         switch (type) {
408         case SYS_RES_IRQ:
409                 return BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
410                     rid, start, end, count, flags);
411                 break;
412
413         case SYS_RES_MEMORY:
414                 rm = &sc->hs_pci_mem_rman;
415                 bt = sc->hs_pci_memt;
416                 bh = sc->hs_pci_memh;
417                 break;
418
419         case SYS_RES_IOPORT:
420 #ifdef DEBUG
421                 printf("alloc: start: %#lx, end: %#lx, count: %#lx\n", start, end, count);
422 #endif
423                 rm = &sc->hs_pci_io_rman;
424                 bt = sc->hs_pci_iot;
425                 bh = sc->hs_pci_ioh;
426                 break;
427
428         default:
429                 return (NULL);
430         }
431
432         rv = rman_reserve_resource(rm, start, end, count, flags, child);
433         if (rv == NULL)
434                 return (NULL);
435
436         bh += rman_get_start(rv);
437         rman_set_bustag(rv, bt);
438         rman_set_bushandle(rv, bh);
439
440         if (needactivate) {
441                 if (bus_activate_resource(child, type, *rid, rv)) {
442                         rman_release_resource(rv);
443                         return (NULL);
444                 }
445         }
446
447         return (rv);
448 }
449
450 static int
451 hvpci_activate_resource(device_t bus, device_t child, int type, int rid,
452     struct resource *r) 
453 {
454         void *p;
455
456         if (type == SYS_RES_MEMORY) {
457                 /* XXX - we may still need to set the IE bit on the mapping */
458                 p = (void *)TLB_PHYS_TO_DIRECT(rman_get_bushandle(r));
459                 rman_set_virtual(r, p);
460         }
461         return (rman_activate_resource(r));
462 }
463
464 static int
465 hvpci_deactivate_resource(device_t bus, device_t child, int type, int rid,
466     struct resource *r) 
467 {
468
469         return (0);
470 }
471
472 static int
473 hvpci_release_resource(device_t bus, device_t child, int type, int rid,
474     struct resource *r)
475 {
476
477         return (0);
478 }
479
480 static bus_dma_tag_t
481 hvpci_get_dma_tag(device_t bus, device_t child)
482 {
483         struct hvpci_softc *sc;
484
485         sc = device_get_softc(bus);
486
487         return &sc->hs_dmatag;
488 }