This is a multi-part message in MIME format. ------=_NextPart_000_003E_01C4C57D.9D366C70 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Use generic MII interface. Signed-off-by: Mikael Starvik ------=_NextPart_000_003E_01C4C57D.9D366C70 Content-Type: application/octet-stream; name="cris269_3.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="cris269_3.patch" ../linux/arch/cris/arch-v10/drivers/ethernet.c = lx25/arch/cris/arch-v10/drivers/ethernet.c Signed-off-by: Andrew Morton --- /dev/null | 0 25-akpm/arch/cris/arch-v10/drivers/ethernet.c | 423 ++++++++++++++------------ 2 files changed, 244 insertions(+), 179 deletions(-) diff -puN arch/cris/arch-v10/drivers/ethernet.c~cris-architecture-update-ethernet-driver arch/cris/arch-v10/drivers/ethernet.c --- 25/arch/cris/arch-v10/drivers/ethernet.c~cris-architecture-update-ethernet-driver Mon Nov 8 14:19:26 2004 +++ 25-akpm/arch/cris/arch-v10/drivers/ethernet.c Mon Nov 8 14:19:26 2004 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.22 2004/05/14 07:58:03 starvik Exp $ +/* $Id: ethernet.c,v 1.31 2004/10/18 14:49:03 starvik Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,27 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.31 2004/10/18 14:49:03 starvik + * Use RX interrupt as random source + * + * Revision 1.30 2004/09/29 10:44:04 starvik + * Enabed MAC-address output again + * + * Revision 1.29 2004/08/24 07:14:05 starvik + * Make use of generic MDIO interface and constants. + * + * Revision 1.28 2004/08/20 09:37:11 starvik + * Added support for Intel LXT972A. Creds to Randy Scarborough. + * + * Revision 1.27 2004/08/16 12:37:22 starvik + * Merge of Linux 2.6.8 + * + * Revision 1.25 2004/06/21 10:29:57 starvik + * Merge of Linux 2.6.7 + * + * Revision 1.23 2004/06/09 05:29:22 starvik + * Avoid any race where R_DMA_CH1_FIRST is NULL (may trigger cache bug). + * * Revision 1.22 2004/05/14 07:58:03 starvik * Merge of changes from 2.4 * @@ -222,13 +243,13 @@ #include #include #include -#include #include /* DMA and register descriptions */ #include /* LED_* I/O functions */ #include #include #include +#include #include #include @@ -252,6 +273,7 @@ static struct sockaddr default_mac = { /* Information that need to be kept for each board. */ struct net_local { struct net_device_stats stats; + struct mii_if_info mii_if; /* Tx control lock. This protects the transmit buffer ring * state along with the "tx full" state of the driver. This @@ -271,8 +293,8 @@ typedef struct etrax_eth_descr struct transceiver_ops { unsigned int oui; - void (*check_speed)(void); - void (*check_duplex)(void); + void (*check_speed)(struct net_device* dev); + void (*check_duplex)(struct net_device* dev); }; struct transceiver_ops* transceiver; @@ -295,25 +317,6 @@ enum duplex /* ** MDIO constants. */ -#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 -#define MDIO_ADVERT_10_FD 0x040 -#define MDIO_ADVERT_10_HD 0x020 -#define MDIO_LINK_UP_MASK 0x4 #define MDIO_START 0x1 #define MDIO_READ 0x2 #define MDIO_WRITE 0x1 @@ -329,6 +332,11 @@ enum duplex #define MDIO_TDK_DIAGNOSTIC_RATE 0x400 #define MDIO_TDK_DIAGNOSTIC_DPLX 0x800 +/*Intel LXT972A specific*/ +#define MDIO_INT_STATUS_REG_2 0x0011 +#define MDIO_INT_FULL_DUPLEX_IND ( 1 << 9 ) +#define MDIO_INT_SPEED ( 1 << 14 ) + /* Network flash constants */ #define NET_FLASH_TIME (HZ/50) /* 20 ms */ #define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ @@ -401,6 +409,7 @@ static irqreturn_t e100nw_interrupt(int static void e100_rx(struct net_device *dev); static int e100_close(struct net_device *dev); static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr); static int e100_set_config(struct net_device* dev, struct ifmap* map); static void e100_tx_timeout(struct net_device *dev); static struct net_device_stats *e100_get_stats(struct net_device *dev); @@ -408,37 +417,40 @@ static void set_multicast_list(struct ne 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 struct ethtool_ops ethtool_ops; +static int e100_probe_transceiver(struct net_device* dev); + +static void e100_check_speed(unsigned long priv); +static void e100_set_speed(struct net_device* dev, unsigned long speed); +static void e100_check_duplex(unsigned long priv); +static void e100_set_duplex(struct net_device* dev, enum duplex); +static void e100_negotiate(struct net_device* dev); -static void e100_check_speed(unsigned long dummy); -static void e100_set_speed(unsigned long speed); -static void e100_check_duplex(unsigned long dummy); -static void e100_set_duplex(enum duplex); -static void e100_negotiate(void); +static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location); +static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value); -static unsigned short e100_get_mdio_reg(unsigned char reg_num); -static void e100_set_mdio_reg(unsigned char reg, unsigned short data); static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); static void e100_send_mdio_bit(unsigned char bit); static unsigned char e100_receive_mdio_bit(void); -static void e100_reset_transceiver(void); +static void e100_reset_transceiver(struct net_device* net); 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); +static void broadcom_check_speed(struct net_device* dev); +static void broadcom_check_duplex(struct net_device* dev); +static void tdk_check_speed(struct net_device* dev); +static void tdk_check_duplex(struct net_device* dev); +static void intel_check_speed(struct net_device* dev); +static void intel_check_duplex(struct net_device* dev); +static void generic_check_speed(struct net_device* dev); +static void generic_check_duplex(struct net_device* dev); 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 */ + {0x04de, intel_check_speed, intel_check_duplex}, /* Intel LXT972A*/ {0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */ }; @@ -456,12 +468,15 @@ static int __init etrax_ethernet_init(void) { struct net_device *dev; + struct net_local* np; int i, err; printk(KERN_INFO "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); dev = alloc_etherdev(sizeof(struct net_local)); + np = dev->priv; + if (!dev) return -ENOMEM; @@ -483,7 +498,6 @@ etrax_ethernet_init(void) dev->do_ioctl = e100_ioctl; dev->set_config = e100_set_config; dev->tx_timeout = e100_tx_timeout; - SET_ETHTOOL_OPS(dev, ðtool_ops); /* Initialise the list of Etrax DMA-descriptors */ @@ -546,6 +560,7 @@ etrax_ethernet_init(void) current_speed = 10; current_speed_selection = 0; /* Auto */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; + duplex_timer.data = (unsigned long)dev; speed_timer.function = e100_check_speed; clear_led_timer.function = e100_clear_network_leds; @@ -553,8 +568,17 @@ etrax_ethernet_init(void) full_duplex = 0; current_duplex = autoneg; duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; + duplex_timer.data = (unsigned long)dev; duplex_timer.function = e100_check_duplex; + /* Initialize mii interface */ + np->mii_if.phy_id = mdio_phy_addr; + np->mii_if.phy_id_mask = 0x1f; + np->mii_if.reg_num_mask = 0x1f; + np->mii_if.dev = dev; + np->mii_if.mdio_read = e100_get_mdio_reg; + np->mii_if.mdio_write = e100_set_mdio_reg; + /* Initialize group address registers to make sure that no */ /* unwanted addresses are matched */ *R_NETWORK_GA_0 = 0x00000000; @@ -645,8 +669,8 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, - cardname, (void *)dev)) { + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, + SA_SAMPLE_RANDOM, cardname, (void *)dev)) { goto grace_exit0; } @@ -734,7 +758,7 @@ e100_open(struct net_device *dev) restore_flags(flags); /* Probe for transceiver */ - if (e100_probe_transceiver()) + if (e100_probe_transceiver(dev)) goto grace_exit3; /* Start duplex/speed timers */ @@ -760,45 +784,54 @@ grace_exit0: static void -generic_check_speed(void) +generic_check_speed(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); - if ((data & MDIO_ADVERT_100_FD) || - (data & MDIO_ADVERT_100_HD)) + data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE); + if ((data & ADVERTISE_100FULL) || + (data & ADVERTISE_100HALF)) current_speed = 100; else current_speed = 10; } static void -tdk_check_speed(void) +tdk_check_speed(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG); + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG); current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10); } static void -broadcom_check_speed(void) +broadcom_check_speed(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG); current_speed = (data & MDIO_BC_SPEED ? 100 : 10); } static void -e100_check_speed(unsigned long dummy) +intel_check_speed(struct net_device* dev) { + unsigned long data; + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2); + current_speed = (data & MDIO_INT_SPEED ? 100 : 10); +} + +static void +e100_check_speed(unsigned long priv) +{ + struct net_device* dev = (struct net_device*)priv; static int led_initiated = 0; unsigned long data; int old_speed = current_speed; - data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG); - if (!(data & MDIO_LINK_UP_MASK)) { + data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR); + if (!(data & BMSR_LSTATUS)) { current_speed = 0; } else { - transceiver->check_speed(); + transceiver->check_speed(dev); } if ((old_speed != current_speed) || !led_initiated) { @@ -812,70 +845,73 @@ e100_check_speed(unsigned long dummy) } static void -e100_negotiate(void) +e100_negotiate(struct net_device* dev) { - unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); + unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE); /* Discard old speed and duplex settings */ - data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | - MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD); + data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL | + ADVERTISE_10HALF | ADVERTISE_10FULL); switch (current_speed_selection) { case 10 : if (current_duplex == full) - data |= MDIO_ADVERT_10_FD; + data |= ADVERTISE_10FULL; else if (current_duplex == half) - data |= MDIO_ADVERT_10_HD; + data |= ADVERTISE_10HALF; else - data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD; + data |= ADVERTISE_10HALF | ADVERTISE_10FULL; break; case 100 : if (current_duplex == full) - data |= MDIO_ADVERT_100_FD; + data |= ADVERTISE_100FULL; else if (current_duplex == half) - data |= MDIO_ADVERT_100_HD; + data |= ADVERTISE_100HALF; else - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD; + data |= ADVERTISE_100HALF | ADVERTISE_100FULL; break; case 0 : /* Auto */ if (current_duplex == full) - data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD; + data |= ADVERTISE_100FULL | ADVERTISE_10FULL; else if (current_duplex == half) - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD; + data |= ADVERTISE_100HALF | ADVERTISE_10HALF; else - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + data |= ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL; break; default : /* assume autoneg speed and duplex */ - data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | - MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + data |= ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL; } - e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data); + e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data); /* Renegotiate with link partner */ - data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); - data |= MDIO_BC_NEGOTIATE; + data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR); + data |= BMCR_ANENABLE | BMCR_ANRESTART; - e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data); + e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data); } static void -e100_set_speed(unsigned long speed) +e100_set_speed(struct net_device* dev, unsigned long speed) { if (speed != current_speed_selection) { current_speed_selection = speed; - e100_negotiate(); + e100_negotiate(dev); } } static void -e100_check_duplex(unsigned long dummy) +e100_check_duplex(unsigned long priv) { + struct net_device *dev = (struct net_device *)priv; + struct net_local *np = (struct net_local *)dev->priv; int old_duplex = full_duplex; - transceiver->check_duplex(); + transceiver->check_duplex(dev); if (old_duplex != full_duplex) { /* Duplex changed */ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); @@ -885,47 +921,56 @@ e100_check_duplex(unsigned long dummy) /* Reinitialize the timer. */ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; add_timer(&duplex_timer); + np->mii_if.full_duplex = full_duplex; } static void -generic_check_duplex(void) +generic_check_duplex(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); - if ((data & MDIO_ADVERT_100_FD) || - (data & MDIO_ADVERT_10_FD)) + data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE); + if ((data & ADVERTISE_10FULL) || + (data & ADVERTISE_100FULL)) full_duplex = 1; else full_duplex = 0; } static void -tdk_check_duplex(void) +tdk_check_duplex(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG); + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG); full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0; } static void -broadcom_check_duplex(void) +broadcom_check_duplex(struct net_device* dev) { unsigned long data; - data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG); full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0; } +static void +intel_check_duplex(struct net_device* dev) +{ + unsigned long data; + data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2); + full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0; +} + static void -e100_set_duplex(enum duplex new_duplex) +e100_set_duplex(struct net_device* dev, enum duplex new_duplex) { if (new_duplex != current_duplex) { current_duplex = new_duplex; - e100_negotiate(); + e100_negotiate(dev); } } static int -e100_probe_transceiver(void) +e100_probe_transceiver(struct net_device* dev) { unsigned int phyid_high; unsigned int phyid_low; @@ -934,15 +979,15 @@ e100_probe_transceiver(void) /* 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) + if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 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); + phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1); + phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2); oui = (phyid_high << 6) | (phyid_low >> 10); for (ops = &transceivers[0]; ops->oui; ops++) { @@ -954,16 +999,16 @@ e100_probe_transceiver(void) return 0; } -static unsigned short -e100_get_mdio_reg(unsigned char reg_num) +static int +e100_get_mdio_reg(struct net_device *dev, int phy_id, int location) { unsigned short cmd; /* Data to be sent on MDIO port */ - unsigned short data; /* Data read from MDIO */ + int data; /* Data read from MDIO */ int bitCounter; /* Start of frame, OP Code, Physical Address, Register Address */ - cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (mdio_phy_addr << 7) | - (reg_num << 2); + cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) | + (location << 2); e100_send_mdio_cmd(cmd, 0); @@ -978,19 +1023,19 @@ e100_get_mdio_reg(unsigned char reg_num) } static void -e100_set_mdio_reg(unsigned char reg, unsigned short data) +e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value) { int bitCounter; unsigned short cmd; - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | - (reg << 2); + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) | + (location << 2); e100_send_mdio_cmd(cmd, 1); /* Data... */ for (bitCounter=15; bitCounter>=0 ; bitCounter--) { - e100_send_mdio_bit(GET_BIT(bitCounter, data)); + e100_send_mdio_bit(GET_BIT(bitCounter, value)); } } @@ -1043,15 +1088,15 @@ e100_receive_mdio_bit() } static void -e100_reset_transceiver(void) +e100_reset_transceiver(struct net_device* dev) { unsigned short cmd; unsigned short data; int bitCounter; - data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); + data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR); - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MDIO_BASE_CONTROL_REG << 2); + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2); e100_send_mdio_cmd(cmd, 1); @@ -1088,7 +1133,7 @@ e100_tx_timeout(struct net_device *dev) /* Reset the transceiver. */ - e100_reset_transceiver(); + e100_reset_transceiver(dev); /* and get rid of the packets that never got an interrupt */ while (myFirstTxDesc != myNextTxDesc) @@ -1170,7 +1215,8 @@ e100rxtx_interrupt(int irq, void *dev_id /* check if one or more complete packets were indeed received */ - while (*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) { + while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) && + (myNextRxDesc != myLastRxDesc)) { /* Take out the buffer and give it to the OS, then * allocate a new buffer to put a packet in. */ @@ -1402,34 +1448,36 @@ e100_ioctl(struct net_device *dev, struc 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_phy_addr; break; case SIOCGMIIREG: /* Read MII register */ - data->val_out = e100_get_mdio_reg(data->reg_num); + data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num); break; case SIOCSMIIREG: /* Write MII register */ - e100_set_mdio_reg(data->reg_num, data->val_in); + e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in); break; /* The ioctls below should be considered obsolete but are */ /* still present for compatability with old scripts/apps */ case SET_ETH_SPEED_10: /* 10 Mbps */ - e100_set_speed(10); + e100_set_speed(dev, 10); break; case SET_ETH_SPEED_100: /* 100 Mbps */ - e100_set_speed(100); + e100_set_speed(dev, 100); break; case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ - e100_set_speed(0); + e100_set_speed(dev, 0); break; case SET_ETH_DUPLEX_HALF: /* Half duplex. */ - e100_set_duplex(half); + e100_set_duplex(dev, half); break; case SET_ETH_DUPLEX_FULL: /* Full duplex. */ - e100_set_duplex(full); + e100_set_duplex(dev, full); break; case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ - e100_set_duplex(autoneg); + e100_set_duplex(dev, autoneg); break; default: return -EINVAL; @@ -1438,71 +1486,88 @@ e100_ioctl(struct net_device *dev, struc return 0; } -static int e100_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int +e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) { - ecmd->supported = - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | - SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; - ecmd->port = PORT_TP; - ecmd->transceiver = XCVR_EXTERNAL; - 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; - else { - ecmd->advertising |= - ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; - if (current_speed_selection == 10) - ecmd->advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); - else if (current_speed_selection == 100) - ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); - if (current_duplex == half) - ecmd->advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); - else if (current_duplex == full) - ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); - } - ecmd->autoneg = AUTONEG_ENABLE; - return 0; -} + struct ethtool_cmd ecmd; -static int e100_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - if (ecmd->autoneg == AUTONEG_ENABLE) { - e100_set_duplex(autoneg); - e100_set_speed(0); - } else { - e100_set_duplex(ecmd->duplex == DUPLEX_HALF ? half : full); - e100_set_speed(ecmd->speed == SPEED_10 ? 10: 100); - } - return 0; -} + if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) + return -EFAULT; -static void e100_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 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); -} - -static int e100_nway_reset(struct net_device *dev) -{ - if (current_duplex == autoneg && current_speed_selection == 0) - e100_negotiate(); + switch (ecmd.cmd) { + case ETHTOOL_GSET: + { + memset((void *) &ecmd, 0, sizeof (ecmd)); + ecmd.supported = + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_EXTERNAL; + 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; + else { + ecmd.advertising |= + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + if (current_speed_selection == 10) + ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); + else if (current_speed_selection == 100) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); + if (current_duplex == half) + ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); + else if (current_duplex == full) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); + } + ecmd.autoneg = AUTONEG_ENABLE; + if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) + return -EFAULT; + } + break; + case ETHTOOL_SSET: + { + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + if (ecmd.autoneg == AUTONEG_ENABLE) { + e100_set_duplex(dev, autoneg); + e100_set_speed(dev, 0); + } else { + e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full); + e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100); + } + } + break; + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info; + memset((void *) &info, 0, sizeof (info)); + strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1); + strncpy(info.version, "$Revision: 1.31 $", 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; + info.eedump_len = 0; + info.testinfo_len = 0; + if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) + return -EFAULT; + } + break; + case ETHTOOL_NWAY_RST: + if (current_duplex == autoneg && current_speed_selection == 0) + e100_negotiate(dev); + break; + default: + return -EOPNOTSUPP; + break; + } return 0; } -static struct ethtool_ops ethtool_ops = { - .get_settings = e100_get_settings, - .set_settings = e100_set_settings, - .get_drvinfo = e100_get_drvinfo, - .nway_reset = e100_nway_reset, -}; - static int e100_set_config(struct net_device *dev, struct ifmap *map) { @@ -1512,17 +1577,17 @@ e100_set_config(struct net_device *dev, switch(map->port) { case IF_PORT_UNKNOWN: /* Use autoneg */ - e100_set_speed(0); - e100_set_duplex(autoneg); + e100_set_speed(dev, 0); + e100_set_duplex(dev, autoneg); break; case IF_PORT_10BASET: - e100_set_speed(10); - e100_set_duplex(autoneg); + e100_set_speed(dev, 10); + e100_set_duplex(dev, autoneg); break; case IF_PORT_100BASET: case IF_PORT_100BASETX: - e100_set_speed(100); - e100_set_duplex(autoneg); + e100_set_speed(dev, 100); + e100_set_duplex(dev, autoneg); break; case IF_PORT_100BASEFX: case IF_PORT_10BASE2: diff -L linux/arch/cris/arch-v10/drivers/ethernet.c -puN /dev/null /dev/null _