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:
parent
1f0fa15432
commit
cac1c52c36
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue