1 /* $NetBSD: if_ath_arbus.c,v 1.9 2007/01/24 13:08:11 hubertf Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Jared D. McNeill <jmcneill@invisible.ca> 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: if_ath_arbus.c,v 1.9 2007/01/24 13:08:11 hubertf Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/mbuf.h> 43 #include <sys/malloc.h> 44 #include <sys/kernel.h> 45 #include <sys/errno.h> 46 47 #include <machine/bus.h> 48 #include <machine/intr.h> 49 50 #include <net/if.h> 51 #include <net/if_media.h> 52 #include <net/if_ether.h> 53 #include <net/if_llc.h> 54 #include <net/if_arp.h> 55 56 #include <netinet/in.h> 57 58 #include <net80211/ieee80211_netbsd.h> 59 #include <net80211/ieee80211_var.h> 60 61 #include <mips/atheros/include/ar531xvar.h> 62 #include <mips/atheros/include/arbusvar.h> 63 64 #include <dev/pci/pcidevs.h> 65 #include <dev/ic/ath_netbsd.h> 66 #include <dev/ic/athvar.h> 67 #include <contrib/dev/ath/ah.h> 68 #include <contrib/dev/ath/ah_soc.h> /* XXX really doesn't belong in hal */ 69 70 struct ath_arbus_softc { 71 struct ath_softc sc_ath; 72 bus_space_tag_t sc_iot; 73 bus_space_handle_t sc_ioh; 74 void *sc_ih; 75 struct ar531x_config sc_config; 76 void *sc_sdhook; 77 }; 78 79 static int ath_arbus_match(struct device *, struct cfdata *, void *); 80 static void ath_arbus_attach(struct device *, struct device *, void *); 81 static int ath_arbus_detach(struct device *, int); 82 static void ath_arbus_shutdown(void *); 83 84 CFATTACH_DECL(ath_arbus, sizeof(struct ath_arbus_softc), 85 ath_arbus_match, ath_arbus_attach, ath_arbus_detach, NULL); 86 87 static int 88 ath_arbus_match(struct device *parent, struct cfdata *cf, void *opaque) 89 { 90 struct arbus_attach_args *aa; 91 92 aa = (struct arbus_attach_args *)opaque; 93 if (strcmp(aa->aa_name, "ath") == 0) 94 return 1; 95 96 return 0; 97 } 98 99 static void 100 ath_arbus_attach(struct device *parent, struct device *self, void *opaque) 101 { 102 struct ath_arbus_softc *asc; 103 struct ath_softc *sc; 104 struct arbus_attach_args *aa; 105 const char *name; 106 prop_number_t prop; 107 int rv; 108 uint16_t devid; 109 110 asc = (struct ath_arbus_softc *)self; 111 sc = &asc->sc_ath; 112 aa = (struct arbus_attach_args *)opaque; 113 114 prop = prop_dictionary_get(device_properties(&sc->sc_dev), 115 "wmac-rev"); 116 if (prop == NULL) { 117 printf(": unable to get wmac-rev property\n"); 118 return; 119 } 120 KDASSERT(prop_object_type(prop) == PROP_TYPE_NUMBER); 121 122 devid = (uint16_t)prop_number_integer_value(prop); 123 name = ath_hal_probe(PCI_VENDOR_ATHEROS, devid); 124 125 printf(": %s\n", name ? name : "Unknown AR531X WLAN"); 126 127 asc->sc_iot = aa->aa_bst; 128 rv = bus_space_map(asc->sc_iot, aa->aa_addr, aa->aa_size, 0, 129 &asc->sc_ioh); 130 if (rv) { 131 aprint_error("%s: unable to map registers\n", 132 sc->sc_dev.dv_xname); 133 return; 134 } 135 /* 136 * Setup HAL configuration state for use by the driver. 137 */ 138 rv = ar531x_board_config(&asc->sc_config); 139 if (rv) { 140 aprint_error("%s: unable to locate board configuration\n", 141 sc->sc_dev.dv_xname); 142 return; 143 } 144 asc->sc_config.unit = sc->sc_dev.dv_unit; /* XXX? */ 145 asc->sc_config.tag = asc->sc_iot; 146 147 /* NB: the HAL expects the config state passed as the tag */ 148 sc->sc_st = (HAL_BUS_TAG) &asc->sc_config; 149 sc->sc_sh = (HAL_BUS_HANDLE) asc->sc_ioh; 150 sc->sc_dmat = aa->aa_dmat; 151 152 sc->sc_invalid = 1; 153 154 asc->sc_ih = arbus_intr_establish(aa->aa_cirq, aa->aa_mirq, ath_intr, 155 sc); 156 if (asc->sc_ih == NULL) { 157 aprint_error("%s: couldn't establish interrupt\n", 158 sc->sc_dev.dv_xname); 159 return; 160 } 161 162 if (ath_attach(devid, sc) != 0) { 163 aprint_error("%s: ath_attach failed\n", sc->sc_dev.dv_xname); 164 goto err; 165 } 166 167 asc->sc_sdhook = shutdownhook_establish(ath_arbus_shutdown, asc); 168 if (asc->sc_sdhook == NULL) { 169 aprint_error("%s: couldn't establish shutdown hook\n", 170 sc->sc_dev.dv_xname); 171 goto err; 172 } 173 174 return; 175 176 err: 177 arbus_intr_disestablish(asc->sc_ih); 178 } 179 180 static int 181 ath_arbus_detach(struct device *self, int flags) 182 { 183 struct ath_arbus_softc *asc = (struct ath_arbus_softc *)self; 184 185 shutdownhook_disestablish(asc->sc_sdhook); 186 ath_detach(&asc->sc_ath); 187 arbus_intr_disestablish(asc->sc_ih); 188 189 return (0); 190 } 191 192 static void 193 ath_arbus_shutdown(void *opaque) 194 { 195 struct ath_arbus_softc *asc = opaque; 196 197 ath_shutdown(&asc->sc_ath); 198 199 return; 200 } 201