PERFORCE change 126945 for review
Andrew Thompson
thompsa at FreeBSD.org
Fri Sep 28 14:46:09 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=126945
Change 126945 by thompsa at thompsa_heff on 2007/09/28 21:45:44
Drop in a reduced set of changes to HEAD which seem to work quite well.
Affected files ...
.. //depot/projects/wifi/sys/dev/ipw/if_ipw.c#26 edit
.. //depot/projects/wifi/sys/dev/ipw/if_ipwreg.h#6 edit
.. //depot/projects/wifi/sys/dev/ipw/if_ipwvar.h#8 edit
Differences ...
==== //depot/projects/wifi/sys/dev/ipw/if_ipw.c#26 (text+ko) ====
@@ -1,3 +1,5 @@
+/* $FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.30 2007/09/05 21:31:31 sam Exp $ */
+
/*-
* Copyright (c) 2004-2006
* Damien Bergamini <damien.bergamini at free.fr>. All rights reserved.
@@ -81,7 +83,7 @@
#ifdef IPW_DEBUG
#define DPRINTF(x) do { if (ipw_debug > 0) printf x; } while (0)
#define DPRINTFN(n, x) do { if (ipw_debug >= (n)) printf x; } while (0)
-int ipw_debug = 40;
+int ipw_debug = 3;
SYSCTL_INT(_debug, OID_AUTO, ipw, CTLFLAG_RW, &ipw_debug, 0, "ipw debug level");
#else
#define DPRINTF(x)
@@ -109,49 +111,37 @@
static int ipw_media_change(struct ifnet *);
static void ipw_media_status(struct ifnet *, struct ifmediareq *);
static int ipw_newstate(struct ieee80211com *, enum ieee80211_state, int);
-static void ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *);
-static void ipw_rx_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
-static void ipw_rx_data_intr(struct ipw_softc *, struct ipw_status *,
+static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t);
+static void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
+static void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
+static void ipw_data_intr(struct ipw_softc *, struct ipw_status *,
struct ipw_soft_bd *, struct ipw_soft_buf *);
static void ipw_rx_intr(struct ipw_softc *);
static void ipw_release_sbd(struct ipw_softc *, struct ipw_soft_bd *);
static void ipw_tx_intr(struct ipw_softc *);
-static const char *ipw_cmdname(int);
static void ipw_intr(void *);
static void ipw_dma_map_addr(void *, bus_dma_segment_t *, int, int);
-static int ipw_cmd(struct ipw_softc *, uint32_t, const void *, uint32_t);
+static const char * ipw_cmdname(int);
+static int ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t);
static int ipw_tx_start(struct ifnet *, struct mbuf *,
struct ieee80211_node *);
-static void ipw_start_locked(struct ifnet *);
static void ipw_start(struct ifnet *);
-static void ipw_watchdog(void *);
+static void ipw_watchdog(struct ifnet *);
static int ipw_ioctl(struct ifnet *, u_long, caddr_t);
static void ipw_stop_master(struct ipw_softc *);
-static int ipw_reset(struct ipw_softc *);
static int ipw_enable(struct ipw_softc *);
static int ipw_disable(struct ipw_softc *);
+static int ipw_reset(struct ipw_softc *);
+static int ipw_load_ucode(struct ipw_softc *, const char *, int);
+static int ipw_load_firmware(struct ipw_softc *, const char *, int);
+static void ipw_assoc_task(void *, int);
+static int ipw_auth_and_assoc(struct ipw_softc *);
static int ipw_config(struct ipw_softc *);
-static void ipw_restart(void *, int);
-static int ipw_scan(struct ipw_softc *);
-static void ipw_assoc_lost(void *, int);
-static void ipw_assoc(struct ieee80211com *);
-static void ipw_disassoc(struct ieee80211com *);
-static int ipw_auth_and_assoc(struct ipw_softc *);
-static int ipw_disassociate(struct ipw_softc *);
-static void ipw_ops(void *, int);
+static void ipw_init_task(void *, int);
static void ipw_init(void *);
-static void ipw_init_locked(struct ipw_softc *, int);
-static void ipw_stop_locked(struct ipw_softc *);
static void ipw_stop(void *);
static int ipw_sysctl_stats(SYSCTL_HANDLER_ARGS);
-static int ipw_getrfkill(struct ipw_softc *);
-static void ipw_radio_on(void *, int);
-static void ipw_radio_off(void *, int);
static int ipw_sysctl_radio(SYSCTL_HANDLER_ARGS);
-static int ipw_get_firmware(struct ipw_softc *);
-static void ipw_put_firmware(struct ipw_softc *);
-static int ipw_load_ucode(struct ipw_softc *, const struct ipw_fw *);
-static int ipw_load_firmware(struct ipw_softc *, const struct ipw_fw *);
static uint32_t ipw_read_table1(struct ipw_softc *, uint32_t);
static void ipw_write_table1(struct ipw_softc *, uint32_t, uint32_t);
#if 0
@@ -162,8 +152,8 @@
#endif
static void ipw_write_mem_1(struct ipw_softc *, bus_size_t,
const uint8_t *, bus_size_t);
-static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t);
-static void ipw_sysctlattach(struct ipw_softc *);
+static void ipw_scan_task(void *, int);
+static int ipw_scan(struct ipw_softc *);
static void ipw_scan_start(struct ieee80211com *);
static void ipw_scan_end(struct ieee80211com *);
static void ipw_set_channel(struct ieee80211com *);
@@ -232,25 +222,10 @@
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
- IPW_CMD_LOCK_INIT(sc);
-#if __FreeBSD_version >= 700000
- sc->sc_tq = taskqueue_create("ipw_taskq", M_NOWAIT,
- taskqueue_thread_enqueue, &sc->sc_tq);
- taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
- device_get_nameunit(dev));
-#else
- sc->sc_tq = taskqueue_create("ipw_taskq", M_NOWAIT,
- taskqueue_thread_enqueue, &sc->sc_tq, &sc->sc_tqproc);
- taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
- device_get_nameunit(dev));
-#endif
- TASK_INIT(&sc->sc_radiontask, 0, ipw_radio_on, sc);
- TASK_INIT(&sc->sc_radiofftask, 0, ipw_radio_off, sc);
- TASK_INIT(&sc->sc_assoclosttask,0, ipw_assoc_lost, sc);
- TASK_INIT(&sc->sc_restarttask, 0, ipw_restart, sc);
- TASK_INIT(&sc->sc_opstask, 0, ipw_ops, sc);
- callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
+ TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
+ TASK_INIT(&sc->sc_scan_task, 0, ipw_scan_task, sc);
+ TASK_INIT(&sc->sc_assoc_task, 0, ipw_assoc_task, sc);
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
@@ -304,6 +279,7 @@
ifp->if_init = ipw_init;
ifp->if_ioctl = ipw_ioctl;
ifp->if_start = ipw_start;
+ ifp->if_watchdog = ipw_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
@@ -314,12 +290,11 @@
ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
- ic->ic_caps = IEEE80211_C_IBSS /* IBSS mode supported */
- | IEEE80211_C_MONITOR /* monitor mode supported */
- | IEEE80211_C_PMGT /* power save supported */
- | IEEE80211_C_SHPREAMBLE /* short preamble supported */
- | IEEE80211_C_WPA /* 802.11i supported */
- ;
+ ic->ic_caps =
+ IEEE80211_C_IBSS | /* IBSS mode supported */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
+ IEEE80211_C_TXPMGT | /* tx power management */
+ IEEE80211_C_SHPREAMBLE; /* short preamble supported */
/* read MAC address from EEPROM */
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0);
@@ -335,7 +310,6 @@
/* set supported .11b channels (read from EEPROM) */
if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0)
val = 0x7ff; /* default to channels 1-11 */
- sc->chanmask = val;
val <<= 1;
for (i = 1; i < 16; i++) {
if (val & (1 << i)) {
@@ -345,11 +319,10 @@
c->ic_ieee = i;
}
}
- DPRINTF(("%s: added %d channels\n", __func__, ic->ic_nchans));
/* check support for radio transmitter switch in EEPROM */
if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8))
- sc->flags |= IPW_FLAG_HAS_RFSWITCH;
+ sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH;
ieee80211_ifattach(ic);
/* override state transition machine */
@@ -364,7 +337,7 @@
ic->ic_scan_mindwell = ipw_scan_mindwell;
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
- sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap),
+ sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap),
&sc->sc_drvbpf);
sc->sc_rxtap_len = sizeof sc->sc_rxtap;
@@ -375,7 +348,25 @@
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT);
- ipw_sysctlattach(sc);
+ /*
+ * Add a few sysctl knobs.
+ */
+ sc->dwelltime = 100;
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "radio",
+ CTLTYPE_INT | CTLFLAG_RD, sc, 0, ipw_sysctl_radio, "I",
+ "radio transmitter switch state (0=off, 1=on)");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats",
+ CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, ipw_sysctl_stats, "S",
+ "statistics");
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell",
+ CTLFLAG_RW, &sc->dwelltime, 0,
+ "channel dwell time (ms) for AP/station scanning");
/*
* Hook our interrupt after all initialization is complete.
@@ -404,8 +395,6 @@
struct ifnet *ifp = ic->ic_ifp;
ipw_stop(sc);
- callout_drain(&sc->sc_wdtimer);
- ipw_put_firmware(sc);
if (ifp != NULL) {
bpfdetach(ifp);
@@ -425,10 +414,12 @@
if (ifp != NULL)
if_free(ifp);
- taskqueue_free(sc->sc_tq);
+ if (sc->sc_firmware != NULL) {
+ firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+ sc->sc_firmware = NULL;
+ }
mtx_destroy(&sc->sc_mtx);
- IPW_CMD_LOCK_DESTROY(sc);
return 0;
}
@@ -726,7 +717,6 @@
struct ipw_softc *sc = device_get_softc(dev);
ipw_stop(sc);
- ipw_put_firmware(sc); /* ??? XXX */
return 0;
}
@@ -746,19 +736,18 @@
{
struct ipw_softc *sc = device_get_softc(dev);
struct ifnet *ifp = sc->sc_ic.ic_ifp;
- IPW_LOCK_DECL;
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
pci_write_config(dev, 0x41, 0, 1);
if (ifp->if_flags & IFF_UP) {
- ipw_init_locked(sc, 0);
+ ifp->if_init(ifp->if_softc);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ipw_start_locked(ifp);
+ ifp->if_start(ifp);
}
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
return 0;
}
@@ -768,30 +757,20 @@
{
struct ipw_softc *sc = ifp->if_softc;
int error;
- IPW_LOCK_DECL;
+
+ mtx_lock(&sc->sc_mtx);
- IPW_LOCK(sc);
error = ieee80211_media_change(ifp);
- if (error == ENETRESET) {
- if ((ifp->if_flags & IFF_UP) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING))
- ipw_init_locked(sc, 0);
- error = 0;
+ if (error != ENETRESET) {
+ mtx_unlock(&sc->sc_mtx);
+ return error;
}
- IPW_UNLOCK(sc);
+
+ if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+ ipw_init(sc);
- return error;
-}
+ mtx_unlock(&sc->sc_mtx);
-static int
-ipw_cvtrate(int ipwrate)
-{
- switch (ipwrate) {
- case IPW_RATE_DS1: return 2;
- case IPW_RATE_DS2: return 4;
- case IPW_RATE_DS5: return 11;
- case IPW_RATE_DS11: return 22;
- }
return 0;
}
@@ -802,9 +781,20 @@
static void
ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
{
+#define N(a) (sizeof (a) / sizeof (a[0]))
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- int rate;
+ static const struct {
+ uint32_t val;
+ int rate;
+ } rates[] = {
+ { IPW_RATE_DS1, 2 },
+ { IPW_RATE_DS2, 4 },
+ { IPW_RATE_DS5, 11 },
+ { IPW_RATE_DS11, 22 },
+ };
+ uint32_t val;
+ int rate, i;
imr->ifm_status = IFM_AVALID;
imr->ifm_active = IFM_IEEE80211;
@@ -812,13 +802,33 @@
imr->ifm_status |= IFM_ACTIVE;
/* read current transmission rate from adapter */
- rate = ipw_cvtrate(ipw_read_table1(sc, IPW_INFO_CURRENT_TX_RATE) & 0xf);
+ val = ipw_read_table1(sc, IPW_INFO_CURRENT_TX_RATE) & 0xf;
+
+ /* convert ipw rate to 802.11 rate */
+ for (i = 0; i < N(rates) && rates[i].val != val; i++);
+ rate = (i < N(rates)) ? rates[i].rate : 0;
+
+ imr->ifm_active |= IFM_IEEE80211_11B;
imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ break;
- if (ic->ic_opmode == IEEE80211_M_IBSS)
+ case IEEE80211_M_IBSS:
imr->ifm_active |= IFM_IEEE80211_IBSS;
- else if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ break;
+
+ case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
+ break;
+
+ case IEEE80211_M_AHDEMO:
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_WDS:
+ /* should not get there */
+ break;
+ }
+#undef N
}
static int
@@ -826,56 +836,129 @@
{
struct ifnet *ifp = ic->ic_ifp;
struct ipw_softc *sc = ifp->if_softc;
+#if 0
+ struct ieee80211_node *ni;
+ uint32_t len, error;
+#endif
DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__,
ieee80211_state_name[ic->ic_state],
ieee80211_state_name[nstate], sc->flags));
switch (nstate) {
- case IEEE80211_S_AUTH:
- ipw_assoc(ic);
- break;
+ case IEEE80211_S_RUN:
+#if 0
+ ni = ic->ic_bss;
+ DELAY(200); /* firmware needs a short delay here */
+
+ len = IEEE80211_ADDR_LEN;
+ ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, ni->ni_bssid, &len);
+ IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
+ len = IEEE80211_NWID_LEN;
+ error = ipw_read_table2(sc, IPW_INFO_CURRENT_SSID,
+ ni->ni_essid, &len);
- case IEEE80211_S_RUN:
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- /*
- * XXX when joining an ibss network we are called
- * with a SCAN -> RUN transition on scan complete.
- * Use that to call ipw_auth_and_assoc. On completing
- * the join we are then called again with an
- * AUTH -> RUN transition and we want to do nothing.
- * This is all totally bogus and needs to be redone.
- */
- if (ic->ic_state == IEEE80211_S_SCAN)
- ipw_assoc(ic);
+ if (error == 0) {
+ ni->ni_esslen = len;
+#ifdef IPW_DEBUG
+ if (ipw_debug > 0) {
+ printf("Associated to ");
+ ieee80211_print_essid(ni->ni_essid,
+ ni->ni_esslen);
+ printf("\n");
+ }
+#endif
+ }
}
- /* XXX way wrong */
- return sc->sc_newstate(ic, nstate,
- IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
+#endif
+ return (*sc->sc_newstate)(ic, nstate, arg);
+
+ case IEEE80211_S_INIT:
+ case IEEE80211_S_SCAN:
+ return sc->sc_newstate(ic, nstate, arg);
+
+ case IEEE80211_S_AUTH:
+ taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_assoc_task);
break;
case IEEE80211_S_ASSOC:
- break;
-
- case IEEE80211_S_INIT:
/*
- * NB: don't try to do this if ipw_stop_master has
- * shutdown the firmware and disabled interrupts.
+ * If we are not transitioning from AUTH the resend the
+ * association request.
*/
- if (ic->ic_state == IEEE80211_S_RUN &&
- (sc->flags & IPW_FLAG_FW_INITED))
- ipw_disassoc(ic);
- default:
+ if (ic->ic_state != IEEE80211_S_AUTH)
+ taskqueue_enqueue_fast(taskqueue_fast,
+ &sc->sc_assoc_task);
break;
default:
break;
}
- return sc->sc_newstate(ic, nstate, arg);
+
+ ic->ic_state = nstate;
+
+ return 0;
+}
+
+/*
+ * Read 16 bits at address 'addr' from the serial EEPROM.
+ */
+static uint16_t
+ipw_read_prom_word(struct ipw_softc *sc, uint8_t addr)
+{
+ uint32_t tmp;
+ uint16_t val;
+ int n;
+
+ /* clock C once before the first command */
+ IPW_EEPROM_CTL(sc, 0);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+
+ /* write start bit (1) */
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C);
+
+ /* write READ opcode (10) */
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
+
+ /* write address A7-A0 */
+ for (n = 7; n >= 0; n--) {
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S |
+ (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D));
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S |
+ (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D) | IPW_EEPROM_C);
+ }
+
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+
+ /* read data Q15-Q0 */
+ val = 0;
+ for (n = 15; n >= 0; n--) {
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+ tmp = MEM_READ_4(sc, IPW_MEM_EEPROM_CTL);
+ val |= ((tmp & IPW_EEPROM_Q) >> IPW_EEPROM_SHIFT_Q) << n;
+ }
+
+ IPW_EEPROM_CTL(sc, 0);
+
+ /* clear Chip Select and clock C */
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_S);
+ IPW_EEPROM_CTL(sc, 0);
+ IPW_EEPROM_CTL(sc, IPW_EEPROM_C);
+
+ return le16toh(val);
}
static void
-ipw_rx_cmd_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
+ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
{
struct ipw_cmd *cmd;
@@ -883,16 +966,17 @@
cmd = mtod(sbuf->m, struct ipw_cmd *);
- DPRINTFN(9, ("%s(%s subtype %u seq %u len %u status %u)\n",
- __func__, ipw_cmdname(le32toh(cmd->type)), le32toh(cmd->subtype),
- le32toh(cmd->seq), le32toh(cmd->len), le32toh(cmd->status)));
+ DPRINTFN(4, ("cmd ack'ed %s(%u, %u, %u, %u, %u)\n",
+ ipw_cmdname(le32toh(cmd->type)), le32toh(cmd->type),
+ le32toh(cmd->subtype), le32toh(cmd->seq), le32toh(cmd->len),
+ le32toh(cmd->status)));
sc->flags &= ~IPW_FLAG_BUSY;
- wakeup_one(&sc->cmd);
+ wakeup(sc);
}
static void
-ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
+ipw_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
{
#define IEEESTATE(ic) ieee80211_state_name[ic->ic_state]
struct ieee80211com *ic = &sc->sc_ic;
@@ -903,26 +987,20 @@
state = le32toh(*mtod(sbuf->m, uint32_t *));
switch (state) {
- case IPW_STATE_INITIALIZED:
- case IPW_STATE_DISABLED:
- break;
-
case IPW_STATE_ASSOCIATED:
DPRINTFN(2, ("Association succeeded (%s flags 0x%x)\n",
IEEESTATE(ic), sc->flags));
+ if (sc->flags & IPW_FLAG_SCANNING) {
+ ieee80211_cancel_scan(ic);
+ sc->flags &= ~IPW_FLAG_SCANNING;
+ }
sc->flags |= IPW_FLAG_ASSOCIATED;
- IPW_STATE_END(sc, IPW_FW_ASSOCIATING);
- /* XXX suppress state change in case the fw auto-associates */
- if (ic->ic_state != IEEE80211_S_ASSOC) {
- DPRINTF(("Unexpected association (state %u)\n",
- ic->ic_state));
- } else
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
break;
case IPW_STATE_SCANNING:
DPRINTFN(3, ("Scanning (%s flags 0x%x)\n",
- IEEESTATE(ic), sc->flags));
+ IEEESTATE(ic), sc->flags));
/*
* NB: Check driver state for association on assoc
* loss as the firmware will immediately start to
@@ -931,32 +1009,14 @@
*/
if (sc->flags & IPW_FLAG_ASSOCIATED)
ieee80211_beacon_miss(ic);
-
- sc->sc_state_timer = 3; /* fw is still alive */
break;
case IPW_STATE_SCAN_COMPLETE:
DPRINTFN(3, ("Scan complete (%s flags 0x%x)\n",
- IEEESTATE(ic), sc->flags));
- /*
- * XXX For some reason scan requests generate scan
- * started + scan done events before any traffic is
- * received (e.g. probe response frames). We work
- * around this by marking the HACK flag and skipping
- * the first scan complete event. This works ok
- * because the adapter scans only 2.4G channels so
- * doing an extra pass doesn't take long.
- if (sc->flags & IPW_FLAG_HACK) {
- sc->flags &= ~IPW_FLAG_HACK;
- break;
- }
- */
-
- /* Only update the scan module if we were actaully scanning */
- if (sc->fw_state == IPW_FW_SCANNING) {
+ IEEESTATE(ic), sc->flags));
+ if (sc->flags & IPW_FLAG_SCANNING) {
+ ieee80211_scan_done(ic);
sc->flags &= ~IPW_FLAG_SCANNING;
- IPW_STATE_END(sc, IPW_FW_SCANNING);
- ieee80211_scan_done(ic);
}
break;
@@ -964,16 +1024,24 @@
DPRINTFN(2, ("Association lost (%s flags 0x%x)\n",
IEEESTATE(ic), sc->flags));
sc->flags &= ~IPW_FLAG_ASSOCIATED;
- taskqueue_enqueue(sc->sc_tq, &sc->sc_assoclosttask);
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ break;
+
+ case IPW_STATE_DISABLED:
+ DPRINTFN(2, ("Firmware disabled (%s flags 0x%x)\n",
+ IEEESTATE(ic), sc->flags));
break;
- case IPW_STATE_RADIO_OFF:
+ case IPW_STATE_RADIO_DISABLED:
DPRINTFN(2, ("Radio off (%s flags 0x%x)\n",
IEEESTATE(ic), sc->flags));
- taskqueue_enqueue(sc->sc_tq, &sc->sc_radiofftask);
+ ic->ic_ifp->if_flags &= ~IFF_UP;
+ ipw_stop(sc);
break;
+
default:
- DPRINTFN(2, ("%s: state %u %s flags 0x%x\n",
+ DPRINTFN(2, ("%s: unhandled state %u %s flags 0x%x\n",
__func__, state, IEEESTATE(ic), sc->flags));
break;
}
@@ -998,7 +1066,6 @@
/*
* XXX: Hack to set the current channel to the value advertised in beacons or
* probe responses. Only used during AP detection.
- * XXX value comes from DSPARMS ie which is wrong for off-channel rx's
*/
static void
ipw_fix_channel(struct ipw_softc *sc, struct mbuf *m)
@@ -1025,11 +1092,12 @@
frm += 12; /* skip tstamp, bintval and capinfo fields */
while (frm < efrm) {
- if (*frm == IEEE80211_ELEMID_DSPARMS
+ if (*frm == IEEE80211_ELEMID_DSPARMS)
#if IEEE80211_CHAN_MAX < 255
- && frm[2] <= IEEE80211_CHAN_MAX
+ if (frm[2] <= IEEE80211_CHAN_MAX)
#endif
- ) {
+ {
+ DPRINTF(("Fixing channel to %d\n", frm[2]));
c = ieee80211_find_channel(ic,
ieee80211_ieee2mhz(frm[2], 0),
IEEE80211_CHAN_B);
@@ -1043,7 +1111,7 @@
}
static void
-ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status,
+ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -1052,25 +1120,15 @@
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
bus_addr_t physaddr;
- int error, framelen;
- IPW_LOCK_DECL;
-
- framelen = le32toh(status->len);
- if (framelen < IEEE80211_MIN_LEN || framelen > MCLBYTES) {
- /*
- * XXX >MCLBYTES is bogus as it means the h/w dma'd
- * out of bounds; need to figure out how to limit
- * frame size in the firmware
- */
- /* XXX stat */
- DPRINTF(("drop rx frame len=%u rssi=%u\n",
- framelen, status->rssi));
- return;
- }
+ int error;
DPRINTFN(5, ("received frame len=%u, rssi=%u\n", le32toh(status->len),
status->rssi));
+ if (le32toh(status->len) < sizeof (struct ieee80211_frame_min) ||
+ le32toh(status->len) > MCLBYTES)
+ return;
+
/*
* Try to allocate a new mbuf for this ring element and load it before
* processing the current mbuf. If the ring element cannot be loaded,
@@ -1116,21 +1174,22 @@
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = le32toh(status->len);
- /* XXX */
- if (sc->flags & IPW_FLAG_SCANNING)
- ipw_fix_channel(sc, m);
-
- if (sc->sc_drvbpf != NULL) {
+ if (bpf_peers_present(sc->sc_drvbpf)) {
struct ipw_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->wr_flags = 0;
- tap->wr_antsignal = status->rssi + IPW_RSSI_TO_DBM;
+ tap->wr_antsignal = status->rssi;
+ tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ ipw_fix_channel(sc, m);
+
wh = mtod(m, struct ieee80211_frame *);
- IPW_UNLOCK(sc);
+ mtx_unlock(&sc->sc_mtx);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
@@ -1138,7 +1197,7 @@
/* node is no longer needed */
ieee80211_free_node(ni);
- IPW_LOCK(sc);
+ mtx_lock(&sc->sc_mtx);
bus_dmamap_sync(sc->rbd_dmat, sc->rbd_map, BUS_DMASYNC_PREWRITE);
}
@@ -1166,16 +1225,16 @@
switch (le16toh(status->code) & 0xf) {
case IPW_STATUS_CODE_COMMAND:
- ipw_rx_cmd_intr(sc, sbuf);
+ ipw_command_intr(sc, sbuf);
break;
case IPW_STATUS_CODE_NEWSTATE:
- ipw_rx_newstate_intr(sc, sbuf);
+ ipw_newstate_intr(sc, sbuf);
break;
case IPW_STATUS_CODE_DATA_802_3:
case IPW_STATUS_CODE_DATA_802_11:
- ipw_rx_data_intr(sc, status, sbd, sbuf);
+ ipw_data_intr(sc, status, sbd, sbuf);
break;
case IPW_STATUS_CODE_NOTIFICATION:
@@ -1191,8 +1250,12 @@
default:
device_printf(sc->sc_dev, "unexpected status code %u\n",
le16toh(status->code));
- break;
}
+
+ /* firmware was killed, stop processing received frames */
+ if (!(sc->flags & IPW_FLAG_FW_INITED))
+ return;
+
sbd->bd->flags = 0;
}
@@ -1230,8 +1293,12 @@
bus_dmamap_unload(sc->txbuf_dmat, sbuf->map);
SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
+ if (sbuf->m->m_flags & M_TXCB)
+ ieee80211_process_callback(sbuf->ni, sbuf->m, 0/*XXX*/);
m_freem(sbuf->m);
ieee80211_free_node(sbuf->ni);
+
+ sc->sc_tx_timer = 0;
break;
}
@@ -1263,10 +1330,8 @@
/* remember what the firmware has processed */
sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1;
- sc->sc_tx_timer = 0;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-
- ipw_start_locked(ifp);
+ ipw_start(ifp);
}
static void
@@ -1276,39 +1341,36 @@
uint32_t r;
mtx_lock(&sc->sc_mtx);
- r = CSR_READ_4(sc, IPW_CSR_INTR);
- if (r != 0 && r != 0xffffffff) {
- /* acknowledge all interrupts */
- CSR_WRITE_4(sc, IPW_CSR_INTR, r);
+
+ if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff) {
+ mtx_unlock(&sc->sc_mtx);
+ return;
+ }
+
+ /* disable interrupts */
+ CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
- DPRINTFN(9, ("%s: 0x%x\n", __func__, r));
+ /* acknowledge all interrupts */
+ CSR_WRITE_4(sc, IPW_CSR_INTR, r);
- if (r & IPW_INTR_FATAL_ERROR) {
- device_printf(sc->sc_dev, "firmware error\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
- r = 0; /* NB: don't do anything else */
- }
- if (r & IPW_INTR_FW_INIT_DONE) {
- wakeup_one(sc);
- r &= ~IPW_INTR_FW_INIT_DONE;
- }
- if (r & IPW_INTR_RX_TRANSFER) {
- ipw_rx_intr(sc);
- r &= ~IPW_INTR_RX_TRANSFER;
- }
- if (r & IPW_INTR_TX_TRANSFER) {
- ipw_tx_intr(sc);
- r &= ~IPW_INTR_TX_TRANSFER;
- }
- if (r & IPW_INTR_PARITY_ERROR) {
- /* XXX rate limit */
- device_printf(sc->sc_dev, "parity error\n");
- r &= ~IPW_INTR_PARITY_ERROR;
- }
- if (r != 0)
- device_printf(sc->sc_dev,
- "%s: 0x%x unserviced\n", __func__, r);
+ if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
+ device_printf(sc->sc_dev, "firmware error\n");
+ taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_init_task);
+ r = 0; /* don't process more interrupts */
}
+
+ if (r & IPW_INTR_FW_INIT_DONE)
+ wakeup(sc);
+
+ if (r & IPW_INTR_RX_TRANSFER)
+ ipw_rx_intr(sc);
+
+ if (r & IPW_INTR_TX_TRANSFER)
+ ipw_tx_intr(sc);
+
+ /* re-enable interrupts */
+ CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
+
mtx_unlock(&sc->sc_mtx);
}
@@ -1335,7 +1397,6 @@
{ IPW_CMD_BROADCAST_SCAN, "BROADCAST_SCAN" },
{ IPW_CMD_DISABLE, "DISABLE" },
{ IPW_CMD_DISABLE_PHY, "DISABLE_PHY" },
- { IPW_CMD_DISASSOCIATE, "DISASSOCIATE" },
{ IPW_CMD_ENABLE, "ENABLE" },
{ IPW_CMD_PREPARE_POWER_DOWN, "PREPARE_POWER_DOWN" },
{ IPW_CMD_SET_BASIC_TX_RATES, "SET_BASIC_TX_RATES" },
@@ -1345,17 +1406,13 @@
{ IPW_CMD_SET_DESIRED_BSSID, "SET_DESIRED_BSSID" },
{ IPW_CMD_SET_ESSID, "SET_ESSID" },
{ IPW_CMD_SET_FRAG_THRESHOLD, "SET_FRAG_THRESHOLD" },
- { IPW_CMD_SET_LONG_RETRY, "SET_LONG_RETRY" },
{ IPW_CMD_SET_MAC_ADDRESS, "SET_MAC_ADDRESS" },
{ IPW_CMD_SET_MANDATORY_BSSID, "SET_MANDATORY_BSSID" },
{ IPW_CMD_SET_MODE, "SET_MODE" },
- { IPW_CMD_SET_MSDU_TX_RATES, "SET_MSDU_TX_RATES" },
{ IPW_CMD_SET_POWER_MODE, "SET_POWER_MODE" },
{ IPW_CMD_SET_RTS_THRESHOLD, "SET_RTS_THRESHOLD" },
- { IPW_CMD_SET_SCAN_DWELL_TIME, "SET_SCAN_DWELL_TIME" },
{ IPW_CMD_SET_SCAN_OPTIONS, "SET_SCAN_OPTIONS" },
- { IPW_CMD_SET_SECURITY_INFO, "SET_SECURITY_INFO" },
- { IPW_CMD_SET_SHORT_RETRY, "SET_SHORT_RETRY" },
+ { IPW_CMD_SET_SECURITY_INFORMATION, "SET_SECURITY_INFO" },
{ IPW_CMD_SET_TX_POWER_INDEX, "SET_TX_POWER_INDEX" },
{ IPW_CMD_SET_TX_RATES, "SET_TX_RATES" },
{ IPW_CMD_SET_WEP_FLAGS, "SET_WEP_FLAGS" },
@@ -1379,15 +1436,18 @@
* Send a command to the firmware and wait for the acknowledgement.
*/
static int
-ipw_cmd(struct ipw_softc *sc, uint32_t cmd, const void *data, uint32_t len)
+ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
{
struct ipw_soft_bd *sbd;
bus_addr_t physaddr;
int error;
+ if (mtx_recursed(&sc->sc_mtx))
+ device_printf(sc->sc_dev, "OMG, msleeping on a recursed mtx\n");
+
if (sc->flags & IPW_FLAG_BUSY) {
device_printf(sc->sc_dev, "%s: %s not sent, busy\n",
- __func__, ipw_cmdname(cmd));
+ __func__, ipw_cmdname(type));
return EAGAIN;
}
sc->flags |= IPW_FLAG_BUSY;
@@ -1397,13 +1457,12 @@
error = bus_dmamap_load(sc->cmd_dmat, sc->cmd_map, &sc->cmd,
sizeof (struct ipw_cmd), ipw_dma_map_addr, &physaddr, 0);
if (error != 0) {
- device_printf(sc->sc_dev,
- "%s: %s not sent, could not map memory (error %u)\n",
- __func__, ipw_cmdname(cmd), error);
+ device_printf(sc->sc_dev, "could not map command DMA memory\n");
+ sc->flags &= ~IPW_FLAG_BUSY;
return error;
}
- sc->cmd.type = htole32(cmd);
+ sc->cmd.type = htole32(type);
sc->cmd.subtype = 0;
sc->cmd.len = htole32(len);
sc->cmd.seq = 0;
@@ -1420,7 +1479,7 @@
bus_dmamap_sync(sc->tbd_dmat, sc->tbd_map, BUS_DMASYNC_PREWRITE);
DPRINTFN(4, ("sending %s(%u, %u, %u, %u)\n",
- ipw_cmdname(cmd), cmd, 0, 0, len));
+ ipw_cmdname(type), type, 0, 0, len));
/* kick firmware */
sc->txfree--;
@@ -1428,13 +1487,14 @@
CSR_WRITE_4(sc, IPW_CSR_TX_WRITE, sc->txcur);
/* wait at most one second for command to complete */
- error = msleep(&sc->cmd, &sc->sc_mtx, 0, "ipwcmd", hz);
+ error = msleep(sc, &sc->sc_mtx, 0, "ipwcmd", hz);
if (error != 0) {
device_printf(sc->sc_dev, "%s: %s failed, timeout (error %u)\n",
- __func__, ipw_cmdname(cmd), error);
- return error;
+ __func__, ipw_cmdname(type), error);
+ sc->flags &= ~IPW_FLAG_BUSY;
+ return (error);
}
- return 0;
+ return (0);
}
static int
@@ -1450,15 +1510,11 @@
struct mbuf *mnew;
bus_dma_segment_t segs[IPW_MAX_NSEG];
bus_addr_t physaddr;
- int nsegs, error, i, iswep, hdrlen, ismcast;
+ int nsegs, error, i;
wh = mtod(m0, struct ieee80211_frame *);
- /* NB: only data frames use this path */
- iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
- hdrlen = ieee80211_hdrsize(wh);
- ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
- if (iswep) {
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
k = ieee80211_crypto_encap(ic, ni, m0);
if (k == NULL) {
m_freem(m0);
@@ -1469,10 +1525,12 @@
wh = mtod(m0, struct ieee80211_frame *);
}
- if (sc->sc_drvbpf != NULL) {
+ if (bpf_peers_present(sc->sc_drvbpf)) {
struct ipw_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
+ tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list