[SUNGEM]: PHY updates & pause fixes (#2)

This patch adds support for a few more PHYs used by Apple and fixes
advertising and detecting of Pause (we were missing setting the bit in
MII_ADVERTISE and weren't testing in LPA for all PHYs).

Note that I currently only advertise pause, not asymetric pause. I
don't know for sure the details there, I suppose I should read a bit
more 802.3 references, and I don't now what sungem is capable of, but
I noticed the PCS code (originated from you) does the same.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Benjamin Herrenschmidt and committed by David S. Miller 63ea998a 7f18ba62

+163 -26
+2 -1
drivers/net/sungem.c
··· 90 90 91 91 #define ADVERTISE_MASK (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ 92 92 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ 93 - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) 93 + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full | \ 94 + SUPPORTED_Pause | SUPPORTED_Autoneg) 94 95 95 96 #define DRV_NAME "sungem" 96 97 #define DRV_VERSION "0.98"
+155 -24
drivers/net/sungem_phy.c
··· 3 3 * 4 4 * This file could be shared with other drivers. 5 5 * 6 - * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org) 6 + * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org) 7 7 * 8 8 * TODO: 9 - * - Implement WOL 10 9 * - Add support for PHYs that provide an IRQ line 11 10 * - Eventually moved the entire polling state machine in 12 11 * there (out of the eth driver), so that it can easily be ··· 147 148 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 148 149 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 149 150 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE); 151 + 152 + return 0; 153 + } 154 + 155 + static int bcm5241_init(struct mii_phy* phy) 156 + { 157 + u16 data; 158 + 159 + data = phy_read(phy, MII_BCM5221_TEST); 160 + phy_write(phy, MII_BCM5221_TEST, 161 + data | MII_BCM5221_TEST_ENABLE_SHADOWS); 162 + 163 + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2); 164 + phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2, 165 + data | MII_BCM5221_SHDOW_AUX_STAT2_APD); 166 + 167 + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 168 + phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 169 + data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); 170 + 171 + data = phy_read(phy, MII_BCM5221_TEST); 172 + phy_write(phy, MII_BCM5221_TEST, 173 + data & ~MII_BCM5221_TEST_ENABLE_SHADOWS); 174 + 175 + return 0; 176 + } 177 + 178 + static int bcm5241_suspend(struct mii_phy* phy) 179 + { 180 + u16 data; 181 + 182 + data = phy_read(phy, MII_BCM5221_TEST); 183 + phy_write(phy, MII_BCM5221_TEST, 184 + data | MII_BCM5221_TEST_ENABLE_SHADOWS); 185 + 186 + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); 187 + phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, 188 + data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); 150 189 151 190 return 0; 152 191 } ··· 410 373 adv |= ADVERTISE_100HALF; 411 374 if (advertise & ADVERTISED_100baseT_Full) 412 375 adv |= ADVERTISE_100FULL; 376 + if (advertise & ADVERTISED_Pause) 377 + adv |= ADVERTISE_PAUSE_CAP; 378 + if (advertise & ADVERTISED_Asym_Pause) 379 + adv |= ADVERTISE_PAUSE_ASYM; 413 380 phy_write(phy, MII_ADVERTISE, adv); 414 381 415 382 /* Setup 1000BT advertise */ ··· 477 436 val = phy_read(phy, MII_BCM5400_AUXSTATUS); 478 437 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> 479 438 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); 480 - phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF; 439 + phy->duplex = phy_BCM5400_link_table[link_mode][0] ? 440 + DUPLEX_FULL : DUPLEX_HALF; 481 441 phy->speed = phy_BCM5400_link_table[link_mode][2] ? 482 442 SPEED_1000 : 483 - (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10); 443 + (phy_BCM5400_link_table[link_mode][1] ? 444 + SPEED_100 : SPEED_10); 484 445 val = phy_read(phy, MII_LPA); 485 - phy->pause = ((val & LPA_PAUSE) != 0); 446 + phy->pause = (phy->duplex == DUPLEX_FULL) && 447 + ((val & LPA_PAUSE) != 0); 486 448 } 487 449 /* On non-aneg, we assume what we put in BMCR is the speed, 488 450 * though magic-aneg shouldn't prevent this case from occurring 489 451 */ 490 452 453 + return 0; 454 + } 455 + 456 + static int marvell88e1111_init(struct mii_phy* phy) 457 + { 458 + u16 rev; 459 + 460 + /* magic init sequence for rev 0 */ 461 + rev = phy_read(phy, MII_PHYSID2) & 0x000f; 462 + if (rev == 0) { 463 + phy_write(phy, 0x1d, 0x000a); 464 + phy_write(phy, 0x1e, 0x0821); 465 + 466 + phy_write(phy, 0x1d, 0x0006); 467 + phy_write(phy, 0x1e, 0x8600); 468 + 469 + phy_write(phy, 0x1d, 0x000b); 470 + phy_write(phy, 0x1e, 0x0100); 471 + 472 + phy_write(phy, 0x1d, 0x0004); 473 + phy_write(phy, 0x1e, 0x4850); 474 + } 491 475 return 0; 492 476 } 493 477 ··· 537 471 adv |= ADVERTISE_100HALF; 538 472 if (advertise & ADVERTISED_100baseT_Full) 539 473 adv |= ADVERTISE_100FULL; 474 + if (advertise & ADVERTISED_Pause) 475 + adv |= ADVERTISE_PAUSE_CAP; 476 + if (advertise & ADVERTISED_Asym_Pause) 477 + adv |= ADVERTISE_PAUSE_ASYM; 540 478 phy_write(phy, MII_ADVERTISE, adv); 541 479 542 480 /* Setup 1000BT advertise & enable crossover detect ··· 619 549 620 550 static int marvell_read_link(struct mii_phy *phy) 621 551 { 622 - u16 status; 552 + u16 status, pmask; 623 553 624 554 if (phy->autoneg) { 625 555 status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS); ··· 635 565 phy->duplex = DUPLEX_FULL; 636 566 else 637 567 phy->duplex = DUPLEX_HALF; 638 - phy->pause = 0; /* XXX Check against spec ! */ 568 + pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE | 569 + MII_M1011_PHY_SPEC_STATUS_RX_PAUSE; 570 + phy->pause = (status & pmask) == pmask; 639 571 } 640 572 /* On non-aneg, we assume what we put in BMCR is the speed, 641 573 * though magic-aneg shouldn't prevent this case from occurring ··· 667 595 adv |= ADVERTISE_100HALF; 668 596 if (advertise & ADVERTISED_100baseT_Full) 669 597 adv |= ADVERTISE_100FULL; 598 + if (advertise & ADVERTISED_Pause) 599 + adv |= ADVERTISE_PAUSE_CAP; 600 + if (advertise & ADVERTISED_Asym_Pause) 601 + adv |= ADVERTISE_PAUSE_ASYM; 670 602 phy_write(phy, MII_ADVERTISE, adv); 671 603 672 604 /* Start/Restart aneg */ ··· 742 666 phy->speed = SPEED_100; 743 667 else 744 668 phy->speed = SPEED_10; 745 - phy->pause = 0; 669 + phy->pause = (phy->duplex == DUPLEX_FULL) && 670 + ((lpa & LPA_PAUSE) != 0); 746 671 } 747 672 /* On non-aneg, we assume what we put in BMCR is the speed, 748 673 * though magic-aneg shouldn't prevent this case from occurring ··· 753 676 } 754 677 755 678 756 - #define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ 757 - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ 758 - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) 759 - #define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ 760 - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) 679 + #define MII_BASIC_FEATURES \ 680 + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ 681 + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ 682 + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \ 683 + SUPPORTED_Pause) 684 + 685 + /* On gigabit capable PHYs, we advertise Pause support but not asym pause 686 + * support for now as I'm not sure it's supported and Darwin doesn't do 687 + * it neither. --BenH. 688 + */ 689 + #define MII_GBIT_FEATURES \ 690 + (MII_BASIC_FEATURES | \ 691 + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) 761 692 762 693 /* Broadcom BCM 5201 */ 763 694 static struct mii_phy_ops bcm5201_phy_ops = { ··· 803 718 .features = MII_BASIC_FEATURES, 804 719 .magic_aneg = 1, 805 720 .ops = &bcm5221_phy_ops 721 + }; 722 + 723 + /* Broadcom BCM 5241 */ 724 + static struct mii_phy_ops bcm5241_phy_ops = { 725 + .suspend = bcm5241_suspend, 726 + .init = bcm5241_init, 727 + .setup_aneg = genmii_setup_aneg, 728 + .setup_forced = genmii_setup_forced, 729 + .poll_link = genmii_poll_link, 730 + .read_link = genmii_read_link, 731 + }; 732 + static struct mii_phy_def bcm5241_phy_def = { 733 + .phy_id = 0x0143bc30, 734 + .phy_id_mask = 0xfffffff0, 735 + .name = "BCM5241", 736 + .features = MII_BASIC_FEATURES, 737 + .magic_aneg = 1, 738 + .ops = &bcm5241_phy_ops 806 739 }; 807 740 808 741 /* Broadcom BCM 5400 */ ··· 957 854 .ops = &bcm5462V_phy_ops 958 855 }; 959 856 960 - /* Marvell 88E1101 (Apple seem to deal with 2 different revs, 961 - * I masked out the 8 last bits to get both, but some specs 962 - * would be useful here) --BenH. 963 - */ 964 - static struct mii_phy_ops marvell_phy_ops = { 857 + /* Marvell 88E1101 amd 88E1111 */ 858 + static struct mii_phy_ops marvell88e1101_phy_ops = { 965 859 .suspend = generic_suspend, 966 860 .setup_aneg = marvell_setup_aneg, 967 861 .setup_forced = marvell_setup_forced, ··· 966 866 .read_link = marvell_read_link 967 867 }; 968 868 969 - static struct mii_phy_def marvell_phy_def = { 970 - .phy_id = 0x01410c00, 971 - .phy_id_mask = 0xffffff00, 972 - .name = "Marvell 88E1101", 869 + static struct mii_phy_ops marvell88e1111_phy_ops = { 870 + .init = marvell88e1111_init, 871 + .suspend = generic_suspend, 872 + .setup_aneg = marvell_setup_aneg, 873 + .setup_forced = marvell_setup_forced, 874 + .poll_link = genmii_poll_link, 875 + .read_link = marvell_read_link 876 + }; 877 + 878 + /* two revs in darwin for the 88e1101 ... I could use a datasheet 879 + * to get the proper names... 880 + */ 881 + static struct mii_phy_def marvell88e1101v1_phy_def = { 882 + .phy_id = 0x01410c20, 883 + .phy_id_mask = 0xfffffff0, 884 + .name = "Marvell 88E1101v1", 973 885 .features = MII_GBIT_FEATURES, 974 886 .magic_aneg = 1, 975 - .ops = &marvell_phy_ops 887 + .ops = &marvell88e1101_phy_ops 888 + }; 889 + static struct mii_phy_def marvell88e1101v2_phy_def = { 890 + .phy_id = 0x01410c60, 891 + .phy_id_mask = 0xfffffff0, 892 + .name = "Marvell 88E1101v2", 893 + .features = MII_GBIT_FEATURES, 894 + .magic_aneg = 1, 895 + .ops = &marvell88e1101_phy_ops 896 + }; 897 + static struct mii_phy_def marvell88e1111_phy_def = { 898 + .phy_id = 0x01410cc0, 899 + .phy_id_mask = 0xfffffff0, 900 + .name = "Marvell 88E1111", 901 + .features = MII_GBIT_FEATURES, 902 + .magic_aneg = 1, 903 + .ops = &marvell88e1111_phy_ops 976 904 }; 977 905 978 906 /* Generic implementation for most 10/100 PHYs */ ··· 1023 895 static struct mii_phy_def* mii_phy_table[] = { 1024 896 &bcm5201_phy_def, 1025 897 &bcm5221_phy_def, 898 + &bcm5241_phy_def, 1026 899 &bcm5400_phy_def, 1027 900 &bcm5401_phy_def, 1028 901 &bcm5411_phy_def, ··· 1031 902 &bcm5421k2_phy_def, 1032 903 &bcm5461_phy_def, 1033 904 &bcm5462V_phy_def, 1034 - &marvell_phy_def, 905 + &marvell88e1101v1_phy_def, 906 + &marvell88e1101v2_phy_def, 907 + &marvell88e1111_phy_def, 1035 908 &genmii_phy_def, 1036 909 NULL 1037 910 };
+6 -1
drivers/net/sungem_phy.h
··· 30 30 struct mii_phy 31 31 { 32 32 struct mii_phy_def* def; 33 - int advertising; 33 + u32 advertising; 34 34 int mii_id; 35 35 36 36 /* 1: autoneg enabled, 0: disabled */ ··· 85 85 #define MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE 0x0001 86 86 #define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR 0x0004 87 87 88 + /* MII BCM5241 Additional registers */ 89 + #define MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR 0x0008 90 + 88 91 /* MII BCM5400 1000-BASET Control register */ 89 92 #define MII_BCM5400_GB_CONTROL 0x09 90 93 #define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 ··· 118 115 #define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 119 116 #define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 120 117 #define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 118 + #define MII_M1011_PHY_SPEC_STATUS_TX_PAUSE 0x0008 119 + #define MII_M1011_PHY_SPEC_STATUS_RX_PAUSE 0x0004 121 120 122 121 #endif /* __SUNGEM_PHY_H__ */