xref: /dragonfly/sys/dev/pccard/cardbus/cardbus.c (revision f2c43266)
1 /*-
2  * Copyright (c) 2003 M. Warner Losh.  All Rights Reserved.
3  * Copyright (c) 2000,2001 Jonathan Chen.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/cardbus/cardbus.c,v 1.28 2002/11/27 17:30:41 imp Exp $
27  * $FreeBSD @153896,@153900,@159532,@166104 merged
28  * $FreeBSD @169620,@169633 merged
29  */
30 
31 /*
32  * Cardbus Bus Driver
33  *
34  * much of the bus code was stolen directly from sys/pci/pci.c
35  *   (Copyright (c) 1997, Stefan Esser <se@freebsd.org>)
36  *
37  * Written by Jonathan Chen <jon@freebsd.org>
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
46 
47 #include <sys/bus.h>
48 #include <sys/rman.h>
49 
50 #include <sys/pciio.h>
51 #include <bus/pci/pcivar.h>
52 #include <bus/pci/pcireg.h>
53 #include <bus/pci/pci_private.h>
54 
55 #include <dev/pccard/cardbus/cardbusreg.h>
56 #include <dev/pccard/cardbus/cardbusvar.h>
57 #include <dev/pccard/cardbus/cardbus_cis.h>
58 #include <bus/pccard/pccard_cis.h>
59 #include <bus/pccard/pccardvar.h>
60 
61 #include "power_if.h"
62 #include "pcib_if.h"
63 
64 /* sysctl vars */
65 SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters");
66 
67 int    cardbus_debug = 0;
68 TUNABLE_INT("hw.cardbus.debug", &cardbus_debug);
69 SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW,
70     &cardbus_debug, 0,
71   "CardBus debug");
72 
73 int    cardbus_cis_debug = 0;
74 TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug);
75 SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW,
76     &cardbus_cis_debug, 0,
77   "CardBus CIS debug");
78 
79 #define	DPRINTF(a) if (cardbus_debug) kprintf a
80 #define	DEVPRINTF(x) if (cardbus_debug) device_printf x
81 
82 
83 static int	cardbus_attach(device_t cbdev);
84 static int	cardbus_attach_card(device_t cbdev);
85 static int	cardbus_detach(device_t cbdev);
86 static int	cardbus_detach_card(device_t cbdev);
87 static void	cardbus_device_setup_regs(pcicfgregs *cfg);
88 static void	cardbus_driver_added(device_t cbdev, driver_t *driver);
89 static int	cardbus_probe(device_t cbdev);
90 static int	cardbus_read_ivar(device_t cbdev, device_t child, int which,
91 		    uintptr_t *result);
92 static void	cardbus_release_all_resources(device_t cbdev,
93 		    struct cardbus_devinfo *dinfo);
94 static int	cardbus_write_ivar(device_t cbdev, device_t child, int which,
95 		    uintptr_t value);
96 
97 /************************************************************************/
98 /* Probe/Attach								*/
99 /************************************************************************/
100 
101 static int
102 cardbus_probe(device_t cbdev)
103 {
104 	device_set_desc(cbdev, "CardBus bus");
105 	return 0;
106 }
107 
108 static int
109 cardbus_attach(device_t cbdev)
110 {
111 	return 0;
112 }
113 
114 static int
115 cardbus_detach(device_t cbdev)
116 {
117 	cardbus_detach_card(cbdev);
118 	return 0;
119 }
120 
121 static int
122 cardbus_suspend(device_t self)
123 {
124 	cardbus_detach_card(self);
125 	return (0);
126 }
127 
128 static int
129 cardbus_resume(device_t self)
130 {
131 	return (0);
132 }
133 
134 /************************************************************************/
135 /* Attach/Detach card							*/
136 /************************************************************************/
137 
138 static void
139 cardbus_device_setup_regs(pcicfgregs *cfg)
140 {
141 	device_t dev = cfg->dev;
142 	int i;
143 
144 	/*
145 	 * Some cards power up with garbage in their BARs.  This
146 	 * code clears all that junk out.
147 	 */
148 	for (i = 0; i < PCIR_MAX_BAR_0; i++)
149 		pci_write_config(dev, PCIR_BAR(i), 0, 4);
150 
151 	cfg->intline =
152 	    pci_get_irq(device_get_parent(device_get_parent(dev)));
153 	pci_write_config(dev, PCIR_INTLINE, cfg->intline, 1);
154 	pci_write_config(dev, PCIR_CACHELNSZ, 0x08, 1);
155 	pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1);
156 	pci_write_config(dev, PCIR_MINGNT, 0x14, 1);
157 	pci_write_config(dev, PCIR_MAXLAT, 0x14, 1);
158 }
159 
160 static int
161 cardbus_attach_card(device_t cbdev)
162 {
163 	device_t brdev = device_get_parent(cbdev);
164 	device_t child;
165 	int cardattached = 0;
166 	int bus, slot, func, domain;
167 
168 	cardbus_detach_card(cbdev); /* detach existing cards */
169 	POWER_ENABLE_SOCKET(brdev, cbdev);
170 	bus = pcib_get_bus(cbdev);
171 	domain = pcib_get_domain(cbdev);
172 
173 	/* For each function, set it up and try to attach a driver to it */
174 	for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) {
175 		int cardbusfunchigh = 0;
176 
177 		for (func = 0; func <= cardbusfunchigh; func++) {
178 			struct cardbus_devinfo *dinfo;
179 
180 			dinfo = (struct cardbus_devinfo *)
181 			    pci_read_device(brdev, domain, bus, slot, func,
182 				sizeof(struct cardbus_devinfo));
183 			if (dinfo == NULL)
184 				continue;
185 			if (dinfo->pci.cfg.mfdev)
186 				cardbusfunchigh = CARDBUS_FUNCMAX;
187 
188 			child = device_add_child(cbdev, NULL, -1);
189 			if (child == NULL) {
190 				DEVPRINTF((cbdev, "Cannot add child!\n"));
191 				pci_freecfg((struct pci_devinfo *)dinfo);
192 				continue;
193 			}
194 			dinfo->pci.cfg.dev = child;
195 			resource_list_init(&dinfo->pci.resources);
196 			device_set_ivars(child, dinfo);
197 			if (cardbus_do_cis(cbdev, child) != 0) {
198 				DEVPRINTF((cbdev,
199 					   "Warning: Bogus CIS ignored\n"));
200 			}
201 			pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
202 			pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci);
203 			cardbus_device_setup_regs(&dinfo->pci.cfg);
204 			pci_add_resources(brdev, cbdev, child, 1,
205 					  dinfo->mprefetchable);
206 			pci_print_verbose(&dinfo->pci);
207 			if (device_probe_and_attach(child) != 0)
208 				pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1);
209 			else
210 				cardattached++;
211 		}
212 	}
213 
214 	if (cardattached > 0)
215 		return (0);
216 	POWER_DISABLE_SOCKET(brdev, cbdev);
217 	return (ENOENT);
218 }
219 
220 static int
221 cardbus_detach_card(device_t cbdev)
222 {
223 	int numdevs;
224 	device_t *devlist;
225 	int tmp;
226 	int err = 0;
227 
228 	if (device_get_children(cbdev, &devlist, &numdevs) != 0)
229 		return (ENOENT);
230 
231 	if (numdevs == 0) {
232 		kfree(devlist, M_TEMP);
233 		return (ENOENT);
234 	}
235 
236 	for (tmp = 0; tmp < numdevs; tmp++) {
237 		struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]);
238 		int status = device_get_state(devlist[tmp]);
239 
240 		if (dinfo->pci.cfg.dev != devlist[tmp])
241 			device_printf(cbdev, "devinfo dev mismatch\n");
242 		if (status == DS_ATTACHED || status == DS_BUSY)
243 			device_detach(devlist[tmp]);
244 		cardbus_release_all_resources(cbdev, dinfo);
245 		device_delete_child(cbdev, devlist[tmp]);
246 		pci_freecfg((struct pci_devinfo *)dinfo);
247 	}
248 	POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);
249 	kfree(devlist, M_TEMP);
250 	return (err);
251 }
252 
253 static void
254 cardbus_driver_added(device_t cbdev, driver_t *driver)
255 {
256 	int numdevs;
257 	device_t *devlist;
258 	device_t dev;
259 	int i;
260 	struct cardbus_devinfo *dinfo;
261 
262 	DEVICE_IDENTIFY(driver, cbdev);
263 	if (device_get_children(cbdev, &devlist, &numdevs) != 0)
264 		return;
265 
266 	/*
267 	 * If there are no drivers attached, but there are children,
268 	 * then power the card up.
269 	 */
270 	for (i = 0; i < numdevs; i++) {
271 		dev = devlist[i];
272 		if (device_get_state(dev) != DS_NOTPRESENT)
273 		    break;
274 	}
275 	if (i > 0 && i == numdevs)
276 		POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev);
277 	for (i = 0; i < numdevs; i++) {
278 		dev = devlist[i];
279 		if (device_get_state(dev) != DS_NOTPRESENT)
280 			continue;
281 		dinfo = device_get_ivars(dev);
282 		pci_print_verbose(&dinfo->pci);
283 		if (bootverbose)
284 			kprintf("pci%d:%d:%d:%d: reprobing on driver added\n",
285 			    dinfo->pci.cfg.domain, dinfo->pci.cfg.bus,
286 			    dinfo->pci.cfg.slot, dinfo->pci.cfg.func);
287 		pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci);
288 		if (device_probe_and_attach(dev) != 0)
289 			pci_cfg_save(dev, &dinfo->pci, 1);
290 	}
291 	kfree(devlist, M_TEMP);
292 }
293 
294 static void
295 cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo)
296 {
297 	struct resource_list_entry *rle;
298 
299 	/* Free all allocated resources */
300 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
301 		if (rle->res) {
302 			BUS_RELEASE_RESOURCE(device_get_parent(cbdev),
303 			    cbdev, rle->type, rle->rid, rle->res);
304 			rle->res = NULL;
305 			/*
306 			 * zero out config so the card won't acknowledge
307 			 * access to the space anymore
308 			 */
309 			pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4);
310 		}
311 	}
312 	resource_list_free(&dinfo->pci.resources);
313 }
314 
315 /************************************************************************/
316 /* Other Bus Methods							*/
317 /************************************************************************/
318 
319 static int
320 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result)
321 {
322 	struct cardbus_devinfo *dinfo;
323 
324 	dinfo = device_get_ivars(child);
325 
326 	switch (which) {
327 	case PCI_IVAR_ETHADDR:
328 		/*
329 		 * The generic accessor doesn't deal with failure, so
330 		 * we set the return value, then return an error.
331 		 */
332 		if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) {
333 			*((uint8_t **) result) = dinfo->funce.lan.nid;
334 			break;
335 		}
336 		*((uint8_t **) result) = NULL;
337 		return (EINVAL);
338 	default:
339 		return (pci_read_ivar(cbdev, child, which, result));
340 	}
341 	return 0;
342 }
343 
344 static int
345 cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value)
346 {
347 	return(pci_write_ivar(cbdev, child, which, value));
348 }
349 
350 static device_method_t cardbus_methods[] = {
351 	/* Device interface */
352 	DEVMETHOD(device_probe,		cardbus_probe),
353 	DEVMETHOD(device_attach,	cardbus_attach),
354 	DEVMETHOD(device_detach,	cardbus_detach),
355 	DEVMETHOD(device_suspend,	cardbus_suspend),
356 	DEVMETHOD(device_resume,	cardbus_resume),
357 
358 	/* Bus interface */
359 	DEVMETHOD(bus_read_ivar,	cardbus_read_ivar),
360 	DEVMETHOD(bus_write_ivar,	cardbus_write_ivar),
361 	DEVMETHOD(bus_driver_added,	cardbus_driver_added),
362 
363 	/* Card Interface */
364 	DEVMETHOD(card_attach_card,	cardbus_attach_card),
365 	DEVMETHOD(card_detach_card,	cardbus_detach_card),
366 
367 	DEVMETHOD_END
368 };
369 
370 DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 0, pci_driver);
371 
372 static devclass_t cardbus_devclass;
373 
374 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, NULL, NULL);
375 MODULE_VERSION(cardbus, 1);
376