Commit dcaa6a94 authored by Finn Thain's avatar Finn Thain Committed by David S. Miller
Browse files

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: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 87d75b52
...@@ -223,69 +223,73 @@ static int __devinit macsonic_init(struct net_device *dev) ...@@ -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;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = SONIC_READ_PROM(i);
if (!INVALID_MAC(dev->dev_addr))
return;
/* Most of the time, the address is bit-reversed. The NetBSD /*
source has a rather long and detailed historical account of * Most of the time, the address is bit-reversed. The NetBSD
why this is so. */ * source has a rather long and detailed historical account of
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && * why this is so.
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); bit_reverse_addr(dev->dev_addr);
else if (!INVALID_MAC(dev->dev_addr))
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. */
/* 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! * 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_ERR "macsonic: ERROR (INVALID MAC)\n"); printk(KERN_WARNING "macsonic: MAC address in PROM seems "
return -EIO; "to be invalid, trying CAM\n");
} else return 0; } 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) ...@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment