xref: /openbsd/sys/dev/cardbus/if_malo_cardbus.c (revision 8529ddd3)
1 /*	$OpenBSD: if_malo_cardbus.c,v 1.12 2013/12/06 21:03:02 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "bpfilter.h"
20 
21 #include <sys/param.h>
22 #include <sys/mbuf.h>
23 #include <sys/socket.h>
24 #include <sys/systm.h>
25 #include <sys/timeout.h>
26 
27 #include <net/if.h>
28 #include <net/if_media.h>
29 
30 #include <netinet/in.h>
31 #include <netinet/if_ether.h>
32 
33 #include <net80211/ieee80211_var.h>
34 #include <net80211/ieee80211_radiotap.h>
35 
36 #include <dev/pci/pcireg.h>
37 #include <dev/pci/pcivar.h>
38 #include <dev/pci/pcidevs.h>
39 
40 #include <dev/cardbus/cardbusvar.h>
41 
42 #include <dev/ic/malo.h>
43 
44 struct malo_cardbus_softc {
45 	struct malo_softc	sc_malo;
46 
47 	/* cardbus specific goo */
48 	cardbus_devfunc_t	sc_ct;
49 	pcitag_t		sc_tag;
50 	void			*sc_ih;
51 
52 	bus_size_t		sc_mapsize1;
53 	bus_size_t		sc_mapsize2;
54 	pcireg_t		sc_bar1_val;
55 	pcireg_t		sc_bar2_val;
56 	int			sc_intrline;
57 	pci_chipset_tag_t	sc_pc;
58 };
59 
60 int	malo_cardbus_match(struct device *parent, void *match, void *aux);
61 void	malo_cardbus_attach(struct device *parent, struct device *self,
62 	    void *aux);
63 int	malo_cardbus_detach(struct device *self, int flags);
64 void	malo_cardbus_setup(struct malo_cardbus_softc *csc);
65 int	malo_cardbus_enable(struct malo_softc *sc);
66 void	malo_cardbus_disable(struct malo_softc *sc);
67 
68 struct cfattach malo_cardbus_ca = {
69 	sizeof (struct malo_cardbus_softc), malo_cardbus_match,
70 	malo_cardbus_attach, malo_cardbus_detach
71 };
72 
73 static const struct pci_matchid malo_cardbus_devices[] = {
74 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88W8310 },
75 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88W8335_1 },
76 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88W8335_2 }
77 };
78 
79 int
80 malo_cardbus_match(struct device *parent, void *match, void *aux)
81 {
82 	return (cardbus_matchbyid(aux, malo_cardbus_devices,
83 	    sizeof (malo_cardbus_devices) / sizeof (malo_cardbus_devices[0])));
84 }
85 
86 void
87 malo_cardbus_attach(struct device *parent, struct device *self, void *aux)
88 {
89 	struct malo_cardbus_softc *csc = (struct malo_cardbus_softc *)self;
90 	struct cardbus_attach_args *ca = aux;
91 	struct malo_softc *sc = &csc->sc_malo;
92 	cardbus_devfunc_t ct = ca->ca_ct;
93 	bus_addr_t base;
94 	int error;
95 
96 	sc->sc_dmat = ca->ca_dmat;
97 	csc->sc_ct = ct;
98 	csc->sc_tag = ca->ca_tag;
99 	csc->sc_intrline = ca->ca_intrline;
100 	csc->sc_pc = ca->ca_pc;
101 
102 	/* power management hooks */
103 	sc->sc_enable = malo_cardbus_enable;
104 	sc->sc_disable = malo_cardbus_disable;
105 #if 0
106 	sc->sc_power = malo_cardbus_power;
107 #endif
108 
109 	/* map control/status registers */
110 	error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
111 	    PCI_MAPREG_TYPE_MEM, 0, &sc->sc_mem1_bt,
112 	    &sc->sc_mem1_bh, &base, &csc->sc_mapsize1);
113 	if (error != 0) {
114 		printf(": can't map mem1 space\n");
115 		return;
116 	}
117 	csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM;
118 
119 	/* map control/status registers */
120 	error = Cardbus_mapreg_map(ct, CARDBUS_BASE1_REG,
121 	    PCI_MAPREG_TYPE_MEM, 0, &sc->sc_mem2_bt,
122 	    &sc->sc_mem2_bh, &base, &csc->sc_mapsize2);
123 	if (error != 0) {
124 		printf(": can't map mem2 space\n");
125 		Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem1_bt,
126 		    sc->sc_mem1_bh, csc->sc_mapsize1);
127 		return;
128 	}
129 	csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM;
130 
131 	/* set up the PCI configuration registers */
132 	malo_cardbus_setup(csc);
133 
134 	printf(": irq %d", csc->sc_intrline);
135 
136 	error = malo_attach(sc);
137 	if (error != 0)
138 		malo_cardbus_detach(&sc->sc_dev, 0);
139 
140 	Cardbus_function_disable(ct);
141 }
142 
143 int
144 malo_cardbus_detach(struct device *self, int flags)
145 {
146 	struct malo_cardbus_softc *csc = (struct malo_cardbus_softc *)self;
147 	struct malo_softc *sc = &csc->sc_malo;
148 	cardbus_devfunc_t ct = csc->sc_ct;
149 	cardbus_chipset_tag_t cc = ct->ct_cc;
150 	cardbus_function_tag_t cf = ct->ct_cf;
151 	int error;
152 
153 	error = malo_detach(sc);
154 	if (error != 0)
155 		return (error);
156 
157 	/* unhook the interrupt handler */
158 	if (csc->sc_ih != NULL) {
159 		cardbus_intr_disestablish(cc, cf, csc->sc_ih);
160 		csc->sc_ih = NULL;
161 	}
162 
163 	/* release bus space and close window */
164 	Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem1_bt,
165 	    sc->sc_mem1_bh, csc->sc_mapsize1);
166 	Cardbus_mapreg_unmap(ct, CARDBUS_BASE1_REG, sc->sc_mem2_bt,
167 	    sc->sc_mem2_bh, csc->sc_mapsize2);
168 
169 	return (0);
170 }
171 
172 void
173 malo_cardbus_setup(struct malo_cardbus_softc *csc)
174 {
175 	cardbus_devfunc_t ct = csc->sc_ct;
176 	cardbus_chipset_tag_t cc = ct->ct_cc;
177 	pci_chipset_tag_t pc = csc->sc_pc;
178 	cardbus_function_tag_t cf = ct->ct_cf;
179 	pcireg_t reg;
180 
181 	/* program the BAR */
182 	pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
183 	    csc->sc_bar1_val);
184 	pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE1_REG,
185 	    csc->sc_bar2_val);
186 
187 	/* make sure the right access type is on the cardbus bridge */
188 	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
189 	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
190 
191 	/* enable the appropriate bits in the PCI CSR */
192 	reg = pci_conf_read(pc, csc->sc_tag,
193 	    PCI_COMMAND_STATUS_REG);
194 	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
195 	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
196 	    reg);
197 }
198 
199 int
200 malo_cardbus_enable(struct malo_softc *sc)
201 {
202 	struct malo_cardbus_softc *csc = (struct malo_cardbus_softc *)sc;
203 	cardbus_devfunc_t ct = csc->sc_ct;
204 	cardbus_chipset_tag_t cc = ct->ct_cc;
205 	cardbus_function_tag_t cf = ct->ct_cf;
206 
207 	/* power on the socket */
208 	Cardbus_function_enable(ct);
209 
210 	/* setup the PCI configuration registers */
211 	malo_cardbus_setup(csc);
212 
213 	/* map and establish the interrupt handler */
214 	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
215 	    malo_intr, sc, sc->sc_dev.dv_xname);
216 	if (csc->sc_ih == NULL) {
217 		printf("%s: could not establish interrupt at %d\n",
218 		    sc->sc_dev.dv_xname, csc->sc_intrline);
219 		Cardbus_function_disable(ct);
220 		return (1);
221 	}
222 
223 	return (0);
224 }
225 
226 void
227 malo_cardbus_disable(struct malo_softc *sc)
228 {
229 	struct malo_cardbus_softc *csc = (struct malo_cardbus_softc *)sc;
230 	cardbus_devfunc_t ct = csc->sc_ct;
231 	cardbus_chipset_tag_t cc = ct->ct_cc;
232 	cardbus_function_tag_t cf = ct->ct_cf;
233 
234 	/* unhook the interrupt handler */
235 	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
236 	csc->sc_ih = NULL;
237 
238 	/* power down the socket */
239 	Cardbus_function_disable(ct);
240 }
241