diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-12-13 08:14:20 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-19 15:23:11 -0500 |
commit | 54fdb040b4760d5b2994d15c1371e297679420e9 (patch) | |
tree | e287e40aa879482c9509cf4e3abe30af05efe4d6 /drivers/net/wireless | |
parent | d5e490362feb648048ef20db9b0b2531d5425775 (diff) |
p54: move statistic timer update routine into a workqueue
This patch moves a good chunk of code from the former statistic update
timer routine into a workqueue, which is kindly provided by mac80211.
Also as a nice side-effect we can lay the foundation for other
essential housekeeping features we want to do in the future.
e.g:
- drain the (clogged) tx_queue.
- initiate bursts.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/p54/p54.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 104 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.h | 5 |
3 files changed, 68 insertions, 46 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index d2dbb9e15d97..23b80ef4d015 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h | |||
@@ -71,6 +71,7 @@ struct p54_edcf_queue_param { | |||
71 | #define FW_LM20 0x4c4d3230 | 71 | #define FW_LM20 0x4c4d3230 |
72 | 72 | ||
73 | struct p54_common { | 73 | struct p54_common { |
74 | struct ieee80211_hw *hw; | ||
74 | u32 rx_start; | 75 | u32 rx_start; |
75 | u32 rx_end; | 76 | u32 rx_end; |
76 | struct sk_buff_head tx_queue; | 77 | struct sk_buff_head tx_queue; |
@@ -106,9 +107,7 @@ struct p54_common { | |||
106 | struct ieee80211_tx_queue_stats tx_stats[8]; | 107 | struct ieee80211_tx_queue_stats tx_stats[8]; |
107 | struct p54_edcf_queue_param qos_params[8]; | 108 | struct p54_edcf_queue_param qos_params[8]; |
108 | struct ieee80211_low_level_stats stats; | 109 | struct ieee80211_low_level_stats stats; |
109 | struct timer_list stats_timer; | 110 | struct delayed_work work; |
110 | struct completion stats_comp; | ||
111 | struct sk_buff *cached_stats; | ||
112 | struct sk_buff *cached_beacon; | 111 | struct sk_buff *cached_beacon; |
113 | int noise; | 112 | int noise; |
114 | void *eeprom; | 113 | void *eeprom; |
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index a4e99b02af02..36310f881874 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -589,6 +589,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
589 | 589 | ||
590 | ieee80211_rx_irqsafe(dev, skb, &rx_status); | 590 | ieee80211_rx_irqsafe(dev, skb, &rx_status); |
591 | 591 | ||
592 | queue_delayed_work(dev->workqueue, &priv->work, | ||
593 | msecs_to_jiffies(P54_STATISTICS_UPDATE)); | ||
594 | |||
592 | return -1; | 595 | return -1; |
593 | } | 596 | } |
594 | 597 | ||
@@ -652,6 +655,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
652 | } | 655 | } |
653 | EXPORT_SYMBOL_GPL(p54_free_skb); | 656 | EXPORT_SYMBOL_GPL(p54_free_skb); |
654 | 657 | ||
658 | static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, | ||
659 | __le32 req_id) | ||
660 | { | ||
661 | struct p54_common *priv = dev->priv; | ||
662 | struct sk_buff *entry = priv->tx_queue.next; | ||
663 | unsigned long flags; | ||
664 | |||
665 | spin_lock_irqsave(&priv->tx_queue.lock, flags); | ||
666 | while (entry != (struct sk_buff *)&priv->tx_queue) { | ||
667 | struct p54_hdr *hdr = (struct p54_hdr *) entry->data; | ||
668 | |||
669 | if (hdr->req_id == req_id) { | ||
670 | spin_unlock_irqrestore(&priv->tx_queue.lock, flags); | ||
671 | return entry; | ||
672 | } | ||
673 | entry = entry->next; | ||
674 | } | ||
675 | spin_unlock_irqrestore(&priv->tx_queue.lock, flags); | ||
676 | return NULL; | ||
677 | } | ||
678 | |||
655 | static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | 679 | static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) |
656 | { | 680 | { |
657 | struct p54_common *priv = dev->priv; | 681 | struct p54_common *priv = dev->priv; |
@@ -775,8 +799,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
775 | struct p54_common *priv = dev->priv; | 799 | struct p54_common *priv = dev->priv; |
776 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; | 800 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; |
777 | struct p54_statistics *stats = (struct p54_statistics *) hdr->data; | 801 | struct p54_statistics *stats = (struct p54_statistics *) hdr->data; |
778 | u32 tsf32 = le32_to_cpu(stats->tsf32); | 802 | u32 tsf32; |
803 | |||
804 | if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) | ||
805 | return ; | ||
779 | 806 | ||
807 | tsf32 = le32_to_cpu(stats->tsf32); | ||
780 | if (tsf32 < priv->tsf_low32) | 808 | if (tsf32 < priv->tsf_low32) |
781 | priv->tsf_high32++; | 809 | priv->tsf_high32++; |
782 | priv->tsf_low32 = tsf32; | 810 | priv->tsf_low32 = tsf32; |
@@ -786,9 +814,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
786 | priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); | 814 | priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); |
787 | 815 | ||
788 | priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); | 816 | priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); |
789 | complete(&priv->stats_comp); | ||
790 | 817 | ||
791 | mod_timer(&priv->stats_timer, jiffies + 5 * HZ); | 818 | p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); |
792 | } | 819 | } |
793 | 820 | ||
794 | static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) | 821 | static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) |
@@ -897,6 +924,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, | |||
897 | * have a few spare slots for control frames left. | 924 | * have a few spare slots for control frames left. |
898 | */ | 925 | */ |
899 | ieee80211_stop_queues(dev); | 926 | ieee80211_stop_queues(dev); |
927 | queue_delayed_work(dev->workqueue, &priv->work, | ||
928 | msecs_to_jiffies(P54_TX_TIMEOUT)); | ||
900 | 929 | ||
901 | if (unlikely(left == 32)) { | 930 | if (unlikely(left == 32)) { |
902 | /* | 931 | /* |
@@ -1354,6 +1383,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
1354 | if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) | 1383 | if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) |
1355 | goto err; | 1384 | goto err; |
1356 | priv->tx(dev, skb, 0); | 1385 | priv->tx(dev, skb, 0); |
1386 | |||
1387 | queue_delayed_work(dev->workqueue, &priv->work, | ||
1388 | msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); | ||
1389 | |||
1357 | return 0; | 1390 | return 0; |
1358 | 1391 | ||
1359 | err: | 1392 | err: |
@@ -1579,20 +1612,6 @@ static int p54_set_edcf(struct ieee80211_hw *dev) | |||
1579 | return 0; | 1612 | return 0; |
1580 | } | 1613 | } |
1581 | 1614 | ||
1582 | static int p54_init_stats(struct ieee80211_hw *dev) | ||
1583 | { | ||
1584 | struct p54_common *priv = dev->priv; | ||
1585 | |||
1586 | priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, | ||
1587 | sizeof(struct p54_hdr) + sizeof(struct p54_statistics), | ||
1588 | P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); | ||
1589 | if (!priv->cached_stats) | ||
1590 | return -ENOMEM; | ||
1591 | |||
1592 | mod_timer(&priv->stats_timer, jiffies + HZ); | ||
1593 | return 0; | ||
1594 | } | ||
1595 | |||
1596 | static int p54_beacon_tim(struct sk_buff *skb) | 1615 | static int p54_beacon_tim(struct sk_buff *skb) |
1597 | { | 1616 | { |
1598 | /* | 1617 | /* |
@@ -1686,9 +1705,6 @@ static int p54_start(struct ieee80211_hw *dev) | |||
1686 | err = p54_set_edcf(dev); | 1705 | err = p54_set_edcf(dev); |
1687 | if (err) | 1706 | if (err) |
1688 | goto out; | 1707 | goto out; |
1689 | err = p54_init_stats(dev); | ||
1690 | if (err) | ||
1691 | goto out; | ||
1692 | 1708 | ||
1693 | memset(priv->bssid, ~0, ETH_ALEN); | 1709 | memset(priv->bssid, ~0, ETH_ALEN); |
1694 | priv->mode = NL80211_IFTYPE_MONITOR; | 1710 | priv->mode = NL80211_IFTYPE_MONITOR; |
@@ -1698,6 +1714,8 @@ static int p54_start(struct ieee80211_hw *dev) | |||
1698 | goto out; | 1714 | goto out; |
1699 | } | 1715 | } |
1700 | 1716 | ||
1717 | queue_delayed_work(dev->workqueue, &priv->work, 0); | ||
1718 | |||
1701 | out: | 1719 | out: |
1702 | mutex_unlock(&priv->conf_mutex); | 1720 | mutex_unlock(&priv->conf_mutex); |
1703 | return err; | 1721 | return err; |
@@ -1710,9 +1728,7 @@ static void p54_stop(struct ieee80211_hw *dev) | |||
1710 | 1728 | ||
1711 | mutex_lock(&priv->conf_mutex); | 1729 | mutex_lock(&priv->conf_mutex); |
1712 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | 1730 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; |
1713 | del_timer(&priv->stats_timer); | 1731 | cancel_delayed_work_sync(&priv->work); |
1714 | p54_free_skb(dev, priv->cached_stats); | ||
1715 | priv->cached_stats = NULL; | ||
1716 | if (priv->cached_beacon) | 1732 | if (priv->cached_beacon) |
1717 | p54_tx_cancel(dev, priv->cached_beacon); | 1733 | p54_tx_cancel(dev, priv->cached_beacon); |
1718 | 1734 | ||
@@ -1889,14 +1905,29 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) | |||
1889 | return 0; | 1905 | return 0; |
1890 | } | 1906 | } |
1891 | 1907 | ||
1892 | static void p54_statistics_timer(unsigned long data) | 1908 | static void p54_work(struct work_struct *work) |
1893 | { | 1909 | { |
1894 | struct ieee80211_hw *dev = (struct ieee80211_hw *) data; | 1910 | struct p54_common *priv = container_of(work, struct p54_common, |
1895 | struct p54_common *priv = dev->priv; | 1911 | work.work); |
1912 | struct ieee80211_hw *dev = priv->hw; | ||
1913 | struct sk_buff *skb; | ||
1914 | |||
1915 | if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) | ||
1916 | return ; | ||
1917 | |||
1918 | /* | ||
1919 | * TODO: walk through tx_queue and do the following tasks | ||
1920 | * 1. initiate bursts. | ||
1921 | * 2. cancel stuck frames / reset the device if necessary. | ||
1922 | */ | ||
1896 | 1923 | ||
1897 | BUG_ON(!priv->cached_stats); | 1924 | skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) + |
1925 | sizeof(struct p54_statistics), | ||
1926 | P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); | ||
1927 | if (!skb) | ||
1928 | return ; | ||
1898 | 1929 | ||
1899 | priv->tx(dev, priv->cached_stats, 0); | 1930 | priv->tx(dev, skb, 0); |
1900 | } | 1931 | } |
1901 | 1932 | ||
1902 | static int p54_get_stats(struct ieee80211_hw *dev, | 1933 | static int p54_get_stats(struct ieee80211_hw *dev, |
@@ -1904,17 +1935,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, | |||
1904 | { | 1935 | { |
1905 | struct p54_common *priv = dev->priv; | 1936 | struct p54_common *priv = dev->priv; |
1906 | 1937 | ||
1907 | del_timer(&priv->stats_timer); | ||
1908 | p54_statistics_timer((unsigned long)dev); | ||
1909 | |||
1910 | if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { | ||
1911 | printk(KERN_ERR "%s: device does not respond!\n", | ||
1912 | wiphy_name(dev->wiphy)); | ||
1913 | return -EBUSY; | ||
1914 | } | ||
1915 | |||
1916 | memcpy(stats, &priv->stats, sizeof(*stats)); | 1938 | memcpy(stats, &priv->stats, sizeof(*stats)); |
1917 | |||
1918 | return 0; | 1939 | return 0; |
1919 | } | 1940 | } |
1920 | 1941 | ||
@@ -2072,6 +2093,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
2072 | return NULL; | 2093 | return NULL; |
2073 | 2094 | ||
2074 | priv = dev->priv; | 2095 | priv = dev->priv; |
2096 | priv->hw = dev; | ||
2075 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | 2097 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; |
2076 | priv->basic_rate_mask = 0x15f; | 2098 | priv->basic_rate_mask = 0x15f; |
2077 | skb_queue_head_init(&priv->tx_queue); | 2099 | skb_queue_head_init(&priv->tx_queue); |
@@ -2107,9 +2129,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
2107 | 2129 | ||
2108 | mutex_init(&priv->conf_mutex); | 2130 | mutex_init(&priv->conf_mutex); |
2109 | init_completion(&priv->eeprom_comp); | 2131 | init_completion(&priv->eeprom_comp); |
2110 | init_completion(&priv->stats_comp); | 2132 | INIT_DELAYED_WORK(&priv->work, p54_work); |
2111 | setup_timer(&priv->stats_timer, p54_statistics_timer, | ||
2112 | (unsigned long)dev); | ||
2113 | 2133 | ||
2114 | return dev; | 2134 | return dev; |
2115 | } | 2135 | } |
@@ -2118,8 +2138,6 @@ EXPORT_SYMBOL_GPL(p54_init_common); | |||
2118 | void p54_free_common(struct ieee80211_hw *dev) | 2138 | void p54_free_common(struct ieee80211_hw *dev) |
2119 | { | 2139 | { |
2120 | struct p54_common *priv = dev->priv; | 2140 | struct p54_common *priv = dev->priv; |
2121 | del_timer(&priv->stats_timer); | ||
2122 | kfree_skb(priv->cached_stats); | ||
2123 | kfree(priv->iq_autocal); | 2141 | kfree(priv->iq_autocal); |
2124 | kfree(priv->output_limit); | 2142 | kfree(priv->output_limit); |
2125 | kfree(priv->curve_data); | 2143 | kfree(priv->curve_data); |
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 5a68fdae7730..06e1643cc295 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h | |||
@@ -355,6 +355,11 @@ struct p54_tx_data { | |||
355 | u8 align[0]; | 355 | u8 align[0]; |
356 | } __attribute__ ((packed)); | 356 | } __attribute__ ((packed)); |
357 | 357 | ||
358 | /* unit is ms */ | ||
359 | #define P54_TX_FRAME_LIFETIME 2000 | ||
360 | #define P54_TX_TIMEOUT 4000 | ||
361 | #define P54_STATISTICS_UPDATE 5000 | ||
362 | |||
358 | #define P54_FILTER_TYPE_NONE 0 | 363 | #define P54_FILTER_TYPE_NONE 0 |
359 | #define P54_FILTER_TYPE_STATION BIT(0) | 364 | #define P54_FILTER_TYPE_STATION BIT(0) |
360 | #define P54_FILTER_TYPE_IBSS BIT(1) | 365 | #define P54_FILTER_TYPE_IBSS BIT(1) |