Linux wireless drivers development
 help / color / mirror / Atom feed
* rtl8187b Problem with tx level
From: Tobias Schlemmer @ 2009-08-30 20:44 UTC (permalink / raw)
  To: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1527 bytes --]

Hi,

I have some problem with my rtl8187b device. It is included in my laptop 
running Ubuntu linux 2.6.28. I've tested several compat-wireless 
releases including 2.6.30 and 2.6.31-rc7.

The problem is that the network adapter looses the connection to the 
access point at very low distances. It seems to be as if the driver is 
too optimistic about tx power. I monitored the singnal strength on the 
access point (Buffalo running DD-WRT). When I associate the laptop with 
it the recieved signal strength starts full and drops rapidly in the 
first seconds. At the end it is about 0 at a distance of 4m. At this 
moment no ping will arrive the destination. Tests with other access 
points show similar results.

After several attempts to get different drivers working I used an Ubuntu 
8.04 boot CD this morning which seems to work out of the box. It has 
kernel 2.6.24 using a module called r8187. I compared these two drivers 
and got much better signal strengths, at least more stable connections. 
Maybe it's interesting that the two drivers report different signal 
strength (compat-wireless reports about 10dBm higher values than the old 
driver) also in signal quality the compat wireless driver seems to be 
more optimistic.

Interestingly iwconfig always reports TX power of 20dBm, regardless of 
the actual tx power, but always a TX rate of 1M. Setting the latter to a 
higher value results in packet loss.

As I leave for holidays on Tuesday I can give further information only 
tomorrow and in two weeks.

Tobias

[-- Attachment #2: eventlog --]
[-- Type: text/plain, Size: 3844 bytes --]

Log of iw event -t 
Sun Aug 30 21:26:57 2009

iwdied with signal 2

Sun Aug 30 21:27:22 2009
----------------
1251660460.087134: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660481.753561: wlan0 (phy #0): disassoc 00:16:44:fb:52:6c -> 00:17:3f:7e:ab:08 reason 1: Unspecified
1251660486.831135: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660487.041865: wlan0 (phy #0): auth 00:17:3f:7e:ab:08 -> 00:16:44:fb:52:6c status: 0: Successful
1251660487.050600: wlan0 (phy #0): assoc 00:17:3f:7e:ab:08 -> 00:16:44:fb:52:6c status: 0: Successful
1251660588.213505: wlan0 (phy #0): deauth 00:16:44:fb:52:6c -> 00:17:3f:7e:ab:08 reason 3: Deauthenticated because sending station is leaving (or has left) the IBSS or ESS
1251660600.900453: wlan0 (phy #0): scan aborted: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660607.237699: wlan0 (phy #0): disassoc 00:16:44:fb:52:6c -> 00:17:3f:7e:ab:08 reason 1: Unspecified
1251660613.427166: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660614.348485: wlan0 (phy #0): auth: timed out
1251660620.263160: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660621.152487: wlan0 (phy #0): auth: timed out
1251660626.311193: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660627.200489: wlan0 (phy #0): auth: timed out
1251660632.359167: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660633.248491: wlan0 (phy #0): auth: timed out
1251660638.415165: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660639.304490: wlan0 (phy #0): auth: timed out
1251660644.467730: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660645.356493: wlan0 (phy #0): auth: timed out
1251660650.519172: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660651.419254: wlan0 (phy #0): auth: timed out
1251660656.587182: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660657.512517: wlan0 (phy #0): auth: timed out
1251660662.655181: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660663.532509: wlan0 (phy #0): auth: timed out
1251660668.711181: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660669.588513: wlan0 (phy #0): auth: timed out
1251660674.779164: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660675.656519: wlan0 (phy #0): auth: timed out
1251660680.943163: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660681.836528: wlan0 (phy #0): auth: timed out
1251660686.879163: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660687.768520: wlan0 (phy #0): auth: timed out
1251660692.927168: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660693.816525: wlan0 (phy #0): auth: timed out
1251660698.975165: wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484, ""
1251660699.400865: wlan0 (phy #0): auth 00:17:3f:7e:ab:08 -> 00:16:44:fb:52:6c status: 0: Successful
1251660699.412964: wlan0 (phy #0): assoc 00:17:3f:7e:ab:08 -> 00:16:44:fb:52:6c status: 0: Successful


[-- Attachment #3: kernel-short.log --]
[-- Type: text/x-log, Size: 3813 bytes --]

[  346.940054] usb 1-1: new high speed USB device using ehci_hcd and address 4
[  347.086851] usb 1-1: configuration #1 chosen from 1 choice
[  347.418280] cfg80211: Calling CRDA for country: EU
[  348.348579] phy0: Selected rate control algorithm 'minstrel'
[  348.349108] phy0: hwaddr e3c7a080, RTL8187BvE V0 + rtl8225z2
[  348.349131] usbcore: registered new interface driver rtl8187
[  361.807409] phy0: device now idle
[  361.878423] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  361.893826] phy0: device no longer idle - scanning
[  364.225226] phy0: device now idle
[  364.806379] phy0: device no longer idle - scanning
[  366.893227] phy0: device now idle
[  390.835706] phy0: device no longer idle - scanning
[  392.917362] phy0: device now idle
[  412.002426] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  412.371061] phy0: device no longer idle - scanning
[  414.498373] wlan0: authenticate with AP e3c7b708
[  414.498397] wlan0: privacy configuration mismatch and mixed-cell disabled - disassociate
[  414.499742] phy0: device now idle
[  417.572157] phy0: device no longer idle - scanning
[  419.649259] phy0: device now idle
[  419.718250] phy0: device no longer idle - in use
[  419.785249] wlan0: authenticate with AP e3c7b708
[  419.786755] wlan0: authenticated
[  419.786756] wlan0: associate with AP e3c7b708
[  419.789134] wlan0: RX AssocResp from e3f8201a (capab=0x411 status=0 aid=3)
[  419.789138] wlan0: associated
[  419.789142] phy0: Allocated STA e3c00a08
[  419.789403] phy0: Inserted STA e3c00a08
[  419.790372] wlan0: switched to short barker preamble (BSSID=e3c7b708)
[  419.790374] wlan0: switched to short slot time (BSSID=e3c7b708)
[  419.795862] ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
[  420.664625] padlock: VIA PadLock not detected.
[  426.992527] wlan0: setting MTU 1492
[  429.796020] wlan0: no IPv6 routers present
[  465.032820] usb 2-2: USB disconnect, address 2
[  520.958259] wlan0: deauthenticating by local choice (reason=3)
[  520.959293] phy0: device now idle
[  521.037304] phy0: Removed STA e3c00a08
[  521.037411] phy0: Destroyed STA e3c00a08
[  524.902800] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  533.450798] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  533.452844] phy0: device no longer idle - scanning
[  533.645340] phy0: device now idle
[  537.890760] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  537.890876] phy0: device no longer idle - scanning
[  539.982438] wlan0: direct probe to AP e3c7b708 try 1
[  539.982476] wlan0: privacy configuration mismatch and mixed-cell disabled - disassociate
[  539.983926] phy0: device now idle
[  543.973724] phy0: device no longer idle - scanning
[  546.270791] phy0: device now idle
[  546.358314] phy0: device no longer idle - in use
[  546.425311] wlan0: direct probe to AP e3c7b708 try 1
[  546.624050] wlan0: direct probe to AP e3c7b708 try 2
[  546.824039] wlan0: direct probe to AP e3c7b708 try 3
[  547.024037] wlan0: direct probe to AP e3c7b708 timed out
[  547.024044] phy0: device now idle
[  551.030732] phy0: device no longer idle - scanning
[  553.093323] phy0: device now idle
[  553.162315] phy0: device no longer idle - in use
[  553.229316] wlan0: direct probe to AP e3c7b708 try 1
[  553.428042] wlan0: direct probe to AP e3c7b708 try 2
[  553.628037] wlan0: direct probe to AP e3c7b708 try 3
[  553.828036] wlan0: direct probe to AP e3c7b708 timed out
[  553.828043] phy0: device now idle
[  557.082433] phy0: device no longer idle - scanning
[  559.141327] phy0: device now idle
[  559.210312] phy0: device no longer idle - in use
[  559.277319] wlan0: direct probe to AP e3c7b708 try 1
[  559.476045] wlan0: direct probe to AP e3c7b708 try 2
[  559.676044] wlan0: direct probe to AP e3c7b708 try 3
[  559.876044] wlan0: direct probe to AP e3c7b708 timed out


[-- Attachment #4: lsusb --]
[-- Type: text/plain, Size: 5080 bytes --]

Bus 001 Device 004: ID 0bda:8189 Realtek Semiconductor Corp. RTL8187B Wireless 802.11g 54Mbps Network Adapter
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x0bda Realtek Semiconductor Corp.
  idProduct          0x8189 RTL8187B Wireless 802.11g 54Mbps Network Adapter
  bcdDevice            2.00
  iManufacturer           1 Manufacturer_Realtek
  iProduct                2 
  iSerial                 3 00e04c000001
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           81
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 Wireless Network Card
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           9
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              2 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x05  EP 5 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x06  EP 6 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x07  EP 7 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x89  EP 9 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x0a  EP 10 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x0b  EP 11 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x0c  EP 12 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0000
  (Bus Powered)


^ permalink raw reply

* [PATCH -next] ipw2200: fix kconfig dependencies
From: Randy Dunlap @ 2009-08-30 20:22 UTC (permalink / raw)
  To: linux-wireless; +Cc: ipw2100-devel, linville, akpm

From: Randy Dunlap <randy.dunlap@oracle.com>

Fix kconfig dependencies for ipw2x00 drivers, fixes build errors:

ERROR: "wiphy_free" [drivers/net/wireless/ipw2x00/libipw.ko] undefined!
ERROR: "wiphy_unregister" [drivers/net/wireless/ipw2x00/libipw.ko] undefined!
ERROR: "wiphy_new" [drivers/net/wireless/ipw2x00/libipw.ko] undefined!
ERROR: "cfg80211_wext_giwname" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined!
ERROR: "wiphy_register" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined!

Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
---
 drivers/net/wireless/ipw2x00/Kconfig |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- linux-next-20090828.orig/drivers/net/wireless/ipw2x00/Kconfig
+++ linux-next-20090828/drivers/net/wireless/ipw2x00/Kconfig
@@ -4,7 +4,7 @@
 
 config IPW2100
 	tristate "Intel PRO/Wireless 2100 Network Connection"
-	depends on PCI && WLAN_80211
+	depends on PCI && WLAN_80211 && CFG80211
 	select WIRELESS_EXT
 	select FW_LOADER
 	select LIB80211
@@ -63,7 +63,7 @@ config IPW2100_DEBUG
 
 config IPW2200
 	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-	depends on PCI && WLAN_80211
+	depends on PCI && WLAN_80211 && CFG80211
 	select WIRELESS_EXT
 	select FW_LOADER
 	select LIB80211
@@ -150,7 +150,7 @@ config IPW2200_DEBUG
 
 config LIBIPW
 	tristate
-	depends on PCI && WLAN_80211
+	depends on PCI && WLAN_80211 && CFG80211
 	select WIRELESS_EXT
 	select CRYPTO
 	select CRYPTO_ARC4

^ permalink raw reply

* Re: [rt2x00-users] [PATCH] rt2x00: Reorganize padding & L2 padding
From: Benoit PAPILLAULT @ 2009-08-30 19:47 UTC (permalink / raw)
  To: rt2x00 Users List; +Cc: linux-wireless
In-Reply-To: <200908301532.47769.IvDoorn@gmail.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ivo van Doorn a écrit :
>>> +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int
>>> header_length) +{ +    struct skb_frame_desc *skbdesc =
>>> get_skb_frame_desc(skb); +    unsigned int l2pad = 4 - (header_length
>>> & 3);
>> This formula is incorrect, it should be at least (4 -
>> (header_length%4)%4). I have a fix in my pending patches...
>> If header_length is 0 => l2pad should be 0 as well.
> 
> Header_length should never be 0 (that was fixed by this patch), so that should
> not be a problem. I'll review your patch so it can be send as update later. But I
> do think this patch can be merged into linux-wireless in regardless.
> 
> Ivo
> 
> P.S. Your mail client is really messing up the replies by removing end-of-line
> characters. :S

Sorry about my mail client (there was an HTML conversion). It should be
fixed now.

Regards,
Benoit
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkqa12MACgkQOR6EySwP7oIviQCdHXzTBbHuFuJE5BulKy1+a80z
rHMAnA4nL9XEz7sYAK5ifcQypJkNkcki
=Rg+z
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: ath9k DMA problems
From: Kunal Gangakhedkar @ 2009-08-30 18:00 UTC (permalink / raw)
  To: Howard Chu; +Cc: linux-wireless@vger.kernel.org, ath9k-devel@lists.ath9k.org
In-Reply-To: <4A987F0F.9040905@symas.com>

On Saturday 29 Aug 2009 6:36:23 am Howard Chu wrote:
> Am I the only one having these problems? ath9k hasn't worked well for me
> since 2.6.29.4; every snapshot since then has suffered from random drops.
> In 2.6.29.6 it at least would quickly reassociate. The current ones hang
> within 20-30 minutes of use and never come back. The compat-wireless
> snapshots have all been equally unusable.
>
> Howard Chu wrote:
> > Still seeing occasional hangs using the ath9k in 2.6.31-rc6, and even
> > worse using compat-wireless 2009-08-22. Today I got this which was even
> > more interesting:
> >
> > [369014.776586] wlan0: associate with AP 00:12:17:26:56:10 (try 1)
> > [369014.779197] wlan0: RX ReassocResp from 00:12:17:26:56:10 (capab=0x411
> > status=0 aid=2)
> > [369014.779197] wlan0: associated
> > [369472.707961] ath9k: DMA failed to stop in 10 ms AR_CR=0xdeadbeef
> > AR_DIAG_SW=0xdeadbeef
> >
> > This is on an HP dv5z laptop, it reports an AR9280 at boot.

Neither for me - I'm on an HP dv6 series laptop and have AR9285 chip.
I have also posted my logs to the ath9k-devel list, but yet to receive any 
further response.

The driver seems quite erratic - especially under heavy network load & also 
after pm-resume.

Admittedly, I haven't tried compat-wireless at all.

Kunal

^ permalink raw reply

* Re: [PATCH v2] b43: LP-PHY: Begin implementing calibration & software RFKILL support
From: Michael Buesch @ 2009-08-30 15:55 UTC (permalink / raw)
  To: Larry Finger
  Cc: Gábor Stefanik, John Linville, Mark Huijgen,
	Broadcom Wireless, linux-wireless
In-Reply-To: <4A9A965F.8020200@lwfinger.net>

On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
> Michael Buesch wrote:
> > On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:
> >>  static void lpphy_pr41573_workaround(struct b43_wldev *dev)
> >>  {
> >>  	struct b43_phy_lp *lpphy = dev->phy.lp;
> >> @@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
> >>  		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
> >>  				    saved_tab_size, saved_tab);
> >>  	}
> >> +	b43_put_phy_into_reset(dev);
> > 
> > Are you sure you really want this?
> > This function completely disables the PHY on the backplane and keeps the physical
> > PHY reset pin asserted (even after return from the function).
> > So the PHY will physically be powered down from this point on. The following
> > PHY accesses could even hang the machine, because the PHY won't respond to
> > register accesses anymore.
> > 
> > We currently only use this function on A/G Multi-PHY devices to permanently
> > hard-disable the PHY that's not used.
> 
> The PHY reset routine in
> http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated
> for the latest N PHY changes, appears to be a different routine than
> b43_put_phy_into_reset(). The names are confusing.

b43_put_phy_into_reset() is opencoded in the specifications in various init
routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH v2] b43: LP-PHY: Begin implementing calibration & software RFKILL support
From: Larry Finger @ 2009-08-30 15:10 UTC (permalink / raw)
  To: Michael Buesch
  Cc: Gábor Stefanik, John Linville, Mark Huijgen,
	Broadcom Wireless, linux-wireless
In-Reply-To: <200908301228.16845.mb@bu3sch.de>

Michael Buesch wrote:
> On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:
>>  static void lpphy_pr41573_workaround(struct b43_wldev *dev)
>>  {
>>  	struct b43_phy_lp *lpphy = dev->phy.lp;
>> @@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
>>  		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
>>  				    saved_tab_size, saved_tab);
>>  	}
>> +	b43_put_phy_into_reset(dev);
> 
> Are you sure you really want this?
> This function completely disables the PHY on the backplane and keeps the physical
> PHY reset pin asserted (even after return from the function).
> So the PHY will physically be powered down from this point on. The following
> PHY accesses could even hang the machine, because the PHY won't respond to
> register accesses anymore.
> 
> We currently only use this function on A/G Multi-PHY devices to permanently
> hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated
for the latest N PHY changes, appears to be a different routine than
b43_put_phy_into_reset(). The names are confusing.

Larry

^ permalink raw reply

* Re: [rt2x00-users] [PATCH] rt2x00: Reorganize padding & L2 padding
From: Ivo van Doorn @ 2009-08-30 13:32 UTC (permalink / raw)
  To: users; +Cc: Benoit PAPILLAULT, linux-wireless
In-Reply-To: <4A9990A8.1080002@free.fr>

> > +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int
> > header_length) +{ +    struct skb_frame_desc *skbdesc =
> > get_skb_frame_desc(skb); +    unsigned int l2pad = 4 - (header_length
> > & 3);
> This formula is incorrect, it should be at least (4 -
> (header_length%4)%4). I have a fix in my pending patches...
> If header_length is 0 => l2pad should be 0 as well.

Header_length should never be 0 (that was fixed by this patch), so that should
not be a problem. I'll review your patch so it can be send as update later. But I
do think this patch can be merged into linux-wireless in regardless.

Ivo

P.S. Your mail client is really messing up the replies by removing end-of-line
characters. :S

^ permalink raw reply

* Re: [rt2x00-users] [PATCH] rt2x00: Fix TX status reporting
From: Ivo van Doorn @ 2009-08-30 13:30 UTC (permalink / raw)
  To: users; +Cc: Benoit PAPILLAULT, linux-wireless
In-Reply-To: <4A999024.6060800@free.fr>

On Saturday 29 August 2009, Benoit PAPILLAULT wrote:
> Ivo van Doorn a écrit :
> > Not all values of the TX status enumeration were covered during
> > updating of the TX statistics. This could lead to wrong bitrate
> > tuning but also wrong behavior in tools like hostapd.
> >
> > Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
> I have a pending patch about TX status that changed the meaning of
> TXDONE_FALLBACK just a bit... just to avoid this change in fact.
> I should be able to send those patches in few hours.
> 
> In my code, you success/failure of the packet is reported with
> TXDONE_SUCCESS / TXDONE_FAILURE. The TXDONE_FALLBACK is set
> independently to indicate that a fallback rate table has been used
> (and this could be the case for either success or failure).

Well that shouldn't block this patch at this time since it is a bugfix which
is quite important to get minstrel and hostapd working properly.

Once I have reviewed your patch it can be send upstream immediately or
in a single batch together with the rt2800pci driver. ;)

Ivo

^ permalink raw reply

* Re: ipw2200: firmware DMA loading rework
From: Bartlomiej Zolnierkiewicz @ 2009-08-30 12:37 UTC (permalink / raw)
  To: Zhu Yi
  Cc: Andrew Morton, Mel Gorman, Johannes Weiner, Pekka Enberg,
	Rafael J. Wysocki, Linux Kernel Mailing List, Kernel Testers List,
	Mel Gorman, netdev@vger.kernel.org, linux-mm@kvack.org,
	James Ketrenos, Chatre, Reinette, linux-wireless@vger.kernel.org,
	ipw2100-devel@lists.sourceforge.net
In-Reply-To: <1251430951.3704.181.camel@debian>

On Friday 28 August 2009 05:42:31 Zhu Yi wrote:
> Bartlomiej Zolnierkiewicz reported an atomic order-6 allocation failure
> for ipw2200 firmware loading in kernel 2.6.30. High order allocation is

s/2.6.30/2.6.31-rc6/

The issue has always been there but it was some recent change that
explicitly triggered the allocation failures (after 2.6.31-rc1).

> likely to fail and should always be avoided.
> 
> The patch fixes this problem by replacing the original order-6
> pci_alloc_consistent() with an array of order-1 pages from a pci pool.
> This utilized the ipw2200 DMA command blocks (up to 64 slots). The
> maximum firmware size support remains the same (64*8K).
> 
> This patch fixes bug http://bugzilla.kernel.org/show_bug.cgi?id=14016
> 
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Mel Gorman <mel@csn.ul.ie>
> Signed-off-by: Zhu Yi <yi.zhu@intel.com>

Thanks for the fix (also kudos to other people helping with the bugreport),
it works fine so far and looks OK to me:

Tested-and-reviewed-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

^ permalink raw reply

* Re: [PATCH v2] b43: LP-PHY: Begin implementing calibration & software RFKILL support
From: Michael Buesch @ 2009-08-30 10:28 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: John Linville, Larry Finger, Mark Huijgen, Broadcom Wireless,
	linux-wireless
In-Reply-To: <4A99C4BB.7080806@gmail.com>

On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:
>  static void lpphy_pr41573_workaround(struct b43_wldev *dev)
>  {
>  	struct b43_phy_lp *lpphy = dev->phy.lp;
> @@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
>  		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
>  				    saved_tab_size, saved_tab);
>  	}
> +	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical
PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following
PHY accesses could even hang the machine, because the PHY won't respond to
register accesses anymore.

We currently only use this function on A/G Multi-PHY devices to permanently
hard-disable the PHY that's not used.

> +	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFF8);
> +	lpphy_table_init(dev); //FIXME is table init needed?
> +	lpphy_baseband_init(dev);
> +	b43_lpphy_op_software_rfkill(dev, false);
> +	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
> +	if (dev->phy.rev < 2) {
> +		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
> +				     saved_tab_size, saved_tab);
> +	} else {
> +		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
> +				     saved_tab_size, saved_tab);
> +	}
> +	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
> +	lpphy->tssi_npt = tssi_npt;
> +	lpphy->tssi_idx = tssi_idx;
> +	lpphy_set_analog_filter(dev, lpphy->channel);
> +	if (tx_pwr_idx_over != -1)
> +		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
> +	if (lpphy->rc_cap)
> +		lpphy_set_rc_cap(dev);
> +	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
> +	lpphy_set_tx_power_control(dev, txpctl_mode);
> +	kfree(saved_tab);
> +}

-- 
Greetings, Michael.

^ permalink raw reply

* [PATCH v2] b43: LP-PHY: Begin implementing calibration & software RFKILL support
From: Gábor Stefanik @ 2009-08-30  0:15 UTC (permalink / raw)
  To: John Linville, Michael Buesch, Larry Finger, Mark Huijgen
  Cc: Broadcom Wireless, linux-wireless

This implements the following calibration functions:
-Set TX IQCC
-Set TX Power by Index
-PR41573 workaround
-Calc RX IQ Comp
-PHY Cordic
-Run Samples
-Start/Stop TX Tone
-part of PAPD Cal TX Power
-RX I/Q Calibration
-The basic structure of the periodic calibration wrapper

Software RFKILL (required by calibration) is also implemented in
this round.

Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
---
V2: Fix a mistake I made in the PHY Cordic routine.

 drivers/net/wireless/b43/main.c   |    2 +-
 drivers/net/wireless/b43/main.h   |    2 +
 drivers/net/wireless/b43/phy_lp.c |  686 ++++++++++++++++++++++++++++++++-----
 drivers/net/wireless/b43/phy_lp.h |   11 +-
 4 files changed, 613 insertions(+), 88 deletions(-)

diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index f2c5b2d..59bee02 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3345,7 +3345,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 	mutex_unlock(&wl->mutex);
 }
 
-static void b43_put_phy_into_reset(struct b43_wldev *dev)
+void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
 	struct ssb_device *sdev = dev->dev;
 	u32 tmslow;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 0406e06..fdbea9a 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -129,6 +129,8 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
 
 void b43_controller_restart(struct b43_wldev *dev, const char *reason);
 
+void b43_put_phy_into_reset(struct b43_wldev *dev);
+
 #define B43_PS_ENABLED	(1 << 0)	/* Force enable hardware power saving */
 #define B43_PS_DISABLED	(1 << 1)	/* Force disable hardware power saving */
 #define B43_PS_AWAKE	(1 << 2)	/* Force device awake */
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 5fff30a..c13385b 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -67,6 +67,7 @@ static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
 	struct b43_phy_lp *lpphy = phy->lp;
 
 	memset(lpphy, 0, sizeof(*lpphy));
+	lpphy->antenna = B43_ANTENNA_DEFAULT;
 
 	//TODO
 }
@@ -751,11 +752,17 @@ static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
 	}
 }
 
+static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
+{
+	u16 trsw = (tx << 1) | rx;
+	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+}
+
 static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
 {
 	lpphy_set_deaf(dev, user);
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+	lpphy_set_trsw_over(dev, false, true);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
@@ -790,6 +797,60 @@ static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
 
 struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
 
+static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
+	if (dev->phy.rev >= 2) {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
+		}
+	} else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
+	}
+}
+
+static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
+{
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+	if (dev->phy.rev >= 2) {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
+		}
+	} else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
+	}
+}
+
+static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
+{
+	if (dev->phy.rev < 2)
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+	else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
+	}
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
+}
+
+static void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
+{
+	if (dev->phy.rev < 2)
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+	else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
+	}
+	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
+}
+
 static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
 {
 	struct lpphy_tx_gains gains;
@@ -819,6 +880,17 @@ static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
 	b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
 }
 
+static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
+{
+	return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
+}
+
+static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
+{
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
+}
+
 static void lpphy_set_tx_gains(struct b43_wldev *dev,
 			       struct lpphy_tx_gains gains)
 {
@@ -829,8 +901,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 				0xF800, rf_gain);
 	} else {
-		pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0;
-		pa_gain <<= 2;
+		pa_gain = lpphy_get_pa_gain(dev);
 		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 			      (gains.pga << 8) | gains.gm);
 		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
@@ -841,13 +912,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 				0x8000, gains.pad | pa_gain);
 	}
 	lpphy_set_dac_gain(dev, gains.dac);
-	if (dev->phy.rev < 2) {
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8);
-	} else {
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
-	}
-	b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6);
+	lpphy_enable_tx_gain_override(dev);
 }
 
 static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
@@ -887,38 +952,6 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
 	}
 }
 
-static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
-{
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
-	if (dev->phy.rev >= 2) {
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
-		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
-			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
-		}
-	} else {
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
-	}
-}
-
-static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
-{
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
-	if (dev->phy.rev >= 2) {
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
-		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
-			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
-		}
-	} else {
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
-	}
-}
-
 static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
 {
 	if (dev->phy.rev < 2)
@@ -1003,8 +1036,7 @@ static int lpphy_loopback(struct b43_wldev *dev)
 
 	memset(&iq_est, 0, sizeof(iq_est));
 
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+	lpphy_set_trsw_over(dev, true, true);
 	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
 	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
@@ -1126,7 +1158,7 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
 			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
 					0x8FFF, ((u16)lpphy->tssi_npt << 16));
 			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
-			//TODO Disable TX gain override
+			lpphy_disable_tx_gain_override(dev);
 			lpphy->tx_pwr_idx_over = -1;
 		}
 	}
@@ -1312,15 +1344,73 @@ static void lpphy_calibrate_rc(struct b43_wldev *dev)
 	}
 }
 
+static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+	if (dev->phy.rev >= 2)
+		return; // rev2+ doesn't support antenna diversity
+
+	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
+		return;
+
+	b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
+
+	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
+	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
+
+	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
+
+	dev->phy.lp->antenna = antenna;
+}
+
+static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
+{
+	u16 tmp[2];
+
+	tmp[0] = a;
+	tmp[1] = b;
+	b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
+}
+
 static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct lpphy_tx_gains gains;
+	u32 iq_comp, tx_gain, coeff, rf_power;
 
 	lpphy->tx_pwr_idx_over = index;
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
 	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
 		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
-
-	//TODO
+	if (dev->phy.rev >= 2) {
+		iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
+		tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
+		gains.pad = (tx_gain >> 16) & 0xFF;
+		gains.gm = tx_gain & 0xFF;
+		gains.pga = (tx_gain >> 8) & 0xFF;
+		gains.dac = (iq_comp >> 28) & 0xFF;
+		lpphy_set_tx_gains(dev, gains);
+	} else {
+		iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
+		tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
+		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+				0xF800, (tx_gain >> 4) & 0x7FFF);
+		lpphy_set_dac_gain(dev, tx_gain & 0x7);
+		lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
+	}
+	lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
+	lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
+	if (dev->phy.rev >= 2) {
+		coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
+	} else {
+		coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
+	}
+	b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
+	if (dev->phy.rev >= 2) {
+		rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
+		b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
+				rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
+	}
+	lpphy_enable_tx_gain_override(dev);
 }
 
 static void lpphy_btcoex_override(struct b43_wldev *dev)
@@ -1329,6 +1419,47 @@ static void lpphy_btcoex_override(struct b43_wldev *dev)
 	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
 }
 
+static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
+					 bool blocked)
+{
+	//TODO check MAC control register
+	if (blocked) {
+		if (dev->phy.rev >= 2) {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+			b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
+		} else {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
+		}
+	} else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
+		if (dev->phy.rev >= 2)
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
+		else
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
+	}
+}
+
+/* This was previously called lpphy_japan_filter */
+static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
+
+	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
+		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
+		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
+			lpphy_set_rc_cap(dev);
+	} else {
+		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
+	}
+}
+
 static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFF8);
+	lpphy_table_init(dev); //FIXME is table init needed?
+	lpphy_baseband_init(dev);
+	b43_lpphy_op_software_rfkill(dev, false);
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+	if (dev->phy.rev < 2) {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
+				     saved_tab_size, saved_tab);
+	} else {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
+				     saved_tab_size, saved_tab);
+	}
+	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
+	lpphy->tssi_npt = tssi_npt;
+	lpphy->tssi_idx = tssi_idx;
+	lpphy_set_analog_filter(dev, lpphy->channel);
+	if (tx_pwr_idx_over != -1)
+		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
+	if (lpphy->rc_cap)
+		lpphy_set_rc_cap(dev);
+	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
+	lpphy_set_tx_power_control(dev, txpctl_mode);
+	kfree(saved_tab);
+}
+
+struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
+
+static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
+	{ .chan = 1, .c1 = -66, .c0 = 15, },
+	{ .chan = 2, .c1 = -66, .c0 = 15, },
+	{ .chan = 3, .c1 = -66, .c0 = 15, },
+	{ .chan = 4, .c1 = -66, .c0 = 15, },
+	{ .chan = 5, .c1 = -66, .c0 = 15, },
+	{ .chan = 6, .c1 = -66, .c0 = 15, },
+	{ .chan = 7, .c1 = -66, .c0 = 14, },
+	{ .chan = 8, .c1 = -66, .c0 = 14, },
+	{ .chan = 9, .c1 = -66, .c0 = 14, },
+	{ .chan = 10, .c1 = -66, .c0 = 14, },
+	{ .chan = 11, .c1 = -66, .c0 = 14, },
+	{ .chan = 12, .c1 = -66, .c0 = 13, },
+	{ .chan = 13, .c1 = -66, .c0 = 13, },
+	{ .chan = 14, .c1 = -66, .c0 = 13, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
+	{ .chan = 1, .c1 = -64, .c0 = 13, },
+	{ .chan = 2, .c1 = -64, .c0 = 13, },
+	{ .chan = 3, .c1 = -64, .c0 = 13, },
+	{ .chan = 4, .c1 = -64, .c0 = 13, },
+	{ .chan = 5, .c1 = -64, .c0 = 12, },
+	{ .chan = 6, .c1 = -64, .c0 = 12, },
+	{ .chan = 7, .c1 = -64, .c0 = 12, },
+	{ .chan = 8, .c1 = -64, .c0 = 12, },
+	{ .chan = 9, .c1 = -64, .c0 = 12, },
+	{ .chan = 10, .c1 = -64, .c0 = 11, },
+	{ .chan = 11, .c1 = -64, .c0 = 11, },
+	{ .chan = 12, .c1 = -64, .c0 = 11, },
+	{ .chan = 13, .c1 = -64, .c0 = 11, },
+	{ .chan = 14, .c1 = -64, .c0 = 10, },
+	{ .chan = 34, .c1 = -62, .c0 = 24, },
+	{ .chan = 38, .c1 = -62, .c0 = 24, },
+	{ .chan = 42, .c1 = -62, .c0 = 24, },
+	{ .chan = 46, .c1 = -62, .c0 = 23, },
+	{ .chan = 36, .c1 = -62, .c0 = 24, },
+	{ .chan = 40, .c1 = -62, .c0 = 24, },
+	{ .chan = 44, .c1 = -62, .c0 = 23, },
+	{ .chan = 48, .c1 = -62, .c0 = 23, },
+	{ .chan = 52, .c1 = -62, .c0 = 23, },
+	{ .chan = 56, .c1 = -62, .c0 = 22, },
+	{ .chan = 60, .c1 = -62, .c0 = 22, },
+	{ .chan = 64, .c1 = -62, .c0 = 22, },
+	{ .chan = 100, .c1 = -62, .c0 = 16, },
+	{ .chan = 104, .c1 = -62, .c0 = 16, },
+	{ .chan = 108, .c1 = -62, .c0 = 15, },
+	{ .chan = 112, .c1 = -62, .c0 = 14, },
+	{ .chan = 116, .c1 = -62, .c0 = 14, },
+	{ .chan = 120, .c1 = -62, .c0 = 13, },
+	{ .chan = 124, .c1 = -62, .c0 = 12, },
+	{ .chan = 128, .c1 = -62, .c0 = 12, },
+	{ .chan = 132, .c1 = -62, .c0 = 12, },
+	{ .chan = 136, .c1 = -62, .c0 = 11, },
+	{ .chan = 140, .c1 = -62, .c0 = 10, },
+	{ .chan = 149, .c1 = -61, .c0 = 9, },
+	{ .chan = 153, .c1 = -61, .c0 = 9, },
+	{ .chan = 157, .c1 = -61, .c0 = 9, },
+	{ .chan = 161, .c1 = -61, .c0 = 8, },
+	{ .chan = 165, .c1 = -61, .c0 = 8, },
+	{ .chan = 184, .c1 = -62, .c0 = 25, },
+	{ .chan = 188, .c1 = -62, .c0 = 25, },
+	{ .chan = 192, .c1 = -62, .c0 = 25, },
+	{ .chan = 196, .c1 = -62, .c0 = 25, },
+	{ .chan = 200, .c1 = -62, .c0 = 25, },
+	{ .chan = 204, .c1 = -62, .c0 = 25, },
+	{ .chan = 208, .c1 = -62, .c0 = 25, },
+	{ .chan = 212, .c1 = -62, .c0 = 25, },
+	{ .chan = 216, .c1 = -62, .c0 = 26, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
+	.chan = 0,
+	.c1 = -64,
+	.c0 = 0,
+};
+
+static u8 lpphy_nbits(s32 val)
+{
+	u32 tmp = abs(val);
+	u8 nbits = 0;
+
+	while (tmp != 0) {
+		nbits++;
+		tmp >>= 1;
+	}
+
+	return nbits;
+}
+
+static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
+{
+	struct lpphy_iq_est iq_est;
+	u16 c0, c1;
+	int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
+
+	c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
+	c0 = c1 >> 8;
+	c1 |= 0xFF;
+
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
+	b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
+
+	ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
+	if (!ret)
+		goto out;
+
+	prod = iq_est.iq_prod;
+	ipwr = iq_est.i_pwr;
+	qpwr = iq_est.q_pwr;
+
+	if (ipwr + qpwr < 2) {
+		ret = 0;
+		goto out;
+	}
+
+	prod_msb = lpphy_nbits(prod);
+	q_msb = lpphy_nbits(qpwr);
+	tmp1 = prod_msb - 20;
+
+	if (tmp1 >= 0) {
+		tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
+			(ipwr >> tmp1);
+	} else {
+		tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
+			(ipwr << -tmp1);
+	}
+
+	tmp2 = q_msb - 11;
+
+	if (tmp2 >= 0)
+		tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
+	else
+		tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
+
+	tmp4 -= tmp3 * tmp3;
+	tmp4 = -int_sqrt(tmp4);
+
+	c0 = tmp3 >> 3;
+	c1 = tmp4 >> 4;
+
+out:
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
+	return ret;
+}
+
+/* Complex number using 2 32-bit signed integers */
+typedef struct {s32 i, q;} lpphy_c32;
+
+static lpphy_c32 lpphy_cordic(int theta)
+{
+	u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
+		      58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
+		      229, 115, 57, 29, };
+	int i, tmp, signx = 1, angle = 0;
+	lpphy_c32 ret = { .i = 39797, .q = 0, };
+
+	theta = clamp_t(int, theta, -180, 180);
+
+	if (theta > 90) {
+		theta -= 180;
+		signx = -1;
+	} else if (theta < -90) {
+		theta += 180;
+		signx = -1;
+	}
+
+	for (i = 0; i <= 17; i++) {
+		if (theta > angle) {
+			tmp = ret.i - (ret.q >> i);
+			ret.q += ret.i >> i;
+			ret.i = tmp;
+			angle += arctg[i];
+		} else {
+			tmp = ret.i + (ret.q >> i);
+			ret.q -= ret.i >> i;
+			ret.i = tmp;
+			angle -= arctg[i];
+		}
+	}
+
+	ret.i *= signx;
+	ret.q *= signx;
+
+	return ret;
+}
+
+static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
+			      u16 wait)
+{
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
+			0xFFC0, samples - 1);
+	if (loops != 0xFFFF)
+		loops--;
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
+	b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
+}
+
+//SPEC FIXME what does a negative freq mean?
+static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 buf[64];
+	int i, samples, angle = 0, rotation = (9 * freq) / 500;
+	lpphy_c32 sample;
+
+	lpphy->tx_tone_freq = freq;
+
+	if (freq) {
+		/* Find i for which abs(freq) integrally divides 20000 * i */
+		for (i = 1; samples * abs(freq) != 20000 * i; i++) {
+			samples = (20000 * i) / abs(freq);
+			if(B43_WARN_ON(samples > 63))
+				return;
+		}
+	} else {
+		samples = 2;
+	}
+
+	for (i = 0; i < samples; i++) {
+		sample = lpphy_cordic(angle);
+		angle += rotation;
+		buf[i] = ((sample.i * max) & 0xFF) << 8;
+		buf[i] |= (sample.q * max) & 0xFF;
+	}
+
+	b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
+
+	lpphy_run_samples(dev, samples, 0xFFFF, 0);
+}
+
+static void lpphy_stop_tx_tone(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	int i;
+
+	lpphy->tx_tone_freq = 0;
+
+	b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
+	for (i = 0; i < 31; i++) {
+		if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
+			break;
+		udelay(100);
+	}
+}
+
+
+static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
+			   int mode, bool useindex, u8 index)
+{
 	//TODO
+}
 
-	kfree(saved_tab);
+static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct lpphy_tx_gains gains, oldgains;
+	int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
+
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	old_txpctl = lpphy->txpctl_mode;
+	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+	if (old_afe_ovr)
+		oldgains = lpphy_get_tx_gains(dev);
+	old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
+	old_bbmult = lpphy_get_bb_mult(dev);
+
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+
+	if (bus->chip_id == 0x4325 && bus->chip_rev == 0)
+		lpphy_papd_cal(dev, gains, 0, 1, 30);
+	else
+		lpphy_papd_cal(dev, gains, 0, 1, 65);
+
+	if (old_afe_ovr)
+		lpphy_set_tx_gains(dev, oldgains);
+	lpphy_set_bb_mult(dev, old_bbmult);
+	lpphy_set_tx_power_control(dev, old_txpctl);
+	b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
+}
+
+static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
+			    bool rx, bool pa, struct lpphy_tx_gains *gains)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct ssb_bus *bus = dev->dev->bus;
+	const struct lpphy_rx_iq_comp *iqcomp = NULL;
+	struct lpphy_tx_gains nogains, oldgains;
+	u16 tmp;
+	int i, ret;
+
+	memset(&nogains, 0, sizeof(nogains));
+	memset(&oldgains, 0, sizeof(oldgains));
+
+	if (bus->chip_id == 0x5354) {
+		for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
+			if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
+				iqcomp = &lpphy_5354_iq_table[i];
+			}
+		}
+	} else if (dev->phy.rev >= 2) {
+		iqcomp = &lpphy_rev2plus_iq_comp;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
+			if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
+				iqcomp = &lpphy_rev0_1_iq_table[i];
+			}
+		}
+	}
+
+	if (B43_WARN_ON(!iqcomp))
+		return 0;
+
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
+			0x00FF, iqcomp->c0 << 8);
+
+	if (noise) {
+		tx = true;
+		rx = false;
+		pa = false;
+	}
+
+	lpphy_set_trsw_over(dev, tx, rx);
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+				0xFFF7, pa << 3);
+	} else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
+		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+				0xFFDF, pa << 5);
+	}
+
+	tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+
+	if (noise)
+		lpphy_set_rx_gain(dev, 0x2D5D);
+	else {
+		if (tmp)
+			oldgains = lpphy_get_tx_gains(dev);
+		if (!gains)
+			gains = &nogains;
+		lpphy_set_tx_gains(dev, *gains);
+	}
+
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
+	lpphy_set_deaf(dev, false);
+	if (noise)
+		ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
+	else {
+		lpphy_start_tx_tone(dev, 4000, 100);
+		ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
+		lpphy_stop_tx_tone(dev);
+	}
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
+	if (!noise) {
+		if (tmp)
+			lpphy_set_tx_gains(dev, oldgains);
+		else
+			lpphy_disable_tx_gain_override(dev);
+	}
+	lpphy_disable_rx_gain_override(dev);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
+	return ret;
 }
 
 static void lpphy_calibration(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
 	enum b43_lpphy_txpctl_mode saved_pctl_mode;
+	bool full_cal = false;
+
+	if (lpphy->full_calib_chan != lpphy->channel) {
+		full_cal = true;
+		lpphy->full_calib_chan = lpphy->channel;
+	}
 
 	b43_mac_suspend(dev);
 
 	lpphy_btcoex_override(dev);
+	if (dev->phy.rev >= 2)
+		lpphy_save_dig_flt_state(dev);
 	lpphy_read_tx_pctl_mode_from_hardware(dev);
 	saved_pctl_mode = lpphy->txpctl_mode;
 	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
 	//TODO Perform transmit power table I/Q LO calibration
 	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
 		lpphy_pr41573_workaround(dev);
-	//TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration
+	if ((dev->phy.rev >= 2) && full_cal) {
+		lpphy_papd_cal_txpwr(dev);
+	}
 	lpphy_set_tx_power_control(dev, saved_pctl_mode);
-	//TODO Perform I/Q calibration with a single control value set
+	if (dev->phy.rev >= 2)
+		lpphy_restore_dig_flt_state(dev);
+	lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
 
 	b43_mac_enable(dev);
 }
@@ -1532,12 +2075,6 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
-static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
-					 bool blocked)
-{
-	//TODO
-}
-
 struct b206x_channel {
 	u8 channel;
 	u16 freq;
@@ -2003,22 +2540,6 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
 	return err;
 }
 
-
-/* This was previously called lpphy_japan_filter */
-static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
-{
-	struct b43_phy_lp *lpphy = dev->phy.lp;
-	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
-
-	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
-		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
-		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
-			lpphy_set_rc_cap(dev);
-	} else {
-		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
-	}
-}
-
 static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
 {
 	u16 tmp;
@@ -2203,18 +2724,6 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
 	return 0;
 }
 
-static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
-{
-	if (dev->phy.rev >= 2)
-		return; // rev2+ doesn't support antenna diversity
-
-	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
-		return;
-
-	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
-	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
-}
-
 static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
 {
 	//TODO
@@ -2227,6 +2736,11 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
 	return B43_TXPWR_RES_DONE;
 }
 
+static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
+{
+	//TODO
+}
+
 const struct b43_phy_operations b43_phyops_lp = {
 	.allocate		= b43_lpphy_op_allocate,
 	.free			= b43_lpphy_op_free,
@@ -2244,4 +2758,6 @@ const struct b43_phy_operations b43_phyops_lp = {
 	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
 	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
 	.adjust_txpower		= b43_lpphy_op_adjust_txpower,
+	.pwork_15sec		= b43_lpphy_op_pwork_15sec,
+	.pwork_60sec		= lpphy_calibration,
 };
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
index c3232c1..62737f7 100644
--- a/drivers/net/wireless/b43/phy_lp.h
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -286,6 +286,7 @@
 #define B43_LPPHY_TR_LOOKUP_6			B43_PHY_OFDM(0xC8) /* TR Lookup 6 */
 #define B43_LPPHY_TR_LOOKUP_7			B43_PHY_OFDM(0xC9) /* TR Lookup 7 */
 #define B43_LPPHY_TR_LOOKUP_8			B43_PHY_OFDM(0xCA) /* TR Lookup 8 */
+#define B43_LPPHY_RF_PWR_OVERRIDE		B43_PHY_OFDM(0xD3) /* RF power override */
 
 
 
@@ -871,12 +872,12 @@ struct b43_phy_lp {
 	u8 rssi_gs;
 
 	/* RC cap */
-	u8 rc_cap; /* FIXME initial value? */
+	u8 rc_cap;
 	/* BX arch */
 	u8 bx_arch;
 
 	/* Full calibration channel */
-	u8 full_calib_chan; /* FIXME initial value? */
+	u8 full_calib_chan;
 
 	/* Transmit iqlocal best coeffs */
 	bool tx_iqloc_best_coeffs_valid;
@@ -891,6 +892,12 @@ struct b43_phy_lp {
 
 	/* The channel we are tuned to */
 	u8 channel;
+
+	/* The active antenna diversity mode */
+	int antenna;
+
+	/* Frequency of the active TX tone */
+	int tx_tone_freq;
 };
 
 enum tssi_mux_mode {
-- 
1.6.2.4




^ permalink raw reply related

* [PATCH] b43: LP-PHY: Begin implementing calibration & software RFKILL support
From: Gábor Stefanik @ 2009-08-29 23:20 UTC (permalink / raw)
  To: John Linville, Michael Buesch, Larry Finger, Mark Huijgen
  Cc: Broadcom Wireless, linux-wireless

This implements the following calibration functions:
-Set TX IQCC
-Set TX Power by Index
-PR41573 workaround
-Calc RX IQ Comp
-PHY Cordic
-Run Samples
-Start/Stop TX Tone
-part of PAPD Cal TX Power
-RX I/Q Calibration
-The basic structure of the periodic calibration wrapper

Software RFKILL (required by calibration) is also implemented in
this round.

Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
---
Larry, please check if I got the math in "PHY Cordic" right!

 drivers/net/wireless/b43/main.c   |    2 +-
 drivers/net/wireless/b43/main.h   |    2 +
 drivers/net/wireless/b43/phy_lp.c |  684 ++++++++++++++++++++++++++++++++-----
 drivers/net/wireless/b43/phy_lp.h |   11 +-
 4 files changed, 611 insertions(+), 88 deletions(-)

diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index f2c5b2d..59bee02 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3345,7 +3345,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 	mutex_unlock(&wl->mutex);
 }
 
-static void b43_put_phy_into_reset(struct b43_wldev *dev)
+void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
 	struct ssb_device *sdev = dev->dev;
 	u32 tmslow;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 0406e06..fdbea9a 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -129,6 +129,8 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
 
 void b43_controller_restart(struct b43_wldev *dev, const char *reason);
 
+void b43_put_phy_into_reset(struct b43_wldev *dev);
+
 #define B43_PS_ENABLED	(1 << 0)	/* Force enable hardware power saving */
 #define B43_PS_DISABLED	(1 << 1)	/* Force disable hardware power saving */
 #define B43_PS_AWAKE	(1 << 2)	/* Force device awake */
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 5fff30a..60e8f6f 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -67,6 +67,7 @@ static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
 	struct b43_phy_lp *lpphy = phy->lp;
 
 	memset(lpphy, 0, sizeof(*lpphy));
+	lpphy->antenna = B43_ANTENNA_DEFAULT;
 
 	//TODO
 }
@@ -751,11 +752,17 @@ static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
 	}
 }
 
+static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
+{
+	u16 trsw = (tx << 1) | rx;
+	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+}
+
 static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
 {
 	lpphy_set_deaf(dev, user);
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+	lpphy_set_trsw_over(dev, false, true);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
@@ -790,6 +797,60 @@ static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
 
 struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
 
+static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
+	if (dev->phy.rev >= 2) {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
+		}
+	} else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
+	}
+}
+
+static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
+{
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+	if (dev->phy.rev >= 2) {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
+		}
+	} else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
+	}
+}
+
+static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
+{
+	if (dev->phy.rev < 2)
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+	else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
+	}
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
+}
+
+static void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
+{
+	if (dev->phy.rev < 2)
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+	else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
+	}
+	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
+}
+
 static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
 {
 	struct lpphy_tx_gains gains;
@@ -819,6 +880,17 @@ static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
 	b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
 }
 
+static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
+{
+	return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
+}
+
+static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
+{
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
+}
+
 static void lpphy_set_tx_gains(struct b43_wldev *dev,
 			       struct lpphy_tx_gains gains)
 {
@@ -829,8 +901,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 				0xF800, rf_gain);
 	} else {
-		pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0;
-		pa_gain <<= 2;
+		pa_gain = lpphy_get_pa_gain(dev);
 		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 			      (gains.pga << 8) | gains.gm);
 		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
@@ -841,13 +912,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 				0x8000, gains.pad | pa_gain);
 	}
 	lpphy_set_dac_gain(dev, gains.dac);
-	if (dev->phy.rev < 2) {
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8);
-	} else {
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
-		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
-	}
-	b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6);
+	lpphy_enable_tx_gain_override(dev);
 }
 
 static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
@@ -887,38 +952,6 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
 	}
 }
 
-static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
-{
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
-	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
-	if (dev->phy.rev >= 2) {
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
-		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
-			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
-		}
-	} else {
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
-	}
-}
-
-static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
-{
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
-	if (dev->phy.rev >= 2) {
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
-		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
-			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
-		}
-	} else {
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
-	}
-}
-
 static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
 {
 	if (dev->phy.rev < 2)
@@ -1003,8 +1036,7 @@ static int lpphy_loopback(struct b43_wldev *dev)
 
 	memset(&iq_est, 0, sizeof(iq_est));
 
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+	lpphy_set_trsw_over(dev, true, true);
 	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
 	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
@@ -1126,7 +1158,7 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
 			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
 					0x8FFF, ((u16)lpphy->tssi_npt << 16));
 			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
-			//TODO Disable TX gain override
+			lpphy_disable_tx_gain_override(dev);
 			lpphy->tx_pwr_idx_over = -1;
 		}
 	}
@@ -1312,15 +1344,73 @@ static void lpphy_calibrate_rc(struct b43_wldev *dev)
 	}
 }
 
+static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+	if (dev->phy.rev >= 2)
+		return; // rev2+ doesn't support antenna diversity
+
+	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
+		return;
+
+	b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
+
+	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
+	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
+
+	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
+
+	dev->phy.lp->antenna = antenna;
+}
+
+static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
+{
+	u16 tmp[2];
+
+	tmp[0] = a;
+	tmp[1] = b;
+	b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
+}
+
 static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct lpphy_tx_gains gains;
+	u32 iq_comp, tx_gain, coeff, rf_power;
 
 	lpphy->tx_pwr_idx_over = index;
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
 	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
 		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
-
-	//TODO
+	if (dev->phy.rev >= 2) {
+		iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
+		tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
+		gains.pad = (tx_gain >> 16) & 0xFF;
+		gains.gm = tx_gain & 0xFF;
+		gains.pga = (tx_gain >> 8) & 0xFF;
+		gains.dac = (iq_comp >> 28) & 0xFF;
+		lpphy_set_tx_gains(dev, gains);
+	} else {
+		iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
+		tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
+		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+				0xF800, (tx_gain >> 4) & 0x7FFF);
+		lpphy_set_dac_gain(dev, tx_gain & 0x7);
+		lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
+	}
+	lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
+	lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
+	if (dev->phy.rev >= 2) {
+		coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
+	} else {
+		coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
+	}
+	b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
+	if (dev->phy.rev >= 2) {
+		rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
+		b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
+				rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
+	}
+	lpphy_enable_tx_gain_override(dev);
 }
 
 static void lpphy_btcoex_override(struct b43_wldev *dev)
@@ -1329,6 +1419,47 @@ static void lpphy_btcoex_override(struct b43_wldev *dev)
 	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
 }
 
+static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
+					 bool blocked)
+{
+	//TODO check MAC control register
+	if (blocked) {
+		if (dev->phy.rev >= 2) {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+			b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
+		} else {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
+		}
+	} else {
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
+		if (dev->phy.rev >= 2)
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
+		else
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
+	}
+}
+
+/* This was previously called lpphy_japan_filter */
+static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
+
+	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
+		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
+		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
+			lpphy_set_rc_cap(dev);
+	} else {
+		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
+	}
+}
+
 static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,438 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFF8);
+	lpphy_table_init(dev); //FIXME is table init needed?
+	lpphy_baseband_init(dev);
+	b43_lpphy_op_software_rfkill(dev, false);
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+	if (dev->phy.rev < 2) {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
+				     saved_tab_size, saved_tab);
+	} else {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
+				     saved_tab_size, saved_tab);
+	}
+	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
+	lpphy->tssi_npt = tssi_npt;
+	lpphy->tssi_idx = tssi_idx;
+	lpphy_set_analog_filter(dev, lpphy->channel);
+	if (tx_pwr_idx_over != -1)
+		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
+	if (lpphy->rc_cap)
+		lpphy_set_rc_cap(dev);
+	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
+	lpphy_set_tx_power_control(dev, txpctl_mode);
+	kfree(saved_tab);
+}
+
+struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
+
+static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
+	{ .chan = 1, .c1 = -66, .c0 = 15, },
+	{ .chan = 2, .c1 = -66, .c0 = 15, },
+	{ .chan = 3, .c1 = -66, .c0 = 15, },
+	{ .chan = 4, .c1 = -66, .c0 = 15, },
+	{ .chan = 5, .c1 = -66, .c0 = 15, },
+	{ .chan = 6, .c1 = -66, .c0 = 15, },
+	{ .chan = 7, .c1 = -66, .c0 = 14, },
+	{ .chan = 8, .c1 = -66, .c0 = 14, },
+	{ .chan = 9, .c1 = -66, .c0 = 14, },
+	{ .chan = 10, .c1 = -66, .c0 = 14, },
+	{ .chan = 11, .c1 = -66, .c0 = 14, },
+	{ .chan = 12, .c1 = -66, .c0 = 13, },
+	{ .chan = 13, .c1 = -66, .c0 = 13, },
+	{ .chan = 14, .c1 = -66, .c0 = 13, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
+	{ .chan = 1, .c1 = -64, .c0 = 13, },
+	{ .chan = 2, .c1 = -64, .c0 = 13, },
+	{ .chan = 3, .c1 = -64, .c0 = 13, },
+	{ .chan = 4, .c1 = -64, .c0 = 13, },
+	{ .chan = 5, .c1 = -64, .c0 = 12, },
+	{ .chan = 6, .c1 = -64, .c0 = 12, },
+	{ .chan = 7, .c1 = -64, .c0 = 12, },
+	{ .chan = 8, .c1 = -64, .c0 = 12, },
+	{ .chan = 9, .c1 = -64, .c0 = 12, },
+	{ .chan = 10, .c1 = -64, .c0 = 11, },
+	{ .chan = 11, .c1 = -64, .c0 = 11, },
+	{ .chan = 12, .c1 = -64, .c0 = 11, },
+	{ .chan = 13, .c1 = -64, .c0 = 11, },
+	{ .chan = 14, .c1 = -64, .c0 = 10, },
+	{ .chan = 34, .c1 = -62, .c0 = 24, },
+	{ .chan = 38, .c1 = -62, .c0 = 24, },
+	{ .chan = 42, .c1 = -62, .c0 = 24, },
+	{ .chan = 46, .c1 = -62, .c0 = 23, },
+	{ .chan = 36, .c1 = -62, .c0 = 24, },
+	{ .chan = 40, .c1 = -62, .c0 = 24, },
+	{ .chan = 44, .c1 = -62, .c0 = 23, },
+	{ .chan = 48, .c1 = -62, .c0 = 23, },
+	{ .chan = 52, .c1 = -62, .c0 = 23, },
+	{ .chan = 56, .c1 = -62, .c0 = 22, },
+	{ .chan = 60, .c1 = -62, .c0 = 22, },
+	{ .chan = 64, .c1 = -62, .c0 = 22, },
+	{ .chan = 100, .c1 = -62, .c0 = 16, },
+	{ .chan = 104, .c1 = -62, .c0 = 16, },
+	{ .chan = 108, .c1 = -62, .c0 = 15, },
+	{ .chan = 112, .c1 = -62, .c0 = 14, },
+	{ .chan = 116, .c1 = -62, .c0 = 14, },
+	{ .chan = 120, .c1 = -62, .c0 = 13, },
+	{ .chan = 124, .c1 = -62, .c0 = 12, },
+	{ .chan = 128, .c1 = -62, .c0 = 12, },
+	{ .chan = 132, .c1 = -62, .c0 = 12, },
+	{ .chan = 136, .c1 = -62, .c0 = 11, },
+	{ .chan = 140, .c1 = -62, .c0 = 10, },
+	{ .chan = 149, .c1 = -61, .c0 = 9, },
+	{ .chan = 153, .c1 = -61, .c0 = 9, },
+	{ .chan = 157, .c1 = -61, .c0 = 9, },
+	{ .chan = 161, .c1 = -61, .c0 = 8, },
+	{ .chan = 165, .c1 = -61, .c0 = 8, },
+	{ .chan = 184, .c1 = -62, .c0 = 25, },
+	{ .chan = 188, .c1 = -62, .c0 = 25, },
+	{ .chan = 192, .c1 = -62, .c0 = 25, },
+	{ .chan = 196, .c1 = -62, .c0 = 25, },
+	{ .chan = 200, .c1 = -62, .c0 = 25, },
+	{ .chan = 204, .c1 = -62, .c0 = 25, },
+	{ .chan = 208, .c1 = -62, .c0 = 25, },
+	{ .chan = 212, .c1 = -62, .c0 = 25, },
+	{ .chan = 216, .c1 = -62, .c0 = 26, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
+	.chan = 0,
+	.c1 = -64,
+	.c0 = 0,
+};
+
+static u8 lpphy_nbits(s32 val)
+{
+	u32 tmp = abs(val);
+	u8 nbits = 0;
+
+	while (tmp != 0) {
+		nbits++;
+		tmp >>= 1;
+	}
+
+	return nbits;
+}
+
+static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
+{
+	struct lpphy_iq_est iq_est;
+	u16 c0, c1;
+	int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
+
+	c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
+	c0 = c1 >> 8;
+	c1 |= 0xFF;
+
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
+	b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
+
+	ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
+	if (!ret)
+		goto out;
+
+	prod = iq_est.iq_prod;
+	ipwr = iq_est.i_pwr;
+	qpwr = iq_est.q_pwr;
+
+	if (ipwr + qpwr < 2) {
+		ret = 0;
+		goto out;
+	}
+
+	prod_msb = lpphy_nbits(prod);
+	q_msb = lpphy_nbits(qpwr);
+	tmp1 = prod_msb - 20;
+
+	if (tmp1 >= 0) {
+		tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
+			(ipwr >> tmp1);
+	} else {
+		tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
+			(ipwr << -tmp1);
+	}
+
+	tmp2 = q_msb - 11;
+
+	if (tmp2 >= 0)
+		tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
+	else
+		tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
+
+	tmp4 -= tmp3 * tmp3;
+	tmp4 = -int_sqrt(tmp4);
+
+	c0 = tmp3 >> 3;
+	c1 = tmp4 >> 4;
+
+out:
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
+	return ret;
+}
+
+/* Complex number using 2 32-bit signed integers */
+typedef struct {s32 i, q;} lpphy_c32;
+
+static lpphy_c32 lpphy_cordic(int theta)
+{
+	u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
+		      58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
+		      229, 115, 57, 29, };
+	int i, tmp, signx = 1, angle = 0;
+	lpphy_c32 ret = { .i = 39797, .q = 0, };
+
+	theta = clamp_t(int, theta, -180, 180);
+
+	if (theta > 90) {
+		theta -= 180;
+		signx = -1;
+	} else if (theta < -90) {
+		theta += 180;
+		signx = -1;
+	}
+
+	for (i = 0; i <= 17; i++) {
+		if (theta > angle) {
+			tmp = ret.i - (ret.q >> i);
+			ret.q += ret.i >> i;
+			ret.i = tmp + arctg[i];
+		} else {
+			tmp = ret.i + (ret.q >> i);
+			ret.q -= ret.i >> i;
+			ret.i = tmp - arctg[i];
+		}
+	}
+
+	ret.i *= signx;
+	ret.q *= signx;
+
+	return ret;
+}
+
+static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
+			      u16 wait)
+{
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
+			0xFFC0, samples - 1);
+	if (loops != 0xFFFF)
+		loops--;
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
+	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
+	b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
+}
+
+//SPEC FIXME what does a negative freq mean?
+static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 buf[64];
+	int i, samples, angle = 0, rotation = (9 * freq) / 500;
+	lpphy_c32 sample;
+
+	lpphy->tx_tone_freq = freq;
+
+	if (freq) {
+		/* Find i for which abs(freq) integrally divides 20000 * i */
+		for (i = 1; samples * abs(freq) != 20000 * i; i++) {
+			samples = (20000 * i) / abs(freq);
+			if(B43_WARN_ON(samples > 63))
+				return;
+		}
+	} else {
+		samples = 2;
+	}
+
+	for (i = 0; i < samples; i++) {
+		sample = lpphy_cordic(angle);
+		angle += rotation;
+		buf[i] = ((sample.i * max) & 0xFF) << 8;
+		buf[i] |= (sample.q * max) & 0xFF;
+	}
+
+	b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
+
+	lpphy_run_samples(dev, samples, 0xFFFF, 0);
+}
+
+static void lpphy_stop_tx_tone(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	int i;
+
+	lpphy->tx_tone_freq = 0;
+
+	b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
+	for (i = 0; i < 31; i++) {
+		if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
+			break;
+		udelay(100);
+	}
+}
+
+
+static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
+			   int mode, bool useindex, u8 index)
+{
 	//TODO
+}
 
-	kfree(saved_tab);
+static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct lpphy_tx_gains gains, oldgains;
+	int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
+
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	old_txpctl = lpphy->txpctl_mode;
+	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+	if (old_afe_ovr)
+		oldgains = lpphy_get_tx_gains(dev);
+	old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
+	old_bbmult = lpphy_get_bb_mult(dev);
+
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+
+	if (bus->chip_id == 0x4325 && bus->chip_rev == 0)
+		lpphy_papd_cal(dev, gains, 0, 1, 30);
+	else
+		lpphy_papd_cal(dev, gains, 0, 1, 65);
+
+	if (old_afe_ovr)
+		lpphy_set_tx_gains(dev, oldgains);
+	lpphy_set_bb_mult(dev, old_bbmult);
+	lpphy_set_tx_power_control(dev, old_txpctl);
+	b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
+}
+
+static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
+			    bool rx, bool pa, struct lpphy_tx_gains *gains)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct ssb_bus *bus = dev->dev->bus;
+	const struct lpphy_rx_iq_comp *iqcomp = NULL;
+	struct lpphy_tx_gains nogains, oldgains;
+	u16 tmp;
+	int i, ret;
+
+	memset(&nogains, 0, sizeof(nogains));
+	memset(&oldgains, 0, sizeof(oldgains));
+
+	if (bus->chip_id == 0x5354) {
+		for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
+			if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
+				iqcomp = &lpphy_5354_iq_table[i];
+			}
+		}
+	} else if (dev->phy.rev >= 2) {
+		iqcomp = &lpphy_rev2plus_iq_comp;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
+			if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
+				iqcomp = &lpphy_rev0_1_iq_table[i];
+			}
+		}
+	}
+
+	if (B43_WARN_ON(!iqcomp))
+		return 0;
+
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
+	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
+			0x00FF, iqcomp->c0 << 8);
+
+	if (noise) {
+		tx = true;
+		rx = false;
+		pa = false;
+	}
+
+	lpphy_set_trsw_over(dev, tx, rx);
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+				0xFFF7, pa << 3);
+	} else {
+		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
+		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+				0xFFDF, pa << 5);
+	}
+
+	tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+
+	if (noise)
+		lpphy_set_rx_gain(dev, 0x2D5D);
+	else {
+		if (tmp)
+			oldgains = lpphy_get_tx_gains(dev);
+		if (!gains)
+			gains = &nogains;
+		lpphy_set_tx_gains(dev, *gains);
+	}
+
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
+	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
+	lpphy_set_deaf(dev, false);
+	if (noise)
+		ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
+	else {
+		lpphy_start_tx_tone(dev, 4000, 100);
+		ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
+		lpphy_stop_tx_tone(dev);
+	}
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
+	if (!noise) {
+		if (tmp)
+			lpphy_set_tx_gains(dev, oldgains);
+		else
+			lpphy_disable_tx_gain_override(dev);
+	}
+	lpphy_disable_rx_gain_override(dev);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
+	return ret;
 }
 
 static void lpphy_calibration(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
 	enum b43_lpphy_txpctl_mode saved_pctl_mode;
+	bool full_cal = false;
+
+	if (lpphy->full_calib_chan != lpphy->channel) {
+		full_cal = true;
+		lpphy->full_calib_chan = lpphy->channel;
+	}
 
 	b43_mac_suspend(dev);
 
 	lpphy_btcoex_override(dev);
+	if (dev->phy.rev >= 2)
+		lpphy_save_dig_flt_state(dev);
 	lpphy_read_tx_pctl_mode_from_hardware(dev);
 	saved_pctl_mode = lpphy->txpctl_mode;
 	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
 	//TODO Perform transmit power table I/Q LO calibration
 	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
 		lpphy_pr41573_workaround(dev);
-	//TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration
+	if ((dev->phy.rev >= 2) && full_cal) {
+		lpphy_papd_cal_txpwr(dev);
+	}
 	lpphy_set_tx_power_control(dev, saved_pctl_mode);
-	//TODO Perform I/Q calibration with a single control value set
+	if (dev->phy.rev >= 2)
+		lpphy_restore_dig_flt_state(dev);
+	lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
 
 	b43_mac_enable(dev);
 }
@@ -1532,12 +2073,6 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
-static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
-					 bool blocked)
-{
-	//TODO
-}
-
 struct b206x_channel {
 	u8 channel;
 	u16 freq;
@@ -2003,22 +2538,6 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
 	return err;
 }
 
-
-/* This was previously called lpphy_japan_filter */
-static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
-{
-	struct b43_phy_lp *lpphy = dev->phy.lp;
-	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
-
-	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
-		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
-		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
-			lpphy_set_rc_cap(dev);
-	} else {
-		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
-	}
-}
-
 static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
 {
 	u16 tmp;
@@ -2203,18 +2722,6 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
 	return 0;
 }
 
-static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
-{
-	if (dev->phy.rev >= 2)
-		return; // rev2+ doesn't support antenna diversity
-
-	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
-		return;
-
-	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
-	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
-}
-
 static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
 {
 	//TODO
@@ -2227,6 +2734,11 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
 	return B43_TXPWR_RES_DONE;
 }
 
+static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
+{
+	//TODO
+}
+
 const struct b43_phy_operations b43_phyops_lp = {
 	.allocate		= b43_lpphy_op_allocate,
 	.free			= b43_lpphy_op_free,
@@ -2244,4 +2756,6 @@ const struct b43_phy_operations b43_phyops_lp = {
 	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
 	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
 	.adjust_txpower		= b43_lpphy_op_adjust_txpower,
+	.pwork_15sec		= b43_lpphy_op_pwork_15sec,
+	.pwork_60sec		= lpphy_calibration,
 };
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
index c3232c1..62737f7 100644
--- a/drivers/net/wireless/b43/phy_lp.h
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -286,6 +286,7 @@
 #define B43_LPPHY_TR_LOOKUP_6			B43_PHY_OFDM(0xC8) /* TR Lookup 6 */
 #define B43_LPPHY_TR_LOOKUP_7			B43_PHY_OFDM(0xC9) /* TR Lookup 7 */
 #define B43_LPPHY_TR_LOOKUP_8			B43_PHY_OFDM(0xCA) /* TR Lookup 8 */
+#define B43_LPPHY_RF_PWR_OVERRIDE		B43_PHY_OFDM(0xD3) /* RF power override */
 
 
 
@@ -871,12 +872,12 @@ struct b43_phy_lp {
 	u8 rssi_gs;
 
 	/* RC cap */
-	u8 rc_cap; /* FIXME initial value? */
+	u8 rc_cap;
 	/* BX arch */
 	u8 bx_arch;
 
 	/* Full calibration channel */
-	u8 full_calib_chan; /* FIXME initial value? */
+	u8 full_calib_chan;
 
 	/* Transmit iqlocal best coeffs */
 	bool tx_iqloc_best_coeffs_valid;
@@ -891,6 +892,12 @@ struct b43_phy_lp {
 
 	/* The channel we are tuned to */
 	u8 channel;
+
+	/* The active antenna diversity mode */
+	int antenna;
+
+	/* Frequency of the active TX tone */
+	int tx_tone_freq;
 };
 
 enum tssi_mux_mode {
-- 
1.6.2.4




^ permalink raw reply related

* Re: [rt2x00-users] [PATCH] rt2x00: Reorganize padding & L2 padding
From: Benoit PAPILLAULT @ 2009-08-29 20:33 UTC (permalink / raw)
  To: rt2x00 Users List; +Cc: John Linville, linux-wireless
In-Reply-To: <200908292030.45659.IvDoorn@gmail.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ivo van Doorn a écrit :
> The old function rt2x00queue_payload_align() handled both adding
> and removing L2 padding and some basic frame alignment. The entire
> function was being abused because it had multiple functions and the
> header length argument was somtimes used to align the header
> instead of the payload.
>
> Additionally there was a bug when inserting L2 padding that only
> the payload was aligned but not the header. This happens when the
> header wasn't aligned properly by mac80211, but rt2x00lib only
> moves the payload.
>
> A secondary problem was that when removing L2 padding during TXdone
> or RX the skb wasn't resized to the proper size.
>
> Split the function into seperate functions each handling its task
> as it should.
>
> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> ---
> drivers/net/wireless/rt2x00/rt2x00crypto.c |    6 +-
> drivers/net/wireless/rt2x00/rt2x00dev.c    |   10 ++--
> drivers/net/wireless/rt2x00/rt2x00lib.h    |   45 +++++++++----
> drivers/net/wireless/rt2x00/rt2x00queue.c  |   99
> +++++++++++++++++++++------- 4 files changed, 116 insertions(+), 44
> deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c
> b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 30fbd3b..de36837
> 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++
> b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -154,7 +154,7 @@
> void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int
> header_length) skbdesc->flags &= ~SKBDESC_IV_STRIPPED; }
>
> -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
> +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int
> header_length, struct rxdone_entry_desc *rxdesc) { @@ -199,7 +199,7
> @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
> * move the header more then iv_len since we must * make room for
> the payload move as well. */ -    if (l2pad) { +    if (rxdesc->dev_flags
> & RXDONE_L2PAD) { skb_push(skb, iv_len - align); skb_put(skb,
> icv_len);
>
> @@ -230,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff
> *skb, bool l2pad, * Move payload for alignment purposes. Note that
> * this is only needed when no l2 padding is present. */ -    if
> (!l2pad) { +    if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
> memmove(skb->data + transfer, skb->data + transfer + align,
> payload_len); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c
> b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3f8c70e..5db613f
> 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++
> b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -216,7 +216,7 @@ void
> rt2x00lib_txdone(struct queue_entry *entry, * Remove L2 padding
> which was added during */ if (test_bit(DRIVER_REQUIRE_L2PAD,
> &rt2x00dev->flags)) -        rt2x00queue_payload_align(entry->skb, true,
> header_length); +        rt2x00queue_remove_l2pad(entry->skb,
> header_length);
>
> /* * If the IV/EIV data was stripped from the frame before it was
> @@ -360,7 +360,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev
> *rt2x00dev, struct sk_buff *skb; struct ieee80211_rx_status
> *rx_status = &rt2x00dev->rx_status; unsigned int header_length; -
> bool l2pad; int rate_idx; /* * Allocate a new sk_buffer. If no new
> buffer available, drop the @@ -389,7 +388,6 @@ void
> rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * aligned on a 4
> byte boundary. */ header_length =
> ieee80211_get_hdrlen_from_skb(entry->skb); -    l2pad =
> !!(rxdesc.dev_flags & RXDONE_L2PAD);
>
> /* * Hardware might have stripped the IV/EIV/ICV data, @@ -399,10
> +397,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, */
> if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && (rxdesc.flags &
> RX_FLAG_IV_STRIPPED)) -        rt2x00crypto_rx_insert_iv(entry->skb,
> l2pad, header_length, +        rt2x00crypto_rx_insert_iv(entry->skb,
> header_length, &rxdesc); +    else if (rxdesc.dev_flags &
> RXDONE_L2PAD) +        rt2x00queue_remove_l2pad(entry->skb,
> header_length); else -        rt2x00queue_payload_align(entry->skb,
> l2pad, header_length); +        rt2x00queue_align_payload(entry->skb,
> header_length);
>
> /* * Check if the frame was received using HT. In that case, diff
> --git a/drivers/net/wireless/rt2x00/rt2x00lib.h
> b/drivers/net/wireless/rt2x00/rt2x00lib.h index eeb2881..5462cb5
> 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++
> b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -120,21 +120,42 @@
> void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct
> sk_buff *skb); void rt2x00queue_free_skb(struct rt2x00_dev
> *rt2x00dev, struct sk_buff *skb);
>
> /** - * rt2x00queue_payload_align - Align 802.11 payload to 4-byte
> boundary + * rt2x00queue_align_frame - Align 802.11 frame to 4-byte
> boundary + * @skb: The skb to align + * + * Align the start of the
> 802.11 frame to a 4-byte boundary, this could + * mean the payload
> is not aligned properly though. + */ +void
> rt2x00queue_align_frame(struct sk_buff *skb); + +/** + *
> rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
>  + * @skb: The skb to align + * @header_length: Length of 802.11
> header + * + * Align the 802.11 payload to a 4-byte boundary, this
> could + * mean the header is not aligned properly though. + */
> +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int
> header_length); + +/** + * rt2x00queue_insert_l2pad - Align 802.11
> header & payload to 4-byte boundary + * @skb: The skb to align + *
> @header_length: Length of 802.11 header + * + * Apply L2 padding to
> align both header and payload to 4-byte boundary + */ +void
> rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int
> header_length); + +/** + * rt2x00queue_insert_l2pad - Remove L2
> padding from 802.11 frame * @skb: The skb to align - * @l2pad:
> Should L2 padding be used * @header_length: Length of 802.11 header
>  * - * This function prepares the @skb to be send to the device or
> mac80211. - * If @l2pad is set to true padding will occur between
> the 802.11 header - * and payload. Otherwise the padding will be
> done in front of the 802.11 - * header. - * When @l2pad is set the
> function will check for the &SKBDESC_L2_PADDED - * flag in
> &skb_frame_desc. If that flag is set, the padding is removed - *
> and the flag cleared. Otherwise the padding is added and the flag
> is set. + * Remove L2 padding used to align both header and payload
> to 4-byte boundary, + * by removing the L2 padding the header will
> no longer be 4-byte aligned. */ -void
> rt2x00queue_payload_align(struct sk_buff *skb, -                   bool
> l2pad, unsigned int header_length); +void
> rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int
> header_length);
>
> /** * rt2x00queue_write_tx_frame - Write TX frame to hardware @@
> -324,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
> void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct
> txentry_desc *txdesc); void rt2x00crypto_tx_insert_iv(struct
> sk_buff *skb, unsigned int header_length); -void
> rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, +void
> rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int
> header_length, struct rxdone_entry_desc *rxdesc); #else diff --git
> a/drivers/net/wireless/rt2x00/rt2x00queue.c
> b/drivers/net/wireless/rt2x00/rt2x00queue.c index 06af823..577029e
> 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++
> b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,35 +148,89 @@
> void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct
> sk_buff *skb) dev_kfree_skb_any(skb); }
>
> -void rt2x00queue_payload_align(struct sk_buff *skb, -
> bool l2pad, unsigned int header_length) +void
> rt2x00queue_align_frame(struct sk_buff *skb) { -    struct
> skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int
> frame_length = skb->len; -    unsigned int align = ALIGN_SIZE(skb,
> header_length); +    unsigned int align = ALIGN_SIZE(skb, 0);
>
> if (!align) return;
>
> -    if (l2pad) { -        if (skbdesc->flags & SKBDESC_L2_PADDED) {
-            /*
> Remove L2 padding */ -            memmove(skb->data + align, skb->data,
> header_length); -            skb_pull(skb, align); -           
skbdesc->flags &=
> ~SKBDESC_L2_PADDED; -        } else { -            /* Add L2 padding */ -
> skb_push(skb, align); -            memmove(skb->data, skb->data + align,
> header_length); -            skbdesc->flags |= SKBDESC_L2_PADDED;
-        } +
> skb_push(skb, align); +    memmove(skb->data, skb->data + align,
> frame_length); +    skb_trim(skb, frame_length); +} + +void
> rt2x00queue_align_payload(struct sk_buff *skb, unsigned int
> header_lengt) +{ +    unsigned int frame_length = skb->len; +    unsigned
> int align = ALIGN_SIZE(skb, header_lengt); + +    if (!align) +
> return; + +    skb_push(skb, align); +    memmove(skb->data, skb->data +
> align, frame_length); +    skb_trim(skb, frame_length); +} + +void
> rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int
> header_length) +{ +    struct skb_frame_desc *skbdesc =
> get_skb_frame_desc(skb); +    unsigned int frame_length = skb->len; +
> unsigned int header_align = ALIGN_SIZE(skb, 0); +    unsigned int
> payload_align = ALIGN_SIZE(skb, header_length); +    unsigned int
> l2pad = 4 - (payload_align - header_align); + +    if (header_align ==
> payload_align) { +        /* +         * Both header and payload must
be moved
> the same +         * amount of bytes to align them properly. This means +
> * we don't use the L2 padding but just move the entire +         * frame.
>  +         */ +        rt2x00queue_align_frame(skb); +    } else if
> (!payload_align) { +        /* +         * Simple L2 padding, only the
header
> needs to be moved, +         * the payload is already properly aligned. +
> */ +        skb_push(skb, header_align); +        memmove(skb->data,
skb->data
> + header_align, frame_length); +        skbdesc->flags |=
> SKBDESC_L2_PADDED; } else { -        /* Generic payload alignment to
> 4-byte boundary */ -        skb_push(skb, align); -       
memmove(skb->data,
> skb->data + align, frame_length); +        /* +         * +         *
Complicated L2
> padding, both header and payload need +         * to be moved. By default
> we only move to the start +         * of the buffer, so our header
> alignment needs to be +         * increased if there is not enough room
> for the header +         * to be moved. +         */ +        if
(payload_align >
> header_align) +            header_align += 4; + +        skb_push(skb,
> header_align); +        memmove(skb->data, skb->data + header_align,
> header_length); +        memmove(skb->data + header_length + l2pad, +
> skb->data + header_length + l2pad + header_align, +            frame_length
> - header_length); +        skbdesc->flags |= SKBDESC_L2_PADDED; } }
>
> +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int
> header_length) +{ +    struct skb_frame_desc *skbdesc =
> get_skb_frame_desc(skb); +    unsigned int l2pad = 4 - (header_length
> & 3);
This formula is incorrect, it should be at least (4 -
(header_length%4)%4). I have a fix in my pending patches...
If header_length is 0 => l2pad should be 0 as well.

> + +    if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) +       
return;
> + +    memmove(skb->data + l2pad, skb->data, header_length); +
> skb_pull(skb, l2pad); +} + static void
> rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
> struct txentry_desc *txdesc) { @@ -456,18 +510,15 @@ int
> rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff
> *skb) /* * When DMA allocation is required we should guarentee to
> the * driver that the DMA is aligned to a 4-byte boundary. -     *
> Aligning the header to this boundary can be done by calling -     *
> rt2x00queue_payload_align with the header length of 0. * However
> some drivers require L2 padding to pad the payload * rather then
> the header. This could be a requirement for * PCI and USB devices,
> while header alignment only is valid * for PCI devices. */ if
> (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) -
> rt2x00queue_payload_align(entry->skb, true, -
> txdesc.header_length); +        rt2x00queue_insert_l2pad(entry->skb,
> txdesc.header_length); else if (test_bit(DRIVER_REQUIRE_DMA,
> &queue->rt2x00dev->flags)) -        rt2x00queue_payload_align(entry->skb,
> false, 0); +        rt2x00queue_align_frame(entry->skb);
>
> /* * It could be possible that the queue was corrupted and this
Regards,
Benoit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkqZkKUACgkQOR6EySwP7oJcQwCfUBeCwBVJHDWt0B1RINNZNt/G
pUQAoKTx2BizEOoUR7hB3sRvxbORJRMy
=LuW0
-----END PGP SIGNATURE-----


^ permalink raw reply

* Re: [rt2x00-users] [PATCH] rt2x00: Fix TX status reporting
From: Benoit PAPILLAULT @ 2009-08-29 20:31 UTC (permalink / raw)
  To: rt2x00 Users List; +Cc: John Linville, linux-wireless
In-Reply-To: <200908291910.14528.IvDoorn@gmail.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ivo van Doorn a écrit :
> Not all values of the TX status enumeration were covered during
> updating of the TX statistics. This could lead to wrong bitrate
> tuning but also wrong behavior in tools like hostapd.
>
> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
I have a pending patch about TX status that changed the meaning of
TXDONE_FALLBACK just a bit... just to avoid this change in fact.
I should be able to send those patches in few hours.

In my code, you success/failure of the packet is reported with
TXDONE_SUCCESS / TXDONE_FAILURE. The TXDONE_FALLBACK is set
independently to indicate that a fallback rate table has been used
(and this could be the case for either success or failure).

Regards,
Benoit

> --- drivers/net/wireless/rt2x00/rt2x00dev.c |   28
> ++++++++++++++++------------ 1 files changed, 16 insertions(+), 12
> deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c
> b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5db613f..71761b3
> 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++
> b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -206,6 +206,7 @@ void
> rt2x00lib_txdone(struct queue_entry *entry, unsigned int
> header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8
> rate_idx, rate_flags, retry_rates; unsigned int i; +    bool success;
>
> /* * Unmap the skb. @@ -234,13 +235,18 @@ void
> rt2x00lib_txdone(struct queue_entry *entry,
> rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
>
> /* -     * Update TX statistics. +     * Determine if the frame has been
> successfully transmitted. */ -    rt2x00dev->link.qual.tx_success += +
> success = test_bit(TXDONE_SUCCESS, &txdesc->flags) || -
> test_bit(TXDONE_UNKNOWN, &txdesc->flags); -
> rt2x00dev->link.qual.tx_failed += -        test_bit(TXDONE_FAILURE,
> &txdesc->flags); +        test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
> +        test_bit(TXDONE_FALLBACK, &txdesc->flags); + +    /* +     *
Update
> TX statistics. +     */ +    rt2x00dev->link.qual.tx_success += success;
> +    rt2x00dev->link.qual.tx_failed += !success;
>
> rate_idx = skbdesc->tx_rate_idx; rate_flags =
> skbdesc->tx_rate_flags; @@ -263,22 +269,20 @@ void
> rt2x00lib_txdone(struct queue_entry *entry,
> tx_info->status.rates[i].flags = rate_flags;
> tx_info->status.rates[i].count = 1; } -    if (i <
> (IEEE80211_TX_MAX_RATES -1)) +    if (i < (IEEE80211_TX_MAX_RATES -
> 1)) tx_info->status.rates[i].idx = -1; /* terminate */
>
> if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { -        if
> (test_bit(TXDONE_SUCCESS, &txdesc->flags) || -
> test_bit(TXDONE_UNKNOWN, &txdesc->flags)) +        if (success)
> tx_info->flags |= IEEE80211_TX_STAT_ACK; -        else if
> (test_bit(TXDONE_FAILURE, &txdesc->flags)) +        else
> rt2x00dev->low_level_stats.dot11ACKFailureCount++; }
>
> if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { -        if
> (test_bit(TXDONE_SUCCESS, &txdesc->flags) || -
> test_bit(TXDONE_UNKNOWN, &txdesc->flags)) +        if (success)
> rt2x00dev->low_level_stats.dot11RTSSuccessCount++; -        else if
> (test_bit(TXDONE_FAILURE, &txdesc->flags)) +        else
> rt2x00dev->low_level_stats.dot11RTSFailureCount++; }
>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkqZkB8ACgkQOR6EySwP7oKnaQCglW+lu167n88CR3Chv1i4uF1P
I1kAoLrVvvXCbmzWN8M2/wHtyTSCnUZu
=IJEh
-----END PGP SIGNATURE-----


^ permalink raw reply

* Re: [ath5k-devel] Ath5k and proprietary extensions
From: Luis R. Rodriguez @ 2009-08-29 19:15 UTC (permalink / raw)
  To: Nick Kossifidis
  Cc: Benoit PAPILLAULT, ic.felix, ath5k-devel, linux-wireless,
	John W. Linville
In-Reply-To: <40f31dec0908290847g698a65e2t589a466a13b1b7f5@mail.gmail.com>

On Sat, Aug 29, 2009 at 8:47 AM, Nick Kossifidis<mickflemm@gmail.com> wrote:
> 2009/8/29 Benoit PAPILLAULT <benoit.papillault@free.fr>:
>>
>> I have been working on XR (in madwifi) for some time with no result. I
>> would appreciate to be able to test it in ath5k.
>
> All XR related stuff is missing from both Legacy and Sam's HAL + it's
> nasty IMHO.

Agreed.

  Luis

^ permalink raw reply

* [PATCH] rt2x00: Reorganize padding & L2 padding
From: Ivo van Doorn @ 2009-08-29 18:30 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users

The old function rt2x00queue_payload_align() handled
both adding and removing L2 padding and some basic
frame alignment. The entire function was being abused
because it had multiple functions and the header length
argument was somtimes used to align the header instead
of the payload.

Additionally there was a bug when inserting L2 padding
that only the payload was aligned but not the header. This
happens when the header wasn't aligned properly by mac80211,
but rt2x00lib only moves the payload.

A secondary problem was that when removing L2 padding during
TXdone or RX the skb wasn't resized to the proper size.

Split the function into seperate functions each handling
its task as it should.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
 drivers/net/wireless/rt2x00/rt2x00crypto.c |    6 +-
 drivers/net/wireless/rt2x00/rt2x00dev.c    |   10 ++--
 drivers/net/wireless/rt2x00/rt2x00lib.h    |   45 +++++++++----
 drivers/net/wireless/rt2x00/rt2x00queue.c  |   99 +++++++++++++++++++++-------
 4 files changed, 116 insertions(+), 44 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 30fbd3b..de36837 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -154,7 +154,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
 	skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
 }
 
-void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
 			       unsigned int header_length,
 			       struct rxdone_entry_desc *rxdesc)
 {
@@ -199,7 +199,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
 	 * move the header more then iv_len since we must
 	 * make room for the payload move as well.
 	 */
-	if (l2pad) {
+	if (rxdesc->dev_flags & RXDONE_L2PAD) {
 		skb_push(skb, iv_len - align);
 		skb_put(skb, icv_len);
 
@@ -230,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
 	 * Move payload for alignment purposes. Note that
 	 * this is only needed when no l2 padding is present.
 	 */
-	if (!l2pad) {
+	if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
 		memmove(skb->data + transfer,
 			skb->data + transfer + align,
 			payload_len);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 3f8c70e..5db613f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -216,7 +216,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 	 * Remove L2 padding which was added during
 	 */
 	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
-		rt2x00queue_payload_align(entry->skb, true, header_length);
+		rt2x00queue_remove_l2pad(entry->skb, header_length);
 
 	/*
 	 * If the IV/EIV data was stripped from the frame before it was
@@ -360,7 +360,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
 	struct sk_buff *skb;
 	struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
 	unsigned int header_length;
-	bool l2pad;
 	int rate_idx;
 	/*
 	 * Allocate a new sk_buffer. If no new buffer available, drop the
@@ -389,7 +388,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
 	 * aligned on a 4 byte boundary.
 	 */
 	header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-	l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD);
 
 	/*
 	 * Hardware might have stripped the IV/EIV/ICV data,
@@ -399,10 +397,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
 	 */
 	if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
 	    (rxdesc.flags & RX_FLAG_IV_STRIPPED))
-		rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length,
+		rt2x00crypto_rx_insert_iv(entry->skb, header_length,
 					  &rxdesc);
+	else if (rxdesc.dev_flags & RXDONE_L2PAD)
+		rt2x00queue_remove_l2pad(entry->skb, header_length);
 	else
-		rt2x00queue_payload_align(entry->skb, l2pad, header_length);
+		rt2x00queue_align_payload(entry->skb, header_length);
 
 	/*
 	 * Check if the frame was received using HT. In that case,
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index eeb2881..5462cb5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -120,21 +120,42 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
- * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary
+ * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
+ * @skb: The skb to align
+ *
+ * Align the start of the 802.11 frame to a 4-byte boundary, this could
+ * mean the payload is not aligned properly though.
+ */
+void rt2x00queue_align_frame(struct sk_buff *skb);
+
+/**
+ * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
+ * @skb: The skb to align
+ * @header_length: Length of 802.11 header
+ *
+ * Align the 802.11 payload to a 4-byte boundary, this could
+ * mean the header is not aligned properly though.
+ */
+void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
+
+/**
+ * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
+ * @skb: The skb to align
+ * @header_length: Length of 802.11 header
+ *
+ * Apply L2 padding to align both header and payload to 4-byte boundary
+ */
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length);
+
+/**
+ * rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame
  * @skb: The skb to align
- * @l2pad: Should L2 padding be used
  * @header_length: Length of 802.11 header
  *
- * This function prepares the @skb to be send to the device or mac80211.
- * If @l2pad is set to true padding will occur between the 802.11 header
- * and payload. Otherwise the padding will be done in front of the 802.11
- * header.
- * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED
- * flag in &skb_frame_desc. If that flag is set, the padding is removed
- * and the flag cleared. Otherwise the padding is added and the flag is set.
+ * Remove L2 padding used to align both header and payload to 4-byte boundary,
+ * by removing the L2 padding the header will no longer be 4-byte aligned.
  */
-void rt2x00queue_payload_align(struct sk_buff *skb,
-			       bool l2pad, unsigned int header_length);
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
 
 /**
  * rt2x00queue_write_tx_frame - Write TX frame to hardware
@@ -324,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
 void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
 			       struct txentry_desc *txdesc);
 void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length);
-void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
 			       unsigned int header_length,
 			       struct rxdone_entry_desc *rxdesc);
 #else
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 06af823..577029e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 	dev_kfree_skb_any(skb);
 }
 
-void rt2x00queue_payload_align(struct sk_buff *skb,
-			       bool l2pad, unsigned int header_length)
+void rt2x00queue_align_frame(struct sk_buff *skb)
 {
-	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 	unsigned int frame_length = skb->len;
-	unsigned int align = ALIGN_SIZE(skb, header_length);
+	unsigned int align = ALIGN_SIZE(skb, 0);
 
 	if (!align)
 		return;
 
-	if (l2pad) {
-		if (skbdesc->flags & SKBDESC_L2_PADDED) {
-			/* Remove L2 padding */
-			memmove(skb->data + align, skb->data, header_length);
-			skb_pull(skb, align);
-			skbdesc->flags &= ~SKBDESC_L2_PADDED;
-		} else {
-			/* Add L2 padding */
-			skb_push(skb, align);
-			memmove(skb->data, skb->data + align, header_length);
-			skbdesc->flags |= SKBDESC_L2_PADDED;
-		}
+	skb_push(skb, align);
+	memmove(skb->data, skb->data + align, frame_length);
+	skb_trim(skb, frame_length);
+}
+
+void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt)
+{
+	unsigned int frame_length = skb->len;
+	unsigned int align = ALIGN_SIZE(skb, header_lengt);
+
+	if (!align)
+		return;
+
+	skb_push(skb, align);
+	memmove(skb->data, skb->data + align, frame_length);
+	skb_trim(skb, frame_length);
+}
+
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
+{
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+	unsigned int frame_length = skb->len;
+	unsigned int header_align = ALIGN_SIZE(skb, 0);
+	unsigned int payload_align = ALIGN_SIZE(skb, header_length);
+	unsigned int l2pad = 4 - (payload_align - header_align);
+
+	if (header_align == payload_align) {
+		/*
+		 * Both header and payload must be moved the same
+		 * amount of bytes to align them properly. This means
+		 * we don't use the L2 padding but just move the entire
+		 * frame.
+		 */
+		rt2x00queue_align_frame(skb);
+	} else if (!payload_align) {
+		/*
+		 * Simple L2 padding, only the header needs to be moved,
+		 * the payload is already properly aligned.
+		 */
+		skb_push(skb, header_align);
+		memmove(skb->data, skb->data + header_align, frame_length);
+		skbdesc->flags |= SKBDESC_L2_PADDED;
 	} else {
-		/* Generic payload alignment to 4-byte boundary */
-		skb_push(skb, align);
-		memmove(skb->data, skb->data + align, frame_length);
+		/*
+		 *
+		 * Complicated L2 padding, both header and payload need
+		 * to be moved. By default we only move to the start
+		 * of the buffer, so our header alignment needs to be
+		 * increased if there is not enough room for the header
+		 * to be moved.
+		 */
+		if (payload_align > header_align)
+			header_align += 4;
+
+		skb_push(skb, header_align);
+		memmove(skb->data, skb->data + header_align, header_length);
+		memmove(skb->data + header_length + l2pad,
+			skb->data + header_length + l2pad + header_align,
+			frame_length - header_length);
+		skbdesc->flags |= SKBDESC_L2_PADDED;
 	}
 }
 
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
+{
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+	unsigned int l2pad = 4 - (header_length & 3);
+
+	if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
+		return;
+
+	memmove(skb->data + l2pad, skb->data, header_length);
+	skb_pull(skb, l2pad);
+}
+
 static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
 						 struct txentry_desc *txdesc)
 {
@@ -456,18 +510,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	/*
 	 * When DMA allocation is required we should guarentee to the
 	 * driver that the DMA is aligned to a 4-byte boundary.
-	 * Aligning the header to this boundary can be done by calling
-	 * rt2x00queue_payload_align with the header length of 0.
 	 * However some drivers require L2 padding to pad the payload
 	 * rather then the header. This could be a requirement for
 	 * PCI and USB devices, while header alignment only is valid
 	 * for PCI devices.
 	 */
 	if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
-		rt2x00queue_payload_align(entry->skb, true,
-					  txdesc.header_length);
+		rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
 	else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
-		rt2x00queue_payload_align(entry->skb, false, 0);
+		rt2x00queue_align_frame(entry->skb);
 
 	/*
 	 * It could be possible that the queue was corrupted and this
-- 
1.6.4.1


^ permalink raw reply related

* [PATCH] rt2x00: Fix TX status reporting
From: Ivo van Doorn @ 2009-08-29 17:10 UTC (permalink / raw)
  To: John Linville; +Cc: users, linux-wireless

Not all values of the TX status enumeration were
covered during updating of the TX statistics. This
could lead to wrong bitrate tuning but also wrong
behavior in tools like hostapd.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
 drivers/net/wireless/rt2x00/rt2x00dev.c |   28 ++++++++++++++++------------
 1 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 5db613f..71761b3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -206,6 +206,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 	unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
 	u8 rate_idx, rate_flags, retry_rates;
 	unsigned int i;
+	bool success;
 
 	/*
 	 * Unmap the skb.
@@ -234,13 +235,18 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
 
 	/*
-	 * Update TX statistics.
+	 * Determine if the frame has been successfully transmitted.
 	 */
-	rt2x00dev->link.qual.tx_success +=
+	success =
 	    test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
-	    test_bit(TXDONE_UNKNOWN, &txdesc->flags);
-	rt2x00dev->link.qual.tx_failed +=
-	    test_bit(TXDONE_FAILURE, &txdesc->flags);
+	    test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
+	    test_bit(TXDONE_FALLBACK, &txdesc->flags);
+
+	/*
+	 * Update TX statistics.
+	 */
+	rt2x00dev->link.qual.tx_success += success;
+	rt2x00dev->link.qual.tx_failed += !success;
 
 	rate_idx = skbdesc->tx_rate_idx;
 	rate_flags = skbdesc->tx_rate_flags;
@@ -263,22 +269,20 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 		tx_info->status.rates[i].flags = rate_flags;
 		tx_info->status.rates[i].count = 1;
 	}
-	if (i < (IEEE80211_TX_MAX_RATES -1))
+	if (i < (IEEE80211_TX_MAX_RATES - 1))
 		tx_info->status.rates[i].idx = -1; /* terminate */
 
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-		if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
-				test_bit(TXDONE_UNKNOWN, &txdesc->flags))
+		if (success)
 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
-		else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
+		else
 			rt2x00dev->low_level_stats.dot11ACKFailureCount++;
 	}
 
 	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
-		if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
-				test_bit(TXDONE_UNKNOWN, &txdesc->flags))
+		if (success)
 			rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
-		else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
+		else
 			rt2x00dev->low_level_stats.dot11RTSFailureCount++;
 	}
 
-- 
1.6.4.1


^ permalink raw reply related

* Re: [ath5k-devel] Ath5k and proprietary extensions
From: Nick Kossifidis @ 2009-08-29 15:47 UTC (permalink / raw)
  To: Benoit PAPILLAULT; +Cc: John W. Linville, ath5k-devel, linux-wireless, ic.felix
In-Reply-To: <4A98D65B.9060103@free.fr>

2009/8/29 Benoit PAPILLAULT <benoit.papillault@free.fr>:
>
> I have been working on XR (in madwifi) for some time with no result. I
> would appreciate to be able to test it in ath5k.

All XR related stuff is missing from both Legacy and Sam's HAL + it's
nasty IMHO. We need to define new rates, send beacons on both 0.25 and
1Mbits, use that polling mechanism, introduce a new IE etc. It 'll
need lots of changes and the code will get even more complex + if we
want to do it right at least the polling mechanism has to go to
mac80211 and i don't think anyone wants that, imagine if every vendor
started putting proprietary stuff like that on mac80211 (and there are
way more nasty vendor specific stuff). I don't want to see
ath5k/mac80211 become like MadWiFi. If we can find a way to support XR
on ath5k without touching mac80211 then we can talk about it but right
now we don't even know how to make it work.

-- 
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick

^ permalink raw reply

* Re: [ath5k-devel] Ath5k and proprietary extensions
From: RHS Linux User @ 2009-08-29  9:56 UTC (permalink / raw)
  To: Benoit PAPILLAULT
  Cc: Nick Kossifidis, ic.felix, ath5k-devel, linux-wireless,
	John W. Linville
In-Reply-To: <4A98D65B.9060103@free.fr>


Hi All,

   I am VERY interested in XR. 

   John



^ permalink raw reply

* Re: [RFT] ar9170: use eeprom's frequency calibration values
From: Joerg Albert @ 2009-08-29 11:33 UTC (permalink / raw)
  To: Johannes Berg, Christian Lamparter; +Cc: linux-wireless, John Linville
In-Reply-To: <1250927567.23605.9.camel@johannes.local>

On 08/22/2009 09:52 AM, Johannes Berg wrote:
> On Fri, 2009-08-21 at 22:52 +0200, Christian Lamparter wrote:
> 
>> Johannes, in phy.c (now at line) line 429
>>
>> int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
>> {
>> [...]
>>         /* XXX: use EEPROM data here! */
>>
>>         err = ar9170_init_power_cal(ar);
>>         if (err)
>> [...]
>> }
>>
>> do you still know what EEPROM data is missing here? 
> 
> Sorry, no, I don't remember, and can't seem to find it either in otus
> right now.

Maybe this refers to the values in eepromBoardData initialized from the eeprom in otus/hal/hpmain.c, lines 522 ff.
and written into the registers in line 828?

I guess they should come from the modal_header[] in struct ar9170_eeprom, but I cannot map the 
offset in hpmain.c for hpPriv->eepromImage[] into the modal_header's members.

Regards,
Joerg



^ permalink raw reply

* Re: [PATCH 1/2] cfg80211: initialize rate control after station inserted
From: Johannes Berg @ 2009-08-29  9:34 UTC (permalink / raw)
  To: reinette chatre; +Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
In-Reply-To: <1251497929.3805.173.camel@rc-desk>

[-- Attachment #1: Type: text/plain, Size: 4409 bytes --]

Hi Reinette,

> > Interesting. I've been thinking about making it go the other way --
> > remove rate scaling hooks completely. wl1271 apparently has rate scaling
> > completely in the firmware, so the RS algorithm on the host is just
> > overhead. I've been thinking putting 4965+ RS into the _driver_ makes
> > more sense since it really does a lot in the firmware and not on the
> > host.
> 
> Yes, it does do a lot in firmware. Unfortunately I am not too familiar
> with the details (yet).

As far as I know/can tell, you basically upload the LQ command to the
firmware for each station and it in a way controls the parameters. What
exactly it does I'm not sure, but I am pretty sure that we don't have up
to 16 retries programmed into the TX descriptor for each packet, but we
can do that many retries.

iwl_tx_cmd contains only a single rate_n_flags field, and then there's
TX_CMD_FLG_STA_RATE_MSK, there's a comment on that definition that
explains some more.

> > I've also been thinking if there's a way to make sta_notify() able to
> > sleep but so far I don't see one unfortunately.
> 
> Having it sleep will help a lot. When a station is added we need to tell
> the device about it. Since the call cannot sleep we cannot really tell
> mac80211 if this failed because the failure will only be known at a
> later time. I have not yet figured out how to deal with this case.

Yeah, that would help. On the other hand, mac80211 isn't actually
prepared to deal with that. In fact, sta_notify has no return value. And
I'm not really sure how to deal with errors from it. Leaving AP aside
for a minute, I think we probably can't do anything. If we exceed the
capacity of the microcode's station memory, I think the best we can do
is just not use rate control for that station, and use the broadcast
station. It won't really happen anyway. And software crypto, of course.
So there's not much to be done.

Now looking at AP again, it _might_ make sense to tell hostapd "sorry we
can't really talk to that station well", but on the other hand I suspect
it's not a case we should really consider. I'd say we can export the
number of stations so that hostapd can actually try not to exceed the
limit in the first place.

As such, having the sta_notify callback sleep will not actually help
much.

I'd say we do the following: At startup, we program the broadcast STA
into the device so we always have that, and do that synchronously so if
that fails for some stupid reason. I think we already do that.

Then, we use a station private area that mac80211 can allocate for us to
store the STA_ID for each station. Set this to the broadcast STA ID,
which is always valid in some sense, at sta_notify(add) time. Then,
asynchronously, tell the device about the station. Once that command
finishes, look up the sta struct again and set the STA_ID to the new ID
that we used in the device. This way, a sta struct will always have a
valid sta ID in it.

Now, when we need to set a key for a station, we actually get the
station struct. Thus, we can keep two separate flag in the station
struct that tells us whether the STA_ADD was successful. If this flag is
unset, then we reject the add_key with -ENOSPC. Or when we detect that
the key command was too fast after the sta_notify we can wait for the
ADD_STA to finish in the key notification since that can sleep.

And then rate stuff we can just also do as part of the async sta add
command, so that the sta ID is only set after we have the sta programmed
into the device and also initialised rate control properly for it.
Ultimately the rate control algorithm could do nothing at all, and then
we can remove it completely.

> > As soon as sta_insert() got called, a packet transmitted to that station
> > can be processed, find the sta info, and it seems we could end up
> > calling rate_control_get_rate() before the init was done, through a race
> > condition.
> 
> oh - I see - that's bad. Although, that may explain why iwlwifi is
> adding stations in get_rate() also. 

No, the explanation for that is "history" :) The rate algorithm was
written before mac80211 actually _had_ the sta_notify command, and it
was (and still is, as you've pointed out in these patches) the first
place that is notified about the new station. But I think we don't
really need that.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* rndis endian warnings
From: Johannes Berg @ 2009-08-29  9:08 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 185 bytes --]

Hi,

There are a whole bunch of endianness warnings from sparse in rndis --
please run

make M=drivers/net/wireless C=2 CF=-D__CHECK_ENDIAN__

and check the result.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] cfg80211: initialize rate control after station inserted
From: Johannes Berg @ 2009-08-29  9:01 UTC (permalink / raw)
  To: tim.gardner
  Cc: reinette chatre, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org
In-Reply-To: <4A984EBA.9040608@canonical.com>

[-- Attachment #1: Type: text/plain, Size: 657 bytes --]

On Fri, 2009-08-28 at 15:40 -0600, Tim Gardner wrote:

> Wouldn't that make it difficult to experiment with external rate scaling 
> algorithms? Not that minstrel or the other in-driver rate scaling 
> algorithms always get it right, but they are certainly more transparent 
> (and changeable) then firmware.

It does, in theory, but then again you don't really _have_ the choice.
iwlagn only lets you control the rate on the host to some extent,
there's not a lot we can do. IMHO using the rate control algorithms like
they are now is a kludge because we've always needed a rate control
algorithm, but it's still not really useful.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [ath5k-devel] Ath5k and proprietary extensions
From: Benoit PAPILLAULT @ 2009-08-29  7:18 UTC (permalink / raw)
  To: Nick Kossifidis; +Cc: John W. Linville, ath5k-devel, linux-wireless, ic.felix
In-Reply-To: <40f31dec0908282151t245912f0ye79684d4a519f3c9@mail.gmail.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Nick Kossifidis a écrit :
> Since we started the discussion about ath5k and proprietary
> features i started a new thread to continue.
>
> So this is what we have...
>
> a) X.R.: eXtended Range is a set of proprietary rates and some
> extra techniques (various hw tweaks etc) to enable long distance,
> low bandwidth links. This feature was never really supported on
> MadWiFi (some code for sta mode is there but i don't think anyone
> used it) and it's ugly (sends beacons on both 1Mbit and 250Kbit,
> has some sort of polling mechanism etc). We should remove XR stuff
> since we all agree that we won't support it + even if we want we
> don't have anything to work with anyway, 5/10MHz channels should be
> enough for long distance links. Just leave XR rate code definitions
> there for reference (in case we get any of these from the card
> -normally we shouldn't but it's good to know all hw rate code
> values).
I have been working on XR (in madwifi) for some time with no result. I
would appreciate to be able to test it in ath5k.
>
> b) OFDM-only g settings for AR5211: AR5211 chips have support for
> draft-g (eg. no dynamic CCK/OFDM modulation, only OFDM). I don't
> know if we want to support it or not, removing the settings will
> save us some space and since it's a draft g implementation i don't
> think there are many compatible APs out there. Is there any
> possibility to support draft-g on mac80211/cfg80211 ? If not we can
> just drop it else it's just some extra data, no big deal.
>
> c) Half/quarter rate channels (10/5MHz width) and turbo mode
> (double rate - 40MHz width): Hw can transmit with different channel
> width allowing us to operate on half, quarter or double rate (also
> called turbo mode). Half and quarter rates are straight forward
> (just re-program pll/clock and tweak various phy/rf settings) and
> most chips support it, turbo mode on the other hand has some extra
> parameters and is supported only on super ag enabled (non-lite)
> chips (5212,2414,5414,5424 etc). First we want to use it only on
> "middle" channels so that we don't get outside band boundaries when
> changing channel width, so we have to limit the available channels
> we can use (check out super ag white paper), second we have the
> opportunity to support both 20MHz and 40MHz at the same time by
> using "dynamic turbo" feature on hw so if we are an AP we can deal
> both with turbo-enabled clients and normal clients. I was thinking
> if we are going to have an API to set channel width to 10 and 5 MHz
> for half and quarter rate channels, we can use the same API to set
> channel width to 40MHz width for double rate channels on cards that
> support it and when we are on AP mode use the "dynamic turbo"
> stuff. We don't even have to call it turbo mode, it's just double
> rate + some tweaks.
>
> Most code is there for half/quarter and (static) turbo operation,
> we just have to deal with pll programming, clock settings etc.
> Question is how do we use it, NL80211_CMD_TESTMODE is an option i
> guess and in case no one else thinks that we could use a channel
> width API (or extend what we have) for setting 5/10/40MHz width
> through cfg80211, we can just stick to NL80211_CMD_TESTMODE.
5/10 MHz channels are defined in 802.11-2007, so it must be part of
mac80211 and supported by ath5k if the HW support it. For 40 MHz, as
far as the mac80211 API is concerned, we could treat it like HT40,
even it's clearly a proprietary extension.
>
> d) Fast frames: Hw can tx/rx jumbo frames of 3kbytes+ so fast frame
>  aggregation is a way to make use of that hw feature by sending 2
> frames together (for more infos check out super ag white paper). On
>  FreeBSD fast frames aggregation is implemented on the protocol
> stack (net80211) so that any hw that can tx/rx such jumbo frames
> can use fast frame aggregation
> (http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/net80211/ieee80211_superg.c?rev=1.7;content-type=text%2Fx-cvsweb-markup;sortby=rev)
>  but it still maintains atheros's format to be compatible with
> commercial Atheros APs. We have talked about this and it seems no
> one is willing to support fast frames aggregation so on ath5k we
> only use single tx/rx descriptors and there is no related code for
> handling multiple descriptors.
>
> e) Compression: Hw can do on-chip compression/decompression using
> standard Lempel Ziv algorithm per tx queue, MadWiFi implements this
>  and uses a vendor IE to let others know that it supports this
> feature (same IE is used for all capabilities, fast frames, XR
> etc). I guess this can also work for other cards by doing
> compression/decompression on software since it's a standard
> algorithm (and i think kernel already has code for it) but it's way
> outside cfg80211/mac80211's scope. I think we can just use
> NL80211_CMD_TESTMODE to enable/disable this on all data queues and
> skip the IE stuff (user will have to enable it on both sides to
> make it work). There is no related code on ath5k for
> compression/decompression at the moment.
>
>
>
My whole feeling is that an operating system, be it GNU/Linux,
Windows(tm), *bsd or whatever is here to bring all the HW features to
the user. So if users are interested by any of the above features, be
it proprietary or not, we need to find a way to allow their
implementation in ath5k. Some of those implementations would need
mac80211 changes, so we need to decide if we want a proper mac80211
support for all those features (proprietary or not) or if mac80211
only wants to support standard features (which seems fair) and find
another way to support proprietary features.

Regards,
Benoit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkqY1lYACgkQOR6EySwP7oJTZACfUO8m4OXls+5yVLMbnn/oax0E
vTcAoO9NJ5Wdtr3gNEALF0sPk4RxNj7c
=5Srl
-----END PGP SIGNATURE-----


^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-08-28
From: David Miller @ 2009-08-29  6:06 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20090828191119.GD32694@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Fri, 28 Aug 2009 15:11:19 -0400

> Another huge batch of updates/changes/etc intended for 2.6.32...  This
> includes the usual driver updates and miscellaneous fixes, etc.
> Highlights in this batch include more LP-PHY support for b43 and the
> completion of the cfg80211 API conversion for rndis_wlan.

Pulled, thanks!

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox