All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] wl12xx: add support for rx streaming
@ 2011-02-02  9:12 Eliad Peller
  2011-02-02  9:12 ` [PATCH 2/3] wl12xx: add automatic rx streaming support Eliad Peller
  2011-02-02  9:12 ` [PATCH 3/3] wl12xx: add rx_streaming debugfs entry Eliad Peller
  0 siblings, 2 replies; 3+ messages in thread
From: Eliad Peller @ 2011-02-02  9:12 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

wl1271 supports a feature called "rx streaming".
when in ps mode, and @timeout msecs have passed since last tx, it issues
trigger packets (QoS-null/PS-Poll according to the ac type) in const
intervals (in order to reduce rx time).

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
Note: this patchset is rebased on top of the new firmware api patchset,
      although the feature exists in the older firmware as well.
 drivers/net/wireless/wl12xx/acx.c  |   37 ++++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/acx.h  |   14 +++++++++++++
 drivers/net/wireless/wl12xx/conf.h |   25 ++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/main.c |    7 +++++-
 4 files changed, 82 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 33840d9..54aec2e 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1489,6 +1489,43 @@ out:
 	return ret;
 }
 
+int wl1271_acx_ps_rx_streaming(struct wl1271 *wl)
+{
+	struct wl1271_acx_ps_rx_streaming *rx_streaming;
+	u32 rx_streaming_queues;
+	int ret, i;
+
+	wl1271_debug(DEBUG_ACX, "acx ps rx streaming");
+
+	rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL);
+	if (!rx_streaming) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	rx_streaming_queues = wl->conf.rx_streaming.queues;
+	for (i = 0; i < 8; i++) {
+		rx_streaming->tid = i;
+		rx_streaming->enable = rx_streaming_queues & 1;
+		rx_streaming->period = wl->conf.rx_streaming.interval;
+		rx_streaming->timeout = wl->conf.rx_streaming.interval;
+
+		ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
+					   rx_streaming,
+					   sizeof(*rx_streaming));
+		if (ret < 0) {
+			wl1271_warning("acx ps rx streaming failed: %d", ret);
+			goto out;
+		}
+
+		rx_streaming_queues >>= 1;
+	}
+
+out:
+	kfree(rx_streaming);
+	return ret;
+}
+
 int wl1271_acx_max_tx_retry(struct wl1271 *wl)
 {
 	struct wl1271_acx_max_tx_retry *acx = NULL;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 9822e16..aa1fad8 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1135,6 +1135,19 @@ struct wl1271_acx_fw_tsf_information {
 	u8 padding[3];
 } __packed;
 
+struct wl1271_acx_ps_rx_streaming {
+	struct acx_header header;
+
+	u8 tid;
+	u8 enable;
+
+	/* interval between triggers (10-100 msec) */
+	u8 period;
+
+	/* timeout before first trigger (0-200 msec) */
+	u8 timeout;
+} __packed;
+
 struct wl1271_acx_max_tx_retry {
 	struct acx_header header;
 
@@ -1288,6 +1301,7 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
 int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
 				       bool enable);
 int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+int wl1271_acx_ps_rx_streaming(struct wl1271 *wl);
 int wl1271_acx_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 856a8a2..85775c8 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -1191,6 +1191,30 @@ struct conf_memory_settings {
 	u8 tx_min;
 };
 
+struct conf_rx_streaming_settings {
+	/*
+	 * RX Streaming duration (in msec) from last tx/rx
+	 *
+	 * Range: u32
+	 */
+	u32 duration;
+
+	/*
+	 * Bitmap of tids to be polled during RX streaming.
+	 * (Note: it doesn't look like it really matters)
+	 *
+	 * Range: 0x1-0xff
+	 */
+	u8 queues;
+
+	/*
+	 * RX Streaming interval.
+	 * (Note:this value is also used as the rx streaming timeout)
+	 * Range: 10 - 100
+	 */
+	u8 interval;
+};
+
 struct conf_drv_settings {
 	struct conf_sg_settings sg;
 	struct conf_rx_settings rx;
@@ -1203,6 +1227,7 @@ struct conf_drv_settings {
 	struct conf_rf_settings rf;
 	struct conf_ht_setting ht;
 	struct conf_memory_settings mem;
+	struct conf_rx_streaming_settings rx_streaming;
 };
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 6ef69a4..ff991c9 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -307,7 +307,12 @@ static struct conf_drv_settings default_conf = {
 		.min_req_tx_blocks            = 104,
 		.min_req_rx_blocks            = 22,
 		.tx_min                       = 27,
-	}
+	},
+	.rx_streaming = {
+		.duration                      = 30000,
+		.queues                        = 0xff,
+		.interval                      = 0,
+	},
 };
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/3] wl12xx: add automatic rx streaming support
  2011-02-02  9:12 [PATCH 1/3] wl12xx: add support for rx streaming Eliad Peller
@ 2011-02-02  9:12 ` Eliad Peller
  2011-02-02  9:12 ` [PATCH 3/3] wl12xx: add rx_streaming debugfs entry Eliad Peller
  1 sibling, 0 replies; 3+ messages in thread
From: Eliad Peller @ 2011-02-02  9:12 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

when rx_streaming.interval is non-zero, use automatic rx streaming.
we enable rx streaming on the each rx/tx packet, and disable it
rx_streaming.duration msecs later.

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/main.c   |  126 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/rx.c     |   13 ++++
 drivers/net/wireless/wl12xx/tx.c     |   11 +++
 drivers/net/wireless/wl12xx/wl12xx.h |    9 ++-
 4 files changed, 158 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ff991c9..ad8bbc2 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -419,6 +419,121 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
 	return 0;
 }
 
+static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
+{
+	int ret = 0;
+
+	/* we should hold wl->mutex */
+	if (enable) {
+		wl->conf.rx_streaming.queues = 0xff;
+		ret = wl1271_acx_ps_rx_streaming(wl);
+		if (!ret)
+			set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
+	} else {
+		wl->conf.rx_streaming.queues = 0;
+		ret = wl1271_acx_ps_rx_streaming(wl);
+		if (!ret)
+			clear_bit(WL1271_FLAG_RX_STREAMING_STARTED,
+				  &wl->flags);
+	}
+
+	return ret;
+}
+
+/*
+ * this function is being called when the rx_streaming interval
+ * has beed changed
+ */
+int wl1271_recalc_rx_streaming(struct wl1271 *wl)
+{
+	int ret = 0;
+	int period = wl->conf.rx_streaming.interval;
+
+	/* don't reconfigure if rx_streaming is disabled */
+	if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl, false);
+	if (ret < 0)
+		goto out;
+
+	/* reconfigure/disable according to new streaming_period */
+	if (period)
+		ret = wl1271_set_rx_streaming(wl, true);
+	else {
+		ret = wl1271_set_rx_streaming(wl, false);
+		/* don't cancel_work_sync since we might deadlock */
+		del_timer_sync(&wl->rx_streaming_timer);
+	}
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	return ret;
+}
+
+static void wl1271_rx_streaming_enable_work(struct work_struct *work)
+{
+	int ret;
+	struct wl1271 *wl =
+		container_of(work, struct wl1271, rx_streaming_enable_work);
+
+	mutex_lock(&wl->mutex);
+
+	if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+		goto out;
+
+	if (!wl->conf.rx_streaming.interval)
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl, false);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_set_rx_streaming(wl, true);
+	if (ret < 0)
+		goto out_sleep;
+
+	/* stop it after some time of inactivity */
+	mod_timer(&wl->rx_streaming_timer,
+		  jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void wl1271_rx_streaming_disable_work(struct work_struct *work)
+{
+	int ret;
+	struct wl1271 *wl =
+		container_of(work, struct wl1271, rx_streaming_disable_work);
+
+	mutex_lock(&wl->mutex);
+
+	if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl, false);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_set_rx_streaming(wl, false);
+	if (ret)
+		goto out_sleep;
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void wl1271_rx_streaming_timer(unsigned long data)
+{
+	struct wl1271 *wl = (struct wl1271 *)data;
+	ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
+}
+
 static void wl1271_conf_init(struct wl1271 *wl)
 {
 
@@ -3302,6 +3417,11 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	INIT_WORK(&wl->tx_work, wl1271_tx_work);
 	INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
 	INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+	INIT_WORK(&wl->rx_streaming_enable_work,
+		  wl1271_rx_streaming_enable_work);
+	INIT_WORK(&wl->rx_streaming_disable_work,
+		  wl1271_rx_streaming_disable_work);
+
 	wl->channel = WL1271_DEFAULT_CHANNEL;
 	wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
 	wl->default_key = 0;
@@ -3321,6 +3441,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	wl->bss_type = MAX_BSS_TYPE;
 	wl->set_bss_type = MAX_BSS_TYPE;
 	wl->fw_bss_type = MAX_BSS_TYPE;
+	setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
+		    (unsigned long) wl);
 
 	memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
@@ -3389,6 +3511,10 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 
 int wl1271_free_hw(struct wl1271 *wl)
 {
+	del_timer_sync(&wl->rx_streaming_timer);
+	cancel_work_sync(&wl->rx_streaming_enable_work);
+	cancel_work_sync(&wl->rx_streaming_disable_work);
+
 	platform_device_unregister(wl->plat_dev);
 	free_pages((unsigned long)wl->aggr_buf,
 			get_order(WL1271_AGGR_BUFFER_SIZE));
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 029597b..0846242 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -144,6 +144,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 	u32 mem_block;
 	u32 pkt_length;
 	u32 pkt_offset;
+	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
 
 	while (drv_rx_counter != fw_rx_counter) {
 		buf_size = 0;
@@ -199,6 +200,18 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 		}
 	}
 	wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+
+	if (!is_ap && wl->conf.rx_streaming.interval) {
+		u32 timeout = wl->conf.rx_streaming.duration;
+
+		/* restart rx streaming */
+		if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+			ieee80211_queue_work(wl->hw,
+					     &wl->rx_streaming_enable_work);
+
+		mod_timer(&wl->rx_streaming_timer,
+			  jiffies + msecs_to_jiffies(timeout));
+	}
 }
 
 void wl1271_set_default_filters(struct wl1271 *wl)
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 67a0094..797a449 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -336,6 +336,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 	bool woken_up = false;
 	u32 buf_offset = 0;
 	bool sent_packets = false;
+	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
 	int ret;
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -389,7 +390,17 @@ out_ack:
 		wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
 		handle_tx_low_watermark(wl);
 	}
+	if (!is_ap && wl->conf.rx_streaming.interval) {
+		u32 timeout = wl->conf.rx_streaming.duration;
+
+		/* enable rx streaming */
+		if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+			ieee80211_queue_work(wl->hw,
+					     &wl->rx_streaming_enable_work);
 
+		mod_timer(&wl->rx_streaming_timer,
+			  jiffies + msecs_to_jiffies(timeout));
+	}
 out:
 	if (woken_up)
 		wl1271_ps_elp_sleep(wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 15d9e9e..f2ec0f9 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -316,7 +316,8 @@ enum wl12xx_flags {
 	WL1271_FLAG_PSPOLL_FAILURE,
 	WL1271_FLAG_STA_STATE_SENT,
 	WL1271_FLAG_FW_TX_BUSY,
-	WL1271_FLAG_AP_STARTED
+	WL1271_FLAG_AP_STARTED,
+	WL1271_FLAG_RX_STREAMING_STARTED
 };
 
 struct wl1271 {
@@ -443,6 +444,11 @@ struct wl1271 {
 	/* Default key (for WEP) */
 	u32 default_key;
 
+	/* Rx Streaming */
+	struct work_struct rx_streaming_enable_work;
+	struct work_struct rx_streaming_disable_work;
+	struct timer_list rx_streaming_timer;
+
 	unsigned int filters;
 	unsigned int rx_config;
 	unsigned int rx_filter;
@@ -506,6 +512,7 @@ struct wl1271_station {
 
 int wl1271_plt_start(struct wl1271 *wl);
 int wl1271_plt_stop(struct wl1271 *wl);
+int wl1271_recalc_rx_streaming(struct wl1271 *wl);
 
 #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 3/3] wl12xx: add rx_streaming debugfs entry
  2011-02-02  9:12 [PATCH 1/3] wl12xx: add support for rx streaming Eliad Peller
  2011-02-02  9:12 ` [PATCH 2/3] wl12xx: add automatic rx streaming support Eliad Peller
@ 2011-02-02  9:12 ` Eliad Peller
  1 sibling, 0 replies; 3+ messages in thread
From: Eliad Peller @ 2011-02-02  9:12 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

allow control over rx_streaming interval via debugfs (value is in ms).

e.g.
echo 100 > /debug/ieee80211/phy0/wl12xx/rx_streaming_interval

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/debugfs.c |   54 +++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index bebfa28..43b4599 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -291,6 +291,59 @@ static const struct file_operations gpio_power_ops = {
 	.llseek = default_llseek,
 };
 
+static ssize_t rx_streaming_interval_write(struct file *file,
+			   const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	char buf[10];
+	size_t len;
+	unsigned long value;
+	int ret;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+	buf[len] = '\0';
+
+	ret = strict_strtoul(buf, 0, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in rx_streaming_interval!");
+		return -EINVAL;
+	}
+
+	/* valid values: 0, 10-100 */
+	if (value && (value < 10 || value > 100)) {
+		wl1271_warning("value is not in range!");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.rx_streaming.interval = value;
+
+	wl1271_recalc_rx_streaming(wl);
+
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static ssize_t rx_streaming_interval_read(struct file *file,
+			    char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	return wl1271_format_buffer(userbuf, count, ppos,
+				    "%d\n", wl->conf.rx_streaming.interval);
+}
+
+static const struct file_operations rx_streaming_interval_ops = {
+	.read = rx_streaming_interval_read,
+	.write = rx_streaming_interval_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static int wl1271_debugfs_add_files(struct wl1271 *wl,
 				     struct dentry *rootdir)
 {
@@ -399,6 +452,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
 	DEBUGFS_ADD(excessive_retries, rootdir);
 
 	DEBUGFS_ADD(gpio_power, rootdir);
+	DEBUGFS_ADD(rx_streaming_interval, rootdir);
 
 	return 0;
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-02-02  9:12 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-02  9:12 [PATCH 1/3] wl12xx: add support for rx streaming Eliad Peller
2011-02-02  9:12 ` [PATCH 2/3] wl12xx: add automatic rx streaming support Eliad Peller
2011-02-02  9:12 ` [PATCH 3/3] wl12xx: add rx_streaming debugfs entry Eliad Peller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.