1*9ad90adaSthorpej /* $NetBSD: rbus_ppb.c,v 1.50 2022/09/25 17:33:19 thorpej Exp $ */
2c34df0c3Smcr
3c34df0c3Smcr /*
4c34df0c3Smcr * Copyright (c) 1999 The NetBSD Foundation, Inc.
5c34df0c3Smcr * All rights reserved.
6c34df0c3Smcr *
7c34df0c3Smcr * This code is derived from software contributed to The NetBSD Foundation
8c34df0c3Smcr * by Michael Richardson <mcr@sandelman.ottawa.on.ca>
9c34df0c3Smcr *
10c34df0c3Smcr * Redistribution and use in source and binary forms, with or without
11c34df0c3Smcr * modification, are permitted provided that the following conditions
12c34df0c3Smcr * are met:
13c34df0c3Smcr * 1. Redistributions of source code must retain the above copyright
14c34df0c3Smcr * notice, this list of conditions and the following disclaimer.
15c34df0c3Smcr * 2. Redistributions in binary form must reproduce the above copyright
16c34df0c3Smcr * notice, this list of conditions and the following disclaimer in the
17c34df0c3Smcr * documentation and/or other materials provided with the distribution.
18c34df0c3Smcr *
19c34df0c3Smcr * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20c34df0c3Smcr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21c34df0c3Smcr * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c34df0c3Smcr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23c34df0c3Smcr * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24c34df0c3Smcr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25c34df0c3Smcr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26c34df0c3Smcr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27c34df0c3Smcr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28c34df0c3Smcr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29c34df0c3Smcr * POSSIBILITY OF SUCH DAMAGE.
30c34df0c3Smcr */
31c34df0c3Smcr
32c34df0c3Smcr /*
33c34df0c3Smcr * CardBus front-end for the Intel/Digital DECchip 21152 PCI-PCI bridge
34c34df0c3Smcr */
35c34df0c3Smcr
36f61cbe74Slukem #include <sys/cdefs.h>
37*9ad90adaSthorpej __KERNEL_RCSID(0, "$NetBSD: rbus_ppb.c,v 1.50 2022/09/25 17:33:19 thorpej Exp $");
38f61cbe74Slukem
39c34df0c3Smcr #include <sys/param.h>
40c34df0c3Smcr #include <sys/systm.h>
41c34df0c3Smcr #include <sys/mbuf.h>
42c34df0c3Smcr #include <sys/kernel.h>
43c34df0c3Smcr #include <sys/socket.h>
44c34df0c3Smcr #include <sys/ioctl.h>
45c34df0c3Smcr #include <sys/errno.h>
46c34df0c3Smcr #include <sys/device.h>
4755ce6763Sdyoung #include <sys/kmem.h>
48c34df0c3Smcr
49c34df0c3Smcr #include <machine/endian.h>
50c34df0c3Smcr
51a2a38285Sad #include <sys/bus.h>
52a2a38285Sad #include <sys/intr.h>
53c34df0c3Smcr
54c34df0c3Smcr #include <dev/pci/pcivar.h>
55c34df0c3Smcr #include <dev/pci/pcireg.h>
56c34df0c3Smcr #include <dev/pci/pcidevs.h>
57c34df0c3Smcr #include <dev/pci/ppbreg.h>
58c34df0c3Smcr
59c34df0c3Smcr #include <dev/ic/i82365reg.h>
60c34df0c3Smcr
611ca3ef38Sdrochner #include <dev/cardbus/rbus.h>
62c34df0c3Smcr #include <dev/pci/pccbbreg.h>
63c34df0c3Smcr #include <dev/pci/pccbbvar.h>
64c34df0c3Smcr
65c34df0c3Smcr #include <dev/cardbus/cardbusvar.h>
66eed3298aSmycroft #include <dev/pci/pcidevs.h>
67c34df0c3Smcr
689709f2afSjmcneill #include <x86/pci/pci_addr_fixup.h>
699709f2afSjmcneill #include <x86/pci/pci_bus_fixup.h>
70c34df0c3Smcr #include <i386/pci/pci_intr_fixup.h>
71c34df0c3Smcr #include <i386/pci/pcibios.h>
72c34df0c3Smcr
73c34df0c3Smcr struct ppb_softc;
74c34df0c3Smcr
75529e91fcScegger static int ppb_cardbus_match(device_t, cfdata_t, void *);
76529e91fcScegger static void ppb_cardbus_attach(device_t, device_t, void *);
77529e91fcScegger static int ppb_activate(device_t, enum devact);
781fbab2d8Sdrochner int rppbprint(void *, const char *);
791fbab2d8Sdrochner int rbus_intr_fixup(pci_chipset_tag_t, int, int, int);
801fbab2d8Sdrochner void rbus_do_header_fixup(pci_chipset_tag_t, pcitag_t, void *);
81c34df0c3Smcr
821fbab2d8Sdrochner static void rbus_pci_phys_allocate(pci_chipset_tag_t, pcitag_t, void *);
83c34df0c3Smcr
841fbab2d8Sdrochner static int rbus_do_phys_allocate(pci_chipset_tag_t, pcitag_t, int,
851fbab2d8Sdrochner void *, int, bus_addr_t *, bus_size_t);
86c34df0c3Smcr
871fbab2d8Sdrochner static void rbus_pci_phys_countspace(pci_chipset_tag_t, pcitag_t, void *);
88c34df0c3Smcr
891fbab2d8Sdrochner static int rbus_do_phys_countspace(pci_chipset_tag_t, pcitag_t, int,
901fbab2d8Sdrochner void *, int, bus_addr_t *, bus_size_t);
91c34df0c3Smcr
921fbab2d8Sdrochner unsigned int rbus_round_up(unsigned int, unsigned int);
93c34df0c3Smcr
94c34df0c3Smcr
95c34df0c3Smcr struct ppb_cardbus_softc {
960d1213e5Sjoerg device_t sc_dev;
97204183c0Sthorpej pcitag_t sc_tag;
98c34df0c3Smcr int foo;
99c34df0c3Smcr };
100c34df0c3Smcr
1010d1213e5Sjoerg CFATTACH_DECL_NEW(rbus_ppb, sizeof(struct ppb_cardbus_softc),
1026d8bb433Sdyoung ppb_cardbus_match, ppb_cardbus_attach, NULL, ppb_activate);
103c34df0c3Smcr
104c34df0c3Smcr #ifdef CBB_DEBUG
105c34df0c3Smcr int rbus_ppb_debug = 0; /* hack with kdb */
106c34df0c3Smcr #define DPRINTF(X) if(rbus_ppb_debug) printf X
107c34df0c3Smcr #else
108c34df0c3Smcr #define DPRINTF(X)
109c34df0c3Smcr #endif
110c34df0c3Smcr
111c34df0c3Smcr static int
ppb_cardbus_match(device_t parent,cfdata_t match,void * aux)112529e91fcScegger ppb_cardbus_match(device_t parent, cfdata_t match, void *aux)
113c34df0c3Smcr {
114c34df0c3Smcr struct cardbus_attach_args *ca = aux;
115c34df0c3Smcr
116508883c1Sdyoung if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_DEC &&
117508883c1Sdyoung PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_DEC_21152)
118c34df0c3Smcr return (1);
119c34df0c3Smcr
120c34df0c3Smcr if(PCI_CLASS(ca->ca_class) == PCI_CLASS_BRIDGE &&
121c34df0c3Smcr PCI_SUBCLASS(ca->ca_class) == PCI_SUBCLASS_BRIDGE_PCI) {
122c34df0c3Smcr /* XXX */
123c34df0c3Smcr printf("recognizing generic bridge chip\n");
124c34df0c3Smcr }
125c34df0c3Smcr
126c34df0c3Smcr return (0);
127c34df0c3Smcr }
128c34df0c3Smcr
129c34df0c3Smcr
130c34df0c3Smcr int
rppbprint(void * aux,const char * pnp)131454af1c0Sdsl rppbprint(void *aux, const char *pnp)
132c34df0c3Smcr {
133c34df0c3Smcr struct pcibus_attach_args *pba = aux;
134c34df0c3Smcr
135c34df0c3Smcr /* only PCIs can attach to PPBs; easy. */
136c34df0c3Smcr if (pnp)
13772a7af27Sthorpej aprint_normal("pci at %s", pnp);
13872a7af27Sthorpej aprint_normal(" bus %d (rbus)", pba->pba_bus);
139c34df0c3Smcr return (UNCONF);
140c34df0c3Smcr }
141c34df0c3Smcr
142c34df0c3Smcr int
rbus_intr_fixup(pci_chipset_tag_t pc,int minbus,int maxbus,int line)143c34df0c3Smcr rbus_intr_fixup(pci_chipset_tag_t pc,
144c34df0c3Smcr int minbus,
145c34df0c3Smcr int maxbus,
146c34df0c3Smcr int line)
147c34df0c3Smcr {
148c34df0c3Smcr pci_device_foreach_min(pc, minbus,
149c34df0c3Smcr maxbus, rbus_do_header_fixup, (void *)&line);
150c34df0c3Smcr return 0;
151c34df0c3Smcr }
152c34df0c3Smcr
153c34df0c3Smcr void
rbus_do_header_fixup(pci_chipset_tag_t pc,pcitag_t tag,void * context)154454af1c0Sdsl rbus_do_header_fixup(pci_chipset_tag_t pc, pcitag_t tag, void *context)
155c34df0c3Smcr {
156c34df0c3Smcr int bus, device, function;
157aa71c16aSuebayasi pcireg_t intr;
158c34df0c3Smcr int *pline = (int *)context;
159c34df0c3Smcr int line = *pline;
160c34df0c3Smcr
161c34df0c3Smcr pci_decompose_tag(pc, tag, &bus, &device, &function);
162c34df0c3Smcr
163c34df0c3Smcr intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
164c34df0c3Smcr
165c34df0c3Smcr intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
166c34df0c3Smcr intr |= (line << PCI_INTERRUPT_LINE_SHIFT);
167c34df0c3Smcr pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
168c34df0c3Smcr
169c34df0c3Smcr }
170c34df0c3Smcr
171c34df0c3Smcr /*
172c34df0c3Smcr * This function takes a range of PCI bus numbers and
173c34df0c3Smcr * allocates space for all devices found in this space (the BARs) from
174c34df0c3Smcr * the rbus space maps (I/O and memory).
175c34df0c3Smcr *
176c34df0c3Smcr * It assumes that "rbus" is defined. The whole concept does.
177c34df0c3Smcr *
178c34df0c3Smcr * It uses pci_device_foreach_min() to call rbus_pci_phys_allocate.
179c34df0c3Smcr * This function is mostly stolen from
180c34df0c3Smcr * pci_addr_fixup.c:pciaddr_resource_reserve.
181c34df0c3Smcr *
182c34df0c3Smcr */
183c34df0c3Smcr struct rbus_pci_addr_fixup_context {
184c34df0c3Smcr struct ppb_cardbus_softc *csc;
185c34df0c3Smcr cardbus_chipset_tag_t ct;
186c34df0c3Smcr struct cardbus_softc *sc;
187c34df0c3Smcr struct cardbus_attach_args *caa;
188c34df0c3Smcr int minbus;
189c34df0c3Smcr int maxbus;
190c34df0c3Smcr bus_size_t *bussize_ioreqs;
191c34df0c3Smcr bus_size_t *bussize_memreqs;
192c34df0c3Smcr rbus_tag_t *iobustags;
193c34df0c3Smcr rbus_tag_t *membustags;
194c34df0c3Smcr };
195c34df0c3Smcr
196c34df0c3Smcr unsigned int
rbus_round_up(unsigned int size,unsigned int minval)1971fbab2d8Sdrochner rbus_round_up(unsigned int size, unsigned int minval)
198c34df0c3Smcr {
199c34df0c3Smcr unsigned int power2;
200c34df0c3Smcr
201c34df0c3Smcr if(size == 0) {
202c34df0c3Smcr return 0;
203c34df0c3Smcr }
204c34df0c3Smcr
2051fbab2d8Sdrochner power2=minval;
206c34df0c3Smcr
207c34df0c3Smcr while(power2 < (1 << 31) &&
208c34df0c3Smcr power2 < size) {
209c34df0c3Smcr power2 = power2 << 1;
210c34df0c3Smcr }
211c34df0c3Smcr
212c34df0c3Smcr return power2;
213c34df0c3Smcr }
214c34df0c3Smcr
215c34df0c3Smcr static void
rbus_pci_addr_fixup(struct ppb_cardbus_softc * csc,cardbus_chipset_tag_t ct,struct cardbus_softc * sc,pci_chipset_tag_t pc,struct cardbus_attach_args * caa,int minbus,const int maxbus)216c34df0c3Smcr rbus_pci_addr_fixup(struct ppb_cardbus_softc *csc,
217c34df0c3Smcr cardbus_chipset_tag_t ct,
218c34df0c3Smcr struct cardbus_softc *sc,
219c34df0c3Smcr pci_chipset_tag_t pc,
220c34df0c3Smcr struct cardbus_attach_args *caa,
22155ce6763Sdyoung int minbus, const int maxbus)
222c34df0c3Smcr {
223c34df0c3Smcr struct rbus_pci_addr_fixup_context rct;
22455ce6763Sdyoung const size_t size = sizeof(bus_size_t[maxbus+1]);
22555ce6763Sdyoung int busnum;
226c34df0c3Smcr bus_addr_t start;
227c34df0c3Smcr bus_space_handle_t handle;
228c34df0c3Smcr u_int32_t reg;
229c34df0c3Smcr
230c34df0c3Smcr rct.csc=csc;
231c34df0c3Smcr rct.ct=ct;
232c34df0c3Smcr rct.sc=sc;
233c34df0c3Smcr rct.caa=caa;
234c34df0c3Smcr rct.minbus = minbus;
235c34df0c3Smcr rct.maxbus = maxbus;
236fd34ea77Schs rct.bussize_ioreqs = kmem_zalloc(size, KM_SLEEP);
237fd34ea77Schs rct.bussize_memreqs = kmem_zalloc(size, KM_SLEEP);
238fd34ea77Schs rct.iobustags = kmem_zalloc(maxbus * sizeof(rbus_tag_t), KM_SLEEP);
239fd34ea77Schs rct.membustags = kmem_zalloc(maxbus * sizeof(rbus_tag_t), KM_SLEEP);
240c34df0c3Smcr
241c34df0c3Smcr printf("%s: sizing buses %d-%d\n",
2420d1213e5Sjoerg device_xname(rct.csc->sc_dev),
243c34df0c3Smcr minbus, maxbus);
244c34df0c3Smcr
245c34df0c3Smcr pci_device_foreach_min(pc, minbus, maxbus,
246c34df0c3Smcr rbus_pci_phys_countspace, &rct);
247c34df0c3Smcr
248c34df0c3Smcr /*
249c34df0c3Smcr * we need to determine amount of address space for each
250c34df0c3Smcr * bus. To do this, we have to roll up amounts and then
251c34df0c3Smcr * we need to divide up the cardbus's extent to allocate
252c34df0c3Smcr * some space to each bus.
253c34df0c3Smcr */
254c34df0c3Smcr
255c34df0c3Smcr for(busnum=maxbus; busnum > minbus; busnum--) {
256c34df0c3Smcr if(pci_bus_parent[busnum] != 0) {
257c34df0c3Smcr if(pci_bus_parent[busnum] < minbus ||
258c34df0c3Smcr pci_bus_parent[busnum] >= maxbus) {
259c34df0c3Smcr printf("%s: bus %d has illegal parent %d\n",
2600d1213e5Sjoerg device_xname(rct.csc->sc_dev),
261c34df0c3Smcr busnum, pci_bus_parent[busnum]);
262c34df0c3Smcr continue;
263c34df0c3Smcr }
264c34df0c3Smcr
265c34df0c3Smcr /* first round amount of space up */
266c34df0c3Smcr rct.bussize_ioreqs[busnum] =
26779770474Smsaitoh rbus_round_up(rct.bussize_ioreqs[busnum], PCI_BRIDGE_IO_MIN);
268c34df0c3Smcr rct.bussize_ioreqs[pci_bus_parent[busnum]] +=
269c34df0c3Smcr rct.bussize_ioreqs[busnum];
270c34df0c3Smcr
271c34df0c3Smcr rct.bussize_memreqs[busnum] =
27279770474Smsaitoh rbus_round_up(rct.bussize_memreqs[busnum], PCI_BRIDGE_MEM_MIN);
273c34df0c3Smcr rct.bussize_memreqs[pci_bus_parent[busnum]] +=
274c34df0c3Smcr rct.bussize_memreqs[busnum];
275c34df0c3Smcr
276c34df0c3Smcr }
277c34df0c3Smcr }
278c34df0c3Smcr
279c34df0c3Smcr rct.bussize_ioreqs[minbus] =
28079770474Smsaitoh rbus_round_up(rct.bussize_ioreqs[minbus], PCI_BRIDGE_IO_MIN);
28179770474Smsaitoh rct.bussize_memreqs[minbus] = /* XXX Not 8 but PCI_BRIDGE_MEM_MIN ? */
282c34df0c3Smcr rbus_round_up(rct.bussize_memreqs[minbus], 8);
283c34df0c3Smcr
28455ce6763Sdyoung printf("%s: total needs IO %08zx and MEM %08zx\n",
2850d1213e5Sjoerg device_xname(rct.csc->sc_dev),
286c34df0c3Smcr rct.bussize_ioreqs[minbus], rct.bussize_memreqs[minbus]);
287c34df0c3Smcr
288c34df0c3Smcr if(!caa->ca_rbus_iot) {
289c34df0c3Smcr panic("no iot bus");
290c34df0c3Smcr }
291c34df0c3Smcr
292c34df0c3Smcr if(rct.bussize_ioreqs[minbus]) {
293c34df0c3Smcr if(rbus_space_alloc(caa->ca_rbus_iot, 0,
294c34df0c3Smcr rct.bussize_ioreqs[minbus],
295c34df0c3Smcr rct.bussize_ioreqs[minbus]-1 /* mask */,
296c34df0c3Smcr rct.bussize_ioreqs[minbus] /* align */,
297c34df0c3Smcr /* flags */ 0,
298c34df0c3Smcr &start,
299c34df0c3Smcr &handle) != 0) {
30055ce6763Sdyoung panic("rbus_ppb: can not allocate %zu bytes in IO bus %d",
301c34df0c3Smcr rct.bussize_ioreqs[minbus], minbus);
302c34df0c3Smcr }
303c34df0c3Smcr rct.iobustags[minbus]=rbus_new(caa->ca_rbus_iot,
304c34df0c3Smcr start,
305c34df0c3Smcr rct.bussize_ioreqs[minbus],
306c34df0c3Smcr 0 /* offset to add to physical address
307c34df0c3Smcr to make processor address */,
308c34df0c3Smcr RBUS_SPACE_DEDICATE);
309c34df0c3Smcr }
310c34df0c3Smcr
311c34df0c3Smcr if(rct.bussize_memreqs[minbus]) {
312c34df0c3Smcr if(rbus_space_alloc(caa->ca_rbus_memt, 0,
313c34df0c3Smcr rct.bussize_memreqs[minbus],
314c34df0c3Smcr rct.bussize_memreqs[minbus]-1 /* mask */,
315c34df0c3Smcr rct.bussize_memreqs[minbus] /* align */,
316c34df0c3Smcr /* flags */ 0,
317c34df0c3Smcr &start,
318c34df0c3Smcr &handle) != 0) {
31955ce6763Sdyoung panic("%s: can not allocate %zu bytes in MEM bus %d",
3200d1213e5Sjoerg device_xname(rct.csc->sc_dev),
321c34df0c3Smcr rct.bussize_memreqs[minbus], minbus);
322c34df0c3Smcr }
323c34df0c3Smcr rct.membustags[minbus]=rbus_new(caa->ca_rbus_memt,
324c34df0c3Smcr start,
325c34df0c3Smcr rct.bussize_memreqs[minbus],
326c34df0c3Smcr 0 /* offset to add to physical
327c34df0c3Smcr address to make processor
328c34df0c3Smcr address */,
329c34df0c3Smcr RBUS_SPACE_DEDICATE);
330c34df0c3Smcr }
331c34df0c3Smcr
332c34df0c3Smcr for(busnum=minbus+1; busnum <= maxbus; busnum++) {
333c34df0c3Smcr int busparent;
334c34df0c3Smcr
335c34df0c3Smcr busparent = pci_bus_parent[busnum];
336c34df0c3Smcr
33755ce6763Sdyoung printf("%s: bus %d (parent=%d) needs IO %08zx and MEM %08zx\n",
3380d1213e5Sjoerg device_xname(rct.csc->sc_dev),
339c34df0c3Smcr busnum,
340c34df0c3Smcr busparent,
341c34df0c3Smcr rct.bussize_ioreqs[busnum],
342c34df0c3Smcr rct.bussize_memreqs[busnum]);
343c34df0c3Smcr
344c34df0c3Smcr if(busparent > maxbus) {
345c34df0c3Smcr panic("rbus_ppb: illegal parent");
346c34df0c3Smcr }
347c34df0c3Smcr
348c34df0c3Smcr if(rct.bussize_ioreqs[busnum]) {
349c34df0c3Smcr if(rbus_space_alloc(rct.iobustags[busparent],
350c34df0c3Smcr 0,
351c34df0c3Smcr rct.bussize_ioreqs[busnum],
352c34df0c3Smcr rct.bussize_ioreqs[busnum]-1 /*mask */,
353c34df0c3Smcr rct.bussize_ioreqs[busnum] /* align */,
354c34df0c3Smcr /* flags */ 0,
355c34df0c3Smcr &start,
356c34df0c3Smcr &handle) != 0) {
35755ce6763Sdyoung panic("rbus_ppb: can not allocate %zu bytes in IO bus %d",
358c34df0c3Smcr rct.bussize_ioreqs[busnum], busnum);
359c34df0c3Smcr }
360c34df0c3Smcr rct.iobustags[busnum]=rbus_new(rct.iobustags[busparent],
361c34df0c3Smcr start,
362c34df0c3Smcr rct.bussize_ioreqs[busnum],
363c34df0c3Smcr 0 /* offset to add to physical
364c34df0c3Smcr address
365c34df0c3Smcr to make processor address */,
366c34df0c3Smcr RBUS_SPACE_DEDICATE);
367c34df0c3Smcr
368c34df0c3Smcr /* program the bridge */
369c34df0c3Smcr
370c34df0c3Smcr /* enable I/O space */
371c34df0c3Smcr reg = pci_conf_read(pc, pci_bus_tag[busnum],
372c34df0c3Smcr PCI_COMMAND_STATUS_REG);
373c34df0c3Smcr reg |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
374c34df0c3Smcr pci_conf_write(pc, pci_bus_tag[busnum],
375c34df0c3Smcr PCI_COMMAND_STATUS_REG, reg);
376c34df0c3Smcr
377c34df0c3Smcr /* now init the limit register for I/O */
37879770474Smsaitoh pci_conf_write(pc, pci_bus_tag[busnum], PCI_BRIDGE_STATIO_REG,
37979770474Smsaitoh __SHIFTIN((start >> 8)
38079770474Smsaitoh & PCI_BRIDGE_STATIO_IOADDR, PCI_BRIDGE_STATIO_IOBASE) |
38179770474Smsaitoh __SHIFTIN(((start + rct.bussize_ioreqs[busnum] + 4095) >> 8)
38279770474Smsaitoh & PCI_BRIDGE_STATIO_IOADDR, PCI_BRIDGE_STATIO_IOLIMIT));
383c34df0c3Smcr }
384c34df0c3Smcr
385c34df0c3Smcr if(rct.bussize_memreqs[busnum]) {
386c34df0c3Smcr if(rbus_space_alloc(rct.membustags[busparent],
387c34df0c3Smcr 0,
388c34df0c3Smcr rct.bussize_memreqs[busnum] /* size */,
389c34df0c3Smcr rct.bussize_memreqs[busnum]-1 /*mask */,
390c34df0c3Smcr rct.bussize_memreqs[busnum] /* align */,
391c34df0c3Smcr /* flags */ 0,
392c34df0c3Smcr &start,
393c34df0c3Smcr &handle) != 0) {
39455ce6763Sdyoung panic("rbus_ppb: can not allocate %zu bytes in MEM bus %d",
395c34df0c3Smcr rct.bussize_memreqs[busnum], busnum);
396c34df0c3Smcr }
397c34df0c3Smcr rct.membustags[busnum]=rbus_new(rct.membustags[busparent],
398c34df0c3Smcr start,
399c34df0c3Smcr rct.bussize_memreqs[busnum],
400c34df0c3Smcr 0 /* offset to add to physical
401c34df0c3Smcr address to make processor
402c34df0c3Smcr address */,
403c34df0c3Smcr RBUS_SPACE_DEDICATE);
404c34df0c3Smcr
405c34df0c3Smcr /* program the bridge */
406c34df0c3Smcr /* enable memory space */
407c34df0c3Smcr reg = pci_conf_read(pc, pci_bus_tag[busnum],
408c34df0c3Smcr PCI_COMMAND_STATUS_REG);
409c34df0c3Smcr reg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
410c34df0c3Smcr pci_conf_write(pc, pci_bus_tag[busnum],
411c34df0c3Smcr PCI_COMMAND_STATUS_REG, reg);
412c34df0c3Smcr
413c34df0c3Smcr /* now init the limit register for memory */
41479770474Smsaitoh pci_conf_write(pc, pci_bus_tag[busnum], PCI_BRIDGE_MEMORY_REG,
41579770474Smsaitoh __SHIFTIN((start >> 16) & PCI_BRIDGE_MEMORY_ADDR,
41679770474Smsaitoh PCI_BRIDGE_MEMORY_BASE) |
417e370c0d5Smsaitoh __SHIFTIN(((start + rct.bussize_memreqs[busnum]
418e370c0d5Smsaitoh + PCI_BRIDGE_MEM_MIN - 1) >> 16)
419e370c0d5Smsaitoh & PCI_BRIDGE_MEMORY_ADDR, PCI_BRIDGE_MEMORY_LIMIT));
420c34df0c3Smcr
421c34df0c3Smcr /* and set the prefetchable limits as well */
42279770474Smsaitoh pci_conf_write(pc, pci_bus_tag[busnum], PCI_BRIDGE_PREFETCHMEM_REG,
42379770474Smsaitoh __SHIFTIN((start >> 16) & PCI_BRIDGE_PREFETCHMEM_ADDR,
42479770474Smsaitoh PCI_BRIDGE_PREFETCHMEM_BASE) |
425e370c0d5Smsaitoh __SHIFTIN(((start + rct.bussize_memreqs[busnum]
426e370c0d5Smsaitoh + PCI_BRIDGE_MEM_MIN - 1) >> 16)
427e370c0d5Smsaitoh & PCI_BRIDGE_PREFETCHMEM_ADDR,
42879770474Smsaitoh PCI_BRIDGE_PREFETCHMEM_LIMIT));
429c34df0c3Smcr
430c34df0c3Smcr /* pci_conf_print(pc, pci_bus_tag[busnum], NULL); */
431c34df0c3Smcr }
432c34df0c3Smcr }
433c34df0c3Smcr
434c34df0c3Smcr printf("%s: configuring buses %d-%d\n",
4350d1213e5Sjoerg device_xname(rct.csc->sc_dev),
436c34df0c3Smcr minbus, maxbus);
437c34df0c3Smcr pci_device_foreach_min(pc, minbus, maxbus,
438c34df0c3Smcr rbus_pci_phys_allocate, &rct);
43955ce6763Sdyoung
44055ce6763Sdyoung kmem_free(rct.bussize_ioreqs, size);
44155ce6763Sdyoung kmem_free(rct.bussize_memreqs, size);
44255ce6763Sdyoung kmem_free(rct.iobustags, maxbus * sizeof(rbus_tag_t));
44355ce6763Sdyoung kmem_free(rct.membustags, maxbus * sizeof(rbus_tag_t));
444c34df0c3Smcr }
445c34df0c3Smcr
446c34df0c3Smcr static void
rbus_pci_phys_countspace(pci_chipset_tag_t pc,pcitag_t tag,void * context)447454af1c0Sdsl rbus_pci_phys_countspace(pci_chipset_tag_t pc, pcitag_t tag, void *context)
448c34df0c3Smcr {
449c34df0c3Smcr int bus, device, function;
450c34df0c3Smcr struct rbus_pci_addr_fixup_context *rct =
451c34df0c3Smcr (struct rbus_pci_addr_fixup_context *)context;
452c34df0c3Smcr
453c34df0c3Smcr pci_decompose_tag(pc, tag, &bus, &device, &function);
454c34df0c3Smcr
455c34df0c3Smcr printf("%s: configuring device %02x:%02x:%02x\n",
4560d1213e5Sjoerg device_xname(rct->csc->sc_dev),
457c34df0c3Smcr bus, device, function);
458c34df0c3Smcr
459c34df0c3Smcr pciaddr_resource_manage(pc, tag,
460c34df0c3Smcr rbus_do_phys_countspace, context);
461c34df0c3Smcr }
462c34df0c3Smcr
463c34df0c3Smcr
464c34df0c3Smcr int
rbus_do_phys_countspace(pci_chipset_tag_t pc,pcitag_t tag,int mapreg,void * ctx,int type,bus_addr_t * addr,bus_size_t size)46582357f6dSdsl rbus_do_phys_countspace(pci_chipset_tag_t pc, pcitag_t tag, int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size)
466c34df0c3Smcr {
467c34df0c3Smcr struct rbus_pci_addr_fixup_context *rct =
468c34df0c3Smcr (struct rbus_pci_addr_fixup_context *)ctx;
469c34df0c3Smcr int bus, device, function;
470c34df0c3Smcr
471c34df0c3Smcr pci_decompose_tag(pc, tag, &bus, &device, &function);
472c34df0c3Smcr
473c34df0c3Smcr if(size > (1<<24)) {
474c34df0c3Smcr printf("%s: skipping huge space request of size=%08x\n",
4750d1213e5Sjoerg device_xname(rct->csc->sc_dev), (unsigned int)size);
476c34df0c3Smcr return 0;
477c34df0c3Smcr }
478c34df0c3Smcr
479c34df0c3Smcr if(PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
480c34df0c3Smcr rct->bussize_ioreqs[bus] += size;
481c34df0c3Smcr } else {
482c34df0c3Smcr rct->bussize_memreqs[bus]+= size;
483c34df0c3Smcr }
484c34df0c3Smcr
485c34df0c3Smcr return 0;
486c34df0c3Smcr }
487c34df0c3Smcr
488c34df0c3Smcr static void
rbus_pci_phys_allocate(pci_chipset_tag_t pc,pcitag_t tag,void * context)489454af1c0Sdsl rbus_pci_phys_allocate(pci_chipset_tag_t pc, pcitag_t tag, void *context)
490c34df0c3Smcr {
491c34df0c3Smcr int bus, device, function, command;
492c34df0c3Smcr struct rbus_pci_addr_fixup_context *rct =
493c34df0c3Smcr (struct rbus_pci_addr_fixup_context *)context;
494c34df0c3Smcr
495c34df0c3Smcr pci_decompose_tag(pc, tag, &bus, &device, &function);
496c34df0c3Smcr
497c34df0c3Smcr printf("%s: configuring device %02x:%02x:%02x\n",
4980d1213e5Sjoerg device_xname(rct->csc->sc_dev),
499c34df0c3Smcr bus, device, function);
500c34df0c3Smcr
501c34df0c3Smcr pciaddr_resource_manage(pc, tag,
502c34df0c3Smcr rbus_do_phys_allocate, context);
503c34df0c3Smcr
504c34df0c3Smcr /* now turn the device's memory and I/O on */
505c34df0c3Smcr command = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
506c34df0c3Smcr command |= PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE;
507c34df0c3Smcr pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, command);
508c34df0c3Smcr }
509c34df0c3Smcr
510c34df0c3Smcr int
rbus_do_phys_allocate(pci_chipset_tag_t pc,pcitag_t tag,int mapreg,void * ctx,int type,bus_addr_t * addr,bus_size_t size)51182357f6dSdsl rbus_do_phys_allocate(pci_chipset_tag_t pc, pcitag_t tag, int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size)
512c34df0c3Smcr {
513c34df0c3Smcr struct rbus_pci_addr_fixup_context *rct =
514c34df0c3Smcr (struct rbus_pci_addr_fixup_context *)ctx;
515c34df0c3Smcr cardbus_chipset_tag_t ct = rct->ct;
516c34df0c3Smcr struct cardbus_softc *sc = rct->sc;
517c34df0c3Smcr cardbus_function_t *cf = sc->sc_cf;
518c34df0c3Smcr rbus_tag_t rbustag;
519c34df0c3Smcr bus_addr_t mask = size -1;
520c34df0c3Smcr bus_addr_t base = 0;
521c34df0c3Smcr bus_space_handle_t handle;
522c34df0c3Smcr int busflags = 0;
523c34df0c3Smcr int flags = 0;
5241fbab2d8Sdrochner const char *bustype;
525c34df0c3Smcr int bus, device, function;
526c34df0c3Smcr
527c34df0c3Smcr pci_decompose_tag(pc, tag, &bus, &device, &function);
528c34df0c3Smcr
529c34df0c3Smcr /*
530c34df0c3Smcr * some devices come up with garbage in them (Tulip?)
531c34df0c3Smcr * we are in charge here, so give them address
532c34df0c3Smcr * space anyway.
533c34df0c3Smcr *
534c34df0c3Smcr * XXX this may be due to no secondary PCI reset!!!
535c34df0c3Smcr */
536c34df0c3Smcr #if 0
537c34df0c3Smcr if (*addr) {
538c34df0c3Smcr printf("Already allocated space at %08x\n",
539c34df0c3Smcr (unsigned int)*addr);
540c34df0c3Smcr return (0);
541c34df0c3Smcr }
542c34df0c3Smcr #endif
543c34df0c3Smcr
544c34df0c3Smcr if(size > (1<<24)) {
545c34df0c3Smcr printf("%s: skipping huge space request of size=%08x\n",
5460d1213e5Sjoerg device_xname(rct->csc->sc_dev), (unsigned int)size);
547c34df0c3Smcr return 0;
548c34df0c3Smcr }
549c34df0c3Smcr
550c34df0c3Smcr if(PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
551c34df0c3Smcr rbustag = rct->iobustags[bus];
552c34df0c3Smcr bustype = "io";
553c34df0c3Smcr } else {
554c34df0c3Smcr rbustag = rct->membustags[bus];
555c34df0c3Smcr bustype = "mem";
556c34df0c3Smcr }
557c34df0c3Smcr
558c34df0c3Smcr if((*cf->cardbus_space_alloc)(ct, rbustag, base, size,
559c34df0c3Smcr mask, size, busflags|flags,
560c34df0c3Smcr addr, &handle)) {
561c34df0c3Smcr printf("%s: no available resources (size=%08x) for bar %2d. fixup failed\n",
5620d1213e5Sjoerg device_xname(rct->csc->sc_dev), (unsigned int)size, mapreg);
563c34df0c3Smcr
564c34df0c3Smcr *addr = 0;
565c34df0c3Smcr pci_conf_write(pc, tag, mapreg, *addr);
566c34df0c3Smcr return (1);
567c34df0c3Smcr }
568c34df0c3Smcr
569c34df0c3Smcr printf("%s: alloc %s space of size %08x for %02d:%02d:%02d -> %08x\n",
5700d1213e5Sjoerg device_xname(rct->csc->sc_dev),
571c34df0c3Smcr bustype,
572c34df0c3Smcr (unsigned int)size,
573c34df0c3Smcr bus, device, function, (unsigned int)*addr);
574c34df0c3Smcr
575c34df0c3Smcr /* write new address to PCI device configuration header */
576c34df0c3Smcr pci_conf_write(pc, tag, mapreg, *addr);
577c34df0c3Smcr
578c34df0c3Smcr /* check */
579c34df0c3Smcr {
580c34df0c3Smcr DPRINTF(("%s: pci_addr_fixup: ",
5810d1213e5Sjoerg device_xname(rct->csc->sc_dev)));
582c34df0c3Smcr #ifdef CBB_DEBUG
583c34df0c3Smcr if(rbus_ppb_debug) { pciaddr_print_devid(pc, tag); }
584c34df0c3Smcr #endif
585c34df0c3Smcr }
586c34df0c3Smcr
587c34df0c3Smcr /* double check that the value got inserted correctly */
588c34df0c3Smcr if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
589c34df0c3Smcr pci_conf_write(pc, tag, mapreg, 0); /* clear */
590c34df0c3Smcr printf("%s: fixup failed. (new address=%#x)\n",
5910d1213e5Sjoerg device_xname(rct->csc->sc_dev),
592c34df0c3Smcr (unsigned)*addr);
593c34df0c3Smcr return (1);
594c34df0c3Smcr }
595c34df0c3Smcr
596c34df0c3Smcr DPRINTF(("new address 0x%08x\n",
597c34df0c3Smcr (unsigned)*addr));
598c34df0c3Smcr
599c34df0c3Smcr return (0);
600c34df0c3Smcr }
601c34df0c3Smcr
602c34df0c3Smcr static void
ppb_cardbus_attach(device_t parent,device_t self,void * aux)6030d1213e5Sjoerg ppb_cardbus_attach(device_t parent, device_t self, void *aux)
604c34df0c3Smcr {
6050bb04182Sthorpej struct ppb_cardbus_softc *csc = device_private(self);
6063d7462a9Sjoerg struct cardbus_softc *parent_sc = device_private(parent);
607c34df0c3Smcr struct cardbus_attach_args *ca = aux;
608c34df0c3Smcr cardbus_devfunc_t ct = ca->ca_ct;
609c34df0c3Smcr cardbus_chipset_tag_t cc = ct->ct_cc;
610c34df0c3Smcr struct pccbb_softc *psc = (struct pccbb_softc *)cc;
611c34df0c3Smcr struct pcibus_attach_args pba;
612c34df0c3Smcr char devinfo[256];
613c34df0c3Smcr pcireg_t busdata;
614c34df0c3Smcr int minbus, maxbus;
615c34df0c3Smcr
6160d1213e5Sjoerg csc->sc_dev = self;
6170d1213e5Sjoerg
61861230437Sitojun pci_devinfo(ca->ca_id, ca->ca_class, 0, devinfo, sizeof(devinfo));
619c34df0c3Smcr printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(ca->ca_class));
620c34df0c3Smcr
6218089c2dcSdyoung csc->sc_tag = ca->ca_tag;
622204183c0Sthorpej
62379770474Smsaitoh busdata = Cardbus_conf_read(ct, ca->ca_tag, PCI_BRIDGE_BUS_REG);
624c34df0c3Smcr minbus = pcibios_max_bus;
625130aed8eSlukem maxbus = minbus; /* XXX; gcc */
626c34df0c3Smcr
62779770474Smsaitoh if (PCI_BRIDGE_BUS_NUM_SECONDARY(busdata) == 0) {
628c0d1e7cbScegger aprint_error_dev(self, "not configured by system firmware calling pci_bus_fixup(%d)\n", 0);
629c34df0c3Smcr
630c34df0c3Smcr /*
631c34df0c3Smcr * first, pull the reset wire on the secondary bridge
632c34df0c3Smcr * to clear all devices
633c34df0c3Smcr */
63479770474Smsaitoh busdata = Cardbus_conf_read(ct, ca->ca_tag, PCI_BRIDGE_CONTROL_REG);
63579770474Smsaitoh Cardbus_conf_write(ct, ca->ca_tag, PCI_BRIDGE_CONTROL_REG,
63679770474Smsaitoh busdata | PCI_BRIDGE_CONTROL_SECBR);
637c34df0c3Smcr delay(1);
63879770474Smsaitoh Cardbus_conf_write(ct, ca->ca_tag, PCI_BRIDGE_CONTROL_REG,
639c34df0c3Smcr busdata);
640c34df0c3Smcr
641c34df0c3Smcr /* then go initialize the bridge control registers */
642c34df0c3Smcr maxbus = pci_bus_fixup(psc->sc_pc, 0);
643c34df0c3Smcr }
644c34df0c3Smcr
64579770474Smsaitoh busdata = Cardbus_conf_read(ct, ca->ca_tag, PCI_BRIDGE_BUS_REG);
64679770474Smsaitoh if(PCI_BRIDGE_BUS_NUM_SECONDARY(busdata) == 0) {
647c0d1e7cbScegger aprint_error_dev(self, "still not configured, not fixable.\n");
648c34df0c3Smcr return;
649c34df0c3Smcr }
650c34df0c3Smcr
651c34df0c3Smcr #if 0
65279770474Smsaitoh minbus = PCI_BRIDGE_BUS_NUM_SECONDARY(busdata);
65379770474Smsaitoh maxbus = PCI_BRIDGE_BUS_NUM_SUBORDINATE(busdata);
654c34df0c3Smcr #endif
655c34df0c3Smcr
656c34df0c3Smcr /* now, go and assign addresses for the new devices */
657c34df0c3Smcr rbus_pci_addr_fixup(csc, cc, parent_sc,
658c34df0c3Smcr psc->sc_pc,
659c34df0c3Smcr ca,
660c34df0c3Smcr minbus, maxbus);
661c34df0c3Smcr
662c34df0c3Smcr /*
663c34df0c3Smcr * now configure all connected devices to the IRQ which
664c34df0c3Smcr * was assigned to this slot, as they will all arrive from
665c34df0c3Smcr * that IRQ.
666c34df0c3Smcr */
6671ca3ef38Sdrochner rbus_intr_fixup(psc->sc_pc, minbus, maxbus, 0);
668c34df0c3Smcr
669c34df0c3Smcr /*
670c34df0c3Smcr * enable direct routing of interrupts. We do this because
671c34df0c3Smcr * we can not manage to get pccb_intr_establish() called until
672c34df0c3Smcr * PCI subsystem is merged with rbus. The major thing that this
673c34df0c3Smcr * routine does is avoid calling the driver's interrupt routine
674c34df0c3Smcr * when the card has been removed.
675c34df0c3Smcr *
676c34df0c3Smcr * The rbus_ppb.c can not cope with card desertions until the merging
677c34df0c3Smcr * anyway.
678c34df0c3Smcr */
679c34df0c3Smcr pccbb_intr_route(psc);
680c34df0c3Smcr
681c34df0c3Smcr /*
682c34df0c3Smcr * Attach the PCI bus than hangs off of it.
683c34df0c3Smcr *
684c34df0c3Smcr * XXX Don't pass-through Memory Read Multiple. Should we?
685c34df0c3Smcr * XXX Consult the spec...
686c34df0c3Smcr */
687c34df0c3Smcr pba.pba_iot = ca->ca_iot;
688c34df0c3Smcr pba.pba_memt = ca->ca_memt;
689c34df0c3Smcr pba.pba_dmat = ca->ca_dmat;
690c34df0c3Smcr pba.pba_pc = psc->sc_pc;
691a6b2b839Sdyoung pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY;
69279770474Smsaitoh pba.pba_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(busdata);
693cfb25c83Slukem pba.pba_bridgetag = &csc->sc_tag;
694c34df0c3Smcr /*pba.pba_intrswiz = parent_sc->sc_intrswiz; */
695c34df0c3Smcr pba.pba_intrtag = psc->sc_pa.pa_intrtag;
696c34df0c3Smcr
697c7fb772bSthorpej config_found(self, &pba, rppbprint, CFARGS_NONE);
698c34df0c3Smcr }
699c34df0c3Smcr
700c34df0c3Smcr int
ppb_activate(device_t self,enum devact act)701529e91fcScegger ppb_activate(device_t self, enum devact act)
702c34df0c3Smcr {
703c34df0c3Smcr printf("ppb_activate called\n");
704c34df0c3Smcr return 0;
705c34df0c3Smcr }
706