summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2008-04-11 06:30:35 +0200
committerJeff Garzik <jgarzik@redhat.com>2008-04-12 10:38:12 +0200
commita376e79c6079c2ba6c5fadb0e85a3bb7e465ad89 (patch)
treeb00f23487d23a93fe2cce93d5ad682deb27cbad9
parentmacb: Use semicolon instead of comma for statement (diff)
downloadlinux-a376e79c6079c2ba6c5fadb0e85a3bb7e465ad89.tar.xz
linux-a376e79c6079c2ba6c5fadb0e85a3bb7e465ad89.zip
forcedeth: mac address fix
This critical patch fixes a mac address issue recently introduced. If the device's mac address was in correct order and the flag NVREG_TRANSMITPOLL_MAC_ADDR_REV was set, during nv_remove the flag would get cleared. During next load, the mac address would get reversed because the flag is missing. As it has been indicated previously, the flag is cleared across a low power transition. Therefore, the driver should set the mac address back into the reversed order when clearing the flag. Also, the driver should set back the flag after a low power transition to protect against kexec command calling nv_probe a second time. Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com> Cc: "Yinghai Lu" <yhlu.kernel@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/net/forcedeth.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 419f533006ab..9f088a47d8b1 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -5316,8 +5316,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
/* check the workaround bit for correct mac address order */
txreg = readl(base + NvRegTransmitPoll);
- if ((txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) ||
- (id->driver_data & DEV_HAS_CORRECT_MACADDR)) {
+ if (id->driver_data & DEV_HAS_CORRECT_MACADDR) {
/* mac address is already in correct order */
dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
@@ -5325,6 +5324,22 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff;
dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff;
+ } else if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+ /* mac address is already in correct order */
+ dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
+ dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
+ dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
+ dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
+ dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff;
+ dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff;
+ /*
+ * Set orig mac address back to the reversed version.
+ * This flag will be cleared during low power transition.
+ * Therefore, we should always put back the reversed address.
+ */
+ np->orig_mac[0] = (dev->dev_addr[5] << 0) + (dev->dev_addr[4] << 8) +
+ (dev->dev_addr[3] << 16) + (dev->dev_addr[2] << 24);
+ np->orig_mac[1] = (dev->dev_addr[1] << 0) + (dev->dev_addr[0] << 8);
} else {
/* need to reverse mac address to correct order */
dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
@@ -5595,7 +5610,9 @@ out:
static int nv_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ u8 __iomem *base = get_hwbase(dev);
int rc = 0;
+ u32 txreg;
if (!netif_running(dev))
goto out;
@@ -5606,6 +5623,11 @@ static int nv_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D0, 0);
+ /* restore mac address reverse flag */
+ txreg = readl(base + NvRegTransmitPoll);
+ txreg |= NVREG_TRANSMITPOLL_MAC_ADDR_REV;
+ writel(txreg, base + NvRegTransmitPoll);
+
rc = nv_open(dev);
out:
return rc;