1*89ed722cSmpi /* $OpenBSD: mpcpcibus.c,v 1.49 2022/03/13 12:33:01 mpi Exp $ */
2a3667f10Sdrahn
3a3667f10Sdrahn /*
4a3667f10Sdrahn * Copyright (c) 1997 Per Fogelstrom
5a3667f10Sdrahn *
6a3667f10Sdrahn * Redistribution and use in source and binary forms, with or without
7a3667f10Sdrahn * modification, are permitted provided that the following conditions
8a3667f10Sdrahn * are met:
9a3667f10Sdrahn * 1. Redistributions of source code must retain the above copyright
10a3667f10Sdrahn * notice, this list of conditions and the following disclaimer.
11a3667f10Sdrahn * 2. Redistributions in binary form must reproduce the above copyright
12a3667f10Sdrahn * notice, this list of conditions and the following disclaimer in the
13a3667f10Sdrahn * documentation and/or other materials provided with the distribution.
14a3667f10Sdrahn *
15a3667f10Sdrahn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16a3667f10Sdrahn * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17a3667f10Sdrahn * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a3667f10Sdrahn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19a3667f10Sdrahn * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a3667f10Sdrahn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a3667f10Sdrahn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a3667f10Sdrahn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a3667f10Sdrahn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a3667f10Sdrahn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a3667f10Sdrahn * SUCH DAMAGE.
26a3667f10Sdrahn *
27a3667f10Sdrahn */
28a3667f10Sdrahn
29a3667f10Sdrahn #include <sys/param.h>
30a3667f10Sdrahn #include <sys/systm.h>
31a3667f10Sdrahn #include <sys/device.h>
32d223becfSmpi #include <sys/malloc.h>
33d223becfSmpi #include <sys/extent.h>
34a3667f10Sdrahn
35a3667f10Sdrahn #include <machine/autoconf.h>
36020ac846Sdrahn #include <machine/pcb.h>
37a3667f10Sdrahn
38a3667f10Sdrahn #include <dev/pci/pcireg.h>
39a3667f10Sdrahn #include <dev/pci/pcivar.h>
40a3667f10Sdrahn #include <dev/pci/pcidevs.h>
41a3667f10Sdrahn
42a3667f10Sdrahn #include <dev/ofw/openfirm.h>
43a3667f10Sdrahn
44c4071fd1Smillert int mpcpcibrmatch(struct device *, void *, void *);
45c4071fd1Smillert void mpcpcibrattach(struct device *, struct device *, void *);
46a3667f10Sdrahn
47c4071fd1Smillert pcireg_t mpc_conf_read(void *, pcitag_t, int);
48c4071fd1Smillert void mpc_conf_write(void *, pcitag_t, int, pcireg_t);
49a3667f10Sdrahn
50c4071fd1Smillert u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset);
51601244bbSdrahn
52d223becfSmpi struct pcibr_config {
53d223becfSmpi bus_space_tag_t lc_memt;
54d223becfSmpi bus_space_tag_t lc_iot;
55d223becfSmpi bus_space_handle_t ioh_cf8;
56d223becfSmpi bus_space_handle_t ioh_cfc;
57d223becfSmpi struct ppc_pci_chipset lc_pc;
58d223becfSmpi int config_type;
59d223becfSmpi };
60d223becfSmpi
61d223becfSmpi struct pcibr_softc {
62d223becfSmpi struct device sc_dev;
63d223becfSmpi struct ppc_bus_space sc_membus_space;
64d223becfSmpi struct ppc_bus_space sc_iobus_space;
65d223becfSmpi struct pcibr_config pcibr_config;
66d223becfSmpi struct extent *sc_ioex;
67d223becfSmpi struct extent *sc_memex;
68d223becfSmpi char sc_ioex_name[32];
69d223becfSmpi char sc_memex_name[32];
70d223becfSmpi };
71d223becfSmpi
72*89ed722cSmpi const struct cfattach mpcpcibr_ca = {
73a3667f10Sdrahn sizeof(struct pcibr_softc), mpcpcibrmatch, mpcpcibrattach,
74a3667f10Sdrahn };
75a3667f10Sdrahn
76a3667f10Sdrahn struct cfdriver mpcpcibr_cd = {
77a3667f10Sdrahn NULL, "mpcpcibr", DV_DULL,
78a3667f10Sdrahn };
79a3667f10Sdrahn
80c4071fd1Smillert static int mpcpcibrprint(void *, const char *pnp);
81a3667f10Sdrahn
82e90f5639Skettenis void mpcpcibus_find_ranges_32(struct pcibr_softc *, u_int32_t *, int);
83e90f5639Skettenis void mpcpcibus_find_ranges_64(struct pcibr_softc *, u_int32_t *, int);
84e90f5639Skettenis
85a3667f10Sdrahn /*
86a3667f10Sdrahn * config types
87a3667f10Sdrahn * bit meanings
88a3667f10Sdrahn * 0 - standard cf8/cfc type configurations,
89a3667f10Sdrahn * sometimes the base addresses for these are different
90a3667f10Sdrahn * 1 - Config Method #2 configuration - uni-north
91a3667f10Sdrahn *
92a3667f10Sdrahn * 2 - 64 bit config bus, data for accesses &4 is at daddr+4;
93a3667f10Sdrahn */
947caa0606Sdrahn struct config_type{
95a3667f10Sdrahn char * compat;
96a3667f10Sdrahn u_int32_t addr; /* offset */
97a3667f10Sdrahn u_int32_t data; /* offset */
98a3667f10Sdrahn int config_type;
997caa0606Sdrahn };
1007caa0606Sdrahn struct config_type config_offsets[] = {
101a3667f10Sdrahn {"grackle", 0x00c00cf8, 0x00e00cfc, 0 },
102ac780239Sgwk {"bandit", 0x00800000, 0x00c00000, 1 },
103a3667f10Sdrahn {"uni-north", 0x00800000, 0x00c00000, 3 },
1047caa0606Sdrahn {"u3-agp", 0x00800000, 0x00c00000, 3 },
1057caa0606Sdrahn {"u3-ht", 0x00000cf8, 0x00000cfc, 3 },
106f6cf1346Smpi {"u4-pcie", 0x00800000, 0x00c00000, 7 },
107a3667f10Sdrahn {"legacy", 0x00000cf8, 0x00000cfc, 0 },
108a3667f10Sdrahn {"IBM,27-82660", 0x00000cf8, 0x00000cfc, 0 },
109a3667f10Sdrahn {NULL, 0x00000000, 0x00000000, 0 },
110a3667f10Sdrahn };
111a3667f10Sdrahn
112a3667f10Sdrahn int
mpcpcibrmatch(struct device * parent,void * match,void * aux)113601244bbSdrahn mpcpcibrmatch(struct device *parent, void *match, void *aux)
114a3667f10Sdrahn {
115a3667f10Sdrahn struct confargs *ca = aux;
116a3667f10Sdrahn int found = 0;
117a3667f10Sdrahn
118a3667f10Sdrahn if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0)
119a3667f10Sdrahn return (found);
120a3667f10Sdrahn
121a3667f10Sdrahn found = 1;
1226a1aaa0fSderaadt
123a3667f10Sdrahn return found;
124a3667f10Sdrahn }
125a3667f10Sdrahn
1267caa0606Sdrahn struct ranges_32 {
127e90f5639Skettenis u_int32_t cspace;
128e90f5639Skettenis u_int32_t child_hi;
129e90f5639Skettenis u_int32_t child_lo;
130e90f5639Skettenis u_int32_t phys;
131e90f5639Skettenis u_int32_t size_hi;
132e90f5639Skettenis u_int32_t size_lo;
133a3667f10Sdrahn };
134e90f5639Skettenis
1357caa0606Sdrahn void
mpcpcibus_find_ranges_32(struct pcibr_softc * sc,u_int32_t * range_store,int rangesize)1367caa0606Sdrahn mpcpcibus_find_ranges_32(struct pcibr_softc *sc, u_int32_t *range_store,
1377caa0606Sdrahn int rangesize)
138a3667f10Sdrahn {
139e90f5639Skettenis int i, found;
140a3667f10Sdrahn unsigned int base = 0;
141a3667f10Sdrahn unsigned int size = 0;
1427caa0606Sdrahn struct ranges_32 *prange = (void *)range_store;
1437caa0606Sdrahn int rangelen;
1447caa0606Sdrahn
1457caa0606Sdrahn rangelen = rangesize / sizeof(struct ranges_32);
146a3667f10Sdrahn
147a3667f10Sdrahn /* mac configs */
148a3667f10Sdrahn sc->sc_membus_space.bus_base = 0;
1495ae7b674Sdrahn sc->sc_membus_space.bus_io = 0;
150a3667f10Sdrahn sc->sc_iobus_space.bus_base = 0;
1515ae7b674Sdrahn sc->sc_iobus_space.bus_io = 1;
152a3667f10Sdrahn
153a3667f10Sdrahn /* find io(config) base, flag == 0x01000000 */
154a3667f10Sdrahn found = 0;
155601244bbSdrahn for (i = 0; i < rangelen; i++) {
156e90f5639Skettenis if (prange[i].cspace == 0x01000000) {
157a3667f10Sdrahn /* find last? */
158a3667f10Sdrahn found = i;
159e90f5639Skettenis
160e90f5639Skettenis if (sc->sc_ioex)
161e90f5639Skettenis extent_free(sc->sc_ioex, prange[i].child_lo,
162e90f5639Skettenis prange[i].size_lo, EX_NOWAIT);
163a3667f10Sdrahn }
164a3667f10Sdrahn }
165a3667f10Sdrahn /* found the io space ranges */
166e90f5639Skettenis if (prange[found].cspace == 0x01000000) {
167e90f5639Skettenis sc->sc_iobus_space.bus_base = prange[found].phys;
168e90f5639Skettenis sc->sc_iobus_space.bus_size = prange[found].size_lo;
169a3667f10Sdrahn }
170a3667f10Sdrahn
171a3667f10Sdrahn /* the mem space ranges
172a3667f10Sdrahn * apple openfirmware always puts full
173a3667f10Sdrahn * addresses in config information,
174a3667f10Sdrahn * it is not necessary to have correct bus
175a3667f10Sdrahn * base address, but since 0 is reserved
176a3667f10Sdrahn * and all IO and device memory will be in
177a3667f10Sdrahn * upper 2G of address space, set to
178a3667f10Sdrahn * 0x80000000
179a3667f10Sdrahn */
180601244bbSdrahn for (i = 0; i < rangelen; i++) {
181e90f5639Skettenis if (prange[i].cspace == 0x02000000) {
1827caa0606Sdrahn #ifdef DEBUG_PCI
183a3667f10Sdrahn printf("\nfound mem %x %x",
184e90f5639Skettenis prange[i].phys,
185e90f5639Skettenis prange[i].size_lo);
186a3667f10Sdrahn #endif
187a3667f10Sdrahn if (base != 0) {
188e90f5639Skettenis if ((base + size) == prange[i].phys)
189e90f5639Skettenis size += prange[i].size_lo;
1900e4a72beSgwk else {
191e90f5639Skettenis base = prange[i].phys;
192e90f5639Skettenis size = prange[i].size_lo;
193a3667f10Sdrahn }
194a3667f10Sdrahn } else {
195e90f5639Skettenis base = prange[i].phys;
196e90f5639Skettenis size = prange[i].size_lo;
197a3667f10Sdrahn }
198e90f5639Skettenis
199e90f5639Skettenis if (sc->sc_memex)
200e90f5639Skettenis extent_free(sc->sc_memex, prange[i].child_lo,
201e90f5639Skettenis prange[i].size_lo, EX_NOWAIT);
202a3667f10Sdrahn }
203a3667f10Sdrahn }
204a3667f10Sdrahn sc->sc_membus_space.bus_base = base;
205a3667f10Sdrahn sc->sc_membus_space.bus_size = size;
206a3667f10Sdrahn }
2077caa0606Sdrahn
2087caa0606Sdrahn struct ranges_64 {
209e90f5639Skettenis u_int32_t cspace;
210e90f5639Skettenis u_int32_t child_hi;
211e90f5639Skettenis u_int32_t child_lo;
212e90f5639Skettenis u_int32_t phys_hi;
213e90f5639Skettenis u_int32_t phys_lo;
214e90f5639Skettenis u_int32_t size_hi;
215e90f5639Skettenis u_int32_t size_lo;
2167caa0606Sdrahn };
217e90f5639Skettenis
2187caa0606Sdrahn void
mpcpcibus_find_ranges_64(struct pcibr_softc * sc,u_int32_t * range_store,int rangesize)2197caa0606Sdrahn mpcpcibus_find_ranges_64(struct pcibr_softc *sc, u_int32_t *range_store,
2207caa0606Sdrahn int rangesize)
2217caa0606Sdrahn {
2227caa0606Sdrahn int i, found;
2237caa0606Sdrahn unsigned int base = 0;
2247caa0606Sdrahn unsigned int size = 0;
2257caa0606Sdrahn struct ranges_64 *prange = (void *)range_store;
226e90f5639Skettenis int rangelen;
2277caa0606Sdrahn
2287caa0606Sdrahn rangelen = rangesize / sizeof(struct ranges_64);
2297caa0606Sdrahn
2307caa0606Sdrahn /* mac configs */
2317caa0606Sdrahn sc->sc_membus_space.bus_base = 0;
2327caa0606Sdrahn sc->sc_membus_space.bus_io = 0;
2337caa0606Sdrahn sc->sc_iobus_space.bus_base = 0;
2347caa0606Sdrahn sc->sc_iobus_space.bus_io = 1;
2357caa0606Sdrahn
236e90f5639Skettenis if (prange[0].cspace == 0xabb10113) { /* appl U3; */
237e90f5639Skettenis prange[0].cspace = 0x01000000;
238e90f5639Skettenis prange[0].child_lo = 0x00000000;
239e90f5639Skettenis prange[0].phys_lo = 0xf8070000;
240e90f5639Skettenis prange[0].size_lo = 0x00001000;
241e90f5639Skettenis prange[1].cspace = 0x02000000;
242e90f5639Skettenis prange[1].child_lo = 0xf2000000;
243e90f5639Skettenis prange[1].phys_lo = 0xf2000000;
244e90f5639Skettenis prange[1].size_lo = 0x02800000;
2457caa0606Sdrahn rangelen = 2;
2467caa0606Sdrahn }
2477caa0606Sdrahn
2487caa0606Sdrahn /* find io(config) base, flag == 0x01000000 */
2497caa0606Sdrahn found = 0;
2507caa0606Sdrahn for (i = 0; i < rangelen; i++) {
251e90f5639Skettenis if (prange[i].cspace == 0x01000000) {
2527caa0606Sdrahn /* find last? */
2537caa0606Sdrahn found = i;
254e90f5639Skettenis
255e90f5639Skettenis if (sc->sc_ioex)
256e90f5639Skettenis extent_free(sc->sc_ioex, prange[i].child_lo,
257e90f5639Skettenis prange[i].size_lo, EX_NOWAIT);
2587caa0606Sdrahn }
2597caa0606Sdrahn }
2607caa0606Sdrahn /* found the io space ranges */
261e90f5639Skettenis if (prange[found].cspace == 0x01000000) {
262e90f5639Skettenis sc->sc_iobus_space.bus_base = prange[found].phys_lo;
263e90f5639Skettenis sc->sc_iobus_space.bus_size = prange[found].size_lo;
2647caa0606Sdrahn }
2657caa0606Sdrahn
2667caa0606Sdrahn /* the mem space ranges
2677caa0606Sdrahn * apple openfirmware always puts full
2687caa0606Sdrahn * addresses in config information,
2697caa0606Sdrahn * it is not necessary to have correct bus
2707caa0606Sdrahn * base address, but since 0 is reserved
2717caa0606Sdrahn * and all IO and device memory will be in
2727caa0606Sdrahn * upper 2G of address space, set to
2737caa0606Sdrahn * 0x80000000
2747caa0606Sdrahn */
2757caa0606Sdrahn for (i = 0; i < rangelen; i++) {
276e90f5639Skettenis if (prange[i].cspace == 0x02000000) {
2777caa0606Sdrahn #ifdef DEBUG_PCI
2787caa0606Sdrahn printf("\nfound mem %x %x",
279e90f5639Skettenis prange[i].phys_lo,
280e90f5639Skettenis prange[i].size_lo);
2817caa0606Sdrahn #endif
2827caa0606Sdrahn if (base != 0) {
283e90f5639Skettenis if ((base + size) == prange[i].phys_lo) {
284e90f5639Skettenis size += prange[i].size_lo;
2857caa0606Sdrahn } else {
286e90f5639Skettenis base = prange[i].phys_lo;
287e90f5639Skettenis size = prange[i].size_lo;
2887caa0606Sdrahn }
2897caa0606Sdrahn } else {
290e90f5639Skettenis base = prange[i].phys_lo;
291e90f5639Skettenis size = prange[i].size_lo;
2927caa0606Sdrahn }
293e90f5639Skettenis
294e90f5639Skettenis if (sc->sc_memex)
295e90f5639Skettenis extent_free(sc->sc_memex, prange[i].child_lo,
296e90f5639Skettenis prange[i].size_lo, EX_NOWAIT);
2977caa0606Sdrahn }
2987caa0606Sdrahn }
2997caa0606Sdrahn sc->sc_membus_space.bus_base = base;
3007caa0606Sdrahn sc->sc_membus_space.bus_size = size;
3017caa0606Sdrahn }
3027caa0606Sdrahn
3037caa0606Sdrahn void
mpcpcibrattach(struct device * parent,struct device * self,void * aux)3047caa0606Sdrahn mpcpcibrattach(struct device *parent, struct device *self, void *aux)
3057caa0606Sdrahn {
3067caa0606Sdrahn struct pcibr_softc *sc = (struct pcibr_softc *)self;
3077caa0606Sdrahn struct confargs *ca = aux;
3087caa0606Sdrahn struct pcibr_config *lcp;
3097caa0606Sdrahn struct pcibus_attach_args pba;
3107caa0606Sdrahn char compat[32];
3117caa0606Sdrahn u_int32_t addr_offset;
3127caa0606Sdrahn u_int32_t data_offset;
3137caa0606Sdrahn int i;
3147caa0606Sdrahn int len;
3157caa0606Sdrahn int rangesize;
3167caa0606Sdrahn u_int32_t range_store[32];
3173e0aa7ecSmiod int busrange[2];
3187caa0606Sdrahn
3197caa0606Sdrahn if (ca->ca_node == 0) {
3207caa0606Sdrahn printf("invalid node on mpcpcibr config\n");
3217caa0606Sdrahn return;
3227caa0606Sdrahn }
3237caa0606Sdrahn len = OF_getprop(ca->ca_node, "name", compat, sizeof(compat));
3247caa0606Sdrahn compat[len] = '\0';
3257caa0606Sdrahn if (len > 0)
3267caa0606Sdrahn printf(" %s", compat);
3277caa0606Sdrahn
3283e0aa7ecSmiod len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
3297caa0606Sdrahn if (len <= 0) {
3303e0aa7ecSmiod len = OF_getprop(ca->ca_node, "name", compat, sizeof(compat));
3317caa0606Sdrahn if (len <= 0) {
3327caa0606Sdrahn printf(" compatible and name not found\n");
3337caa0606Sdrahn return;
3347caa0606Sdrahn }
3357caa0606Sdrahn compat[len] = 0;
3367caa0606Sdrahn if (strcmp(compat, "bandit") != 0) {
3377caa0606Sdrahn printf(" compatible not found and name %s found\n",
3387caa0606Sdrahn compat);
3397caa0606Sdrahn return;
3407caa0606Sdrahn }
3417caa0606Sdrahn }
3427caa0606Sdrahn compat[len] = 0;
3437caa0606Sdrahn if ((rangesize = OF_getprop(ca->ca_node, "ranges",
3447caa0606Sdrahn range_store, sizeof (range_store))) <= 0) {
3457caa0606Sdrahn if (strcmp(compat, "u3-ht") == 0) {
3467caa0606Sdrahn range_store[0] = 0xabb10113; /* appl U3; */
3477caa0606Sdrahn } else
3487caa0606Sdrahn printf("range lookup failed, node %x\n", ca->ca_node);
3497caa0606Sdrahn }
3507caa0606Sdrahn
351d223becfSmpi lcp = &sc->pcibr_config;
3527caa0606Sdrahn
353e90f5639Skettenis snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
354e90f5639Skettenis "%s pciio", sc->sc_dev.dv_xname);
355e90f5639Skettenis sc->sc_ioex = extent_create(sc->sc_ioex_name, 0x00000000, 0xffffffff,
356e90f5639Skettenis M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
357e90f5639Skettenis snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
358e90f5639Skettenis "%s pcimem", sc->sc_dev.dv_xname);
359e90f5639Skettenis sc->sc_memex = extent_create(sc->sc_memex_name, 0x00000000, 0xffffffff,
360e90f5639Skettenis M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
361e90f5639Skettenis
3627caa0606Sdrahn if (ppc_proc_is_64b)
3637caa0606Sdrahn mpcpcibus_find_ranges_64(sc, range_store, rangesize);
3647caa0606Sdrahn else
3657caa0606Sdrahn mpcpcibus_find_ranges_32(sc, range_store, rangesize);
3667caa0606Sdrahn
367a3667f10Sdrahn addr_offset = 0;
368a3667f10Sdrahn for (i = 0; config_offsets[i].compat != NULL; i++) {
3697caa0606Sdrahn struct config_type *co = &config_offsets[i];
3707caa0606Sdrahn if (strcmp(co->compat, compat) == 0) {
3717caa0606Sdrahn addr_offset = co->addr;
3727caa0606Sdrahn data_offset = co->data;
3737caa0606Sdrahn lcp->config_type = co->config_type;
374a3667f10Sdrahn break;
375a3667f10Sdrahn }
376a3667f10Sdrahn }
377a3667f10Sdrahn if (addr_offset == 0) {
378a3667f10Sdrahn printf("unable to find match for"
379a3667f10Sdrahn " compatible %s\n", compat);
380a3667f10Sdrahn return;
381a3667f10Sdrahn }
38272ad3cd4Sdrahn #ifdef DEBUG_FIXUP
383601244bbSdrahn printf(" mem base %x sz %x io base %x sz %x\n"
384601244bbSdrahn " config addr %x config data %x\n",
385a3667f10Sdrahn sc->sc_membus_space.bus_base,
386a3667f10Sdrahn sc->sc_membus_space.bus_size,
387a3667f10Sdrahn sc->sc_iobus_space.bus_base,
388a3667f10Sdrahn sc->sc_iobus_space.bus_size,
389a3667f10Sdrahn addr_offset, data_offset);
390a3667f10Sdrahn #endif
391a3667f10Sdrahn
392a3667f10Sdrahn if (bus_space_map(&(sc->sc_iobus_space), addr_offset,
3936a1aaa0fSderaadt NBPG, 0, &lcp->ioh_cf8) != 0)
394bc84bce2Skrw panic("mpcpcibus: unable to map self");
395601244bbSdrahn
396a3667f10Sdrahn if (bus_space_map(&(sc->sc_iobus_space), data_offset,
3976a1aaa0fSderaadt NBPG, 0, &lcp->ioh_cfc) != 0)
398bc84bce2Skrw panic("mpcpcibus: unable to map self");
399a3667f10Sdrahn
400a3667f10Sdrahn lcp->lc_pc.pc_conf_v = lcp;
4012d3c312aSmpi lcp->lc_pc.pc_node = ca->ca_node;
402a3667f10Sdrahn lcp->lc_pc.pc_conf_read = mpc_conf_read;
403a3667f10Sdrahn lcp->lc_pc.pc_conf_write = mpc_conf_write;
404a3667f10Sdrahn lcp->lc_iot = &sc->sc_iobus_space;
405a3667f10Sdrahn lcp->lc_memt = &sc->sc_membus_space;
406a3667f10Sdrahn
4076d211ebcSmpi printf(": %s\n", compat);
408a3667f10Sdrahn
4094eb8f200Skettenis bzero(&pba, sizeof(pba));
410a3667f10Sdrahn pba.pba_dmat = &pci_bus_dma_tag;
411a3667f10Sdrahn
412a3667f10Sdrahn pba.pba_busname = "pci";
413a3667f10Sdrahn pba.pba_iot = &sc->sc_iobus_space;
414a3667f10Sdrahn pba.pba_memt = &sc->sc_membus_space;
415e90f5639Skettenis pba.pba_ioex = sc->sc_ioex;
416e90f5639Skettenis pba.pba_memex = sc->sc_memex;
417a3667f10Sdrahn pba.pba_pc = &lcp->lc_pc;
418d307f358Skettenis pba.pba_domain = pci_ndomains++;
4193e0aa7ecSmiod if (OF_getprop(ca->ca_node, "bus-range", &busrange, sizeof(busrange)) <
4203e0aa7ecSmiod 0)
421a3667f10Sdrahn pba.pba_bus = 0;
4223e0aa7ecSmiod else
4233e0aa7ecSmiod pba.pba_bus = busrange[0];
424a3667f10Sdrahn
425a3667f10Sdrahn config_found(self, &pba, mpcpcibrprint);
426a3667f10Sdrahn }
427a3667f10Sdrahn
428a3667f10Sdrahn static int
mpcpcibrprint(void * aux,const char * pnp)429601244bbSdrahn mpcpcibrprint(void *aux, const char *pnp)
430a3667f10Sdrahn {
431a3667f10Sdrahn struct pcibus_attach_args *pba = aux;
432a3667f10Sdrahn
433a3667f10Sdrahn if (pnp)
434a3667f10Sdrahn printf("%s at %s", pba->pba_busname, pnp);
435a3667f10Sdrahn printf(" bus %d", pba->pba_bus);
436a3667f10Sdrahn return(UNCONF);
437a3667f10Sdrahn }
438a3667f10Sdrahn
439a3667f10Sdrahn u_int32_t
mpc_gen_config_reg(void * cpv,pcitag_t tag,int offset)440601244bbSdrahn mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset)
441a3667f10Sdrahn {
442a3667f10Sdrahn struct pcibr_config *cp = cpv;
443a3667f10Sdrahn unsigned int bus, dev, fcn;
4442d3c312aSmpi u_int32_t reg, val = PCITAG_OFFSET(tag);
445a3667f10Sdrahn
4462d3c312aSmpi pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
447a3667f10Sdrahn
448f6cf1346Smpi if (cp->config_type & 4) {
449f6cf1346Smpi reg = val | offset | 1;
450f6cf1346Smpi reg |= (offset >> 8) << 28;
451f6cf1346Smpi } else if (cp->config_type & 1) {
452a3667f10Sdrahn /* Config Mechanism #2 */
453a3667f10Sdrahn if (bus == 0) {
454601244bbSdrahn if (dev < 11)
455a3667f10Sdrahn return 0xffffffff;
456a3667f10Sdrahn /*
457a3667f10Sdrahn * Need to do config type 0 operation
458a3667f10Sdrahn * 1 << (11?+dev) | fcn << 8 | reg
459a3667f10Sdrahn * 11? is because pci spec states
460a3667f10Sdrahn * that 11-15 is reserved.
461a3667f10Sdrahn */
462a3667f10Sdrahn reg = 1 << (dev) | fcn << 8 | offset;
463a3667f10Sdrahn } else {
464601244bbSdrahn if (dev > 15)
465a3667f10Sdrahn return 0xffffffff;
466a3667f10Sdrahn /*
467a3667f10Sdrahn * config type 1
468a3667f10Sdrahn */
4692d3c312aSmpi reg = val | offset | 1;
470a3667f10Sdrahn }
471a3667f10Sdrahn } else {
472a3667f10Sdrahn /* config mechanism #2, type 0
473a3667f10Sdrahn * standard cf8/cfc config
474a3667f10Sdrahn */
4752d3c312aSmpi reg = 0x80000000 | val | offset;
476a3667f10Sdrahn }
477ac780239Sgwk
478a3667f10Sdrahn return reg;
479a3667f10Sdrahn }
480a3667f10Sdrahn
481a3667f10Sdrahn /* #define DEBUG_CONFIG */
482a3667f10Sdrahn pcireg_t
mpc_conf_read(void * cpv,pcitag_t tag,int offset)483601244bbSdrahn mpc_conf_read(void *cpv, pcitag_t tag, int offset)
484a3667f10Sdrahn {
485a3667f10Sdrahn struct pcibr_config *cp = cpv;
486a3667f10Sdrahn pcireg_t data;
487a3667f10Sdrahn u_int32_t reg;
488a3667f10Sdrahn int s;
489a3667f10Sdrahn int daddr = 0;
490020ac846Sdrahn faultbuf env;
491020ac846Sdrahn void *oldh;
492020ac846Sdrahn
493b1926db3Smiod if (offset & 3 ||
494b1926db3Smiod offset < 0 || offset >= PCI_CONFIG_SPACE_SIZE) {
495a3667f10Sdrahn #ifdef DEBUG_CONFIG
496a3667f10Sdrahn printf ("pci_conf_read: bad reg %x\n", offset);
497a3667f10Sdrahn #endif /* DEBUG_CONFIG */
498a3667f10Sdrahn return(~0);
499a3667f10Sdrahn }
500a3667f10Sdrahn
501a3667f10Sdrahn reg = mpc_gen_config_reg(cpv, tag, offset);
502a3667f10Sdrahn /* if invalid tag, return -1 */
503601244bbSdrahn if (reg == 0xffffffff)
504e226fd9fSdrahn return(~0);
505a3667f10Sdrahn
506601244bbSdrahn if ((cp->config_type & 2) && (offset & 0x04))
507a3667f10Sdrahn daddr += 4;
508a3667f10Sdrahn
509a3667f10Sdrahn s = splhigh();
510a3667f10Sdrahn
511020ac846Sdrahn oldh = curpcb->pcb_onfault;
5124140fb10Sdrahn if (setfault(&env)) {
513020ac846Sdrahn /* we faulted during the read? */
514020ac846Sdrahn curpcb->pcb_onfault = oldh;
515a1ec65acSmiod splx(s);
516020ac846Sdrahn return 0xffffffff;
517020ac846Sdrahn }
518020ac846Sdrahn
519a3667f10Sdrahn bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
520a3667f10Sdrahn bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
521a3667f10Sdrahn data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr);
522a3667f10Sdrahn bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
523a3667f10Sdrahn bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
524a3667f10Sdrahn
525020ac846Sdrahn curpcb->pcb_onfault = oldh;
526020ac846Sdrahn
527a3667f10Sdrahn splx(s);
528a3667f10Sdrahn #ifdef DEBUG_CONFIG
529a3667f10Sdrahn if (!((offset == 0) && (data == 0xffffffff))) {
530a3667f10Sdrahn unsigned int bus, dev, fcn;
5312d3c312aSmpi pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
532a3667f10Sdrahn printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn,
533a3667f10Sdrahn offset);
534a3667f10Sdrahn printf(" daddr %x reg %x",daddr, reg);
535a3667f10Sdrahn printf(" data %x\n", data);
536a3667f10Sdrahn }
537a3667f10Sdrahn #endif
538a3667f10Sdrahn
539a3667f10Sdrahn return(data);
540a3667f10Sdrahn }
541a3667f10Sdrahn
542a3667f10Sdrahn void
mpc_conf_write(void * cpv,pcitag_t tag,int offset,pcireg_t data)543601244bbSdrahn mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
544a3667f10Sdrahn {
545a3667f10Sdrahn struct pcibr_config *cp = cpv;
546a3667f10Sdrahn u_int32_t reg;
547a3667f10Sdrahn int s;
548a3667f10Sdrahn int daddr = 0;
549a3667f10Sdrahn
550a3667f10Sdrahn reg = mpc_gen_config_reg(cpv, tag, offset);
551a3667f10Sdrahn
552a3667f10Sdrahn /* if invalid tag, return ??? */
553601244bbSdrahn if (reg == 0xffffffff)
554a3667f10Sdrahn return;
555601244bbSdrahn
556601244bbSdrahn if ((cp->config_type & 2) && (offset & 0x04))
557a3667f10Sdrahn daddr += 4;
558601244bbSdrahn
559a3667f10Sdrahn #ifdef DEBUG_CONFIG
560a3667f10Sdrahn {
561a3667f10Sdrahn unsigned int bus, dev, fcn;
5622d3c312aSmpi pci_decompose_tag(cpv, tag, &bus, &dev, &fcn);
563a3667f10Sdrahn printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus,
564a3667f10Sdrahn dev, fcn, offset);
565a3667f10Sdrahn printf(" daddr %x reg %x",daddr, reg);
566a3667f10Sdrahn printf(" data %x\n", data);
567a3667f10Sdrahn }
568a3667f10Sdrahn #endif
569a3667f10Sdrahn
570a3667f10Sdrahn s = splhigh();
571a3667f10Sdrahn
572a3667f10Sdrahn bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
573a3667f10Sdrahn bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
574a3667f10Sdrahn bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data);
575a3667f10Sdrahn bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
576a3667f10Sdrahn bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
577a3667f10Sdrahn
578a3667f10Sdrahn splx(s);
579a3667f10Sdrahn }
580