macsonic: fix crash on PowerBook 520

No-one seems to know where the PowerBook 500 series store their ethernet
MAC addresses. So, rather than crash, use a MAC address from the SONIC
CAM. Failing that, generate a random one.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Finn Thain 2009-11-03 03:42:40 +00:00 committed by David S. Miller
parent 87d75b5241
commit dcaa6a9414

View file

@ -223,69 +223,73 @@ static int __devinit macsonic_init(struct net_device *dev)
return 0; return 0;
} }
static int __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) #define INVALID_MAC(mac) (memcmp(mac, "\x08\x00\x07", 3) && \
memcmp(mac, "\x00\xA0\x40", 3) && \
memcmp(mac, "\x00\x80\x19", 3) && \
memcmp(mac, "\x00\x05\x02", 3))
static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev)
{ {
struct sonic_local *lp = netdev_priv(dev); struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE; const int prom_addr = ONBOARD_SONIC_PROM_BASE;
int i; unsigned short val;
/* On NuBus boards we can sometimes look in the ROM resources. /*
No such luck for comm-slot/onboard. */ * On NuBus boards we can sometimes look in the ROM resources.
for(i = 0; i < 6; i++) * No such luck for comm-slot/onboard.
dev->dev_addr[i] = SONIC_READ_PROM(i); * On the PowerBook 520, the PROM base address is a mystery.
*/
if (hwreg_present((void *)prom_addr)) {
int i;
/* Most of the time, the address is bit-reversed. The NetBSD for (i = 0; i < 6; i++)
source has a rather long and detailed historical account of dev->dev_addr[i] = SONIC_READ_PROM(i);
why this is so. */ if (!INVALID_MAC(dev->dev_addr))
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && return;
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
bit_reverse_addr(dev->dev_addr);
else
return 0;
/* If we still have what seems to be a bogus address, we'll
look in the CAM. The top entry should be ours. */
/* Danger! This only works if MacOS has already initialized
the card... */
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
{
unsigned short val;
printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP, 15);
val = SONIC_READ(SONIC_CAP2);
dev->dev_addr[5] = val >> 8;
dev->dev_addr[4] = val & 0xff;
val = SONIC_READ(SONIC_CAP1);
dev->dev_addr[3] = val >> 8;
dev->dev_addr[2] = val & 0xff;
val = SONIC_READ(SONIC_CAP0);
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
printk(KERN_INFO "HW Address from CAM 15: %pM\n",
dev->dev_addr);
} else return 0;
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
memcmp(dev->dev_addr, "\x00\x05\x02", 3))
{
/* /*
* Still nonsense ... messed up someplace! * Most of the time, the address is bit-reversed. The NetBSD
* source has a rather long and detailed historical account of
* why this is so.
*/ */
printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n"); bit_reverse_addr(dev->dev_addr);
return -EIO; if (!INVALID_MAC(dev->dev_addr))
} else return 0; return;
/*
* If we still have what seems to be a bogus address, we'll
* look in the CAM. The top entry should be ours.
*/
printk(KERN_WARNING "macsonic: MAC address in PROM seems "
"to be invalid, trying CAM\n");
} else {
printk(KERN_WARNING "macsonic: cannot read MAC address from "
"PROM, trying CAM\n");
}
/* This only works if MacOS has already initialized the card. */
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP, 15);
val = SONIC_READ(SONIC_CAP2);
dev->dev_addr[5] = val >> 8;
dev->dev_addr[4] = val & 0xff;
val = SONIC_READ(SONIC_CAP1);
dev->dev_addr[3] = val >> 8;
dev->dev_addr[2] = val & 0xff;
val = SONIC_READ(SONIC_CAP0);
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
if (!INVALID_MAC(dev->dev_addr))
return;
/* Still nonsense ... messed up someplace! */
printk(KERN_WARNING "macsonic: MAC address in CAM entry 15 "
"seems invalid, will use a random MAC\n");
random_ether_addr(dev->dev_addr);
} }
static int __devinit mac_onboard_sonic_probe(struct net_device *dev) static int __devinit mac_onboard_sonic_probe(struct net_device *dev)
@ -402,8 +406,7 @@ static int __devinit mac_onboard_sonic_probe(struct net_device *dev)
SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_ISR, 0x7fff);
/* Now look for the MAC address. */ /* Now look for the MAC address. */
if (mac_onboard_sonic_ethernet_addr(dev) != 0) mac_onboard_sonic_ethernet_addr(dev);
return -ENODEV;
/* Shared init code */ /* Shared init code */
return macsonic_init(dev); return macsonic_init(dev);