if_malo_pci.c revision 1.2 1 /* $NetBSD: if_malo_pci.c,v 1.2 2012/07/30 20:30:41 degroote Exp $ */
2 /* $OpenBSD: if_malo_pci.c,v 1.6 2010/08/28 23:19:29 deraadt Exp $ */
3
4 /*
5 * Copyright (c) 2006 Marcus Glocker <mglocker (at) openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * PCI front-end for the Marvell Libertas
22 */
23
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: if_malo_pci.c,v 1.2 2012/07/30 20:30:41 degroote Exp $");
26
27 #include <sys/param.h>
28 #include <sys/sockio.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/device.h>
35 #include <sys/bus.h>
36
37 #include <machine/intr.h>
38
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <net/if_media.h>
42 #include <net/if_ether.h>
43
44 #include <netinet/in.h>
45
46 #include <net80211/ieee80211_var.h>
47 #include <net80211/ieee80211_radiotap.h>
48
49 #include <dev/ic/malovar.h>
50
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pcidevs.h>
54
55 /* Base Address Register */
56 #define MALO_PCI_BAR1 0x10
57 #define MALO_PCI_BAR2 0x14
58
59 static int malo_pci_match(device_t parent, cfdata_t match, void *aux);
60 static void malo_pci_attach(device_t, device_t, void *);
61 static int malo_pci_detach(struct device *, int);
62
63 struct malo_pci_softc {
64 struct malo_softc sc_malo;
65
66 pci_chipset_tag_t sc_pc;
67 void *sc_ih;
68
69 bus_size_t sc_mapsize1;
70 bus_size_t sc_mapsize2;
71 };
72
73 CFATTACH_DECL_NEW(malo_pci, sizeof(struct malo_pci_softc),
74 malo_pci_match, malo_pci_attach, malo_pci_detach, NULL);
75
76 static int
77 malo_pci_match(device_t parent, cfdata_t match, void *aux)
78 {
79 struct pci_attach_args *pa = aux;
80
81 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_MARVELL)
82 return (0);
83
84 switch (PCI_PRODUCT(pa->pa_id)) {
85 case PCI_PRODUCT_MARVELL_88W8310:
86 case PCI_PRODUCT_MARVELL_88W8335_1:
87 case PCI_PRODUCT_MARVELL_88W8335_2:
88 return (1);
89 }
90
91 return (0);
92 }
93
94 static void
95 malo_pci_attach(device_t parent, device_t self, void *aux)
96 {
97 struct malo_pci_softc *psc = device_private(self);
98 struct pci_attach_args *pa = aux;
99 struct malo_softc *sc = &psc->sc_malo;
100 const char *intrstr = NULL;
101 pci_intr_handle_t ih;
102 pcireg_t memtype1, memtype2;
103 int error;
104
105 sc->sc_dev = self;
106 sc->sc_dmat = pa->pa_dmat;
107 psc->sc_pc = pa->pa_pc;
108
109 aprint_normal("\n");
110 aprint_normal_dev(self,"Marvell Libertas Wireless\n");
111
112 /* map control / status registers */
113 memtype1 = pci_mapreg_type(pa->pa_pc, pa->pa_tag, MALO_PCI_BAR1);
114 switch (memtype1) {
115 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
116 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
117 break;
118 default:
119 aprint_error_dev(self, "invalid base address register\n");
120 return;
121 }
122
123 error = pci_mapreg_map(pa, MALO_PCI_BAR1,
124 memtype1, 0, &sc->sc_mem1_bt, &sc->sc_mem1_bh,
125 NULL, &psc->sc_mapsize1);
126 if (error != 0) {
127 aprint_error_dev(self, "can't map 1st mem space\n");
128 return;
129 }
130
131 /* map control / status registers */
132 memtype2 = pci_mapreg_type(pa->pa_pc, pa->pa_tag, MALO_PCI_BAR1);
133 switch (memtype2) {
134 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
135 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
136 break;
137 default:
138 aprint_error_dev(self, "invalid base address register\n");
139 return;
140 }
141
142 error = pci_mapreg_map(pa, MALO_PCI_BAR2,
143 memtype2, 0, &sc->sc_mem2_bt, &sc->sc_mem2_bh,
144 NULL, &psc->sc_mapsize2);
145 if (error != 0) {
146 aprint_error_dev(self, "can't map 2nd mem space\n");
147 return;
148 }
149
150 /* map interrupt */
151 if (pci_intr_map(pa, &ih) != 0) {
152 aprint_error_dev(self, "can't map interrupt\n");
153 return;
154 }
155
156 /* establish interrupt */
157 intrstr = pci_intr_string(psc->sc_pc, ih);
158 psc->sc_ih = pci_intr_establish(psc->sc_pc, ih, IPL_NET, malo_intr, sc);
159 if (psc->sc_ih == NULL) {
160 aprint_error_dev(self, "could not establish interrupt");
161 if (intrstr != NULL)
162 aprint_error(" at %s", intrstr);
163 aprint_error("\n");
164 return;
165 }
166 aprint_normal_dev(self, "interrupting at %s\n", intrstr);
167
168 malo_attach(sc);
169 }
170
171 int
172 malo_pci_detach(struct device *self, int flags)
173 {
174 struct malo_pci_softc *psc = (struct malo_pci_softc *)self;
175 struct malo_softc *sc = &psc->sc_malo;
176
177 malo_detach(sc);
178 pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
179
180 return (0);
181 }
182