diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-09-24 00:25:28 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-25 20:04:29 -0400 |
commit | 64f6b64dfb8cdda21652f24a0fb0a68e2f0b0022 (patch) | |
tree | e1706db57e1a1b4c65884c9b79a7f9d4e0e2ae7c /drivers | |
parent | 46798c897e235e71e1e9c46a5e6e9adfffd8b85d (diff) |
[PATCH] skge: fiber support
Add support for older fiber versions of the SysKonnect board. These chipsets
use an internal PHY so they require special handling. The older sk98lin
driver already supported these
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/skge.c | 357 | ||||
-rw-r--r-- | drivers/net/skge.h | 37 |
2 files changed, 301 insertions, 93 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 9142d91355bc..705e9a8fa30f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #define TX_WATCHDOG (5 * HZ) | 58 | #define TX_WATCHDOG (5 * HZ) |
59 | #define NAPI_WEIGHT 64 | 59 | #define NAPI_WEIGHT 64 |
60 | #define BLINK_MS 250 | 60 | #define BLINK_MS 250 |
61 | #define LINK_HZ (HZ/2) | ||
61 | 62 | ||
62 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); | 63 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); |
63 | MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); | 64 | MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); |
@@ -605,7 +606,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
605 | if (hw->chip_id == CHIP_ID_GENESIS) { | 606 | if (hw->chip_id == CHIP_ID_GENESIS) { |
606 | switch (mode) { | 607 | switch (mode) { |
607 | case LED_MODE_OFF: | 608 | case LED_MODE_OFF: |
608 | xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); | 609 | if (hw->phy_type == SK_PHY_BCOM) |
610 | xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); | ||
611 | else { | ||
612 | skge_write32(hw, SK_REG(port, TX_LED_VAL), 0); | ||
613 | skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF); | ||
614 | } | ||
609 | skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); | 615 | skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); |
610 | skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); | 616 | skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); |
611 | skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); | 617 | skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); |
@@ -625,8 +631,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
625 | skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); | 631 | skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); |
626 | skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); | 632 | skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); |
627 | 633 | ||
628 | xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); | 634 | if (hw->phy_type == SK_PHY_BCOM) |
629 | break; | 635 | xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); |
636 | else { | ||
637 | skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON); | ||
638 | skge_write32(hw, SK_REG(port, TX_LED_VAL), 100); | ||
639 | skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); | ||
640 | } | ||
641 | |||
630 | } | 642 | } |
631 | } else { | 643 | } else { |
632 | switch (mode) { | 644 | switch (mode) { |
@@ -879,6 +891,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) | |||
879 | xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); | 891 | xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); |
880 | *val = xm_read16(hw, port, XM_PHY_DATA); | 892 | *val = xm_read16(hw, port, XM_PHY_DATA); |
881 | 893 | ||
894 | if (hw->phy_type == SK_PHY_XMAC) | ||
895 | goto ready; | ||
896 | |||
882 | for (i = 0; i < PHY_RETRIES; i++) { | 897 | for (i = 0; i < PHY_RETRIES; i++) { |
883 | if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) | 898 | if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) |
884 | goto ready; | 899 | goto ready; |
@@ -965,7 +980,8 @@ static void genesis_reset(struct skge_hw *hw, int port) | |||
965 | xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ | 980 | xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ |
966 | 981 | ||
967 | /* disable Broadcom PHY IRQ */ | 982 | /* disable Broadcom PHY IRQ */ |
968 | xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); | 983 | if (hw->phy_type == SK_PHY_BCOM) |
984 | xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); | ||
969 | 985 | ||
970 | xm_outhash(hw, port, XM_HSM, zero); | 986 | xm_outhash(hw, port, XM_HSM, zero); |
971 | } | 987 | } |
@@ -1000,60 +1016,64 @@ static void bcom_check_link(struct skge_hw *hw, int port) | |||
1000 | 1016 | ||
1001 | if (netif_carrier_ok(dev)) | 1017 | if (netif_carrier_ok(dev)) |
1002 | skge_link_down(skge); | 1018 | skge_link_down(skge); |
1003 | } else { | 1019 | return; |
1004 | if (skge->autoneg == AUTONEG_ENABLE && | 1020 | } |
1005 | (status & PHY_ST_AN_OVER)) { | ||
1006 | u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP); | ||
1007 | u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); | ||
1008 | |||
1009 | if (lpa & PHY_B_AN_RF) { | ||
1010 | printk(KERN_NOTICE PFX "%s: remote fault\n", | ||
1011 | dev->name); | ||
1012 | return; | ||
1013 | } | ||
1014 | 1021 | ||
1015 | /* Check Duplex mismatch */ | 1022 | if (skge->autoneg == AUTONEG_ENABLE) { |
1016 | switch (aux & PHY_B_AS_AN_RES_MSK) { | 1023 | u16 lpa, aux; |
1017 | case PHY_B_RES_1000FD: | ||
1018 | skge->duplex = DUPLEX_FULL; | ||
1019 | break; | ||
1020 | case PHY_B_RES_1000HD: | ||
1021 | skge->duplex = DUPLEX_HALF; | ||
1022 | break; | ||
1023 | default: | ||
1024 | printk(KERN_NOTICE PFX "%s: duplex mismatch\n", | ||
1025 | dev->name); | ||
1026 | return; | ||
1027 | } | ||
1028 | 1024 | ||
1025 | if (!(status & PHY_ST_AN_OVER)) | ||
1026 | return; | ||
1029 | 1027 | ||
1030 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | 1028 | lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); |
1031 | switch (aux & PHY_B_AS_PAUSE_MSK) { | 1029 | if (lpa & PHY_B_AN_RF) { |
1032 | case PHY_B_AS_PAUSE_MSK: | 1030 | printk(KERN_NOTICE PFX "%s: remote fault\n", |
1033 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 1031 | dev->name); |
1034 | break; | 1032 | return; |
1035 | case PHY_B_AS_PRR: | 1033 | } |
1036 | skge->flow_control = FLOW_MODE_REM_SEND; | ||
1037 | break; | ||
1038 | case PHY_B_AS_PRT: | ||
1039 | skge->flow_control = FLOW_MODE_LOC_SEND; | ||
1040 | break; | ||
1041 | default: | ||
1042 | skge->flow_control = FLOW_MODE_NONE; | ||
1043 | } | ||
1044 | 1034 | ||
1045 | skge->speed = SPEED_1000; | 1035 | aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); |
1036 | |||
1037 | /* Check Duplex mismatch */ | ||
1038 | switch (aux & PHY_B_AS_AN_RES_MSK) { | ||
1039 | case PHY_B_RES_1000FD: | ||
1040 | skge->duplex = DUPLEX_FULL; | ||
1041 | break; | ||
1042 | case PHY_B_RES_1000HD: | ||
1043 | skge->duplex = DUPLEX_HALF; | ||
1044 | break; | ||
1045 | default: | ||
1046 | printk(KERN_NOTICE PFX "%s: duplex mismatch\n", | ||
1047 | dev->name); | ||
1048 | return; | ||
1046 | } | 1049 | } |
1047 | 1050 | ||
1048 | if (!netif_carrier_ok(dev)) | 1051 | |
1049 | genesis_link_up(skge); | 1052 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ |
1053 | switch (aux & PHY_B_AS_PAUSE_MSK) { | ||
1054 | case PHY_B_AS_PAUSE_MSK: | ||
1055 | skge->flow_control = FLOW_MODE_SYMMETRIC; | ||
1056 | break; | ||
1057 | case PHY_B_AS_PRR: | ||
1058 | skge->flow_control = FLOW_MODE_REM_SEND; | ||
1059 | break; | ||
1060 | case PHY_B_AS_PRT: | ||
1061 | skge->flow_control = FLOW_MODE_LOC_SEND; | ||
1062 | break; | ||
1063 | default: | ||
1064 | skge->flow_control = FLOW_MODE_NONE; | ||
1065 | } | ||
1066 | skge->speed = SPEED_1000; | ||
1050 | } | 1067 | } |
1068 | |||
1069 | if (!netif_carrier_ok(dev)) | ||
1070 | genesis_link_up(skge); | ||
1051 | } | 1071 | } |
1052 | 1072 | ||
1053 | /* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional | 1073 | /* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional |
1054 | * Phy on for 100 or 10Mbit operation | 1074 | * Phy on for 100 or 10Mbit operation |
1055 | */ | 1075 | */ |
1056 | static void bcom_phy_init(struct skge_port *skge, int jumbo) | 1076 | static void bcom_phy_init(struct skge_port *skge) |
1057 | { | 1077 | { |
1058 | struct skge_hw *hw = skge->hw; | 1078 | struct skge_hw *hw = skge->hw; |
1059 | int port = skge->port; | 1079 | int port = skge->port; |
@@ -1144,7 +1164,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) | |||
1144 | phy_pause_map[skge->flow_control] | PHY_AN_CSMA); | 1164 | phy_pause_map[skge->flow_control] | PHY_AN_CSMA); |
1145 | 1165 | ||
1146 | /* Handle Jumbo frames */ | 1166 | /* Handle Jumbo frames */ |
1147 | if (jumbo) { | 1167 | if (hw->dev[port]->mtu > ETH_DATA_LEN) { |
1148 | xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, | 1168 | xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, |
1149 | PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); | 1169 | PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); |
1150 | 1170 | ||
@@ -1157,8 +1177,154 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) | |||
1157 | 1177 | ||
1158 | /* Use link status change interrupt */ | 1178 | /* Use link status change interrupt */ |
1159 | xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); | 1179 | xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); |
1180 | } | ||
1160 | 1181 | ||
1161 | bcom_check_link(hw, port); | 1182 | static void xm_phy_init(struct skge_port *skge) |
1183 | { | ||
1184 | struct skge_hw *hw = skge->hw; | ||
1185 | int port = skge->port; | ||
1186 | u16 ctrl = 0; | ||
1187 | |||
1188 | if (skge->autoneg == AUTONEG_ENABLE) { | ||
1189 | if (skge->advertising & ADVERTISED_1000baseT_Half) | ||
1190 | ctrl |= PHY_X_AN_HD; | ||
1191 | if (skge->advertising & ADVERTISED_1000baseT_Full) | ||
1192 | ctrl |= PHY_X_AN_FD; | ||
1193 | |||
1194 | switch(skge->flow_control) { | ||
1195 | case FLOW_MODE_NONE: | ||
1196 | ctrl |= PHY_X_P_NO_PAUSE; | ||
1197 | break; | ||
1198 | case FLOW_MODE_LOC_SEND: | ||
1199 | ctrl |= PHY_X_P_ASYM_MD; | ||
1200 | break; | ||
1201 | case FLOW_MODE_SYMMETRIC: | ||
1202 | ctrl |= PHY_X_P_BOTH_MD; | ||
1203 | break; | ||
1204 | } | ||
1205 | |||
1206 | xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); | ||
1207 | |||
1208 | /* Restart Auto-negotiation */ | ||
1209 | ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; | ||
1210 | } else { | ||
1211 | /* Set DuplexMode in Config register */ | ||
1212 | if (skge->duplex == DUPLEX_FULL) | ||
1213 | ctrl |= PHY_CT_DUP_MD; | ||
1214 | /* | ||
1215 | * Do NOT enable Auto-negotiation here. This would hold | ||
1216 | * the link down because no IDLEs are transmitted | ||
1217 | */ | ||
1218 | } | ||
1219 | |||
1220 | xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); | ||
1221 | |||
1222 | /* Poll PHY for status changes */ | ||
1223 | schedule_delayed_work(&skge->link_thread, LINK_HZ); | ||
1224 | } | ||
1225 | |||
1226 | static void xm_check_link(struct net_device *dev) | ||
1227 | { | ||
1228 | struct skge_port *skge = netdev_priv(dev); | ||
1229 | struct skge_hw *hw = skge->hw; | ||
1230 | int port = skge->port; | ||
1231 | u16 status; | ||
1232 | |||
1233 | /* read twice because of latch */ | ||
1234 | (void) xm_phy_read(hw, port, PHY_XMAC_STAT); | ||
1235 | status = xm_phy_read(hw, port, PHY_XMAC_STAT); | ||
1236 | |||
1237 | if ((status & PHY_ST_LSYNC) == 0) { | ||
1238 | u16 cmd = xm_read16(hw, port, XM_MMU_CMD); | ||
1239 | cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); | ||
1240 | xm_write16(hw, port, XM_MMU_CMD, cmd); | ||
1241 | /* dummy read to ensure writing */ | ||
1242 | (void) xm_read16(hw, port, XM_MMU_CMD); | ||
1243 | |||
1244 | if (netif_carrier_ok(dev)) | ||
1245 | skge_link_down(skge); | ||
1246 | return; | ||
1247 | } | ||
1248 | |||
1249 | if (skge->autoneg == AUTONEG_ENABLE) { | ||
1250 | u16 lpa, res; | ||
1251 | |||
1252 | if (!(status & PHY_ST_AN_OVER)) | ||
1253 | return; | ||
1254 | |||
1255 | lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); | ||
1256 | if (lpa & PHY_B_AN_RF) { | ||
1257 | printk(KERN_NOTICE PFX "%s: remote fault\n", | ||
1258 | dev->name); | ||
1259 | return; | ||
1260 | } | ||
1261 | |||
1262 | res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); | ||
1263 | |||
1264 | /* Check Duplex mismatch */ | ||
1265 | switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) { | ||
1266 | case PHY_X_RS_FD: | ||
1267 | skge->duplex = DUPLEX_FULL; | ||
1268 | break; | ||
1269 | case PHY_X_RS_HD: | ||
1270 | skge->duplex = DUPLEX_HALF; | ||
1271 | break; | ||
1272 | default: | ||
1273 | printk(KERN_NOTICE PFX "%s: duplex mismatch\n", | ||
1274 | dev->name); | ||
1275 | return; | ||
1276 | } | ||
1277 | |||
1278 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | ||
1279 | if (lpa & PHY_X_P_SYM_MD) | ||
1280 | skge->flow_control = FLOW_MODE_SYMMETRIC; | ||
1281 | else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) | ||
1282 | skge->flow_control = FLOW_MODE_REM_SEND; | ||
1283 | else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) | ||
1284 | skge->flow_control = FLOW_MODE_LOC_SEND; | ||
1285 | else | ||
1286 | skge->flow_control = FLOW_MODE_NONE; | ||
1287 | |||
1288 | |||
1289 | skge->speed = SPEED_1000; | ||
1290 | } | ||
1291 | |||
1292 | if (!netif_carrier_ok(dev)) | ||
1293 | genesis_link_up(skge); | ||
1294 | } | ||
1295 | |||
1296 | /* Poll to check for link coming up. | ||
1297 | * Since internal PHY is wired to a level triggered pin, can't | ||
1298 | * get an interrupt when carrier is detected. | ||
1299 | */ | ||
1300 | static void xm_link_timer(void *arg) | ||
1301 | { | ||
1302 | struct net_device *dev = arg; | ||
1303 | struct skge_port *skge = netdev_priv(arg); | ||
1304 | struct skge_hw *hw = skge->hw; | ||
1305 | int port = skge->port; | ||
1306 | |||
1307 | if (!netif_running(dev)) | ||
1308 | return; | ||
1309 | |||
1310 | if (netif_carrier_ok(dev)) { | ||
1311 | xm_read16(hw, port, XM_ISRC); | ||
1312 | if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) | ||
1313 | goto nochange; | ||
1314 | } else { | ||
1315 | if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) | ||
1316 | goto nochange; | ||
1317 | xm_read16(hw, port, XM_ISRC); | ||
1318 | if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) | ||
1319 | goto nochange; | ||
1320 | } | ||
1321 | |||
1322 | mutex_lock(&hw->phy_mutex); | ||
1323 | xm_check_link(dev); | ||
1324 | mutex_unlock(&hw->phy_mutex); | ||
1325 | |||
1326 | nochange: | ||
1327 | schedule_delayed_work(&skge->link_thread, LINK_HZ); | ||
1162 | } | 1328 | } |
1163 | 1329 | ||
1164 | static void genesis_mac_init(struct skge_hw *hw, int port) | 1330 | static void genesis_mac_init(struct skge_hw *hw, int port) |
@@ -1189,20 +1355,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port) | |||
1189 | * namely for the 1000baseTX cards that use the XMAC's | 1355 | * namely for the 1000baseTX cards that use the XMAC's |
1190 | * GMII mode. | 1356 | * GMII mode. |
1191 | */ | 1357 | */ |
1192 | /* Take external Phy out of reset */ | 1358 | if (hw->phy_type != SK_PHY_XMAC) { |
1193 | r = skge_read32(hw, B2_GP_IO); | 1359 | /* Take external Phy out of reset */ |
1194 | if (port == 0) | 1360 | r = skge_read32(hw, B2_GP_IO); |
1195 | r |= GP_DIR_0|GP_IO_0; | 1361 | if (port == 0) |
1196 | else | 1362 | r |= GP_DIR_0|GP_IO_0; |
1197 | r |= GP_DIR_2|GP_IO_2; | 1363 | else |
1364 | r |= GP_DIR_2|GP_IO_2; | ||
1198 | 1365 | ||
1199 | skge_write32(hw, B2_GP_IO, r); | 1366 | skge_write32(hw, B2_GP_IO, r); |
1200 | 1367 | ||
1368 | /* Enable GMII interface */ | ||
1369 | xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); | ||
1370 | } | ||
1201 | 1371 | ||
1202 | /* Enable GMII interface */ | ||
1203 | xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); | ||
1204 | 1372 | ||
1205 | bcom_phy_init(skge, jumbo); | 1373 | switch(hw->phy_type) { |
1374 | case SK_PHY_XMAC: | ||
1375 | xm_phy_init(skge); | ||
1376 | break; | ||
1377 | case SK_PHY_BCOM: | ||
1378 | bcom_phy_init(skge); | ||
1379 | bcom_check_link(hw, port); | ||
1380 | } | ||
1206 | 1381 | ||
1207 | /* Set Station Address */ | 1382 | /* Set Station Address */ |
1208 | xm_outaddr(hw, port, XM_SA, dev->dev_addr); | 1383 | xm_outaddr(hw, port, XM_SA, dev->dev_addr); |
@@ -1335,16 +1510,18 @@ static void genesis_stop(struct skge_port *skge) | |||
1335 | skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); | 1510 | skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); |
1336 | 1511 | ||
1337 | /* For external PHYs there must be special handling */ | 1512 | /* For external PHYs there must be special handling */ |
1338 | reg = skge_read32(hw, B2_GP_IO); | 1513 | if (hw->phy_type != SK_PHY_XMAC) { |
1339 | if (port == 0) { | 1514 | reg = skge_read32(hw, B2_GP_IO); |
1340 | reg |= GP_DIR_0; | 1515 | if (port == 0) { |
1341 | reg &= ~GP_IO_0; | 1516 | reg |= GP_DIR_0; |
1342 | } else { | 1517 | reg &= ~GP_IO_0; |
1343 | reg |= GP_DIR_2; | 1518 | } else { |
1344 | reg &= ~GP_IO_2; | 1519 | reg |= GP_DIR_2; |
1520 | reg &= ~GP_IO_2; | ||
1521 | } | ||
1522 | skge_write32(hw, B2_GP_IO, reg); | ||
1523 | skge_read32(hw, B2_GP_IO); | ||
1345 | } | 1524 | } |
1346 | skge_write32(hw, B2_GP_IO, reg); | ||
1347 | skge_read32(hw, B2_GP_IO); | ||
1348 | 1525 | ||
1349 | xm_write16(hw, port, XM_MMU_CMD, | 1526 | xm_write16(hw, port, XM_MMU_CMD, |
1350 | xm_read16(hw, port, XM_MMU_CMD) | 1527 | xm_read16(hw, port, XM_MMU_CMD) |
@@ -1406,7 +1583,7 @@ static void genesis_link_up(struct skge_port *skge) | |||
1406 | struct skge_hw *hw = skge->hw; | 1583 | struct skge_hw *hw = skge->hw; |
1407 | int port = skge->port; | 1584 | int port = skge->port; |
1408 | u16 cmd; | 1585 | u16 cmd; |
1409 | u32 mode, msk; | 1586 | u32 mode; |
1410 | 1587 | ||
1411 | cmd = xm_read16(hw, port, XM_MMU_CMD); | 1588 | cmd = xm_read16(hw, port, XM_MMU_CMD); |
1412 | 1589 | ||
@@ -1454,27 +1631,24 @@ static void genesis_link_up(struct skge_port *skge) | |||
1454 | } | 1631 | } |
1455 | 1632 | ||
1456 | xm_write32(hw, port, XM_MODE, mode); | 1633 | xm_write32(hw, port, XM_MODE, mode); |
1457 | 1634 | xm_write16(hw, port, XM_IMSK, XM_DEF_MSK); | |
1458 | msk = XM_DEF_MSK; | ||
1459 | /* disable GP0 interrupt bit for external Phy */ | ||
1460 | msk |= XM_IS_INP_ASS; | ||
1461 | |||
1462 | xm_write16(hw, port, XM_IMSK, msk); | ||
1463 | xm_read16(hw, port, XM_ISRC); | 1635 | xm_read16(hw, port, XM_ISRC); |
1464 | 1636 | ||
1465 | /* get MMU Command Reg. */ | 1637 | /* get MMU Command Reg. */ |
1466 | cmd = xm_read16(hw, port, XM_MMU_CMD); | 1638 | cmd = xm_read16(hw, port, XM_MMU_CMD); |
1467 | if (skge->duplex == DUPLEX_FULL) | 1639 | if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) |
1468 | cmd |= XM_MMU_GMII_FD; | 1640 | cmd |= XM_MMU_GMII_FD; |
1469 | 1641 | ||
1470 | /* | 1642 | /* |
1471 | * Workaround BCOM Errata (#10523) for all BCom Phys | 1643 | * Workaround BCOM Errata (#10523) for all BCom Phys |
1472 | * Enable Power Management after link up | 1644 | * Enable Power Management after link up |
1473 | */ | 1645 | */ |
1474 | xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, | 1646 | if (hw->phy_type == SK_PHY_BCOM) { |
1475 | xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) | 1647 | xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, |
1476 | & ~PHY_B_AC_DIS_PM); | 1648 | xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) |
1477 | xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); | 1649 | & ~PHY_B_AC_DIS_PM); |
1650 | xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); | ||
1651 | } | ||
1478 | 1652 | ||
1479 | /* enable Rx/Tx */ | 1653 | /* enable Rx/Tx */ |
1480 | xm_write16(hw, port, XM_MMU_CMD, | 1654 | xm_write16(hw, port, XM_MMU_CMD, |
@@ -2240,6 +2414,8 @@ static int skge_down(struct net_device *dev) | |||
2240 | printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); | 2414 | printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); |
2241 | 2415 | ||
2242 | netif_stop_queue(dev); | 2416 | netif_stop_queue(dev); |
2417 | if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) | ||
2418 | cancel_rearming_delayed_work(&skge->link_thread); | ||
2243 | 2419 | ||
2244 | skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); | 2420 | skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); |
2245 | if (hw->chip_id == CHIP_ID_GENESIS) | 2421 | if (hw->chip_id == CHIP_ID_GENESIS) |
@@ -2862,7 +3038,7 @@ static void skge_extirq(void *arg) | |||
2862 | if (netif_running(dev)) { | 3038 | if (netif_running(dev)) { |
2863 | if (hw->chip_id != CHIP_ID_GENESIS) | 3039 | if (hw->chip_id != CHIP_ID_GENESIS) |
2864 | yukon_phy_intr(skge); | 3040 | yukon_phy_intr(skge); |
2865 | else | 3041 | else if (hw->phy_type == SK_PHY_BCOM) |
2866 | bcom_phy_intr(skge); | 3042 | bcom_phy_intr(skge); |
2867 | } | 3043 | } |
2868 | } | 3044 | } |
@@ -3014,7 +3190,7 @@ static int skge_reset(struct skge_hw *hw) | |||
3014 | { | 3190 | { |
3015 | u32 reg; | 3191 | u32 reg; |
3016 | u16 ctst, pci_status; | 3192 | u16 ctst, pci_status; |
3017 | u8 t8, mac_cfg, pmd_type, phy_type; | 3193 | u8 t8, mac_cfg, pmd_type; |
3018 | int i; | 3194 | int i; |
3019 | 3195 | ||
3020 | ctst = skge_read16(hw, B0_CTST); | 3196 | ctst = skge_read16(hw, B0_CTST); |
@@ -3038,19 +3214,22 @@ static int skge_reset(struct skge_hw *hw) | |||
3038 | ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); | 3214 | ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); |
3039 | 3215 | ||
3040 | hw->chip_id = skge_read8(hw, B2_CHIP_ID); | 3216 | hw->chip_id = skge_read8(hw, B2_CHIP_ID); |
3041 | phy_type = skge_read8(hw, B2_E_1) & 0xf; | 3217 | hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; |
3042 | pmd_type = skge_read8(hw, B2_PMD_TYP); | 3218 | pmd_type = skge_read8(hw, B2_PMD_TYP); |
3043 | hw->copper = (pmd_type == 'T' || pmd_type == '1'); | 3219 | hw->copper = (pmd_type == 'T' || pmd_type == '1'); |
3044 | 3220 | ||
3045 | switch (hw->chip_id) { | 3221 | switch (hw->chip_id) { |
3046 | case CHIP_ID_GENESIS: | 3222 | case CHIP_ID_GENESIS: |
3047 | switch (phy_type) { | 3223 | switch (hw->phy_type) { |
3224 | case SK_PHY_XMAC: | ||
3225 | hw->phy_addr = PHY_ADDR_XMAC; | ||
3226 | break; | ||
3048 | case SK_PHY_BCOM: | 3227 | case SK_PHY_BCOM: |
3049 | hw->phy_addr = PHY_ADDR_BCOM; | 3228 | hw->phy_addr = PHY_ADDR_BCOM; |
3050 | break; | 3229 | break; |
3051 | default: | 3230 | default: |
3052 | printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", | 3231 | printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", |
3053 | pci_name(hw->pdev), phy_type); | 3232 | pci_name(hw->pdev), hw->phy_type); |
3054 | return -EOPNOTSUPP; | 3233 | return -EOPNOTSUPP; |
3055 | } | 3234 | } |
3056 | break; | 3235 | break; |
@@ -3058,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw) | |||
3058 | case CHIP_ID_YUKON: | 3237 | case CHIP_ID_YUKON: |
3059 | case CHIP_ID_YUKON_LITE: | 3238 | case CHIP_ID_YUKON_LITE: |
3060 | case CHIP_ID_YUKON_LP: | 3239 | case CHIP_ID_YUKON_LP: |
3061 | if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') | 3240 | if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') |
3062 | hw->copper = 1; | 3241 | hw->copper = 1; |
3063 | 3242 | ||
3064 | hw->phy_addr = PHY_ADDR_MARV; | 3243 | hw->phy_addr = PHY_ADDR_MARV; |
@@ -3089,10 +3268,13 @@ static int skge_reset(struct skge_hw *hw) | |||
3089 | else | 3268 | else |
3090 | hw->ram_size = t8 * 4096; | 3269 | hw->ram_size = t8 * 4096; |
3091 | 3270 | ||
3092 | hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; | 3271 | hw->intr_mask = IS_HW_ERR | IS_PORT_1; |
3093 | if (hw->ports > 1) | 3272 | if (hw->ports > 1) |
3094 | hw->intr_mask |= IS_PORT_2; | 3273 | hw->intr_mask |= IS_PORT_2; |
3095 | 3274 | ||
3275 | if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)) | ||
3276 | hw->intr_mask |= IS_EXT_REG; | ||
3277 | |||
3096 | if (hw->chip_id == CHIP_ID_GENESIS) | 3278 | if (hw->chip_id == CHIP_ID_GENESIS) |
3097 | genesis_init(hw); | 3279 | genesis_init(hw); |
3098 | else { | 3280 | else { |
@@ -3226,6 +3408,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, | |||
3226 | 3408 | ||
3227 | skge->port = port; | 3409 | skge->port = port; |
3228 | 3410 | ||
3411 | /* Only used for Genesis XMAC */ | ||
3412 | INIT_WORK(&skge->link_thread, xm_link_timer, dev); | ||
3413 | |||
3229 | if (hw->chip_id != CHIP_ID_GENESIS) { | 3414 | if (hw->chip_id != CHIP_ID_GENESIS) { |
3230 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; | 3415 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; |
3231 | skge->rx_csum = 1; | 3416 | skge->rx_csum = 1; |
diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 79e09271bcf9..d0b47d46cf9d 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h | |||
@@ -934,7 +934,7 @@ enum { | |||
934 | PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ | 934 | PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ |
935 | PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */ | 935 | PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */ |
936 | PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ | 936 | PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ |
937 | PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ | 937 | PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ |
938 | PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ | 938 | PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ |
939 | 939 | ||
940 | PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */ | 940 | PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */ |
@@ -1097,13 +1097,36 @@ enum { | |||
1097 | 1097 | ||
1098 | /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ | 1098 | /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ |
1099 | enum { | 1099 | enum { |
1100 | PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */ | 1100 | PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */ |
1101 | PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */ | 1101 | PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */ |
1102 | PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */ | 1102 | PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */ |
1103 | PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */ | 1103 | PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */ |
1104 | }; | 1104 | }; |
1105 | 1105 | ||
1106 | 1106 | ||
1107 | /***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/ | ||
1108 | enum { | ||
1109 | PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */ | ||
1110 | PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */ | ||
1111 | }; | ||
1112 | |||
1113 | /***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/ | ||
1114 | enum { | ||
1115 | PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */ | ||
1116 | PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */ | ||
1117 | PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */ | ||
1118 | PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */ | ||
1119 | PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */ | ||
1120 | }; | ||
1121 | |||
1122 | /* Remote Fault Bits (PHY_X_AN_RFB) encoding */ | ||
1123 | enum { | ||
1124 | X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */ | ||
1125 | X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */ | ||
1126 | X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */ | ||
1127 | X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */ | ||
1128 | }; | ||
1129 | |||
1107 | /* Broadcom-Specific */ | 1130 | /* Broadcom-Specific */ |
1108 | /***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ | 1131 | /***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ |
1109 | enum { | 1132 | enum { |
@@ -2158,8 +2181,8 @@ enum { | |||
2158 | XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */ | 2181 | XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */ |
2159 | XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */ | 2182 | XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */ |
2160 | XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */ | 2183 | XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */ |
2161 | XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ | 2184 | XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ |
2162 | XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ | 2185 | XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ |
2163 | XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */ | 2186 | XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */ |
2164 | XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */ | 2187 | XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */ |
2165 | XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */ | 2188 | XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */ |
@@ -2172,9 +2195,7 @@ enum { | |||
2172 | XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ | 2195 | XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ |
2173 | }; | 2196 | }; |
2174 | 2197 | ||
2175 | #define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \ | 2198 | #define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR)) |
2176 | XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \ | ||
2177 | XM_IS_RXF_OV | XM_IS_TXF_UR)) | ||
2178 | 2199 | ||
2179 | 2200 | ||
2180 | /* XM_HW_CFG 16 bit r/w Hardware Config Register */ | 2201 | /* XM_HW_CFG 16 bit r/w Hardware Config Register */ |
@@ -2396,6 +2417,7 @@ struct skge_hw { | |||
2396 | u8 chip_rev; | 2417 | u8 chip_rev; |
2397 | u8 copper; | 2418 | u8 copper; |
2398 | u8 ports; | 2419 | u8 ports; |
2420 | u8 phy_type; | ||
2399 | 2421 | ||
2400 | u32 ram_size; | 2422 | u32 ram_size; |
2401 | u32 ram_offset; | 2423 | u32 ram_offset; |
@@ -2422,6 +2444,7 @@ struct skge_port { | |||
2422 | 2444 | ||
2423 | struct net_device_stats net_stats; | 2445 | struct net_device_stats net_stats; |
2424 | 2446 | ||
2447 | struct work_struct link_thread; | ||
2425 | u8 rx_csum; | 2448 | u8 rx_csum; |
2426 | u8 blink_on; | 2449 | u8 blink_on; |
2427 | u8 flow_control; | 2450 | u8 flow_control; |