aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43legacy/main.c')
-rw-r--r--drivers/net/wireless/b43legacy/main.c193
1 files changed, 150 insertions, 43 deletions
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 879edc786713..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;
@@ -1013,7 +1044,8 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
1013 b43legacywarn(dev->wl, "Did not find a valid TIM IE in the " 1044 b43legacywarn(dev->wl, "Did not find a valid TIM IE in the "
1014 "beacon template packet. AP or IBSS operation " 1045 "beacon template packet. AP or IBSS operation "
1015 "may be broken.\n"); 1046 "may be broken.\n");
1016 } 1047 } else
1048 b43legacydbg(dev->wl, "Updated beacon template\n");
1017} 1049}
1018 1050
1019static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, 1051static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
@@ -1025,7 +1057,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
1025 __le16 dur; 1057 __le16 dur;
1026 1058
1027 plcp.data = 0; 1059 plcp.data = 0;
1028 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); 1060 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
1029 dur = ieee80211_generic_frame_duration(dev->wl->hw, 1061 dur = ieee80211_generic_frame_duration(dev->wl->hw,
1030 dev->wl->vif, 1062 dev->wl->vif,
1031 size, 1063 size,
@@ -1129,10 +1161,104 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
1129 0x200 - sizeof(struct b43legacy_plcp_hdr6)); 1161 0x200 - sizeof(struct b43legacy_plcp_hdr6));
1130 b43legacy_write_template_common(dev, probe_resp_data, 1162 b43legacy_write_template_common(dev, probe_resp_data,
1131 size, ram_offset, 1163 size, ram_offset,
1132 shm_size_offset, rate->bitrate); 1164 shm_size_offset, rate->hw_value);
1133 kfree(probe_resp_data); 1165 kfree(probe_resp_data);
1134} 1166}
1135 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
1240static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
1241{
1242 struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
1243 beacon_update_trigger);
1244 struct b43legacy_wldev *dev;
1245
1246 mutex_lock(&wl->mutex);
1247 dev = wl->current_dev;
1248 if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
1249 spin_lock_irq(&wl->irq_lock);
1250 /* update beacon right away or defer to irq */
1251 dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
1252 handle_irq_beacon(dev);
1253 /* The handler might have updated the IRQ mask. */
1254 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
1255 dev->irq_savedstate);
1256 mmiowb();
1257 spin_unlock_irq(&wl->irq_lock);
1258 }
1259 mutex_unlock(&wl->mutex);
1260}
1261
1136/* Asynchronously update the packet templates in template RAM. 1262/* Asynchronously update the packet templates in template RAM.
1137 * Locking: Requires wl->irq_lock to be locked. */ 1263 * Locking: Requires wl->irq_lock to be locked. */
1138static void b43legacy_update_templates(struct b43legacy_wl *wl) 1264static void b43legacy_update_templates(struct b43legacy_wl *wl)
@@ -1156,54 +1282,24 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
1156 wl->current_beacon = beacon; 1282 wl->current_beacon = beacon;
1157 wl->beacon0_uploaded = 0; 1283 wl->beacon0_uploaded = 0;
1158 wl->beacon1_uploaded = 0; 1284 wl->beacon1_uploaded = 0;
1285 queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
1159} 1286}
1160 1287
1161static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, 1288static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
1162 u16 beacon_int) 1289 u16 beacon_int)
1163{ 1290{
1164 b43legacy_time_lock(dev); 1291 b43legacy_time_lock(dev);
1165 if (dev->dev->id.revision >= 3) 1292 if (dev->dev->id.revision >= 3) {
1166 b43legacy_write32(dev, 0x188, (beacon_int << 16)); 1293 b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_REP,
1167 else { 1294 (beacon_int << 16));
1295 b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_START,
1296 (beacon_int << 10));
1297 } else {
1168 b43legacy_write16(dev, 0x606, (beacon_int >> 6)); 1298 b43legacy_write16(dev, 0x606, (beacon_int >> 6));
1169 b43legacy_write16(dev, 0x610, beacon_int); 1299 b43legacy_write16(dev, 0x610, beacon_int);
1170 } 1300 }
1171 b43legacy_time_unlock(dev); 1301 b43legacy_time_unlock(dev);
1172} 1302 b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
1173
1174static void handle_irq_beacon(struct b43legacy_wldev *dev)
1175{
1176 struct b43legacy_wl *wl = dev->wl;
1177 u32 cmd;
1178
1179 if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
1180 return;
1181
1182 /* This is the bottom half of the asynchronous beacon update. */
1183
1184 cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
1185 if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) {
1186 if (!wl->beacon0_uploaded) {
1187 b43legacy_write_beacon_template(dev, 0x68,
1188 B43legacy_SHM_SH_BTL0,
1189 B43legacy_CCK_RATE_1MB);
1190 b43legacy_write_probe_resp_template(dev, 0x268,
1191 B43legacy_SHM_SH_PRTLEN,
1192 &__b43legacy_ratetable[3]);
1193 wl->beacon0_uploaded = 1;
1194 }
1195 cmd |= B43legacy_MACCMD_BEACON0_VALID;
1196 }
1197 if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) {
1198 if (!wl->beacon1_uploaded) {
1199 b43legacy_write_beacon_template(dev, 0x468,
1200 B43legacy_SHM_SH_BTL1,
1201 B43legacy_CCK_RATE_1MB);
1202 wl->beacon1_uploaded = 1;
1203 }
1204 cmd |= B43legacy_MACCMD_BEACON1_VALID;
1205 }
1206 b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
1207} 1303}
1208 1304
1209static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) 1305static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
@@ -2297,6 +2393,7 @@ static void b43legacy_security_init(struct b43legacy_wldev *dev)
2297 dev->max_nr_keys - 8); 2393 dev->max_nr_keys - 8);
2298} 2394}
2299 2395
2396#ifdef CONFIG_B43LEGACY_HWRNG
2300static int b43legacy_rng_read(struct hwrng *rng, u32 *data) 2397static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
2301{ 2398{
2302 struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv; 2399 struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
@@ -2312,17 +2409,21 @@ static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
2312 2409
2313 return (sizeof(u16)); 2410 return (sizeof(u16));
2314} 2411}
2412#endif
2315 2413
2316static void b43legacy_rng_exit(struct b43legacy_wl *wl) 2414static void b43legacy_rng_exit(struct b43legacy_wl *wl)
2317{ 2415{
2416#ifdef CONFIG_B43LEGACY_HWRNG
2318 if (wl->rng_initialized) 2417 if (wl->rng_initialized)
2319 hwrng_unregister(&wl->rng); 2418 hwrng_unregister(&wl->rng);
2419#endif
2320} 2420}
2321 2421
2322static int b43legacy_rng_init(struct b43legacy_wl *wl) 2422static int b43legacy_rng_init(struct b43legacy_wl *wl)
2323{ 2423{
2324 int err; 2424 int err = 0;
2325 2425
2426#ifdef CONFIG_B43LEGACY_HWRNG
2326 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), 2427 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
2327 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); 2428 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
2328 wl->rng.name = wl->rng_name; 2429 wl->rng.name = wl->rng_name;
@@ -2336,6 +2437,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
2336 "number generator (%d)\n", err); 2437 "number generator (%d)\n", err);
2337 } 2438 }
2338 2439
2440#endif
2339 return err; 2441 return err;
2340} 2442}
2341 2443
@@ -3392,6 +3494,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
3392 memset(wl->bssid, 0, ETH_ALEN); 3494 memset(wl->bssid, 0, ETH_ALEN);
3393 memset(wl->mac_addr, 0, ETH_ALEN); 3495 memset(wl->mac_addr, 0, ETH_ALEN);
3394 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;
3395 3500
3396 mutex_lock(&wl->mutex); 3501 mutex_lock(&wl->mutex);
3397 3502
@@ -3429,6 +3534,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
3429 struct b43legacy_wldev *dev = wl->current_dev; 3534 struct b43legacy_wldev *dev = wl->current_dev;
3430 3535
3431 b43legacy_rfkill_exit(dev); 3536 b43legacy_rfkill_exit(dev);
3537 cancel_work_sync(&(wl->beacon_update_trigger));
3432 3538
3433 mutex_lock(&wl->mutex); 3539 mutex_lock(&wl->mutex);
3434 if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) 3540 if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
@@ -3760,6 +3866,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
3760 spin_lock_init(&wl->leds_lock); 3866 spin_lock_init(&wl->leds_lock);
3761 mutex_init(&wl->mutex); 3867 mutex_init(&wl->mutex);
3762 INIT_LIST_HEAD(&wl->devlist); 3868 INIT_LIST_HEAD(&wl->devlist);
3869 INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
3763 3870
3764 ssb_set_devtypedata(dev, wl); 3871 ssb_set_devtypedata(dev, wl);
3765 b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); 3872 b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);