diff options
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 264 |
1 files changed, 230 insertions, 34 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index abfc61c3a38c..5f6beabf2d17 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -33,8 +33,8 @@ | |||
33 | 33 | ||
34 | #define DRV_MODULE_NAME "niu" | 34 | #define DRV_MODULE_NAME "niu" |
35 | #define PFX DRV_MODULE_NAME ": " | 35 | #define PFX DRV_MODULE_NAME ": " |
36 | #define DRV_MODULE_VERSION "0.5" | 36 | #define DRV_MODULE_VERSION "0.6" |
37 | #define DRV_MODULE_RELDATE "October 5, 2007" | 37 | #define DRV_MODULE_RELDATE "January 5, 2008" |
38 | 38 | ||
39 | static char version[] __devinitdata = | 39 | static char version[] __devinitdata = |
40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
@@ -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) | ||
1096 | goto out; | 1213 | goto out; |
1097 | 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) | ||
1221 | goto out; | ||
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,14 +1283,43 @@ 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 | ||
1143 | static int link_status_1g(struct niu *np, int *link_up_p) | 1320 | static int link_status_1g(struct niu *np, int *link_up_p) |
1144 | { | 1321 | { |
1322 | struct niu_link_config *lp = &np->link_config; | ||
1145 | u16 current_speed, bmsr; | 1323 | u16 current_speed, bmsr; |
1146 | unsigned long flags; | 1324 | unsigned long flags; |
1147 | u8 current_duplex; | 1325 | u8 current_duplex; |
@@ -1209,6 +1387,8 @@ static int link_status_1g(struct niu *np, int *link_up_p) | |||
1209 | link_up = 0; | 1387 | link_up = 0; |
1210 | } | 1388 | } |
1211 | } | 1389 | } |
1390 | lp->active_speed = current_speed; | ||
1391 | lp->active_duplex = current_duplex; | ||
1212 | err = 0; | 1392 | err = 0; |
1213 | 1393 | ||
1214 | out: | 1394 | out: |
@@ -2241,6 +2421,8 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) | |||
2241 | skb->protocol = eth_type_trans(skb, np->dev); | 2421 | skb->protocol = eth_type_trans(skb, np->dev); |
2242 | netif_receive_skb(skb); | 2422 | netif_receive_skb(skb); |
2243 | 2423 | ||
2424 | np->dev->last_rx = jiffies; | ||
2425 | |||
2244 | return num_rcr; | 2426 | return num_rcr; |
2245 | } | 2427 | } |
2246 | 2428 | ||
@@ -2508,15 +2690,19 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) | |||
2508 | u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); | 2690 | u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); |
2509 | int err = 0; | 2691 | int err = 0; |
2510 | 2692 | ||
2511 | dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", | ||
2512 | np->dev->name, rp->rx_channel, (unsigned long long) stat); | ||
2513 | |||
2514 | niu_log_rxchan_errors(np, rp, stat); | ||
2515 | 2693 | ||
2516 | if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | | 2694 | if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | |
2517 | RX_DMA_CTL_STAT_PORT_FATAL)) | 2695 | RX_DMA_CTL_STAT_PORT_FATAL)) |
2518 | err = -EINVAL; | 2696 | err = -EINVAL; |
2519 | 2697 | ||
2698 | if (err) { | ||
2699 | dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", | ||
2700 | np->dev->name, rp->rx_channel, | ||
2701 | (unsigned long long) stat); | ||
2702 | |||
2703 | niu_log_rxchan_errors(np, rp, stat); | ||
2704 | } | ||
2705 | |||
2520 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), | 2706 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), |
2521 | stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); | 2707 | stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); |
2522 | 2708 | ||
@@ -2749,13 +2935,16 @@ static int niu_device_error(struct niu *np) | |||
2749 | return -ENODEV; | 2935 | return -ENODEV; |
2750 | } | 2936 | } |
2751 | 2937 | ||
2752 | static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | 2938 | static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp, |
2939 | u64 v0, u64 v1, u64 v2) | ||
2753 | { | 2940 | { |
2754 | u64 v0 = lp->v0; | 2941 | |
2755 | u64 v1 = lp->v1; | ||
2756 | u64 v2 = lp->v2; | ||
2757 | int i, err = 0; | 2942 | int i, err = 0; |
2758 | 2943 | ||
2944 | lp->v0 = v0; | ||
2945 | lp->v1 = v1; | ||
2946 | lp->v2 = v2; | ||
2947 | |||
2759 | if (v1 & 0x00000000ffffffffULL) { | 2948 | if (v1 & 0x00000000ffffffffULL) { |
2760 | u32 rx_vec = (v1 & 0xffffffff); | 2949 | u32 rx_vec = (v1 & 0xffffffff); |
2761 | 2950 | ||
@@ -2764,8 +2953,13 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | |||
2764 | 2953 | ||
2765 | if (rx_vec & (1 << rp->rx_channel)) { | 2954 | if (rx_vec & (1 << rp->rx_channel)) { |
2766 | int r = niu_rx_error(np, rp); | 2955 | int r = niu_rx_error(np, rp); |
2767 | if (r) | 2956 | if (r) { |
2768 | err = r; | 2957 | err = r; |
2958 | } else { | ||
2959 | if (!v0) | ||
2960 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), | ||
2961 | RX_DMA_CTL_STAT_MEX); | ||
2962 | } | ||
2769 | } | 2963 | } |
2770 | } | 2964 | } |
2771 | } | 2965 | } |
@@ -2803,7 +2997,7 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | |||
2803 | if (err) | 2997 | if (err) |
2804 | niu_enable_interrupts(np, 0); | 2998 | niu_enable_interrupts(np, 0); |
2805 | 2999 | ||
2806 | return -EINVAL; | 3000 | return err; |
2807 | } | 3001 | } |
2808 | 3002 | ||
2809 | static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, | 3003 | static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, |
@@ -2905,7 +3099,7 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id) | |||
2905 | } | 3099 | } |
2906 | 3100 | ||
2907 | if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { | 3101 | if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { |
2908 | int err = niu_slowpath_interrupt(np, lp); | 3102 | int err = niu_slowpath_interrupt(np, lp, v0, v1, v2); |
2909 | if (err) | 3103 | if (err) |
2910 | goto out; | 3104 | goto out; |
2911 | } | 3105 | } |
@@ -5194,7 +5388,8 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
5194 | } | 5388 | } |
5195 | kfree_skb(skb); | 5389 | kfree_skb(skb); |
5196 | skb = skb_new; | 5390 | skb = skb_new; |
5197 | } | 5391 | } else |
5392 | skb_orphan(skb); | ||
5198 | 5393 | ||
5199 | align = ((unsigned long) skb->data & (16 - 1)); | 5394 | align = ((unsigned long) skb->data & (16 - 1)); |
5200 | headroom = align + sizeof(struct tx_pkt_hdr); | 5395 | headroom = align + sizeof(struct tx_pkt_hdr); |
@@ -6282,7 +6477,8 @@ static int __devinit phy_record(struct niu_parent *parent, | |||
6282 | if (dev_id_1 < 0 || dev_id_2 < 0) | 6477 | if (dev_id_1 < 0 || dev_id_2 < 0) |
6283 | return 0; | 6478 | return 0; |
6284 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { | 6479 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { |
6285 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) | 6480 | if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) && |
6481 | ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011)) | ||
6286 | return 0; | 6482 | return 0; |
6287 | } else { | 6483 | } else { |
6288 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) | 6484 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) |