X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fcris%2Farch-v10%2Fdrivers%2Fethernet.c;h=f258c00085fcb25f5bbfa7a63592580e5e76d841;hb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;hp=943db0b9980377a9625b19c9aa301784d2b4ec18;hpb=c449269f45c2cdf53af08c8d0af37472f66539d9;p=linux-2.6.git diff --git a/arch/cris/arch-v10/drivers/ethernet.c b/arch/cris/arch-v10/drivers/ethernet.c index 943db0b99..f258c0008 100644 --- a/arch/cris/arch-v10/drivers/ethernet.c +++ b/arch/cris/arch-v10/drivers/ethernet.c @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ +/* $Id: ethernet.c,v 1.22 2004/05/14 07:58:03 starvik Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,15 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.22 2004/05/14 07:58:03 starvik + * Merge of changes from 2.4 + * + * Revision 1.20 2004/03/11 11:38:40 starvik + * Merge of Linux 2.6.4 + * + * Revision 1.18 2003/12/03 13:45:46 starvik + * Use hardware pad for short packets to prevent information leakage. + * * Revision 1.17 2003/07/04 08:27:37 starvik * Merge of Linux 2.5.74 * @@ -258,6 +267,16 @@ typedef struct etrax_eth_descr struct sk_buff* skb; } etrax_eth_descr; +/* Some transceivers requires special handling */ +struct transceiver_ops +{ + unsigned int oui; + void (*check_speed)(void); + void (*check_duplex)(void); +}; + +struct transceiver_ops* transceiver; + /* Duplex settings */ enum duplex { @@ -278,10 +297,17 @@ enum duplex */ #define MDIO_BASE_STATUS_REG 0x1 #define MDIO_BASE_CONTROL_REG 0x0 +#define MDIO_PHY_ID_HIGH_REG 0x2 +#define MDIO_PHY_ID_LOW_REG 0x3 #define MDIO_BC_NEGOTIATE 0x0200 #define MDIO_BC_FULL_DUPLEX_MASK 0x0100 #define MDIO_BC_AUTO_NEG_MASK 0x1000 #define MDIO_BC_SPEED_SELECT_MASK 0x2000 +#define MDIO_STATUS_100_FD 0x4000 +#define MDIO_STATUS_100_HD 0x2000 +#define MDIO_STATUS_10_FD 0x1000 +#define MDIO_STATUS_10_HD 0x0800 +#define MDIO_STATUS_SPEED_DUPLEX_MASK 0x7800 #define MDIO_ADVERTISMENT_REG 0x4 #define MDIO_ADVERT_100_FD 0x100 #define MDIO_ADVERT_100_HD 0x080 @@ -295,9 +321,13 @@ enum duplex /* Broadcom specific */ #define MDIO_AUX_CTRL_STATUS_REG 0x18 -#define MDIO_FULL_DUPLEX_IND 0x1 -#define MDIO_SPEED 0x2 -#define MDIO_PHYS_ADDR 0x0 +#define MDIO_BC_FULL_DUPLEX_IND 0x1 +#define MDIO_BC_SPEED 0x2 + +/* TDK specific */ +#define MDIO_TDK_DIAGNOSTIC_REG 18 +#define MDIO_TDK_DIAGNOSTIC_RATE 0x400 +#define MDIO_TDK_DIAGNOSTIC_DPLX 0x800 /* Network flash constants */ #define NET_FLASH_TIME (HZ/50) /* 20 ms */ @@ -341,6 +371,9 @@ static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); static unsigned int network_rec_config_shadow = 0; +static unsigned int mdio_phy_addr; /* Transciever address */ + +static unsigned int network_tr_ctrl_shadow = 0; /* Network speed indication. */ static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0); @@ -376,6 +409,7 @@ static void set_multicast_list(struct net_device *dev); static void e100_hardware_send_packet(char *buf, int length); static void update_rx_stats(struct net_device_stats *); static void update_tx_stats(struct net_device_stats *); +static int e100_probe_transceiver(void); static void e100_check_speed(unsigned long dummy); static void e100_set_speed(unsigned long speed); @@ -393,6 +427,21 @@ static void e100_reset_transceiver(void); static void e100_clear_network_leds(unsigned long dummy); static void e100_set_network_leds(int active); +static void broadcom_check_speed(void); +static void broadcom_check_duplex(void); +static void tdk_check_speed(void); +static void tdk_check_duplex(void); +static void generic_check_speed(void); +static void generic_check_duplex(void); + +struct transceiver_ops transceivers[] = +{ + {0x1018, broadcom_check_speed, broadcom_check_duplex}, /* Broadcom */ + {0xC039, tdk_check_speed, tdk_check_duplex}, /* TDK 2120 */ + {0x039C, tdk_check_speed, tdk_check_duplex}, /* TDK 2120C */ + {0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */ +}; + #define tx_done(dev) (*R_DMA_CH0_CMD == 0) /* @@ -409,7 +458,8 @@ etrax_ethernet_init(void) struct net_device *dev; int i, err; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); + printk(KERN_INFO + "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) @@ -496,7 +546,6 @@ etrax_ethernet_init(void) current_speed_selection = 0; /* Auto */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.function = e100_check_speed; - add_timer(&speed_timer); clear_led_timer.function = e100_clear_network_leds; @@ -504,7 +553,6 @@ etrax_ethernet_init(void) current_duplex = autoneg; duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; duplex_timer.function = e100_check_duplex; - add_timer(&duplex_timer); /* Initialize group address registers to make sure that no */ /* unwanted addresses are matched */ @@ -543,7 +591,7 @@ e100_set_mac_address(struct net_device *dev, void *p) /* show it in the log as well */ - printk("%s: changed MAC to ", dev->name); + printk(KERN_INFO "%s: changed MAC to ", dev->name); for (i = 0; i < 5; i++) printk("%02X:", dev->dev_addr[i]); @@ -569,12 +617,6 @@ e100_open(struct net_device *dev) { unsigned long flags; - /* disable the ethernet interface while we configure it */ - - *R_NETWORK_GEN_CONFIG = - IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | - IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); - /* enable the MDIO output pin */ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); @@ -645,14 +687,14 @@ e100_open(struct net_device *dev) IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); - *R_NETWORK_TR_CTRL = - IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | - IO_STATE(R_NETWORK_TR_CTRL, delay, none) | - IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | - IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | - IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | - IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | - IO_STATE(R_NETWORK_TR_CTRL, crc, enable); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable); + *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; save_flags(flags); cli(); @@ -660,7 +702,8 @@ e100_open(struct net_device *dev) /* enable the irq's for ethernet DMA */ *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); + IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, overrun, set) | @@ -689,6 +732,14 @@ e100_open(struct net_device *dev) restore_flags(flags); + /* Probe for transceiver */ + if (e100_probe_transceiver()) + goto grace_exit3; + + /* Start duplex/speed timers */ + add_timer(&speed_timer); + add_timer(&duplex_timer); + /* We are now ready to accept transmit requeusts from * the queueing layer of the networking. */ @@ -696,6 +747,8 @@ e100_open(struct net_device *dev) return 0; +grace_exit3: + free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); grace_exit2: free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); grace_exit1: @@ -705,9 +758,38 @@ grace_exit0: } +static void +generic_check_speed(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); + if ((data & MDIO_ADVERT_100_FD) || + (data & MDIO_ADVERT_100_HD)) + current_speed = 100; + else + current_speed = 10; +} + +static void +tdk_check_speed(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG); + current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10); +} + +static void +broadcom_check_speed(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + current_speed = (data & MDIO_BC_SPEED ? 100 : 10); +} + static void e100_check_speed(unsigned long dummy) { + static int led_initiated = 0; unsigned long data; int old_speed = current_speed; @@ -715,12 +797,13 @@ e100_check_speed(unsigned long dummy) if (!(data & MDIO_LINK_UP_MASK)) { current_speed = 0; } else { - data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); - current_speed = (data & MDIO_SPEED ? 100 : 10); + transceiver->check_speed(); } - if (old_speed != current_speed) + if ((old_speed != current_speed) || !led_initiated) { + led_initiated = 1; e100_set_network_leds(NO_NETWORK_ACTIVITY); + } /* Reinitialize the timer. */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; @@ -781,29 +864,21 @@ e100_negotiate(void) static void e100_set_speed(unsigned long speed) { - current_speed_selection = speed; - e100_negotiate(); + if (speed != current_speed_selection) { + current_speed_selection = speed; + e100_negotiate(); + } } static void e100_check_duplex(unsigned long dummy) { - unsigned long data; - - data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); - - if (data & MDIO_FULL_DUPLEX_IND) { - if (!full_duplex) { /* Duplex changed to full? */ - full_duplex = 1; - SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); - *R_NETWORK_REC_CONFIG = network_rec_config_shadow; - } - } else { /* half */ - if (full_duplex) { /* Duplex changed to half? */ - full_duplex = 0; - SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); - *R_NETWORK_REC_CONFIG = network_rec_config_shadow; - } + int old_duplex = full_duplex; + transceiver->check_duplex(); + if (old_duplex != full_duplex) { + /* Duplex changed */ + SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } /* Reinitialize the timer. */ @@ -811,13 +886,72 @@ e100_check_duplex(unsigned long dummy) add_timer(&duplex_timer); } +static void +generic_check_duplex(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); + if ((data & MDIO_ADVERT_100_FD) || + (data & MDIO_ADVERT_10_FD)) + full_duplex = 1; + else + full_duplex = 0; +} + +static void +tdk_check_duplex(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG); + full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0; +} + +static void +broadcom_check_duplex(void) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0; +} + static void e100_set_duplex(enum duplex new_duplex) { - current_duplex = new_duplex; - e100_negotiate(); + if (new_duplex != current_duplex) { + current_duplex = new_duplex; + e100_negotiate(); + } } +static int +e100_probe_transceiver(void) +{ + unsigned int phyid_high; + unsigned int phyid_low; + unsigned int oui; + struct transceiver_ops* ops = NULL; + + /* Probe MDIO physical address */ + for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) { + if (e100_get_mdio_reg(MDIO_BASE_STATUS_REG) != 0xffff) + break; + } + if (mdio_phy_addr == 32) + return -ENODEV; + + /* Get manufacturer */ + phyid_high = e100_get_mdio_reg(MDIO_PHY_ID_HIGH_REG); + phyid_low = e100_get_mdio_reg(MDIO_PHY_ID_LOW_REG); + oui = (phyid_high << 6) | (phyid_low >> 10); + + for (ops = &transceivers[0]; ops->oui; ops++) { + if (ops->oui == oui) + break; + } + transceiver = ops; + + return 0; +} static unsigned short e100_get_mdio_reg(unsigned char reg_num) @@ -827,7 +961,7 @@ e100_get_mdio_reg(unsigned char reg_num) int bitCounter; /* Start of frame, OP Code, Physical Address, Register Address */ - cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) | + cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (mdio_phy_addr << 7) | (reg_num << 2); e100_send_mdio_cmd(cmd, 0); @@ -848,7 +982,7 @@ e100_set_mdio_reg(unsigned char reg, unsigned short data) int bitCounter; unsigned short cmd; - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (reg << 2); e100_send_mdio_cmd(cmd, 1); @@ -916,7 +1050,7 @@ e100_reset_transceiver(void) data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MDIO_BASE_CONTROL_REG << 2); e100_send_mdio_cmd(cmd, 1); @@ -984,7 +1118,6 @@ static int e100_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *np = (struct net_local *)dev->priv; - int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; unsigned long flags; @@ -997,15 +1130,12 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - e100_hardware_send_packet(buf, length); + e100_hardware_send_packet(buf, skb->len); myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); /* Stop queue if full */ if (myNextTxDesc == myFirstTxDesc) { - /* Enable transmit interrupt to wake up queue */ - *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); - *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set); netif_stop_queue(dev); } @@ -1026,6 +1156,11 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK2_RD; + /* Disable RX/TX IRQs to avoid reentrancy */ + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); + /* Handle received packets */ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -1069,9 +1204,14 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { /* acknowledge the eop interrupt and wake up queue */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); - *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr); netif_wake_queue(dev); } + + /* Enable RX/TX IRQs again */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); + return IRQ_HANDLED; } @@ -1084,7 +1224,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* check for underrun irq */ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { - *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); + *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); np->stats.tx_errors++; D(printk("ethernet receiver underrun!\n")); } @@ -1096,6 +1238,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) } /* check for excessive collision irq */ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); + *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; + SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); @@ -1210,14 +1355,10 @@ e100_close(struct net_device *dev) { struct net_local *np = (struct net_local *)dev->priv; - printk("Closing %s.\n", dev->name); + printk(KERN_INFO "Closing %s.\n", dev->name); netif_stop_queue(dev); - *R_NETWORK_GEN_CONFIG = - IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | - IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); - *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | @@ -1245,21 +1386,25 @@ e100_close(struct net_device *dev) update_rx_stats(&np->stats); update_tx_stats(&np->stats); + /* Stop speed/duplex timers */ + del_timer(&speed_timer); + del_timer(&duplex_timer); + return 0; } static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; - struct net_local *np = (struct net_local *)dev->priv; + struct mii_ioctl_data *data = if_mii(ifr); + struct net_local *np = netdev_priv(dev); spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { case SIOCETHTOOL: return e100_ethtool_ioctl(dev,ifr); case SIOCGMIIPHY: /* Get PHY address */ - data->phy_id = MDIO_PHYS_ADDR; + data->phy_id = mdio_phy_addr; break; case SIOCGMIIREG: /* Read MII register */ data->val_out = e100_get_mdio_reg(data->reg_num); @@ -1278,7 +1423,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ e100_set_speed(0); break; - case SET_ETH_DUPLEX_HALF: /* Hhalf duplex. */ + case SET_ETH_DUPLEX_HALF: /* Half duplex. */ e100_set_duplex(half); break; case SET_ETH_DUPLEX_FULL: /* Full duplex. */ @@ -1312,12 +1457,12 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; ecmd.port = PORT_TP; ecmd.transceiver = XCVR_EXTERNAL; - ecmd.phy_address = MDIO_PHYS_ADDR; + ecmd.phy_address = mdio_phy_addr; ecmd.speed = current_speed; ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; ecmd.advertising = ADVERTISED_TP; if (current_duplex == autoneg && current_speed_selection == 0) - ecmd.advertising = ADVERTISED_Autoneg; + ecmd.advertising |= ADVERTISED_Autoneg; else { ecmd.advertising |= ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | @@ -1355,7 +1500,7 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) struct ethtool_drvinfo info; memset((void *) &info, 0, sizeof (info)); strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1); - strncpy(info.version, "$Revision: 1.17 $", sizeof(info.version) - 1); + strncpy(info.version, "$Revision: 1.22 $", sizeof(info.version) - 1); strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); info.regdump_len = 0; @@ -1595,7 +1740,11 @@ e100_set_network_leds(int active) if (!current_speed) { /* Make LED red, link is down */ +#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION) + LED_NETWORK_SET(LED_RED); +#else LED_NETWORK_SET(LED_OFF); +#endif } else if (light_leds) { if (current_speed == 10) { @@ -1615,4 +1764,26 @@ etrax_init_module(void) return etrax_ethernet_init(); } +static int __init +e100_boot_setup(char* str) +{ + struct sockaddr sa = {0}; + int i; + + /* Parse the colon separated Ethernet station address */ + for (i = 0; i < ETH_ALEN; i++) { + unsigned int tmp; + if (sscanf(str + 3*i, "%2x", &tmp) != 1) { + printk(KERN_WARNING "Malformed station address"); + return 0; + } + sa.sa_data[i] = (char)tmp; + } + + default_mac = sa; + return 1; +} + +__setup("etrax100_eth=", e100_boot_setup); + module_init(etrax_init_module);