xref: /freebsd/sys/dev/cardbus/cardbus.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/sysctl.h>
36 
37 #include <sys/bus.h>
38 #include <machine/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41 
42 #include <sys/pciio.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pci_private.h>
46 
47 #include <dev/cardbus/cardbusreg.h>
48 #include <dev/cardbus/cardbusvar.h>
49 #include <dev/cardbus/cardbus_cis.h>
50 #include <dev/pccard/pccardvar.h>
51 
52 #include "power_if.h"
53 #include "pcib_if.h"
54 
55 /* sysctl vars */
56 SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters");
57 
58 int    cardbus_debug = 0;
59 TUNABLE_INT("hw.cardbus.debug", &cardbus_debug);
60 SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW,
61     &cardbus_debug, 0,
62   "CardBus debug");
63 
64 int    cardbus_cis_debug = 0;
65 TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug);
66 SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW,
67     &cardbus_cis_debug, 0,
68   "CardBus CIS debug");
69 
70 #define	DPRINTF(a) if (cardbus_debug) printf a
71 #define	DEVPRINTF(x) if (cardbus_debug) device_printf x
72 
73 
74 static int	cardbus_attach(device_t cbdev);
75 static int	cardbus_attach_card(device_t cbdev);
76 static int	cardbus_detach(device_t cbdev);
77 static int	cardbus_detach_card(device_t cbdev);
78 static void	cardbus_device_setup_regs(device_t brdev, int b, int s, int f,
79 		    pcicfgregs *cfg);
80 static void	cardbus_driver_added(device_t cbdev, driver_t *driver);
81 static int	cardbus_probe(device_t cbdev);
82 static int	cardbus_read_ivar(device_t cbdev, device_t child, int which,
83 		    uintptr_t *result);
84 static void	cardbus_release_all_resources(device_t cbdev,
85 		    struct cardbus_devinfo *dinfo);
86 static int	cardbus_write_ivar(device_t cbdev, device_t child, int which,
87 		    uintptr_t value);
88 
89 /************************************************************************/
90 /* Probe/Attach								*/
91 /************************************************************************/
92 
93 static int
94 cardbus_probe(device_t cbdev)
95 {
96 	device_set_desc(cbdev, "CardBus bus");
97 	return 0;
98 }
99 
100 static int
101 cardbus_attach(device_t cbdev)
102 {
103 	return 0;
104 }
105 
106 static int
107 cardbus_detach(device_t cbdev)
108 {
109 	cardbus_detach_card(cbdev);
110 	return 0;
111 }
112 
113 static int
114 cardbus_suspend(device_t self)
115 {
116 	cardbus_detach_card(self);
117 	return (0);
118 }
119 
120 static int
121 cardbus_resume(device_t self)
122 {
123 	return (0);
124 }
125 
126 /************************************************************************/
127 /* Attach/Detach card							*/
128 /************************************************************************/
129 
130 static void
131 cardbus_device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg)
132 {
133 	PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_INTLINE,
134 	    pci_get_irq(device_get_parent(brdev)), 1);
135 	cfg->intline = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_INTLINE, 1);
136 
137 	PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1);
138 	cfg->cachelnsz = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 1);
139 
140 	PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 0xa8, 1);
141 	cfg->lattimer = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 1);
142 
143 	PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MINGNT, 0x14, 1);
144 	cfg->mingnt = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MINGNT, 1);
145 
146 	PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 0x14, 1);
147 	cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1);
148 }
149 
150 static int
151 cardbus_attach_card(device_t cbdev)
152 {
153 	device_t brdev = device_get_parent(cbdev);
154 	int cardattached = 0;
155 	static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
156 	int bus, slot, func;
157 
158 	cardbus_detach_card(cbdev); /* detach existing cards */
159 
160 	POWER_ENABLE_SOCKET(brdev, cbdev);
161 	bus = pcib_get_bus(cbdev);
162 	if (bus == 0) {
163 		/*
164 		 * XXX EVILE BAD XXX
165 		 * Not all BIOSes initialize the secondary bus number properly,
166 		 * so if the default is bad, we just put one in and hope it
167 		 * works.
168 		 */
169 		bus = curr_bus_number;
170 		pci_write_config(brdev, PCIR_SECBUS_2, curr_bus_number, 1);
171 		pci_write_config(brdev, PCIR_SUBBUS_2, curr_bus_number + 2, 1);
172 		curr_bus_number += 3;
173 	}
174 	/* For each function, set it up and try to attach a driver to it */
175 	for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) {
176 		int cardbusfunchigh = 0;
177 		for (func = 0; func <= cardbusfunchigh; func++) {
178 			struct cardbus_devinfo *dinfo;
179 
180 			dinfo = (struct cardbus_devinfo *)
181 			    pci_read_device(brdev, 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 			cardbus_device_setup_regs(brdev, bus, slot, func,
189 			    &dinfo->pci.cfg);
190 			dinfo->pci.cfg.dev = device_add_child(cbdev, NULL, -1);
191 			if (!dinfo->pci.cfg.dev) {
192 				DEVPRINTF((cbdev, "Cannot add child!\n"));
193 				pci_freecfg((struct pci_devinfo *)dinfo);
194 				continue;
195 			}
196 			resource_list_init(&dinfo->pci.resources);
197 			device_set_ivars(dinfo->pci.cfg.dev, dinfo);
198 			cardbus_do_cis(cbdev, dinfo->pci.cfg.dev);
199 			pci_print_verbose(&dinfo->pci);
200 			if (device_probe_and_attach(dinfo->pci.cfg.dev) != 0)
201 				cardbus_release_all_resources(cbdev, dinfo);
202 			else
203 				cardattached++;
204 		}
205 	}
206 
207 	if (cardattached > 0)
208 		return (0);
209 	POWER_DISABLE_SOCKET(brdev, cbdev);
210 	return (ENOENT);
211 }
212 
213 static int
214 cardbus_detach_card(device_t cbdev)
215 {
216 	int numdevs;
217 	device_t *devlist;
218 	int tmp;
219 	int err = 0;
220 
221 	device_get_children(cbdev, &devlist, &numdevs);
222 
223 	if (numdevs == 0) {
224 		free(devlist, M_TEMP);
225 		return (ENOENT);
226 	}
227 
228 	for (tmp = 0; tmp < numdevs; tmp++) {
229 		struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]);
230 		int status = device_get_state(devlist[tmp]);
231 
232 		if (dinfo->pci.cfg.dev != devlist[tmp])
233 			device_printf(cbdev, "devinfo dev mismatch\n");
234 		if (status == DS_ATTACHED || status == DS_BUSY)
235 			device_detach(devlist[tmp]);
236 		cardbus_release_all_resources(cbdev, dinfo);
237 		device_delete_child(cbdev, devlist[tmp]);
238 		pci_freecfg((struct pci_devinfo *)dinfo);
239 	}
240 	POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);
241 	free(devlist, M_TEMP);
242 	return (err);
243 }
244 
245 static void
246 cardbus_driver_added(device_t cbdev, driver_t *driver)
247 {
248 	int numdevs;
249 	device_t *devlist;
250 	device_t dev;
251 	int i;
252 	struct cardbus_devinfo *dinfo;
253 
254 	DEVICE_IDENTIFY(driver, cbdev);
255 	device_get_children(cbdev, &devlist, &numdevs);
256 	/*
257 	 * If there are no drivers attached, but there are children,
258 	 * then power the card up.
259 	 */
260 	for (i = 0; i < numdevs; i++) {
261 		dev = devlist[i];
262 		if (device_get_state(dev) != DS_NOTPRESENT)
263 		    break;
264 	}
265 	if (i > 0 && i == numdevs)
266 		POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev);
267 	for (i = 0; i < numdevs; i++) {
268 		dev = devlist[i];
269 		if (device_get_state(dev) != DS_NOTPRESENT)
270 			continue;
271 		dinfo = device_get_ivars(dev);
272 		pci_print_verbose(&dinfo->pci);
273 		resource_list_init(&dinfo->pci.resources);
274 		cardbus_do_cis(cbdev, dev);
275 		if (device_probe_and_attach(dev) != 0)
276 			cardbus_release_all_resources(cbdev, dinfo);
277 	}
278 	free(devlist, M_TEMP);
279 }
280 
281 static void
282 cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo)
283 {
284 	struct resource_list_entry *rle;
285 
286 	/* Free all allocated resources */
287 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
288 		if (rle->res) {
289 			if (rman_get_device(rle->res) != cbdev)
290 				device_printf(cbdev, "release_all_resource: "
291 				    "Resource still owned by child, oops. "
292 				    "(type=%d, rid=%d, addr=%lx)\n",
293 				    rle->type, rle->rid,
294 				    rman_get_start(rle->res));
295 			BUS_RELEASE_RESOURCE(device_get_parent(cbdev),
296 			    cbdev, rle->type, rle->rid, rle->res);
297 			rle->res = NULL;
298 			/*
299 			 * zero out config so the card won't acknowledge
300 			 * access to the space anymore
301 			 */
302 			pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4);
303 		}
304 	}
305 	resource_list_free(&dinfo->pci.resources);
306 }
307 
308 /************************************************************************/
309 /* Other Bus Methods							*/
310 /************************************************************************/
311 
312 static int
313 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result)
314 {
315 	struct cardbus_devinfo *dinfo;
316 	pcicfgregs *cfg;
317 
318 	dinfo = device_get_ivars(child);
319 	cfg = &dinfo->pci.cfg;
320 
321 	switch (which) {
322 	case PCI_IVAR_ETHADDR:
323 		/*
324 		 * The generic accessor doesn't deal with failure, so
325 		 * we set the return value, then return an error.
326 		 */
327 		if ((dinfo->fepresent & (1 << TPL_FUNCE_LAN_NID)) == 0) {
328 			*((uint8_t **) result) = NULL;
329 			return (EINVAL);
330 		}
331 		*((uint8_t **) result) = dinfo->funce.lan.nid;
332 		break;
333 	default:
334 		return (pci_read_ivar(cbdev, child, which, result));
335 	}
336 	return 0;
337 }
338 
339 static int
340 cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value)
341 {
342 	return(pci_write_ivar(cbdev, child, which, value));
343 }
344 
345 static device_method_t cardbus_methods[] = {
346 	/* Device interface */
347 	DEVMETHOD(device_probe,		cardbus_probe),
348 	DEVMETHOD(device_attach,	cardbus_attach),
349 	DEVMETHOD(device_detach,	cardbus_detach),
350 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
351 	DEVMETHOD(device_suspend,	cardbus_suspend),
352 	DEVMETHOD(device_resume,	cardbus_resume),
353 
354 	/* Bus interface */
355 	DEVMETHOD(bus_print_child,	pci_print_child),
356 	DEVMETHOD(bus_probe_nomatch,	pci_probe_nomatch),
357 	DEVMETHOD(bus_read_ivar,	cardbus_read_ivar),
358 	DEVMETHOD(bus_write_ivar,	cardbus_write_ivar),
359 	DEVMETHOD(bus_driver_added,	cardbus_driver_added),
360 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
361 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
362 	DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
363 	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
364 	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
365 	DEVMETHOD(bus_delete_resource,	pci_delete_resource),
366 	DEVMETHOD(bus_alloc_resource,	pci_alloc_resource),
367 	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
368 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
369 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
370 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
371 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
372 	DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
373 	DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
374 
375 	/* Card Interface */
376 	DEVMETHOD(card_attach_card,	cardbus_attach_card),
377 	DEVMETHOD(card_detach_card,	cardbus_detach_card),
378 	DEVMETHOD(card_cis_read,	cardbus_cis_read),
379 	DEVMETHOD(card_cis_free,	cardbus_cis_free),
380 
381 	/* Cardbus/PCI interface */
382 	DEVMETHOD(pci_read_config,	pci_read_config_method),
383 	DEVMETHOD(pci_write_config,	pci_write_config_method),
384 	DEVMETHOD(pci_enable_busmaster,	pci_enable_busmaster_method),
385 	DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
386 	DEVMETHOD(pci_enable_io,	pci_enable_io_method),
387 	DEVMETHOD(pci_disable_io,	pci_disable_io_method),
388 	DEVMETHOD(pci_get_powerstate,	pci_get_powerstate_method),
389 	DEVMETHOD(pci_set_powerstate,	pci_set_powerstate_method),
390 
391 	{0,0}
392 };
393 
394 static driver_t cardbus_driver = {
395 	"cardbus",
396 	cardbus_methods,
397 	0 /* no softc */
398 };
399 
400 static devclass_t cardbus_devclass;
401 
402 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0);
403 MODULE_VERSION(cardbus, 1);
404