Date: Tue, 22 Sep 2015 02:57:19 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r288089 - head/sys/dev/usb/wlan Message-ID: <201509220257.t8M2vJKI088040@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Tue Sep 22 02:57:18 2015 New Revision: 288089 URL: https://svnweb.freebsd.org/changeset/base/288089 Log: Begin fleshing out basic power-on / power-off and A-MPDU TX support. * Add a new method to control NIC poweron / network-sleep / power off; * Add in A-MPDU TX negotiation support, but comment it out because it does break TX traffic; * blank out the tx buffer before sending a firmware message, just in case; * go into network-sleep once associated; TODO: * figure out why ampdu negotiation isn't working and breaking TX traffic, then enable it. Modified: head/sys/dev/usb/wlan/if_rsu.c head/sys/dev/usb/wlan/if_rsureg.h Modified: head/sys/dev/usb/wlan/if_rsu.c ============================================================================== --- head/sys/dev/usb/wlan/if_rsu.c Tue Sep 22 02:48:59 2015 (r288088) +++ head/sys/dev/usb/wlan/if_rsu.c Tue Sep 22 02:57:18 2015 (r288089) @@ -100,6 +100,7 @@ TUNABLE_INT("hw.usb.rsu.enable_11n", &rs #define RSU_DEBUG_TXDONE 0x00000080 #define RSU_DEBUG_FW 0x00000100 #define RSU_DEBUG_FWDBG 0x00000200 +#define RSU_DEBUG_AMPDU 0x00000400 static const STRUCT_USB_HOST_ID rsu_devs[] = { #define RSU_HT_NOT_SUPPORTED 0 @@ -336,11 +337,51 @@ rsu_update_chw(struct ieee80211com *ic) } +/* + * notification from net80211 that it'd like to do A-MPDU on the given TID. + * + * Note: this actually hangs traffic at the present moment, so don't use it. + * The firmware debug does indiciate it's sending and establishing a TX AMPDU + * session, but then no traffic flows. + */ static int rsu_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { +#if 0 + struct rsu_softc *sc = ni->ni_ic->ic_softc; + struct r92s_add_ba_req req; - /* Firmware handles this; not our problem */ + /* Don't enable if it's requested or running */ + if (IEEE80211_AMPDU_REQUESTED(tap)) + return (0); + if (IEEE80211_AMPDU_RUNNING(tap)) + return (0); + + /* We've decided to send addba; so send it */ + req.tid = htole32(tap->txa_tid); + + /* Attempt net80211 state */ + if (ieee80211_ampdu_tx_request_ext(ni, tap->txa_tid) != 1) + return (0); + + /* Send the firmware command */ + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: establishing AMPDU TX for TID %d\n", + __func__, + tap->txa_tid); + + RSU_LOCK(sc); + if (rsu_fw_cmd(sc, R92S_CMD_ADDBA_REQ, &req, sizeof(req)) != 1) { + RSU_UNLOCK(sc); + /* Mark failure */ + (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 0); + return (0); + } + RSU_UNLOCK(sc); + + /* Mark success; we don't get any further notifications */ + (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 1); +#endif + /* Return 0, we're driving this ourselves */ return (0); } @@ -606,6 +647,7 @@ rsu_scan_start(struct ieee80211com *ic) /* Scanning is done by the firmware. */ RSU_LOCK(sc); + /* XXX TODO: force awake if in in network-sleep? */ error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps)); RSU_UNLOCK(sc); if (error != 0) @@ -965,7 +1007,11 @@ rsu_fw_cmd(struct rsu_softc *sc, uint8_t if (data == NULL) return (ENOMEM); + /* Blank the entire payload, just to be safe */ + memset(data->buf, '\0', RSU_TXBUFSZ); + /* Round-up command length to a multiple of 8 bytes. */ + /* XXX TODO: is this required? */ cmdsz = (len + 7) & ~7; xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz; @@ -1042,6 +1088,66 @@ rsu_tx_task(void *arg, int pending __unu RSU_UNLOCK(sc); } +#define RSU_PWR_ACTIVE 0x1 +#define RSU_PWR_OFF 0x2 +#define RSU_PWR_SLEEP 0x3 + +/* + * Set the current power state. + * + * The rtlwifi code doesn't do this so aggressively; it + * waits for an idle period after association with + * no traffic before doing this. + * + * For now - it's on in all states except RUN, and + * in RUN it'll transition to allow sleep. + */ + +struct r92s_pwr_cmd { + uint8_t mode; + uint8_t smart_ps; + uint8_t bcn_pass_time; +}; + +static int +rsu_set_fw_power_state(struct rsu_softc *sc, int state) +{ + struct r92s_set_pwr_mode cmd; + //struct r92s_pwr_cmd cmd; + int error; + + memset(&cmd, 0, sizeof(cmd)); + + /* XXX TODO: only change state if required */ + RSU_ASSERT_LOCKED(sc); + + switch (state) { + case RSU_PWR_ACTIVE: + /* Force the hardware awake */ + rsu_write_1(sc, R92S_USB_HRPWM, + R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON); + cmd.mode = R92S_PS_MODE_ACTIVE; + break; + case RSU_PWR_SLEEP: + cmd.mode = R92S_PS_MODE_DTIM; /* XXX configurable? */ + cmd.smart_ps = 1; /* XXX 2 if doing p2p */ + cmd.bcn_pass_time = 5; /* in 100mS usb.c, linux/rtlwifi */ + break; + default: + device_printf(sc->sc_dev, "%s: unknown ps mode (%d)\n", + __func__, + state); + return (ENXIO); + } + + RSU_DPRINTF(sc, RSU_DEBUG_RESET, + "%s: setting ps mode to %d (mode %d)\n", + __func__, state, cmd.mode); + error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd)); + + return (error); +} + static int rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { @@ -1074,9 +1180,11 @@ rsu_newstate(struct ieee80211vap *vap, e RSU_LOCK(sc); switch (nstate) { case IEEE80211_S_INIT: + (void) rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); break; case IEEE80211_S_AUTH: ni = ieee80211_ref_node(vap->iv_bss); + (void) rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); error = rsu_join_bss(sc, ni); ieee80211_free_node(ni); if (error != 0) { @@ -1089,6 +1197,7 @@ rsu_newstate(struct ieee80211vap *vap, e rs = &ni->ni_rates; /* Indicate highest supported rate. */ ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; + (void) rsu_set_fw_power_state(sc, RSU_PWR_SLEEP); ieee80211_free_node(ni); startcal = 1; break; @@ -1477,13 +1586,11 @@ rsu_rx_event(struct rsu_softc *sc, uint8 buf[60] = '\0'; RSU_DPRINTF(sc, RSU_DEBUG_FWDBG, "FWDBG: %s\n", (char *)buf); break; - case R92S_EVT_ADDBA_REQ_REPORT: rsu_event_addba_req_report(sc, buf, len); break; default: - RSU_DPRINTF(sc, RSU_DEBUG_ANY, "%s: unhandled code (%d)\n", - __func__, code); + device_printf(sc->sc_dev, "%s: unhandled code (%d)\n", __func__, code); break; } } @@ -2403,7 +2510,7 @@ rsu_load_firmware(struct rsu_softc *sc) int ntries, error; if (rsu_read_1(sc, R92S_TCR) & R92S_TCR_FWRDY) { - RSU_DPRINTF(sc, RSU_DEBUG_FW | RSU_DEBUG_RESET, + RSU_DPRINTF(sc, RSU_DEBUG_ANY, "%s: Firmware already loaded\n", __func__); return (0); @@ -2527,6 +2634,7 @@ rsu_load_firmware(struct rsu_softc *sc) memset(dmem, 0, sizeof(*dmem)); dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172; dmem->nendpoints = sc->sc_nendpoints; + dmem->chip_version = sc->cut; /* XXX TODO: rf_config should come from ROM */ dmem->rf_config = 0x11; /* 1T1R */ dmem->vcs_type = R92S_VCS_TYPE_AUTO; @@ -2537,6 +2645,8 @@ rsu_load_firmware(struct rsu_softc *sc) dmem->ampdu_en = !! (sc->sc_ht); dmem->agg_offload = !! (sc->sc_ht); dmem->qos_en = 1; + dmem->ps_offload = 1; + dmem->lowpower_mode = 1; /* XXX TODO: configurable? */ /* Load DMEM section. */ error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem)); if (error != 0) { @@ -2613,7 +2723,6 @@ rsu_init(struct rsu_softc *sc) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint8_t macaddr[IEEE80211_ADDR_LEN]; - struct r92s_set_pwr_mode cmd; int error; int i; @@ -2625,6 +2734,9 @@ rsu_init(struct rsu_softc *sc) /* Init host async commands ring. */ sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; + /* Reset power management state. */ + rsu_write_1(sc, R92S_USB_HRPWM, 0); + /* Power on adapter. */ if (sc->cut == 1) rsu_power_on_acut(sc); @@ -2677,15 +2789,9 @@ rsu_init(struct rsu_softc *sc) goto fail; } - rsu_write_1(sc, R92S_USB_HRPWM, - R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON); - /* Set PS mode fully active */ - memset(&cmd, 0, sizeof(cmd)); - cmd.mode = R92S_PS_MODE_ACTIVE; - RSU_DPRINTF(sc, RSU_DEBUG_RESET, "%s: setting ps mode to %d\n", - __func__, cmd.mode); - error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd)); + error = rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); + if (error != 0) { device_printf(sc->sc_dev, "could not set PS mode\n"); goto fail; Modified: head/sys/dev/usb/wlan/if_rsureg.h ============================================================================== --- head/sys/dev/usb/wlan/if_rsureg.h Tue Sep 22 02:48:59 2015 (r288088) +++ head/sys/dev/usb/wlan/if_rsureg.h Tue Sep 22 02:57:18 2015 (r288089) @@ -599,6 +599,10 @@ struct r92s_add_ba_event { uint8_t tid; }; +struct r92s_add_ba_req { + uint32_t tid; +}; + /* * Driver definitions. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509220257.t8M2vJKI088040>