Commit bc02ff95 authored by Steve Glendinning's avatar Steve Glendinning Committed by David S. Miller

net: Refactor full duplex flow control resolution

These 4 drivers have identical full duplex flow control resolution
functions.  This patch changes them all to use one common function.

The function in question decides whether a device should enable TX and
RX flow control in a standard way (IEEE 802.3-2005 table 28B-3), so this
should also be useful for other drivers.
Signed-off-by: default avatarSteve Glendinning <steve.glendinning@smsc.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e18ce346
...@@ -642,28 +642,6 @@ static int smsc911x_phy_loopbacktest(struct net_device *dev) ...@@ -642,28 +642,6 @@ static int smsc911x_phy_loopbacktest(struct net_device *dev)
} }
#endif /* USE_PHY_WORK_AROUND */ #endif /* USE_PHY_WORK_AROUND */
static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = FLOW_CTRL_TX;
}
return cap;
}
static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
{ {
struct phy_device *phy_dev = pdata->phy_dev; struct phy_device *phy_dev = pdata->phy_dev;
...@@ -674,7 +652,7 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) ...@@ -674,7 +652,7 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
if (phy_dev->duplex == DUPLEX_FULL) { if (phy_dev->duplex == DUPLEX_FULL) {
u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
u16 rmtadv = phy_read(phy_dev, MII_LPA); u16 rmtadv = phy_read(phy_dev, MII_LPA);
u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
if (cap & FLOW_CTRL_RX) if (cap & FLOW_CTRL_RX)
flow = 0xFFFF0002; flow = 0xFFFF0002;
......
...@@ -1080,28 +1080,6 @@ static void smsc9420_set_multicast_list(struct net_device *dev) ...@@ -1080,28 +1080,6 @@ static void smsc9420_set_multicast_list(struct net_device *dev)
smsc9420_pci_flush_write(pd); smsc9420_pci_flush_write(pd);
} }
static u8 smsc9420_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = FLOW_CTRL_TX;
}
return cap;
}
static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
{ {
struct phy_device *phy_dev = pd->phy_dev; struct phy_device *phy_dev = pd->phy_dev;
...@@ -1110,7 +1088,7 @@ static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) ...@@ -1110,7 +1088,7 @@ static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
if (phy_dev->duplex == DUPLEX_FULL) { if (phy_dev->duplex == DUPLEX_FULL) {
u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
u16 rmtadv = phy_read(phy_dev, MII_LPA); u16 rmtadv = phy_read(phy_dev, MII_LPA);
u8 cap = smsc9420_resolve_flowctrl_fulldplx(lcladv, rmtadv); u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
if (cap & FLOW_CTRL_RX) if (cap & FLOW_CTRL_RX)
flow = 0xFFFF0002; flow = 0xFFFF0002;
......
...@@ -1227,28 +1227,6 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) ...@@ -1227,28 +1227,6 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
return miireg; return miireg;
} }
static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = TG3_FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = TG3_FLOW_CTRL_TX;
}
return cap;
}
static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
{ {
u8 cap = 0; u8 cap = 0;
...@@ -1288,7 +1266,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) ...@@ -1288,7 +1266,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
else else
flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
} else } else
flowctrl = tp->link_config.flowctrl; flowctrl = tp->link_config.flowctrl;
......
...@@ -435,28 +435,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev) ...@@ -435,28 +435,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
} }
static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = FLOW_CTRL_TX;
}
return cap;
}
static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
u16 lcladv, u16 rmtadv) u16 lcladv, u16 rmtadv)
{ {
...@@ -469,7 +447,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, ...@@ -469,7 +447,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
} }
if (duplex == DUPLEX_FULL) { if (duplex == DUPLEX_FULL) {
u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
if (cap & FLOW_CTRL_RX) if (cap & FLOW_CTRL_RX)
flow = 0xFFFF0002; flow = 0xFFFF0002;
......
...@@ -239,5 +239,34 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, ...@@ -239,5 +239,34 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock,
return 0; return 0;
} }
/**
* mii_resolve_flowctrl_fdx
* @lcladv: value of MII ADVERTISE register
* @rmtadv: value of MII LPA register
*
* Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
*/
static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = FLOW_CTRL_TX;
}
return cap;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __LINUX_MII_H__ */ #endif /* __LINUX_MII_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment