diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-01-15 11:06:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-01-15 11:06:47 -0500 |
commit | 612166c76d6bd1ccd2624a15586a92444d2c4c0e (patch) | |
tree | cbe3bbc73fe5321d109c01259e64ea98e2646a9c /drivers/net/niu.c | |
parent | f885b51967fb5f611c462841e5119853df00cc97 (diff) | |
parent | 1b310fca30ac9851f79337ca72b1cf6a0f58064a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
[TOKENRING]: rif_timer not initialized properly
[NETFILTER]: bridge: fix double POST_ROUTING invocation
[NETFILTER]: xt_helper: Do not bypass RCU
[NETFILTER]: ip6t_eui64: Fixes calculation of Universal/Local bit
[MACVLAN]: Prevent nesting macvlan devices
[VLAN]: nested VLAN: fix lockdep's recursive locking warning
[DECNET] ROUTE: fix rcu_dereference() uses in /proc/net/decnet_cache
[BLUETOOTH]: Always send explicit hci_ll wake-up acks.
[BLUETOOTH]: rfcomm tty BUG_ON() code fix
[AX25] af_ax25: Possible circular locking.
[AX25]: Kill user triggable printks.
[IPV4] ROUTE: fix rcu_dereference() uses in /proc/net/rt_cache
[NEIGH]: Fix race between neigh_parms_release and neightbl_fill_parms
[NIU]: Support for Marvell PHY
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 218 |
1 files changed, 198 insertions, 20 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 9a0c6d3adfe9..3bbcea11329f 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -801,22 +801,90 @@ static int bcm8704_init_user_dev3(struct niu *np) | |||
801 | return 0; | 801 | return 0; |
802 | } | 802 | } |
803 | 803 | ||
804 | static int xcvr_init_10g(struct niu *np) | 804 | static int mrvl88x2011_act_led(struct niu *np, int val) |
805 | { | ||
806 | int err; | ||
807 | |||
808 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, | ||
809 | MRVL88X2011_LED_8_TO_11_CTL); | ||
810 | if (err < 0) | ||
811 | return err; | ||
812 | |||
813 | err &= ~MRVL88X2011_LED(MRVL88X2011_LED_ACT,MRVL88X2011_LED_CTL_MASK); | ||
814 | err |= MRVL88X2011_LED(MRVL88X2011_LED_ACT,val); | ||
815 | |||
816 | return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, | ||
817 | MRVL88X2011_LED_8_TO_11_CTL, err); | ||
818 | } | ||
819 | |||
820 | static int mrvl88x2011_led_blink_rate(struct niu *np, int rate) | ||
821 | { | ||
822 | int err; | ||
823 | |||
824 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, | ||
825 | MRVL88X2011_LED_BLINK_CTL); | ||
826 | if (err >= 0) { | ||
827 | err &= ~MRVL88X2011_LED_BLKRATE_MASK; | ||
828 | err |= (rate << 4); | ||
829 | |||
830 | err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR, | ||
831 | MRVL88X2011_LED_BLINK_CTL, err); | ||
832 | } | ||
833 | |||
834 | return err; | ||
835 | } | ||
836 | |||
837 | static int xcvr_init_10g_mrvl88x2011(struct niu *np) | ||
838 | { | ||
839 | int err; | ||
840 | |||
841 | /* Set LED functions */ | ||
842 | err = mrvl88x2011_led_blink_rate(np, MRVL88X2011_LED_BLKRATE_134MS); | ||
843 | if (err) | ||
844 | return err; | ||
845 | |||
846 | /* led activity */ | ||
847 | err = mrvl88x2011_act_led(np, MRVL88X2011_LED_CTL_OFF); | ||
848 | if (err) | ||
849 | return err; | ||
850 | |||
851 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, | ||
852 | MRVL88X2011_GENERAL_CTL); | ||
853 | if (err < 0) | ||
854 | return err; | ||
855 | |||
856 | err |= MRVL88X2011_ENA_XFPREFCLK; | ||
857 | |||
858 | err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, | ||
859 | MRVL88X2011_GENERAL_CTL, err); | ||
860 | if (err < 0) | ||
861 | return err; | ||
862 | |||
863 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, | ||
864 | MRVL88X2011_PMA_PMD_CTL_1); | ||
865 | if (err < 0) | ||
866 | return err; | ||
867 | |||
868 | if (np->link_config.loopback_mode == LOOPBACK_MAC) | ||
869 | err |= MRVL88X2011_LOOPBACK; | ||
870 | else | ||
871 | err &= ~MRVL88X2011_LOOPBACK; | ||
872 | |||
873 | err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, | ||
874 | MRVL88X2011_PMA_PMD_CTL_1, err); | ||
875 | if (err < 0) | ||
876 | return err; | ||
877 | |||
878 | /* Enable PMD */ | ||
879 | return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, | ||
880 | MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX); | ||
881 | } | ||
882 | |||
883 | static int xcvr_init_10g_bcm8704(struct niu *np) | ||
805 | { | 884 | { |
806 | struct niu_link_config *lp = &np->link_config; | 885 | struct niu_link_config *lp = &np->link_config; |
807 | u16 analog_stat0, tx_alarm_status; | 886 | u16 analog_stat0, tx_alarm_status; |
808 | int err; | 887 | int err; |
809 | u64 val; | ||
810 | |||
811 | val = nr64_mac(XMAC_CONFIG); | ||
812 | val &= ~XMAC_CONFIG_LED_POLARITY; | ||
813 | val |= XMAC_CONFIG_FORCE_LED_ON; | ||
814 | nw64_mac(XMAC_CONFIG, val); | ||
815 | |||
816 | /* XXX shared resource, lock parent XXX */ | ||
817 | val = nr64(MIF_CONFIG); | ||
818 | val |= MIF_CONFIG_INDIRECT_MODE; | ||
819 | nw64(MIF_CONFIG, val); | ||
820 | 888 | ||
821 | err = bcm8704_reset(np); | 889 | err = bcm8704_reset(np); |
822 | if (err) | 890 | if (err) |
@@ -896,6 +964,38 @@ static int xcvr_init_10g(struct niu *np) | |||
896 | return 0; | 964 | return 0; |
897 | } | 965 | } |
898 | 966 | ||
967 | static int xcvr_init_10g(struct niu *np) | ||
968 | { | ||
969 | int phy_id, err; | ||
970 | u64 val; | ||
971 | |||
972 | val = nr64_mac(XMAC_CONFIG); | ||
973 | val &= ~XMAC_CONFIG_LED_POLARITY; | ||
974 | val |= XMAC_CONFIG_FORCE_LED_ON; | ||
975 | nw64_mac(XMAC_CONFIG, val); | ||
976 | |||
977 | /* XXX shared resource, lock parent XXX */ | ||
978 | val = nr64(MIF_CONFIG); | ||
979 | val |= MIF_CONFIG_INDIRECT_MODE; | ||
980 | nw64(MIF_CONFIG, val); | ||
981 | |||
982 | phy_id = phy_decode(np->parent->port_phy, np->port); | ||
983 | phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port]; | ||
984 | |||
985 | /* handle different phy types */ | ||
986 | switch (phy_id & NIU_PHY_ID_MASK) { | ||
987 | case NIU_PHY_ID_MRVL88X2011: | ||
988 | err = xcvr_init_10g_mrvl88x2011(np); | ||
989 | break; | ||
990 | |||
991 | default: /* bcom 8704 */ | ||
992 | err = xcvr_init_10g_bcm8704(np); | ||
993 | break; | ||
994 | } | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
899 | static int mii_reset(struct niu *np) | 999 | static int mii_reset(struct niu *np) |
900 | { | 1000 | { |
901 | int limit, err; | 1001 | int limit, err; |
@@ -1082,19 +1182,68 @@ static int niu_link_status_common(struct niu *np, int link_up) | |||
1082 | return 0; | 1182 | return 0; |
1083 | } | 1183 | } |
1084 | 1184 | ||
1085 | static int link_status_10g(struct niu *np, int *link_up_p) | 1185 | static int link_status_10g_mrvl(struct niu *np, int *link_up_p) |
1086 | { | 1186 | { |
1087 | unsigned long flags; | 1187 | int err, link_up, pma_status, pcs_status; |
1088 | int err, link_up; | ||
1089 | 1188 | ||
1090 | link_up = 0; | 1189 | link_up = 0; |
1091 | 1190 | ||
1092 | spin_lock_irqsave(&np->lock, flags); | 1191 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, |
1192 | MRVL88X2011_10G_PMD_STATUS_2); | ||
1193 | if (err < 0) | ||
1194 | goto out; | ||
1093 | 1195 | ||
1094 | err = -EINVAL; | 1196 | /* Check PMA/PMD Register: 1.0001.2 == 1 */ |
1095 | if (np->link_config.loopback_mode != LOOPBACK_DISABLED) | 1197 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR, |
1198 | MRVL88X2011_PMA_PMD_STATUS_1); | ||
1199 | if (err < 0) | ||
1200 | goto out; | ||
1201 | |||
1202 | pma_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0); | ||
1203 | |||
1204 | /* Check PMC Register : 3.0001.2 == 1: read twice */ | ||
1205 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, | ||
1206 | MRVL88X2011_PMA_PMD_STATUS_1); | ||
1207 | if (err < 0) | ||
1208 | goto out; | ||
1209 | |||
1210 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR, | ||
1211 | MRVL88X2011_PMA_PMD_STATUS_1); | ||
1212 | if (err < 0) | ||
1213 | goto out; | ||
1214 | |||
1215 | pcs_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0); | ||
1216 | |||
1217 | /* Check XGXS Register : 4.0018.[0-3,12] */ | ||
1218 | err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV4_ADDR, | ||
1219 | MRVL88X2011_10G_XGXS_LANE_STAT); | ||
1220 | if (err < 0) | ||
1096 | goto out; | 1221 | goto out; |
1097 | 1222 | ||
1223 | if (err == (PHYXS_XGXS_LANE_STAT_ALINGED | PHYXS_XGXS_LANE_STAT_LANE3 | | ||
1224 | PHYXS_XGXS_LANE_STAT_LANE2 | PHYXS_XGXS_LANE_STAT_LANE1 | | ||
1225 | PHYXS_XGXS_LANE_STAT_LANE0 | PHYXS_XGXS_LANE_STAT_MAGIC | | ||
1226 | 0x800)) | ||
1227 | link_up = (pma_status && pcs_status) ? 1 : 0; | ||
1228 | |||
1229 | np->link_config.active_speed = SPEED_10000; | ||
1230 | np->link_config.active_duplex = DUPLEX_FULL; | ||
1231 | err = 0; | ||
1232 | out: | ||
1233 | mrvl88x2011_act_led(np, (link_up ? | ||
1234 | MRVL88X2011_LED_CTL_PCS_ACT : | ||
1235 | MRVL88X2011_LED_CTL_OFF)); | ||
1236 | |||
1237 | *link_up_p = link_up; | ||
1238 | return err; | ||
1239 | } | ||
1240 | |||
1241 | static int link_status_10g_bcom(struct niu *np, int *link_up_p) | ||
1242 | { | ||
1243 | int err, link_up; | ||
1244 | |||
1245 | link_up = 0; | ||
1246 | |||
1098 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, | 1247 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, |
1099 | BCM8704_PMD_RCV_SIGDET); | 1248 | BCM8704_PMD_RCV_SIGDET); |
1100 | if (err < 0) | 1249 | if (err < 0) |
@@ -1134,9 +1283,37 @@ static int link_status_10g(struct niu *np, int *link_up_p) | |||
1134 | err = 0; | 1283 | err = 0; |
1135 | 1284 | ||
1136 | out: | 1285 | out: |
1286 | *link_up_p = link_up; | ||
1287 | return err; | ||
1288 | } | ||
1289 | |||
1290 | static int link_status_10g(struct niu *np, int *link_up_p) | ||
1291 | { | ||
1292 | unsigned long flags; | ||
1293 | int err = -EINVAL; | ||
1294 | |||
1295 | spin_lock_irqsave(&np->lock, flags); | ||
1296 | |||
1297 | if (np->link_config.loopback_mode == LOOPBACK_DISABLED) { | ||
1298 | int phy_id; | ||
1299 | |||
1300 | phy_id = phy_decode(np->parent->port_phy, np->port); | ||
1301 | phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port]; | ||
1302 | |||
1303 | /* handle different phy types */ | ||
1304 | switch (phy_id & NIU_PHY_ID_MASK) { | ||
1305 | case NIU_PHY_ID_MRVL88X2011: | ||
1306 | err = link_status_10g_mrvl(np, link_up_p); | ||
1307 | break; | ||
1308 | |||
1309 | default: /* bcom 8704 */ | ||
1310 | err = link_status_10g_bcom(np, link_up_p); | ||
1311 | break; | ||
1312 | } | ||
1313 | } | ||
1314 | |||
1137 | spin_unlock_irqrestore(&np->lock, flags); | 1315 | spin_unlock_irqrestore(&np->lock, flags); |
1138 | 1316 | ||
1139 | *link_up_p = link_up; | ||
1140 | return err; | 1317 | return err; |
1141 | } | 1318 | } |
1142 | 1319 | ||
@@ -6297,7 +6474,8 @@ static int __devinit phy_record(struct niu_parent *parent, | |||
6297 | if (dev_id_1 < 0 || dev_id_2 < 0) | 6474 | if (dev_id_1 < 0 || dev_id_2 < 0) |
6298 | return 0; | 6475 | return 0; |
6299 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { | 6476 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { |
6300 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) | 6477 | if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) && |
6478 | ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011)) | ||
6301 | return 0; | 6479 | return 0; |
6302 | } else { | 6480 | } else { |
6303 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) | 6481 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) |