All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3] ssb: Implement virtual SPROM
@ 2010-03-23 19:13 Larry Finger
  2010-03-23 22:09 ` Michael Buesch
  0 siblings, 1 reply; 2+ messages in thread
From: Larry Finger @ 2010-03-23 19:13 UTC (permalink / raw)
  To: John W Linville, Michael Buesch; +Cc: bcm43xx-dev, linux-wireless

Some recent BCM43XX devices lack an on-board SPROM. The pertinent data
from the SPROM could be included in the kernel; however, this presents
a problem in the generation of a unique, reproducible MAC address. The
solution is to use a file in /lib/firmware/ssb, which has some "random"
information generated by /bin/dbus-uuidgen. This file is loaded using the
asynchronous firmware facility and a MAC address is generated from those
data. To prevent multiple devices in a single box from having the same
MAC address, the last two digits are replaced by the bus numbers of the
device.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---

John,

Unless someone comes up with a unique way to generate a MAC address using
only udev rules, I think this is ready.

I suspect it is a little to invasive for 2.6.34. In addition, it fixes
a bug, but not a regression.

Larry
---

V2 - make virtual SPROM loading asynchronous.
V3 - eliminate the need for a special external utility
   - set for unique MAC address even if a box has more than one of these
     devices

Index: wireless-testing/drivers/ssb/pci.c
===================================================================
--- wireless-testing.orig/drivers/ssb/pci.c
+++ wireless-testing/drivers/ssb/pci.c
@@ -19,6 +19,7 @@
 #include <linux/ssb/ssb_regs.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 
 #include "ssb_private.h"
 
@@ -613,6 +614,120 @@ static int sprom_extract(struct ssb_bus
 	return 0;
 }
 
+static void ssb_vsprom_load_failed(void)
+{
+	printk(KERN_ERR "ssb: The BCM43XX device does not have an "
+		    "SPROM built in. Use the command\n");
+	printk(KERN_ERR "     'mkdir -p /lib/firmware/ssb ; /bin/dbus-uuidgen"
+		    " > /lib/firmware/ssb/mac_addr'\n");
+	printk(KERN_ERR "     to generate the required file.\n");
+}
+
+static inline u8 ascii_to_bin(u8 input)
+{
+	/* return the binary value of the ASCII char in the low nibble */
+	return (input <= 0x39) ? input & 0xF : (input - 0x27) & 0xF;
+}
+
+static void ssb_get_vsprom(const struct firmware *fw, void *context)
+{
+	/* Second part of asynchronous firmware load */
+	int i;
+	struct ssb_bus *bus = context;
+	struct ssb_sprom *sprom = &bus->sprom;
+	u8 buf2[8];
+	char *name;
+
+	if (!fw) {
+		ssb_vsprom_load_failed();
+		return;
+	}
+	/* Get values extracted from SPROM. If sprom_extract_r8() is changed,
+	 * this section must be changed as well. For any device with 5GHz
+	 * capability, some variables will have to be changed.
+	 */
+	sprom->revision = 8;
+	sprom->boardflags_lo = 0x0A01;
+	sprom->boardflags_hi = 0x0006;
+	sprom->boardflags2_lo = 0x0000;
+	sprom->boardflags2_hi = 0x0000;
+	sprom->ant_available_a = 0x00;
+	sprom->ant_available_bg = 0x03;
+	sprom->maxpwr_bg = 0x4A;
+	sprom->itssi_bg = 0x3E;
+	sprom->maxpwr_a = 0xFF;
+	sprom->itssi_a = 0xFF;
+	sprom->maxpwr_ah = 0xFF;
+	sprom->maxpwr_al = 0xFF;
+	sprom->gpio0 = 0x83;
+	sprom->gpio1 = 0xFF;
+	sprom->gpio2 = 0xFF;
+	sprom->gpio3 = 0xFF;
+	sprom->tri2g = 0x6C;
+	sprom->tri5g = 0x00;
+	sprom->tri5gl = 0xFF;
+	sprom->tri5gh = 0xFF;
+	sprom->rxpo2g = 0xFA;
+	sprom->rxpo5g = 0xFF;
+	sprom->rssismf2g = 0x0F;
+	sprom->rssismc2g = 0x00;
+	sprom->rssisav2g = 0x00;
+	sprom->bxa2g = 0x00;
+	sprom->rssismf5g = 0x0F;
+	sprom->rssismc5g = 0x0F;
+	sprom->rssisav5g = 0x07;
+	sprom->bxa5g = 0x03;
+	sprom->pa0b0 = 0x1a57;
+	sprom->pa0b1 = 0xF98A;
+	sprom->pa0b2 = 0xFE91;
+	sprom->pa1b0 = 0xFFFF;
+	sprom->pa1b1 = 0xFFFF;
+	sprom->pa1b2 = 0xFFFF;
+	sprom->pa1lob0 = 0xFFFF;
+	sprom->pa1lob1 = 0xFFFF;
+	sprom->pa1lob2 = 0xFFFF;
+	sprom->pa1hib0 = 0xFFFF;
+	sprom->pa1hib1 = 0xFFFF;
+	sprom->pa1hib2 = 0xFFFF;
+	sprom->cck2gpo = 0xFFFF;
+	sprom->ofdm2gpo = 0x00000002;
+	sprom->ofdm5glpo = 0xFFFFFFFF;
+	sprom->ofdm5gpo = 0xFFFFFFFF;
+	sprom->ofdm5ghpo = 0xFFFFFFFF;
+	memset(sprom->et0mac, 0xFF, 6);
+	memset(sprom->et1mac, 0xFF, 6);
+
+	if (fw->size != 33) {
+		printk(KERN_ERR "ssb: The MAC address file has the wrong"
+		       " size\n");
+		goto out;
+	}
+	/* Input MAC address data in ASCII - get low nibble in binary */
+	for (i = 0 ; i < 8; i++) {
+		u8 tmp = ascii_to_bin(fw->data[2 * i]);
+		u8 tmp1 = ascii_to_bin(fw->data[2 * i + 1]);
+		buf2[i] = tmp << 4 | tmp1;
+	}
+	/* make sure 2 least significant bits of first byte are clear
+	 * These bits are multicast address and LAA bit, and
+	 * copy the randomized MAC address to the sprom variables
+	 */
+	buf2[0] &= ~(3);
+	memcpy(sprom->il0mac, buf2, 4);
+
+	/* As there may be more than one such interface on a given box,
+	 * modify the random MAC address in the file with the
+	 * bus information as provided by dev_name(). This will be in
+	 * the form "nnnn:mm:oo.p". The last two digits of the MAC address
+	 * will be set to oo and mm.
+	 */
+	name = (char *)dev_name(&bus->host_pci->dev);
+	sprom->il0mac[5] = ascii_to_bin(name[5]) << 4 | ascii_to_bin(name[6]);
+	sprom->il0mac[4] = ascii_to_bin(name[8]) << 4 | ascii_to_bin(name[9]);
+out:
+	release_firmware(fw);
+}
+
 static int ssb_pci_sprom_get(struct ssb_bus *bus,
 			     struct ssb_sprom *sprom)
 {
@@ -620,8 +735,18 @@ static int ssb_pci_sprom_get(struct ssb_
 	int err = -ENOMEM;
 	u16 *buf;
 
-	if (!ssb_is_sprom_available(bus))
-		return -ENODEV;
+	if (!ssb_is_sprom_available(bus)) {
+		/* This device has no SPROM. Try for a random MAC address */
+		err = request_firmware_nowait(THIS_MODULE,
+			FW_ACTION_HOTPLUG, "ssb/mac_addr",
+			&bus->host_pci->dev, GFP_KERNEL, bus,
+			ssb_get_vsprom);
+		if (err) {
+			ssb_vsprom_load_failed();
+			return err;
+		}
+		return 0;
+	}
 
 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
 	if (!buf)
Index: wireless-testing/drivers/net/wireless/b43/phy_lp.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/phy_lp.c
+++ wireless-testing/drivers/net/wireless/b43/phy_lp.c
@@ -107,7 +107,8 @@ static void lpphy_read_band_sprom(struct
 		 * opo == ofdm2gpo and we don't know any SSB with LP-PHY
 		 * and SPROM rev below 8.
 		 */
-		B43_WARN_ON(bus->sprom.revision < 8);
+		if (bus->sprom.revision < 8)
+			b43err(dev->wl, "Illegal SPROM Revision\n");
 		ofdmpo = bus->sprom.ofdm2gpo;
 		if (cckpo) {
 			for (i = 0; i < 4; i++) {

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH V3] ssb: Implement virtual SPROM
  2010-03-23 19:13 [PATCH V3] ssb: Implement virtual SPROM Larry Finger
@ 2010-03-23 22:09 ` Michael Buesch
  0 siblings, 0 replies; 2+ messages in thread
From: Michael Buesch @ 2010-03-23 22:09 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W Linville, bcm43xx-dev, linux-wireless

On Tuesday 23 March 2010 20:13:54 Larry Finger wrote:
> Some recent BCM43XX devices lack an on-board SPROM. The pertinent data
> from the SPROM could be included in the kernel; however, this presents
> a problem in the generation of a unique, reproducible MAC address. The
> solution is to use a file in /lib/firmware/ssb, which has some "random"
> information generated by /bin/dbus-uuidgen. This file is loaded using the
> asynchronous firmware facility and a MAC address is generated from those
> data. To prevent multiple devices in a single box from having the same
> MAC address, the last two digits are replaced by the bus numbers of the
> device.
> 
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> ---
> 
> John,
> 
> Unless someone comes up with a unique way to generate a MAC address using
> only udev rules, I think this is ready.

Please take a look at Calvin Walton's RFC.
It would avoid the need for abusing the firmware loading mechanism.

> +	/* Input MAC address data in ASCII - get low nibble in binary */
> +	for (i = 0 ; i < 8; i++) {
> +		u8 tmp = ascii_to_bin(fw->data[2 * i]);
> +		u8 tmp1 = ascii_to_bin(fw->data[2 * i + 1]);
> +		buf2[i] = tmp << 4 | tmp1;
> +	}

You would basically initialize the mac address to FFFFFFFFFFFF here and
udev would take care of the rest.

>  static int ssb_pci_sprom_get(struct ssb_bus *bus,
>  			     struct ssb_sprom *sprom)
>  {
> @@ -620,8 +735,18 @@ static int ssb_pci_sprom_get(struct ssb_
>  	int err = -ENOMEM;
>  	u16 *buf;
>  
> -	if (!ssb_is_sprom_available(bus))
> -		return -ENODEV;
> +	if (!ssb_is_sprom_available(bus)) {
> +		/* This device has no SPROM. Try for a random MAC address */
> +		err = request_firmware_nowait(THIS_MODULE,
> +			FW_ACTION_HOTPLUG, "ssb/mac_addr",
> +			&bus->host_pci->dev, GFP_KERNEL, bus,
> +			ssb_get_vsprom);

Well, I'm not sure how this is supposed to work. What happens if a part of ssb
or b43 uses the SPROM data structure, but ssb_get_vsprom() didn't run, yet?

So: Get rid of the firmware fetching stuff completely and do it via udev.
It reduces the headache by a few magnitudes of headachenesses.

> +		if (err) {
> +			ssb_vsprom_load_failed();
> +			return err;
> +		}
> +		return 0;
> +	}
>  
>  	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
>  	if (!buf)
-- 
Greetings, Michael.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-03-23 22:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-23 19:13 [PATCH V3] ssb: Implement virtual SPROM Larry Finger
2010-03-23 22:09 ` Michael Buesch

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.