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@xxxxxxxxxxxx> --- 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++) { -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html