xref: /dragonfly/sys/dev/pccard/pccbb/pccbb.c (revision 0e6f0e28)
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