|
@@ -234,6 +234,7 @@ enum {
|
|
|
#define NVREG_XMITCTL_HOST_SEMA_MASK 0x0000f000
|
|
|
#define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000
|
|
|
#define NVREG_XMITCTL_HOST_LOADED 0x00004000
|
|
|
+#define NVREG_XMITCTL_TX_PATH_EN 0x01000000
|
|
|
NvRegTransmitterStatus = 0x088,
|
|
|
#define NVREG_XMITSTAT_BUSY 0x01
|
|
|
|
|
@@ -249,6 +250,7 @@ enum {
|
|
|
#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
|
|
|
NvRegReceiverControl = 0x094,
|
|
|
#define NVREG_RCVCTL_START 0x01
|
|
|
+#define NVREG_RCVCTL_RX_PATH_EN 0x01000000
|
|
|
NvRegReceiverStatus = 0x98,
|
|
|
#define NVREG_RCVSTAT_BUSY 0x01
|
|
|
|
|
@@ -1169,16 +1171,21 @@ static void nv_start_rx(struct net_device *dev)
|
|
|
{
|
|
|
struct fe_priv *np = netdev_priv(dev);
|
|
|
u8 __iomem *base = get_hwbase(dev);
|
|
|
+ u32 rx_ctrl = readl(base + NvRegReceiverControl);
|
|
|
|
|
|
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
|
|
|
/* Already running? Stop it. */
|
|
|
- if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
|
|
|
- writel(0, base + NvRegReceiverControl);
|
|
|
+ if ((readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) && !np->mac_in_use) {
|
|
|
+ rx_ctrl &= ~NVREG_RCVCTL_START;
|
|
|
+ writel(rx_ctrl, base + NvRegReceiverControl);
|
|
|
pci_push(base);
|
|
|
}
|
|
|
writel(np->linkspeed, base + NvRegLinkSpeed);
|
|
|
pci_push(base);
|
|
|
- writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);
|
|
|
+ rx_ctrl |= NVREG_RCVCTL_START;
|
|
|
+ if (np->mac_in_use)
|
|
|
+ rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN;
|
|
|
+ writel(rx_ctrl, base + NvRegReceiverControl);
|
|
|
dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n",
|
|
|
dev->name, np->duplex, np->linkspeed);
|
|
|
pci_push(base);
|
|
@@ -1186,39 +1193,59 @@ static void nv_start_rx(struct net_device *dev)
|
|
|
|
|
|
static void nv_stop_rx(struct net_device *dev)
|
|
|
{
|
|
|
+ struct fe_priv *np = netdev_priv(dev);
|
|
|
u8 __iomem *base = get_hwbase(dev);
|
|
|
+ u32 rx_ctrl = readl(base + NvRegReceiverControl);
|
|
|
|
|
|
dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
|
|
|
- writel(0, base + NvRegReceiverControl);
|
|
|
+ if (!np->mac_in_use)
|
|
|
+ rx_ctrl &= ~NVREG_RCVCTL_START;
|
|
|
+ else
|
|
|
+ rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN;
|
|
|
+ writel(rx_ctrl, base + NvRegReceiverControl);
|
|
|
reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
|
|
|
NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
|
|
|
KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
|
|
|
|
|
|
udelay(NV_RXSTOP_DELAY2);
|
|
|
- writel(0, base + NvRegLinkSpeed);
|
|
|
+ if (!np->mac_in_use)
|
|
|
+ writel(0, base + NvRegLinkSpeed);
|
|
|
}
|
|
|
|
|
|
static void nv_start_tx(struct net_device *dev)
|
|
|
{
|
|
|
+ struct fe_priv *np = netdev_priv(dev);
|
|
|
u8 __iomem *base = get_hwbase(dev);
|
|
|
+ u32 tx_ctrl = readl(base + NvRegTransmitterControl);
|
|
|
|
|
|
dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
|
|
|
- writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
|
|
|
+ tx_ctrl |= NVREG_XMITCTL_START;
|
|
|
+ if (np->mac_in_use)
|
|
|
+ tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN;
|
|
|
+ writel(tx_ctrl, base + NvRegTransmitterControl);
|
|
|
pci_push(base);
|
|
|
}
|
|
|
|
|
|
static void nv_stop_tx(struct net_device *dev)
|
|
|
{
|
|
|
+ struct fe_priv *np = netdev_priv(dev);
|
|
|
u8 __iomem *base = get_hwbase(dev);
|
|
|
+ u32 tx_ctrl = readl(base + NvRegTransmitterControl);
|
|
|
|
|
|
dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
|
|
|
- writel(0, base + NvRegTransmitterControl);
|
|
|
+ if (!np->mac_in_use)
|
|
|
+ tx_ctrl &= ~NVREG_XMITCTL_START;
|
|
|
+ else
|
|
|
+ tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN;
|
|
|
+ writel(tx_ctrl, base + NvRegTransmitterControl);
|
|
|
reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
|
|
|
NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
|
|
|
KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
|
|
|
|
|
|
udelay(NV_TXSTOP_DELAY2);
|
|
|
- writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
|
|
|
+ if (!np->mac_in_use)
|
|
|
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV,
|
|
|
+ base + NvRegTransmitPoll);
|
|
|
}
|
|
|
|
|
|
static void nv_txrx_reset(struct net_device *dev)
|
|
@@ -4148,20 +4175,6 @@ static int nv_mgmt_acquire_sema(struct net_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Indicate to mgmt unit whether driver is loaded or not */
|
|
|
-static void nv_mgmt_driver_loaded(struct net_device *dev, int loaded)
|
|
|
-{
|
|
|
- u8 __iomem *base = get_hwbase(dev);
|
|
|
- u32 tx_ctrl;
|
|
|
-
|
|
|
- tx_ctrl = readl(base + NvRegTransmitterControl);
|
|
|
- if (loaded)
|
|
|
- tx_ctrl |= NVREG_XMITCTL_HOST_LOADED;
|
|
|
- else
|
|
|
- tx_ctrl &= ~NVREG_XMITCTL_HOST_LOADED;
|
|
|
- writel(tx_ctrl, base + NvRegTransmitterControl);
|
|
|
-}
|
|
|
-
|
|
|
static int nv_open(struct net_device *dev)
|
|
|
{
|
|
|
struct fe_priv *np = netdev_priv(dev);
|
|
@@ -4659,33 +4672,24 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|
|
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
|
|
|
|
|
|
if (id->driver_data & DEV_HAS_MGMT_UNIT) {
|
|
|
- writel(0x1, base + 0x204); pci_push(base);
|
|
|
- msleep(500);
|
|
|
/* management unit running on the mac? */
|
|
|
- np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST;
|
|
|
- if (np->mac_in_use) {
|
|
|
- u32 mgmt_sync;
|
|
|
- /* management unit setup the phy already? */
|
|
|
- mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK;
|
|
|
- if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY) {
|
|
|
- if (!nv_mgmt_acquire_sema(dev)) {
|
|
|
- for (i = 0; i < 5000; i++) {
|
|
|
- msleep(1);
|
|
|
- mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK;
|
|
|
- if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY)
|
|
|
- continue;
|
|
|
- if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT)
|
|
|
- phyinitialized = 1;
|
|
|
- break;
|
|
|
+ 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);
|
|
|
+ for (i = 0; i < 5000; i++) {
|
|
|
+ msleep(1);
|
|
|
+ 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 */
|
|
|
}
|
|
|
- } else {
|
|
|
- /* we need to init the phy */
|
|
|
+ break;
|
|
|
}
|
|
|
- } else if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT) {
|
|
|
- /* phy is inited by SMU */
|
|
|
- phyinitialized = 1;
|
|
|
- } else {
|
|
|
- /* we need to init the phy */
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -4724,10 +4728,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|
|
if (!phyinitialized) {
|
|
|
/* reset it */
|
|
|
phy_init(dev);
|
|
|
- }
|
|
|
-
|
|
|
- if (id->driver_data & DEV_HAS_MGMT_UNIT) {
|
|
|
- nv_mgmt_driver_loaded(dev, 1);
|
|
|
+ } else {
|
|
|
+ /* see if it is a gigabit phy */
|
|
|
+ u32 mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
|
|
|
+ if (mii_status & PHY_GIGABIT) {
|
|
|
+ np->gigabit = PHY_GIGABIT;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* set default link speed settings */
|
|
@@ -4749,8 +4755,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|
|
out_error:
|
|
|
if (phystate_orig)
|
|
|
writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
|
|
|
- if (np->mac_in_use)
|
|
|
- nv_mgmt_driver_loaded(dev, 0);
|
|
|
pci_set_drvdata(pci_dev, NULL);
|
|
|
out_freering:
|
|
|
free_rings(dev);
|
|
@@ -4780,9 +4784,6 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
|
|
|
writel(np->orig_mac[0], base + NvRegMacAddrA);
|
|
|
writel(np->orig_mac[1], base + NvRegMacAddrB);
|
|
|
|
|
|
- if (np->mac_in_use)
|
|
|
- nv_mgmt_driver_loaded(dev, 0);
|
|
|
-
|
|
|
/* free all structures */
|
|
|
free_rings(dev);
|
|
|
iounmap(get_hwbase(dev));
|