1/*	$NetBSD: if_ath_cardbus.c,v 1.46 2022/09/25 17:33:19 thorpej Exp $ */
2/*
3 * Copyright (c) 2003
4 *	Ichiro FUKUHARA <ichiro@ichiro.org>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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/*
29 * CardBus bus front-end for the AR5001 Wireless LAN 802.11a/b/g CardBus.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.46 2022/09/25 17:33:19 thorpej Exp $");
34
35#include "opt_inet.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/mbuf.h>
40#include <sys/kernel.h>
41#include <sys/socket.h>
42#include <sys/ioctl.h>
43#include <sys/errno.h>
44#include <sys/device.h>
45
46#include <machine/endian.h>
47
48#include <net/if.h>
49#include <net/if_dl.h>
50#include <net/if_media.h>
51#include <net/if_ether.h>
52
53#include <net80211/ieee80211_netbsd.h>
54#include <net80211/ieee80211_var.h>
55
56#ifdef INET
57#include <netinet/in.h>
58#include <netinet/if_inarp.h>
59#endif
60
61
62#include <sys/bus.h>
63#include <sys/intr.h>
64
65#include <dev/mii/miivar.h>
66#include <dev/mii/mii_bitbang.h>
67
68#include <dev/ic/ath_netbsd.h>
69#include <dev/ic/athvar.h>
70
71#include <external/isc/atheros_hal/dist/ah.h>
72
73#include <dev/pci/pcivar.h>
74#include <dev/pci/pcireg.h>
75#include <dev/pci/pcidevs.h>
76
77#include <dev/cardbus/cardbusvar.h>
78#include <dev/pci/pcidevs.h>
79
80/*
81 * PCI configuration space registers
82 */
83#define ATH_PCI_MMBA PCI_BAR(0)	/* memory mapped base */
84
85struct ath_cardbus_softc {
86	struct ath_softc	sc_ath;
87
88	/* CardBus-specific goo. */
89	void	*sc_ih;			/* interrupt handle */
90	cardbus_devfunc_t sc_ct;	/* our CardBus devfuncs */
91	pcitag_t sc_tag;		/* our CardBus tag */
92	bus_size_t sc_mapsize;		/* the size of mapped bus space region */
93
94	pcireg_t sc_bar_val;		/* value of the BAR */
95
96	bus_space_tag_t sc_iot;
97	bus_space_handle_t sc_ioh;
98};
99
100int	ath_cardbus_match(device_t, cfdata_t, void *);
101void	ath_cardbus_attach(device_t, device_t, void *);
102int	ath_cardbus_detach(device_t, int);
103
104CFATTACH_DECL_NEW(ath_cardbus, sizeof(struct ath_cardbus_softc),
105    ath_cardbus_match, ath_cardbus_attach, ath_cardbus_detach, NULL);
106
107void	ath_cardbus_setup(struct ath_cardbus_softc *);
108
109static bool
110ath_cardbus_suspend(device_t self, const pmf_qual_t *qual)
111{
112	struct ath_cardbus_softc *csc = device_private(self);
113
114	ath_suspend(&csc->sc_ath);
115	if (csc->sc_ih != NULL) {
116		Cardbus_intr_disestablish(csc->sc_ct, csc->sc_ih);
117		csc->sc_ih = NULL;
118	}
119	return true;
120}
121
122static bool
123ath_cardbus_resume(device_t self, const pmf_qual_t *qual)
124{
125	struct ath_cardbus_softc *csc = device_private(self);
126
127	csc->sc_ih = Cardbus_intr_establish(csc->sc_ct,
128	    IPL_NET, ath_intr, &csc->sc_ath);
129
130	if (csc->sc_ih == NULL) {
131		aprint_error_dev(self,
132		    "unable to establish interrupt\n");
133		return false;
134	}
135
136	return ath_resume(&csc->sc_ath);
137}
138
139int
140ath_cardbus_match(device_t parent, cfdata_t match, void *aux)
141{
142	struct cardbus_attach_args *ca = aux;
143	const char *devname;
144
145	devname = ath_hal_probe(PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
146
147	if (devname)
148		return 1;
149
150	return 0;
151}
152
153void
154ath_cardbus_attach(device_t parent, device_t self, void *aux)
155{
156	struct ath_cardbus_softc *csc = device_private(self);
157	struct ath_softc *sc = &csc->sc_ath;
158	struct cardbus_attach_args *ca = aux;
159	cardbus_devfunc_t ct = ca->ca_ct;
160	bus_addr_t adr;
161
162	sc->sc_dev = self;
163	sc->sc_dmat = ca->ca_dmat;
164	csc->sc_ct = ct;
165	csc->sc_tag = ca->ca_tag;
166
167	aprint_normal("\n");
168
169	/*
170	 * Map the device.
171	 */
172	if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
173	    &csc->sc_iot, &csc->sc_ioh, &adr, &csc->sc_mapsize) == 0) {
174		csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM;
175	} else {
176		aprint_error_dev(self, "unable to map device registers\n");
177		return;
178	}
179
180	sc->sc_st = HALTAG(csc->sc_iot);
181	sc->sc_sh = HALHANDLE(csc->sc_ioh);
182
183	/*
184	 * Set up the PCI configuration registers.
185	 */
186	ath_cardbus_setup(csc);
187
188	/*
189	 * Finish off the attach.
190	 */
191	if (ath_attach(PCI_PRODUCT(ca->ca_id), sc) != 0)
192		return;
193
194	if (pmf_device_register(self,
195	    ath_cardbus_suspend, ath_cardbus_resume)) {
196		pmf_class_network_register(self, &sc->sc_if);
197		pmf_device_suspend(self, &sc->sc_qual);
198	} else
199		aprint_error_dev(self, "couldn't establish power handler\n");
200}
201
202int
203ath_cardbus_detach(device_t self, int flags)
204{
205	struct ath_cardbus_softc *csc = device_private(self);
206	struct ath_softc *sc = &csc->sc_ath;
207	struct cardbus_devfunc *ct = csc->sc_ct;
208	int rv;
209
210#if defined(DIAGNOSTIC)
211	if (ct == NULL)
212		panic("%s: data structure lacks", device_xname(sc->sc_dev));
213#endif
214
215	rv = ath_detach(sc);
216	if (rv)
217		return (rv);
218
219	pmf_device_deregister(self);
220
221	/*
222	 * Unhook the interrupt handler.
223	 */
224	if (csc->sc_ih != NULL) {
225		Cardbus_intr_disestablish(ct, csc->sc_ih);
226		csc->sc_ih = NULL;
227	}
228
229	/*
230	 * Release bus space and close window.
231	 */
232	Cardbus_mapreg_unmap(ct, ATH_PCI_MMBA, csc->sc_iot, csc->sc_ioh,
233	    csc->sc_mapsize);
234
235	return (0);
236}
237
238void
239ath_cardbus_setup(struct ath_cardbus_softc *csc)
240{
241	cardbus_devfunc_t ct = csc->sc_ct;
242	int rc;
243	pcireg_t reg;
244
245	if ((rc = cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0)) != 0)
246		aprint_debug("%s: cardbus_set_powerstate %d\n", __func__, rc);
247
248	/* Program the BAR. */
249	Cardbus_conf_write(ct, csc->sc_tag, ATH_PCI_MMBA, csc->sc_bar_val);
250
251	/* Enable the appropriate bits in the PCI CSR. */
252	reg = Cardbus_conf_read(ct, csc->sc_tag,
253	    PCI_COMMAND_STATUS_REG);
254	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
255	Cardbus_conf_write(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg);
256}
257