1139749Simp/*-
2185015Simp * Copyright (c) 2003-2008 M. Warner Losh.  All Rights Reserved.
3111056Simp * Copyright (c) 2000,2001 Jonathan Chen.  All rights reserved.
453343Simp *
553343Simp * Redistribution and use in source and binary forms, with or without
653343Simp * modification, are permitted provided that the following conditions
753343Simp * are met:
853343Simp * 1. Redistributions of source code must retain the above copyright
9140198Simp *    notice, this list of conditions and the following disclaimer.
1053343Simp * 2. Redistributions in binary form must reproduce the above copyright
11140198Simp *    notice, this list of conditions and the following disclaimer in the
12140198Simp *    documentation and/or other materials provided with the distribution.
1353343Simp *
1467276Sjon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1567276Sjon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1667276Sjon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17140198Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18140198Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1967276Sjon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2067276Sjon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2167276Sjon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2267276Sjon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2367276Sjon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2467276Sjon * SUCH DAMAGE.
2553343Simp */
2667276Sjon
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/cardbus/cardbus.c 330938 2018-03-14 19:04:40Z jhb $");
29119418Sobrien
3053343Simp#include <sys/param.h>
3153343Simp#include <sys/systm.h>
3253343Simp#include <sys/malloc.h>
33129876Sphk#include <sys/module.h>
3453343Simp#include <sys/kernel.h>
3591787Simp#include <sys/sysctl.h>
3653343Simp
3767276Sjon#include <sys/bus.h>
3853343Simp#include <machine/bus.h>
3967276Sjon#include <sys/rman.h>
4067276Sjon#include <machine/resource.h>
4153343Simp
4291355Simp#include <sys/pciio.h>
4382378Sjon#include <dev/pci/pcivar.h>
4482378Sjon#include <dev/pci/pcireg.h>
45110975Simp#include <dev/pci/pci_private.h>
4653343Simp
4753343Simp#include <dev/cardbus/cardbusreg.h>
4853343Simp#include <dev/cardbus/cardbusvar.h>
4967276Sjon#include <dev/cardbus/cardbus_cis.h>
50141412Simp#include <dev/pccard/pccard_cis.h>
5197613Stakawata#include <dev/pccard/pccardvar.h>
5253343Simp
5369288Sjon#include "power_if.h"
5467276Sjon#include "pcib_if.h"
5553343Simp
5691787Simp/* sysctl vars */
57227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters");
5853343Simp
5992301Simpint    cardbus_debug = 0;
6091787SimpTUNABLE_INT("hw.cardbus.debug", &cardbus_debug);
6191787SimpSYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW,
6291787Simp    &cardbus_debug, 0,
6391787Simp  "CardBus debug");
6491787Simp
6592301Simpint    cardbus_cis_debug = 0;
6691787SimpTUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug);
6791787SimpSYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW,
6891787Simp    &cardbus_cis_debug, 0,
6991787Simp  "CardBus CIS debug");
7091787Simp
7191787Simp#define	DPRINTF(a) if (cardbus_debug) printf a
7291787Simp#define	DEVPRINTF(x) if (cardbus_debug) device_printf x
7391787Simp
7482375Sjonstatic int	cardbus_attach(device_t cbdev);
75104639Simpstatic int	cardbus_attach_card(device_t cbdev);
7682375Sjonstatic int	cardbus_detach(device_t cbdev);
77106362Simpstatic int	cardbus_detach_card(device_t cbdev);
78169633Sjhbstatic void	cardbus_device_setup_regs(pcicfgregs *cfg);
7982375Sjonstatic void	cardbus_driver_added(device_t cbdev, driver_t *driver);
80104639Simpstatic int	cardbus_probe(device_t cbdev);
81104639Simpstatic int	cardbus_read_ivar(device_t cbdev, device_t child, int which,
82110975Simp		    uintptr_t *result);
83189653Simp
8467276Sjon/************************************************************************/
8567276Sjon/* Probe/Attach								*/
8667276Sjon/************************************************************************/
8753343Simp
8867276Sjonstatic int
8982375Sjoncardbus_probe(device_t cbdev)
9067276Sjon{
9187975Simp	device_set_desc(cbdev, "CardBus bus");
92153896Simp	return (0);
9367276Sjon}
9453343Simp
9567276Sjonstatic int
9682375Sjoncardbus_attach(device_t cbdev)
9767276Sjon{
98185015Simp	struct cardbus_softc *sc;
99280970Sjhb#ifdef PCI_RES_BUS
100280970Sjhb	int rid;
101280970Sjhb#endif
102153811Simp
103185015Simp	sc = device_get_softc(cbdev);
104153811Simp	sc->sc_dev = cbdev;
105280970Sjhb#ifdef PCI_RES_BUS
106280970Sjhb	rid = 0;
107280970Sjhb	sc->sc_bus = bus_alloc_resource(cbdev, PCI_RES_BUS, &rid,
108280970Sjhb	    pcib_get_bus(cbdev), pcib_get_bus(cbdev), 1, 0);
109280970Sjhb	if (sc->sc_bus == NULL) {
110280970Sjhb		device_printf(cbdev, "failed to allocate bus number\n");
111280970Sjhb		return (ENXIO);
112280970Sjhb	}
113280970Sjhb#endif
114153896Simp	return (0);
11553343Simp}
11653343Simp
11769288Sjonstatic int
11882375Sjoncardbus_detach(device_t cbdev)
11969288Sjon{
120280970Sjhb#ifdef PCI_RES_BUS
121280970Sjhb	struct cardbus_softc *sc;
122280970Sjhb#endif
123153811Simp
124106362Simp	cardbus_detach_card(cbdev);
125280970Sjhb#ifdef PCI_RES_BUS
126280970Sjhb	sc = device_get_softc(cbdev);
127280970Sjhb	(void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus);
128280970Sjhb#endif
129153896Simp	return (0);
13069288Sjon}
13169288Sjon
13287975Simpstatic int
13387975Simpcardbus_suspend(device_t self)
13487975Simp{
135153896Simp
136106362Simp	cardbus_detach_card(self);
13787975Simp	return (0);
13887975Simp}
13987975Simp
14087975Simpstatic int
14187975Simpcardbus_resume(device_t self)
14287975Simp{
143153896Simp
14487975Simp	return (0);
14587975Simp}
14687975Simp
14767276Sjon/************************************************************************/
14867276Sjon/* Attach/Detach card							*/
14967276Sjon/************************************************************************/
15067276Sjon
15167276Sjonstatic void
152169633Sjhbcardbus_device_setup_regs(pcicfgregs *cfg)
15353343Simp{
154169633Sjhb	device_t dev = cfg->dev;
155169620Simp	int i;
15669291Sjon
157169620Simp	/*
158169620Simp	 * Some cards power up with garbage in their BARs.  This
159169620Simp	 * code clears all that junk out.
160169620Simp	 */
161188033Sjhb	for (i = 0; i < PCIR_MAX_BAR_0; i++)
162169620Simp		pci_write_config(dev, PCIR_BAR(i), 0, 4);
16367276Sjon
164169633Sjhb	cfg->intline =
165169633Sjhb	    pci_get_irq(device_get_parent(device_get_parent(dev)));
166169633Sjhb	pci_write_config(dev, PCIR_INTLINE, cfg->intline, 1);
167169620Simp	pci_write_config(dev, PCIR_CACHELNSZ, 0x08, 1);
168169620Simp	pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1);
169169620Simp	pci_write_config(dev, PCIR_MINGNT, 0x14, 1);
170169620Simp	pci_write_config(dev, PCIR_MAXLAT, 0x14, 1);
17153343Simp}
17253343Simp
17367276Sjonstatic int
17482375Sjoncardbus_attach_card(device_t cbdev)
17553343Simp{
17682375Sjon	device_t brdev = device_get_parent(cbdev);
177141412Simp	device_t child;
178172394Smarius	int bus, domain, slot, func;
17967276Sjon	int cardattached = 0;
180151789Simp	int cardbusfunchigh = 0;
181185015Simp	struct cardbus_softc *sc;
18253343Simp
183185015Simp	sc = device_get_softc(cbdev);
184106362Simp	cardbus_detach_card(cbdev); /* detach existing cards */
18582375Sjon	POWER_ENABLE_SOCKET(brdev, cbdev);
186172394Smarius	domain = pcib_get_domain(cbdev);
18782375Sjon	bus = pcib_get_bus(cbdev);
188151789Simp	slot = 0;
18982375Sjon	/* For each function, set it up and try to attach a driver to it */
190151789Simp	for (func = 0; func <= cardbusfunchigh; func++) {
191151789Simp		struct cardbus_devinfo *dinfo;
19292301Simp
193151789Simp		dinfo = (struct cardbus_devinfo *)
194172394Smarius		    pci_read_device(brdev, domain, bus, slot, func,
195151789Simp			sizeof(struct cardbus_devinfo));
196151789Simp		if (dinfo == NULL)
197151789Simp			continue;
198151789Simp		if (dinfo->pci.cfg.mfdev)
199151789Simp			cardbusfunchigh = PCI_FUNCMAX;
200106362Simp
201151789Simp		child = device_add_child(cbdev, NULL, -1);
202151789Simp		if (child == NULL) {
203151789Simp			DEVPRINTF((cbdev, "Cannot add child!\n"));
204151789Simp			pci_freecfg((struct pci_devinfo *)dinfo);
205151789Simp			continue;
20667276Sjon		}
207151789Simp		dinfo->pci.cfg.dev = child;
208151789Simp		resource_list_init(&dinfo->pci.resources);
209151789Simp		device_set_ivars(child, dinfo);
210185015Simp		cardbus_device_create(sc, dinfo, cbdev, child);
211159532Simp		if (cardbus_do_cis(cbdev, child) != 0)
212159532Simp			DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n"));
213153896Simp		pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
214153896Simp		pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci);
215169633Sjhb		cardbus_device_setup_regs(&dinfo->pci.cfg);
216153896Simp		pci_add_resources(cbdev, child, 1, dinfo->mprefetchable);
217151789Simp		pci_print_verbose(&dinfo->pci);
218153896Simp		if (device_probe_and_attach(child) == 0)
219153896Simp			cardattached++;
220151789Simp		else
221153896Simp			pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1);
22267276Sjon	}
22382375Sjon	if (cardattached > 0)
224106362Simp		return (0);
225186642Simp/*	POWER_DISABLE_SOCKET(brdev, cbdev); */
226106362Simp	return (ENOENT);
22753343Simp}
22853343Simp
229330938Sjhbstatic void
230330938Sjhbcardbus_child_deleted(device_t cbdev, device_t child)
231330938Sjhb{
232330938Sjhb	struct cardbus_devinfo *dinfo = device_get_ivars(child);
233330938Sjhb
234330938Sjhb	if (dinfo->pci.cfg.dev != child)
235330938Sjhb		device_printf(cbdev, "devinfo dev mismatch\n");
236330938Sjhb	cardbus_device_destroy(dinfo);
237330938Sjhb	pci_child_deleted(cbdev, child);
238330938Sjhb}
239330938Sjhb
24067276Sjonstatic int
241106362Simpcardbus_detach_card(device_t cbdev)
24253343Simp{
24382375Sjon	int err = 0;
24453343Simp
245330938Sjhb	err = bus_generic_detach(cbdev);
246330938Sjhb	if (err)
247330938Sjhb		return (err);
248330938Sjhb	err = device_delete_children(cbdev);
249330938Sjhb	if (err)
250330938Sjhb		return (err);
25153343Simp
252106362Simp	POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);
253106362Simp	return (err);
25467276Sjon}
25553343Simp
25669288Sjonstatic void
25782375Sjoncardbus_driver_added(device_t cbdev, driver_t *driver)
25869288Sjon{
25970715Sjon	int numdevs;
26070715Sjon	device_t *devlist;
261110673Simp	device_t dev;
262110673Simp	int i;
263106362Simp	struct cardbus_devinfo *dinfo;
26470715Sjon
265110673Simp	DEVICE_IDENTIFY(driver, cbdev);
266166104Simp	if (device_get_children(cbdev, &devlist, &numdevs) != 0)
267166104Simp		return;
268166104Simp
269110750Simp	/*
270110750Simp	 * If there are no drivers attached, but there are children,
271110750Simp	 * then power the card up.
272110750Simp	 */
273110673Simp	for (i = 0; i < numdevs; i++) {
274110673Simp		dev = devlist[i];
275110673Simp		if (device_get_state(dev) != DS_NOTPRESENT)
276110750Simp		    break;
277110750Simp	}
278110750Simp	if (i > 0 && i == numdevs)
279110750Simp		POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev);
280110750Simp	for (i = 0; i < numdevs; i++) {
281110750Simp		dev = devlist[i];
282110750Simp		if (device_get_state(dev) != DS_NOTPRESENT)
283110673Simp			continue;
284110673Simp		dinfo = device_get_ivars(dev);
285110975Simp		pci_print_verbose(&dinfo->pci);
286189619Simp		if (bootverbose)
287189619Simp			printf("pci%d:%d:%d:%d: reprobing on driver added\n",
288189619Simp			    dinfo->pci.cfg.domain, dinfo->pci.cfg.bus,
289189619Simp			    dinfo->pci.cfg.slot, dinfo->pci.cfg.func);
290153896Simp		pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci);
291143394Simp		if (device_probe_and_attach(dev) != 0)
292153896Simp			pci_cfg_save(dev, &dinfo->pci, 1);
29370715Sjon	}
29472185Simp	free(devlist, M_TEMP);
29569288Sjon}
29669288Sjon
29792301Simp/************************************************************************/
29892301Simp/* Other Bus Methods							*/
29992301Simp/************************************************************************/
30092301Simp
30192301Simpstatic int
302110975Simpcardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result)
30392301Simp{
30492301Simp	struct cardbus_devinfo *dinfo;
30592301Simp	pcicfgregs *cfg;
30692301Simp
30792301Simp	dinfo = device_get_ivars(child);
30892301Simp	cfg = &dinfo->pci.cfg;
30992301Simp
31092301Simp	switch (which) {
311107301Simp	case PCI_IVAR_ETHADDR:
312107301Simp		/*
313107301Simp		 * The generic accessor doesn't deal with failure, so
314107301Simp		 * we set the return value, then return an error.
315107301Simp		 */
316141412Simp		if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) {
317141412Simp			*((uint8_t **) result) = dinfo->funce.lan.nid;
318141412Simp			break;
319107301Simp		}
320141412Simp		*((uint8_t **) result) = NULL;
321141412Simp		return (EINVAL);
32292301Simp	default:
323110975Simp		return (pci_read_ivar(cbdev, child, which, result));
32492301Simp	}
32592301Simp	return 0;
32692301Simp}
32792301Simp
32867276Sjonstatic device_method_t cardbus_methods[] = {
32967276Sjon	/* Device interface */
33067276Sjon	DEVMETHOD(device_probe,		cardbus_probe),
33167276Sjon	DEVMETHOD(device_attach,	cardbus_attach),
33269288Sjon	DEVMETHOD(device_detach,	cardbus_detach),
33387975Simp	DEVMETHOD(device_suspend,	cardbus_suspend),
33487975Simp	DEVMETHOD(device_resume,	cardbus_resume),
33567276Sjon
33667276Sjon	/* Bus interface */
337330938Sjhb	DEVMETHOD(bus_child_deleted,	cardbus_child_deleted),
338232403Sjhb	DEVMETHOD(bus_get_dma_tag,	bus_generic_get_dma_tag),
33992301Simp	DEVMETHOD(bus_read_ivar,	cardbus_read_ivar),
34069288Sjon	DEVMETHOD(bus_driver_added,	cardbus_driver_added),
34192301Simp
34267276Sjon	/* Card Interface */
34367276Sjon	DEVMETHOD(card_attach_card,	cardbus_attach_card),
34467276Sjon	DEVMETHOD(card_detach_card,	cardbus_detach_card),
34567276Sjon
34667276Sjon	{0,0}
34767276Sjon};
34867276Sjon
349153832SglebiusDEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods,
350153832Sglebius    sizeof(struct cardbus_softc), pci_driver);
35167276Sjon
35269288Sjonstatic devclass_t cardbus_devclass;
35367276Sjon
354101905SimpDRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0);
35597613StakawataMODULE_VERSION(cardbus, 1);
356