diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_main.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_main.c --- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_main.c Mon Aug 26 19:32:44 2002 +++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_main.c Mon Aug 26 20:25:18 2002 @@ -46,6 +46,21 @@ /* Change Log * + * 2.1.12 8/2/02 + * o Feature: ethtool register dump + * o Bug fix: Driver passes wrong name to /proc/interrupts + * o Bug fix: Ethernet bridging not working + * o Bug fix: Promiscuous mode is not working + * o Bug fix: Checked return value from copy_from_user (William Stinson, + * wstinson@infonie.fr) + * o Bug fix: ARP wake on LAN fails + * o Bug fix: mii-diag does not update driver level's speed, duplex and + * re-configure flow control + * o Bug fix: Ethtool shows wrong speed/duplex when not connected + * o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced + * speed/duplex + * o Bug fix: PHY loopback diagnostic fails + * * 2.1.6 7/5/02 * o Added device ID support for Dell LOM. * o Added device ID support for 82511QM mobile nics. @@ -128,7 +143,7 @@ static void e100_non_tx_background(unsig /* Global Data structures and variables */ char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation"; -char e100_driver_version[]="2.1.6-k1"; +char e100_driver_version[]="2.1.15-k1"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; char e100_short_driver_name[] = "e100"; static int e100nics = 0; @@ -731,16 +746,6 @@ e100_remove1(struct pci_dev *pcid) bdp->non_tx_command_state = E100_NON_TX_IDLE; } - /* Set up wol options and enable PME if wol is enabled */ - if (bdp->wolopts) { - e100_do_wol(pcid, bdp); - /* Enable PME for power state D3 */ - pci_enable_wake(pcid, 3, 1); - /* Set power state to D1 in case driver is RELOADED */ - /* If system powers down, device is switched from D1 to D3 */ - pci_set_power_state(pcid, 1); - } - e100_clear_structs(dev); --e100nics; @@ -1011,7 +1016,9 @@ e100_close(struct net_device *dev) bdp->intr_mask = SCB_INT_MASK; e100_isolate_driver(bdp); - bdp->ip_lbytes = e100_get_ip_lbytes(dev); + netif_carrier_off(bdp->device); + bdp->cur_line_speed = 0; + bdp->cur_dplx_mode = 0; free_irq(dev->irq, dev); e100_clear_pools(bdp); @@ -3345,9 +3352,15 @@ e100_ethtool_get_settings(struct net_dev ecmd.transceiver = XCVR_INTERNAL; ecmd.phy_address = bdp->phy_addr; - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; + if (netif_carrier_ok(bdp->device)) { + ecmd.speed = bdp->cur_line_speed; + ecmd.duplex = + (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; + } + else { + ecmd.speed = -1; + ecmd.duplex = -1; + } ecmd.advertising = ADVERTISED_TP; @@ -3469,7 +3482,8 @@ e100_ethtool_glink(struct net_device *de bdp = dev->priv; info.cmd = ETHTOOL_GLINK; - info.data = e100_get_link_state(bdp); + /* Consider both PHY link and netif_running */ + info.data = e100_update_link_state(bdp); if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) return -EFAULT; @@ -3882,7 +3896,6 @@ e100_ethtool_wol(struct net_device *dev, if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) res = -EFAULT; break; - case ETHTOOL_SWOL: /* If ALL requests are supported or request is DISABLE wol */ if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) @@ -3891,6 +3904,8 @@ e100_ethtool_wol(struct net_device *dev, } else { res = -EOPNOTSUPP; } + if (wolinfo.wolopts & WAKE_ARP) + bdp->ip_lbytes = e100_get_ip_lbytes(dev); break; default: break; @@ -3968,8 +3983,30 @@ e100_mii_ioctl(struct net_device *dev, s if (netif_running(dev)) { return -EBUSY; } - e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, + /* If reg = 0 && change speed/duplex */ + if (data_ptr->reg_num == 0 && + (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ + || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ + || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) + || data_ptr->val_in == 0)) { + if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) + || data_ptr->val_in == (BMCR_RESET)) + bdp->params.e100_speed_duplex = E100_AUTONEG; + else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) + bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; + else if (data_ptr->val_in == (BMCR_SPEED100)) + bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; + else if (data_ptr->val_in == (BMCR_FULLDPLX)) + bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; + else + bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; + e100_set_speed_duplex(bdp); + } + else { + e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr, data_ptr->val_in); + } + break; default: @@ -4140,8 +4177,6 @@ static int e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) { struct pci_dev *pdev = NULL; - struct net_device *netdev; - struct e100_private *bdp; switch(event) { case SYS_DOWN: @@ -4149,18 +4184,10 @@ e100_notify_reboot(struct notifier_block case SYS_POWER_OFF: pci_for_each_dev(pdev) { if(pci_dev_driver(pdev) == &e100_driver) { - netdev = pci_get_drvdata(pdev); /* If net_device struct is allocated? */ - if (netdev) { - bdp = netdev->priv; - if (bdp->wolopts) { - bdp->ip_lbytes = - e100_get_ip_lbytes(netdev); - e100_do_wol(pdev, bdp); - pci_enable_wake(pdev, 3, 1); - pci_set_power_state(pdev, 3); - } - } + if (pci_get_drvdata(pdev)) + e100_suspend(pdev, 3); + } } } @@ -4178,7 +4205,6 @@ e100_suspend(struct pci_dev *pcid, u32 s /* If wol is enabled */ if (bdp->wolopts) { - bdp->ip_lbytes = e100_get_ip_lbytes(netdev); e100_do_wol(pcid, bdp); pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ pci_set_power_state(pcid, 3); /* Set power state to D3. */ @@ -4187,7 +4213,6 @@ e100_suspend(struct pci_dev *pcid, u32 s pci_disable_device(pcid); pci_set_power_state(pcid, state); } - return 0; } @@ -4215,7 +4240,6 @@ e100_resume(struct pci_dev *pcid) return 0; } - #endif /* CONFIG_PM */ static void diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.c --- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.c Mon Aug 26 19:21:14 2002 +++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.c Mon Aug 26 20:21:24 2002 @@ -45,11 +45,12 @@ void e100_handle_zlock(struct e100_priva * Returns: * NOTHING */ -void +int e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) { int e100_retry; u32 temp_val; + unsigned int mdi_cntrl; spin_lock_bh(&bdp->mdi_access_lock); temp_val = (((u32) data) | (reg_addr << 16) | @@ -62,13 +63,18 @@ e100_mdi_write(struct e100_private *bdp, /* poll for the mdi write to complete */ e100_retry = E100_CMD_WAIT; - while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && - (e100_retry)) { + while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { udelay(20); e100_retry--; } spin_unlock_bh(&bdp->mdi_access_lock); + if (mdi_cntrl & MDI_PHY_READY) + return 0; + else { + printk(KERN_ERR "e100: MDI write timeout\n"); + return 1; + } } /* @@ -90,11 +96,12 @@ e100_mdi_write(struct e100_private *bdp, * Returns: * NOTHING */ -void +int e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) { int e100_retry; u32 temp_val; + unsigned int mdi_cntrl; spin_lock_bh(&bdp->mdi_access_lock); /* Issue the read command to the MDI control register. */ @@ -107,16 +114,22 @@ e100_mdi_read(struct e100_private *bdp, /* poll for the mdi read to complete */ e100_retry = E100_CMD_WAIT; - while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && - (e100_retry)) { + while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { udelay(20); e100_retry--; } - // return the lower word - *data = (u16) readl(&bdp->scb->scb_mdi_cntrl); spin_unlock_bh(&bdp->mdi_access_lock); + if (mdi_cntrl & MDI_PHY_READY) { + /* return the lower word */ + *data = (u16) mdi_cntrl; + return 0; + } + else { + printk(KERN_ERR "e100: MDI read timeout\n"); + return 1; + } } static unsigned char __devinit @@ -480,10 +493,8 @@ e100_find_speed_duplex(struct e100_priva /* First we should check to see if we have link */ /* If we don't have a link no reason to print a speed and duplex */ if (!e100_update_link_state(bdp)) { - return; - } - - if (bdp->flags & DF_SPEED_FORCED) { + bdp->cur_line_speed = 0; + bdp->cur_dplx_mode = 0; return; } @@ -617,10 +628,13 @@ e100_force_speed_duplex(struct e100_priv u16 control; unsigned long expires; + e100_phy_reset(bdp); + bdp->flags |= DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); control &= ~BMCR_ANENABLE; + control &= ~BMCR_LOOPBACK; /* Check e100.c values */ switch (bdp->params.e100_speed_duplex) { @@ -838,7 +852,7 @@ e100_phy_set_speed_duplex(struct e100_pr } void -e100_phy_reset(struct e100_private *bdp) +e100_phy_autoneg(struct e100_private *bdp) { u16 ctrl_reg; @@ -849,6 +863,23 @@ e100_phy_reset(struct e100_private *bdp) udelay(100); } +void +e100_phy_set_loopback(struct e100_private *bdp) +{ + u16 ctrl_reg; + ctrl_reg = BMCR_LOOPBACK; + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); + udelay(100); +} + +void +e100_phy_reset(struct e100_private *bdp) +{ + u16 ctrl_reg; + ctrl_reg = BMCR_RESET; + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); +} + unsigned char __devinit e100_phy_init(struct e100_private *bdp) { @@ -915,7 +946,8 @@ e100_get_link_state(struct e100_private /* * Procedure: e100_update_link_state * - * Description: This routine updates the link status of the adapter + * Description: This routine updates the link status of the adapter, + * also considering netif_running * * Arguments: bdp - Pointer to the e100_private structure for the board * @@ -929,7 +961,8 @@ e100_update_link_state(struct e100_priva { unsigned char link; - link = e100_get_link_state(bdp); + /* Logical AND PHY link & netif_running */ + link = e100_get_link_state(bdp) && netif_running(bdp->device); if (link) { if (!netif_carrier_ok(bdp->device)) diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.h linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.h --- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.h Mon Aug 26 19:21:14 2002 +++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.h Mon Aug 26 20:21:24 2002 @@ -151,8 +151,10 @@ extern unsigned char e100_update_link_st extern unsigned char e100_phy_check(struct e100_private *bdp); extern void e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart); +extern void e100_phy_autoneg(struct e100_private *bdp); extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_mdi_write(struct e100_private *, u32, u32, u16); -extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *); +extern void e100_phy_set_loopback(struct e100_private *bdp); +extern int e100_mdi_write(struct e100_private *, u32, u32, u16); +extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); #endif diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_proc.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_proc.c --- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_proc.c Mon Aug 26 19:21:14 2002 +++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_proc.c Mon Aug 26 20:21:24 2002 @@ -61,7 +61,7 @@ extern char e100_short_driver_name[]; extern char e100_driver_version[]; extern struct net_device_stats *e100_get_stats(struct net_device *dev); extern char *e100_get_brand_msg(struct e100_private *bdp); -extern void e100_mdi_write(struct e100_private *, u32, u32, u16); +extern int e100_mdi_write(struct e100_private *, u32, u32, u16); static void e100_proc_cleanup(void); static unsigned char e100_init_proc_dir(void); diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_test.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_test.c --- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_test.c Mon Aug 26 19:21:14 2002 +++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_test.c Mon Aug 26 20:21:24 2002 @@ -31,6 +31,9 @@ extern u16 e100_eeprom_read(struct e100_private *, u16); extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8); extern void e100_phy_reset(struct e100_private *bdp); +extern void e100_phy_autoneg(struct e100_private *bdp); +extern void e100_phy_set_loopback(struct e100_private *bdp); +extern void e100_force_speed_duplex(struct e100_private *bdp); static u8 e100_diag_selftest(struct net_device *); static u8 e100_diag_eeprom(struct net_device *); @@ -239,6 +242,7 @@ e100_diag_config_loopback(struct e100_pr *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); if (set_loopback) { + /* Configure loopback on MAC */ e100_config_loopback_mode(bdp,loopback_mode); } else { e100_config_loopback_mode(bdp,NO_LOOPBACK); @@ -247,16 +251,20 @@ e100_diag_config_loopback(struct e100_pr e100_config(bdp); if (loopback_mode == PHY_LOOPBACK) { - unsigned long expires = jiffies + HZ * 5; - if (set_loopback) - e100_phy_reset(bdp); - - /* wait up to 5 secs for PHY loopback ON/OFF to take effect */ - while ((e100_get_link_state(bdp) != set_loopback) && - time_before(jiffies, expires)) { - yield(); + /* Set PHY loopback mode */ + e100_phy_set_loopback(bdp); + else { /* Back to normal speed and duplex */ + if (bdp->params.e100_speed_duplex == E100_AUTONEG) + /* Reset PHY and do autoneg */ + e100_phy_autoneg(bdp); + else + /* Reset PHY and force speed and duplex */ + e100_force_speed_duplex(bdp); } + /* Wait for PHY state change */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); } else { /* For MAC loopback wait 500 msec to take effect */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 2); @@ -276,6 +284,7 @@ e100_diag_loopback_alloc(struct e100_pri rfd_t *rfd; tbd_t *tbd; + /* tcb, tbd and transmit buffer are allocated */ tcb = pci_alloc_consistent(bdp->pdev, (sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE), @@ -283,22 +292,26 @@ e100_diag_loopback_alloc(struct e100_pri if (tcb == NULL) return false; - memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE); + memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); tcb->tcb_phys = dma_handle; tcb->tcb_hdr.cb_status = 0; tcb->tcb_hdr.cb_cmd = cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys); - tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff); + /* Next command is null */ + tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); tcb->tcb_cnt = 0; tcb->tcb_thrshld = bdp->tx_thld; tcb->tcb_tbd_num = 1; + /* Set up tcb tbd pointer */ tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); + /* Set up tbd transmit buffer */ tbd->tbd_buf_addr = cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024); + /* The value of first 512 bytes is FF */ + memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); + /* The value of second 512 bytes is BA */ memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); wmb(); rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); @@ -313,10 +326,9 @@ e100_diag_loopback_alloc(struct e100_pri memset(rfd, 0x00, sizeof (rfd_t)); /* init all fields in rfd */ - rfd->rfd_header.cb_status = 0; rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_act_cnt = 0; rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); + /* dma_handle is physical address of rfd */ bdp->loopback.dma_handle = dma_handle; bdp->loopback.tcb = tcb; bdp->loopback.rfd = rfd; @@ -354,12 +366,15 @@ e100_diag_loopback_cu_ru_exec(struct e10 static u8 e100_diag_check_pkt(u8 *datap) { - if( (*datap)==0xFF) { - if(*(datap + 600) == 0xBA) { - return true; - } - } - return false; + int i; + for (i = 0; i<512; i++) { + if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { + printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); + return false; + } + } + printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); + return true; } /** @@ -389,10 +404,14 @@ e100_diag_rcv_loopback_pkt(struct e100_p } } - if (rfd_status & RFD_STATUS_COMPLETE) + if (rfd_status & RFD_STATUS_COMPLETE) { + printk(KERN_DEBUG "e100: Loopback packet received\n"); return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - else + } + else { + printk(KERN_ERR "e100: Loopback packet not received\n"); return false; + } } /** .