diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-09-05 20:56:23 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-11 15:53:32 -0400 |
commit | cc6de669f648bc8820f1cf93ee311eb4eaab9fc5 (patch) | |
tree | 574b6b0b848ae045cfcae6fc8cab6c29a5c30812 | |
parent | 78d57eb2b666617dd75aac0f1a420238004a98b3 (diff) |
p54: add lots of useful rx/tx statistics
The firmware can provide lots of useful statistics about noise floor,
mac time and lots of numbers about successful transfers and dropped
frames.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/p54/p54.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 92 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.h | 13 |
3 files changed, 105 insertions, 5 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ea72b65428ec..370202f6de2c 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h | |||
@@ -91,6 +91,11 @@ struct p54_common { | |||
91 | u32 tsf_low32; | 91 | u32 tsf_low32; |
92 | u32 tsf_high32; | 92 | u32 tsf_high32; |
93 | struct ieee80211_tx_queue_stats tx_stats[8]; | 93 | struct ieee80211_tx_queue_stats tx_stats[8]; |
94 | struct ieee80211_low_level_stats stats; | ||
95 | struct timer_list stats_timer; | ||
96 | struct completion stats_comp; | ||
97 | void *cached_stats; | ||
98 | int noise; | ||
94 | void *eeprom; | 99 | void *eeprom; |
95 | struct completion eeprom_comp; | 100 | struct completion eeprom_comp; |
96 | }; | 101 | }; |
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 300f97b1bfe4..670d7ad4120b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -424,6 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | |||
424 | } | 424 | } |
425 | EXPORT_SYMBOL_GPL(p54_parse_eeprom); | 425 | EXPORT_SYMBOL_GPL(p54_parse_eeprom); |
426 | 426 | ||
427 | static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) | ||
428 | { | ||
429 | /* TODO: get the rssi_add & rssi_mul data from the eeprom */ | ||
430 | return ((rssi * 0x83) / 64 - 400) / 4; | ||
431 | } | ||
432 | |||
427 | static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | 433 | static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) |
428 | { | 434 | { |
429 | struct p54_common *priv = dev->priv; | 435 | struct p54_common *priv = dev->priv; |
@@ -440,7 +446,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
440 | return 0; | 446 | return 0; |
441 | } | 447 | } |
442 | 448 | ||
443 | rx_status.signal = hdr->rssi; | 449 | rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); |
450 | rx_status.noise = priv->noise; | ||
444 | /* XX correct? */ | 451 | /* XX correct? */ |
445 | rx_status.qual = (100 * hdr->rssi) / 127; | 452 | rx_status.qual = (100 * hdr->rssi) / 127; |
446 | rx_status.rate_idx = hdr->rate & 0xf; | 453 | rx_status.rate_idx = hdr->rate & 0xf; |
@@ -526,7 +533,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
526 | info->status.excessive_retries = 1; | 533 | info->status.excessive_retries = 1; |
527 | } | 534 | } |
528 | info->status.retry_count = payload->retries - 1; | 535 | info->status.retry_count = payload->retries - 1; |
529 | info->status.ack_signal = le16_to_cpu(payload->ack_rssi); | 536 | info->status.ack_signal = p54_rssi_to_dbm(dev, |
537 | le16_to_cpu(payload->ack_rssi)); | ||
530 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); | 538 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); |
531 | ieee80211_tx_status_irqsafe(dev, entry); | 539 | ieee80211_tx_status_irqsafe(dev, entry); |
532 | goto out; | 540 | goto out; |
@@ -557,6 +565,27 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, | |||
557 | complete(&priv->eeprom_comp); | 565 | complete(&priv->eeprom_comp); |
558 | } | 566 | } |
559 | 567 | ||
568 | static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) | ||
569 | { | ||
570 | struct p54_common *priv = dev->priv; | ||
571 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; | ||
572 | struct p54_statistics *stats = (struct p54_statistics *) hdr->data; | ||
573 | u32 tsf32 = le32_to_cpu(stats->tsf32); | ||
574 | |||
575 | if (tsf32 < priv->tsf_low32) | ||
576 | priv->tsf_high32++; | ||
577 | priv->tsf_low32 = tsf32; | ||
578 | |||
579 | priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); | ||
580 | priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); | ||
581 | priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); | ||
582 | |||
583 | priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); | ||
584 | complete(&priv->stats_comp); | ||
585 | |||
586 | mod_timer(&priv->stats_timer, jiffies + 5 * HZ); | ||
587 | } | ||
588 | |||
560 | static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) | 589 | static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) |
561 | { | 590 | { |
562 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; | 591 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; |
@@ -567,6 +596,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
567 | break; | 596 | break; |
568 | case P54_CONTROL_TYPE_BBP: | 597 | case P54_CONTROL_TYPE_BBP: |
569 | break; | 598 | break; |
599 | case P54_CONTROL_TYPE_STAT_READBACK: | ||
600 | p54_rx_stats(dev, skb); | ||
601 | break; | ||
570 | case P54_CONTROL_TYPE_EEPROM_READBACK: | 602 | case P54_CONTROL_TYPE_EEPROM_READBACK: |
571 | p54_rx_eeprom_readback(dev, skb); | 603 | p54_rx_eeprom_readback(dev, skb); |
572 | break; | 604 | break; |
@@ -1036,12 +1068,25 @@ static int p54_start(struct ieee80211_hw *dev) | |||
1036 | return -ENOMEM; | 1068 | return -ENOMEM; |
1037 | } | 1069 | } |
1038 | 1070 | ||
1071 | if (!priv->cached_stats) { | ||
1072 | priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + | ||
1073 | priv->tx_hdr_len + sizeof(struct p54_control_hdr), | ||
1074 | GFP_KERNEL); | ||
1075 | |||
1076 | if (!priv->cached_stats) { | ||
1077 | kfree(priv->cached_vdcf); | ||
1078 | priv->cached_vdcf = NULL; | ||
1079 | return -ENOMEM; | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1039 | err = priv->open(dev); | 1083 | err = priv->open(dev); |
1040 | if (!err) | 1084 | if (!err) |
1041 | priv->mode = IEEE80211_IF_TYPE_MNTR; | 1085 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
1042 | 1086 | ||
1043 | p54_init_vdcf(dev); | 1087 | p54_init_vdcf(dev); |
1044 | 1088 | ||
1089 | mod_timer(&priv->stats_timer, jiffies + HZ); | ||
1045 | return err; | 1090 | return err; |
1046 | } | 1091 | } |
1047 | 1092 | ||
@@ -1049,6 +1094,8 @@ static void p54_stop(struct ieee80211_hw *dev) | |||
1049 | { | 1094 | { |
1050 | struct p54_common *priv = dev->priv; | 1095 | struct p54_common *priv = dev->priv; |
1051 | struct sk_buff *skb; | 1096 | struct sk_buff *skb; |
1097 | |||
1098 | del_timer(&priv->stats_timer); | ||
1052 | while ((skb = skb_dequeue(&priv->tx_queue))) | 1099 | while ((skb = skb_dequeue(&priv->tx_queue))) |
1053 | kfree_skb(skb); | 1100 | kfree_skb(skb); |
1054 | priv->stop(dev); | 1101 | priv->stop(dev); |
@@ -1177,10 +1224,40 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, | |||
1177 | return 0; | 1224 | return 0; |
1178 | } | 1225 | } |
1179 | 1226 | ||
1227 | static void p54_statistics_timer(unsigned long data) | ||
1228 | { | ||
1229 | struct ieee80211_hw *dev = (struct ieee80211_hw *) data; | ||
1230 | struct p54_common *priv = dev->priv; | ||
1231 | struct p54_control_hdr *hdr; | ||
1232 | struct p54_statistics *stats; | ||
1233 | |||
1234 | BUG_ON(!priv->cached_stats); | ||
1235 | |||
1236 | hdr = (void *)priv->cached_stats + priv->tx_hdr_len; | ||
1237 | hdr->magic1 = cpu_to_le16(0x8000); | ||
1238 | hdr->len = cpu_to_le16(sizeof(*stats)); | ||
1239 | hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); | ||
1240 | p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); | ||
1241 | |||
1242 | priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); | ||
1243 | } | ||
1244 | |||
1180 | static int p54_get_stats(struct ieee80211_hw *dev, | 1245 | static int p54_get_stats(struct ieee80211_hw *dev, |
1181 | struct ieee80211_low_level_stats *stats) | 1246 | struct ieee80211_low_level_stats *stats) |
1182 | { | 1247 | { |
1183 | /* TODO */ | 1248 | struct p54_common *priv = dev->priv; |
1249 | |||
1250 | del_timer(&priv->stats_timer); | ||
1251 | p54_statistics_timer((unsigned long)dev); | ||
1252 | |||
1253 | if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { | ||
1254 | printk(KERN_ERR "%s: device does not respond!\n", | ||
1255 | wiphy_name(dev->wiphy)); | ||
1256 | return -EBUSY; | ||
1257 | } | ||
1258 | |||
1259 | memcpy(stats, &priv->stats, sizeof(*stats)); | ||
1260 | |||
1184 | return 0; | 1261 | return 0; |
1185 | } | 1262 | } |
1186 | 1263 | ||
@@ -1222,12 +1299,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
1222 | skb_queue_head_init(&priv->tx_queue); | 1299 | skb_queue_head_init(&priv->tx_queue); |
1223 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ | 1300 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ |
1224 | IEEE80211_HW_RX_INCLUDES_FCS | | 1301 | IEEE80211_HW_RX_INCLUDES_FCS | |
1225 | IEEE80211_HW_SIGNAL_UNSPEC; | 1302 | IEEE80211_HW_SIGNAL_DBM | |
1303 | IEEE80211_HW_NOISE_DBM; | ||
1226 | 1304 | ||
1227 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 1305 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
1228 | 1306 | ||
1229 | dev->channel_change_time = 1000; /* TODO: find actual value */ | 1307 | dev->channel_change_time = 1000; /* TODO: find actual value */ |
1230 | dev->max_signal = 127; | ||
1231 | 1308 | ||
1232 | priv->tx_stats[0].limit = 1; | 1309 | priv->tx_stats[0].limit = 1; |
1233 | priv->tx_stats[1].limit = 1; | 1310 | priv->tx_stats[1].limit = 1; |
@@ -1235,11 +1312,15 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
1235 | priv->tx_stats[3].limit = 1; | 1312 | priv->tx_stats[3].limit = 1; |
1236 | priv->tx_stats[4].limit = 5; | 1313 | priv->tx_stats[4].limit = 5; |
1237 | dev->queues = 1; | 1314 | dev->queues = 1; |
1315 | priv->noise = -94; | ||
1238 | dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + | 1316 | dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + |
1239 | sizeof(struct p54_tx_control_allocdata); | 1317 | sizeof(struct p54_tx_control_allocdata); |
1240 | 1318 | ||
1241 | mutex_init(&priv->conf_mutex); | 1319 | mutex_init(&priv->conf_mutex); |
1242 | init_completion(&priv->eeprom_comp); | 1320 | init_completion(&priv->eeprom_comp); |
1321 | init_completion(&priv->stats_comp); | ||
1322 | setup_timer(&priv->stats_timer, p54_statistics_timer, | ||
1323 | (unsigned long)dev); | ||
1243 | 1324 | ||
1244 | return dev; | 1325 | return dev; |
1245 | } | 1326 | } |
@@ -1248,6 +1329,7 @@ EXPORT_SYMBOL_GPL(p54_init_common); | |||
1248 | void p54_free_common(struct ieee80211_hw *dev) | 1329 | void p54_free_common(struct ieee80211_hw *dev) |
1249 | { | 1330 | { |
1250 | struct p54_common *priv = dev->priv; | 1331 | struct p54_common *priv = dev->priv; |
1332 | kfree(priv->cached_stats); | ||
1251 | kfree(priv->iq_autocal); | 1333 | kfree(priv->iq_autocal); |
1252 | kfree(priv->output_limit); | 1334 | kfree(priv->output_limit); |
1253 | kfree(priv->curve_data); | 1335 | kfree(priv->curve_data); |
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 976cbf9689b5..9e544ce59c3c 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h | |||
@@ -301,4 +301,17 @@ struct p54_tx_control_vdcf { | |||
301 | __le16 frameburst; | 301 | __le16 frameburst; |
302 | } __attribute__ ((packed)); | 302 | } __attribute__ ((packed)); |
303 | 303 | ||
304 | struct p54_statistics { | ||
305 | __le32 rx_success; | ||
306 | __le32 rx_bad_fcs; | ||
307 | __le32 rx_abort; | ||
308 | __le32 rx_abort_phy; | ||
309 | __le32 rts_success; | ||
310 | __le32 rts_fail; | ||
311 | __le32 tsf32; | ||
312 | __le32 airtime; | ||
313 | __le32 noise; | ||
314 | __le32 unkn[10]; /* CCE / CCA / RADAR */ | ||
315 | } __attribute__ ((packed)); | ||
316 | |||
304 | #endif /* P54COMMON_H */ | 317 | #endif /* P54COMMON_H */ |