Skip to contentSkip to conversation

b43: N-PHY: add RSSI calculation for PHY rev < 3

PATCH In review Rafał Miłecki 3 participants 9 messages Jan 10, 2010 – Jan 11, 2010 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH 3/6 b43: N-PHY: add RSSI calculation for PHY rev < 3

---
 drivers/net/wireless/b43/phy_n.c |  159 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 158 insertions(+), 1 deletions(-)
drivers/net/wireless/b43/phy_n.c +158 -1
index d7e408b..b39b817 100644
@@ -810,7 +810,164 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
 static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
 {
-	//TODO
+	int i, j;
+	u8 state[4];
+	u8 code, val;
+	u16 class, override;
+	u8 regs_save_radio[2];
+	u16 regs_save_phy[2];
+	s8 offset[4];
+
+	u16 clip_state[2];
+	u16 clip_off[2] = { 0xFFFF, 0xFFFF };
+	s32 results_min[4];
+	u8 vcm_final[4];
+	s32 results[4][4];
+	s32 miniq[4][2];
+	memset(results_min, 0, sizeof(s32) * 4);
+	memset(vcm_final, 0, sizeof(u8) * 4);
+	memset(results, 0, sizeof(s32) * 4 * 4);
+	memset(miniq, 0, sizeof(s32) * 4 * 2);
+
+	if (type == 2) {
+		code = 0;
+		val = 6;
+	} else if (type < 2) {
+		code = 25;
+		val = 4;
+	} else {
+		B43_WARN_ON(1);
+		return;
+	}
+
+	class = b43_nphy_classifier(dev, 0, 0);
+	b43_nphy_classifier(dev, 7, 4);
+	b43_nphy_read_clip_detection(dev, clip_state);
+	b43_nphy_write_clip_detection(dev, clip_off);
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+		override = 0x140;
+	else
+		override = 0x110;
+
+	regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+	regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
+	b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+
+	regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+	regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
+	b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+
+	state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
+	state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
+	b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, 0);
+	b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, 0);
+	state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
+	state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+
+	b43_nphy_rssi_select(dev, 5, type);
+	b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
+	b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+
+	for (i = 0; i < 4; i++) {
+		u8 tmp[4];
+		for (j = 0; j < 4; j++)
+			tmp[j] = i;
+		if (type != 1)
+			b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
+		b43_nphy_poll_rssi(dev, type, results[i], 8);
+		if (type < 2)
+			for (j = 0; j < 2; j++)
+				miniq[i][j] = min(results[i][2 * j],
+						results[i][2 * j + 1]);
+	}
+
+	for (i = 0; i < 4; i++) {
+		s32 mind = 40;
+		u8 minvcm = 0;
+		s32 minpoll = 249;
+		s32 curr;
+		for (j = 0; j < 4; j++) {
+			if (type == 2)
+				curr = abs(results[j][i]);
+			else
+				curr = abs(miniq[j][i / 2] - code * 8);
+
+			if (curr < mind) {
+				mind = curr;
+				minvcm = j;
+			}
+
+			if (results[j][i] < minpoll)
+				minpoll = results[j][i];
+		}
+		results_min[i] = minpoll;
+		vcm_final[i] = minvcm;
+	}
+
+	if (type != 1)
+		b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
+
+	for (i = 0; i < 4; i++) {
+		offset[i] = (code * 8) - results[vcm_final[i]][i];
+
+		if (offset[i] < 0)
+			offset[i] = -((abs(offset[i]) + 4) / 8);
+		else
+			offset[i] = (offset[i] + 4) / 8;
+
+		if (results_min[i] == 248)
+			offset[i] = code - 32;
+
+		if (i % 2 == 0)
+			b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0,
+							type);
+		else
+			b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1,
+							type);
+	}
+
+	b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
+	b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]);
+
+	switch (state[2]) {
+	case 1:
+		b43_nphy_rssi_select(dev, 1, 2);
+		break;
+	case 4:
+		b43_nphy_rssi_select(dev, 1, 0);
+		break;
+	case 2:
+		b43_nphy_rssi_select(dev, 1, 1);
+		break;
+	default:
+		b43_nphy_rssi_select(dev, 1, 1);
+		break;
+	}
+
+	switch (state[3]) {
+	case 1:
+		b43_nphy_rssi_select(dev, 2, 2);
+		break;
+	case 4:
+		b43_nphy_rssi_select(dev, 2, 0);
+		break;
+	default:
+		b43_nphy_rssi_select(dev, 2, 1);
+		break;
+	}
+
+	b43_nphy_rssi_select(dev, 0, type);
+
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
+	b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
+	b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+
+	b43_nphy_classifier(dev, 7, class);
+	b43_nphy_write_clip_detection(dev, clip_state);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
Signature · 1 line
1.6.4.2
#1 lore raw

drivers/net/wireless/b43/phy_n.c static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, · line 830

Quoted 8 lines · On Sunday 10 January 2010 23:13:34 Rafał Miłecki wrote:
drivers/net/wireless/b43/phy_n.c +8 -0
+	s32 results_min[4];
+	u8 vcm_final[4];
+	s32 results[4][4];
+	s32 miniq[4][2];
+	memset(results_min, 0, sizeof(s32) * 4);
+	memset(vcm_final, 0, sizeof(u8) * 4);
+	memset(results, 0, sizeof(s32) * 4 * 4);
+	memset(miniq, 0, sizeof(s32) * 4 * 2);

Just initialize the variables to zero instead of doing a memset:

+ s32 results_min[4] = { 0, };
+ u8 vcm_final[4] = { 0, };
+ s32 results[4][4] = { 0, };
+ s32 miniq[4][2] = { 0, };

drivers/net/wireless/b43/phy_n.c static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, · line 866

Quoted 2 lines
drivers/net/wireless/b43/phy_n.c +2 -0
+	b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, 0);
+	b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, 0);

If you don't set anything, you can use
b43_radio_mask();

Signature · 1 line
Greetings, Michael.
#2 lore raw

2010/1/10 Michael Buesch <[email protected]>:

Quoted 10 lines · On Sunday 10 January 2010 23:13:34 Rafał Miłecki wrote:
Quoted 8 lines

+     s32 results_min[4];
+     u8 vcm_final[4];
+     s32 results[4][4];
+     s32 miniq[4][2];
+     memset(results_min, 0, sizeof(s32) * 4);
+     memset(vcm_final, 0, sizeof(u8) * 4);
+     memset(results, 0, sizeof(s32) * 4 * 4);
+     memset(miniq, 0, sizeof(s32) * 4 * 2);

Quoted 6 lines

Just initialize the variables to zero instead of doing a memset:

+       s32 results_min[4] = { 0, };
+       u8 vcm_final[4] = { 0, };
+       s32 results[4][4] = { 0, };
+       s32 miniq[4][2] = { 0, };

Nice trick, thanks :) Just for two-dimensional arrays I'll have to hack it to:
s32 results[4][4] = { { 0, }, { 0, }, { 0, }, { 0, } };
I believe.

Quoted 5 lines
Quoted 2 lines

+     b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, 0);
+     b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, 0);

If you don't set anything, you can use
b43_radio_mask();

Sure I can ;) Thanks.

Signature · 1 line
Rafał
#3 lore raw
Quoted 13 lines · On Monday 11 January 2010 22:13:31 Rafał Miłecki wrote:

2010/1/10 Michael Buesch <[email protected]>:

Quoted 12 lines · On Sunday 10 January 2010 23:13:34 Rafał Miłecki wrote:
Quoted 8 lines

+     s32 results_min[4];
+     u8 vcm_final[4];
+     s32 results[4][4];
+     s32 miniq[4][2];
+     memset(results_min, 0, sizeof(s32) * 4);
+     memset(vcm_final, 0, sizeof(u8) * 4);
+     memset(results, 0, sizeof(s32) * 4 * 4);
+     memset(miniq, 0, sizeof(s32) * 4 * 2);

Just initialize the variables to zero instead of doing a memset:

Quoted 8 lines
Quoted 4 lines

+       s32 results_min[4] = { 0, };
+       u8 vcm_final[4] = { 0, };
+       s32 results[4][4] = { 0, };
+       s32 miniq[4][2] = { 0, };

Nice trick, thanks :) Just for two-dimensional arrays I'll have to hack it to:
s32 results[4][4] = { { 0, }, { 0, }, { 0, }, { 0, } };
I believe.

No I don't think so.
It's C standard that uninitialized elements on automatic variables are initialized to zero, _if_ at least one element is initialized to something.
So if you init one element to 0, all others will be 0, too.
I think that should also work for multidimensional arrays. So my example s32 results[4][4] = { 0, };
should do the right thing. Am I wrong?

Here's a test-program:

mb@maggie:~$ cat t.c
#include <stdio.h>
#include <stdint.h>

int main(void)

{
        int i, j;
        int32_t results[4][4]

#ifdef INIT_IT
= { 0, };
#else
;
#endif

        for (i = 0; i < 4; i++)
                for (j = 0; j < 4; j++)
                        printf("%d\n", results[i][j]);

}

mb@maggie:~$ gcc -o t t.c
mb@maggie:~$ ./t
0
0
0
1
-1077483840
0
0
0
-1077483824
268436224
268536212
0
-1077483776
268436888
268353524
0
mb@maggie:~$ gcc -D INIT_IT -o t t.c
mb@maggie:~$ ./t
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Signature · 1 line
Greetings, Michael.
maintainer
#4 lore raw
Quoted 5 lines · Michael Buesch

No I don't think so.
It's C standard that uninitialized elements on automatic variables are initialized
to zero, _if_ at least one element is initialized to something. So if you init one element to 0, all others will be 0, too.

AFAIK, you don't even have to init anything, since otherwise not mentioned fields will be set to 0. Hence, just = {} is sufficient for arrays and will hopefully compile to the same code as an explicit memset().

johannes

#5 lore raw
Quoted 8 lines · On Monday 11 January 2010 23:19:52 Johannes Berg wrote:
Quoted 5 lines · Michael Buesch

No I don't think so.
It's C standard that uninitialized elements on automatic variables are initialized
to zero, _if_ at least one element is initialized to something. So if you init one element to 0, all others will be 0, too.

Quoted 4 lines

AFAIK, you don't even have to init anything, since otherwise not mentioned fields will be set to 0. Hence, just = {} is sufficient for arrays and will hopefully compile to the same code as an explicit memset().

Oh, nice. You are right, indeed. I didn't know that.

Signature · 1 line
Greetings, Michael.
#6 lore raw
In reply to Michael Buesch
Quoted 23 lines · W dniu 11 stycznia 2010 23:13 użytkownik Michael Buesch <[email protected]> napisał:
Quoted 13 lines · On Monday 11 January 2010 22:13:31 Rafał Miłecki wrote:

2010/1/10 Michael Buesch <[email protected]>:

Quoted 12 lines · On Sunday 10 January 2010 23:13:34 Rafał Miłecki wrote:
Quoted 8 lines

+     s32 results_min[4];
+     u8 vcm_final[4];
+     s32 results[4][4];
+     s32 miniq[4][2];
+     memset(results_min, 0, sizeof(s32) * 4);
+     memset(vcm_final, 0, sizeof(u8) * 4);
+     memset(results, 0, sizeof(s32) * 4 * 4);
+     memset(miniq, 0, sizeof(s32) * 4 * 2);

Just initialize the variables to zero instead of doing a memset:

Quoted 8 lines
Quoted 4 lines

+       s32 results_min[4] = { 0, };
+       u8 vcm_final[4] = { 0, };
+       s32 results[4][4] = { 0, };
+       s32 miniq[4][2] = { 0, };

Nice trick, thanks :) Just for two-dimensional arrays I'll have to hack it to:
s32 results[4][4] = { { 0, }, { 0, }, { 0, }, { 0, } };
I believe.

Quoted 7 lines

No I don't think so.
It's C standard that uninitialized elements on automatic variables are initialized to zero, _if_ at least one element is initialized to something.
So if you init one element to 0, all others will be 0, too.
I think that should also work for multidimensional arrays. So my example s32 results[4][4] = { 0, };
should do the right thing. Am I wrong?

Whoops, I should have explained what I mean. I am not sure what CFLAGS "make" picks for compiled but I get:

CC [M] drivers/net/wireless/b43/phy_n.o
drivers/net/wireless/b43/phy_n.c: In function ‘b43_nphy_rev2_rssi_cal’:
drivers/net/wireless/b43/phy_n.c:887: warning: missing braces around initializer drivers/net/wireless/b43/phy_n.c:887: warning: (near initialization for ‘results[0]’)

for s32 results[4][4] = { 0, };

Signature · 1 line
Rafał
#7 lore raw
Quoted 11 lines · On Monday 11 January 2010 23:27:18 Rafał Miłecki wrote:

Whoops, I should have explained what I mean. I am not sure what CFLAGS "make" picks for compiled but I get:

CC [M] drivers/net/wireless/b43/phy_n.o
drivers/net/wireless/b43/phy_n.c: In function ‘b43_nphy_rev2_rssi_cal’:
drivers/net/wireless/b43/phy_n.c:887: warning: missing braces around initializer drivers/net/wireless/b43/phy_n.c:887: warning: (near initialization for ‘results[0]’)

for s32 results[4][4] = { 0, };

But does this work?
s32 results[4][4] = { };

Signature · 1 line
Greetings, Michael.
#8 lore raw
Quoted 10 lines · W dniu 11 stycznia 2010 23:42 użytkownik Michael Buesch <[email protected]> napisał:
Quoted 9 lines · On Monday 11 January 2010 23:27:18 Rafał Miłecki wrote:

Whoops, I should have explained what I mean. I am not sure what CFLAGS "make" picks for compiled but I get:

  CC [M]  drivers/net/wireless/b43/phy_n.o drivers/net/wireless/b43/phy_n.c: In function ‘b43_nphy_rev2_rssi_cal’:
drivers/net/wireless/b43/phy_n.c:887: warning: missing braces around initializer drivers/net/wireless/b43/phy_n.c:887: warning: (near initialization for ‘results[0]’)

Quoted 5 lines
Quoted 2 lines

for s32 results[4][4] = { 0, };

But does this work?
s32 results[4][4] = { };

Yes, this compiles fine, and I believe it works fine :)

Signature · 1 line
Rafał