13aef8050SSepherosa Ziehau /*-
23aef8050SSepherosa Ziehau * Copyright (c) 2002-2004 M. Warner Losh.
33aef8050SSepherosa Ziehau * Copyright (c) 2000-2001 Jonathan Chen.
4666d2603SJoerg Sonnenberger * All rights reserved.
5666d2603SJoerg Sonnenberger *
6666d2603SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
7666d2603SJoerg Sonnenberger * modification, are permitted provided that the following conditions
8666d2603SJoerg Sonnenberger * are met:
9666d2603SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
103aef8050SSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
11666d2603SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
123aef8050SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
133aef8050SSepherosa Ziehau * documentation and/or other materials provided with the distribution.
14666d2603SJoerg Sonnenberger *
15666d2603SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16666d2603SJoerg Sonnenberger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17666d2603SJoerg Sonnenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183aef8050SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193aef8050SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20666d2603SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21666d2603SJoerg Sonnenberger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22666d2603SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23666d2603SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24666d2603SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25666d2603SJoerg Sonnenberger * SUCH DAMAGE.
26666d2603SJoerg Sonnenberger *
273aef8050SSepherosa Ziehau * $FreeBSD: src/sys/dev/pccbb/pccbb.c,v 1.126 2005/07/17 19:40:05 imp Exp $
283aef8050SSepherosa Ziehau * $DragonFly: src/sys/dev/pccard/pccbb/pccbb.c,v 1.21 2007/07/05 12:08:54 sephe Exp $
29666d2603SJoerg Sonnenberger */
30666d2603SJoerg Sonnenberger
313aef8050SSepherosa Ziehau /*-
32666d2603SJoerg Sonnenberger * Copyright (c) 1998, 1999 and 2000
33666d2603SJoerg Sonnenberger * HAYAKAWA Koichi. All rights reserved.
34666d2603SJoerg Sonnenberger *
35666d2603SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
36666d2603SJoerg Sonnenberger * modification, are permitted provided that the following conditions
37666d2603SJoerg Sonnenberger * are met:
38666d2603SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
39666d2603SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
40666d2603SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
41666d2603SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
42666d2603SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
43666d2603SJoerg Sonnenberger * 3. All advertising materials mentioning features or use of this software
44666d2603SJoerg Sonnenberger * must display the following acknowledgement:
45666d2603SJoerg Sonnenberger * This product includes software developed by HAYAKAWA Koichi.
46666d2603SJoerg Sonnenberger * 4. The name of the author may not be used to endorse or promote products
47666d2603SJoerg Sonnenberger * derived from this software without specific prior written permission.
48666d2603SJoerg Sonnenberger *
49666d2603SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
50666d2603SJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51666d2603SJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52666d2603SJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
53666d2603SJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
54666d2603SJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55666d2603SJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56666d2603SJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57666d2603SJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
58666d2603SJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59666d2603SJoerg Sonnenberger */
60666d2603SJoerg Sonnenberger
61666d2603SJoerg Sonnenberger /*
62666d2603SJoerg Sonnenberger * Driver for PCI to CardBus Bridge chips
633aef8050SSepherosa Ziehau * and PCI to PCMCIA Bridge chips
643aef8050SSepherosa Ziehau * and ISA to PCMCIA host adapters
653aef8050SSepherosa Ziehau * and C Bus to PCMCIA host adapters
66666d2603SJoerg Sonnenberger *
67666d2603SJoerg Sonnenberger * References:
68666d2603SJoerg Sonnenberger * TI Datasheets:
69666d2603SJoerg Sonnenberger * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS
70666d2603SJoerg Sonnenberger *
71666d2603SJoerg Sonnenberger * Written by Jonathan Chen <jon@freebsd.org>
72666d2603SJoerg Sonnenberger * The author would like to acknowledge:
73666d2603SJoerg Sonnenberger * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing
74666d2603SJoerg Sonnenberger * * Warner Losh: Newbus/newcard guru and author of the pccard side of things
75666d2603SJoerg Sonnenberger * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver
76666d2603SJoerg Sonnenberger * * David Cross: Author of the initial ugly hack for a specific cardbus card
77666d2603SJoerg Sonnenberger */
78666d2603SJoerg Sonnenberger
79666d2603SJoerg Sonnenberger #include <sys/param.h>
803aef8050SSepherosa Ziehau #include <sys/bus.h>
81666d2603SJoerg Sonnenberger #include <sys/errno.h>
82f5100ab5SMatthew Dillon #include <sys/interrupt.h>
83666d2603SJoerg Sonnenberger #include <sys/kernel.h>
843aef8050SSepherosa Ziehau #include <sys/module.h>
853aef8050SSepherosa Ziehau #include <sys/kthread.h>
86666d2603SJoerg Sonnenberger #include <sys/lock.h>
87666d2603SJoerg Sonnenberger #include <sys/malloc.h>
883aef8050SSepherosa Ziehau #include <sys/proc.h>
89666d2603SJoerg Sonnenberger #include <sys/rman.h>
903aef8050SSepherosa Ziehau #include <sys/sysctl.h>
913aef8050SSepherosa Ziehau #include <sys/systm.h>
92cd8ab232SMatthew Dillon
933aef8050SSepherosa Ziehau #include <sys/thread2.h>
94cd8ab232SMatthew Dillon #include <sys/mplock2.h>
95666d2603SJoerg Sonnenberger
96666d2603SJoerg Sonnenberger #include <bus/pci/pcireg.h>
97666d2603SJoerg Sonnenberger #include <bus/pci/pcivar.h>
98666d2603SJoerg Sonnenberger #include <machine/clock.h>
99666d2603SJoerg Sonnenberger
100666d2603SJoerg Sonnenberger #include <bus/pccard/pccardreg.h>
101666d2603SJoerg Sonnenberger #include <bus/pccard/pccardvar.h>
102666d2603SJoerg Sonnenberger
103666d2603SJoerg Sonnenberger #include <dev/pccard/exca/excareg.h>
104666d2603SJoerg Sonnenberger #include <dev/pccard/exca/excavar.h>
105666d2603SJoerg Sonnenberger
106666d2603SJoerg Sonnenberger #include <dev/pccard/pccbb/pccbbreg.h>
107666d2603SJoerg Sonnenberger #include <dev/pccard/pccbb/pccbbvar.h>
108666d2603SJoerg Sonnenberger
109666d2603SJoerg Sonnenberger #include "power_if.h"
110666d2603SJoerg Sonnenberger #include "card_if.h"
111666d2603SJoerg Sonnenberger #include "pcib_if.h"
112666d2603SJoerg Sonnenberger
113e3869ec7SSascha Wildner #define DPRINTF(x) do { if (cbb_debug) kprintf x; } while (0)
114666d2603SJoerg Sonnenberger #define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
115666d2603SJoerg Sonnenberger
116666d2603SJoerg Sonnenberger #define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \
117666d2603SJoerg Sonnenberger pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE)
118666d2603SJoerg Sonnenberger #define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \
119666d2603SJoerg Sonnenberger pci_write_config(DEV, REG, ( \
120666d2603SJoerg Sonnenberger pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE)
121666d2603SJoerg Sonnenberger
1223aef8050SSepherosa Ziehau #define CBB_CARD_PRESENT(s) ((s & CBB_STATE_CD) == 0)
1233aef8050SSepherosa Ziehau
124666d2603SJoerg Sonnenberger #define CBB_START_MEM 0x88000000
125666d2603SJoerg Sonnenberger #define CBB_START_32_IO 0x1000
126666d2603SJoerg Sonnenberger #define CBB_START_16_IO 0x100
127666d2603SJoerg Sonnenberger
1283aef8050SSepherosa Ziehau devclass_t cbb_devclass;
129666d2603SJoerg Sonnenberger
130666d2603SJoerg Sonnenberger /* sysctl vars */
131666d2603SJoerg Sonnenberger SYSCTL_NODE(_hw, OID_AUTO, cbb, CTLFLAG_RD, 0, "CBB parameters");
132666d2603SJoerg Sonnenberger
133666d2603SJoerg Sonnenberger /* There's no way to say TUNEABLE_LONG to get the right types */
134666d2603SJoerg Sonnenberger u_long cbb_start_mem = CBB_START_MEM;
135da44240fSMatthew Dillon TUNABLE_ULONG("hw.cbb.start_memory", &cbb_start_mem);
136666d2603SJoerg Sonnenberger SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_memory, CTLFLAG_RW,
137666d2603SJoerg Sonnenberger &cbb_start_mem, CBB_START_MEM,
138666d2603SJoerg Sonnenberger "Starting address for memory allocations");
139666d2603SJoerg Sonnenberger
140666d2603SJoerg Sonnenberger u_long cbb_start_16_io = CBB_START_16_IO;
141da44240fSMatthew Dillon TUNABLE_ULONG("hw.cbb.start_16_io", &cbb_start_16_io);
142666d2603SJoerg Sonnenberger SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_16_io, CTLFLAG_RW,
143666d2603SJoerg Sonnenberger &cbb_start_16_io, CBB_START_16_IO,
144666d2603SJoerg Sonnenberger "Starting ioport for 16-bit cards");
145666d2603SJoerg Sonnenberger
146666d2603SJoerg Sonnenberger u_long cbb_start_32_io = CBB_START_32_IO;
147da44240fSMatthew Dillon TUNABLE_ULONG("hw.cbb.start_32_io", &cbb_start_32_io);
148666d2603SJoerg Sonnenberger SYSCTL_ULONG(_hw_cbb, OID_AUTO, start_32_io, CTLFLAG_RW,
149666d2603SJoerg Sonnenberger &cbb_start_32_io, CBB_START_32_IO,
150666d2603SJoerg Sonnenberger "Starting ioport for 32-bit cards");
151666d2603SJoerg Sonnenberger
152666d2603SJoerg Sonnenberger int cbb_debug = 0;
153666d2603SJoerg Sonnenberger TUNABLE_INT("hw.cbb.debug", &cbb_debug);
154666d2603SJoerg Sonnenberger SYSCTL_ULONG(_hw_cbb, OID_AUTO, debug, CTLFLAG_RW, &cbb_debug, 0,
155666d2603SJoerg Sonnenberger "Verbose cardbus bridge debugging");
156666d2603SJoerg Sonnenberger
157666d2603SJoerg Sonnenberger static void cbb_insert(struct cbb_softc *sc);
158666d2603SJoerg Sonnenberger static void cbb_removal(struct cbb_softc *sc);
1593aef8050SSepherosa Ziehau static uint32_t cbb_detect_voltage(device_t brdev);
160666d2603SJoerg Sonnenberger static void cbb_cardbus_reset(device_t brdev);
161666d2603SJoerg Sonnenberger static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start,
162666d2603SJoerg Sonnenberger uint32_t end);
163666d2603SJoerg Sonnenberger static int cbb_cardbus_mem_open(device_t brdev, int win,
164666d2603SJoerg Sonnenberger uint32_t start, uint32_t end);
165666d2603SJoerg Sonnenberger static void cbb_cardbus_auto_open(struct cbb_softc *sc, int type);
166666d2603SJoerg Sonnenberger static int cbb_cardbus_activate_resource(device_t brdev, device_t child,
167666d2603SJoerg Sonnenberger int type, int rid, struct resource *res);
168666d2603SJoerg Sonnenberger static int cbb_cardbus_deactivate_resource(device_t brdev,
169666d2603SJoerg Sonnenberger device_t child, int type, int rid, struct resource *res);
170666d2603SJoerg Sonnenberger static struct resource *cbb_cardbus_alloc_resource(device_t brdev,
171666d2603SJoerg Sonnenberger device_t child, int type, int *rid, u_long start,
1724f7fe8c7SSepherosa Ziehau u_long end, u_long count, u_int flags, int cpuid);
173666d2603SJoerg Sonnenberger static int cbb_cardbus_release_resource(device_t brdev, device_t child,
174666d2603SJoerg Sonnenberger int type, int rid, struct resource *res);
1753aef8050SSepherosa Ziehau static int cbb_cardbus_power_enable_socket(device_t brdev,
1763aef8050SSepherosa Ziehau device_t child);
1773aef8050SSepherosa Ziehau static void cbb_cardbus_power_disable_socket(device_t brdev,
1783aef8050SSepherosa Ziehau device_t child);
1793aef8050SSepherosa Ziehau static void cbb_func_intr(void *arg);
180666d2603SJoerg Sonnenberger
181666d2603SJoerg Sonnenberger static void
cbb_remove_res(struct cbb_softc * sc,struct resource * res)182666d2603SJoerg Sonnenberger cbb_remove_res(struct cbb_softc *sc, struct resource *res)
183666d2603SJoerg Sonnenberger {
184666d2603SJoerg Sonnenberger struct cbb_reslist *rle;
185666d2603SJoerg Sonnenberger
186666d2603SJoerg Sonnenberger SLIST_FOREACH(rle, &sc->rl, link) {
187666d2603SJoerg Sonnenberger if (rle->res == res) {
188666d2603SJoerg Sonnenberger SLIST_REMOVE(&sc->rl, rle, cbb_reslist, link);
189efda3bd0SMatthew Dillon kfree(rle, M_DEVBUF);
190666d2603SJoerg Sonnenberger return;
191666d2603SJoerg Sonnenberger }
192666d2603SJoerg Sonnenberger }
193666d2603SJoerg Sonnenberger }
194666d2603SJoerg Sonnenberger
195666d2603SJoerg Sonnenberger static struct resource *
cbb_find_res(struct cbb_softc * sc,int type,int rid)196666d2603SJoerg Sonnenberger cbb_find_res(struct cbb_softc *sc, int type, int rid)
197666d2603SJoerg Sonnenberger {
198666d2603SJoerg Sonnenberger struct cbb_reslist *rle;
199666d2603SJoerg Sonnenberger
200666d2603SJoerg Sonnenberger SLIST_FOREACH(rle, &sc->rl, link)
201666d2603SJoerg Sonnenberger if (SYS_RES_MEMORY == rle->type && rid == rle->rid)
202666d2603SJoerg Sonnenberger return (rle->res);
203666d2603SJoerg Sonnenberger return (NULL);
204666d2603SJoerg Sonnenberger }
205666d2603SJoerg Sonnenberger
2063aef8050SSepherosa Ziehau static void
cbb_insert_res(struct cbb_softc * sc,struct resource * res,int type,int rid)207666d2603SJoerg Sonnenberger cbb_insert_res(struct cbb_softc *sc, struct resource *res, int type,
208666d2603SJoerg Sonnenberger int rid)
209666d2603SJoerg Sonnenberger {
210666d2603SJoerg Sonnenberger struct cbb_reslist *rle;
211666d2603SJoerg Sonnenberger
212666d2603SJoerg Sonnenberger /*
213666d2603SJoerg Sonnenberger * Need to record allocated resource so we can iterate through
214666d2603SJoerg Sonnenberger * it later.
215666d2603SJoerg Sonnenberger */
216efda3bd0SMatthew Dillon rle = kmalloc(sizeof(struct cbb_reslist), M_DEVBUF, M_NOWAIT);
2174b87c318SSimon Schubert if (rle == NULL)
2183aef8050SSepherosa Ziehau panic("cbb_cardbus_alloc_resource: can't record entry!");
219666d2603SJoerg Sonnenberger rle->res = res;
220666d2603SJoerg Sonnenberger rle->type = type;
221666d2603SJoerg Sonnenberger rle->rid = rid;
222666d2603SJoerg Sonnenberger SLIST_INSERT_HEAD(&sc->rl, rle, link);
223666d2603SJoerg Sonnenberger }
224666d2603SJoerg Sonnenberger
225666d2603SJoerg Sonnenberger static void
cbb_destroy_res(struct cbb_softc * sc)226666d2603SJoerg Sonnenberger cbb_destroy_res(struct cbb_softc *sc)
227666d2603SJoerg Sonnenberger {
228666d2603SJoerg Sonnenberger struct cbb_reslist *rle;
229666d2603SJoerg Sonnenberger
230666d2603SJoerg Sonnenberger while ((rle = SLIST_FIRST(&sc->rl)) != NULL) {
231666d2603SJoerg Sonnenberger device_printf(sc->dev, "Danger Will Robinson: Resource "
232666d2603SJoerg Sonnenberger "left allocated! This is a bug... "
233666d2603SJoerg Sonnenberger "(rid=%x, type=%d, addr=%lx)\n", rle->rid, rle->type,
234666d2603SJoerg Sonnenberger rman_get_start(rle->res));
235666d2603SJoerg Sonnenberger SLIST_REMOVE_HEAD(&sc->rl, link);
236efda3bd0SMatthew Dillon kfree(rle, M_DEVBUF);
237666d2603SJoerg Sonnenberger }
238666d2603SJoerg Sonnenberger }
239666d2603SJoerg Sonnenberger
240666d2603SJoerg Sonnenberger /*
2413aef8050SSepherosa Ziehau * Disable function interrupts by telling the bridge to generate IRQ1
2423aef8050SSepherosa Ziehau * interrupts. These interrupts aren't really generated by the chip, since
2433aef8050SSepherosa Ziehau * IRQ1 is reserved. Some chipsets assert INTA# inappropriately during
2443aef8050SSepherosa Ziehau * initialization, so this helps to work around the problem.
245666d2603SJoerg Sonnenberger *
2463aef8050SSepherosa Ziehau * XXX We can't do this workaround for all chipsets, because this
2473aef8050SSepherosa Ziehau * XXX causes interference with the keyboard because somechipsets will
2483aef8050SSepherosa Ziehau * XXX actually signal IRQ1 over their serial interrupt connections to
2493aef8050SSepherosa Ziehau * XXX the south bridge. Disable it it for now.
250666d2603SJoerg Sonnenberger */
2513c89d513SMatthew Dillon void
cbb_disable_func_intr(struct cbb_softc * sc)2523aef8050SSepherosa Ziehau cbb_disable_func_intr(struct cbb_softc *sc)
2533c89d513SMatthew Dillon {
2543aef8050SSepherosa Ziehau #if 0
2553aef8050SSepherosa Ziehau uint8_t reg;
2563aef8050SSepherosa Ziehau reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
2573aef8050SSepherosa Ziehau EXCA_INTR_IRQ_RESERVED1;
2583aef8050SSepherosa Ziehau exca_putb(&sc->exca[0], EXCA_INTR, reg);
2593aef8050SSepherosa Ziehau #endif
2603c89d513SMatthew Dillon }
2613c89d513SMatthew Dillon
2623c89d513SMatthew Dillon /*
2633aef8050SSepherosa Ziehau * Enable function interrupts. We turn on function interrupts when the card
2643aef8050SSepherosa Ziehau * requests an interrupt. The PCMCIA standard says that we should set
2653aef8050SSepherosa Ziehau * the lower 4 bits to 0 to route via PCI. Note: we call this for both
2663aef8050SSepherosa Ziehau * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus
2673aef8050SSepherosa Ziehau * cards.
2683c89d513SMatthew Dillon */
2693aef8050SSepherosa Ziehau static void
cbb_enable_func_intr(struct cbb_softc * sc)2703aef8050SSepherosa Ziehau cbb_enable_func_intr(struct cbb_softc *sc)
2713aef8050SSepherosa Ziehau {
2723aef8050SSepherosa Ziehau uint8_t reg;
2733c89d513SMatthew Dillon
2743aef8050SSepherosa Ziehau reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
2753aef8050SSepherosa Ziehau EXCA_INTR_IRQ_NONE;
2763aef8050SSepherosa Ziehau exca_putb(&sc->exca[0], EXCA_INTR, reg);
2773c89d513SMatthew Dillon }
2783c89d513SMatthew Dillon
2793aef8050SSepherosa Ziehau int
cbb_detach(device_t brdev)280666d2603SJoerg Sonnenberger cbb_detach(device_t brdev)
281666d2603SJoerg Sonnenberger {
2823aef8050SSepherosa Ziehau struct cbb_softc *sc = device_get_softc(brdev);
2833c89d513SMatthew Dillon int numdevs;
2843aef8050SSepherosa Ziehau device_t *devlist;
2853aef8050SSepherosa Ziehau int tmp;
286666d2603SJoerg Sonnenberger int error;
287666d2603SJoerg Sonnenberger
288666d2603SJoerg Sonnenberger device_get_children(brdev, &devlist, &numdevs);
289666d2603SJoerg Sonnenberger
290666d2603SJoerg Sonnenberger error = 0;
2913aef8050SSepherosa Ziehau for (tmp = 0; tmp < numdevs; tmp++) {
2923aef8050SSepherosa Ziehau if (device_detach(devlist[tmp]) == 0)
2933aef8050SSepherosa Ziehau device_delete_child(brdev, devlist[tmp]);
294666d2603SJoerg Sonnenberger else
295666d2603SJoerg Sonnenberger error++;
296666d2603SJoerg Sonnenberger }
297efda3bd0SMatthew Dillon kfree(devlist, M_TEMP);
2983aef8050SSepherosa Ziehau if (error > 0)
2993aef8050SSepherosa Ziehau return (ENXIO);
300666d2603SJoerg Sonnenberger
3013c89d513SMatthew Dillon /*
3023aef8050SSepherosa Ziehau * XXX do we teardown all the ones still registered to guard against
3033aef8050SSepherosa Ziehau * XXX buggy client drivers?
3043c89d513SMatthew Dillon */
3053aef8050SSepherosa Ziehau bus_teardown_intr(brdev, sc->irq_res, sc->intrhand);
3063aef8050SSepherosa Ziehau sc->flags |= CBB_KTHREAD_DONE;
3073aef8050SSepherosa Ziehau if (sc->flags & CBB_KTHREAD_RUNNING) {
3083aef8050SSepherosa Ziehau crit_enter();
3093aef8050SSepherosa Ziehau wakeup(&sc->generic_cv);
3103aef8050SSepherosa Ziehau tsleep(sc->event_thread, 0, "cbbun", 0);
3113aef8050SSepherosa Ziehau crit_exit();
3123aef8050SSepherosa Ziehau }
3133aef8050SSepherosa Ziehau
3143aef8050SSepherosa Ziehau bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
3153aef8050SSepherosa Ziehau bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
3163aef8050SSepherosa Ziehau sc->base_res);
3173aef8050SSepherosa Ziehau return (0);
3183aef8050SSepherosa Ziehau }
3193aef8050SSepherosa Ziehau
3203aef8050SSepherosa Ziehau int
cbb_shutdown(device_t brdev)3213aef8050SSepherosa Ziehau cbb_shutdown(device_t brdev)
3223aef8050SSepherosa Ziehau {
3233aef8050SSepherosa Ziehau struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
3243aef8050SSepherosa Ziehau /* properly reset everything at shutdown */
3253aef8050SSepherosa Ziehau
3263aef8050SSepherosa Ziehau PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2);
3273aef8050SSepherosa Ziehau exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
3283aef8050SSepherosa Ziehau
3293aef8050SSepherosa Ziehau cbb_set(sc, CBB_SOCKET_MASK, 0);
3303aef8050SSepherosa Ziehau
3313aef8050SSepherosa Ziehau cbb_power(brdev, CARD_OFF);
3323aef8050SSepherosa Ziehau
3333aef8050SSepherosa Ziehau exca_putb(&sc->exca[0], EXCA_ADDRWIN_ENABLE, 0);
3343aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_MEMBASE0, 0, 4);
3353aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_MEMLIMIT0, 0, 4);
3363aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_MEMBASE1, 0, 4);
3373aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_MEMLIMIT1, 0, 4);
3383aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_IOBASE0, 0, 4);
3393aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_IOLIMIT0, 0, 4);
3403aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_IOBASE1, 0, 4);
3413aef8050SSepherosa Ziehau pci_write_config(brdev, CBBR_IOLIMIT1, 0, 4);
342666d2603SJoerg Sonnenberger pci_write_config(brdev, PCIR_COMMAND, 0, 2);
343666d2603SJoerg Sonnenberger return (0);
344666d2603SJoerg Sonnenberger }
345666d2603SJoerg Sonnenberger
3463aef8050SSepherosa Ziehau int
cbb_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_intr_t * intr,void * arg,void ** cookiep,lwkt_serialize_t serializer,const char * desc)347666d2603SJoerg Sonnenberger cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
348e9cb6d99SMatthew Dillon int flags, driver_intr_t *intr, void *arg,
349*0e6f0e28SSepherosa Ziehau void **cookiep, lwkt_serialize_t serializer, const char *desc)
350666d2603SJoerg Sonnenberger {
351666d2603SJoerg Sonnenberger struct cbb_intrhand *ih;
352666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(dev);
3533aef8050SSepherosa Ziehau int err;
354666d2603SJoerg Sonnenberger
3553aef8050SSepherosa Ziehau ih = kmalloc(sizeof(struct cbb_intrhand), M_DEVBUF, M_NOWAIT);
356666d2603SJoerg Sonnenberger if (ih == NULL)
357666d2603SJoerg Sonnenberger return (ENOMEM);
358666d2603SJoerg Sonnenberger *cookiep = ih;
359666d2603SJoerg Sonnenberger ih->intr = intr;
360666d2603SJoerg Sonnenberger ih->arg = arg;
3613aef8050SSepherosa Ziehau ih->sc = sc;
362f5100ab5SMatthew Dillon ih->serializer = serializer;
363666d2603SJoerg Sonnenberger /*
364666d2603SJoerg Sonnenberger * XXX need to turn on ISA interrupts, if we ever support them, but
365666d2603SJoerg Sonnenberger * XXX for now that's all we need to do.
366666d2603SJoerg Sonnenberger */
3673aef8050SSepherosa Ziehau err = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags,
368*0e6f0e28SSepherosa Ziehau cbb_func_intr, ih, &ih->cookie, NULL, desc);
3693aef8050SSepherosa Ziehau if (err != 0) {
3703aef8050SSepherosa Ziehau kfree(ih, M_DEVBUF);
3713aef8050SSepherosa Ziehau return (err);
3723aef8050SSepherosa Ziehau }
3733aef8050SSepherosa Ziehau cbb_enable_func_intr(sc);
3743aef8050SSepherosa Ziehau sc->flags |= CBB_CARD_OK;
3753aef8050SSepherosa Ziehau return 0;
376666d2603SJoerg Sonnenberger }
377666d2603SJoerg Sonnenberger
3783aef8050SSepherosa Ziehau int
cbb_teardown_intr(device_t dev,device_t child,struct resource * irq,void * cookie)379666d2603SJoerg Sonnenberger cbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
380666d2603SJoerg Sonnenberger void *cookie)
381666d2603SJoerg Sonnenberger {
382666d2603SJoerg Sonnenberger struct cbb_intrhand *ih;
3833aef8050SSepherosa Ziehau int err;
384666d2603SJoerg Sonnenberger
385666d2603SJoerg Sonnenberger /* XXX Need to do different things for ISA interrupts. */
386666d2603SJoerg Sonnenberger ih = (struct cbb_intrhand *) cookie;
3873aef8050SSepherosa Ziehau err = BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq,
3883aef8050SSepherosa Ziehau ih->cookie);
3893aef8050SSepherosa Ziehau if (err != 0)
3903aef8050SSepherosa Ziehau return (err);
391efda3bd0SMatthew Dillon kfree(ih, M_DEVBUF);
392666d2603SJoerg Sonnenberger return (0);
393666d2603SJoerg Sonnenberger }
394666d2603SJoerg Sonnenberger
395666d2603SJoerg Sonnenberger
3963aef8050SSepherosa Ziehau void
cbb_driver_added(device_t brdev,driver_t * driver)397666d2603SJoerg Sonnenberger cbb_driver_added(device_t brdev, driver_t *driver)
398666d2603SJoerg Sonnenberger {
399666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
400666d2603SJoerg Sonnenberger device_t *devlist;
4013aef8050SSepherosa Ziehau device_t dev;
402666d2603SJoerg Sonnenberger int tmp;
403666d2603SJoerg Sonnenberger int numdevs;
4043aef8050SSepherosa Ziehau int wake = 0;
405666d2603SJoerg Sonnenberger
406666d2603SJoerg Sonnenberger DEVICE_IDENTIFY(driver, brdev);
407666d2603SJoerg Sonnenberger device_get_children(brdev, &devlist, &numdevs);
408666d2603SJoerg Sonnenberger for (tmp = 0; tmp < numdevs; tmp++) {
4093aef8050SSepherosa Ziehau dev = devlist[tmp];
4103aef8050SSepherosa Ziehau if (device_get_state(dev) == DS_NOTPRESENT &&
4113aef8050SSepherosa Ziehau device_probe_and_attach(dev) == 0)
412666d2603SJoerg Sonnenberger wake++;
413666d2603SJoerg Sonnenberger }
414efda3bd0SMatthew Dillon kfree(devlist, M_TEMP);
415666d2603SJoerg Sonnenberger
4163aef8050SSepherosa Ziehau if (wake > 0)
4173aef8050SSepherosa Ziehau wakeup_one(&sc->generic_cv);
418666d2603SJoerg Sonnenberger }
419666d2603SJoerg Sonnenberger
4203aef8050SSepherosa Ziehau void
cbb_child_detached(device_t brdev,device_t child)421666d2603SJoerg Sonnenberger cbb_child_detached(device_t brdev, device_t child)
422666d2603SJoerg Sonnenberger {
423666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
424666d2603SJoerg Sonnenberger
4253aef8050SSepherosa Ziehau if (child != sc->cbdev && child != sc->exca[0].pccarddev)
4263aef8050SSepherosa Ziehau device_printf(brdev, "Unknown child detached: %s\n",
4273aef8050SSepherosa Ziehau device_get_nameunit(child));
428666d2603SJoerg Sonnenberger }
429666d2603SJoerg Sonnenberger
430666d2603SJoerg Sonnenberger /************************************************************************/
431666d2603SJoerg Sonnenberger /* Kthreads */
432666d2603SJoerg Sonnenberger /************************************************************************/
433666d2603SJoerg Sonnenberger
4343aef8050SSepherosa Ziehau void
cbb_event_thread(void * arg)435666d2603SJoerg Sonnenberger cbb_event_thread(void *arg)
436666d2603SJoerg Sonnenberger {
437666d2603SJoerg Sonnenberger struct cbb_softc *sc = arg;
438666d2603SJoerg Sonnenberger uint32_t status;
439666d2603SJoerg Sonnenberger int err;
4403aef8050SSepherosa Ziehau int not_a_card = 0;
441666d2603SJoerg Sonnenberger
442cd8ab232SMatthew Dillon get_mplock();
443666d2603SJoerg Sonnenberger sc->flags |= CBB_KTHREAD_RUNNING;
4443aef8050SSepherosa Ziehau while ((sc->flags & CBB_KTHREAD_DONE) == 0) {
445666d2603SJoerg Sonnenberger /*
4463aef8050SSepherosa Ziehau * We take out Giant here because we need it deep,
4473aef8050SSepherosa Ziehau * down in the bowels of the vm system for mapping the
4483aef8050SSepherosa Ziehau * memory we need to read the CIS. In addition, since
4493aef8050SSepherosa Ziehau * we are adding/deleting devices from the dev tree,
4503aef8050SSepherosa Ziehau * and that code isn't MP safe, we have to hold Giant.
451666d2603SJoerg Sonnenberger */
452666d2603SJoerg Sonnenberger status = cbb_get(sc, CBB_SOCKET_STATE);
4533aef8050SSepherosa Ziehau DPRINTF(("Status is 0x%x\n", status));
4543aef8050SSepherosa Ziehau if (!CBB_CARD_PRESENT(status)) {
4553aef8050SSepherosa Ziehau not_a_card = 0; /* We know card type */
456666d2603SJoerg Sonnenberger cbb_removal(sc);
4573aef8050SSepherosa Ziehau } else if (status & CBB_STATE_NOT_A_CARD) {
4583aef8050SSepherosa Ziehau /*
4593aef8050SSepherosa Ziehau * Up to 20 times, try to rescan the card when we
4603aef8050SSepherosa Ziehau * see NOT_A_CARD.
4613aef8050SSepherosa Ziehau */
4623aef8050SSepherosa Ziehau if (not_a_card++ < 20) {
4633aef8050SSepherosa Ziehau DEVPRINTF((sc->dev,
4643aef8050SSepherosa Ziehau "Not a card bit set, rescanning\n"));
4653aef8050SSepherosa Ziehau cbb_setb(sc, CBB_SOCKET_FORCE, CBB_FORCE_CV_TEST);
4663aef8050SSepherosa Ziehau } else {
4673aef8050SSepherosa Ziehau device_printf(sc->dev,
4683aef8050SSepherosa Ziehau "Can't determine card type\n");
4693aef8050SSepherosa Ziehau }
4703aef8050SSepherosa Ziehau } else {
4713aef8050SSepherosa Ziehau not_a_card = 0; /* We know card type */
4723aef8050SSepherosa Ziehau cbb_insert(sc);
4733aef8050SSepherosa Ziehau }
474666d2603SJoerg Sonnenberger
475666d2603SJoerg Sonnenberger /*
476666d2603SJoerg Sonnenberger * Wait until it has been 1s since the last time we
477666d2603SJoerg Sonnenberger * get an interrupt. We handle the rest of the interrupt
4783aef8050SSepherosa Ziehau * at the top of the loop. Although we clear the bit in the
4793aef8050SSepherosa Ziehau * ISR, we signal sc->generic_cv from the detach path after
4803aef8050SSepherosa Ziehau * we've set the CBB_KTHREAD_DONE bit, so we can't do a simple
4813aef8050SSepherosa Ziehau * 1s sleep here.
4823aef8050SSepherosa Ziehau *
4833aef8050SSepherosa Ziehau * In our ISR, we turn off the card changed interrupt. Turn
4843aef8050SSepherosa Ziehau * them back on here before we wait for them to happen. We
4853aef8050SSepherosa Ziehau * turn them on/off so that we can tolerate a large latency
4863aef8050SSepherosa Ziehau * between the time we signal cbb_event_thread and it gets
4873aef8050SSepherosa Ziehau * a chance to run.
488666d2603SJoerg Sonnenberger */
4893aef8050SSepherosa Ziehau crit_enter();
4903aef8050SSepherosa Ziehau cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
4913aef8050SSepherosa Ziehau tsleep(&sc->generic_cv, 0, "cbbgcv", 0);
4923aef8050SSepherosa Ziehau err = 0;
493666d2603SJoerg Sonnenberger while (err != EWOULDBLOCK &&
494666d2603SJoerg Sonnenberger (sc->flags & CBB_KTHREAD_DONE) == 0)
4953aef8050SSepherosa Ziehau err = tsleep(&sc->generic_cv, 0, "cbbgcv", hz);
4963aef8050SSepherosa Ziehau crit_exit();
497666d2603SJoerg Sonnenberger }
498666d2603SJoerg Sonnenberger sc->flags &= ~CBB_KTHREAD_RUNNING;
4993aef8050SSepherosa Ziehau wakeup(sc->event_thread);
500cd8ab232SMatthew Dillon rel_mplock();
501666d2603SJoerg Sonnenberger }
502666d2603SJoerg Sonnenberger
503666d2603SJoerg Sonnenberger /************************************************************************/
504666d2603SJoerg Sonnenberger /* Insert/removal */
505666d2603SJoerg Sonnenberger /************************************************************************/
506666d2603SJoerg Sonnenberger
507666d2603SJoerg Sonnenberger static void
cbb_insert(struct cbb_softc * sc)508666d2603SJoerg Sonnenberger cbb_insert(struct cbb_softc *sc)
509666d2603SJoerg Sonnenberger {
510666d2603SJoerg Sonnenberger uint32_t sockevent, sockstate;
511666d2603SJoerg Sonnenberger
512666d2603SJoerg Sonnenberger sockevent = cbb_get(sc, CBB_SOCKET_EVENT);
513666d2603SJoerg Sonnenberger sockstate = cbb_get(sc, CBB_SOCKET_STATE);
514666d2603SJoerg Sonnenberger
515666d2603SJoerg Sonnenberger DEVPRINTF((sc->dev, "card inserted: event=0x%08x, state=%08x\n",
516666d2603SJoerg Sonnenberger sockevent, sockstate));
517666d2603SJoerg Sonnenberger
5183aef8050SSepherosa Ziehau if (sockstate & CBB_STATE_R2_CARD) {
5193aef8050SSepherosa Ziehau if (sc->exca[0].pccarddev) {
520666d2603SJoerg Sonnenberger sc->flags |= CBB_16BIT_CARD;
5213aef8050SSepherosa Ziehau exca_insert(&sc->exca[0]);
522666d2603SJoerg Sonnenberger } else {
523666d2603SJoerg Sonnenberger device_printf(sc->dev,
5243aef8050SSepherosa Ziehau "16-bit card inserted, but no pccard bus.\n");
525666d2603SJoerg Sonnenberger }
5263aef8050SSepherosa Ziehau } else if (sockstate & CBB_STATE_CB_CARD) {
527666d2603SJoerg Sonnenberger if (sc->cbdev != NULL) {
528666d2603SJoerg Sonnenberger sc->flags &= ~CBB_16BIT_CARD;
5293aef8050SSepherosa Ziehau CARD_ATTACH_CARD(sc->cbdev);
530666d2603SJoerg Sonnenberger } else {
531666d2603SJoerg Sonnenberger device_printf(sc->dev,
532666d2603SJoerg Sonnenberger "CardBus card inserted, but no cardbus bus.\n");
533666d2603SJoerg Sonnenberger }
534666d2603SJoerg Sonnenberger } else {
535666d2603SJoerg Sonnenberger /*
536666d2603SJoerg Sonnenberger * We should power the card down, and try again a couple of
537666d2603SJoerg Sonnenberger * times if this happens. XXX
538666d2603SJoerg Sonnenberger */
539666d2603SJoerg Sonnenberger device_printf(sc->dev, "Unsupported card type detected\n");
540666d2603SJoerg Sonnenberger }
541666d2603SJoerg Sonnenberger }
542666d2603SJoerg Sonnenberger
543666d2603SJoerg Sonnenberger static void
cbb_removal(struct cbb_softc * sc)544666d2603SJoerg Sonnenberger cbb_removal(struct cbb_softc *sc)
545666d2603SJoerg Sonnenberger {
5463aef8050SSepherosa Ziehau sc->flags &= ~CBB_CARD_OK;
547666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD) {
5483aef8050SSepherosa Ziehau exca_removal(&sc->exca[0]);
549666d2603SJoerg Sonnenberger } else {
550666d2603SJoerg Sonnenberger if (sc->cbdev != NULL)
551666d2603SJoerg Sonnenberger CARD_DETACH_CARD(sc->cbdev);
552666d2603SJoerg Sonnenberger }
553666d2603SJoerg Sonnenberger cbb_destroy_res(sc);
554666d2603SJoerg Sonnenberger }
555666d2603SJoerg Sonnenberger
556666d2603SJoerg Sonnenberger /************************************************************************/
557666d2603SJoerg Sonnenberger /* Interrupt Handler */
558666d2603SJoerg Sonnenberger /************************************************************************/
559666d2603SJoerg Sonnenberger
5603aef8050SSepherosa Ziehau /*
5613aef8050SSepherosa Ziehau * Since we touch hardware in the worst case, we don't need to use atomic
5623aef8050SSepherosa Ziehau * ops on the CARD_OK tests. They would save us a trip to the hardware
5633aef8050SSepherosa Ziehau * if CARD_OK was recently cleared and the caches haven't updated yet.
5643aef8050SSepherosa Ziehau * However, an atomic op costs between 100-200 CPU cycles. On a 3GHz
5653aef8050SSepherosa Ziehau * machine, this is about 33-66ns, whereas a trip the the hardware
5663aef8050SSepherosa Ziehau * is about that. On slower machines, the cost is even higher, so the
5673aef8050SSepherosa Ziehau * trip to the hardware is cheaper and achieves the same ends that
5683aef8050SSepherosa Ziehau * a fully locked operation would give us.
5693aef8050SSepherosa Ziehau *
5703aef8050SSepherosa Ziehau * This is a separate routine because we'd have to use locking and/or
5713aef8050SSepherosa Ziehau * other synchronization in cbb_intr to do this there. That would be
5723aef8050SSepherosa Ziehau * even more expensive.
5733aef8050SSepherosa Ziehau *
5743aef8050SSepherosa Ziehau * I need to investigate what this means for a SMP machine with multiple
5753aef8050SSepherosa Ziehau * CPUs servicing the ISR when an eject happens. In the case of a dirty
5763aef8050SSepherosa Ziehau * eject, CD glitches and we might read 'card present' from the hardware
5773aef8050SSepherosa Ziehau * due to this jitter. If we assumed that cbb_intr() ran before
5783aef8050SSepherosa Ziehau * cbb_func_intr(), we could just check the SOCKET_MASK register and if
5793aef8050SSepherosa Ziehau * CD changes were clear there, then we'd know the card was gone.
5803aef8050SSepherosa Ziehau */
581666d2603SJoerg Sonnenberger static void
cbb_func_intr(void * arg)5823aef8050SSepherosa Ziehau cbb_func_intr(void *arg)
5833aef8050SSepherosa Ziehau {
5843aef8050SSepherosa Ziehau struct cbb_intrhand *ih = arg;
5853aef8050SSepherosa Ziehau struct cbb_softc *sc = ih->sc;
5863aef8050SSepherosa Ziehau
5873aef8050SSepherosa Ziehau /*
5883aef8050SSepherosa Ziehau * Make sure that the card is really there.
5893aef8050SSepherosa Ziehau */
5903aef8050SSepherosa Ziehau if ((sc->flags & CBB_CARD_OK) == 0)
5913aef8050SSepherosa Ziehau return;
5923aef8050SSepherosa Ziehau if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
5933aef8050SSepherosa Ziehau sc->flags &= ~CBB_CARD_OK;
5943aef8050SSepherosa Ziehau return;
5953aef8050SSepherosa Ziehau }
5963aef8050SSepherosa Ziehau
5973aef8050SSepherosa Ziehau /*
5983aef8050SSepherosa Ziehau * nb: don't have to check for giant or not, since that's done
5993aef8050SSepherosa Ziehau * in the ISR dispatch
6003aef8050SSepherosa Ziehau */
6013aef8050SSepherosa Ziehau if (ih->serializer) {
6023aef8050SSepherosa Ziehau lwkt_serialize_handler_call(ih->serializer,
6033aef8050SSepherosa Ziehau (inthand2_t *)ih->intr, ih->arg, NULL);
6043aef8050SSepherosa Ziehau } else {
6053aef8050SSepherosa Ziehau (*ih->intr)(ih->arg);
6063aef8050SSepherosa Ziehau }
6073aef8050SSepherosa Ziehau }
6083aef8050SSepherosa Ziehau
6093aef8050SSepherosa Ziehau void
cbb_intr(void * arg)610666d2603SJoerg Sonnenberger cbb_intr(void *arg)
611666d2603SJoerg Sonnenberger {
612666d2603SJoerg Sonnenberger struct cbb_softc *sc = arg;
613666d2603SJoerg Sonnenberger uint32_t sockevent;
614666d2603SJoerg Sonnenberger
615666d2603SJoerg Sonnenberger sockevent = cbb_get(sc, CBB_SOCKET_EVENT);
6163aef8050SSepherosa Ziehau if (sockevent != 0) {
617666d2603SJoerg Sonnenberger /* ack the interrupt */
6183aef8050SSepherosa Ziehau cbb_set(sc, CBB_SOCKET_EVENT, sockevent);
619666d2603SJoerg Sonnenberger
620666d2603SJoerg Sonnenberger /*
621666d2603SJoerg Sonnenberger * If anything has happened to the socket, we assume that
622666d2603SJoerg Sonnenberger * the card is no longer OK, and we shouldn't call its
623666d2603SJoerg Sonnenberger * ISR. We set CARD_OK as soon as we've attached the
624666d2603SJoerg Sonnenberger * card. This helps in a noisy eject, which happens
625666d2603SJoerg Sonnenberger * all too often when users are ejecting their PC Cards.
626666d2603SJoerg Sonnenberger *
627666d2603SJoerg Sonnenberger * We use this method in preference to checking to see if
628666d2603SJoerg Sonnenberger * the card is still there because the check suffers from
629666d2603SJoerg Sonnenberger * a race condition in the bouncing case. Prior versions
630666d2603SJoerg Sonnenberger * of the pccard software used a similar trick and achieved
631666d2603SJoerg Sonnenberger * excellent results.
632666d2603SJoerg Sonnenberger */
633666d2603SJoerg Sonnenberger if (sockevent & CBB_SOCKET_EVENT_CD) {
6343aef8050SSepherosa Ziehau crit_enter();
6353aef8050SSepherosa Ziehau cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
636666d2603SJoerg Sonnenberger sc->flags &= ~CBB_CARD_OK;
6373aef8050SSepherosa Ziehau cbb_disable_func_intr(sc);
6383aef8050SSepherosa Ziehau wakeup_one(&sc->generic_cv);
6393aef8050SSepherosa Ziehau crit_exit();
640666d2603SJoerg Sonnenberger }
6413aef8050SSepherosa Ziehau /*
6423aef8050SSepherosa Ziehau * If we get a power interrupt, wakeup anybody that might
6433aef8050SSepherosa Ziehau * be waiting for one.
6443aef8050SSepherosa Ziehau */
645666d2603SJoerg Sonnenberger if (sockevent & CBB_SOCKET_EVENT_POWER) {
6463aef8050SSepherosa Ziehau crit_enter();
6473aef8050SSepherosa Ziehau sc->powerintr++;
6483aef8050SSepherosa Ziehau wakeup(&sc->power_cv);
6493aef8050SSepherosa Ziehau crit_exit();
650666d2603SJoerg Sonnenberger }
651f5100ab5SMatthew Dillon }
6523aef8050SSepherosa Ziehau /*
6533aef8050SSepherosa Ziehau * Some chips also require us to read the old ExCA registe for
6543aef8050SSepherosa Ziehau * card status change when we route CSC vis PCI. This isn't supposed
6553aef8050SSepherosa Ziehau * to be required, but it clears the interrupt state on some chipsets.
6563aef8050SSepherosa Ziehau * Maybe there's a setting that would obviate its need. Maybe we
6573aef8050SSepherosa Ziehau * should test the status bits and deal with them, but so far we've
6583aef8050SSepherosa Ziehau * not found any machines that don't also give us the socket status
6593aef8050SSepherosa Ziehau * indication above.
6603aef8050SSepherosa Ziehau *
6613aef8050SSepherosa Ziehau * We have to call this unconditionally because some bridges deliver
6623aef8050SSepherosa Ziehau * the even independent of the CBB_SOCKET_EVENT_CD above.
6633aef8050SSepherosa Ziehau */
6643aef8050SSepherosa Ziehau exca_getb(&sc->exca[0], EXCA_CSC);
665666d2603SJoerg Sonnenberger }
666666d2603SJoerg Sonnenberger
667666d2603SJoerg Sonnenberger /************************************************************************/
668666d2603SJoerg Sonnenberger /* Generic Power functions */
669666d2603SJoerg Sonnenberger /************************************************************************/
670666d2603SJoerg Sonnenberger
6713aef8050SSepherosa Ziehau static uint32_t
cbb_detect_voltage(device_t brdev)672666d2603SJoerg Sonnenberger cbb_detect_voltage(device_t brdev)
673666d2603SJoerg Sonnenberger {
674666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
675666d2603SJoerg Sonnenberger uint32_t psr;
6763aef8050SSepherosa Ziehau uint32_t vol = CARD_UKN_CARD;
677666d2603SJoerg Sonnenberger
678666d2603SJoerg Sonnenberger psr = cbb_get(sc, CBB_SOCKET_STATE);
679666d2603SJoerg Sonnenberger
6803aef8050SSepherosa Ziehau if (psr & CBB_STATE_5VCARD)
681666d2603SJoerg Sonnenberger vol |= CARD_5V_CARD;
6823aef8050SSepherosa Ziehau if (psr & CBB_STATE_3VCARD)
683666d2603SJoerg Sonnenberger vol |= CARD_3V_CARD;
6843aef8050SSepherosa Ziehau if (psr & CBB_STATE_XVCARD)
685666d2603SJoerg Sonnenberger vol |= CARD_XV_CARD;
6863aef8050SSepherosa Ziehau if (psr & CBB_STATE_YVCARD)
687666d2603SJoerg Sonnenberger vol |= CARD_YV_CARD;
688666d2603SJoerg Sonnenberger
689666d2603SJoerg Sonnenberger return (vol);
690666d2603SJoerg Sonnenberger }
691666d2603SJoerg Sonnenberger
6923aef8050SSepherosa Ziehau static uint8_t
cbb_o2micro_power_hack(struct cbb_softc * sc)6933aef8050SSepherosa Ziehau cbb_o2micro_power_hack(struct cbb_softc *sc)
6943aef8050SSepherosa Ziehau {
6953aef8050SSepherosa Ziehau uint8_t reg;
6963aef8050SSepherosa Ziehau
6973aef8050SSepherosa Ziehau /*
6983aef8050SSepherosa Ziehau * Issue #2: INT# not qualified with IRQ Routing Bit. An
6993aef8050SSepherosa Ziehau * unexpected PCI INT# may be generated during PC-Card
7003aef8050SSepherosa Ziehau * initialization even with the IRQ Routing Bit Set with some
7013aef8050SSepherosa Ziehau * PC-Cards.
7023aef8050SSepherosa Ziehau *
7033aef8050SSepherosa Ziehau * This is a two part issue. The first part is that some of
7043aef8050SSepherosa Ziehau * our older controllers have an issue in which the slot's PCI
7053aef8050SSepherosa Ziehau * INT# is NOT qualified by the IRQ routing bit (PCI reg. 3Eh
7063aef8050SSepherosa Ziehau * bit 7). Regardless of the IRQ routing bit, if NO ISA IRQ
7073aef8050SSepherosa Ziehau * is selected (ExCA register 03h bits 3:0, of the slot, are
7083aef8050SSepherosa Ziehau * cleared) we will generate INT# if IREQ# is asserted. The
7093aef8050SSepherosa Ziehau * second part is because some PC-Cards prematurally assert
7103aef8050SSepherosa Ziehau * IREQ# before the ExCA registers are fully programmed. This
7113aef8050SSepherosa Ziehau * in turn asserts INT# because ExCA register 03h bits 3:0
7123aef8050SSepherosa Ziehau * (ISA IRQ Select) are not yet programmed.
7133aef8050SSepherosa Ziehau *
7143aef8050SSepherosa Ziehau * The fix for this issue, which will work for any controller
7153aef8050SSepherosa Ziehau * (old or new), is to set ExCA register 03h bits 3:0 = 0001b
7163aef8050SSepherosa Ziehau * (select IRQ1), of the slot, before turning on slot power.
7173aef8050SSepherosa Ziehau * Selecting IRQ1 will result in INT# NOT being asserted
7183aef8050SSepherosa Ziehau * (because IRQ1 is selected), and IRQ1 won't be asserted
7193aef8050SSepherosa Ziehau * because our controllers don't generate IRQ1.
7203aef8050SSepherosa Ziehau *
7213aef8050SSepherosa Ziehau * Other, non O2Micro controllers will generate irq 1 in some
7223aef8050SSepherosa Ziehau * situations, so we can't do this hack for everybody. Reports of
7233aef8050SSepherosa Ziehau * keyboard controller's interrupts being suppressed occurred when
7243aef8050SSepherosa Ziehau * we did this.
7253aef8050SSepherosa Ziehau */
7263aef8050SSepherosa Ziehau reg = exca_getb(&sc->exca[0], EXCA_INTR);
7273aef8050SSepherosa Ziehau exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1);
7283aef8050SSepherosa Ziehau return (reg);
7293aef8050SSepherosa Ziehau }
7303aef8050SSepherosa Ziehau
7313aef8050SSepherosa Ziehau /*
7323aef8050SSepherosa Ziehau * Restore the damage that cbb_o2micro_power_hack does to EXCA_INTR so
7333aef8050SSepherosa Ziehau * we don't have an interrupt storm on power on. This has the efect of
7343aef8050SSepherosa Ziehau * disabling card status change interrupts for the duration of poweron.
7353aef8050SSepherosa Ziehau */
7363aef8050SSepherosa Ziehau static void
cbb_o2micro_power_hack2(struct cbb_softc * sc,uint8_t reg)7373aef8050SSepherosa Ziehau cbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg)
7383aef8050SSepherosa Ziehau {
7393aef8050SSepherosa Ziehau exca_putb(&sc->exca[0], EXCA_INTR, reg);
7403aef8050SSepherosa Ziehau }
7413aef8050SSepherosa Ziehau
7423aef8050SSepherosa Ziehau int
cbb_power(device_t brdev,int volts)743666d2603SJoerg Sonnenberger cbb_power(device_t brdev, int volts)
744666d2603SJoerg Sonnenberger {
7453aef8050SSepherosa Ziehau uint32_t status, sock_ctrl, mask;
746666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
7473aef8050SSepherosa Ziehau int cnt, sane;
7483aef8050SSepherosa Ziehau int retval = 0;
7493aef8050SSepherosa Ziehau int on = 0;
7503aef8050SSepherosa Ziehau uint8_t reg = 0;
751666d2603SJoerg Sonnenberger
752666d2603SJoerg Sonnenberger sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL);
753666d2603SJoerg Sonnenberger
7543aef8050SSepherosa Ziehau sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK;
755666d2603SJoerg Sonnenberger switch (volts & CARD_VCCMASK) {
7563aef8050SSepherosa Ziehau case 5:
757666d2603SJoerg Sonnenberger sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V;
7583aef8050SSepherosa Ziehau on++;
759666d2603SJoerg Sonnenberger break;
7603aef8050SSepherosa Ziehau case 3:
761666d2603SJoerg Sonnenberger sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V;
7623aef8050SSepherosa Ziehau on++;
763666d2603SJoerg Sonnenberger break;
7643aef8050SSepherosa Ziehau case XV:
7653aef8050SSepherosa Ziehau sock_ctrl |= CBB_SOCKET_CTRL_VCC_XV;
7663aef8050SSepherosa Ziehau on++;
7673aef8050SSepherosa Ziehau break;
7683aef8050SSepherosa Ziehau case YV:
7693aef8050SSepherosa Ziehau sock_ctrl |= CBB_SOCKET_CTRL_VCC_YV;
7703aef8050SSepherosa Ziehau on++;
7713aef8050SSepherosa Ziehau break;
7723aef8050SSepherosa Ziehau case 0:
773666d2603SJoerg Sonnenberger break;
774666d2603SJoerg Sonnenberger default:
775666d2603SJoerg Sonnenberger return (0); /* power NEVER changed */
776666d2603SJoerg Sonnenberger }
777666d2603SJoerg Sonnenberger
7783aef8050SSepherosa Ziehau /* VPP == VCC */
779666d2603SJoerg Sonnenberger sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK;
780666d2603SJoerg Sonnenberger sock_ctrl |= ((sock_ctrl >> 4) & 0x07);
781666d2603SJoerg Sonnenberger
782666d2603SJoerg Sonnenberger if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl)
783666d2603SJoerg Sonnenberger return (1); /* no change necessary */
7843aef8050SSepherosa Ziehau DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts));
7853aef8050SSepherosa Ziehau if (volts != 0 && sc->chipset == CB_O2MICRO)
7863aef8050SSepherosa Ziehau reg = cbb_o2micro_power_hack(sc);
787666d2603SJoerg Sonnenberger
788666d2603SJoerg Sonnenberger /*
7893aef8050SSepherosa Ziehau * We have to mask the card change detect interrupt while we're
7903aef8050SSepherosa Ziehau * messing with the power. It is allowed to bounce while we're
7913aef8050SSepherosa Ziehau * messing with power as things settle down. In addition, we mask off
7923aef8050SSepherosa Ziehau * the card's function interrupt by routing it via the ISA bus. This
7933aef8050SSepherosa Ziehau * bit generally only affects 16bit cards. Some bridges allow one to
7943aef8050SSepherosa Ziehau * set another bit to have it also affect 32bit cards. Since 32bit
7953aef8050SSepherosa Ziehau * cards are required to be better behaved, we don't bother to get
7963aef8050SSepherosa Ziehau * into those bridge specific features.
797666d2603SJoerg Sonnenberger */
7983aef8050SSepherosa Ziehau mask = cbb_get(sc, CBB_SOCKET_MASK);
7993aef8050SSepherosa Ziehau mask |= CBB_SOCKET_MASK_POWER;
8003aef8050SSepherosa Ziehau mask &= ~CBB_SOCKET_MASK_CD;
8013aef8050SSepherosa Ziehau cbb_set(sc, CBB_SOCKET_MASK, mask);
8023aef8050SSepherosa Ziehau PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
8033aef8050SSepherosa Ziehau |CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2);
8043aef8050SSepherosa Ziehau cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl);
8053aef8050SSepherosa Ziehau if (on) {
8063aef8050SSepherosa Ziehau crit_enter();
8073aef8050SSepherosa Ziehau cnt = sc->powerintr;
8083aef8050SSepherosa Ziehau sane = 200;
8093aef8050SSepherosa Ziehau while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) &&
8103aef8050SSepherosa Ziehau cnt == sc->powerintr && sane-- > 0)
8113aef8050SSepherosa Ziehau tsleep(&sc->power_cv, 0, "cbbpcv", hz / 10);
8123aef8050SSepherosa Ziehau crit_exit();
8133aef8050SSepherosa Ziehau if (sane <= 0)
8143aef8050SSepherosa Ziehau device_printf(sc->dev, "power timeout, doom?\n");
815666d2603SJoerg Sonnenberger }
816666d2603SJoerg Sonnenberger
8173aef8050SSepherosa Ziehau /*
8183aef8050SSepherosa Ziehau * After the power is good, we can turn off the power interrupt.
8193aef8050SSepherosa Ziehau * However, the PC Card standard says that we must delay turning the
8203aef8050SSepherosa Ziehau * CD bit back on for a bit to allow for bouncyness on power down
8213aef8050SSepherosa Ziehau * (recall that we don't wait above for a power down, since we don't
8223aef8050SSepherosa Ziehau * get an interrupt for that). We're called either from the suspend
8233aef8050SSepherosa Ziehau * code in which case we don't want to turn card change on again, or
8243aef8050SSepherosa Ziehau * we're called from the card insertion code, in which case the cbb
8253aef8050SSepherosa Ziehau * thread will turn it on for us before it waits to be woken by a
8263aef8050SSepherosa Ziehau * change event.
827666d2603SJoerg Sonnenberger */
8283aef8050SSepherosa Ziehau cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
8293aef8050SSepherosa Ziehau status = cbb_get(sc, CBB_SOCKET_STATE);
8303aef8050SSepherosa Ziehau if (on) {
8313aef8050SSepherosa Ziehau if ((status & CBB_STATE_POWER_CYCLE) == 0)
8323aef8050SSepherosa Ziehau device_printf(sc->dev, "Power not on?\n");
833666d2603SJoerg Sonnenberger }
8343aef8050SSepherosa Ziehau if (status & CBB_STATE_BAD_VCC_REQ) {
8353aef8050SSepherosa Ziehau device_printf(sc->dev, "Bad Vcc requested\n");
8363aef8050SSepherosa Ziehau /* XXX Do we want to do something to mitigate things here? */
8373aef8050SSepherosa Ziehau goto done;
8383aef8050SSepherosa Ziehau }
8393aef8050SSepherosa Ziehau PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
8403aef8050SSepherosa Ziehau & ~CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2);
8413aef8050SSepherosa Ziehau retval = 1;
8423aef8050SSepherosa Ziehau done:;
8433aef8050SSepherosa Ziehau if (volts != 0 && sc->chipset == CB_O2MICRO)
8443aef8050SSepherosa Ziehau cbb_o2micro_power_hack2(sc, reg);
8453aef8050SSepherosa Ziehau return (retval);
8463aef8050SSepherosa Ziehau }
8473aef8050SSepherosa Ziehau
8483aef8050SSepherosa Ziehau static int
cbb_current_voltage(device_t brdev)8493aef8050SSepherosa Ziehau cbb_current_voltage(device_t brdev)
8503aef8050SSepherosa Ziehau {
8513aef8050SSepherosa Ziehau struct cbb_softc *sc = device_get_softc(brdev);
8523aef8050SSepherosa Ziehau uint32_t ctrl;
8533aef8050SSepherosa Ziehau
8543aef8050SSepherosa Ziehau ctrl = cbb_get(sc, CBB_SOCKET_CONTROL);
8553aef8050SSepherosa Ziehau switch (ctrl & CBB_SOCKET_CTRL_VCCMASK) {
8563aef8050SSepherosa Ziehau case CBB_SOCKET_CTRL_VCC_5V:
8573aef8050SSepherosa Ziehau return CARD_5V_CARD;
8583aef8050SSepherosa Ziehau case CBB_SOCKET_CTRL_VCC_3V:
8593aef8050SSepherosa Ziehau return CARD_3V_CARD;
8603aef8050SSepherosa Ziehau case CBB_SOCKET_CTRL_VCC_XV:
8613aef8050SSepherosa Ziehau return CARD_XV_CARD;
8623aef8050SSepherosa Ziehau case CBB_SOCKET_CTRL_VCC_YV:
8633aef8050SSepherosa Ziehau return CARD_YV_CARD;
8643aef8050SSepherosa Ziehau }
8653aef8050SSepherosa Ziehau return 0;
866666d2603SJoerg Sonnenberger }
867666d2603SJoerg Sonnenberger
868666d2603SJoerg Sonnenberger /*
869666d2603SJoerg Sonnenberger * detect the voltage for the card, and set it. Since the power
870666d2603SJoerg Sonnenberger * used is the square of the voltage, lower voltages is a big win
871666d2603SJoerg Sonnenberger * and what Windows does (and what Microsoft prefers). The MS paper
8723aef8050SSepherosa Ziehau * also talks about preferring the CIS entry as well, but that has
8733aef8050SSepherosa Ziehau * to be done elsewhere. We also optimize power sequencing here
8743aef8050SSepherosa Ziehau * and don't change things if we're already powered up at a supported
8753aef8050SSepherosa Ziehau * voltage.
8763aef8050SSepherosa Ziehau *
8773aef8050SSepherosa Ziehau * In addition, we power up with OE disabled. We'll set it later
8783aef8050SSepherosa Ziehau * in the power up sequence.
879666d2603SJoerg Sonnenberger */
880666d2603SJoerg Sonnenberger static int
cbb_do_power(device_t brdev)881666d2603SJoerg Sonnenberger cbb_do_power(device_t brdev)
882666d2603SJoerg Sonnenberger {
8833aef8050SSepherosa Ziehau struct cbb_softc *sc = device_get_softc(brdev);
8843aef8050SSepherosa Ziehau uint32_t voltage, curpwr;
8853aef8050SSepherosa Ziehau uint32_t status;
886666d2603SJoerg Sonnenberger
8873aef8050SSepherosa Ziehau /* Don't enable OE (output enable) until power stable */
8883aef8050SSepherosa Ziehau exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE);
8893aef8050SSepherosa Ziehau
890666d2603SJoerg Sonnenberger voltage = cbb_detect_voltage(brdev);
8913aef8050SSepherosa Ziehau curpwr = cbb_current_voltage(brdev);
8923aef8050SSepherosa Ziehau status = cbb_get(sc, CBB_SOCKET_STATE);
8933aef8050SSepherosa Ziehau if ((status & CBB_STATE_POWER_CYCLE) && (voltage & curpwr))
8943aef8050SSepherosa Ziehau return 0;
8953aef8050SSepherosa Ziehau /* Prefer lowest voltage supported */
8963aef8050SSepherosa Ziehau cbb_power(brdev, CARD_OFF);
897666d2603SJoerg Sonnenberger if (voltage & CARD_YV_CARD)
8983aef8050SSepherosa Ziehau cbb_power(brdev, CARD_VCC(YV));
899666d2603SJoerg Sonnenberger else if (voltage & CARD_XV_CARD)
9003aef8050SSepherosa Ziehau cbb_power(brdev, CARD_VCC(XV));
901666d2603SJoerg Sonnenberger else if (voltage & CARD_3V_CARD)
9023aef8050SSepherosa Ziehau cbb_power(brdev, CARD_VCC(3));
903666d2603SJoerg Sonnenberger else if (voltage & CARD_5V_CARD)
9043aef8050SSepherosa Ziehau cbb_power(brdev, CARD_VCC(5));
905666d2603SJoerg Sonnenberger else {
906666d2603SJoerg Sonnenberger device_printf(brdev, "Unknown card voltage\n");
907666d2603SJoerg Sonnenberger return (ENXIO);
908666d2603SJoerg Sonnenberger }
909666d2603SJoerg Sonnenberger return (0);
910666d2603SJoerg Sonnenberger }
911666d2603SJoerg Sonnenberger
912666d2603SJoerg Sonnenberger /************************************************************************/
913666d2603SJoerg Sonnenberger /* CardBus power functions */
914666d2603SJoerg Sonnenberger /************************************************************************/
915666d2603SJoerg Sonnenberger
916666d2603SJoerg Sonnenberger static void
cbb_cardbus_reset(device_t brdev)917666d2603SJoerg Sonnenberger cbb_cardbus_reset(device_t brdev)
918666d2603SJoerg Sonnenberger {
919666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
9203aef8050SSepherosa Ziehau int delay;
921666d2603SJoerg Sonnenberger
9223aef8050SSepherosa Ziehau /*
9233aef8050SSepherosa Ziehau * 20ms is necessary for most bridges. For some reason, the Ricoh
9243aef8050SSepherosa Ziehau * RF5C47x bridges need 400ms.
9253aef8050SSepherosa Ziehau */
9263aef8050SSepherosa Ziehau delay = sc->chipset == CB_RF5C47X ? 400 : 20;
927666d2603SJoerg Sonnenberger
928666d2603SJoerg Sonnenberger PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2);
929666d2603SJoerg Sonnenberger
9303aef8050SSepherosa Ziehau tsleep(sc, 0, "cbbP3", hz * delay / 1000);
931666d2603SJoerg Sonnenberger
932666d2603SJoerg Sonnenberger /* If a card exists, unreset it! */
9333aef8050SSepherosa Ziehau if (CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
934666d2603SJoerg Sonnenberger PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
935666d2603SJoerg Sonnenberger &~CBBM_BRIDGECTRL_RESET, 2);
9363aef8050SSepherosa Ziehau tsleep(sc, 0, "cbbP3", hz * delay / 1000);
937666d2603SJoerg Sonnenberger }
938666d2603SJoerg Sonnenberger }
939666d2603SJoerg Sonnenberger
940666d2603SJoerg Sonnenberger static int
cbb_cardbus_power_enable_socket(device_t brdev,device_t child)941666d2603SJoerg Sonnenberger cbb_cardbus_power_enable_socket(device_t brdev, device_t child)
942666d2603SJoerg Sonnenberger {
943666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
944666d2603SJoerg Sonnenberger int err;
945666d2603SJoerg Sonnenberger
9463aef8050SSepherosa Ziehau if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE)))
947666d2603SJoerg Sonnenberger return (ENODEV);
948666d2603SJoerg Sonnenberger
949666d2603SJoerg Sonnenberger err = cbb_do_power(brdev);
950666d2603SJoerg Sonnenberger if (err)
951666d2603SJoerg Sonnenberger return (err);
952666d2603SJoerg Sonnenberger cbb_cardbus_reset(brdev);
953666d2603SJoerg Sonnenberger return (0);
954666d2603SJoerg Sonnenberger }
955666d2603SJoerg Sonnenberger
956666d2603SJoerg Sonnenberger static void
cbb_cardbus_power_disable_socket(device_t brdev,device_t child)957666d2603SJoerg Sonnenberger cbb_cardbus_power_disable_socket(device_t brdev, device_t child)
958666d2603SJoerg Sonnenberger {
9593aef8050SSepherosa Ziehau cbb_power(brdev, CARD_OFF);
960666d2603SJoerg Sonnenberger cbb_cardbus_reset(brdev);
961666d2603SJoerg Sonnenberger }
962666d2603SJoerg Sonnenberger
963666d2603SJoerg Sonnenberger /************************************************************************/
964666d2603SJoerg Sonnenberger /* CardBus Resource */
965666d2603SJoerg Sonnenberger /************************************************************************/
966666d2603SJoerg Sonnenberger
967666d2603SJoerg Sonnenberger static int
cbb_cardbus_io_open(device_t brdev,int win,uint32_t start,uint32_t end)968666d2603SJoerg Sonnenberger cbb_cardbus_io_open(device_t brdev, int win, uint32_t start, uint32_t end)
969666d2603SJoerg Sonnenberger {
970666d2603SJoerg Sonnenberger int basereg;
971666d2603SJoerg Sonnenberger int limitreg;
972666d2603SJoerg Sonnenberger
973666d2603SJoerg Sonnenberger if ((win < 0) || (win > 1)) {
974666d2603SJoerg Sonnenberger DEVPRINTF((brdev,
975666d2603SJoerg Sonnenberger "cbb_cardbus_io_open: window out of range %d\n", win));
976666d2603SJoerg Sonnenberger return (EINVAL);
977666d2603SJoerg Sonnenberger }
978666d2603SJoerg Sonnenberger
979666d2603SJoerg Sonnenberger basereg = win * 8 + CBBR_IOBASE0;
980666d2603SJoerg Sonnenberger limitreg = win * 8 + CBBR_IOLIMIT0;
981666d2603SJoerg Sonnenberger
982666d2603SJoerg Sonnenberger pci_write_config(brdev, basereg, start, 4);
983666d2603SJoerg Sonnenberger pci_write_config(brdev, limitreg, end, 4);
984666d2603SJoerg Sonnenberger return (0);
985666d2603SJoerg Sonnenberger }
986666d2603SJoerg Sonnenberger
987666d2603SJoerg Sonnenberger static int
cbb_cardbus_mem_open(device_t brdev,int win,uint32_t start,uint32_t end)988666d2603SJoerg Sonnenberger cbb_cardbus_mem_open(device_t brdev, int win, uint32_t start, uint32_t end)
989666d2603SJoerg Sonnenberger {
990666d2603SJoerg Sonnenberger int basereg;
991666d2603SJoerg Sonnenberger int limitreg;
992666d2603SJoerg Sonnenberger
993666d2603SJoerg Sonnenberger if ((win < 0) || (win > 1)) {
994666d2603SJoerg Sonnenberger DEVPRINTF((brdev,
995666d2603SJoerg Sonnenberger "cbb_cardbus_mem_open: window out of range %d\n", win));
996666d2603SJoerg Sonnenberger return (EINVAL);
997666d2603SJoerg Sonnenberger }
998666d2603SJoerg Sonnenberger
999666d2603SJoerg Sonnenberger basereg = win*8 + CBBR_MEMBASE0;
1000666d2603SJoerg Sonnenberger limitreg = win*8 + CBBR_MEMLIMIT0;
1001666d2603SJoerg Sonnenberger
1002666d2603SJoerg Sonnenberger pci_write_config(brdev, basereg, start, 4);
1003666d2603SJoerg Sonnenberger pci_write_config(brdev, limitreg, end, 4);
1004666d2603SJoerg Sonnenberger return (0);
1005666d2603SJoerg Sonnenberger }
1006666d2603SJoerg Sonnenberger
1007666d2603SJoerg Sonnenberger /*
1008666d2603SJoerg Sonnenberger * XXX The following function belongs in the pci bus layer.
1009666d2603SJoerg Sonnenberger */
1010666d2603SJoerg Sonnenberger static void
cbb_cardbus_auto_open(struct cbb_softc * sc,int type)1011666d2603SJoerg Sonnenberger cbb_cardbus_auto_open(struct cbb_softc *sc, int type)
1012666d2603SJoerg Sonnenberger {
1013666d2603SJoerg Sonnenberger uint32_t starts[2];
1014666d2603SJoerg Sonnenberger uint32_t ends[2];
1015666d2603SJoerg Sonnenberger struct cbb_reslist *rle;
1016666d2603SJoerg Sonnenberger int align;
1017666d2603SJoerg Sonnenberger int prefetchable[2];
1018666d2603SJoerg Sonnenberger uint32_t reg;
1019666d2603SJoerg Sonnenberger
1020666d2603SJoerg Sonnenberger starts[0] = starts[1] = 0xffffffff;
1021666d2603SJoerg Sonnenberger ends[0] = ends[1] = 0;
1022666d2603SJoerg Sonnenberger
1023666d2603SJoerg Sonnenberger if (type == SYS_RES_MEMORY)
1024666d2603SJoerg Sonnenberger align = CBB_MEMALIGN;
1025666d2603SJoerg Sonnenberger else if (type == SYS_RES_IOPORT)
1026666d2603SJoerg Sonnenberger align = CBB_IOALIGN;
1027666d2603SJoerg Sonnenberger else
1028666d2603SJoerg Sonnenberger align = 1;
1029666d2603SJoerg Sonnenberger
10303aef8050SSepherosa Ziehau /*
10313aef8050SSepherosa Ziehau * This looks somewhat bogus, and doesn't seem to really respect
10323aef8050SSepherosa Ziehau * alignment. The alignment stuff is happening too late (it
10333aef8050SSepherosa Ziehau * should happen at allocation time, not activation time) and
10343aef8050SSepherosa Ziehau * this code looks generally to be too complex for the purpose
10353aef8050SSepherosa Ziehau * it surves.
10363aef8050SSepherosa Ziehau */
1037666d2603SJoerg Sonnenberger SLIST_FOREACH(rle, &sc->rl, link) {
1038666d2603SJoerg Sonnenberger if (rle->type != type)
1039666d2603SJoerg Sonnenberger ;
1040666d2603SJoerg Sonnenberger else if (rle->res == NULL) {
1041666d2603SJoerg Sonnenberger device_printf(sc->dev, "WARNING: Resource not reserved? "
1042666d2603SJoerg Sonnenberger "(type=%d, addr=%lx)\n",
1043666d2603SJoerg Sonnenberger rle->type, rman_get_start(rle->res));
1044666d2603SJoerg Sonnenberger } else if (!(rman_get_flags(rle->res) & RF_ACTIVE)) {
1045666d2603SJoerg Sonnenberger /* XXX */
1046666d2603SJoerg Sonnenberger } else if (starts[0] == 0xffffffff) {
1047666d2603SJoerg Sonnenberger starts[0] = rman_get_start(rle->res);
1048666d2603SJoerg Sonnenberger ends[0] = rman_get_end(rle->res);
1049666d2603SJoerg Sonnenberger prefetchable[0] =
1050666d2603SJoerg Sonnenberger rman_get_flags(rle->res) & RF_PREFETCHABLE;
1051666d2603SJoerg Sonnenberger } else if (rman_get_end(rle->res) > ends[0] &&
1052666d2603SJoerg Sonnenberger rman_get_start(rle->res) - ends[0] <
1053666d2603SJoerg Sonnenberger CBB_AUTO_OPEN_SMALLHOLE && prefetchable[0] ==
1054666d2603SJoerg Sonnenberger (rman_get_flags(rle->res) & RF_PREFETCHABLE)) {
1055666d2603SJoerg Sonnenberger ends[0] = rman_get_end(rle->res);
1056666d2603SJoerg Sonnenberger } else if (rman_get_start(rle->res) < starts[0] &&
1057666d2603SJoerg Sonnenberger starts[0] - rman_get_end(rle->res) <
1058666d2603SJoerg Sonnenberger CBB_AUTO_OPEN_SMALLHOLE && prefetchable[0] ==
1059666d2603SJoerg Sonnenberger (rman_get_flags(rle->res) & RF_PREFETCHABLE)) {
1060666d2603SJoerg Sonnenberger starts[0] = rman_get_start(rle->res);
1061666d2603SJoerg Sonnenberger } else if (starts[1] == 0xffffffff) {
1062666d2603SJoerg Sonnenberger starts[1] = rman_get_start(rle->res);
1063666d2603SJoerg Sonnenberger ends[1] = rman_get_end(rle->res);
1064666d2603SJoerg Sonnenberger prefetchable[1] =
1065666d2603SJoerg Sonnenberger rman_get_flags(rle->res) & RF_PREFETCHABLE;
1066666d2603SJoerg Sonnenberger } else if (rman_get_end(rle->res) > ends[1] &&
1067666d2603SJoerg Sonnenberger rman_get_start(rle->res) - ends[1] <
1068666d2603SJoerg Sonnenberger CBB_AUTO_OPEN_SMALLHOLE && prefetchable[1] ==
1069666d2603SJoerg Sonnenberger (rman_get_flags(rle->res) & RF_PREFETCHABLE)) {
1070666d2603SJoerg Sonnenberger ends[1] = rman_get_end(rle->res);
1071666d2603SJoerg Sonnenberger } else if (rman_get_start(rle->res) < starts[1] &&
1072666d2603SJoerg Sonnenberger starts[1] - rman_get_end(rle->res) <
1073666d2603SJoerg Sonnenberger CBB_AUTO_OPEN_SMALLHOLE && prefetchable[1] ==
1074666d2603SJoerg Sonnenberger (rman_get_flags(rle->res) & RF_PREFETCHABLE)) {
1075666d2603SJoerg Sonnenberger starts[1] = rman_get_start(rle->res);
1076666d2603SJoerg Sonnenberger } else {
1077666d2603SJoerg Sonnenberger uint32_t diffs[2];
1078666d2603SJoerg Sonnenberger int win;
1079666d2603SJoerg Sonnenberger
1080666d2603SJoerg Sonnenberger diffs[0] = diffs[1] = 0xffffffff;
1081666d2603SJoerg Sonnenberger if (rman_get_start(rle->res) > ends[0])
1082666d2603SJoerg Sonnenberger diffs[0] = rman_get_start(rle->res) - ends[0];
1083666d2603SJoerg Sonnenberger else if (rman_get_end(rle->res) < starts[0])
1084666d2603SJoerg Sonnenberger diffs[0] = starts[0] - rman_get_end(rle->res);
1085666d2603SJoerg Sonnenberger if (rman_get_start(rle->res) > ends[1])
1086666d2603SJoerg Sonnenberger diffs[1] = rman_get_start(rle->res) - ends[1];
1087666d2603SJoerg Sonnenberger else if (rman_get_end(rle->res) < starts[1])
1088666d2603SJoerg Sonnenberger diffs[1] = starts[1] - rman_get_end(rle->res);
1089666d2603SJoerg Sonnenberger
1090666d2603SJoerg Sonnenberger win = (diffs[0] <= diffs[1])?0:1;
1091666d2603SJoerg Sonnenberger if (rman_get_start(rle->res) > ends[win])
1092666d2603SJoerg Sonnenberger ends[win] = rman_get_end(rle->res);
1093666d2603SJoerg Sonnenberger else if (rman_get_end(rle->res) < starts[win])
1094666d2603SJoerg Sonnenberger starts[win] = rman_get_start(rle->res);
1095666d2603SJoerg Sonnenberger if (!(rman_get_flags(rle->res) & RF_PREFETCHABLE))
1096666d2603SJoerg Sonnenberger prefetchable[win] = 0;
1097666d2603SJoerg Sonnenberger }
1098666d2603SJoerg Sonnenberger
1099666d2603SJoerg Sonnenberger if (starts[0] != 0xffffffff)
1100666d2603SJoerg Sonnenberger starts[0] -= starts[0] % align;
1101666d2603SJoerg Sonnenberger if (starts[1] != 0xffffffff)
1102666d2603SJoerg Sonnenberger starts[1] -= starts[1] % align;
1103666d2603SJoerg Sonnenberger if (ends[0] % align != 0)
1104666d2603SJoerg Sonnenberger ends[0] += align - ends[0] % align - 1;
1105666d2603SJoerg Sonnenberger if (ends[1] % align != 0)
1106666d2603SJoerg Sonnenberger ends[1] += align - ends[1] % align - 1;
1107666d2603SJoerg Sonnenberger }
1108666d2603SJoerg Sonnenberger
1109666d2603SJoerg Sonnenberger if (type == SYS_RES_MEMORY) {
1110666d2603SJoerg Sonnenberger cbb_cardbus_mem_open(sc->dev, 0, starts[0], ends[0]);
1111666d2603SJoerg Sonnenberger cbb_cardbus_mem_open(sc->dev, 1, starts[1], ends[1]);
1112666d2603SJoerg Sonnenberger reg = pci_read_config(sc->dev, CBBR_BRIDGECTRL, 2);
1113666d2603SJoerg Sonnenberger reg &= ~(CBBM_BRIDGECTRL_PREFETCH_0|
1114666d2603SJoerg Sonnenberger CBBM_BRIDGECTRL_PREFETCH_1);
1115666d2603SJoerg Sonnenberger reg |= (prefetchable[0]?CBBM_BRIDGECTRL_PREFETCH_0:0)|
1116666d2603SJoerg Sonnenberger (prefetchable[1]?CBBM_BRIDGECTRL_PREFETCH_1:0);
1117666d2603SJoerg Sonnenberger pci_write_config(sc->dev, CBBR_BRIDGECTRL, reg, 2);
1118666d2603SJoerg Sonnenberger } else if (type == SYS_RES_IOPORT) {
1119666d2603SJoerg Sonnenberger cbb_cardbus_io_open(sc->dev, 0, starts[0], ends[0]);
1120666d2603SJoerg Sonnenberger cbb_cardbus_io_open(sc->dev, 1, starts[1], ends[1]);
1121666d2603SJoerg Sonnenberger }
1122666d2603SJoerg Sonnenberger }
1123666d2603SJoerg Sonnenberger
1124666d2603SJoerg Sonnenberger static int
cbb_cardbus_activate_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1125666d2603SJoerg Sonnenberger cbb_cardbus_activate_resource(device_t brdev, device_t child, int type,
1126666d2603SJoerg Sonnenberger int rid, struct resource *res)
1127666d2603SJoerg Sonnenberger {
1128666d2603SJoerg Sonnenberger int ret;
1129666d2603SJoerg Sonnenberger
1130666d2603SJoerg Sonnenberger ret = BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child,
1131666d2603SJoerg Sonnenberger type, rid, res);
1132666d2603SJoerg Sonnenberger if (ret != 0)
1133666d2603SJoerg Sonnenberger return (ret);
1134666d2603SJoerg Sonnenberger cbb_cardbus_auto_open(device_get_softc(brdev), type);
1135666d2603SJoerg Sonnenberger return (0);
1136666d2603SJoerg Sonnenberger }
1137666d2603SJoerg Sonnenberger
1138666d2603SJoerg Sonnenberger static int
cbb_cardbus_deactivate_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1139666d2603SJoerg Sonnenberger cbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type,
1140666d2603SJoerg Sonnenberger int rid, struct resource *res)
1141666d2603SJoerg Sonnenberger {
1142666d2603SJoerg Sonnenberger int ret;
1143666d2603SJoerg Sonnenberger
1144666d2603SJoerg Sonnenberger ret = BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child,
1145666d2603SJoerg Sonnenberger type, rid, res);
1146666d2603SJoerg Sonnenberger if (ret != 0)
1147666d2603SJoerg Sonnenberger return (ret);
1148666d2603SJoerg Sonnenberger cbb_cardbus_auto_open(device_get_softc(brdev), type);
1149666d2603SJoerg Sonnenberger return (0);
1150666d2603SJoerg Sonnenberger }
1151666d2603SJoerg Sonnenberger
1152666d2603SJoerg Sonnenberger static struct resource *
cbb_cardbus_alloc_resource(device_t brdev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid)1153666d2603SJoerg Sonnenberger cbb_cardbus_alloc_resource(device_t brdev, device_t child, int type,
11544f7fe8c7SSepherosa Ziehau int *rid, u_long start, u_long end, u_long count, u_int flags, int cpuid)
1155666d2603SJoerg Sonnenberger {
1156666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1157666d2603SJoerg Sonnenberger int tmp;
1158666d2603SJoerg Sonnenberger struct resource *res;
11593aef8050SSepherosa Ziehau u_long align;
1160666d2603SJoerg Sonnenberger
1161666d2603SJoerg Sonnenberger switch (type) {
1162666d2603SJoerg Sonnenberger case SYS_RES_IRQ:
1163666d2603SJoerg Sonnenberger tmp = rman_get_start(sc->irq_res);
1164666d2603SJoerg Sonnenberger if (start > tmp || end < tmp || count != 1) {
1165666d2603SJoerg Sonnenberger device_printf(child, "requested interrupt %ld-%ld,"
1166666d2603SJoerg Sonnenberger "count = %ld not supported by cbb\n",
1167666d2603SJoerg Sonnenberger start, end, count);
1168666d2603SJoerg Sonnenberger return (NULL);
1169666d2603SJoerg Sonnenberger }
1170666d2603SJoerg Sonnenberger start = end = tmp;
11714f7fe8c7SSepherosa Ziehau cpuid = rman_get_cpuid(sc->irq_res);
11723aef8050SSepherosa Ziehau flags |= RF_SHAREABLE;
1173666d2603SJoerg Sonnenberger break;
1174666d2603SJoerg Sonnenberger case SYS_RES_IOPORT:
1175666d2603SJoerg Sonnenberger if (start <= cbb_start_32_io)
1176666d2603SJoerg Sonnenberger start = cbb_start_32_io;
1177666d2603SJoerg Sonnenberger if (end < start)
1178666d2603SJoerg Sonnenberger end = start;
1179666d2603SJoerg Sonnenberger break;
1180666d2603SJoerg Sonnenberger case SYS_RES_MEMORY:
1181666d2603SJoerg Sonnenberger if (start <= cbb_start_mem)
1182666d2603SJoerg Sonnenberger start = cbb_start_mem;
1183666d2603SJoerg Sonnenberger if (end < start)
1184666d2603SJoerg Sonnenberger end = start;
11853aef8050SSepherosa Ziehau if (count < CBB_MEMALIGN)
11863aef8050SSepherosa Ziehau align = CBB_MEMALIGN;
11873aef8050SSepherosa Ziehau else
11883aef8050SSepherosa Ziehau align = count;
11893aef8050SSepherosa Ziehau if (align > (1 << RF_ALIGNMENT(flags)))
11903aef8050SSepherosa Ziehau flags = (flags & ~RF_ALIGNMENT_MASK) |
11913aef8050SSepherosa Ziehau rman_make_alignment_flags(align);
1192666d2603SJoerg Sonnenberger break;
1193666d2603SJoerg Sonnenberger }
1194666d2603SJoerg Sonnenberger
1195666d2603SJoerg Sonnenberger res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid,
11964f7fe8c7SSepherosa Ziehau start, end, count, flags & ~RF_ACTIVE, cpuid);
1197666d2603SJoerg Sonnenberger if (res == NULL) {
1198e3869ec7SSascha Wildner kprintf("cbb alloc res fail\n");
1199666d2603SJoerg Sonnenberger return (NULL);
1200666d2603SJoerg Sonnenberger }
12013aef8050SSepherosa Ziehau cbb_insert_res(sc, res, type, *rid);
1202666d2603SJoerg Sonnenberger if (flags & RF_ACTIVE)
1203666d2603SJoerg Sonnenberger if (bus_activate_resource(child, type, *rid, res) != 0) {
1204666d2603SJoerg Sonnenberger bus_release_resource(child, type, *rid, res);
1205666d2603SJoerg Sonnenberger return (NULL);
1206666d2603SJoerg Sonnenberger }
1207666d2603SJoerg Sonnenberger
1208666d2603SJoerg Sonnenberger return (res);
1209666d2603SJoerg Sonnenberger }
1210666d2603SJoerg Sonnenberger
1211666d2603SJoerg Sonnenberger static int
cbb_cardbus_release_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1212666d2603SJoerg Sonnenberger cbb_cardbus_release_resource(device_t brdev, device_t child, int type,
1213666d2603SJoerg Sonnenberger int rid, struct resource *res)
1214666d2603SJoerg Sonnenberger {
1215666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1216666d2603SJoerg Sonnenberger int error;
1217666d2603SJoerg Sonnenberger
1218666d2603SJoerg Sonnenberger if (rman_get_flags(res) & RF_ACTIVE) {
1219666d2603SJoerg Sonnenberger error = bus_deactivate_resource(child, type, rid, res);
1220666d2603SJoerg Sonnenberger if (error != 0)
1221666d2603SJoerg Sonnenberger return (error);
1222666d2603SJoerg Sonnenberger }
1223666d2603SJoerg Sonnenberger cbb_remove_res(sc, res);
1224666d2603SJoerg Sonnenberger return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
1225666d2603SJoerg Sonnenberger type, rid, res));
1226666d2603SJoerg Sonnenberger }
1227666d2603SJoerg Sonnenberger
1228666d2603SJoerg Sonnenberger /************************************************************************/
1229666d2603SJoerg Sonnenberger /* PC Card Power Functions */
1230666d2603SJoerg Sonnenberger /************************************************************************/
1231666d2603SJoerg Sonnenberger
1232666d2603SJoerg Sonnenberger static int
cbb_pcic_power_enable_socket(device_t brdev,device_t child)1233666d2603SJoerg Sonnenberger cbb_pcic_power_enable_socket(device_t brdev, device_t child)
1234666d2603SJoerg Sonnenberger {
1235666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1236666d2603SJoerg Sonnenberger int err;
1237666d2603SJoerg Sonnenberger
1238666d2603SJoerg Sonnenberger DPRINTF(("cbb_pcic_socket_enable:\n"));
1239666d2603SJoerg Sonnenberger
1240666d2603SJoerg Sonnenberger /* power down/up the socket to reset */
1241666d2603SJoerg Sonnenberger err = cbb_do_power(brdev);
1242666d2603SJoerg Sonnenberger if (err)
1243666d2603SJoerg Sonnenberger return (err);
12443aef8050SSepherosa Ziehau exca_reset(&sc->exca[0], child);
1245666d2603SJoerg Sonnenberger
1246666d2603SJoerg Sonnenberger return (0);
1247666d2603SJoerg Sonnenberger }
1248666d2603SJoerg Sonnenberger
1249666d2603SJoerg Sonnenberger static void
cbb_pcic_power_disable_socket(device_t brdev,device_t child)1250666d2603SJoerg Sonnenberger cbb_pcic_power_disable_socket(device_t brdev, device_t child)
1251666d2603SJoerg Sonnenberger {
1252666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1253666d2603SJoerg Sonnenberger
1254666d2603SJoerg Sonnenberger DPRINTF(("cbb_pcic_socket_disable\n"));
1255666d2603SJoerg Sonnenberger
1256666d2603SJoerg Sonnenberger /* reset signal asserting... */
12573aef8050SSepherosa Ziehau exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
12583aef8050SSepherosa Ziehau tsleep(sc, 0, "cbbP1", hz / 100);
1259666d2603SJoerg Sonnenberger
1260666d2603SJoerg Sonnenberger /* power down the socket */
12613aef8050SSepherosa Ziehau exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE);
12623aef8050SSepherosa Ziehau cbb_power(brdev, CARD_OFF);
1263666d2603SJoerg Sonnenberger
1264666d2603SJoerg Sonnenberger /* wait 300ms until power fails (Tpf). */
12653aef8050SSepherosa Ziehau tsleep(sc, 0, "cbbP1", hz * 300 / 1000);
1266666d2603SJoerg Sonnenberger }
1267666d2603SJoerg Sonnenberger
1268666d2603SJoerg Sonnenberger /************************************************************************/
1269666d2603SJoerg Sonnenberger /* POWER methods */
1270666d2603SJoerg Sonnenberger /************************************************************************/
1271666d2603SJoerg Sonnenberger
12723aef8050SSepherosa Ziehau int
cbb_power_enable_socket(device_t brdev,device_t child)1273666d2603SJoerg Sonnenberger cbb_power_enable_socket(device_t brdev, device_t child)
1274666d2603SJoerg Sonnenberger {
1275666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1276666d2603SJoerg Sonnenberger
1277666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1278666d2603SJoerg Sonnenberger return (cbb_pcic_power_enable_socket(brdev, child));
1279666d2603SJoerg Sonnenberger else
1280666d2603SJoerg Sonnenberger return (cbb_cardbus_power_enable_socket(brdev, child));
1281666d2603SJoerg Sonnenberger }
1282666d2603SJoerg Sonnenberger
12833aef8050SSepherosa Ziehau void
cbb_power_disable_socket(device_t brdev,device_t child)1284666d2603SJoerg Sonnenberger cbb_power_disable_socket(device_t brdev, device_t child)
1285666d2603SJoerg Sonnenberger {
1286666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1287666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1288666d2603SJoerg Sonnenberger cbb_pcic_power_disable_socket(brdev, child);
1289666d2603SJoerg Sonnenberger else
1290666d2603SJoerg Sonnenberger cbb_cardbus_power_disable_socket(brdev, child);
1291666d2603SJoerg Sonnenberger }
12923aef8050SSepherosa Ziehau
1293666d2603SJoerg Sonnenberger static int
cbb_pcic_activate_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1294666d2603SJoerg Sonnenberger cbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid,
1295666d2603SJoerg Sonnenberger struct resource *res)
1296666d2603SJoerg Sonnenberger {
1297666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
12983aef8050SSepherosa Ziehau return (exca_activate_resource(&sc->exca[0], child, type, rid, res));
1299666d2603SJoerg Sonnenberger }
1300666d2603SJoerg Sonnenberger
1301666d2603SJoerg Sonnenberger static int
cbb_pcic_deactivate_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1302666d2603SJoerg Sonnenberger cbb_pcic_deactivate_resource(device_t brdev, device_t child, int type,
1303666d2603SJoerg Sonnenberger int rid, struct resource *res)
1304666d2603SJoerg Sonnenberger {
1305666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
13063aef8050SSepherosa Ziehau return (exca_deactivate_resource(&sc->exca[0], child, type, rid, res));
1307666d2603SJoerg Sonnenberger }
1308666d2603SJoerg Sonnenberger
1309666d2603SJoerg Sonnenberger static struct resource *
cbb_pcic_alloc_resource(device_t brdev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid)1310666d2603SJoerg Sonnenberger cbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid,
13114f7fe8c7SSepherosa Ziehau u_long start, u_long end, u_long count, u_int flags, int cpuid)
1312666d2603SJoerg Sonnenberger {
1313666d2603SJoerg Sonnenberger struct resource *res = NULL;
1314666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
13153aef8050SSepherosa Ziehau int align;
1316666d2603SJoerg Sonnenberger int tmp;
1317666d2603SJoerg Sonnenberger
1318666d2603SJoerg Sonnenberger switch (type) {
1319666d2603SJoerg Sonnenberger case SYS_RES_MEMORY:
1320666d2603SJoerg Sonnenberger if (start < cbb_start_mem)
1321666d2603SJoerg Sonnenberger start = cbb_start_mem;
1322666d2603SJoerg Sonnenberger if (end < start)
1323666d2603SJoerg Sonnenberger end = start;
13243aef8050SSepherosa Ziehau if (count < CBB_MEMALIGN)
13253aef8050SSepherosa Ziehau align = CBB_MEMALIGN;
13263aef8050SSepherosa Ziehau else
13273aef8050SSepherosa Ziehau align = count;
13283aef8050SSepherosa Ziehau if (align > (1 << RF_ALIGNMENT(flags)))
1329666d2603SJoerg Sonnenberger flags = (flags & ~RF_ALIGNMENT_MASK) |
13303aef8050SSepherosa Ziehau rman_make_alignment_flags(align);
1331666d2603SJoerg Sonnenberger break;
1332666d2603SJoerg Sonnenberger case SYS_RES_IOPORT:
1333666d2603SJoerg Sonnenberger if (start < cbb_start_16_io)
1334666d2603SJoerg Sonnenberger start = cbb_start_16_io;
1335666d2603SJoerg Sonnenberger if (end < start)
1336666d2603SJoerg Sonnenberger end = start;
1337666d2603SJoerg Sonnenberger break;
1338666d2603SJoerg Sonnenberger case SYS_RES_IRQ:
1339666d2603SJoerg Sonnenberger tmp = rman_get_start(sc->irq_res);
1340666d2603SJoerg Sonnenberger if (start > tmp || end < tmp || count != 1) {
1341666d2603SJoerg Sonnenberger device_printf(child, "requested interrupt %ld-%ld,"
1342666d2603SJoerg Sonnenberger "count = %ld not supported by cbb\n",
1343666d2603SJoerg Sonnenberger start, end, count);
1344666d2603SJoerg Sonnenberger return (NULL);
1345666d2603SJoerg Sonnenberger }
1346666d2603SJoerg Sonnenberger flags |= RF_SHAREABLE;
1347666d2603SJoerg Sonnenberger start = end = rman_get_start(sc->irq_res);
13484f7fe8c7SSepherosa Ziehau cpuid = rman_get_cpuid(sc->irq_res);
1349666d2603SJoerg Sonnenberger break;
1350666d2603SJoerg Sonnenberger }
1351666d2603SJoerg Sonnenberger res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid,
13524f7fe8c7SSepherosa Ziehau start, end, count, flags & ~RF_ACTIVE, cpuid);
1353666d2603SJoerg Sonnenberger if (res == NULL)
1354666d2603SJoerg Sonnenberger return (NULL);
13553aef8050SSepherosa Ziehau cbb_insert_res(sc, res, type, *rid);
1356666d2603SJoerg Sonnenberger if (flags & RF_ACTIVE) {
1357666d2603SJoerg Sonnenberger if (bus_activate_resource(child, type, *rid, res) != 0) {
1358666d2603SJoerg Sonnenberger bus_release_resource(child, type, *rid, res);
1359666d2603SJoerg Sonnenberger return (NULL);
1360666d2603SJoerg Sonnenberger }
1361666d2603SJoerg Sonnenberger }
1362666d2603SJoerg Sonnenberger
1363666d2603SJoerg Sonnenberger return (res);
1364666d2603SJoerg Sonnenberger }
1365666d2603SJoerg Sonnenberger
1366666d2603SJoerg Sonnenberger static int
cbb_pcic_release_resource(device_t brdev,device_t child,int type,int rid,struct resource * res)1367666d2603SJoerg Sonnenberger cbb_pcic_release_resource(device_t brdev, device_t child, int type,
1368666d2603SJoerg Sonnenberger int rid, struct resource *res)
1369666d2603SJoerg Sonnenberger {
1370666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1371666d2603SJoerg Sonnenberger int error;
1372666d2603SJoerg Sonnenberger
1373666d2603SJoerg Sonnenberger if (rman_get_flags(res) & RF_ACTIVE) {
1374666d2603SJoerg Sonnenberger error = bus_deactivate_resource(child, type, rid, res);
1375666d2603SJoerg Sonnenberger if (error != 0)
1376666d2603SJoerg Sonnenberger return (error);
1377666d2603SJoerg Sonnenberger }
1378666d2603SJoerg Sonnenberger cbb_remove_res(sc, res);
1379666d2603SJoerg Sonnenberger return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
1380666d2603SJoerg Sonnenberger type, rid, res));
1381666d2603SJoerg Sonnenberger }
1382666d2603SJoerg Sonnenberger
1383666d2603SJoerg Sonnenberger /************************************************************************/
1384666d2603SJoerg Sonnenberger /* PC Card methods */
1385666d2603SJoerg Sonnenberger /************************************************************************/
1386666d2603SJoerg Sonnenberger
13873aef8050SSepherosa Ziehau int
cbb_pcic_set_res_flags(device_t brdev,device_t child,int type,int rid,uint32_t flags)1388666d2603SJoerg Sonnenberger cbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid,
1389666d2603SJoerg Sonnenberger uint32_t flags)
1390666d2603SJoerg Sonnenberger {
1391666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1392666d2603SJoerg Sonnenberger struct resource *res;
1393666d2603SJoerg Sonnenberger
1394666d2603SJoerg Sonnenberger if (type != SYS_RES_MEMORY)
1395666d2603SJoerg Sonnenberger return (EINVAL);
1396666d2603SJoerg Sonnenberger res = cbb_find_res(sc, type, rid);
1397666d2603SJoerg Sonnenberger if (res == NULL) {
1398666d2603SJoerg Sonnenberger device_printf(brdev,
1399666d2603SJoerg Sonnenberger "set_res_flags: specified rid not found\n");
1400666d2603SJoerg Sonnenberger return (ENOENT);
1401666d2603SJoerg Sonnenberger }
14023aef8050SSepherosa Ziehau return (exca_mem_set_flags(&sc->exca[0], res, flags));
1403666d2603SJoerg Sonnenberger }
1404666d2603SJoerg Sonnenberger
14053aef8050SSepherosa Ziehau int
cbb_pcic_set_memory_offset(device_t brdev,device_t child,int rid,uint32_t cardaddr,uint32_t * deltap)1406666d2603SJoerg Sonnenberger cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
1407666d2603SJoerg Sonnenberger uint32_t cardaddr, uint32_t *deltap)
1408666d2603SJoerg Sonnenberger {
1409666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1410666d2603SJoerg Sonnenberger struct resource *res;
1411666d2603SJoerg Sonnenberger
1412666d2603SJoerg Sonnenberger res = cbb_find_res(sc, SYS_RES_MEMORY, rid);
1413666d2603SJoerg Sonnenberger if (res == NULL) {
1414666d2603SJoerg Sonnenberger device_printf(brdev,
1415666d2603SJoerg Sonnenberger "set_memory_offset: specified rid not found\n");
1416666d2603SJoerg Sonnenberger return (ENOENT);
1417666d2603SJoerg Sonnenberger }
14183aef8050SSepherosa Ziehau return (exca_mem_set_offset(&sc->exca[0], res, cardaddr, deltap));
1419666d2603SJoerg Sonnenberger }
1420666d2603SJoerg Sonnenberger
1421666d2603SJoerg Sonnenberger /************************************************************************/
1422666d2603SJoerg Sonnenberger /* BUS Methods */
1423666d2603SJoerg Sonnenberger /************************************************************************/
1424666d2603SJoerg Sonnenberger
1425666d2603SJoerg Sonnenberger
14263aef8050SSepherosa Ziehau int
cbb_activate_resource(device_t brdev,device_t child,int type,int rid,struct resource * r)1427666d2603SJoerg Sonnenberger cbb_activate_resource(device_t brdev, device_t child, int type, int rid,
1428666d2603SJoerg Sonnenberger struct resource *r)
1429666d2603SJoerg Sonnenberger {
1430666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1431666d2603SJoerg Sonnenberger
1432666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1433666d2603SJoerg Sonnenberger return (cbb_pcic_activate_resource(brdev, child, type, rid, r));
1434666d2603SJoerg Sonnenberger else
1435666d2603SJoerg Sonnenberger return (cbb_cardbus_activate_resource(brdev, child, type, rid,
1436666d2603SJoerg Sonnenberger r));
1437666d2603SJoerg Sonnenberger }
1438666d2603SJoerg Sonnenberger
14393aef8050SSepherosa Ziehau int
cbb_deactivate_resource(device_t brdev,device_t child,int type,int rid,struct resource * r)1440666d2603SJoerg Sonnenberger cbb_deactivate_resource(device_t brdev, device_t child, int type,
1441666d2603SJoerg Sonnenberger int rid, struct resource *r)
1442666d2603SJoerg Sonnenberger {
1443666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1444666d2603SJoerg Sonnenberger
1445666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1446666d2603SJoerg Sonnenberger return (cbb_pcic_deactivate_resource(brdev, child, type,
1447666d2603SJoerg Sonnenberger rid, r));
1448666d2603SJoerg Sonnenberger else
1449666d2603SJoerg Sonnenberger return (cbb_cardbus_deactivate_resource(brdev, child, type,
1450666d2603SJoerg Sonnenberger rid, r));
1451666d2603SJoerg Sonnenberger }
1452666d2603SJoerg Sonnenberger
14533aef8050SSepherosa Ziehau struct resource *
cbb_alloc_resource(device_t brdev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid)1454666d2603SJoerg Sonnenberger cbb_alloc_resource(device_t brdev, device_t child, int type, int *rid,
14554f7fe8c7SSepherosa Ziehau u_long start, u_long end, u_long count, u_int flags, int cpuid)
1456666d2603SJoerg Sonnenberger {
1457666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1458666d2603SJoerg Sonnenberger
1459666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1460666d2603SJoerg Sonnenberger return (cbb_pcic_alloc_resource(brdev, child, type, rid,
14614f7fe8c7SSepherosa Ziehau start, end, count, flags, cpuid));
1462666d2603SJoerg Sonnenberger else
1463666d2603SJoerg Sonnenberger return (cbb_cardbus_alloc_resource(brdev, child, type, rid,
14644f7fe8c7SSepherosa Ziehau start, end, count, flags, cpuid));
1465666d2603SJoerg Sonnenberger }
1466666d2603SJoerg Sonnenberger
14673aef8050SSepherosa Ziehau int
cbb_release_resource(device_t brdev,device_t child,int type,int rid,struct resource * r)1468666d2603SJoerg Sonnenberger cbb_release_resource(device_t brdev, device_t child, int type, int rid,
1469666d2603SJoerg Sonnenberger struct resource *r)
1470666d2603SJoerg Sonnenberger {
1471666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1472666d2603SJoerg Sonnenberger
1473666d2603SJoerg Sonnenberger if (sc->flags & CBB_16BIT_CARD)
1474666d2603SJoerg Sonnenberger return (cbb_pcic_release_resource(brdev, child, type,
1475666d2603SJoerg Sonnenberger rid, r));
1476666d2603SJoerg Sonnenberger else
1477666d2603SJoerg Sonnenberger return (cbb_cardbus_release_resource(brdev, child, type,
1478666d2603SJoerg Sonnenberger rid, r));
1479666d2603SJoerg Sonnenberger }
1480666d2603SJoerg Sonnenberger
14813aef8050SSepherosa Ziehau int
cbb_read_ivar(device_t brdev,device_t child,int which,uintptr_t * result)1482666d2603SJoerg Sonnenberger cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
1483666d2603SJoerg Sonnenberger {
1484666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1485666d2603SJoerg Sonnenberger
1486666d2603SJoerg Sonnenberger switch (which) {
1487bb3d3555SSepherosa Ziehau case PCIB_IVAR_DOMAIN:
1488bb3d3555SSepherosa Ziehau *result = sc->domain;
1489bb3d3555SSepherosa Ziehau return (0);
1490666d2603SJoerg Sonnenberger case PCIB_IVAR_BUS:
1491666d2603SJoerg Sonnenberger *result = sc->secbus;
1492666d2603SJoerg Sonnenberger return (0);
1493666d2603SJoerg Sonnenberger }
1494666d2603SJoerg Sonnenberger return (ENOENT);
1495666d2603SJoerg Sonnenberger }
1496666d2603SJoerg Sonnenberger
14973aef8050SSepherosa Ziehau int
cbb_write_ivar(device_t brdev,device_t child,int which,uintptr_t value)1498666d2603SJoerg Sonnenberger cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
1499666d2603SJoerg Sonnenberger {
1500666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(brdev);
1501666d2603SJoerg Sonnenberger
1502666d2603SJoerg Sonnenberger switch (which) {
1503bb3d3555SSepherosa Ziehau case PCIB_IVAR_DOMAIN:
1504bb3d3555SSepherosa Ziehau return (EINVAL);
1505666d2603SJoerg Sonnenberger case PCIB_IVAR_BUS:
1506666d2603SJoerg Sonnenberger sc->secbus = value;
1507666d2603SJoerg Sonnenberger break;
1508666d2603SJoerg Sonnenberger }
1509666d2603SJoerg Sonnenberger return (ENOENT);
1510666d2603SJoerg Sonnenberger }
1511666d2603SJoerg Sonnenberger
1512666d2603SJoerg Sonnenberger /************************************************************************/
1513666d2603SJoerg Sonnenberger /* PCI compat methods */
1514666d2603SJoerg Sonnenberger /************************************************************************/
1515666d2603SJoerg Sonnenberger
15163aef8050SSepherosa Ziehau int
cbb_maxslots(device_t brdev)1517666d2603SJoerg Sonnenberger cbb_maxslots(device_t brdev)
1518666d2603SJoerg Sonnenberger {
1519666d2603SJoerg Sonnenberger return (0);
1520666d2603SJoerg Sonnenberger }
1521666d2603SJoerg Sonnenberger
15223aef8050SSepherosa Ziehau uint32_t
cbb_read_config(device_t brdev,int b,int s,int f,int reg,int width)1523666d2603SJoerg Sonnenberger cbb_read_config(device_t brdev, int b, int s, int f, int reg, int width)
1524666d2603SJoerg Sonnenberger {
15253aef8050SSepherosa Ziehau uint32_t rv;
15263aef8050SSepherosa Ziehau
1527666d2603SJoerg Sonnenberger /*
1528666d2603SJoerg Sonnenberger * Pass through to the next ppb up the chain (i.e. our grandparent).
1529666d2603SJoerg Sonnenberger */
15303aef8050SSepherosa Ziehau rv = PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)),
15313aef8050SSepherosa Ziehau b, s, f, reg, width);
15323aef8050SSepherosa Ziehau return (rv);
1533666d2603SJoerg Sonnenberger }
1534666d2603SJoerg Sonnenberger
15353aef8050SSepherosa Ziehau void
cbb_write_config(device_t brdev,int b,int s,int f,int reg,uint32_t val,int width)1536666d2603SJoerg Sonnenberger cbb_write_config(device_t brdev, int b, int s, int f, int reg, uint32_t val,
1537666d2603SJoerg Sonnenberger int width)
1538666d2603SJoerg Sonnenberger {
1539666d2603SJoerg Sonnenberger /*
1540666d2603SJoerg Sonnenberger * Pass through to the next ppb up the chain (i.e. our grandparent).
1541666d2603SJoerg Sonnenberger */
1542666d2603SJoerg Sonnenberger PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(brdev)),
1543666d2603SJoerg Sonnenberger b, s, f, reg, val, width);
1544666d2603SJoerg Sonnenberger }
1545666d2603SJoerg Sonnenberger
15463aef8050SSepherosa Ziehau int
cbb_suspend(device_t self)1547666d2603SJoerg Sonnenberger cbb_suspend(device_t self)
1548666d2603SJoerg Sonnenberger {
1549666d2603SJoerg Sonnenberger int error = 0;
1550666d2603SJoerg Sonnenberger struct cbb_softc *sc = device_get_softc(self);
1551666d2603SJoerg Sonnenberger
15523aef8050SSepherosa Ziehau cbb_set(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */
1553666d2603SJoerg Sonnenberger bus_teardown_intr(self, sc->irq_res, sc->intrhand);
1554666d2603SJoerg Sonnenberger sc->flags &= ~CBB_CARD_OK; /* Card is bogus now */
1555666d2603SJoerg Sonnenberger error = bus_generic_suspend(self);
1556666d2603SJoerg Sonnenberger return (error);
1557666d2603SJoerg Sonnenberger }
1558666d2603SJoerg Sonnenberger
15593aef8050SSepherosa Ziehau int
cbb_resume(device_t self)1560666d2603SJoerg Sonnenberger cbb_resume(device_t self)
1561666d2603SJoerg Sonnenberger {
1562666d2603SJoerg Sonnenberger int error = 0;
1563666d2603SJoerg Sonnenberger struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
1564666d2603SJoerg Sonnenberger uint32_t tmp;
1565666d2603SJoerg Sonnenberger
1566666d2603SJoerg Sonnenberger /*
1567666d2603SJoerg Sonnenberger * Some BIOSes will not save the BARs for the pci chips, so we
1568666d2603SJoerg Sonnenberger * must do it ourselves. If the BAR is reset to 0 for an I/O
1569666d2603SJoerg Sonnenberger * device, it will read back as 0x1, so no explicit test for
1570666d2603SJoerg Sonnenberger * memory devices are needed.
1571666d2603SJoerg Sonnenberger *
1572666d2603SJoerg Sonnenberger * Note: The PCI bus code should do this automatically for us on
1573666d2603SJoerg Sonnenberger * suspend/resume, but until it does, we have to cope.
1574666d2603SJoerg Sonnenberger */
1575666d2603SJoerg Sonnenberger pci_write_config(self, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
1576666d2603SJoerg Sonnenberger DEVPRINTF((self, "PCI Memory allocated: %08lx\n",
1577666d2603SJoerg Sonnenberger rman_get_start(sc->base_res)));
1578666d2603SJoerg Sonnenberger
15793aef8050SSepherosa Ziehau sc->chipinit(sc);
1580666d2603SJoerg Sonnenberger
1581666d2603SJoerg Sonnenberger /* reset interrupt -- Do we really need to do this? */
1582666d2603SJoerg Sonnenberger tmp = cbb_get(sc, CBB_SOCKET_EVENT);
1583666d2603SJoerg Sonnenberger cbb_set(sc, CBB_SOCKET_EVENT, tmp);
1584666d2603SJoerg Sonnenberger
1585666d2603SJoerg Sonnenberger /* re-establish the interrupt. */
15863aef8050SSepherosa Ziehau if (bus_setup_intr(self, sc->irq_res, INTR_MPSAFE, cbb_intr, sc,
1587e9cb6d99SMatthew Dillon &sc->intrhand, NULL)) {
1588666d2603SJoerg Sonnenberger device_printf(self, "couldn't re-establish interrupt");
1589666d2603SJoerg Sonnenberger bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
1590666d2603SJoerg Sonnenberger bus_release_resource(self, SYS_RES_MEMORY, CBBR_SOCKBASE,
1591666d2603SJoerg Sonnenberger sc->base_res);
1592666d2603SJoerg Sonnenberger sc->irq_res = NULL;
1593666d2603SJoerg Sonnenberger sc->base_res = NULL;
1594666d2603SJoerg Sonnenberger return (ENOMEM);
1595666d2603SJoerg Sonnenberger }
1596666d2603SJoerg Sonnenberger
1597666d2603SJoerg Sonnenberger /* CSC Interrupt: Card detect interrupt on */
1598666d2603SJoerg Sonnenberger cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
1599666d2603SJoerg Sonnenberger
1600666d2603SJoerg Sonnenberger /* Signal the thread to wakeup. */
16013aef8050SSepherosa Ziehau wakeup_one(&sc->generic_cv);
1602666d2603SJoerg Sonnenberger
1603666d2603SJoerg Sonnenberger error = bus_generic_resume(self);
1604666d2603SJoerg Sonnenberger
1605666d2603SJoerg Sonnenberger return (error);
1606666d2603SJoerg Sonnenberger }
1607666d2603SJoerg Sonnenberger
16083aef8050SSepherosa Ziehau int
cbb_child_present(device_t self)1609666d2603SJoerg Sonnenberger cbb_child_present(device_t self)
1610666d2603SJoerg Sonnenberger {
1611666d2603SJoerg Sonnenberger struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
1612666d2603SJoerg Sonnenberger uint32_t sockstate;
1613666d2603SJoerg Sonnenberger
1614666d2603SJoerg Sonnenberger sockstate = cbb_get(sc, CBB_SOCKET_STATE);
16153aef8050SSepherosa Ziehau return (CBB_CARD_PRESENT(sockstate) &&
16163aef8050SSepherosa Ziehau (sc->flags & CBB_CARD_OK) == CBB_CARD_OK);
1617666d2603SJoerg Sonnenberger }
1618