forcedeth: mgmt unit interface

This patch updates the logic used to communicate with the mgmt unit. It
also adds a version check for a newer mgmt unit firmware.

* Fixed udelay to schedule_timeout_uninterruptible

Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Ayaz Abdulla 2009-02-07 00:23:57 -08:00 committed by David S. Miller
parent 1f0fa15432
commit cac1c52c36
1 changed files with 82 additions and 16 deletions

View File

@ -157,6 +157,9 @@ enum {
#define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000
#define NVREG_XMITCTL_HOST_LOADED 0x00004000
#define NVREG_XMITCTL_TX_PATH_EN 0x01000000
#define NVREG_XMITCTL_DATA_START 0x00100000
#define NVREG_XMITCTL_DATA_READY 0x00010000
#define NVREG_XMITCTL_DATA_ERROR 0x00020000
NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY 0x01
@ -289,8 +292,10 @@ enum {
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
NvRegMgmtUnitGetVersion = 0x204,
#define NVREG_MGMTUNITGETVERSION 0x01
NvRegMgmtUnitVersion = 0x208,
#define NVREG_MGMTUNITVERSION 0x08
NvRegPowerCap = 0x268,
#define NVREG_POWERCAP_D3SUPP (1<<30)
#define NVREG_POWERCAP_D2SUPP (1<<26)
@ -303,6 +308,8 @@ enum {
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
NvRegMgmtUnitControl = 0x278,
#define NVREG_MGMTUNITCONTROL_INUSE 0x20000
NvRegTxCnt = 0x280,
NvRegTxZeroReXmt = 0x284,
NvRegTxOneReXmt = 0x288,
@ -758,6 +765,8 @@ struct fe_priv {
u32 register_size;
int rx_csum;
u32 mac_in_use;
int mgmt_version;
int mgmt_sema;
void __iomem *base;
@ -5182,6 +5191,7 @@ static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
/* The mgmt unit and driver use a semaphore to access the phy during init */
static int nv_mgmt_acquire_sema(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int i;
u32 tx_ctrl, mgmt_sema;
@ -5204,8 +5214,10 @@ static int nv_mgmt_acquire_sema(struct net_device *dev)
/* verify that semaphore was acquired */
tx_ctrl = readl(base + NvRegTransmitterControl);
if (((tx_ctrl & NVREG_XMITCTL_HOST_SEMA_MASK) == NVREG_XMITCTL_HOST_SEMA_ACQ) &&
((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE))
((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) {
np->mgmt_sema = 1;
return 1;
}
else
udelay(50);
}
@ -5213,6 +5225,51 @@ static int nv_mgmt_acquire_sema(struct net_device *dev)
return 0;
}
static void nv_mgmt_release_sema(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 tx_ctrl;
if (np->driver_data & DEV_HAS_MGMT_UNIT) {
if (np->mgmt_sema) {
tx_ctrl = readl(base + NvRegTransmitterControl);
tx_ctrl &= ~NVREG_XMITCTL_HOST_SEMA_ACQ;
writel(tx_ctrl, base + NvRegTransmitterControl);
}
}
}
static int nv_mgmt_get_version(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 data_ready = readl(base + NvRegTransmitterControl);
u32 data_ready2 = 0;
unsigned long start;
int ready = 0;
writel(NVREG_MGMTUNITGETVERSION, base + NvRegMgmtUnitGetVersion);
writel(data_ready ^ NVREG_XMITCTL_DATA_START, base + NvRegTransmitterControl);
start = jiffies;
while (time_before(jiffies, start + 5*HZ)) {
data_ready2 = readl(base + NvRegTransmitterControl);
if ((data_ready & NVREG_XMITCTL_DATA_READY) != (data_ready2 & NVREG_XMITCTL_DATA_READY)) {
ready = 1;
break;
}
schedule_timeout_uninterruptible(1);
}
if (!ready || (data_ready2 & NVREG_XMITCTL_DATA_ERROR))
return 0;
np->mgmt_version = readl(base + NvRegMgmtUnitVersion) & NVREG_MGMTUNITVERSION;
return 1;
}
static int nv_open(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
@ -5784,19 +5841,26 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id->driver_data & DEV_HAS_MGMT_UNIT) {
/* management unit running on the mac? */
if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) {
np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST;
dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", pci_name(pci_dev), np->mac_in_use);
if (nv_mgmt_acquire_sema(dev)) {
/* management unit setup the phy already? */
if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) ==
NVREG_XMITCTL_SYNC_PHY_INIT) {
/* phy is inited by mgmt unit */
phyinitialized = 1;
dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", pci_name(pci_dev));
} else {
/* we need to init the phy */
}
if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST) &&
(readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) &&
nv_mgmt_acquire_sema(dev) &&
nv_mgmt_get_version(dev)) {
np->mac_in_use = 1;
if (np->mgmt_version > 0) {
np->mac_in_use = readl(base + NvRegMgmtUnitControl) & NVREG_MGMTUNITCONTROL_INUSE;
}
dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n",
pci_name(pci_dev), np->mac_in_use);
/* management unit setup the phy already? */
if (np->mac_in_use &&
((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) ==
NVREG_XMITCTL_SYNC_PHY_INIT)) {
/* phy is inited by mgmt unit */
phyinitialized = 1;
dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n",
pci_name(pci_dev));
} else {
/* we need to init the phy */
}
}
}
@ -5958,6 +6022,8 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
/* restore any phy related changes */
nv_restore_phy(dev);
nv_mgmt_release_sema(dev);
/* free all structures */
free_rings(dev);
iounmap(get_hwbase(dev));