Skip site navigation (1)Skip section navigation (2)
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>