diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 199 |
1 files changed, 116 insertions, 83 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ec28a6ef42be..1aa0f727174b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -1281,22 +1281,107 @@ static void b43_write_template_common(struct b43_wldev *dev, | |||
1281 | size + sizeof(struct b43_plcp_hdr6)); | 1281 | size + sizeof(struct b43_plcp_hdr6)); |
1282 | } | 1282 | } |
1283 | 1283 | ||
1284 | /* Check if the use of the antenna that ieee80211 told us to | ||
1285 | * use is possible. This will fall back to DEFAULT. | ||
1286 | * "antenna_nr" is the antenna identifier we got from ieee80211. */ | ||
1287 | u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, | ||
1288 | u8 antenna_nr) | ||
1289 | { | ||
1290 | u8 antenna_mask; | ||
1291 | |||
1292 | if (antenna_nr == 0) { | ||
1293 | /* Zero means "use default antenna". That's always OK. */ | ||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | /* Get the mask of available antennas. */ | ||
1298 | if (dev->phy.gmode) | ||
1299 | antenna_mask = dev->dev->bus->sprom.ant_available_bg; | ||
1300 | else | ||
1301 | antenna_mask = dev->dev->bus->sprom.ant_available_a; | ||
1302 | |||
1303 | if (!(antenna_mask & (1 << (antenna_nr - 1)))) { | ||
1304 | /* This antenna is not available. Fall back to default. */ | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | return antenna_nr; | ||
1309 | } | ||
1310 | |||
1311 | static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) | ||
1312 | { | ||
1313 | antenna = b43_ieee80211_antenna_sanitize(dev, antenna); | ||
1314 | switch (antenna) { | ||
1315 | case 0: /* default/diversity */ | ||
1316 | return B43_ANTENNA_DEFAULT; | ||
1317 | case 1: /* Antenna 0 */ | ||
1318 | return B43_ANTENNA0; | ||
1319 | case 2: /* Antenna 1 */ | ||
1320 | return B43_ANTENNA1; | ||
1321 | case 3: /* Antenna 2 */ | ||
1322 | return B43_ANTENNA2; | ||
1323 | case 4: /* Antenna 3 */ | ||
1324 | return B43_ANTENNA3; | ||
1325 | default: | ||
1326 | return B43_ANTENNA_DEFAULT; | ||
1327 | } | ||
1328 | } | ||
1329 | |||
1330 | /* Convert a b43 antenna number value to the PHY TX control value. */ | ||
1331 | static u16 b43_antenna_to_phyctl(int antenna) | ||
1332 | { | ||
1333 | switch (antenna) { | ||
1334 | case B43_ANTENNA0: | ||
1335 | return B43_TXH_PHY_ANT0; | ||
1336 | case B43_ANTENNA1: | ||
1337 | return B43_TXH_PHY_ANT1; | ||
1338 | case B43_ANTENNA2: | ||
1339 | return B43_TXH_PHY_ANT2; | ||
1340 | case B43_ANTENNA3: | ||
1341 | return B43_TXH_PHY_ANT3; | ||
1342 | case B43_ANTENNA_AUTO: | ||
1343 | return B43_TXH_PHY_ANT01AUTO; | ||
1344 | } | ||
1345 | B43_WARN_ON(1); | ||
1346 | return 0; | ||
1347 | } | ||
1348 | |||
1284 | static void b43_write_beacon_template(struct b43_wldev *dev, | 1349 | static void b43_write_beacon_template(struct b43_wldev *dev, |
1285 | u16 ram_offset, | 1350 | u16 ram_offset, |
1286 | u16 shm_size_offset, u8 rate) | 1351 | u16 shm_size_offset) |
1287 | { | 1352 | { |
1288 | unsigned int i, len, variable_len; | 1353 | unsigned int i, len, variable_len; |
1289 | const struct ieee80211_mgmt *bcn; | 1354 | const struct ieee80211_mgmt *bcn; |
1290 | const u8 *ie; | 1355 | const u8 *ie; |
1291 | bool tim_found = 0; | 1356 | bool tim_found = 0; |
1357 | unsigned int rate; | ||
1358 | u16 ctl; | ||
1359 | int antenna; | ||
1292 | 1360 | ||
1293 | bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); | 1361 | bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); |
1294 | len = min((size_t) dev->wl->current_beacon->len, | 1362 | len = min((size_t) dev->wl->current_beacon->len, |
1295 | 0x200 - sizeof(struct b43_plcp_hdr6)); | 1363 | 0x200 - sizeof(struct b43_plcp_hdr6)); |
1364 | rate = dev->wl->beacon_txctl.tx_rate->hw_value; | ||
1296 | 1365 | ||
1297 | b43_write_template_common(dev, (const u8 *)bcn, | 1366 | b43_write_template_common(dev, (const u8 *)bcn, |
1298 | len, ram_offset, shm_size_offset, rate); | 1367 | len, ram_offset, shm_size_offset, rate); |
1299 | 1368 | ||
1369 | /* Write the PHY TX control parameters. */ | ||
1370 | antenna = b43_antenna_from_ieee80211(dev, | ||
1371 | dev->wl->beacon_txctl.antenna_sel_tx); | ||
1372 | antenna = b43_antenna_to_phyctl(antenna); | ||
1373 | ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); | ||
1374 | /* We can't send beacons with short preamble. Would get PHY errors. */ | ||
1375 | ctl &= ~B43_TXH_PHY_SHORTPRMBL; | ||
1376 | ctl &= ~B43_TXH_PHY_ANT; | ||
1377 | ctl &= ~B43_TXH_PHY_ENC; | ||
1378 | ctl |= antenna; | ||
1379 | if (b43_is_cck_rate(rate)) | ||
1380 | ctl |= B43_TXH_PHY_ENC_CCK; | ||
1381 | else | ||
1382 | ctl |= B43_TXH_PHY_ENC_OFDM; | ||
1383 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); | ||
1384 | |||
1300 | /* Find the position of the TIM and the DTIM_period value | 1385 | /* Find the position of the TIM and the DTIM_period value |
1301 | * and write them to SHM. */ | 1386 | * and write them to SHM. */ |
1302 | ie = bcn->u.beacon.variable; | 1387 | ie = bcn->u.beacon.variable; |
@@ -1474,8 +1559,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1474 | 1559 | ||
1475 | if (!beacon0_valid) { | 1560 | if (!beacon0_valid) { |
1476 | if (!wl->beacon0_uploaded) { | 1561 | if (!wl->beacon0_uploaded) { |
1477 | b43_write_beacon_template(dev, 0x68, 0x18, | 1562 | b43_write_beacon_template(dev, 0x68, 0x18); |
1478 | B43_CCK_RATE_1MB); | ||
1479 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | 1563 | b43_write_probe_resp_template(dev, 0x268, 0x4A, |
1480 | &__b43_ratetable[3]); | 1564 | &__b43_ratetable[3]); |
1481 | wl->beacon0_uploaded = 1; | 1565 | wl->beacon0_uploaded = 1; |
@@ -1485,8 +1569,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1485 | b43_write32(dev, B43_MMIO_MACCMD, cmd); | 1569 | b43_write32(dev, B43_MMIO_MACCMD, cmd); |
1486 | } else if (!beacon1_valid) { | 1570 | } else if (!beacon1_valid) { |
1487 | if (!wl->beacon1_uploaded) { | 1571 | if (!wl->beacon1_uploaded) { |
1488 | b43_write_beacon_template(dev, 0x468, 0x1A, | 1572 | b43_write_beacon_template(dev, 0x468, 0x1A); |
1489 | B43_CCK_RATE_1MB); | ||
1490 | wl->beacon1_uploaded = 1; | 1573 | wl->beacon1_uploaded = 1; |
1491 | } | 1574 | } |
1492 | cmd = b43_read32(dev, B43_MMIO_MACCMD); | 1575 | cmd = b43_read32(dev, B43_MMIO_MACCMD); |
@@ -1519,7 +1602,8 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) | |||
1519 | 1602 | ||
1520 | /* Asynchronously update the packet templates in template RAM. | 1603 | /* Asynchronously update the packet templates in template RAM. |
1521 | * Locking: Requires wl->irq_lock to be locked. */ | 1604 | * Locking: Requires wl->irq_lock to be locked. */ |
1522 | static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) | 1605 | static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, |
1606 | const struct ieee80211_tx_control *txctl) | ||
1523 | { | 1607 | { |
1524 | /* This is the top half of the ansynchronous beacon update. | 1608 | /* This is the top half of the ansynchronous beacon update. |
1525 | * The bottom half is the beacon IRQ. | 1609 | * The bottom half is the beacon IRQ. |
@@ -1530,6 +1614,7 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) | |||
1530 | if (wl->current_beacon) | 1614 | if (wl->current_beacon) |
1531 | dev_kfree_skb_any(wl->current_beacon); | 1615 | dev_kfree_skb_any(wl->current_beacon); |
1532 | wl->current_beacon = beacon; | 1616 | wl->current_beacon = beacon; |
1617 | memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); | ||
1533 | wl->beacon0_uploaded = 0; | 1618 | wl->beacon0_uploaded = 0; |
1534 | wl->beacon1_uploaded = 0; | 1619 | wl->beacon1_uploaded = 0; |
1535 | queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); | 1620 | queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); |
@@ -2363,38 +2448,28 @@ static void b43_rate_memory_init(struct b43_wldev *dev) | |||
2363 | } | 2448 | } |
2364 | } | 2449 | } |
2365 | 2450 | ||
2451 | /* Set the default values for the PHY TX Control Words. */ | ||
2452 | static void b43_set_phytxctl_defaults(struct b43_wldev *dev) | ||
2453 | { | ||
2454 | u16 ctl = 0; | ||
2455 | |||
2456 | ctl |= B43_TXH_PHY_ENC_CCK; | ||
2457 | ctl |= B43_TXH_PHY_ANT01AUTO; | ||
2458 | ctl |= B43_TXH_PHY_TXPWR; | ||
2459 | |||
2460 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); | ||
2461 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl); | ||
2462 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl); | ||
2463 | } | ||
2464 | |||
2366 | /* Set the TX-Antenna for management frames sent by firmware. */ | 2465 | /* Set the TX-Antenna for management frames sent by firmware. */ |
2367 | static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) | 2466 | static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) |
2368 | { | 2467 | { |
2369 | u16 ant = 0; | 2468 | u16 ant; |
2370 | u16 tmp; | 2469 | u16 tmp; |
2371 | 2470 | ||
2372 | switch (antenna) { | 2471 | ant = b43_antenna_to_phyctl(antenna); |
2373 | case B43_ANTENNA0: | ||
2374 | ant |= B43_TXH_PHY_ANT0; | ||
2375 | break; | ||
2376 | case B43_ANTENNA1: | ||
2377 | ant |= B43_TXH_PHY_ANT1; | ||
2378 | break; | ||
2379 | case B43_ANTENNA2: | ||
2380 | ant |= B43_TXH_PHY_ANT2; | ||
2381 | break; | ||
2382 | case B43_ANTENNA3: | ||
2383 | ant |= B43_TXH_PHY_ANT3; | ||
2384 | break; | ||
2385 | case B43_ANTENNA_AUTO: | ||
2386 | ant |= B43_TXH_PHY_ANT01AUTO; | ||
2387 | break; | ||
2388 | default: | ||
2389 | B43_WARN_ON(1); | ||
2390 | } | ||
2391 | |||
2392 | /* FIXME We also need to set the other flags of the PHY control field somewhere. */ | ||
2393 | 2472 | ||
2394 | /* For Beacons */ | ||
2395 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); | ||
2396 | tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; | ||
2397 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); | ||
2398 | /* For ACK/CTS */ | 2473 | /* For ACK/CTS */ |
2399 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); | 2474 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); |
2400 | tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; | 2475 | tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; |
@@ -3112,52 +3187,6 @@ init_failure: | |||
3112 | return err; | 3187 | return err; |
3113 | } | 3188 | } |
3114 | 3189 | ||
3115 | /* Check if the use of the antenna that ieee80211 told us to | ||
3116 | * use is possible. This will fall back to DEFAULT. | ||
3117 | * "antenna_nr" is the antenna identifier we got from ieee80211. */ | ||
3118 | u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, | ||
3119 | u8 antenna_nr) | ||
3120 | { | ||
3121 | u8 antenna_mask; | ||
3122 | |||
3123 | if (antenna_nr == 0) { | ||
3124 | /* Zero means "use default antenna". That's always OK. */ | ||
3125 | return 0; | ||
3126 | } | ||
3127 | |||
3128 | /* Get the mask of available antennas. */ | ||
3129 | if (dev->phy.gmode) | ||
3130 | antenna_mask = dev->dev->bus->sprom.ant_available_bg; | ||
3131 | else | ||
3132 | antenna_mask = dev->dev->bus->sprom.ant_available_a; | ||
3133 | |||
3134 | if (!(antenna_mask & (1 << (antenna_nr - 1)))) { | ||
3135 | /* This antenna is not available. Fall back to default. */ | ||
3136 | return 0; | ||
3137 | } | ||
3138 | |||
3139 | return antenna_nr; | ||
3140 | } | ||
3141 | |||
3142 | static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) | ||
3143 | { | ||
3144 | antenna = b43_ieee80211_antenna_sanitize(dev, antenna); | ||
3145 | switch (antenna) { | ||
3146 | case 0: /* default/diversity */ | ||
3147 | return B43_ANTENNA_DEFAULT; | ||
3148 | case 1: /* Antenna 0 */ | ||
3149 | return B43_ANTENNA0; | ||
3150 | case 2: /* Antenna 1 */ | ||
3151 | return B43_ANTENNA1; | ||
3152 | case 3: /* Antenna 2 */ | ||
3153 | return B43_ANTENNA2; | ||
3154 | case 4: /* Antenna 3 */ | ||
3155 | return B43_ANTENNA3; | ||
3156 | default: | ||
3157 | return B43_ANTENNA_DEFAULT; | ||
3158 | } | ||
3159 | } | ||
3160 | |||
3161 | static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | 3190 | static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) |
3162 | { | 3191 | { |
3163 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3192 | struct b43_wl *wl = hw_to_b43_wl(hw); |
@@ -3405,8 +3434,10 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, | |||
3405 | if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { | 3434 | if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { |
3406 | B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); | 3435 | B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); |
3407 | b43_set_ssid(dev, conf->ssid, conf->ssid_len); | 3436 | b43_set_ssid(dev, conf->ssid, conf->ssid_len); |
3408 | if (conf->beacon) | 3437 | if (conf->beacon) { |
3409 | b43_update_templates(wl, conf->beacon); | 3438 | b43_update_templates(wl, conf->beacon, |
3439 | conf->beacon_control); | ||
3440 | } | ||
3410 | } | 3441 | } |
3411 | b43_write_mac_bssid_templates(dev); | 3442 | b43_write_mac_bssid_templates(dev); |
3412 | } | 3443 | } |
@@ -3877,6 +3908,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
3877 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1); | 3908 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1); |
3878 | 3909 | ||
3879 | b43_rate_memory_init(dev); | 3910 | b43_rate_memory_init(dev); |
3911 | b43_set_phytxctl_defaults(dev); | ||
3880 | 3912 | ||
3881 | /* Minimum Contention Window */ | 3913 | /* Minimum Contention Window */ |
3882 | if (phy->type == B43_PHYTYPE_B) { | 3914 | if (phy->type == B43_PHYTYPE_B) { |
@@ -4087,16 +4119,17 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) | |||
4087 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4119 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4088 | struct sk_buff *beacon; | 4120 | struct sk_buff *beacon; |
4089 | unsigned long flags; | 4121 | unsigned long flags; |
4122 | struct ieee80211_tx_control txctl; | ||
4090 | 4123 | ||
4091 | /* We could modify the existing beacon and set the aid bit in | 4124 | /* We could modify the existing beacon and set the aid bit in |
4092 | * the TIM field, but that would probably require resizing and | 4125 | * the TIM field, but that would probably require resizing and |
4093 | * moving of data within the beacon template. | 4126 | * moving of data within the beacon template. |
4094 | * Simply request a new beacon and let mac80211 do the hard work. */ | 4127 | * Simply request a new beacon and let mac80211 do the hard work. */ |
4095 | beacon = ieee80211_beacon_get(hw, wl->vif, NULL); | 4128 | beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); |
4096 | if (unlikely(!beacon)) | 4129 | if (unlikely(!beacon)) |
4097 | return -ENOMEM; | 4130 | return -ENOMEM; |
4098 | spin_lock_irqsave(&wl->irq_lock, flags); | 4131 | spin_lock_irqsave(&wl->irq_lock, flags); |
4099 | b43_update_templates(wl, beacon); | 4132 | b43_update_templates(wl, beacon, &txctl); |
4100 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 4133 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
4101 | 4134 | ||
4102 | return 0; | 4135 | return 0; |
@@ -4110,7 +4143,7 @@ static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, | |||
4110 | unsigned long flags; | 4143 | unsigned long flags; |
4111 | 4144 | ||
4112 | spin_lock_irqsave(&wl->irq_lock, flags); | 4145 | spin_lock_irqsave(&wl->irq_lock, flags); |
4113 | b43_update_templates(wl, beacon); | 4146 | b43_update_templates(wl, beacon, ctl); |
4114 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 4147 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
4115 | 4148 | ||
4116 | return 0; | 4149 | return 0; |