This patch fixes the nic initialization. If the nic was in low power
mode, it brings it back to normal power. Also, it utilizes a new
hardware reset during the init.
I am resending based on feedback, I corrected the register size mapping
and delay after posted write.
Signed-Off-By: Ayaz Abdulla <[EMAIL PROTECTED]>
------------------------------------------------------------------------
--- orig-2.6/drivers/net/forcedeth.c 2006-04-04 14:14:16.000000000 -0400
+++ new-2.6/drivers/net/forcedeth.c 2006-04-04 14:26:44.000000000 -0400
@@ -107,6 +107,7 @@
* 0.52: 20 Jan 2006: Add MSI/MSIX support.
* 0.53: 20 Jan 2006: Add flow control (pause frame).
* 0.54: 20 Jan 2006: Additional ethtool and moduleparam support.
+ * 0.55: 19 Mar 2006: Fix init from low power mode and add hw reset.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -118,7 +119,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.54"
+#define FORCEDETH_VERSION "0.55"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -165,6 +166,7 @@
#define DEV_HAS_PAUSEFRAME_TX 0x0100 /* device supports tx pause frames */
#define DEV_HAS_STATISTICS 0x0200 /* device supports hw statistics */
#define DEV_HAS_TEST_EXTENDED 0x0400 /* device supports extended diagnostic
test */
+#define DEV_HAS_POWER_CNTRL 0x0800 /* device supports power savings */
enum {
NvRegIrqStatus = 0x000,
@@ -209,6 +211,8 @@
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
+ NvRegMacReset = 0x3c,
+#define NVREG_MAC_RESET_ASSERT 0x0F3
NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START 0x01
NvRegTransmitterStatus = 0x088,
@@ -365,6 +369,10 @@
NvRegMSIXMap0 = 0x3e0,
NvRegMSIXMap1 = 0x3e4,
NvRegMSIXIrqStatus = 0x3f0,
+
+ NvRegPowerState2 = 0x600,
+#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11
+#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
};
/* Big endian: should work, but is untested */
@@ -453,7 +461,8 @@
#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF)
/* Miscelaneous hardware related defines: */
-#define NV_PCI_REGSZ 0x270
+#define NV_PCI_REGSZ_VER1 0x270
+#define NV_PCI_REGSZ_VER2 0x600
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -470,6 +479,7 @@
#define NV_MIIBUSY_DELAY 50
#define NV_MIIPHY_DELAY 10
#define NV_MIIPHY_DELAYMAX 10000
+#define NV_MAC_RESET_DELAY 64
#define NV_WAKEUPPATTERNS 5
#define NV_WAKEUPMASKENTRIES 4
@@ -700,6 +710,7 @@
u32 txrxctl_bits;
u32 vlanctl_bits;
u32 driver_data;
+ u32 register_size;
void __iomem *base;
@@ -1314,6 +1325,24 @@
pci_push(base);
}
+static void nv_mac_reset(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits,
base + NvRegTxRxControl);
+ pci_push(base);
+ writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
+ pci_push(base);
+ udelay(NV_MAC_RESET_DELAY);
+ writel(0, base + NvRegMacReset);
+ pci_push(base);
+ udelay(NV_MAC_RESET_DELAY);
+ writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
+ pci_push(base);
+}
+
/*
* nv_get_stats: dev->get_stats function
* Get latest stats value from the nic.
@@ -1726,7 +1755,7 @@
dev->name, (unsigned long)np->ring_addr,
np->next_tx, np->nic_tx);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
- for (i=0;i<0x400;i+= 32) {
+ for (i=0;i<=np->register_size;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x
%08x\n",
i,
readl(base + i + 0), readl(base + i +
4),
@@ -3202,11 +3231,11 @@
}
#define FORCEDETH_REGS_VER 1
-#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */
static int nv_get_regs_len(struct net_device *dev)
{
- return FORCEDETH_REGS_SIZE;
+ struct fe_priv *np = netdev_priv(dev);
+ return np->register_size;
}
static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
@@ -3218,7 +3247,7 @@
regs->version = FORCEDETH_REGS_VER;
spin_lock_irq(&np->lock);
- for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
+ for (i = 0;i <= np->register_size/sizeof(u32); i++)
rbuf[i] = readl(base + i*sizeof(u32));
spin_unlock_irq(&np->lock);
}
@@ -3979,6 +4008,8 @@
dprintk(KERN_DEBUG "nv_open: begin\n");
/* 1) erase previous misconfiguration */
+ if (np->driver_data & DEV_HAS_POWER_CNTRL)
+ nv_mac_reset(dev);
/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
@@ -4171,6 +4202,7 @@
unsigned long addr;
u8 __iomem *base;
int err, i;
+ u32 powerstate;
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -4206,6 +4238,11 @@
if (err < 0)
goto out_disable;
+ if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_STATISTICS|DEV_HAS_POWER_CNTRL))
+ np->register_size = NV_PCI_REGSZ_VER2;
+ else
+ np->register_size = NV_PCI_REGSZ_VER1;
+
err = -EINVAL;
addr = 0;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -4214,7 +4251,7 @@
pci_resource_len(pci_dev, i),
pci_resource_flags(pci_dev, i));
if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
- pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) {
+ pci_resource_len(pci_dev, i) >=
np->register_size) {
addr = pci_resource_start(pci_dev, i);
break;
}
@@ -4315,7 +4352,7 @@
np->pause_flags |= NV_PAUSEFRAME_AUTONEG;
err = -ENOMEM;
- np->base = ioremap(addr, NV_PCI_REGSZ);
+ np->base = ioremap(addr, np->register_size);
if (!np->base)
goto out_relreg;
dev->base_addr = (unsigned long)np->base;
@@ -4431,6 +4468,20 @@
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = wol;
+ if (id->driver_data & DEV_HAS_POWER_CNTRL) {
+ u8 revision_id;
+ pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id);
+
+ /* take phy and nic out of low power mode */
+ powerstate = readl(base + NvRegPowerState2);
+ powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
+ if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+ id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) &&
+ revision_id >= 0xA3)
+ powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
+ writel(powerstate, base + NvRegPowerState2);
+ }
+
if (np->desc_ver == DESC_VER_1) {
np->tx_flags = NV_TX_VALID;
} else {
@@ -4584,19 +4635,19 @@
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NVENET_12),
- .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+ .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NVENET_13),
- .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+ .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_POWER_CNTRL,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ .driver_data =
DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_POWER_CNTRL,
},
{0,},
};