diff options
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 36342230a6de..d4843d014bc9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -323,8 +323,8 @@ enum { | |||
323 | NvRegMIIStatus = 0x180, | 323 | NvRegMIIStatus = 0x180, |
324 | #define NVREG_MIISTAT_ERROR 0x0001 | 324 | #define NVREG_MIISTAT_ERROR 0x0001 |
325 | #define NVREG_MIISTAT_LINKCHANGE 0x0008 | 325 | #define NVREG_MIISTAT_LINKCHANGE 0x0008 |
326 | #define NVREG_MIISTAT_MASK 0x000f | 326 | #define NVREG_MIISTAT_MASK_RW 0x0007 |
327 | #define NVREG_MIISTAT_MASK2 0x000f | 327 | #define NVREG_MIISTAT_MASK_ALL 0x000f |
328 | NvRegMIIMask = 0x184, | 328 | NvRegMIIMask = 0x184, |
329 | #define NVREG_MII_LINKCHANGE 0x0008 | 329 | #define NVREG_MII_LINKCHANGE 0x0008 |
330 | 330 | ||
@@ -624,6 +624,9 @@ union ring_type { | |||
624 | #define NV_MSI_X_VECTOR_TX 0x1 | 624 | #define NV_MSI_X_VECTOR_TX 0x1 |
625 | #define NV_MSI_X_VECTOR_OTHER 0x2 | 625 | #define NV_MSI_X_VECTOR_OTHER 0x2 |
626 | 626 | ||
627 | #define NV_RESTART_TX 0x1 | ||
628 | #define NV_RESTART_RX 0x2 | ||
629 | |||
627 | /* statistics */ | 630 | /* statistics */ |
628 | struct nv_ethtool_str { | 631 | struct nv_ethtool_str { |
629 | char name[ETH_GSTRING_LEN]; | 632 | char name[ETH_GSTRING_LEN]; |
@@ -1061,7 +1064,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) | |||
1061 | u32 reg; | 1064 | u32 reg; |
1062 | int retval; | 1065 | int retval; |
1063 | 1066 | ||
1064 | writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); | 1067 | writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus); |
1065 | 1068 | ||
1066 | reg = readl(base + NvRegMIIControl); | 1069 | reg = readl(base + NvRegMIIControl); |
1067 | if (reg & NVREG_MIICTL_INUSE) { | 1070 | if (reg & NVREG_MIICTL_INUSE) { |
@@ -1432,16 +1435,30 @@ static void nv_mac_reset(struct net_device *dev) | |||
1432 | { | 1435 | { |
1433 | struct fe_priv *np = netdev_priv(dev); | 1436 | struct fe_priv *np = netdev_priv(dev); |
1434 | u8 __iomem *base = get_hwbase(dev); | 1437 | u8 __iomem *base = get_hwbase(dev); |
1438 | u32 temp1, temp2, temp3; | ||
1435 | 1439 | ||
1436 | dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name); | 1440 | dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name); |
1441 | |||
1437 | writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); | 1442 | writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); |
1438 | pci_push(base); | 1443 | pci_push(base); |
1444 | |||
1445 | /* save registers since they will be cleared on reset */ | ||
1446 | temp1 = readl(base + NvRegMacAddrA); | ||
1447 | temp2 = readl(base + NvRegMacAddrB); | ||
1448 | temp3 = readl(base + NvRegTransmitPoll); | ||
1449 | |||
1439 | writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset); | 1450 | writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset); |
1440 | pci_push(base); | 1451 | pci_push(base); |
1441 | udelay(NV_MAC_RESET_DELAY); | 1452 | udelay(NV_MAC_RESET_DELAY); |
1442 | writel(0, base + NvRegMacReset); | 1453 | writel(0, base + NvRegMacReset); |
1443 | pci_push(base); | 1454 | pci_push(base); |
1444 | udelay(NV_MAC_RESET_DELAY); | 1455 | udelay(NV_MAC_RESET_DELAY); |
1456 | |||
1457 | /* restore saved registers */ | ||
1458 | writel(temp1, base + NvRegMacAddrA); | ||
1459 | writel(temp2, base + NvRegMacAddrB); | ||
1460 | writel(temp3, base + NvRegTransmitPoll); | ||
1461 | |||
1445 | writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); | 1462 | writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); |
1446 | pci_push(base); | 1463 | pci_push(base); |
1447 | } | 1464 | } |
@@ -2767,6 +2784,7 @@ static int nv_update_linkspeed(struct net_device *dev) | |||
2767 | int mii_status; | 2784 | int mii_status; |
2768 | int retval = 0; | 2785 | int retval = 0; |
2769 | u32 control_1000, status_1000, phyreg, pause_flags, txreg; | 2786 | u32 control_1000, status_1000, phyreg, pause_flags, txreg; |
2787 | u32 txrxFlags = 0; | ||
2770 | 2788 | ||
2771 | /* BMSR_LSTATUS is latched, read it twice: | 2789 | /* BMSR_LSTATUS is latched, read it twice: |
2772 | * we want the current value. | 2790 | * we want the current value. |
@@ -2862,6 +2880,16 @@ set_speed: | |||
2862 | np->duplex = newdup; | 2880 | np->duplex = newdup; |
2863 | np->linkspeed = newls; | 2881 | np->linkspeed = newls; |
2864 | 2882 | ||
2883 | /* The transmitter and receiver must be restarted for safe update */ | ||
2884 | if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) { | ||
2885 | txrxFlags |= NV_RESTART_TX; | ||
2886 | nv_stop_tx(dev); | ||
2887 | } | ||
2888 | if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { | ||
2889 | txrxFlags |= NV_RESTART_RX; | ||
2890 | nv_stop_rx(dev); | ||
2891 | } | ||
2892 | |||
2865 | if (np->gigabit == PHY_GIGABIT) { | 2893 | if (np->gigabit == PHY_GIGABIT) { |
2866 | phyreg = readl(base + NvRegRandomSeed); | 2894 | phyreg = readl(base + NvRegRandomSeed); |
2867 | phyreg &= ~(0x3FF00); | 2895 | phyreg &= ~(0x3FF00); |
@@ -2950,6 +2978,11 @@ set_speed: | |||
2950 | } | 2978 | } |
2951 | nv_update_pause(dev, pause_flags); | 2979 | nv_update_pause(dev, pause_flags); |
2952 | 2980 | ||
2981 | if (txrxFlags & NV_RESTART_TX) | ||
2982 | nv_start_tx(dev); | ||
2983 | if (txrxFlags & NV_RESTART_RX) | ||
2984 | nv_start_rx(dev); | ||
2985 | |||
2953 | return retval; | 2986 | return retval; |
2954 | } | 2987 | } |
2955 | 2988 | ||
@@ -2976,7 +3009,7 @@ static void nv_link_irq(struct net_device *dev) | |||
2976 | u32 miistat; | 3009 | u32 miistat; |
2977 | 3010 | ||
2978 | miistat = readl(base + NvRegMIIStatus); | 3011 | miistat = readl(base + NvRegMIIStatus); |
2979 | writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); | 3012 | writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus); |
2980 | dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat); | 3013 | dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat); |
2981 | 3014 | ||
2982 | if (miistat & (NVREG_MIISTAT_LINKCHANGE)) | 3015 | if (miistat & (NVREG_MIISTAT_LINKCHANGE)) |
@@ -4851,7 +4884,7 @@ static int nv_open(struct net_device *dev) | |||
4851 | 4884 | ||
4852 | writel(0, base + NvRegMIIMask); | 4885 | writel(0, base + NvRegMIIMask); |
4853 | writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); | 4886 | writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); |
4854 | writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); | 4887 | writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); |
4855 | 4888 | ||
4856 | writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); | 4889 | writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); |
4857 | writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); | 4890 | writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); |
@@ -4889,7 +4922,7 @@ static int nv_open(struct net_device *dev) | |||
4889 | 4922 | ||
4890 | nv_disable_hw_interrupts(dev, np->irqmask); | 4923 | nv_disable_hw_interrupts(dev, np->irqmask); |
4891 | pci_push(base); | 4924 | pci_push(base); |
4892 | writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); | 4925 | writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); |
4893 | writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); | 4926 | writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); |
4894 | pci_push(base); | 4927 | pci_push(base); |
4895 | 4928 | ||
@@ -4912,7 +4945,7 @@ static int nv_open(struct net_device *dev) | |||
4912 | { | 4945 | { |
4913 | u32 miistat; | 4946 | u32 miistat; |
4914 | miistat = readl(base + NvRegMIIStatus); | 4947 | miistat = readl(base + NvRegMIIStatus); |
4915 | writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); | 4948 | writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); |
4916 | dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); | 4949 | dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); |
4917 | } | 4950 | } |
4918 | /* set linkspeed to invalid value, thus force nv_update_linkspeed | 4951 | /* set linkspeed to invalid value, thus force nv_update_linkspeed |
@@ -5280,7 +5313,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5280 | phystate &= ~NVREG_ADAPTCTL_RUNNING; | 5313 | phystate &= ~NVREG_ADAPTCTL_RUNNING; |
5281 | writel(phystate, base + NvRegAdapterControl); | 5314 | writel(phystate, base + NvRegAdapterControl); |
5282 | } | 5315 | } |
5283 | writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); | 5316 | writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); |
5284 | 5317 | ||
5285 | if (id->driver_data & DEV_HAS_MGMT_UNIT) { | 5318 | if (id->driver_data & DEV_HAS_MGMT_UNIT) { |
5286 | /* management unit running on the mac? */ | 5319 | /* management unit running on the mac? */ |