aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Mohr <andim2@users.sourceforge.net>2009-06-10 05:55:04 -0400
committerDavid S. Miller <davem@davemloft.net>2009-06-11 05:32:39 -0400
commit720017623ab294b66c8a95d7bc5ccf75a581ebe4 (patch)
treeb5603217826267eaff7022dca689169b29bf8d36
parente5241c448f94feee40b2a285c8bf55d066420073 (diff)
e100: add non-MII PHY support
Restore support for cards with MII-lacking PHYs as compared to removed pre-2.6.29 eepro100 driver: use full low-level MII I/O access abstraction by providing clean PHY-specific mdio_ctrl() functions for either standard MII-compliant cards, slightly special ones or non-MII PHY ones. We now have another netdev_priv member for mdio_ctrl(), thus we have some array indirection, but we save some additional opcodes for specific phy_82552_v handling in the common case. [akpm@linux-foundation.org: cleanups] Signed-off-by: Andreas Mohr <andi@lisas.de> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Cc: Jesse Brandeburg <jesse.brandeburg@intel.com> Cc: Bruce Allan <bruce.w.allan@intel.com> Cc: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com> Cc: John Ronciak <john.ronciak@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/e100.c188
1 files changed, 162 insertions, 26 deletions
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 0c37dd97fa09..119dc5300f9d 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -143,6 +143,8 @@
143 * FIXES: 143 * FIXES:
144 * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com> 144 * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
145 * - Stratus87247: protect MDI control register manipulations 145 * - Stratus87247: protect MDI control register manipulations
146 * 2009/06/01 - Andreas Mohr <andi at lisas dot de>
147 * - add clean lowlevel I/O emulation for cards with MII-lacking PHYs
146 */ 148 */
147 149
148#include <linux/module.h> 150#include <linux/module.h>
@@ -372,6 +374,7 @@ enum eeprom_op {
372 374
373enum eeprom_offsets { 375enum eeprom_offsets {
374 eeprom_cnfg_mdix = 0x03, 376 eeprom_cnfg_mdix = 0x03,
377 eeprom_phy_iface = 0x06,
375 eeprom_id = 0x0A, 378 eeprom_id = 0x0A,
376 eeprom_config_asf = 0x0D, 379 eeprom_config_asf = 0x0D,
377 eeprom_smbus_addr = 0x90, 380 eeprom_smbus_addr = 0x90,
@@ -381,6 +384,18 @@ enum eeprom_cnfg_mdix {
381 eeprom_mdix_enabled = 0x0080, 384 eeprom_mdix_enabled = 0x0080,
382}; 385};
383 386
387enum eeprom_phy_iface {
388 NoSuchPhy = 0,
389 I82553AB,
390 I82553C,
391 I82503,
392 DP83840,
393 S80C240,
394 S80C24,
395 I82555,
396 DP83840A = 10,
397};
398
384enum eeprom_id { 399enum eeprom_id {
385 eeprom_id_wol = 0x0020, 400 eeprom_id_wol = 0x0020,
386}; 401};
@@ -545,6 +560,7 @@ struct nic {
545 u32 msg_enable ____cacheline_aligned; 560 u32 msg_enable ____cacheline_aligned;
546 struct net_device *netdev; 561 struct net_device *netdev;
547 struct pci_dev *pdev; 562 struct pci_dev *pdev;
563 u16 (*mdio_ctrl)(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data);
548 564
549 struct rx *rxs ____cacheline_aligned; 565 struct rx *rxs ____cacheline_aligned;
550 struct rx *rx_to_use; 566 struct rx *rx_to_use;
@@ -899,7 +915,21 @@ err_unlock:
899 return err; 915 return err;
900} 916}
901 917
902static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) 918static int mdio_read(struct net_device *netdev, int addr, int reg)
919{
920 struct nic *nic = netdev_priv(netdev);
921 return nic->mdio_ctrl(nic, addr, mdi_read, reg, 0);
922}
923
924static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
925{
926 struct nic *nic = netdev_priv(netdev);
927
928 nic->mdio_ctrl(nic, addr, mdi_write, reg, data);
929}
930
931/* the standard mdio_ctrl() function for usual MII-compliant hardware */
932static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
903{ 933{
904 u32 data_out = 0; 934 u32 data_out = 0;
905 unsigned int i; 935 unsigned int i;
@@ -938,30 +968,83 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
938 return (u16)data_out; 968 return (u16)data_out;
939} 969}
940 970
941static int mdio_read(struct net_device *netdev, int addr, int reg) 971/* slightly tweaked mdio_ctrl() function for phy_82552_v specifics */
942{ 972static u16 mdio_ctrl_phy_82552_v(struct nic *nic,
943 return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0); 973 u32 addr,
974 u32 dir,
975 u32 reg,
976 u16 data)
977{
978 if ((reg == MII_BMCR) && (dir == mdi_write)) {
979 if (data & (BMCR_ANRESTART | BMCR_ANENABLE)) {
980 u16 advert = mdio_read(nic->netdev, nic->mii.phy_id,
981 MII_ADVERTISE);
982
983 /*
984 * Workaround Si issue where sometimes the part will not
985 * autoneg to 100Mbps even when advertised.
986 */
987 if (advert & ADVERTISE_100FULL)
988 data |= BMCR_SPEED100 | BMCR_FULLDPLX;
989 else if (advert & ADVERTISE_100HALF)
990 data |= BMCR_SPEED100;
991 }
992 }
993 return mdio_ctrl_hw(nic, addr, dir, reg, data);
944} 994}
945 995
946static void mdio_write(struct net_device *netdev, int addr, int reg, int data) 996/* Fully software-emulated mdio_ctrl() function for cards without
947{ 997 * MII-compliant PHYs.
948 struct nic *nic = netdev_priv(netdev); 998 * For now, this is mainly geared towards 80c24 support; in case of further
949 999 * requirements for other types (i82503, ...?) either extend this mechanism
950 if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) && 1000 * or split it, whichever is cleaner.
951 (data & (BMCR_ANRESTART | BMCR_ANENABLE))) { 1001 */
952 u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); 1002static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic,
953 1003 u32 addr,
954 /* 1004 u32 dir,
955 * Workaround Si issue where sometimes the part will not 1005 u32 reg,
956 * autoneg to 100Mbps even when advertised. 1006 u16 data)
957 */ 1007{
958 if (advert & ADVERTISE_100FULL) 1008 /* might need to allocate a netdev_priv'ed register array eventually
959 data |= BMCR_SPEED100 | BMCR_FULLDPLX; 1009 * to be able to record state changes, but for now
960 else if (advert & ADVERTISE_100HALF) 1010 * some fully hardcoded register handling ought to be ok I guess. */
961 data |= BMCR_SPEED100; 1011
1012 if (dir == mdi_read) {
1013 switch (reg) {
1014 case MII_BMCR:
1015 /* Auto-negotiation, right? */
1016 return BMCR_ANENABLE |
1017 BMCR_FULLDPLX;
1018 case MII_BMSR:
1019 return BMSR_LSTATUS /* for mii_link_ok() */ |
1020 BMSR_ANEGCAPABLE |
1021 BMSR_10FULL;
1022 case MII_ADVERTISE:
1023 /* 80c24 is a "combo card" PHY, right? */
1024 return ADVERTISE_10HALF |
1025 ADVERTISE_10FULL;
1026 default:
1027 DPRINTK(HW, DEBUG,
1028 "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
1029 dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
1030 return 0xFFFF;
1031 }
1032 } else {
1033 switch (reg) {
1034 default:
1035 DPRINTK(HW, DEBUG,
1036 "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
1037 dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
1038 return 0xFFFF;
1039 }
962 } 1040 }
963 1041}
964 mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); 1042static inline int e100_phy_supports_mii(struct nic *nic)
1043{
1044 /* for now, just check it by comparing whether we
1045 are using MII software emulation.
1046 */
1047 return (nic->mdio_ctrl != mdio_ctrl_phy_mii_emulated);
965} 1048}
966 1049
967static void e100_get_defaults(struct nic *nic) 1050static void e100_get_defaults(struct nic *nic)
@@ -1013,7 +1096,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
1013 config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ 1096 config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */
1014 config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ 1097 config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */
1015 config->tx_underrun_retry = 0x3; /* # of underrun retries */ 1098 config->tx_underrun_retry = 0x3; /* # of underrun retries */
1016 config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ 1099 if (e100_phy_supports_mii(nic))
1100 config->mii_mode = 1; /* 1=MII mode, 0=i82503 mode */
1017 config->pad10 = 0x6; 1101 config->pad10 = 0x6;
1018 config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ 1102 config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */
1019 config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ 1103 config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */
@@ -1270,6 +1354,42 @@ static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
1270 offsetof(struct mem, dump_buf)); 1354 offsetof(struct mem, dump_buf));
1271} 1355}
1272 1356
1357static int e100_phy_check_without_mii(struct nic *nic)
1358{
1359 u8 phy_type;
1360 int without_mii;
1361
1362 phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f;
1363
1364 switch (phy_type) {
1365 case NoSuchPhy: /* Non-MII PHY; UNTESTED! */
1366 case I82503: /* Non-MII PHY; UNTESTED! */
1367 case S80C24: /* Non-MII PHY; tested and working */
1368 /* paragraph from the FreeBSD driver, "FXP_PHY_80C24":
1369 * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter
1370 * doesn't have a programming interface of any sort. The
1371 * media is sensed automatically based on how the link partner
1372 * is configured. This is, in essence, manual configuration.
1373 */
1374 DPRINTK(PROBE, INFO,
1375 "found MII-less i82503 or 80c24 or other PHY\n");
1376
1377 nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated;
1378 nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */
1379
1380 /* these might be needed for certain MII-less cards...
1381 * nic->flags |= ich;
1382 * nic->flags |= ich_10h_workaround; */
1383
1384 without_mii = 1;
1385 break;
1386 default:
1387 without_mii = 0;
1388 break;
1389 }
1390 return without_mii;
1391}
1392
1273#define NCONFIG_AUTO_SWITCH 0x0080 1393#define NCONFIG_AUTO_SWITCH 0x0080
1274#define MII_NSC_CONG MII_RESV1 1394#define MII_NSC_CONG MII_RESV1
1275#define NSC_CONG_ENABLE 0x0100 1395#define NSC_CONG_ENABLE 0x0100
@@ -1290,9 +1410,21 @@ static int e100_phy_init(struct nic *nic)
1290 if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) 1410 if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
1291 break; 1411 break;
1292 } 1412 }
1293 DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); 1413 if (addr == 32) {
1294 if (addr == 32) 1414 /* uhoh, no PHY detected: check whether we seem to be some
1295 return -EAGAIN; 1415 * weird, rare variant which is *known* to not have any MII.
1416 * But do this AFTER MII checking only, since this does
1417 * lookup of EEPROM values which may easily be unreliable. */
1418 if (e100_phy_check_without_mii(nic))
1419 return 0; /* simply return and hope for the best */
1420 else {
1421 /* for unknown cases log a fatal error */
1422 DPRINTK(HW, ERR,
1423 "Failed to locate any known PHY, aborting.\n");
1424 return -EAGAIN;
1425 }
1426 } else
1427 DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
1296 1428
1297 /* Isolate all the PHY ids */ 1429 /* Isolate all the PHY ids */
1298 for (addr = 0; addr < 32; addr++) 1430 for (addr = 0; addr < 32; addr++)
@@ -1320,6 +1452,9 @@ static int e100_phy_init(struct nic *nic)
1320 if (nic->phy == phy_82552_v) { 1452 if (nic->phy == phy_82552_v) {
1321 u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); 1453 u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
1322 1454
1455 /* assign special tweaked mdio_ctrl() function */
1456 nic->mdio_ctrl = mdio_ctrl_phy_82552_v;
1457
1323 /* Workaround Si not advertising flow-control during autoneg */ 1458 /* Workaround Si not advertising flow-control during autoneg */
1324 advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 1459 advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1325 mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert); 1460 mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert);
@@ -2585,6 +2720,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
2585 nic->netdev = netdev; 2720 nic->netdev = netdev;
2586 nic->pdev = pdev; 2721 nic->pdev = pdev;
2587 nic->msg_enable = (1 << debug) - 1; 2722 nic->msg_enable = (1 << debug) - 1;
2723 nic->mdio_ctrl = mdio_ctrl_hw;
2588 pci_set_drvdata(pdev, netdev); 2724 pci_set_drvdata(pdev, netdev);
2589 2725
2590 if ((err = pci_enable_device(pdev))) { 2726 if ((err = pci_enable_device(pdev))) {