aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2008-07-31 20:30:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-01 15:31:35 -0400
commit7dcdd073bf78bb6958bbc12a1a47754a0f3c4721 (patch)
tree296f03bd684ff19698db4c44330a68f4ae9846b3 /drivers/net/wireless
parentbf4634afd8bb72936d2d56425ec792ca1bfa92a2 (diff)
rtl8187: Fix lockups due to concurrent access to config routine
Some users of the RTL8187B have experienced difficulties since commit 49292d56352a6ab90d04c3448dd8b6106dfef2d6 that introduced the power management wext hooks. This difficulty has not made much sense until it was realized that it was possible for mac80211 to make a call to the config routine while that routine was already being executed. On this device, it is necessary to loopback the TX when changing channels. Unless this is properly restored, the device will lockup. A mutex now protects the device state, and the private data in several places. The problem was found by Herton Ronaldo Krzesinski <herton@mandriva.com.br>, who also suggested this type of fix. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Acked-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Acked-by: Hin-Tak Leung <htl10@users.sourceforge.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/rtl8187.h4
-rw-r--r--drivers/net/wireless/rtl8187_dev.c15
2 files changed, 18 insertions, 1 deletions
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 1b0d750f6623..5a9515c99960 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -94,6 +94,10 @@ struct rtl8187_priv {
94 const struct rtl818x_rf_ops *rf; 94 const struct rtl818x_rf_ops *rf;
95 struct ieee80211_vif *vif; 95 struct ieee80211_vif *vif;
96 int mode; 96 int mode;
97 /* The mutex protects the TX loopback state.
98 * Any attempt to set channels concurrently locks the device.
99 */
100 struct mutex conf_mutex;
97 101
98 /* rtl8187 specific */ 102 /* rtl8187 specific */
99 struct ieee80211_channel channels[14]; 103 struct ieee80211_channel channels[14];
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 461aa26164c2..57376fb993ed 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -728,6 +728,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
728 if (ret) 728 if (ret)
729 return ret; 729 return ret;
730 730
731 mutex_lock(&priv->conf_mutex);
731 if (priv->is_rtl8187b) { 732 if (priv->is_rtl8187b) {
732 reg = RTL818X_RX_CONF_MGMT | 733 reg = RTL818X_RX_CONF_MGMT |
733 RTL818X_RX_CONF_DATA | 734 RTL818X_RX_CONF_DATA |
@@ -749,6 +750,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
749 (7 << 0 /* long retry limit */) | 750 (7 << 0 /* long retry limit */) |
750 (7 << 21 /* MAX TX DMA */)); 751 (7 << 21 /* MAX TX DMA */));
751 rtl8187_init_urbs(dev); 752 rtl8187_init_urbs(dev);
753 mutex_unlock(&priv->conf_mutex);
752 return 0; 754 return 0;
753 } 755 }
754 756
@@ -792,6 +794,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
792 reg |= RTL818X_CMD_TX_ENABLE; 794 reg |= RTL818X_CMD_TX_ENABLE;
793 reg |= RTL818X_CMD_RX_ENABLE; 795 reg |= RTL818X_CMD_RX_ENABLE;
794 rtl818x_iowrite8(priv, &priv->map->CMD, reg); 796 rtl818x_iowrite8(priv, &priv->map->CMD, reg);
797 mutex_unlock(&priv->conf_mutex);
795 798
796 return 0; 799 return 0;
797} 800}
@@ -803,6 +806,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
803 struct sk_buff *skb; 806 struct sk_buff *skb;
804 u32 reg; 807 u32 reg;
805 808
809 mutex_lock(&priv->conf_mutex);
806 rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); 810 rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
807 811
808 reg = rtl818x_ioread8(priv, &priv->map->CMD); 812 reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -822,7 +826,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
822 usb_kill_urb(info->urb); 826 usb_kill_urb(info->urb);
823 kfree_skb(skb); 827 kfree_skb(skb);
824 } 828 }
825 return; 829 mutex_unlock(&priv->conf_mutex);
826} 830}
827 831
828static int rtl8187_add_interface(struct ieee80211_hw *dev, 832static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -842,6 +846,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
842 return -EOPNOTSUPP; 846 return -EOPNOTSUPP;
843 } 847 }
844 848
849 mutex_lock(&priv->conf_mutex);
845 priv->vif = conf->vif; 850 priv->vif = conf->vif;
846 851
847 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 852 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -850,6 +855,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
850 ((u8 *)conf->mac_addr)[i]); 855 ((u8 *)conf->mac_addr)[i]);
851 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 856 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
852 857
858 mutex_unlock(&priv->conf_mutex);
853 return 0; 859 return 0;
854} 860}
855 861
@@ -857,8 +863,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
857 struct ieee80211_if_init_conf *conf) 863 struct ieee80211_if_init_conf *conf)
858{ 864{
859 struct rtl8187_priv *priv = dev->priv; 865 struct rtl8187_priv *priv = dev->priv;
866 mutex_lock(&priv->conf_mutex);
860 priv->mode = IEEE80211_IF_TYPE_MNTR; 867 priv->mode = IEEE80211_IF_TYPE_MNTR;
861 priv->vif = NULL; 868 priv->vif = NULL;
869 mutex_unlock(&priv->conf_mutex);
862} 870}
863 871
864static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) 872static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -866,6 +874,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
866 struct rtl8187_priv *priv = dev->priv; 874 struct rtl8187_priv *priv = dev->priv;
867 u32 reg; 875 u32 reg;
868 876
877 mutex_lock(&priv->conf_mutex);
869 reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); 878 reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
870 /* Enable TX loopback on MAC level to avoid TX during channel 879 /* Enable TX loopback on MAC level to avoid TX during channel
871 * changes, as this has be seen to causes problems and the 880 * changes, as this has be seen to causes problems and the
@@ -898,6 +907,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
898 rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); 907 rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
899 rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); 908 rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
900 rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); 909 rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
910 mutex_unlock(&priv->conf_mutex);
901 return 0; 911 return 0;
902} 912}
903 913
@@ -909,6 +919,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
909 int i; 919 int i;
910 u8 reg; 920 u8 reg;
911 921
922 mutex_lock(&priv->conf_mutex);
912 for (i = 0; i < ETH_ALEN; i++) 923 for (i = 0; i < ETH_ALEN; i++)
913 rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); 924 rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
914 925
@@ -922,6 +933,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
922 rtl818x_iowrite8(priv, &priv->map->MSR, reg); 933 rtl818x_iowrite8(priv, &priv->map->MSR, reg);
923 } 934 }
924 935
936 mutex_unlock(&priv->conf_mutex);
925 return 0; 937 return 0;
926} 938}
927 939
@@ -1189,6 +1201,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
1189 printk(KERN_ERR "rtl8187: Cannot register device\n"); 1201 printk(KERN_ERR "rtl8187: Cannot register device\n");
1190 goto err_free_dev; 1202 goto err_free_dev;
1191 } 1203 }
1204 mutex_init(&priv->conf_mutex);
1192 1205
1193 printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", 1206 printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
1194 wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), 1207 wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),