aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2009-04-11 12:26:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:45 -0400
commit2d1f96dd90a20c25243cc3b13e9f21d72f00aba0 (patch)
tree76dc36f2b2d700ea045b287689405d430d6e5d04 /drivers/net/wireless/b43legacy
parent7858e07b7ccf1d2fd5898a405c93d022d3f1f42d (diff)
b43legacy: Clean up beacon IRQ
This patch ports commit c97a4ccc1fad35d3 "b43: Fix beacon BH update" to b43legacy. It fixes beacon updating in the bottomhalf. In case the device is busy, we will defer to later in the IRQ handler. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Acked-by: Michael Buesch <mb@bu3sch.de> Tested-by: David Ellingsworth <david@identd.dyndns.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h2
-rw-r--r--drivers/net/wireless/b43legacy/main.c164
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c2
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h4
4 files changed, 121 insertions, 51 deletions
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index ad4794a0a327..da59ef02b6ef 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -259,7 +259,6 @@
259 259
260#define B43legacy_IRQ_ALL 0xFFFFFFFF 260#define B43legacy_IRQ_ALL 0xFFFFFFFF
261#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \ 261#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
262 B43legacy_IRQ_BEACON | \
263 B43legacy_IRQ_TBTT_INDI | \ 262 B43legacy_IRQ_TBTT_INDI | \
264 B43legacy_IRQ_ATIM_END | \ 263 B43legacy_IRQ_ATIM_END | \
265 B43legacy_IRQ_PMQ | \ 264 B43legacy_IRQ_PMQ | \
@@ -617,6 +616,7 @@ struct b43legacy_wl {
617 struct sk_buff *current_beacon; 616 struct sk_buff *current_beacon;
618 bool beacon0_uploaded; 617 bool beacon0_uploaded;
619 bool beacon1_uploaded; 618 bool beacon1_uploaded;
619 bool beacon_templates_virgin; /* Never wrote the templates? */
620 struct work_struct beacon_update_trigger; 620 struct work_struct beacon_update_trigger;
621}; 621};
622 622
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 4f3f01629465..ee202b4f77b5 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -955,23 +955,54 @@ static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
955 size + sizeof(struct b43legacy_plcp_hdr6)); 955 size + sizeof(struct b43legacy_plcp_hdr6));
956} 956}
957 957
958/* Convert a b43legacy antenna number value to the PHY TX control value. */
959static u16 b43legacy_antenna_to_phyctl(int antenna)
960{
961 switch (antenna) {
962 case B43legacy_ANTENNA0:
963 return B43legacy_TX4_PHY_ANT0;
964 case B43legacy_ANTENNA1:
965 return B43legacy_TX4_PHY_ANT1;
966 }
967 return B43legacy_TX4_PHY_ANTLAST;
968}
969
958static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, 970static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
959 u16 ram_offset, 971 u16 ram_offset,
960 u16 shm_size_offset, u8 rate) 972 u16 shm_size_offset)
961{ 973{
962 974
963 unsigned int i, len, variable_len; 975 unsigned int i, len, variable_len;
964 const struct ieee80211_mgmt *bcn; 976 const struct ieee80211_mgmt *bcn;
965 const u8 *ie; 977 const u8 *ie;
966 bool tim_found = 0; 978 bool tim_found = 0;
979 unsigned int rate;
980 u16 ctl;
981 int antenna;
982 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
967 983
968 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); 984 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
969 len = min((size_t)dev->wl->current_beacon->len, 985 len = min((size_t)dev->wl->current_beacon->len,
970 0x200 - sizeof(struct b43legacy_plcp_hdr6)); 986 0x200 - sizeof(struct b43legacy_plcp_hdr6));
987 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
971 988
972 b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset, 989 b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset,
973 shm_size_offset, rate); 990 shm_size_offset, rate);
974 991
992 /* Write the PHY TX control parameters. */
993 antenna = B43legacy_ANTENNA_DEFAULT;
994 antenna = b43legacy_antenna_to_phyctl(antenna);
995 ctl = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
996 B43legacy_SHM_SH_BEACPHYCTL);
997 /* We can't send beacons with short preamble. Would get PHY errors. */
998 ctl &= ~B43legacy_TX4_PHY_SHORTPRMBL;
999 ctl &= ~B43legacy_TX4_PHY_ANT;
1000 ctl &= ~B43legacy_TX4_PHY_ENC;
1001 ctl |= antenna;
1002 ctl |= B43legacy_TX4_PHY_ENC_CCK;
1003 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
1004 B43legacy_SHM_SH_BEACPHYCTL, ctl);
1005
975 /* Find the position of the TIM and the DTIM_period value 1006 /* Find the position of the TIM and the DTIM_period value
976 * and write them to SHM. */ 1007 * and write them to SHM. */
977 ie = bcn->u.beacon.variable; 1008 ie = bcn->u.beacon.variable;
@@ -1026,7 +1057,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
1026 __le16 dur; 1057 __le16 dur;
1027 1058
1028 plcp.data = 0; 1059 plcp.data = 0;
1029 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); 1060 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
1030 dur = ieee80211_generic_frame_duration(dev->wl->hw, 1061 dur = ieee80211_generic_frame_duration(dev->wl->hw,
1031 dev->wl->vif, 1062 dev->wl->vif,
1032 size, 1063 size,
@@ -1130,10 +1161,82 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
1130 0x200 - sizeof(struct b43legacy_plcp_hdr6)); 1161 0x200 - sizeof(struct b43legacy_plcp_hdr6));
1131 b43legacy_write_template_common(dev, probe_resp_data, 1162 b43legacy_write_template_common(dev, probe_resp_data,
1132 size, ram_offset, 1163 size, ram_offset,
1133 shm_size_offset, rate->bitrate); 1164 shm_size_offset, rate->hw_value);
1134 kfree(probe_resp_data); 1165 kfree(probe_resp_data);
1135} 1166}
1136 1167
1168static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev)
1169{
1170 struct b43legacy_wl *wl = dev->wl;
1171
1172 if (wl->beacon0_uploaded)
1173 return;
1174 b43legacy_write_beacon_template(dev, 0x68, 0x18);
1175 /* FIXME: Probe resp upload doesn't really belong here,
1176 * but we don't use that feature anyway. */
1177 b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
1178 &__b43legacy_ratetable[3]);
1179 wl->beacon0_uploaded = 1;
1180}
1181
1182static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev)
1183{
1184 struct b43legacy_wl *wl = dev->wl;
1185
1186 if (wl->beacon1_uploaded)
1187 return;
1188 b43legacy_write_beacon_template(dev, 0x468, 0x1A);
1189 wl->beacon1_uploaded = 1;
1190}
1191
1192static void handle_irq_beacon(struct b43legacy_wldev *dev)
1193{
1194 struct b43legacy_wl *wl = dev->wl;
1195 u32 cmd, beacon0_valid, beacon1_valid;
1196
1197 if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
1198 return;
1199
1200 /* This is the bottom half of the asynchronous beacon update. */
1201
1202 /* Ignore interrupt in the future. */
1203 dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
1204
1205 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1206 beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
1207 beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID);
1208
1209 /* Schedule interrupt manually, if busy. */
1210 if (beacon0_valid && beacon1_valid) {
1211 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON);
1212 dev->irq_savedstate |= B43legacy_IRQ_BEACON;
1213 return;
1214 }
1215
1216 if (unlikely(wl->beacon_templates_virgin)) {
1217 /* We never uploaded a beacon before.
1218 * Upload both templates now, but only mark one valid. */
1219 wl->beacon_templates_virgin = 0;
1220 b43legacy_upload_beacon0(dev);
1221 b43legacy_upload_beacon1(dev);
1222 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1223 cmd |= B43legacy_MACCMD_BEACON0_VALID;
1224 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
1225 } else {
1226 if (!beacon0_valid) {
1227 b43legacy_upload_beacon0(dev);
1228 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1229 cmd |= B43legacy_MACCMD_BEACON0_VALID;
1230 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
1231 } else if (!beacon1_valid) {
1232 b43legacy_upload_beacon1(dev);
1233 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1234 cmd |= B43legacy_MACCMD_BEACON1_VALID;
1235 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
1236 }
1237 }
1238}
1239
1137static void b43legacy_beacon_update_trigger_work(struct work_struct *work) 1240static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
1138{ 1241{
1139 struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl, 1242 struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
@@ -1143,13 +1246,14 @@ static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
1143 mutex_lock(&wl->mutex); 1246 mutex_lock(&wl->mutex);
1144 dev = wl->current_dev; 1247 dev = wl->current_dev;
1145 if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { 1248 if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
1146 /* Force the microcode to trigger the
1147 * beacon update bottom-half IRQ. */
1148 spin_lock_irq(&wl->irq_lock); 1249 spin_lock_irq(&wl->irq_lock);
1149 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, 1250 /* update beacon right away or defer to irq */
1150 b43legacy_read32(dev, B43legacy_MMIO_MACCMD) 1251 dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
1151 | B43legacy_MACCMD_BEACON0_VALID 1252 handle_irq_beacon(dev);
1152 | B43legacy_MACCMD_BEACON1_VALID); 1253 /* The handler might have updated the IRQ mask. */
1254 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
1255 dev->irq_savedstate);
1256 mmiowb();
1153 spin_unlock_irq(&wl->irq_lock); 1257 spin_unlock_irq(&wl->irq_lock);
1154 } 1258 }
1155 mutex_unlock(&wl->mutex); 1259 mutex_unlock(&wl->mutex);
@@ -1198,45 +1302,6 @@ static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
1198 b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int); 1302 b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
1199} 1303}
1200 1304
1201static void handle_irq_beacon(struct b43legacy_wldev *dev)
1202{
1203 struct b43legacy_wl *wl = dev->wl;
1204 u32 cmd;
1205 u32 beacon0_valid, beacon1_valid;
1206
1207 if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
1208 return;
1209
1210 /* This is the bottom half of the asynchronous beacon update. */
1211
1212 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1213 beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
1214 beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID);
1215 cmd &= ~(B43legacy_MACCMD_BEACON0_VALID | B43legacy_MACCMD_BEACON1_VALID);
1216
1217 if (!beacon0_valid) {
1218 if (!wl->beacon0_uploaded) {
1219 b43legacy_write_beacon_template(dev, 0x68,
1220 B43legacy_SHM_SH_BTL0,
1221 B43legacy_CCK_RATE_1MB);
1222 b43legacy_write_probe_resp_template(dev, 0x268,
1223 B43legacy_SHM_SH_PRTLEN,
1224 &__b43legacy_ratetable[3]);
1225 wl->beacon0_uploaded = 1;
1226 }
1227 cmd |= B43legacy_MACCMD_BEACON0_VALID;
1228 } else if (!beacon1_valid) {
1229 if (!wl->beacon1_uploaded) {
1230 b43legacy_write_beacon_template(dev, 0x468,
1231 B43legacy_SHM_SH_BTL1,
1232 B43legacy_CCK_RATE_1MB);
1233 wl->beacon1_uploaded = 1;
1234 }
1235 cmd |= B43legacy_MACCMD_BEACON1_VALID;
1236 }
1237 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
1238}
1239
1240static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) 1305static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
1241{ 1306{
1242} 1307}
@@ -3429,6 +3494,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
3429 memset(wl->bssid, 0, ETH_ALEN); 3494 memset(wl->bssid, 0, ETH_ALEN);
3430 memset(wl->mac_addr, 0, ETH_ALEN); 3495 memset(wl->mac_addr, 0, ETH_ALEN);
3431 wl->filter_flags = 0; 3496 wl->filter_flags = 0;
3497 wl->beacon0_uploaded = 0;
3498 wl->beacon1_uploaded = 0;
3499 wl->beacon_templates_virgin = 1;
3432 3500
3433 mutex_lock(&wl->mutex); 3501 mutex_lock(&wl->mutex);
3434 3502
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 12fca99f7578..b8e39dd06e99 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -274,7 +274,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
274 274
275 /* PHY TX Control word */ 275 /* PHY TX Control word */
276 if (rate_ofdm) 276 if (rate_ofdm)
277 phy_ctl |= B43legacy_TX4_PHY_OFDM; 277 phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM;
278 if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 278 if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
279 phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; 279 phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
280 switch (info->antenna_sel_tx) { 280 switch (info->antenna_sel_tx) {
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 62e09d02788f..91633087a20b 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -67,7 +67,9 @@ struct b43legacy_txhdr_fw3 {
67#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ 67#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
68 68
69/* PHY TX control word */ 69/* PHY TX control word */
70#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ 70#define B43legacy_TX4_PHY_ENC 0x0003 /* Data frame encoding */
71#define B43legacy_TX4_PHY_ENC_CCK 0x0000 /* CCK */
72#define B43legacy_TX4_PHY_ENC_OFDM 0x0001 /* Data frame rate type */
71#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ 73#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
72#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */ 74#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
73#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ 75#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */