Commit ec4899bb authored by Scott Feldman's avatar Scott Feldman Committed by Jeff Garzik

e100 net driver update 4/4:

o Bug fix: ethernet bridging not working
o Bug fix: mii-diag does not update driver's speed, 
  duplex, and 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: ethtool PHY loopback diagnostic fails
parent 7e1b0291
......@@ -45,6 +45,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.
......@@ -128,7 +143,7 @@ static void e100_non_tx_background(unsigned long);
/* 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_device *dev, struct ifreq *ifr)
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = bdp->phy_addr;
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 *dev, struct ifreq *ifr)
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, struct ifreq *ifr)
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, struct ifreq *ifr)
} 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, struct ifreq *ifr, int cmd)
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 *nb, unsigned long event, void *p)
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 state)
/* 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 state)
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
......
......@@ -45,11 +45,12 @@ void e100_handle_zlock(struct e100_private *bdp);
* 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, u32 reg_addr, u32 phy_addr, u16 data)
/* 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, u32 reg_addr, u32 phy_addr, u16 data)
* 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, u32 reg_addr, u32 phy_addr, u16 *data)
/* 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_private *bdp)
/* 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_private *bdp)
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_private *bdp, unsigned char force_restart)
}
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 *bdp)
/*
* 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_private *bdp)
{
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))
......
......@@ -151,8 +151,10 @@ extern unsigned char e100_update_link_state(struct e100_private *bdp);
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
......@@ -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);
......
......@@ -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_private* bdp,
*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_private* bdp,
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_private *bdp)
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_private *bdp)
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_private *bdp)
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 e100_private *bdp)
static u8
e100_diag_check_pkt(u8 *datap)
{
if( (*datap)==0xFF) {
if(*(datap + 600) == 0xBA) {
return true;
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;
}
}
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_private* bdp)
}
}
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;
}
}
/**
......
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