diff options
author | Steve Glendinning <steve.glendinning@smsc.com> | 2008-12-16 05:00:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-16 05:00:48 -0500 |
commit | bc02ff95fe4ebd3e5ee7455c0aa6f76ebe39ebca (patch) | |
tree | 675887b8007a53464e84b9da2f7b54a77fab035a | |
parent | e18ce3465477502108187c6c08b6423fb784a313 (diff) |
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: Steve Glendinning <steve.glendinning@smsc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/smsc911x.c | 24 | ||||
-rw-r--r-- | drivers/net/smsc9420.c | 24 | ||||
-rw-r--r-- | drivers/net/tg3.c | 24 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 24 | ||||
-rw-r--r-- | include/linux/mii.h | 29 |
5 files changed, 33 insertions, 92 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index ae327166f978..fa28542b47d5 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c | |||
@@ -642,28 +642,6 @@ static int smsc911x_phy_loopbacktest(struct net_device *dev) | |||
642 | } | 642 | } |
643 | #endif /* USE_PHY_WORK_AROUND */ | 643 | #endif /* USE_PHY_WORK_AROUND */ |
644 | 644 | ||
645 | static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) | ||
646 | { | ||
647 | u8 cap = 0; | ||
648 | |||
649 | if (lcladv & ADVERTISE_PAUSE_CAP) { | ||
650 | if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
651 | if (rmtadv & LPA_PAUSE_CAP) | ||
652 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
653 | else if (rmtadv & LPA_PAUSE_ASYM) | ||
654 | cap = FLOW_CTRL_RX; | ||
655 | } else { | ||
656 | if (rmtadv & LPA_PAUSE_CAP) | ||
657 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
658 | } | ||
659 | } else if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
660 | if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) | ||
661 | cap = FLOW_CTRL_TX; | ||
662 | } | ||
663 | |||
664 | return cap; | ||
665 | } | ||
666 | |||
667 | static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) | 645 | static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) |
668 | { | 646 | { |
669 | struct phy_device *phy_dev = pdata->phy_dev; | 647 | struct phy_device *phy_dev = pdata->phy_dev; |
@@ -674,7 +652,7 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) | |||
674 | if (phy_dev->duplex == DUPLEX_FULL) { | 652 | if (phy_dev->duplex == DUPLEX_FULL) { |
675 | u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); | 653 | u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); |
676 | u16 rmtadv = phy_read(phy_dev, MII_LPA); | 654 | u16 rmtadv = phy_read(phy_dev, MII_LPA); |
677 | u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); | 655 | u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); |
678 | 656 | ||
679 | if (cap & FLOW_CTRL_RX) | 657 | if (cap & FLOW_CTRL_RX) |
680 | flow = 0xFFFF0002; | 658 | flow = 0xFFFF0002; |
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index bc9879d5f281..940220f60921 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c | |||
@@ -1080,28 +1080,6 @@ static void smsc9420_set_multicast_list(struct net_device *dev) | |||
1080 | smsc9420_pci_flush_write(pd); | 1080 | smsc9420_pci_flush_write(pd); |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | static u8 smsc9420_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) | ||
1084 | { | ||
1085 | u8 cap = 0; | ||
1086 | |||
1087 | if (lcladv & ADVERTISE_PAUSE_CAP) { | ||
1088 | if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
1089 | if (rmtadv & LPA_PAUSE_CAP) | ||
1090 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
1091 | else if (rmtadv & LPA_PAUSE_ASYM) | ||
1092 | cap = FLOW_CTRL_RX; | ||
1093 | } else { | ||
1094 | if (rmtadv & LPA_PAUSE_CAP) | ||
1095 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
1096 | } | ||
1097 | } else if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
1098 | if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) | ||
1099 | cap = FLOW_CTRL_TX; | ||
1100 | } | ||
1101 | |||
1102 | return cap; | ||
1103 | } | ||
1104 | |||
1105 | static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) | 1083 | static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) |
1106 | { | 1084 | { |
1107 | struct phy_device *phy_dev = pd->phy_dev; | 1085 | struct phy_device *phy_dev = pd->phy_dev; |
@@ -1110,7 +1088,7 @@ static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) | |||
1110 | if (phy_dev->duplex == DUPLEX_FULL) { | 1088 | if (phy_dev->duplex == DUPLEX_FULL) { |
1111 | u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); | 1089 | u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); |
1112 | u16 rmtadv = phy_read(phy_dev, MII_LPA); | 1090 | u16 rmtadv = phy_read(phy_dev, MII_LPA); |
1113 | u8 cap = smsc9420_resolve_flowctrl_fulldplx(lcladv, rmtadv); | 1091 | u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); |
1114 | 1092 | ||
1115 | if (cap & FLOW_CTRL_RX) | 1093 | if (cap & FLOW_CTRL_RX) |
1116 | flow = 0xFFFF0002; | 1094 | flow = 0xFFFF0002; |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f353f69caeb8..06bd2f4eee6c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -1227,28 +1227,6 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) | |||
1227 | return miireg; | 1227 | return miireg; |
1228 | } | 1228 | } |
1229 | 1229 | ||
1230 | static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) | ||
1231 | { | ||
1232 | u8 cap = 0; | ||
1233 | |||
1234 | if (lcladv & ADVERTISE_PAUSE_CAP) { | ||
1235 | if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
1236 | if (rmtadv & LPA_PAUSE_CAP) | ||
1237 | cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; | ||
1238 | else if (rmtadv & LPA_PAUSE_ASYM) | ||
1239 | cap = TG3_FLOW_CTRL_RX; | ||
1240 | } else { | ||
1241 | if (rmtadv & LPA_PAUSE_CAP) | ||
1242 | cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; | ||
1243 | } | ||
1244 | } else if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
1245 | if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) | ||
1246 | cap = TG3_FLOW_CTRL_TX; | ||
1247 | } | ||
1248 | |||
1249 | return cap; | ||
1250 | } | ||
1251 | |||
1252 | static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) | 1230 | static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) |
1253 | { | 1231 | { |
1254 | u8 cap = 0; | 1232 | u8 cap = 0; |
@@ -1288,7 +1266,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) | |||
1288 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) | 1266 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) |
1289 | flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); | 1267 | flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); |
1290 | else | 1268 | else |
1291 | flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); | 1269 | flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv); |
1292 | } else | 1270 | } else |
1293 | flowctrl = tp->link_config.flowctrl; | 1271 | flowctrl = tp->link_config.flowctrl; |
1294 | 1272 | ||
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index ee2eac3047b3..fed22ffedd57 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -435,28 +435,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
435 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); | 435 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); |
436 | } | 436 | } |
437 | 437 | ||
438 | static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) | ||
439 | { | ||
440 | u8 cap = 0; | ||
441 | |||
442 | if (lcladv & ADVERTISE_PAUSE_CAP) { | ||
443 | if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
444 | if (rmtadv & LPA_PAUSE_CAP) | ||
445 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
446 | else if (rmtadv & LPA_PAUSE_ASYM) | ||
447 | cap = FLOW_CTRL_RX; | ||
448 | } else { | ||
449 | if (rmtadv & LPA_PAUSE_CAP) | ||
450 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
451 | } | ||
452 | } else if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
453 | if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) | ||
454 | cap = FLOW_CTRL_TX; | ||
455 | } | ||
456 | |||
457 | return cap; | ||
458 | } | ||
459 | |||
460 | static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, | 438 | static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, |
461 | u16 lcladv, u16 rmtadv) | 439 | u16 lcladv, u16 rmtadv) |
462 | { | 440 | { |
@@ -469,7 +447,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, | |||
469 | } | 447 | } |
470 | 448 | ||
471 | if (duplex == DUPLEX_FULL) { | 449 | if (duplex == DUPLEX_FULL) { |
472 | u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); | 450 | u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); |
473 | 451 | ||
474 | if (cap & FLOW_CTRL_RX) | 452 | if (cap & FLOW_CTRL_RX) |
475 | flow = 0xFFFF0002; | 453 | flow = 0xFFFF0002; |
diff --git a/include/linux/mii.h b/include/linux/mii.h index 4a376e0816fd..ad748588faf1 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h | |||
@@ -239,5 +239,34 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, | |||
239 | return 0; | 239 | return 0; |
240 | } | 240 | } |
241 | 241 | ||
242 | /** | ||
243 | * mii_resolve_flowctrl_fdx | ||
244 | * @lcladv: value of MII ADVERTISE register | ||
245 | * @rmtadv: value of MII LPA register | ||
246 | * | ||
247 | * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3 | ||
248 | */ | ||
249 | static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv) | ||
250 | { | ||
251 | u8 cap = 0; | ||
252 | |||
253 | if (lcladv & ADVERTISE_PAUSE_CAP) { | ||
254 | if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
255 | if (rmtadv & LPA_PAUSE_CAP) | ||
256 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
257 | else if (rmtadv & LPA_PAUSE_ASYM) | ||
258 | cap = FLOW_CTRL_RX; | ||
259 | } else { | ||
260 | if (rmtadv & LPA_PAUSE_CAP) | ||
261 | cap = FLOW_CTRL_TX | FLOW_CTRL_RX; | ||
262 | } | ||
263 | } else if (lcladv & ADVERTISE_PAUSE_ASYM) { | ||
264 | if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) | ||
265 | cap = FLOW_CTRL_TX; | ||
266 | } | ||
267 | |||
268 | return cap; | ||
269 | } | ||
270 | |||
242 | #endif /* __KERNEL__ */ | 271 | #endif /* __KERNEL__ */ |
243 | #endif /* __LINUX_MII_H__ */ | 272 | #endif /* __LINUX_MII_H__ */ |