In b43legacy, the variable gmode is always set. With a BCM4306/2, and likely a BCM4301, a variable is needed to control the execution path through the PHY and radio initialization, otherwise there are attempts to read from invalid registers. On x86 platforms, these read failures cause no problems; however they lead to machine check errors for the ppc architecture. This patch reverts to the variable and semantics used in the V3 specifications. It has been tested on an i386 platform using special code to detect these invalid reads, and on at least one Powerbook. Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx> --- John, This patch fixes a problem with the Fedora Rawhide kernel reported by David Woodhouse on the bcm43xx mailing list and by Will Woods at https://bugzilla.redhat.com/show_bug.cgi?id=233011. Larry drivers/net/wireless/b43legacy/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) Index: wireless-dev/drivers/net/wireless/b43legacy/main.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/b43legacy/main.c +++ wireless-dev/drivers/net/wireless/b43legacy/main.c @@ -738,8 +738,11 @@ void b43legacy_wireless_core_reset(struc macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); macctl &= ~B43legacy_MACCTL_GMODE; - if (flags & B43legacy_TMSLOW_GMODE) + if (flags & B43legacy_TMSLOW_GMODE) { macctl |= B43legacy_MACCTL_GMODE; + dev->phy.connected = 1; + } else + dev->phy.connected = 0; macctl |= B43legacy_MACCTL_IHR_ENABLED; b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); } @@ -2464,15 +2467,15 @@ static const char *phymode_to_string(uns static int find_wldev_for_phymode(struct b43legacy_wl *wl, unsigned int phymode, struct b43legacy_wldev **dev, - bool *gmode) + bool *connected) { struct b43legacy_wldev *d; list_for_each_entry(d, &wl->devlist, list) { if (d->phy.possible_phymodes & phymode) { /* Ok, this device supports the PHY-mode. - * Set the gmode bit. */ - *gmode = 1; + * Set the connected bit. */ + *connected = 1; *dev = d; return 0; @@ -2508,17 +2511,17 @@ static int b43legacy_switch_phymode(stru struct b43legacy_wldev *up_dev; struct b43legacy_wldev *down_dev; int err; - bool gmode = 0; + bool connected = 0; int prev_status; - err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); + err = find_wldev_for_phymode(wl, new_mode, &up_dev, &connected); if (err) { b43legacyerr(wl, "Could not find a device for %s-PHY mode\n", phymode_to_string(new_mode)); return err; } if ((up_dev == wl->current_dev) && - (!!wl->current_dev->phy.gmode == !!gmode)) + (!!wl->current_dev->phy.connected == !!connected)) /* This device is already running. */ return 0; b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n", @@ -2538,7 +2541,7 @@ static int b43legacy_switch_phymode(stru b43legacy_put_phy_into_reset(down_dev); /* Now start the new core. */ - up_dev->phy.gmode = gmode; + up_dev->phy.connected = connected; if (prev_status >= B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(up_dev); if (err) { @@ -3094,7 +3097,7 @@ static int b43legacy_wireless_core_init( if (err) goto out; if (!ssb_device_is_enabled(dev->dev)) { - tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0; + tmp = phy->connected ? B43legacy_TMSLOW_GMODE : 0; b43legacy_wireless_core_reset(dev, tmp); } @@ -3424,7 +3427,6 @@ static int b43legacy_wireless_core_attac int err; int have_bphy = 0; int have_gphy = 0; - u32 tmp; /* Do NOT do any device initialization here. * Do it in wireless_core_init() instead. @@ -3456,9 +3458,7 @@ static int b43legacy_wireless_core_attac if (err) goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); - tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; - b43legacy_wireless_core_reset(dev, tmp); + b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); err = b43legacy_phy_versioning(dev); if (err) @@ -3482,9 +3482,7 @@ static int b43legacy_wireless_core_attac B43legacy_BUG_ON(1); } } - dev->phy.gmode = (have_gphy || have_bphy); - tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; - b43legacy_wireless_core_reset(dev, tmp); + b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); err = b43legacy_validate_chipaccess(dev); if (err) Index: wireless-dev/drivers/net/wireless/b43legacy/b43legacy.h =================================================================== --- wireless-dev.orig/drivers/net/wireless/b43legacy/b43legacy.h +++ wireless-dev/drivers/net/wireless/b43legacy/b43legacy.h @@ -389,10 +389,10 @@ struct b43legacy_lopair { struct b43legacy_phy { /* Possible PHYMODEs on this PHY */ u8 possible_phymodes; - /* GMODE bit enabled? */ - bool gmode; + /* true if PHY registers can be accessed */ + bool connected; /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ + * This will be either G or B mode */ #define B43legacy_MAX_PHYHWMODES 2 struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES]; Index: wireless-dev/drivers/net/wireless/b43legacy/phy.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/b43legacy/phy.c +++ wireless-dev/drivers/net/wireless/b43legacy/phy.c @@ -176,7 +176,7 @@ static void b43legacy_phy_init_pctl(stru b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF); if (phy->type == B43legacy_PHYTYPE_G) { - if (!phy->gmode) + if (!phy->connected) return; b43legacy_phy_write(dev, 0x047A, 0xC111); } @@ -585,7 +585,7 @@ static void b43legacy_phy_initb5(struct if (phy->radio_ver == 0x2050) b43legacy_phy_write(dev, 0x0038, 0x0667); - if (phy->gmode) { + if (phy->connected) { if (phy->radio_ver == 0x2050) { b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev, 0x007A) @@ -1024,7 +1024,7 @@ static void b43legacy_phy_initg(struct b b43legacy_phy_initb5(dev); else b43legacy_phy_initb6(dev); - if (phy->rev >= 2 || phy->gmode) + if (phy->rev >= 2 || phy->connected) b43legacy_phy_inita(dev); if (phy->rev >= 2) { @@ -1039,7 +1039,7 @@ static void b43legacy_phy_initg(struct b b43legacy_phy_write(dev, 0x0811, 0x0400); b43legacy_phy_write(dev, 0x0015, 0x00C0); } - if (phy->rev >= 2 || phy->gmode) { + if (phy->rev >= 2 || phy->connected) { tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; if (tmp == 3 || tmp == 5) { b43legacy_phy_write(dev, 0x04C2, 0x1816); @@ -1058,7 +1058,7 @@ static void b43legacy_phy_initg(struct b b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E) | 0x0004); } - if (phy->rev >= 2 && phy->gmode) + if (phy->rev >= 2 && phy->connected) b43legacy_calc_loopback_gain(dev); if (phy->radio_rev != 8) { if (phy->initval == 0xFFFF) @@ -1092,7 +1092,7 @@ static void b43legacy_phy_initg(struct b else b43legacy_phy_write(dev, 0x002F, 0x0202); } - if (phy->gmode || phy->rev >= 2) { + if (phy->connected || phy->rev >= 2) { b43legacy_phy_lo_adjust(dev, 0); b43legacy_phy_write(dev, 0x080F, 0x8078); } @@ -1106,7 +1106,7 @@ static void b43legacy_phy_initg(struct b */ b43legacy_nrssi_hw_update(dev, 0xFFFF); b43legacy_calc_nrssi_threshold(dev); - } else if (phy->gmode || phy->rev >= 2) { + } else if (phy->connected || phy->rev >= 2) { if (phy->nrssi[0] == -1000) { B43legacy_WARN_ON(phy->nrssi[1] != -1000); b43legacy_calc_nrssi_slope(dev); @@ -1252,7 +1252,7 @@ u16 b43legacy_phy_lo_g_deviation_subval( unsigned long flags; local_irq_save(flags); - if (phy->gmode) { + if (phy->connected) { b43legacy_phy_write(dev, 0x15, 0xE300); control <<= 8; b43legacy_phy_write(dev, 0x0812, control | 0x00B0); @@ -1517,7 +1517,7 @@ void b43legacy_phy_lo_g_measure(struct b oldchannel = phy->channel; /* Setup */ - if (phy->gmode) { + if (phy->connected) { regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS); regstack[1] = b43legacy_phy_read(dev, 0x0802); b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] @@ -1534,14 +1534,14 @@ void b43legacy_phy_lo_g_measure(struct b regstack[9] = b43legacy_radio_read16(dev, 0x43); regstack[10] = b43legacy_radio_read16(dev, 0x7A); regstack[11] = b43legacy_radio_read16(dev, 0x52); - if (phy->gmode) { + if (phy->connected) { regstack[12] = b43legacy_phy_read(dev, 0x0811); regstack[13] = b43legacy_phy_read(dev, 0x0812); regstack[14] = b43legacy_phy_read(dev, 0x0814); regstack[15] = b43legacy_phy_read(dev, 0x0815); } b43legacy_radio_selectchannel(dev, 6, 0); - if (phy->gmode) { + if (phy->connected) { b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] & 0x7FFF); b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); @@ -1558,7 +1558,7 @@ void b43legacy_phy_lo_g_measure(struct b b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0); b43legacy_phy_write(dev, 0x002B, 0x0203); b43legacy_phy_write(dev, 0x002A, 0x08A3); - if (phy->gmode) { + if (phy->connected) { b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003); b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC); b43legacy_phy_write(dev, 0x0811, 0x01B3); @@ -1680,7 +1680,7 @@ void b43legacy_phy_lo_g_measure(struct b } /* Restoration */ - if (phy->gmode) { + if (phy->connected) { b43legacy_phy_write(dev, 0x0015, 0xE300); b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0); udelay(5); @@ -1692,7 +1692,7 @@ void b43legacy_phy_lo_g_measure(struct b b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0); b43legacy_phy_lo_adjust(dev, is_initializing); b43legacy_phy_write(dev, 0x002E, 0x807F); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x002F, 0x0202); else b43legacy_phy_write(dev, 0x002F, 0x0101); @@ -1707,7 +1707,7 @@ void b43legacy_phy_lo_g_measure(struct b regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F); b43legacy_radio_write16(dev, 0x52, regstack[11]); b43legacy_write16(dev, 0x03E2, regstack[3]); - if (phy->gmode) { + if (phy->connected) { b43legacy_phy_write(dev, 0x0811, regstack[12]); b43legacy_phy_write(dev, 0x0812, regstack[13]); b43legacy_phy_write(dev, 0x0814, regstack[14]); Index: wireless-dev/drivers/net/wireless/b43legacy/phy.h =================================================================== --- wireless-dev.orig/drivers/net/wireless/b43legacy/phy.h +++ wireless-dev/drivers/net/wireless/b43legacy/phy.h @@ -186,7 +186,7 @@ void b43legacy_raw_phy_unlock(struct b43 /* Card uses the loopback gain stuff */ #define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->gmode)) + (((phy)->rev > 1) || ((phy)->connected)) u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset); void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val); Index: wireless-dev/drivers/net/wireless/b43legacy/radio.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/b43legacy/radio.c +++ wireless-dev/drivers/net/wireless/b43legacy/radio.c @@ -856,7 +856,7 @@ void b43legacy_calc_nrssi_threshold(stru break; } case B43legacy_PHYTYPE_G: - if (!phy->gmode || + if (!phy->connected || !(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); @@ -1342,7 +1342,7 @@ int b43legacy_radio_set_interference_mit int currentmode; if ((phy->type != B43legacy_PHYTYPE_G) || - (phy->rev == 0) || (!phy->gmode)) + (phy->rev == 0) || (!phy->connected)) return -ENODEV; phy->aci_wlan_automatic = 0; @@ -1403,7 +1403,7 @@ static u16 b43legacy_get_812_value(struc u8 loop; u16 extern_lna_control; - if (!phy->gmode) + if (!phy->connected) return 0; if (!has_loopback_gain(phy)) { if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo @@ -1515,7 +1515,7 @@ u16 b43legacy_radio_init2050(struct b43l b43legacy_phy_write(dev, 0x0030, 0x00FF); b43legacy_write16(dev, 0x03EC, 0x3F3F); } else { - if (phy->gmode) { + if (phy->connected) { backup[4] = b43legacy_phy_read(dev, 0x0811); backup[5] = b43legacy_phy_read(dev, 0x0812); backup[6] = b43legacy_phy_read(dev, 0x0814); @@ -1584,13 +1584,13 @@ u16 b43legacy_radio_init2050(struct b43l if (phy->type == B43legacy_PHYTYPE_B) b43legacy_radio_write16(dev, 0x0078, 0x0026); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(0, 1, 1))); b43legacy_phy_write(dev, 0x0015, 0xBFAF); b43legacy_phy_write(dev, 0x002B, 0x1403); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(0, 0, 1))); @@ -1612,19 +1612,19 @@ u16 b43legacy_radio_init2050(struct b43l b43legacy_phy_write(dev, 0x005A, 0x0480); b43legacy_phy_write(dev, 0x0059, 0xC810); b43legacy_phy_write(dev, 0x0058, 0x000D); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); b43legacy_phy_write(dev, 0x0015, 0xAFB0); udelay(10); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); b43legacy_phy_write(dev, 0x0015, 0xEFB0); udelay(10); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 0))); @@ -1632,7 +1632,7 @@ u16 b43legacy_radio_init2050(struct b43l udelay(20); tmp1 += b43legacy_phy_read(dev, 0x002D); b43legacy_phy_write(dev, 0x0058, 0x0000); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); @@ -1653,19 +1653,19 @@ u16 b43legacy_radio_init2050(struct b43l b43legacy_phy_write(dev, 0x005A, 0x0D80); b43legacy_phy_write(dev, 0x0059, 0xC810); b43legacy_phy_write(dev, 0x0058, 0x000D); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); b43legacy_phy_write(dev, 0x0015, 0xAFB0); udelay(10); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); b43legacy_phy_write(dev, 0x0015, 0xEFB0); udelay(10); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 0))); @@ -1673,7 +1673,7 @@ u16 b43legacy_radio_init2050(struct b43l udelay(10); tmp2 += b43legacy_phy_read(dev, 0x002D); b43legacy_phy_write(dev, 0x0058, 0x0000); - if (phy->gmode) + if (phy->connected) b43legacy_phy_write(dev, 0x0812, b43legacy_get_812_value(dev, LPD(1, 0, 1))); @@ -1702,7 +1702,7 @@ u16 b43legacy_radio_init2050(struct b43l b43legacy_phy_write(dev, 0x0030, backup[2]); b43legacy_write16(dev, 0x03EC, backup[3]); } else { - if (phy->gmode) { + if (phy->connected) { b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO) & 0x7FFF)); @@ -2082,7 +2082,7 @@ void b43legacy_radio_turn_on(struct b43l b43legacy_phy_write(dev, 0x0015, 0x8000); b43legacy_phy_write(dev, 0x0015, 0xCC00); b43legacy_phy_write(dev, 0x0015, - (phy->gmode ? 0x00C0 : 0x0000)); + (phy->connected ? 0x00C0 : 0x0000)); err = b43legacy_radio_selectchannel(dev, B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); B43legacy_WARN_ON(err != 0); - 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