This patchset adds support for hardware TX fragmentation offload
to mac80211 based drivers. A callback is added to ieee80211_ops
to receive fragmentation threshold updates.
The added functionality is very similar to the one removed by
patch f546638c3f80.
The patchset is required for wl1271 based cards. The firmware
does not support fragmentation in software and in fact clears
the MOREFRAGS flag for TX packets.
v1->v2: Merge mac80211 patches. Remove flag indicating support
for HW fragmentation. An implemented set_frag_threshold callback
indicates HW fragmentation.
Arik Nemtsov (2):
mac80211: support hardware TX fragmentation offload
wl1271: add support for HW TX fragmentation
drivers/net/wireless/wl12xx/wl1271_acx.c | 4 +-
drivers/net/wireless/wl12xx/wl1271_acx.h | 2 +-
drivers/net/wireless/wl12xx/wl1271_init.c | 2 +-
drivers/net/wireless/wl12xx/wl1271_main.c | 31 ++++++++++++++++++++++++++++-
include/net/mac80211.h | 6 +++++
net/mac80211/cfg.c | 7 ++++++
net/mac80211/driver-ops.h | 14 +++++++++++++
net/mac80211/driver-trace.h | 21 +++++++++++++++++++
net/mac80211/tx.c | 11 ++++++++-
net/mac80211/util.c | 3 ++
10 files changed, 94 insertions(+), 7 deletions(-)
On Thu, Nov 11, 2010 at 12:45:42PM +0200, Luciano Coelho wrote:
> On Mon, 2010-11-08 at 10:51 +0100, ext Arik Nemtsov wrote:
> > Indicate to mac80211 we support HW fragmentation.
> > Support updates of the fragmentation threshold via the
> > set_frag_threshold callback.
> >
> > Signed-off-by: Arik Nemtsov <[email protected]>
> > ---
>
> Acked-by: Luciano Coelho <[email protected]>
>
> John, can you apply this directly on your tree, due to the dependency on
> mac80211? There will be a merge conflict with my next pull-request, due
> to the driver renaming, but it should be very easily solvable.
>
> The other option would be for me to wait until the mac80211 part is in
> wireless-next and only then I apply it to wl12xx.
>
> Which one would you prefer?
I'll apply them, thanks.
John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.
On Wed, Nov 17, 2010 at 10:34:47AM +0200, Luciano Coelho wrote:
> Hi John,
>
> On Thu, 2010-11-11 at 17:37 +0100, ext John W. Linville wrote:
> > On Thu, Nov 11, 2010 at 12:45:42PM +0200, Luciano Coelho wrote:
> > > On Mon, 2010-11-08 at 10:51 +0100, ext Arik Nemtsov wrote:
> > > > Indicate to mac80211 we support HW fragmentation.
> > > > Support updates of the fragmentation threshold via the
> > > > set_frag_threshold callback.
> > > >
> > > > Signed-off-by: Arik Nemtsov <[email protected]>
> > > > ---
> > >
> > > Acked-by: Luciano Coelho <[email protected]>
> > >
> > > John, can you apply this directly on your tree, due to the dependency on
> > > mac80211? There will be a merge conflict with my next pull-request, due
> > > to the driver renaming, but it should be very easily solvable.
> > >
> > > The other option would be for me to wait until the mac80211 part is in
> > > wireless-next and only then I apply it to wl12xx.
> > >
> > > Which one would you prefer?
> >
> > I'll apply them, thanks.
>
> I noticed that you applied the mac80211 patch but you didn't apply the
> wl12xx part. So I have applied the latter myself now and will send it
> together with my next pull-request.
>
> Please remove this patch from your "to-be-applied-inbox". ;)
Cool, thanks -- sorry for the confusion!
John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.
Hi John,
On Thu, 2010-11-11 at 17:37 +0100, ext John W. Linville wrote:
> On Thu, Nov 11, 2010 at 12:45:42PM +0200, Luciano Coelho wrote:
> > On Mon, 2010-11-08 at 10:51 +0100, ext Arik Nemtsov wrote:
> > > Indicate to mac80211 we support HW fragmentation.
> > > Support updates of the fragmentation threshold via the
> > > set_frag_threshold callback.
> > >
> > > Signed-off-by: Arik Nemtsov <[email protected]>
> > > ---
> >
> > Acked-by: Luciano Coelho <[email protected]>
> >
> > John, can you apply this directly on your tree, due to the dependency on
> > mac80211? There will be a merge conflict with my next pull-request, due
> > to the driver renaming, but it should be very easily solvable.
> >
> > The other option would be for me to wait until the mac80211 part is in
> > wireless-next and only then I apply it to wl12xx.
> >
> > Which one would you prefer?
>
> I'll apply them, thanks.
I noticed that you applied the mac80211 patch but you didn't apply the
wl12xx part. So I have applied the latter myself now and will send it
together with my next pull-request.
Please remove this patch from your "to-be-applied-inbox". ;)
--
Cheers,
Luca.
The lower driver is notified when the fragmentation threshold changes
and upon a reconfig of the interface.
If the driver supports hardware TX fragmentation, don't fragment
packets in the stack.
Signed-off-by: Arik Nemtsov <[email protected]>
---
include/net/mac80211.h | 6 ++++++
net/mac80211/cfg.c | 7 +++++++
net/mac80211/driver-ops.h | 14 ++++++++++++++
net/mac80211/driver-trace.h | 21 +++++++++++++++++++++
net/mac80211/tx.c | 11 +++++++++--
net/mac80211/util.c | 3 +++
6 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9fdf982..6122e8a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1652,6 +1652,11 @@ enum ieee80211_ampdu_mlme_action {
* and IV16) for the given key from hardware.
* The callback must be atomic.
*
+ * @set_frag_threshold: Configuration of fragmentation threshold. Assign this
+ * if the device does fragmentation by itself; if this callback is
+ * implemented then the stack will not do fragmentation.
+ * The callback can sleep.
+ *
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
* The callback can sleep.
*
@@ -1765,6 +1770,7 @@ struct ieee80211_ops {
struct ieee80211_low_level_stats *stats);
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
u32 *iv32, u16 *iv16);
+ int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 18bd0e5..3df12f7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1299,6 +1299,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
struct ieee80211_local *local = wiphy_priv(wiphy);
int err;
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ err = drv_set_frag_threshold(local, wiphy->frag_threshold);
+
+ if (err)
+ return err;
+ }
+
if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
err = drv_set_coverage_class(local, wiphy->coverage_class);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 1698382..79019f9 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -233,6 +233,20 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local,
trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
}
+static inline int drv_set_frag_threshold(struct ieee80211_local *local,
+ u32 value)
+{
+ int ret = 0;
+
+ might_sleep();
+
+ trace_drv_set_frag_threshold(local, value);
+ if (local->ops->set_frag_threshold)
+ ret = local->ops->set_frag_threshold(&local->hw, value);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
u32 value)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6831fb1..431d655 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -531,6 +531,27 @@ TRACE_EVENT(drv_get_tkip_seq,
)
);
+TRACE_EVENT(drv_set_frag_threshold,
+ TP_PROTO(struct ieee80211_local *local, u32 value),
+
+ TP_ARGS(local, value),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, value)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->value = value;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " value:%d",
+ LOCAL_PR_ARG, __entry->value
+ )
+);
+
TRACE_EVENT(drv_set_rts_threshold,
TP_PROTO(struct ieee80211_local *local, u32 value),
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 96c5943..b392876 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1033,6 +1033,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
+ bool hw_frag;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL);
@@ -1042,6 +1043,9 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
+ /* packet is fragmented in HW if we have a non-NULL driver callback */
+ hw_frag = (tx->local->ops->set_frag_threshold != NULL);
+
/*
* for every radiotap entry that is present
* (ieee80211_radiotap_iterator_next returns -ENOENT when no more
@@ -1078,7 +1082,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
+ if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) &&
+ !hw_frag)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
@@ -1181,8 +1186,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
/*
* Set this flag (used below to indicate "automatic fragmentation"),
* it will be cleared/left by radiotap as desired.
+ * Only valid when fragmentation is done by the stack.
*/
- tx->flags |= IEEE80211_TX_FRAGMENTED;
+ if (!local->ops->set_frag_threshold)
+ tx->flags |= IEEE80211_TX_FRAGMENTED;
/* process and remove the injection radiotap header */
if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0b6fc92..e486286 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1152,6 +1152,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
mutex_unlock(&local->sta_mtx);
+ /* setup fragmentation threshold */
+ drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
+
/* setup RTS threshold */
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
--
1.7.1
On Mon, 2010-11-08 at 10:51 +0100, ext Arik Nemtsov wrote:
> Indicate to mac80211 we support HW fragmentation.
> Support updates of the fragmentation threshold via the
> set_frag_threshold callback.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
Acked-by: Luciano Coelho <[email protected]>
John, can you apply this directly on your tree, due to the dependency on
mac80211? There will be a merge conflict with my next pull-request, due
to the driver renaming, but it should be very easily solvable.
The other option would be for me to wait until the mac80211 part is in
wireless-next and only then I apply it to wl12xx.
Which one would you prefer?
--
Cheers,
Luca.
Indicate to mac80211 we support HW fragmentation.
Support updates of the fragmentation threshold via the
set_frag_threshold callback.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_acx.c | 4 +-
drivers/net/wireless/wl12xx/wl1271_acx.h | 2 +-
drivers/net/wireless/wl12xx/wl1271_init.c | 2 +-
drivers/net/wireless/wl12xx/wl1271_main.c | 31 ++++++++++++++++++++++++++++-
4 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index bd7f95f..bbaf066 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -862,7 +862,7 @@ out:
return ret;
}
-int wl1271_acx_frag_threshold(struct wl1271 *wl)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;
@@ -876,7 +876,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl)
goto out;
}
- acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold);
+ acx->frag_threshold = cpu_to_le16(frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index b7c4908..5963dea 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -1161,7 +1161,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
-int wl1271_acx_frag_threshold(struct wl1271 *wl);
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index 8044bba..3ba7acd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -290,7 +290,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl);
+ ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0)
goto out_free_memmap;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index f5b1d19..a1f2786 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -404,7 +404,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl);
+ ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0)
goto out_free_memmap;
@@ -1724,6 +1724,34 @@ out:
return ret;
}
+static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret = 0;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_frag_threshold(wl, (u16)value);
+ if (ret < 0)
+ wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct wl1271 *wl = hw->priv;
@@ -2406,6 +2434,7 @@ static const struct ieee80211_ops wl1271_ops = {
.set_key = wl1271_op_set_key,
.hw_scan = wl1271_op_hw_scan,
.bss_info_changed = wl1271_op_bss_info_changed,
+ .set_frag_threshold = wl1271_op_set_frag_threshold,
.set_rts_threshold = wl1271_op_set_rts_threshold,
.conf_tx = wl1271_op_conf_tx,
.get_tsf = wl1271_op_get_tsf,
--
1.7.1
On Mon, 2010-11-08 at 10:51 +0100, ext Arik Nemtsov wrote:
> Indicate to mac80211 we support HW fragmentation.
> Support updates of the fragmentation threshold via the
> set_frag_threshold callback.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
Applied to the wl12xx tree. Thanks!
--
Cheers,
Luca.