diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/b43/nphy.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy_a.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy_common.c | 91 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy_common.h | 75 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy_g.c | 218 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy_g.h | 22 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.c | 2 |
9 files changed, 341 insertions, 121 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index fc280157596c..f9c8161671d9 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -173,6 +173,11 @@ enum { | |||
173 | #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ | 173 | #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ |
174 | #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ | 174 | #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ |
175 | #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ | 175 | #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ |
176 | /* TSSI information */ | ||
177 | #define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ | ||
178 | #define B43_SHM_SH_TSSI_OFDM_A 0x0068 /* TSSI for last 4 OFDM frames (32bit) */ | ||
179 | #define B43_SHM_SH_TSSI_OFDM_G 0x0070 /* TSSI for last 4 OFDM frames (32bit) */ | ||
180 | #define B43_TSSI_MAX 0x7F /* Max value for one TSSI value */ | ||
176 | /* SHM_SHARED TX FIFO variables */ | 181 | /* SHM_SHARED TX FIFO variables */ |
177 | #define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ | 182 | #define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ |
178 | #define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ | 183 | #define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ |
@@ -648,6 +653,11 @@ struct b43_wl { | |||
648 | struct b43_qos_params qos_params[4]; | 653 | struct b43_qos_params qos_params[4]; |
649 | /* Workqueue for updating QOS parameters in hardware. */ | 654 | /* Workqueue for updating QOS parameters in hardware. */ |
650 | struct work_struct qos_update_work; | 655 | struct work_struct qos_update_work; |
656 | |||
657 | /* Work for adjustment of the transmission power. | ||
658 | * This is scheduled when we determine that the actual TX output | ||
659 | * power doesn't match what we want. */ | ||
660 | struct work_struct txpower_adjust_work; | ||
651 | }; | 661 | }; |
652 | 662 | ||
653 | /* In-memory representation of a cached microcode file. */ | 663 | /* In-memory representation of a cached microcode file. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index af43f03b3189..63bafc2f3f0a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2805,6 +2805,9 @@ static void b43_periodic_every60sec(struct b43_wldev *dev) | |||
2805 | 2805 | ||
2806 | if (ops->pwork_60sec) | 2806 | if (ops->pwork_60sec) |
2807 | ops->pwork_60sec(dev); | 2807 | ops->pwork_60sec(dev); |
2808 | |||
2809 | /* Force check the TX power emission now. */ | ||
2810 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME); | ||
2808 | } | 2811 | } |
2809 | 2812 | ||
2810 | static void b43_periodic_every30sec(struct b43_wldev *dev) | 2813 | static void b43_periodic_every30sec(struct b43_wldev *dev) |
@@ -2835,8 +2838,6 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) | |||
2835 | if (phy->ops->pwork_15sec) | 2838 | if (phy->ops->pwork_15sec) |
2836 | phy->ops->pwork_15sec(dev); | 2839 | phy->ops->pwork_15sec(dev); |
2837 | 2840 | ||
2838 | phy->ops->xmitpower(dev); | ||
2839 | |||
2840 | atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); | 2841 | atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); |
2841 | wmb(); | 2842 | wmb(); |
2842 | } | 2843 | } |
@@ -3382,10 +3383,13 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | |||
3382 | 3383 | ||
3383 | /* Adjust the desired TX power level. */ | 3384 | /* Adjust the desired TX power level. */ |
3384 | if (conf->power_level != 0) { | 3385 | if (conf->power_level != 0) { |
3385 | if (conf->power_level != phy->power_level) { | 3386 | spin_lock_irqsave(&wl->irq_lock, flags); |
3386 | phy->power_level = conf->power_level; | 3387 | if (conf->power_level != phy->desired_txpower) { |
3387 | phy->ops->xmitpower(dev); | 3388 | phy->desired_txpower = conf->power_level; |
3389 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | | ||
3390 | B43_TXPWR_IGNORE_TSSI); | ||
3388 | } | 3391 | } |
3392 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3389 | } | 3393 | } |
3390 | 3394 | ||
3391 | /* Antennas for RX and management frame TX. */ | 3395 | /* Antennas for RX and management frame TX. */ |
@@ -3785,6 +3789,7 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, | |||
3785 | struct b43_phy *phy) | 3789 | struct b43_phy *phy) |
3786 | { | 3790 | { |
3787 | phy->hardware_power_control = !!modparam_hwpctl; | 3791 | phy->hardware_power_control = !!modparam_hwpctl; |
3792 | phy->next_txpwr_check_time = jiffies; | ||
3788 | /* PHY TX errors counter. */ | 3793 | /* PHY TX errors counter. */ |
3789 | atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); | 3794 | atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); |
3790 | } | 3795 | } |
@@ -4204,6 +4209,8 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
4204 | b43_wireless_core_stop(dev); | 4209 | b43_wireless_core_stop(dev); |
4205 | b43_wireless_core_exit(dev); | 4210 | b43_wireless_core_exit(dev); |
4206 | mutex_unlock(&wl->mutex); | 4211 | mutex_unlock(&wl->mutex); |
4212 | |||
4213 | cancel_work_sync(&(wl->txpower_adjust_work)); | ||
4207 | } | 4214 | } |
4208 | 4215 | ||
4209 | static int b43_op_set_retry_limit(struct ieee80211_hw *hw, | 4216 | static int b43_op_set_retry_limit(struct ieee80211_hw *hw, |
@@ -4581,6 +4588,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4581 | INIT_LIST_HEAD(&wl->devlist); | 4588 | INIT_LIST_HEAD(&wl->devlist); |
4582 | INIT_WORK(&wl->qos_update_work, b43_qos_update_work); | 4589 | INIT_WORK(&wl->qos_update_work, b43_qos_update_work); |
4583 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); | 4590 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); |
4591 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); | ||
4584 | 4592 | ||
4585 | ssb_set_devtypedata(dev, wl); | 4593 | ssb_set_devtypedata(dev, wl); |
4586 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); | 4594 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); |
diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 831986c459f8..4cfeab8560f6 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c | |||
@@ -34,10 +34,16 @@ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) | |||
34 | {//TODO | 34 | {//TODO |
35 | } | 35 | } |
36 | 36 | ||
37 | void b43_nphy_xmitpower(struct b43_wldev *dev) | 37 | static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) |
38 | {//TODO | 38 | {//TODO |
39 | } | 39 | } |
40 | 40 | ||
41 | static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, | ||
42 | bool ignore_tssi) | ||
43 | {//TODO | ||
44 | return B43_TXPWR_RES_DONE; | ||
45 | } | ||
46 | |||
41 | static void b43_chantab_radio_upload(struct b43_wldev *dev, | 47 | static void b43_chantab_radio_upload(struct b43_wldev *dev, |
42 | const struct b43_nphy_channeltab_entry *e) | 48 | const struct b43_nphy_channeltab_entry *e) |
43 | { | 49 | { |
@@ -602,10 +608,6 @@ static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) | |||
602 | return 36; | 608 | return 36; |
603 | } | 609 | } |
604 | 610 | ||
605 | static void b43_nphy_op_xmitpower(struct b43_wldev *dev) | ||
606 | {//TODO | ||
607 | } | ||
608 | |||
609 | const struct b43_phy_operations b43_phyops_n = { | 611 | const struct b43_phy_operations b43_phyops_n = { |
610 | .allocate = b43_nphy_op_allocate, | 612 | .allocate = b43_nphy_op_allocate, |
611 | .init = b43_nphy_op_init, | 613 | .init = b43_nphy_op_init, |
@@ -617,5 +619,6 @@ const struct b43_phy_operations b43_phyops_n = { | |||
617 | .software_rfkill = b43_nphy_op_software_rfkill, | 619 | .software_rfkill = b43_nphy_op_software_rfkill, |
618 | .switch_channel = b43_nphy_op_switch_channel, | 620 | .switch_channel = b43_nphy_op_switch_channel, |
619 | .get_default_chan = b43_nphy_op_get_default_chan, | 621 | .get_default_chan = b43_nphy_op_get_default_chan, |
620 | .xmitpower = b43_nphy_op_xmitpower, | 622 | .recalc_txpower = b43_nphy_op_recalc_txpower, |
623 | .adjust_txpower = b43_nphy_op_adjust_txpower, | ||
621 | }; | 624 | }; |
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index dd347314b76c..4d7d59e30960 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c | |||
@@ -505,10 +505,16 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) | |||
505 | b43_hf_write(dev, hf); | 505 | b43_hf_write(dev, hf); |
506 | } | 506 | } |
507 | 507 | ||
508 | static void b43_aphy_op_xmitpower(struct b43_wldev *dev) | 508 | static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) |
509 | {//TODO | 509 | {//TODO |
510 | } | 510 | } |
511 | 511 | ||
512 | static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev, | ||
513 | bool ignore_tssi) | ||
514 | {//TODO | ||
515 | return B43_TXPWR_RES_DONE; | ||
516 | } | ||
517 | |||
512 | static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) | 518 | static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) |
513 | {//TODO | 519 | {//TODO |
514 | } | 520 | } |
@@ -530,7 +536,8 @@ const struct b43_phy_operations b43_phyops_a = { | |||
530 | .switch_channel = b43_aphy_op_switch_channel, | 536 | .switch_channel = b43_aphy_op_switch_channel, |
531 | .get_default_chan = b43_aphy_op_get_default_chan, | 537 | .get_default_chan = b43_aphy_op_get_default_chan, |
532 | .set_rx_antenna = b43_aphy_op_set_rx_antenna, | 538 | .set_rx_antenna = b43_aphy_op_set_rx_antenna, |
533 | .xmitpower = b43_aphy_op_xmitpower, | 539 | .recalc_txpower = b43_aphy_op_recalc_txpower, |
540 | .adjust_txpower = b43_aphy_op_adjust_txpower, | ||
534 | .pwork_15sec = b43_aphy_op_pwork_15sec, | 541 | .pwork_15sec = b43_aphy_op_pwork_15sec, |
535 | .pwork_60sec = b43_aphy_op_pwork_60sec, | 542 | .pwork_60sec = b43_aphy_op_pwork_60sec, |
536 | }; | 543 | }; |
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 45074c05d51d..5a550a7af2e9 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c | |||
@@ -274,3 +274,94 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) | |||
274 | phy->ops->software_rfkill(dev, state); | 274 | phy->ops->software_rfkill(dev, state); |
275 | phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); | 275 | phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); |
276 | } | 276 | } |
277 | |||
278 | /** | ||
279 | * b43_phy_txpower_adjust_work - TX power workqueue. | ||
280 | * | ||
281 | * Workqueue for updating the TX power parameters in hardware. | ||
282 | */ | ||
283 | void b43_phy_txpower_adjust_work(struct work_struct *work) | ||
284 | { | ||
285 | struct b43_wl *wl = container_of(work, struct b43_wl, | ||
286 | txpower_adjust_work); | ||
287 | struct b43_wldev *dev; | ||
288 | |||
289 | mutex_lock(&wl->mutex); | ||
290 | dev = wl->current_dev; | ||
291 | |||
292 | if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED))) | ||
293 | dev->phy.ops->adjust_txpower(dev); | ||
294 | |||
295 | mutex_unlock(&wl->mutex); | ||
296 | } | ||
297 | |||
298 | /* Called with wl->irq_lock locked */ | ||
299 | void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) | ||
300 | { | ||
301 | struct b43_phy *phy = &dev->phy; | ||
302 | unsigned long now = jiffies; | ||
303 | enum b43_txpwr_result result; | ||
304 | |||
305 | if (!(flags & B43_TXPWR_IGNORE_TIME)) { | ||
306 | /* Check if it's time for a TXpower check. */ | ||
307 | if (time_before(now, phy->next_txpwr_check_time)) | ||
308 | return; /* Not yet */ | ||
309 | } | ||
310 | /* The next check will be needed in two seconds, or later. */ | ||
311 | phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); | ||
312 | |||
313 | if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && | ||
314 | (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306)) | ||
315 | return; /* No software txpower adjustment needed */ | ||
316 | |||
317 | result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); | ||
318 | if (result == B43_TXPWR_RES_DONE) | ||
319 | return; /* We are done. */ | ||
320 | B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST); | ||
321 | B43_WARN_ON(phy->ops->adjust_txpower == NULL); | ||
322 | |||
323 | /* We must adjust the transmission power in hardware. | ||
324 | * Schedule b43_phy_txpower_adjust_work(). */ | ||
325 | queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); | ||
326 | } | ||
327 | |||
328 | int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) | ||
329 | { | ||
330 | const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK); | ||
331 | unsigned int a, b, c, d; | ||
332 | unsigned int average; | ||
333 | u32 tmp; | ||
334 | |||
335 | tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset); | ||
336 | a = tmp & 0xFF; | ||
337 | b = (tmp >> 8) & 0xFF; | ||
338 | c = (tmp >> 16) & 0xFF; | ||
339 | d = (tmp >> 24) & 0xFF; | ||
340 | if (a == 0 || a == B43_TSSI_MAX || | ||
341 | b == 0 || b == B43_TSSI_MAX || | ||
342 | c == 0 || c == B43_TSSI_MAX || | ||
343 | d == 0 || d == B43_TSSI_MAX) | ||
344 | return -ENOENT; | ||
345 | /* The values are OK. Clear them. */ | ||
346 | tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) | | ||
347 | (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24); | ||
348 | b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp); | ||
349 | |||
350 | if (is_ofdm) { | ||
351 | a = (a + 32) & 0x3F; | ||
352 | b = (b + 32) & 0x3F; | ||
353 | c = (c + 32) & 0x3F; | ||
354 | d = (d + 32) & 0x3F; | ||
355 | } | ||
356 | |||
357 | /* Get the average of the values with 0.5 added to each value. */ | ||
358 | average = (a + b + c + d + 2) / 4; | ||
359 | if (is_ofdm) { | ||
360 | /* Adjust for CCK-boost */ | ||
361 | if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO) | ||
362 | & B43_HF_CCKBOOST) | ||
363 | average = (average >= 13) ? (average - 13) : 0; | ||
364 | } | ||
365 | |||
366 | return average; | ||
367 | } | ||
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9b9635eda9c4..f8db9f40df5d 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h | |||
@@ -61,6 +61,17 @@ enum { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | /** | 63 | /** |
64 | * enum b43_txpwr_result - Return value for the recalc_txpower PHY op. | ||
65 | * | ||
66 | * @B43_TXPWR_RES_NEED_ADJUST: Values changed. Hardware adjustment is needed. | ||
67 | * @B43_TXPWR_RES_DONE: No more work to do. Everything is done. | ||
68 | */ | ||
69 | enum b43_txpwr_result { | ||
70 | B43_TXPWR_RES_NEED_ADJUST, | ||
71 | B43_TXPWR_RES_DONE, | ||
72 | }; | ||
73 | |||
74 | /** | ||
64 | * struct b43_phy_operations - Function pointers for PHY ops. | 75 | * struct b43_phy_operations - Function pointers for PHY ops. |
65 | * | 76 | * |
66 | * @prepare: Prepare the PHY. This is called before @init. | 77 | * @prepare: Prepare the PHY. This is called before @init. |
@@ -96,8 +107,23 @@ enum { | |||
96 | * @interf_mitigation: Switch the Interference Mitigation mode. | 107 | * @interf_mitigation: Switch the Interference Mitigation mode. |
97 | * Can be NULL, if not supported. | 108 | * Can be NULL, if not supported. |
98 | * | 109 | * |
99 | * @xmitpower: FIXME REMOVEME | 110 | * @recalc_txpower: Recalculate the transmission power parameters. |
111 | * This callback has to recalculate the TX power settings, | ||
112 | * but does not need to write them to the hardware, yet. | ||
113 | * Returns enum b43_txpwr_result to indicate whether the hardware | ||
114 | * needs to be adjusted. | ||
115 | * If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower | ||
116 | * will be called later. | ||
117 | * If the parameter "ignore_tssi" is true, the TSSI values should | ||
118 | * be ignored and a recalculation of the power settings should be | ||
119 | * done even if the TSSI values did not change. | ||
120 | * This callback is called with wl->irq_lock held and must not sleep. | ||
100 | * Must not be NULL. | 121 | * Must not be NULL. |
122 | * @adjust_txpower: Write the previously calculated TX power settings | ||
123 | * (from @recalc_txpower) to the hardware. | ||
124 | * This function may sleep. | ||
125 | * Can be NULL, if (and ONLY if) @recalc_txpower _always_ | ||
126 | * returns B43_TXPWR_RES_DONE. | ||
101 | * | 127 | * |
102 | * @pwork_15sec: Periodic work. Called every 15 seconds. | 128 | * @pwork_15sec: Periodic work. Called every 15 seconds. |
103 | * Can be NULL, if not required. | 129 | * Can be NULL, if not required. |
@@ -127,7 +153,9 @@ struct b43_phy_operations { | |||
127 | enum b43_interference_mitigation new_mode); | 153 | enum b43_interference_mitigation new_mode); |
128 | 154 | ||
129 | /* Transmission power adjustment */ | 155 | /* Transmission power adjustment */ |
130 | void (*xmitpower)(struct b43_wldev *dev); | 156 | enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev, |
157 | bool ignore_tssi); | ||
158 | void (*adjust_txpower)(struct b43_wldev *dev); | ||
131 | 159 | ||
132 | /* Misc */ | 160 | /* Misc */ |
133 | void (*pwork_15sec)(struct b43_wldev *dev); | 161 | void (*pwork_15sec)(struct b43_wldev *dev); |
@@ -183,11 +211,15 @@ struct b43_phy { | |||
183 | 211 | ||
184 | /* Desired TX power level (in dBm). | 212 | /* Desired TX power level (in dBm). |
185 | * This is set by the user and adjusted in b43_phy_xmitpower(). */ | 213 | * This is set by the user and adjusted in b43_phy_xmitpower(). */ |
186 | u8 power_level; | 214 | int desired_txpower; |
187 | 215 | ||
188 | /* Hardware Power Control enabled? */ | 216 | /* Hardware Power Control enabled? */ |
189 | bool hardware_power_control; | 217 | bool hardware_power_control; |
190 | 218 | ||
219 | /* The time (in absolute jiffies) when the next TX power output | ||
220 | * check is needed. */ | ||
221 | unsigned long next_txpwr_check_time; | ||
222 | |||
191 | /* current channel */ | 223 | /* current channel */ |
192 | unsigned int channel; | 224 | unsigned int channel; |
193 | 225 | ||
@@ -309,4 +341,41 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); | |||
309 | */ | 341 | */ |
310 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); | 342 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); |
311 | 343 | ||
344 | /** | ||
345 | * b43_phy_txpower_check - Check TX power output. | ||
346 | * | ||
347 | * Compare the current TX power output to the desired power emission | ||
348 | * and schedule an adjustment in case it mismatches. | ||
349 | * Requires wl->irq_lock locked. | ||
350 | * | ||
351 | * @flags: OR'ed enum b43_phy_txpower_check_flags flags. | ||
352 | * See the docs below. | ||
353 | */ | ||
354 | void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags); | ||
355 | /** | ||
356 | * enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check() | ||
357 | * | ||
358 | * @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo | ||
359 | * the check now. | ||
360 | * @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average | ||
361 | * TSSI did not change. | ||
362 | */ | ||
363 | enum b43_phy_txpower_check_flags { | ||
364 | B43_TXPWR_IGNORE_TIME = (1 << 0), | ||
365 | B43_TXPWR_IGNORE_TSSI = (1 << 1), | ||
366 | }; | ||
367 | |||
368 | struct work_struct; | ||
369 | void b43_phy_txpower_adjust_work(struct work_struct *work); | ||
370 | |||
371 | /** | ||
372 | * b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM. | ||
373 | * | ||
374 | * @shm_offset: The SHM address to read the values from. | ||
375 | * | ||
376 | * Returns the average of the 4 TSSI values, or a negative error code. | ||
377 | */ | ||
378 | int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); | ||
379 | |||
380 | |||
312 | #endif /* LINUX_B43_PHY_COMMON_H_ */ | 381 | #endif /* LINUX_B43_PHY_COMMON_H_ */ |
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index bb95c54cd43d..fce84896d34c 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c | |||
@@ -2659,6 +2659,7 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) | |||
2659 | /* OFDM-table address caching. */ | 2659 | /* OFDM-table address caching. */ |
2660 | gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; | 2660 | gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; |
2661 | 2661 | ||
2662 | gphy->average_tssi = 0xFF; | ||
2662 | 2663 | ||
2663 | lo = kzalloc(sizeof(*lo), GFP_KERNEL); | 2664 | lo = kzalloc(sizeof(*lo), GFP_KERNEL); |
2664 | if (!lo) { | 2665 | if (!lo) { |
@@ -3011,113 +3012,20 @@ static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, | |||
3011 | *_bbatt = clamp_val(bbatt, bb_min, bb_max); | 3012 | *_bbatt = clamp_val(bbatt, bb_min, bb_max); |
3012 | } | 3013 | } |
3013 | 3014 | ||
3014 | static void b43_gphy_op_xmitpower(struct b43_wldev *dev) | 3015 | static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) |
3015 | { | 3016 | { |
3016 | struct ssb_bus *bus = dev->dev->bus; | ||
3017 | struct b43_phy *phy = &dev->phy; | 3017 | struct b43_phy *phy = &dev->phy; |
3018 | struct b43_phy_g *gphy = phy->g; | 3018 | struct b43_phy_g *gphy = phy->g; |
3019 | u16 tmp; | ||
3020 | s8 v0, v1, v2, v3; | ||
3021 | s8 average; | ||
3022 | int max_pwr; | ||
3023 | int desired_pwr, estimated_pwr, pwr_adjust; | ||
3024 | int rfatt_delta, bbatt_delta; | ||
3025 | int rfatt, bbatt; | 3019 | int rfatt, bbatt; |
3026 | u8 tx_control; | 3020 | u8 tx_control; |
3027 | 3021 | ||
3028 | if (gphy->cur_idle_tssi == 0) | 3022 | spin_lock_irq(&dev->wl->irq_lock); |
3029 | return; | ||
3030 | if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && | ||
3031 | (bus->boardinfo.type == SSB_BOARD_BU4306)) | ||
3032 | return; | ||
3033 | |||
3034 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); | ||
3035 | v0 = (s8) (tmp & 0x00FF); | ||
3036 | v1 = (s8) ((tmp & 0xFF00) >> 8); | ||
3037 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); | ||
3038 | v2 = (s8) (tmp & 0x00FF); | ||
3039 | v3 = (s8) ((tmp & 0xFF00) >> 8); | ||
3040 | tmp = 0; | ||
3041 | |||
3042 | if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F | ||
3043 | || v3 == 0x7F) { | ||
3044 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); | ||
3045 | v0 = (s8) (tmp & 0x00FF); | ||
3046 | v1 = (s8) ((tmp & 0xFF00) >> 8); | ||
3047 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); | ||
3048 | v2 = (s8) (tmp & 0x00FF); | ||
3049 | v3 = (s8) ((tmp & 0xFF00) >> 8); | ||
3050 | if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F | ||
3051 | || v3 == 0x7F) | ||
3052 | return; | ||
3053 | v0 = (v0 + 0x20) & 0x3F; | ||
3054 | v1 = (v1 + 0x20) & 0x3F; | ||
3055 | v2 = (v2 + 0x20) & 0x3F; | ||
3056 | v3 = (v3 + 0x20) & 0x3F; | ||
3057 | tmp = 1; | ||
3058 | } | ||
3059 | b43_shm_clear_tssi(dev); | ||
3060 | |||
3061 | average = (v0 + v1 + v2 + v3 + 2) / 4; | ||
3062 | |||
3063 | if (tmp && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & 0x8)) | ||
3064 | average -= 13; | ||
3065 | |||
3066 | estimated_pwr = b43_gphy_estimate_power_out(dev, average); | ||
3067 | |||
3068 | max_pwr = dev->dev->bus->sprom.maxpwr_bg; | ||
3069 | if ((dev->dev->bus->sprom.boardflags_lo | ||
3070 | & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) | ||
3071 | max_pwr -= 0x3; | ||
3072 | if (unlikely(max_pwr <= 0)) { | ||
3073 | b43warn(dev->wl, | ||
3074 | "Invalid max-TX-power value in SPROM.\n"); | ||
3075 | max_pwr = 60; /* fake it */ | ||
3076 | dev->dev->bus->sprom.maxpwr_bg = max_pwr; | ||
3077 | } | ||
3078 | |||
3079 | /*TODO: | ||
3080 | max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) | ||
3081 | where REG is the max power as per the regulatory domain | ||
3082 | */ | ||
3083 | |||
3084 | /* Get desired power (in Q5.2) */ | ||
3085 | desired_pwr = INT_TO_Q52(phy->power_level); | ||
3086 | /* And limit it. max_pwr already is Q5.2 */ | ||
3087 | desired_pwr = clamp_val(desired_pwr, 0, max_pwr); | ||
3088 | if (b43_debug(dev, B43_DBG_XMITPOWER)) { | ||
3089 | b43dbg(dev->wl, | ||
3090 | "Current TX power output: " Q52_FMT | ||
3091 | " dBm, " "Desired TX power output: " | ||
3092 | Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), | ||
3093 | Q52_ARG(desired_pwr)); | ||
3094 | } | ||
3095 | |||
3096 | /* Calculate the adjustment delta. */ | ||
3097 | pwr_adjust = desired_pwr - estimated_pwr; | ||
3098 | |||
3099 | /* RF attenuation delta. */ | ||
3100 | rfatt_delta = ((pwr_adjust + 7) / 8); | ||
3101 | /* Lower attenuation => Bigger power output. Negate it. */ | ||
3102 | rfatt_delta = -rfatt_delta; | ||
3103 | |||
3104 | /* Baseband attenuation delta. */ | ||
3105 | bbatt_delta = pwr_adjust / 2; | ||
3106 | /* Lower attenuation => Bigger power output. Negate it. */ | ||
3107 | bbatt_delta = -bbatt_delta; | ||
3108 | /* RF att affects power level 4 times as much as | ||
3109 | * Baseband attennuation. Subtract it. */ | ||
3110 | bbatt_delta -= 4 * rfatt_delta; | ||
3111 | |||
3112 | /* So do we finally need to adjust something? */ | ||
3113 | if ((rfatt_delta == 0) && (bbatt_delta == 0)) | ||
3114 | return; | ||
3115 | 3023 | ||
3116 | /* Calculate the new attenuation values. */ | 3024 | /* Calculate the new attenuation values. */ |
3117 | bbatt = gphy->bbatt.att; | 3025 | bbatt = gphy->bbatt.att; |
3118 | bbatt += bbatt_delta; | 3026 | bbatt += gphy->bbatt_delta; |
3119 | rfatt = gphy->rfatt.att; | 3027 | rfatt = gphy->rfatt.att; |
3120 | rfatt += rfatt_delta; | 3028 | rfatt += gphy->rfatt_delta; |
3121 | 3029 | ||
3122 | b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); | 3030 | b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); |
3123 | tx_control = gphy->tx_control; | 3031 | tx_control = gphy->tx_control; |
@@ -3152,6 +3060,14 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) | |||
3152 | gphy->rfatt.att = rfatt; | 3060 | gphy->rfatt.att = rfatt; |
3153 | gphy->bbatt.att = bbatt; | 3061 | gphy->bbatt.att = bbatt; |
3154 | 3062 | ||
3063 | /* We drop the lock early, so we can sleep during hardware | ||
3064 | * adjustment. Possible races with op_recalc_txpower are harmless, | ||
3065 | * as we will be called once again in case we raced. */ | ||
3066 | spin_unlock_irq(&dev->wl->irq_lock); | ||
3067 | |||
3068 | if (b43_debug(dev, B43_DBG_XMITPOWER)) | ||
3069 | b43dbg(dev->wl, "Adjusting TX power\n"); | ||
3070 | |||
3155 | /* Adjust the hardware */ | 3071 | /* Adjust the hardware */ |
3156 | b43_phy_lock(dev); | 3072 | b43_phy_lock(dev); |
3157 | b43_radio_lock(dev); | 3073 | b43_radio_lock(dev); |
@@ -3161,6 +3077,111 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) | |||
3161 | b43_phy_unlock(dev); | 3077 | b43_phy_unlock(dev); |
3162 | } | 3078 | } |
3163 | 3079 | ||
3080 | static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, | ||
3081 | bool ignore_tssi) | ||
3082 | { | ||
3083 | struct b43_phy *phy = &dev->phy; | ||
3084 | struct b43_phy_g *gphy = phy->g; | ||
3085 | unsigned int average_tssi; | ||
3086 | int cck_result, ofdm_result; | ||
3087 | int estimated_pwr, desired_pwr, pwr_adjust; | ||
3088 | int rfatt_delta, bbatt_delta; | ||
3089 | unsigned int max_pwr; | ||
3090 | |||
3091 | /* First get the average TSSI */ | ||
3092 | cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK); | ||
3093 | ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G); | ||
3094 | if ((cck_result < 0) && (ofdm_result < 0)) { | ||
3095 | /* No TSSI information available */ | ||
3096 | if (!ignore_tssi) | ||
3097 | goto no_adjustment_needed; | ||
3098 | cck_result = 0; | ||
3099 | ofdm_result = 0; | ||
3100 | } | ||
3101 | if (cck_result < 0) | ||
3102 | average_tssi = ofdm_result; | ||
3103 | else if (ofdm_result < 0) | ||
3104 | average_tssi = cck_result; | ||
3105 | else | ||
3106 | average_tssi = (cck_result + ofdm_result) / 2; | ||
3107 | /* Merge the average with the stored value. */ | ||
3108 | if (likely(gphy->average_tssi != 0xFF)) | ||
3109 | average_tssi = (average_tssi + gphy->average_tssi) / 2; | ||
3110 | gphy->average_tssi = average_tssi; | ||
3111 | B43_WARN_ON(average_tssi >= B43_TSSI_MAX); | ||
3112 | |||
3113 | /* Estimate the TX power emission based on the TSSI */ | ||
3114 | estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi); | ||
3115 | |||
3116 | B43_WARN_ON(phy->type != B43_PHYTYPE_G); | ||
3117 | max_pwr = dev->dev->bus->sprom.maxpwr_bg; | ||
3118 | if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) | ||
3119 | max_pwr -= 3; /* minus 0.75 */ | ||
3120 | if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) { | ||
3121 | b43warn(dev->wl, | ||
3122 | "Invalid max-TX-power value in SPROM.\n"); | ||
3123 | max_pwr = INT_TO_Q52(20); /* fake it */ | ||
3124 | dev->dev->bus->sprom.maxpwr_bg = max_pwr; | ||
3125 | } | ||
3126 | |||
3127 | /* Get desired power (in Q5.2) */ | ||
3128 | if (phy->desired_txpower < 0) | ||
3129 | desired_pwr = INT_TO_Q52(0); | ||
3130 | else | ||
3131 | desired_pwr = INT_TO_Q52(phy->desired_txpower); | ||
3132 | /* And limit it. max_pwr already is Q5.2 */ | ||
3133 | desired_pwr = clamp_val(desired_pwr, 0, max_pwr); | ||
3134 | if (b43_debug(dev, B43_DBG_XMITPOWER)) { | ||
3135 | b43dbg(dev->wl, | ||
3136 | "[TX power] current = " Q52_FMT | ||
3137 | " dBm, desired = " Q52_FMT | ||
3138 | " dBm, max = " Q52_FMT "\n", | ||
3139 | Q52_ARG(estimated_pwr), | ||
3140 | Q52_ARG(desired_pwr), | ||
3141 | Q52_ARG(max_pwr)); | ||
3142 | } | ||
3143 | |||
3144 | /* Calculate the adjustment delta. */ | ||
3145 | pwr_adjust = desired_pwr - estimated_pwr; | ||
3146 | if (pwr_adjust == 0) | ||
3147 | goto no_adjustment_needed; | ||
3148 | |||
3149 | /* RF attenuation delta. */ | ||
3150 | rfatt_delta = ((pwr_adjust + 7) / 8); | ||
3151 | /* Lower attenuation => Bigger power output. Negate it. */ | ||
3152 | rfatt_delta = -rfatt_delta; | ||
3153 | |||
3154 | /* Baseband attenuation delta. */ | ||
3155 | bbatt_delta = pwr_adjust / 2; | ||
3156 | /* Lower attenuation => Bigger power output. Negate it. */ | ||
3157 | bbatt_delta = -bbatt_delta; | ||
3158 | /* RF att affects power level 4 times as much as | ||
3159 | * Baseband attennuation. Subtract it. */ | ||
3160 | bbatt_delta -= 4 * rfatt_delta; | ||
3161 | |||
3162 | if (b43_debug(dev, B43_DBG_XMITPOWER)) { | ||
3163 | int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust; | ||
3164 | b43dbg(dev->wl, | ||
3165 | "[TX power deltas] %s" Q52_FMT " dBm => " | ||
3166 | "bbatt-delta = %d, rfatt-delta = %d\n", | ||
3167 | (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm), | ||
3168 | bbatt_delta, rfatt_delta); | ||
3169 | } | ||
3170 | /* So do we finally need to adjust something in hardware? */ | ||
3171 | if ((rfatt_delta == 0) && (bbatt_delta == 0)) | ||
3172 | goto no_adjustment_needed; | ||
3173 | |||
3174 | /* Save the deltas for later when we adjust the power. */ | ||
3175 | gphy->bbatt_delta = bbatt_delta; | ||
3176 | gphy->rfatt_delta = rfatt_delta; | ||
3177 | |||
3178 | /* We need to adjust the TX power on the device. */ | ||
3179 | return B43_TXPWR_RES_NEED_ADJUST; | ||
3180 | |||
3181 | no_adjustment_needed: | ||
3182 | return B43_TXPWR_RES_DONE; | ||
3183 | } | ||
3184 | |||
3164 | static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) | 3185 | static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) |
3165 | { | 3186 | { |
3166 | struct b43_phy *phy = &dev->phy; | 3187 | struct b43_phy *phy = &dev->phy; |
@@ -3223,7 +3244,8 @@ const struct b43_phy_operations b43_phyops_g = { | |||
3223 | .get_default_chan = b43_gphy_op_get_default_chan, | 3244 | .get_default_chan = b43_gphy_op_get_default_chan, |
3224 | .set_rx_antenna = b43_gphy_op_set_rx_antenna, | 3245 | .set_rx_antenna = b43_gphy_op_set_rx_antenna, |
3225 | .interf_mitigation = b43_gphy_op_interf_mitigation, | 3246 | .interf_mitigation = b43_gphy_op_interf_mitigation, |
3226 | .xmitpower = b43_gphy_op_xmitpower, | 3247 | .recalc_txpower = b43_gphy_op_recalc_txpower, |
3248 | .adjust_txpower = b43_gphy_op_adjust_txpower, | ||
3227 | .pwork_15sec = b43_gphy_op_pwork_15sec, | 3249 | .pwork_15sec = b43_gphy_op_pwork_15sec, |
3228 | .pwork_60sec = b43_gphy_op_pwork_60sec, | 3250 | .pwork_60sec = b43_gphy_op_pwork_60sec, |
3229 | }; | 3251 | }; |
diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 1f0daebd6eb6..7f95edea1c63 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h | |||
@@ -115,7 +115,6 @@ struct b43_txpower_lo_control; | |||
115 | 115 | ||
116 | struct b43_phy_g { | 116 | struct b43_phy_g { |
117 | bool initialised; | 117 | bool initialised; |
118 | bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ | ||
119 | 118 | ||
120 | /* ACI (adjacent channel interference) flags. */ | 119 | /* ACI (adjacent channel interference) flags. */ |
121 | bool aci_enable; | 120 | bool aci_enable; |
@@ -135,12 +134,26 @@ struct b43_phy_g { | |||
135 | u16 minlowsig[2]; | 134 | u16 minlowsig[2]; |
136 | u16 minlowsigpos[2]; | 135 | u16 minlowsigpos[2]; |
137 | 136 | ||
138 | /* TSSI to dBm table in use */ | 137 | /* Pointer to the table used to convert a |
138 | * TSSI value to dBm-Q5.2 */ | ||
139 | const s8 *tssi2dbm; | 139 | const s8 *tssi2dbm; |
140 | /* tssi2dbm is kmalloc()ed. Only used for free()ing. */ | ||
141 | bool dyn_tssi_tbl; | ||
140 | /* Target idle TSSI */ | 142 | /* Target idle TSSI */ |
141 | int tgt_idle_tssi; | 143 | int tgt_idle_tssi; |
142 | /* Current idle TSSI */ | 144 | /* Current idle TSSI */ |
143 | int cur_idle_tssi; | 145 | int cur_idle_tssi; |
146 | /* The current average TSSI. | ||
147 | * Needs irq_lock, as it's updated in the IRQ path. */ | ||
148 | u8 average_tssi; | ||
149 | /* Current TX power level attenuation control values */ | ||
150 | struct b43_bbatt bbatt; | ||
151 | struct b43_rfatt rfatt; | ||
152 | u8 tx_control; /* B43_TXCTL_XXX */ | ||
153 | /* The calculated attenuation deltas that are used later | ||
154 | * when adjusting the actual power output. */ | ||
155 | int bbatt_delta; | ||
156 | int rfatt_delta; | ||
144 | 157 | ||
145 | /* LocalOscillator control values. */ | 158 | /* LocalOscillator control values. */ |
146 | struct b43_txpower_lo_control *lo_control; | 159 | struct b43_txpower_lo_control *lo_control; |
@@ -151,11 +164,6 @@ struct b43_phy_g { | |||
151 | s16 lna_gain; /* LNA */ | 164 | s16 lna_gain; /* LNA */ |
152 | s16 pga_gain; /* PGA */ | 165 | s16 pga_gain; /* PGA */ |
153 | 166 | ||
154 | /* Current TX power level attenuation control values */ | ||
155 | struct b43_bbatt bbatt; | ||
156 | struct b43_rfatt rfatt; | ||
157 | u8 tx_control; /* B43_TXCTL_XXX */ | ||
158 | |||
159 | /* Current Interference Mitigation mode */ | 167 | /* Current Interference Mitigation mode */ |
160 | int interfmode; | 168 | int interfmode; |
161 | /* Stack of saved values from the Interference Mitigation code. | 169 | /* Stack of saved values from the Interference Mitigation code. |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index c8a831234e4a..5e0b71c3ad02 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -680,6 +680,8 @@ void b43_handle_txstatus(struct b43_wldev *dev, | |||
680 | b43_pio_handle_txstatus(dev, status); | 680 | b43_pio_handle_txstatus(dev, status); |
681 | else | 681 | else |
682 | b43_dma_handle_txstatus(dev, status); | 682 | b43_dma_handle_txstatus(dev, status); |
683 | |||
684 | b43_phy_txpower_check(dev, 0); | ||
683 | } | 685 | } |
684 | 686 | ||
685 | /* Fill out the mac80211 TXstatus report based on the b43-specific | 687 | /* Fill out the mac80211 TXstatus report based on the b43-specific |