diff options
author | Antonio Quartulli <antonio@open-mesh.com> | 2014-05-19 15:53:20 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-05-21 03:15:16 -0400 |
commit | cca674d47e59665630f3005291b61bb883015fc5 (patch) | |
tree | bd83cc2c0b576cdc7adae72ca7c170c1e1648fa8 | |
parent | 867d849fc844623a88ec7b380442952b5ffe5e68 (diff) |
mac80211: export the expected throughput
Add get_expected_throughput() API to mac80211 so that each
driver can implement its own version based on the RC
algorithm they are using (might be using an HW RC algo).
The API returns a value expressed in Kbps.
Also, add the new get_expected_throughput() member
to the rate_control_ops structure in order to be
able to query the RC algorithm (this patch provides an
implementation of this API for both minstrel and
minstrel_ht).
The related member in the station_info object is now
filled accordingly when dumping a station.
Cc: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/mac80211.h | 7 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 13 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 13 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 12 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 17 | ||||
-rw-r--r-- | net/mac80211/trace.h | 32 |
6 files changed, 94 insertions, 0 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a34f26a4ed18..2c78997bc48d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -2769,6 +2769,10 @@ enum ieee80211_roc_type { | |||
2769 | * information in bss_conf is set up and the beacon can be retrieved. A | 2769 | * information in bss_conf is set up and the beacon can be retrieved. A |
2770 | * channel context is bound before this is called. | 2770 | * channel context is bound before this is called. |
2771 | * @leave_ibss: Leave the IBSS again. | 2771 | * @leave_ibss: Leave the IBSS again. |
2772 | * | ||
2773 | * @get_expected_throughput: extract the expected throughput towards the | ||
2774 | * specified station. The returned value is expressed in Kbps. It returns 0 | ||
2775 | * if the RC algorithm does not have proper data to provide. | ||
2772 | */ | 2776 | */ |
2773 | struct ieee80211_ops { | 2777 | struct ieee80211_ops { |
2774 | void (*tx)(struct ieee80211_hw *hw, | 2778 | void (*tx)(struct ieee80211_hw *hw, |
@@ -2962,6 +2966,7 @@ struct ieee80211_ops { | |||
2962 | 2966 | ||
2963 | int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 2967 | int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
2964 | void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 2968 | void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
2969 | u32 (*get_expected_throughput)(struct ieee80211_sta *sta); | ||
2965 | }; | 2970 | }; |
2966 | 2971 | ||
2967 | /** | 2972 | /** |
@@ -4535,6 +4540,8 @@ struct rate_control_ops { | |||
4535 | void (*add_sta_debugfs)(void *priv, void *priv_sta, | 4540 | void (*add_sta_debugfs)(void *priv, void *priv_sta, |
4536 | struct dentry *dir); | 4541 | struct dentry *dir); |
4537 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); | 4542 | void (*remove_sta_debugfs)(void *priv, void *priv_sta); |
4543 | |||
4544 | u32 (*get_expected_throughput)(void *priv_sta); | ||
4538 | }; | 4545 | }; |
4539 | 4546 | ||
4540 | static inline int rate_supported(struct ieee80211_sta *sta, | 4547 | static inline int rate_supported(struct ieee80211_sta *sta, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ac45304590d8..d7513a503be1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -472,8 +472,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
472 | { | 472 | { |
473 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 473 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
474 | struct ieee80211_local *local = sdata->local; | 474 | struct ieee80211_local *local = sdata->local; |
475 | struct rate_control_ref *ref = local->rate_ctrl; | ||
475 | struct timespec uptime; | 476 | struct timespec uptime; |
476 | u64 packets = 0; | 477 | u64 packets = 0; |
478 | u32 thr = 0; | ||
477 | int i, ac; | 479 | int i, ac; |
478 | 480 | ||
479 | sinfo->generation = sdata->local->sta_generation; | 481 | sinfo->generation = sdata->local->sta_generation; |
@@ -587,6 +589,17 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
587 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | 589 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
588 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | 590 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) |
589 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | 591 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); |
592 | |||
593 | /* check if the driver has a SW RC implementation */ | ||
594 | if (ref && ref->ops->get_expected_throughput) | ||
595 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
596 | else | ||
597 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
598 | |||
599 | if (thr != 0) { | ||
600 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
601 | sinfo->expected_throughput = thr; | ||
602 | } | ||
590 | } | 603 | } |
591 | 604 | ||
592 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | 605 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index df1d50291344..696ef78b1fb7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -1156,4 +1156,17 @@ static inline void drv_leave_ibss(struct ieee80211_local *local, | |||
1156 | trace_drv_return_void(local); | 1156 | trace_drv_return_void(local); |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | static inline u32 drv_get_expected_throughput(struct ieee80211_local *local, | ||
1160 | struct ieee80211_sta *sta) | ||
1161 | { | ||
1162 | u32 ret = 0; | ||
1163 | |||
1164 | trace_drv_get_expected_throughput(sta); | ||
1165 | if (local->ops->get_expected_throughput) | ||
1166 | ret = local->ops->get_expected_throughput(sta); | ||
1167 | trace_drv_return_u32(local, ret); | ||
1168 | |||
1169 | return ret; | ||
1170 | } | ||
1171 | |||
1159 | #endif /* __MAC80211_DRIVER_OPS */ | 1172 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 26fd94fa0aed..1c1469c36dca 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -657,6 +657,17 @@ minstrel_free(void *priv) | |||
657 | kfree(priv); | 657 | kfree(priv); |
658 | } | 658 | } |
659 | 659 | ||
660 | static u32 minstrel_get_expected_throughput(void *priv_sta) | ||
661 | { | ||
662 | struct minstrel_sta_info *mi = priv_sta; | ||
663 | int idx = mi->max_tp_rate[0]; | ||
664 | |||
665 | /* convert pkt per sec in kbps (1200 is the average pkt size used for | ||
666 | * computing cur_tp | ||
667 | */ | ||
668 | return MINSTREL_TRUNC(mi->r[idx].cur_tp) * 1200 * 8 / 1024; | ||
669 | } | ||
670 | |||
660 | const struct rate_control_ops mac80211_minstrel = { | 671 | const struct rate_control_ops mac80211_minstrel = { |
661 | .name = "minstrel", | 672 | .name = "minstrel", |
662 | .tx_status = minstrel_tx_status, | 673 | .tx_status = minstrel_tx_status, |
@@ -670,6 +681,7 @@ const struct rate_control_ops mac80211_minstrel = { | |||
670 | .add_sta_debugfs = minstrel_add_sta_debugfs, | 681 | .add_sta_debugfs = minstrel_add_sta_debugfs, |
671 | .remove_sta_debugfs = minstrel_remove_sta_debugfs, | 682 | .remove_sta_debugfs = minstrel_remove_sta_debugfs, |
672 | #endif | 683 | #endif |
684 | .get_expected_throughput = minstrel_get_expected_throughput, | ||
673 | }; | 685 | }; |
674 | 686 | ||
675 | int __init | 687 | int __init |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 4e916ad51a20..85c1e74b7714 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -1032,6 +1032,22 @@ minstrel_ht_free(void *priv) | |||
1032 | mac80211_minstrel.free(priv); | 1032 | mac80211_minstrel.free(priv); |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | static u32 minstrel_ht_get_expected_throughput(void *priv_sta) | ||
1036 | { | ||
1037 | struct minstrel_ht_sta_priv *msp = priv_sta; | ||
1038 | struct minstrel_ht_sta *mi = &msp->ht; | ||
1039 | int i, j; | ||
1040 | |||
1041 | if (!msp->is_ht) | ||
1042 | return mac80211_minstrel.get_expected_throughput(priv_sta); | ||
1043 | |||
1044 | i = mi->max_tp_rate / MCS_GROUP_RATES; | ||
1045 | j = mi->max_tp_rate % MCS_GROUP_RATES; | ||
1046 | |||
1047 | /* convert cur_tp from pkt per second in kbps */ | ||
1048 | return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024; | ||
1049 | } | ||
1050 | |||
1035 | static const struct rate_control_ops mac80211_minstrel_ht = { | 1051 | static const struct rate_control_ops mac80211_minstrel_ht = { |
1036 | .name = "minstrel_ht", | 1052 | .name = "minstrel_ht", |
1037 | .tx_status = minstrel_ht_tx_status, | 1053 | .tx_status = minstrel_ht_tx_status, |
@@ -1046,6 +1062,7 @@ static const struct rate_control_ops mac80211_minstrel_ht = { | |||
1046 | .add_sta_debugfs = minstrel_ht_add_sta_debugfs, | 1062 | .add_sta_debugfs = minstrel_ht_add_sta_debugfs, |
1047 | .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, | 1063 | .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, |
1048 | #endif | 1064 | #endif |
1065 | .get_expected_throughput = minstrel_ht_get_expected_throughput, | ||
1049 | }; | 1066 | }; |
1050 | 1067 | ||
1051 | 1068 | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index a0b0aea76525..942f64b8ce0e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -184,6 +184,20 @@ TRACE_EVENT(drv_return_bool, | |||
184 | "true" : "false") | 184 | "true" : "false") |
185 | ); | 185 | ); |
186 | 186 | ||
187 | TRACE_EVENT(drv_return_u32, | ||
188 | TP_PROTO(struct ieee80211_local *local, u32 ret), | ||
189 | TP_ARGS(local, ret), | ||
190 | TP_STRUCT__entry( | ||
191 | LOCAL_ENTRY | ||
192 | __field(u32, ret) | ||
193 | ), | ||
194 | TP_fast_assign( | ||
195 | LOCAL_ASSIGN; | ||
196 | __entry->ret = ret; | ||
197 | ), | ||
198 | TP_printk(LOCAL_PR_FMT " - %u", LOCAL_PR_ARG, __entry->ret) | ||
199 | ); | ||
200 | |||
187 | TRACE_EVENT(drv_return_u64, | 201 | TRACE_EVENT(drv_return_u64, |
188 | TP_PROTO(struct ieee80211_local *local, u64 ret), | 202 | TP_PROTO(struct ieee80211_local *local, u64 ret), |
189 | TP_ARGS(local, ret), | 203 | TP_ARGS(local, ret), |
@@ -1499,6 +1513,24 @@ DEFINE_EVENT(local_sdata_evt, drv_leave_ibss, | |||
1499 | TP_ARGS(local, sdata) | 1513 | TP_ARGS(local, sdata) |
1500 | ); | 1514 | ); |
1501 | 1515 | ||
1516 | TRACE_EVENT(drv_get_expected_throughput, | ||
1517 | TP_PROTO(struct ieee80211_sta *sta), | ||
1518 | |||
1519 | TP_ARGS(sta), | ||
1520 | |||
1521 | TP_STRUCT__entry( | ||
1522 | STA_ENTRY | ||
1523 | ), | ||
1524 | |||
1525 | TP_fast_assign( | ||
1526 | STA_ASSIGN; | ||
1527 | ), | ||
1528 | |||
1529 | TP_printk( | ||
1530 | STA_PR_FMT, STA_PR_ARG | ||
1531 | ) | ||
1532 | ); | ||
1533 | |||
1502 | /* | 1534 | /* |
1503 | * Tracing for API calls that drivers call. | 1535 | * Tracing for API calls that drivers call. |
1504 | */ | 1536 | */ |