|
@@ -58,6 +58,7 @@
|
|
|
#define TX_WATCHDOG (5 * HZ)
|
|
|
#define NAPI_WEIGHT 64
|
|
|
#define BLINK_MS 250
|
|
|
+#define LINK_HZ (HZ/2)
|
|
|
|
|
|
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
|
|
|
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
|
|
@@ -605,7 +606,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
|
|
|
if (hw->chip_id == CHIP_ID_GENESIS) {
|
|
|
switch (mode) {
|
|
|
case LED_MODE_OFF:
|
|
|
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
|
|
|
+ if (hw->phy_type == SK_PHY_BCOM)
|
|
|
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
|
|
|
+ else {
|
|
|
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
|
|
|
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
|
|
|
+ }
|
|
|
skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
|
|
|
skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
|
|
|
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)
|
|
|
skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
|
|
|
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
|
|
|
|
|
|
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
|
|
|
- break;
|
|
|
+ if (hw->phy_type == SK_PHY_BCOM)
|
|
|
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
|
|
|
+ else {
|
|
|
+ skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
|
|
|
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
|
|
|
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
} else {
|
|
|
switch (mode) {
|
|
@@ -879,6 +891,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
|
|
|
xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
|
|
|
*val = xm_read16(hw, port, XM_PHY_DATA);
|
|
|
|
|
|
+ if (hw->phy_type == SK_PHY_XMAC)
|
|
|
+ goto ready;
|
|
|
+
|
|
|
for (i = 0; i < PHY_RETRIES; i++) {
|
|
|
if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
|
|
|
goto ready;
|
|
@@ -965,7 +980,8 @@ static void genesis_reset(struct skge_hw *hw, int port)
|
|
|
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
|
|
|
|
|
|
/* disable Broadcom PHY IRQ */
|
|
|
- xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
|
|
|
+ if (hw->phy_type == SK_PHY_BCOM)
|
|
|
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
|
|
|
|
|
|
xm_outhash(hw, port, XM_HSM, zero);
|
|
|
}
|
|
@@ -1000,60 +1016,64 @@ static void bcom_check_link(struct skge_hw *hw, int port)
|
|
|
|
|
|
if (netif_carrier_ok(dev))
|
|
|
skge_link_down(skge);
|
|
|
- } else {
|
|
|
- if (skge->autoneg == AUTONEG_ENABLE &&
|
|
|
- (status & PHY_ST_AN_OVER)) {
|
|
|
- u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
|
|
|
- u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
|
|
|
-
|
|
|
- if (lpa & PHY_B_AN_RF) {
|
|
|
- printk(KERN_NOTICE PFX "%s: remote fault\n",
|
|
|
- dev->name);
|
|
|
- return;
|
|
|
- }
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- /* Check Duplex mismatch */
|
|
|
- switch (aux & PHY_B_AS_AN_RES_MSK) {
|
|
|
- case PHY_B_RES_1000FD:
|
|
|
- skge->duplex = DUPLEX_FULL;
|
|
|
- break;
|
|
|
- case PHY_B_RES_1000HD:
|
|
|
- skge->duplex = DUPLEX_HALF;
|
|
|
- break;
|
|
|
- default:
|
|
|
- printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
|
|
- dev->name);
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (skge->autoneg == AUTONEG_ENABLE) {
|
|
|
+ u16 lpa, aux;
|
|
|
|
|
|
+ if (!(status & PHY_ST_AN_OVER))
|
|
|
+ return;
|
|
|
|
|
|
- /* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
|
|
- switch (aux & PHY_B_AS_PAUSE_MSK) {
|
|
|
- case PHY_B_AS_PAUSE_MSK:
|
|
|
- skge->flow_control = FLOW_MODE_SYMMETRIC;
|
|
|
- break;
|
|
|
- case PHY_B_AS_PRR:
|
|
|
- skge->flow_control = FLOW_MODE_REM_SEND;
|
|
|
- break;
|
|
|
- case PHY_B_AS_PRT:
|
|
|
- skge->flow_control = FLOW_MODE_LOC_SEND;
|
|
|
- break;
|
|
|
- default:
|
|
|
- skge->flow_control = FLOW_MODE_NONE;
|
|
|
- }
|
|
|
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
|
|
+ if (lpa & PHY_B_AN_RF) {
|
|
|
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
|
|
|
+ dev->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- skge->speed = SPEED_1000;
|
|
|
+ aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
|
|
|
+
|
|
|
+ /* Check Duplex mismatch */
|
|
|
+ switch (aux & PHY_B_AS_AN_RES_MSK) {
|
|
|
+ case PHY_B_RES_1000FD:
|
|
|
+ skge->duplex = DUPLEX_FULL;
|
|
|
+ break;
|
|
|
+ case PHY_B_RES_1000HD:
|
|
|
+ skge->duplex = DUPLEX_HALF;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
|
|
+ dev->name);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- if (!netif_carrier_ok(dev))
|
|
|
- genesis_link_up(skge);
|
|
|
+
|
|
|
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
|
|
+ switch (aux & PHY_B_AS_PAUSE_MSK) {
|
|
|
+ case PHY_B_AS_PAUSE_MSK:
|
|
|
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
|
|
|
+ break;
|
|
|
+ case PHY_B_AS_PRR:
|
|
|
+ skge->flow_control = FLOW_MODE_REM_SEND;
|
|
|
+ break;
|
|
|
+ case PHY_B_AS_PRT:
|
|
|
+ skge->flow_control = FLOW_MODE_LOC_SEND;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ skge->flow_control = FLOW_MODE_NONE;
|
|
|
+ }
|
|
|
+ skge->speed = SPEED_1000;
|
|
|
}
|
|
|
+
|
|
|
+ if (!netif_carrier_ok(dev))
|
|
|
+ genesis_link_up(skge);
|
|
|
}
|
|
|
|
|
|
/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
|
|
|
* Phy on for 100 or 10Mbit operation
|
|
|
*/
|
|
|
-static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
|
|
+static void bcom_phy_init(struct skge_port *skge)
|
|
|
{
|
|
|
struct skge_hw *hw = skge->hw;
|
|
|
int port = skge->port;
|
|
@@ -1144,7 +1164,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
|
|
phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
|
|
|
|
|
|
/* Handle Jumbo frames */
|
|
|
- if (jumbo) {
|
|
|
+ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
|
|
|
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
|
|
PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
|
|
|
|
|
@@ -1157,8 +1177,154 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
|
|
|
|
|
/* Use link status change interrupt */
|
|
|
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
|
|
+}
|
|
|
|
|
|
- bcom_check_link(hw, port);
|
|
|
+static void xm_phy_init(struct skge_port *skge)
|
|
|
+{
|
|
|
+ struct skge_hw *hw = skge->hw;
|
|
|
+ int port = skge->port;
|
|
|
+ u16 ctrl = 0;
|
|
|
+
|
|
|
+ if (skge->autoneg == AUTONEG_ENABLE) {
|
|
|
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
|
|
|
+ ctrl |= PHY_X_AN_HD;
|
|
|
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
|
|
|
+ ctrl |= PHY_X_AN_FD;
|
|
|
+
|
|
|
+ switch(skge->flow_control) {
|
|
|
+ case FLOW_MODE_NONE:
|
|
|
+ ctrl |= PHY_X_P_NO_PAUSE;
|
|
|
+ break;
|
|
|
+ case FLOW_MODE_LOC_SEND:
|
|
|
+ ctrl |= PHY_X_P_ASYM_MD;
|
|
|
+ break;
|
|
|
+ case FLOW_MODE_SYMMETRIC:
|
|
|
+ ctrl |= PHY_X_P_BOTH_MD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
|
|
|
+
|
|
|
+ /* Restart Auto-negotiation */
|
|
|
+ ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
|
|
|
+ } else {
|
|
|
+ /* Set DuplexMode in Config register */
|
|
|
+ if (skge->duplex == DUPLEX_FULL)
|
|
|
+ ctrl |= PHY_CT_DUP_MD;
|
|
|
+ /*
|
|
|
+ * Do NOT enable Auto-negotiation here. This would hold
|
|
|
+ * the link down because no IDLEs are transmitted
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
|
|
|
+
|
|
|
+ /* Poll PHY for status changes */
|
|
|
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
|
|
|
+}
|
|
|
+
|
|
|
+static void xm_check_link(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct skge_port *skge = netdev_priv(dev);
|
|
|
+ struct skge_hw *hw = skge->hw;
|
|
|
+ int port = skge->port;
|
|
|
+ u16 status;
|
|
|
+
|
|
|
+ /* read twice because of latch */
|
|
|
+ (void) xm_phy_read(hw, port, PHY_XMAC_STAT);
|
|
|
+ status = xm_phy_read(hw, port, PHY_XMAC_STAT);
|
|
|
+
|
|
|
+ if ((status & PHY_ST_LSYNC) == 0) {
|
|
|
+ u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
|
|
|
+ cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
|
|
|
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
|
|
|
+ /* dummy read to ensure writing */
|
|
|
+ (void) xm_read16(hw, port, XM_MMU_CMD);
|
|
|
+
|
|
|
+ if (netif_carrier_ok(dev))
|
|
|
+ skge_link_down(skge);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (skge->autoneg == AUTONEG_ENABLE) {
|
|
|
+ u16 lpa, res;
|
|
|
+
|
|
|
+ if (!(status & PHY_ST_AN_OVER))
|
|
|
+ return;
|
|
|
+
|
|
|
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
|
|
+ if (lpa & PHY_B_AN_RF) {
|
|
|
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
|
|
|
+ dev->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
|
|
|
+
|
|
|
+ /* Check Duplex mismatch */
|
|
|
+ switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
|
|
|
+ case PHY_X_RS_FD:
|
|
|
+ skge->duplex = DUPLEX_FULL;
|
|
|
+ break;
|
|
|
+ case PHY_X_RS_HD:
|
|
|
+ skge->duplex = DUPLEX_HALF;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
|
|
+ dev->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
|
|
+ if (lpa & PHY_X_P_SYM_MD)
|
|
|
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
|
|
|
+ else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
|
|
|
+ skge->flow_control = FLOW_MODE_REM_SEND;
|
|
|
+ else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
|
|
|
+ skge->flow_control = FLOW_MODE_LOC_SEND;
|
|
|
+ else
|
|
|
+ skge->flow_control = FLOW_MODE_NONE;
|
|
|
+
|
|
|
+
|
|
|
+ skge->speed = SPEED_1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!netif_carrier_ok(dev))
|
|
|
+ genesis_link_up(skge);
|
|
|
+}
|
|
|
+
|
|
|
+/* Poll to check for link coming up.
|
|
|
+ * Since internal PHY is wired to a level triggered pin, can't
|
|
|
+ * get an interrupt when carrier is detected.
|
|
|
+ */
|
|
|
+static void xm_link_timer(void *arg)
|
|
|
+{
|
|
|
+ struct net_device *dev = arg;
|
|
|
+ struct skge_port *skge = netdev_priv(arg);
|
|
|
+ struct skge_hw *hw = skge->hw;
|
|
|
+ int port = skge->port;
|
|
|
+
|
|
|
+ if (!netif_running(dev))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (netif_carrier_ok(dev)) {
|
|
|
+ xm_read16(hw, port, XM_ISRC);
|
|
|
+ if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
|
|
|
+ goto nochange;
|
|
|
+ } else {
|
|
|
+ if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
|
|
|
+ goto nochange;
|
|
|
+ xm_read16(hw, port, XM_ISRC);
|
|
|
+ if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
|
|
|
+ goto nochange;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_lock(&hw->phy_mutex);
|
|
|
+ xm_check_link(dev);
|
|
|
+ mutex_unlock(&hw->phy_mutex);
|
|
|
+
|
|
|
+nochange:
|
|
|
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
* namely for the 1000baseTX cards that use the XMAC's
|
|
|
* GMII mode.
|
|
|
*/
|
|
|
- /* Take external Phy out of reset */
|
|
|
- r = skge_read32(hw, B2_GP_IO);
|
|
|
- if (port == 0)
|
|
|
- r |= GP_DIR_0|GP_IO_0;
|
|
|
- else
|
|
|
- r |= GP_DIR_2|GP_IO_2;
|
|
|
+ if (hw->phy_type != SK_PHY_XMAC) {
|
|
|
+ /* Take external Phy out of reset */
|
|
|
+ r = skge_read32(hw, B2_GP_IO);
|
|
|
+ if (port == 0)
|
|
|
+ r |= GP_DIR_0|GP_IO_0;
|
|
|
+ else
|
|
|
+ r |= GP_DIR_2|GP_IO_2;
|
|
|
|
|
|
- skge_write32(hw, B2_GP_IO, r);
|
|
|
+ skge_write32(hw, B2_GP_IO, r);
|
|
|
|
|
|
+ /* Enable GMII interface */
|
|
|
+ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
|
|
|
+ }
|
|
|
|
|
|
- /* Enable GMII interface */
|
|
|
- xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
|
|
|
|
|
|
- bcom_phy_init(skge, jumbo);
|
|
|
+ switch(hw->phy_type) {
|
|
|
+ case SK_PHY_XMAC:
|
|
|
+ xm_phy_init(skge);
|
|
|
+ break;
|
|
|
+ case SK_PHY_BCOM:
|
|
|
+ bcom_phy_init(skge);
|
|
|
+ bcom_check_link(hw, port);
|
|
|
+ }
|
|
|
|
|
|
/* Set Station Address */
|
|
|
xm_outaddr(hw, port, XM_SA, dev->dev_addr);
|
|
@@ -1335,16 +1510,18 @@ static void genesis_stop(struct skge_port *skge)
|
|
|
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
|
|
|
|
|
|
/* For external PHYs there must be special handling */
|
|
|
- reg = skge_read32(hw, B2_GP_IO);
|
|
|
- if (port == 0) {
|
|
|
- reg |= GP_DIR_0;
|
|
|
- reg &= ~GP_IO_0;
|
|
|
- } else {
|
|
|
- reg |= GP_DIR_2;
|
|
|
- reg &= ~GP_IO_2;
|
|
|
+ if (hw->phy_type != SK_PHY_XMAC) {
|
|
|
+ reg = skge_read32(hw, B2_GP_IO);
|
|
|
+ if (port == 0) {
|
|
|
+ reg |= GP_DIR_0;
|
|
|
+ reg &= ~GP_IO_0;
|
|
|
+ } else {
|
|
|
+ reg |= GP_DIR_2;
|
|
|
+ reg &= ~GP_IO_2;
|
|
|
+ }
|
|
|
+ skge_write32(hw, B2_GP_IO, reg);
|
|
|
+ skge_read32(hw, B2_GP_IO);
|
|
|
}
|
|
|
- skge_write32(hw, B2_GP_IO, reg);
|
|
|
- skge_read32(hw, B2_GP_IO);
|
|
|
|
|
|
xm_write16(hw, port, XM_MMU_CMD,
|
|
|
xm_read16(hw, port, XM_MMU_CMD)
|
|
@@ -1406,7 +1583,7 @@ static void genesis_link_up(struct skge_port *skge)
|
|
|
struct skge_hw *hw = skge->hw;
|
|
|
int port = skge->port;
|
|
|
u16 cmd;
|
|
|
- u32 mode, msk;
|
|
|
+ u32 mode;
|
|
|
|
|
|
cmd = xm_read16(hw, port, XM_MMU_CMD);
|
|
|
|
|
@@ -1454,27 +1631,24 @@ static void genesis_link_up(struct skge_port *skge)
|
|
|
}
|
|
|
|
|
|
xm_write32(hw, port, XM_MODE, mode);
|
|
|
-
|
|
|
- msk = XM_DEF_MSK;
|
|
|
- /* disable GP0 interrupt bit for external Phy */
|
|
|
- msk |= XM_IS_INP_ASS;
|
|
|
-
|
|
|
- xm_write16(hw, port, XM_IMSK, msk);
|
|
|
+ xm_write16(hw, port, XM_IMSK, XM_DEF_MSK);
|
|
|
xm_read16(hw, port, XM_ISRC);
|
|
|
|
|
|
/* get MMU Command Reg. */
|
|
|
cmd = xm_read16(hw, port, XM_MMU_CMD);
|
|
|
- if (skge->duplex == DUPLEX_FULL)
|
|
|
+ if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
|
|
|
cmd |= XM_MMU_GMII_FD;
|
|
|
|
|
|
/*
|
|
|
* Workaround BCOM Errata (#10523) for all BCom Phys
|
|
|
* Enable Power Management after link up
|
|
|
*/
|
|
|
- xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
|
|
- xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
|
|
|
- & ~PHY_B_AC_DIS_PM);
|
|
|
- xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
|
|
+ if (hw->phy_type == SK_PHY_BCOM) {
|
|
|
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
|
|
+ xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
|
|
|
+ & ~PHY_B_AC_DIS_PM);
|
|
|
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
|
|
+ }
|
|
|
|
|
|
/* enable Rx/Tx */
|
|
|
xm_write16(hw, port, XM_MMU_CMD,
|
|
@@ -2240,6 +2414,8 @@ static int skge_down(struct net_device *dev)
|
|
|
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
|
|
|
|
|
|
netif_stop_queue(dev);
|
|
|
+ if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
|
|
|
+ cancel_rearming_delayed_work(&skge->link_thread);
|
|
|
|
|
|
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
|
|
|
if (hw->chip_id == CHIP_ID_GENESIS)
|
|
@@ -2862,7 +3038,7 @@ static void skge_extirq(void *arg)
|
|
|
if (netif_running(dev)) {
|
|
|
if (hw->chip_id != CHIP_ID_GENESIS)
|
|
|
yukon_phy_intr(skge);
|
|
|
- else
|
|
|
+ else if (hw->phy_type == SK_PHY_BCOM)
|
|
|
bcom_phy_intr(skge);
|
|
|
}
|
|
|
}
|
|
@@ -3014,7 +3190,7 @@ static int skge_reset(struct skge_hw *hw)
|
|
|
{
|
|
|
u32 reg;
|
|
|
u16 ctst, pci_status;
|
|
|
- u8 t8, mac_cfg, pmd_type, phy_type;
|
|
|
+ u8 t8, mac_cfg, pmd_type;
|
|
|
int i;
|
|
|
|
|
|
ctst = skge_read16(hw, B0_CTST);
|
|
@@ -3038,19 +3214,22 @@ static int skge_reset(struct skge_hw *hw)
|
|
|
ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
|
|
|
|
|
|
hw->chip_id = skge_read8(hw, B2_CHIP_ID);
|
|
|
- phy_type = skge_read8(hw, B2_E_1) & 0xf;
|
|
|
+ hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
|
|
|
pmd_type = skge_read8(hw, B2_PMD_TYP);
|
|
|
hw->copper = (pmd_type == 'T' || pmd_type == '1');
|
|
|
|
|
|
switch (hw->chip_id) {
|
|
|
case CHIP_ID_GENESIS:
|
|
|
- switch (phy_type) {
|
|
|
+ switch (hw->phy_type) {
|
|
|
+ case SK_PHY_XMAC:
|
|
|
+ hw->phy_addr = PHY_ADDR_XMAC;
|
|
|
+ break;
|
|
|
case SK_PHY_BCOM:
|
|
|
hw->phy_addr = PHY_ADDR_BCOM;
|
|
|
break;
|
|
|
default:
|
|
|
printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
|
|
|
- pci_name(hw->pdev), phy_type);
|
|
|
+ pci_name(hw->pdev), hw->phy_type);
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
|
break;
|
|
@@ -3058,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw)
|
|
|
case CHIP_ID_YUKON:
|
|
|
case CHIP_ID_YUKON_LITE:
|
|
|
case CHIP_ID_YUKON_LP:
|
|
|
- if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
|
|
|
+ if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
|
|
|
hw->copper = 1;
|
|
|
|
|
|
hw->phy_addr = PHY_ADDR_MARV;
|
|
@@ -3089,10 +3268,13 @@ static int skge_reset(struct skge_hw *hw)
|
|
|
else
|
|
|
hw->ram_size = t8 * 4096;
|
|
|
|
|
|
- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
|
|
|
+ hw->intr_mask = IS_HW_ERR | IS_PORT_1;
|
|
|
if (hw->ports > 1)
|
|
|
hw->intr_mask |= IS_PORT_2;
|
|
|
|
|
|
+ if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
|
|
|
+ hw->intr_mask |= IS_EXT_REG;
|
|
|
+
|
|
|
if (hw->chip_id == CHIP_ID_GENESIS)
|
|
|
genesis_init(hw);
|
|
|
else {
|
|
@@ -3226,6 +3408,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
|
|
|
|
|
|
skge->port = port;
|
|
|
|
|
|
+ /* Only used for Genesis XMAC */
|
|
|
+ INIT_WORK(&skge->link_thread, xm_link_timer, dev);
|
|
|
+
|
|
|
if (hw->chip_id != CHIP_ID_GENESIS) {
|
|
|
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
|
|
skge->rx_csum = 1;
|