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 @@ ...@@ -45,6 +45,21 @@
**********************************************************************/ **********************************************************************/
/* Change Log /* 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 * 2.1.6 7/5/02
* o Added device ID support for Dell LOM. * o Added device ID support for Dell LOM.
...@@ -128,7 +143,7 @@ static void e100_non_tx_background(unsigned long); ...@@ -128,7 +143,7 @@ static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */ /* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation"; 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"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100"; char e100_short_driver_name[] = "e100";
static int e100nics = 0; static int e100nics = 0;
...@@ -731,16 +746,6 @@ e100_remove1(struct pci_dev *pcid) ...@@ -731,16 +746,6 @@ e100_remove1(struct pci_dev *pcid)
bdp->non_tx_command_state = E100_NON_TX_IDLE; 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); e100_clear_structs(dev);
--e100nics; --e100nics;
...@@ -1011,7 +1016,9 @@ e100_close(struct net_device *dev) ...@@ -1011,7 +1016,9 @@ e100_close(struct net_device *dev)
bdp->intr_mask = SCB_INT_MASK; bdp->intr_mask = SCB_INT_MASK;
e100_isolate_driver(bdp); 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); free_irq(dev->irq, dev);
e100_clear_pools(bdp); e100_clear_pools(bdp);
...@@ -3345,9 +3352,15 @@ e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr) ...@@ -3345,9 +3352,15 @@ e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
ecmd.transceiver = XCVR_INTERNAL; ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = bdp->phy_addr; ecmd.phy_address = bdp->phy_addr;
if (netif_carrier_ok(bdp->device)) {
ecmd.speed = bdp->cur_line_speed; ecmd.speed = bdp->cur_line_speed;
ecmd.duplex = ecmd.duplex =
(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
}
else {
ecmd.speed = -1;
ecmd.duplex = -1;
}
ecmd.advertising = ADVERTISED_TP; ecmd.advertising = ADVERTISED_TP;
...@@ -3469,7 +3482,8 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) ...@@ -3469,7 +3482,8 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
bdp = dev->priv; bdp = dev->priv;
info.cmd = ETHTOOL_GLINK; 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))) if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
...@@ -3882,7 +3896,6 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) ...@@ -3882,7 +3896,6 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
res = -EFAULT; res = -EFAULT;
break; break;
case ETHTOOL_SWOL: case ETHTOOL_SWOL:
/* If ALL requests are supported or request is DISABLE wol */ /* If ALL requests are supported or request is DISABLE wol */
if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
...@@ -3891,6 +3904,8 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) ...@@ -3891,6 +3904,8 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
} else { } else {
res = -EOPNOTSUPP; res = -EOPNOTSUPP;
} }
if (wolinfo.wolopts & WAKE_ARP)
bdp->ip_lbytes = e100_get_ip_lbytes(dev);
break; break;
default: default:
break; break;
...@@ -3968,8 +3983,30 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -3968,8 +3983,30 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (netif_running(dev)) { if (netif_running(dev)) {
return -EBUSY; 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); data_ptr->val_in);
}
break; break;
default: default:
...@@ -4140,8 +4177,6 @@ static int ...@@ -4140,8 +4177,6 @@ static int
e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{ {
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
struct net_device *netdev;
struct e100_private *bdp;
switch(event) { switch(event) {
case SYS_DOWN: case SYS_DOWN:
...@@ -4149,18 +4184,10 @@ e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) ...@@ -4149,18 +4184,10 @@ e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
case SYS_POWER_OFF: case SYS_POWER_OFF:
pci_for_each_dev(pdev) { pci_for_each_dev(pdev) {
if(pci_dev_driver(pdev) == &e100_driver) { if(pci_dev_driver(pdev) == &e100_driver) {
netdev = pci_get_drvdata(pdev);
/* If net_device struct is allocated? */ /* If net_device struct is allocated? */
if (netdev) { if (pci_get_drvdata(pdev))
bdp = netdev->priv; e100_suspend(pdev, 3);
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);
}
}
} }
} }
} }
...@@ -4178,7 +4205,6 @@ e100_suspend(struct pci_dev *pcid, u32 state) ...@@ -4178,7 +4205,6 @@ e100_suspend(struct pci_dev *pcid, u32 state)
/* If wol is enabled */ /* If wol is enabled */
if (bdp->wolopts) { if (bdp->wolopts) {
bdp->ip_lbytes = e100_get_ip_lbytes(netdev);
e100_do_wol(pcid, bdp); e100_do_wol(pcid, bdp);
pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */
pci_set_power_state(pcid, 3); /* Set power state to D3. */ pci_set_power_state(pcid, 3); /* Set power state to D3. */
...@@ -4187,7 +4213,6 @@ e100_suspend(struct pci_dev *pcid, u32 state) ...@@ -4187,7 +4213,6 @@ e100_suspend(struct pci_dev *pcid, u32 state)
pci_disable_device(pcid); pci_disable_device(pcid);
pci_set_power_state(pcid, state); pci_set_power_state(pcid, state);
} }
return 0; return 0;
} }
...@@ -4215,7 +4240,6 @@ e100_resume(struct pci_dev *pcid) ...@@ -4215,7 +4240,6 @@ e100_resume(struct pci_dev *pcid)
return 0; return 0;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static void static void
......
...@@ -45,11 +45,12 @@ void e100_handle_zlock(struct e100_private *bdp); ...@@ -45,11 +45,12 @@ void e100_handle_zlock(struct e100_private *bdp);
* Returns: * Returns:
* NOTHING * NOTHING
*/ */
void int
e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
{ {
int e100_retry; int e100_retry;
u32 temp_val; u32 temp_val;
unsigned int mdi_cntrl;
spin_lock_bh(&bdp->mdi_access_lock); spin_lock_bh(&bdp->mdi_access_lock);
temp_val = (((u32) data) | (reg_addr << 16) | 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) ...@@ -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 */ /* poll for the mdi write to complete */
e100_retry = E100_CMD_WAIT; e100_retry = E100_CMD_WAIT;
while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
(e100_retry)) {
udelay(20); udelay(20);
e100_retry--; e100_retry--;
} }
spin_unlock_bh(&bdp->mdi_access_lock); 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) ...@@ -90,11 +96,12 @@ e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
* Returns: * Returns:
* NOTHING * NOTHING
*/ */
void int
e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
{ {
int e100_retry; int e100_retry;
u32 temp_val; u32 temp_val;
unsigned int mdi_cntrl;
spin_lock_bh(&bdp->mdi_access_lock); spin_lock_bh(&bdp->mdi_access_lock);
/* Issue the read command to the MDI control register. */ /* 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) ...@@ -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 */ /* poll for the mdi read to complete */
e100_retry = E100_CMD_WAIT; e100_retry = E100_CMD_WAIT;
while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) && while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
(e100_retry)) {
udelay(20); udelay(20);
e100_retry--; e100_retry--;
} }
// return the lower word
*data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
spin_unlock_bh(&bdp->mdi_access_lock); 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 static unsigned char __devinit
...@@ -480,10 +493,8 @@ e100_find_speed_duplex(struct e100_private *bdp) ...@@ -480,10 +493,8 @@ e100_find_speed_duplex(struct e100_private *bdp)
/* First we should check to see if we have link */ /* 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 we don't have a link no reason to print a speed and duplex */
if (!e100_update_link_state(bdp)) { if (!e100_update_link_state(bdp)) {
return; bdp->cur_line_speed = 0;
} bdp->cur_dplx_mode = 0;
if (bdp->flags & DF_SPEED_FORCED) {
return; return;
} }
...@@ -617,10 +628,13 @@ e100_force_speed_duplex(struct e100_private *bdp) ...@@ -617,10 +628,13 @@ e100_force_speed_duplex(struct e100_private *bdp)
u16 control; u16 control;
unsigned long expires; unsigned long expires;
e100_phy_reset(bdp);
bdp->flags |= DF_SPEED_FORCED; bdp->flags |= DF_SPEED_FORCED;
e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
control &= ~BMCR_ANENABLE; control &= ~BMCR_ANENABLE;
control &= ~BMCR_LOOPBACK;
/* Check e100.c values */ /* Check e100.c values */
switch (bdp->params.e100_speed_duplex) { switch (bdp->params.e100_speed_duplex) {
...@@ -838,7 +852,7 @@ e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart) ...@@ -838,7 +852,7 @@ e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
} }
void void
e100_phy_reset(struct e100_private *bdp) e100_phy_autoneg(struct e100_private *bdp)
{ {
u16 ctrl_reg; u16 ctrl_reg;
...@@ -849,6 +863,23 @@ e100_phy_reset(struct e100_private *bdp) ...@@ -849,6 +863,23 @@ e100_phy_reset(struct e100_private *bdp)
udelay(100); 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 unsigned char __devinit
e100_phy_init(struct e100_private *bdp) e100_phy_init(struct e100_private *bdp)
{ {
...@@ -915,7 +946,8 @@ e100_get_link_state(struct e100_private *bdp) ...@@ -915,7 +946,8 @@ e100_get_link_state(struct e100_private *bdp)
/* /*
* Procedure: e100_update_link_state * 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 * Arguments: bdp - Pointer to the e100_private structure for the board
* *
...@@ -929,7 +961,8 @@ e100_update_link_state(struct e100_private *bdp) ...@@ -929,7 +961,8 @@ e100_update_link_state(struct e100_private *bdp)
{ {
unsigned char link; 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 (link) {
if (!netif_carrier_ok(bdp->device)) if (!netif_carrier_ok(bdp->device))
......
...@@ -151,8 +151,10 @@ extern unsigned char e100_update_link_state(struct e100_private *bdp); ...@@ -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 unsigned char e100_phy_check(struct e100_private *bdp);
extern void e100_phy_set_speed_duplex(struct e100_private *bdp, extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
unsigned char force_restart); 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_phy_reset(struct e100_private *bdp);
extern void e100_mdi_write(struct e100_private *, u32, u32, u16); extern void e100_phy_set_loopback(struct e100_private *bdp);
extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *); extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *);
#endif #endif
...@@ -61,7 +61,7 @@ extern char e100_short_driver_name[]; ...@@ -61,7 +61,7 @@ extern char e100_short_driver_name[];
extern char e100_driver_version[]; extern char e100_driver_version[];
extern struct net_device_stats *e100_get_stats(struct net_device *dev); extern struct net_device_stats *e100_get_stats(struct net_device *dev);
extern char *e100_get_brand_msg(struct e100_private *bdp); 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 void e100_proc_cleanup(void);
static unsigned char e100_init_proc_dir(void); static unsigned char e100_init_proc_dir(void);
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
extern u16 e100_eeprom_read(struct e100_private *, u16); extern u16 e100_eeprom_read(struct e100_private *, u16);
extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8); extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
extern void e100_phy_reset(struct e100_private *bdp); 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_selftest(struct net_device *);
static u8 e100_diag_eeprom(struct net_device *); static u8 e100_diag_eeprom(struct net_device *);
...@@ -239,6 +242,7 @@ e100_diag_config_loopback(struct e100_private* bdp, ...@@ -239,6 +242,7 @@ e100_diag_config_loopback(struct e100_private* bdp,
*dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
if (set_loopback) { if (set_loopback) {
/* Configure loopback on MAC */
e100_config_loopback_mode(bdp,loopback_mode); e100_config_loopback_mode(bdp,loopback_mode);
} else { } else {
e100_config_loopback_mode(bdp,NO_LOOPBACK); e100_config_loopback_mode(bdp,NO_LOOPBACK);
...@@ -247,16 +251,20 @@ e100_diag_config_loopback(struct e100_private* bdp, ...@@ -247,16 +251,20 @@ e100_diag_config_loopback(struct e100_private* bdp,
e100_config(bdp); e100_config(bdp);
if (loopback_mode == PHY_LOOPBACK) { if (loopback_mode == PHY_LOOPBACK) {
unsigned long expires = jiffies + HZ * 5;
if (set_loopback) if (set_loopback)
e100_phy_reset(bdp); /* Set PHY loopback mode */
e100_phy_set_loopback(bdp);
/* wait up to 5 secs for PHY loopback ON/OFF to take effect */ else { /* Back to normal speed and duplex */
while ((e100_get_link_state(bdp) != set_loopback) && if (bdp->params.e100_speed_duplex == E100_AUTONEG)
time_before(jiffies, expires)) { /* Reset PHY and do autoneg */
yield(); 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 */ } else { /* For MAC loopback wait 500 msec to take effect */
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 2); schedule_timeout(HZ / 2);
...@@ -276,6 +284,7 @@ e100_diag_loopback_alloc(struct e100_private *bdp) ...@@ -276,6 +284,7 @@ e100_diag_loopback_alloc(struct e100_private *bdp)
rfd_t *rfd; rfd_t *rfd;
tbd_t *tbd; tbd_t *tbd;
/* tcb, tbd and transmit buffer are allocated */
tcb = pci_alloc_consistent(bdp->pdev, tcb = pci_alloc_consistent(bdp->pdev,
(sizeof (tcb_t) + sizeof (tbd_t) + (sizeof (tcb_t) + sizeof (tbd_t) +
LB_PACKET_SIZE), LB_PACKET_SIZE),
...@@ -283,22 +292,26 @@ e100_diag_loopback_alloc(struct e100_private *bdp) ...@@ -283,22 +292,26 @@ e100_diag_loopback_alloc(struct e100_private *bdp)
if (tcb == NULL) if (tcb == NULL)
return false; 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_phys = dma_handle;
tcb->tcb_hdr.cb_status = 0; tcb->tcb_hdr.cb_status = 0;
tcb->tcb_hdr.cb_cmd = tcb->tcb_hdr.cb_cmd =
cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys); /* Next command is null */
tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff); tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff);
tcb->tcb_cnt = 0; tcb->tcb_cnt = 0;
tcb->tcb_thrshld = bdp->tx_thld; tcb->tcb_thrshld = bdp->tx_thld;
tcb->tcb_tbd_num = 1; tcb->tcb_tbd_num = 1;
/* Set up tcb tbd pointer */
tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
/* Set up tbd transmit buffer */
tbd->tbd_buf_addr = tbd->tbd_buf_addr =
cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); 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); memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
wmb(); wmb();
rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
...@@ -313,10 +326,9 @@ e100_diag_loopback_alloc(struct e100_private *bdp) ...@@ -313,10 +326,9 @@ e100_diag_loopback_alloc(struct e100_private *bdp)
memset(rfd, 0x00, sizeof (rfd_t)); memset(rfd, 0x00, sizeof (rfd_t));
/* init all fields in rfd */ /* init all fields in rfd */
rfd->rfd_header.cb_status = 0;
rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); 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); 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.dma_handle = dma_handle;
bdp->loopback.tcb = tcb; bdp->loopback.tcb = tcb;
bdp->loopback.rfd = rfd; bdp->loopback.rfd = rfd;
...@@ -354,12 +366,15 @@ e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) ...@@ -354,12 +366,15 @@ e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
static u8 static u8
e100_diag_check_pkt(u8 *datap) e100_diag_check_pkt(u8 *datap)
{ {
if( (*datap)==0xFF) { int i;
if(*(datap + 600) == 0xBA) { for (i = 0; i<512; i++) {
return true; 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) ...@@ -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)); return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
else }
else {
printk(KERN_ERR "e100: Loopback packet not received\n");
return false; 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