diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2009-04-11 12:26:01 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-04-22 16:54:45 -0400 |
commit | 2d1f96dd90a20c25243cc3b13e9f21d72f00aba0 (patch) | |
tree | 76dc36f2b2d700ea045b287689405d430d6e5d04 | |
parent | 7858e07b7ccf1d2fd5898a405c93d022d3f1f42d (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>
-rw-r--r-- | drivers/net/wireless/b43legacy/b43legacy.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/main.c | 164 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/xmit.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/xmit.h | 4 |
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. */ | ||
959 | static 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 | |||
958 | static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, | 970 | static 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 | ||
1168 | static 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 | |||
1182 | static 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 | |||
1192 | static 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 | |||
1137 | static void b43legacy_beacon_update_trigger_work(struct work_struct *work) | 1240 | static 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 | ||
1201 | static 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 | |||
1240 | static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) | 1305 | static 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 */ |