aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sungem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sungem.c')
-rw-r--r--drivers/net/sungem.c144
1 files changed, 88 insertions, 56 deletions
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 1349e419673c..fed7eba65ead 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1142,6 +1142,70 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
1142 return NETDEV_TX_OK; 1142 return NETDEV_TX_OK;
1143} 1143}
1144 1144
1145static void gem_pcs_reset(struct gem *gp)
1146{
1147 int limit;
1148 u32 val;
1149
1150 /* Reset PCS unit. */
1151 val = readl(gp->regs + PCS_MIICTRL);
1152 val |= PCS_MIICTRL_RST;
1153 writel(val, gp->regs + PCS_MIICTRL);
1154
1155 limit = 32;
1156 while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
1157 udelay(100);
1158 if (limit-- <= 0)
1159 break;
1160 }
1161 if (limit <= 0)
1162 printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
1163 gp->dev->name);
1164}
1165
1166static void gem_pcs_reinit_adv(struct gem *gp)
1167{
1168 u32 val;
1169
1170 /* Make sure PCS is disabled while changing advertisement
1171 * configuration.
1172 */
1173 val = readl(gp->regs + PCS_CFG);
1174 val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
1175 writel(val, gp->regs + PCS_CFG);
1176
1177 /* Advertise all capabilities except assymetric
1178 * pause.
1179 */
1180 val = readl(gp->regs + PCS_MIIADV);
1181 val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
1182 PCS_MIIADV_SP | PCS_MIIADV_AP);
1183 writel(val, gp->regs + PCS_MIIADV);
1184
1185 /* Enable and restart auto-negotiation, disable wrapback/loopback,
1186 * and re-enable PCS.
1187 */
1188 val = readl(gp->regs + PCS_MIICTRL);
1189 val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
1190 val &= ~PCS_MIICTRL_WB;
1191 writel(val, gp->regs + PCS_MIICTRL);
1192
1193 val = readl(gp->regs + PCS_CFG);
1194 val |= PCS_CFG_ENABLE;
1195 writel(val, gp->regs + PCS_CFG);
1196
1197 /* Make sure serialink loopback is off. The meaning
1198 * of this bit is logically inverted based upon whether
1199 * you are in Serialink or SERDES mode.
1200 */
1201 val = readl(gp->regs + PCS_SCTRL);
1202 if (gp->phy_type == phy_serialink)
1203 val &= ~PCS_SCTRL_LOOP;
1204 else
1205 val |= PCS_SCTRL_LOOP;
1206 writel(val, gp->regs + PCS_SCTRL);
1207}
1208
1145#define STOP_TRIES 32 1209#define STOP_TRIES 32
1146 1210
1147/* Must be invoked under gp->lock and gp->tx_lock. */ 1211/* Must be invoked under gp->lock and gp->tx_lock. */
@@ -1168,6 +1232,9 @@ static void gem_reset(struct gem *gp)
1168 1232
1169 if (limit <= 0) 1233 if (limit <= 0)
1170 printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); 1234 printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
1235
1236 if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes)
1237 gem_pcs_reinit_adv(gp);
1171} 1238}
1172 1239
1173/* Must be invoked under gp->lock and gp->tx_lock. */ 1240/* Must be invoked under gp->lock and gp->tx_lock. */
@@ -1324,7 +1391,7 @@ static int gem_set_link_modes(struct gem *gp)
1324 gp->phy_type == phy_serdes) { 1391 gp->phy_type == phy_serdes) {
1325 u32 pcs_lpa = readl(gp->regs + PCS_MIILP); 1392 u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
1326 1393
1327 if (pcs_lpa & PCS_MIIADV_FD) 1394 if ((pcs_lpa & PCS_MIIADV_FD) || gp->phy_type == phy_serdes)
1328 full_duplex = 1; 1395 full_duplex = 1;
1329 speed = SPEED_1000; 1396 speed = SPEED_1000;
1330 } 1397 }
@@ -1488,6 +1555,9 @@ static void gem_link_timer(unsigned long data)
1488 val = readl(gp->regs + PCS_MIISTAT); 1555 val = readl(gp->regs + PCS_MIISTAT);
1489 1556
1490 if ((val & PCS_MIISTAT_LS) != 0) { 1557 if ((val & PCS_MIISTAT_LS) != 0) {
1558 if (gp->lstate == link_up)
1559 goto restart;
1560
1491 gp->lstate = link_up; 1561 gp->lstate = link_up;
1492 netif_carrier_on(gp->dev); 1562 netif_carrier_on(gp->dev);
1493 (void)gem_set_link_modes(gp); 1563 (void)gem_set_link_modes(gp);
@@ -1708,61 +1778,8 @@ static void gem_init_phy(struct gem *gp)
1708 if (gp->phy_mii.def && gp->phy_mii.def->ops->init) 1778 if (gp->phy_mii.def && gp->phy_mii.def->ops->init)
1709 gp->phy_mii.def->ops->init(&gp->phy_mii); 1779 gp->phy_mii.def->ops->init(&gp->phy_mii);
1710 } else { 1780 } else {
1711 u32 val; 1781 gem_pcs_reset(gp);
1712 int limit; 1782 gem_pcs_reinit_adv(gp);
1713
1714 /* Reset PCS unit. */
1715 val = readl(gp->regs + PCS_MIICTRL);
1716 val |= PCS_MIICTRL_RST;
1717 writel(val, gp->regs + PCS_MIICTRL);
1718
1719 limit = 32;
1720 while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
1721 udelay(100);
1722 if (limit-- <= 0)
1723 break;
1724 }
1725 if (limit <= 0)
1726 printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
1727 gp->dev->name);
1728
1729 /* Make sure PCS is disabled while changing advertisement
1730 * configuration.
1731 */
1732 val = readl(gp->regs + PCS_CFG);
1733 val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
1734 writel(val, gp->regs + PCS_CFG);
1735
1736 /* Advertise all capabilities except assymetric
1737 * pause.
1738 */
1739 val = readl(gp->regs + PCS_MIIADV);
1740 val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
1741 PCS_MIIADV_SP | PCS_MIIADV_AP);
1742 writel(val, gp->regs + PCS_MIIADV);
1743
1744 /* Enable and restart auto-negotiation, disable wrapback/loopback,
1745 * and re-enable PCS.
1746 */
1747 val = readl(gp->regs + PCS_MIICTRL);
1748 val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
1749 val &= ~PCS_MIICTRL_WB;
1750 writel(val, gp->regs + PCS_MIICTRL);
1751
1752 val = readl(gp->regs + PCS_CFG);
1753 val |= PCS_CFG_ENABLE;
1754 writel(val, gp->regs + PCS_CFG);
1755
1756 /* Make sure serialink loopback is off. The meaning
1757 * of this bit is logically inverted based upon whether
1758 * you are in Serialink or SERDES mode.
1759 */
1760 val = readl(gp->regs + PCS_SCTRL);
1761 if (gp->phy_type == phy_serialink)
1762 val &= ~PCS_SCTRL_LOOP;
1763 else
1764 val |= PCS_SCTRL_LOOP;
1765 writel(val, gp->regs + PCS_SCTRL);
1766 } 1783 }
1767 1784
1768 /* Default aneg parameters */ 1785 /* Default aneg parameters */
@@ -2680,6 +2697,21 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2680 cmd->speed = 0; 2697 cmd->speed = 0;
2681 cmd->duplex = cmd->port = cmd->phy_address = 2698 cmd->duplex = cmd->port = cmd->phy_address =
2682 cmd->transceiver = cmd->autoneg = 0; 2699 cmd->transceiver = cmd->autoneg = 0;
2700
2701 /* serdes means usually a Fibre connector, with most fixed */
2702 if (gp->phy_type == phy_serdes) {
2703 cmd->port = PORT_FIBRE;
2704 cmd->supported = (SUPPORTED_1000baseT_Half |
2705 SUPPORTED_1000baseT_Full |
2706 SUPPORTED_FIBRE | SUPPORTED_Autoneg |
2707 SUPPORTED_Pause | SUPPORTED_Asym_Pause);
2708 cmd->advertising = cmd->supported;
2709 cmd->transceiver = XCVR_INTERNAL;
2710 if (gp->lstate == link_up)
2711 cmd->speed = SPEED_1000;
2712 cmd->duplex = DUPLEX_FULL;
2713 cmd->autoneg = 1;
2714 }
2683 } 2715 }
2684 cmd->maxtxpkt = cmd->maxrxpkt = 0; 2716 cmd->maxtxpkt = cmd->maxrxpkt = 0;
2685 2717