Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cac1c52c authored by Ayaz Abdulla's avatar Ayaz Abdulla Committed by David S. Miller
Browse files

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: default avatarAyaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1f0fa154
Loading
Loading
Loading
Loading
+82 −16
Original line number Diff line number Diff line
@@ -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,22 +5841,29 @@ 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)) {
		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 ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) ==
				    NVREG_XMITCTL_SYNC_PHY_INIT) {
			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));
				dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n",
					pci_name(pci_dev));
			} else {
				/* we need to init the phy */
			}
		}
	}
	}

	/* find a suitable phy */
	for (i = 1; i <= 32; i++) {
@@ -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));