aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/b43/b43.h10
-rw-r--r--drivers/net/wireless/b43/main.c18
-rw-r--r--drivers/net/wireless/b43/nphy.c15
-rw-r--r--drivers/net/wireless/b43/phy_a.c11
-rw-r--r--drivers/net/wireless/b43/phy_common.c91
-rw-r--r--drivers/net/wireless/b43/phy_common.h75
-rw-r--r--drivers/net/wireless/b43/phy_g.c218
-rw-r--r--drivers/net/wireless/b43/phy_g.h22
-rw-r--r--drivers/net/wireless/b43/xmit.c2
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
2810static void b43_periodic_every30sec(struct b43_wldev *dev) 2813static 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
4209static int b43_op_set_retry_limit(struct ieee80211_hw *hw, 4216static 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
37void b43_nphy_xmitpower(struct b43_wldev *dev) 37static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
38{//TODO 38{//TODO
39} 39}
40 40
41static 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
41static void b43_chantab_radio_upload(struct b43_wldev *dev, 47static 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
605static void b43_nphy_op_xmitpower(struct b43_wldev *dev)
606{//TODO
607}
608
609const struct b43_phy_operations b43_phyops_n = { 611const 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
508static void b43_aphy_op_xmitpower(struct b43_wldev *dev) 508static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev)
509{//TODO 509{//TODO
510} 510}
511 511
512static 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
512static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) 518static 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 */
283void 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 */
299void 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
328int 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 */
69enum 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 */
310void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); 342void 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 */
354void 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 */
363enum b43_phy_txpower_check_flags {
364 B43_TXPWR_IGNORE_TIME = (1 << 0),
365 B43_TXPWR_IGNORE_TSSI = (1 << 1),
366};
367
368struct work_struct;
369void 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 */
378int 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
3014static void b43_gphy_op_xmitpower(struct b43_wldev *dev) 3015static 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
3080static 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
3181no_adjustment_needed:
3182 return B43_TXPWR_RES_DONE;
3183}
3184
3164static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) 3185static 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
116struct b43_phy_g { 116struct 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