summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-09-23 21:25:28 -0700
committerJeff Garzik <jeff@garzik.org>2006-09-25 20:04:29 -0400
commit64f6b64dfb8cdda21652f24a0fb0a68e2f0b0022 (patch)
treee1706db57e1a1b4c65884c9b79a7f9d4e0e2ae7c
parent46798c897e235e71e1e9c46a5e6e9adfffd8b85d (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>
-rw-r--r--drivers/net/skge.c357
-rw-r--r--drivers/net/skge.h37
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 @@
#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;
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 {
PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */
PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
+ PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */
@@ -1097,13 +1097,36 @@ enum {
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
enum {
- PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
+ PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */
PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */
PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */
PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */
};
+/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
+enum {
+ PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
+ PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
+};
+
+/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
+enum {
+ PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */
+ PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
+ PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
+ PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
+ PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
+};
+
+/* Remote Fault Bits (PHY_X_AN_RFB) encoding */
+enum {
+ X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
+ X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */
+ X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
+ X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
+};
+
/* Broadcom-Specific */
/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
enum {
@@ -2158,8 +2181,8 @@ enum {
XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */
XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */
XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */
- XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
- XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
+ XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
+ XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */
XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */
XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */
@@ -2172,9 +2195,7 @@ enum {
XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
};
-#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
- XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
- XM_IS_RXF_OV | XM_IS_TXF_UR))
+#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR))
/* XM_HW_CFG 16 bit r/w Hardware Config Register */
@@ -2396,6 +2417,7 @@ struct skge_hw {
u8 chip_rev;
u8 copper;
u8 ports;
+ u8 phy_type;
u32 ram_size;
u32 ram_offset;
@@ -2422,6 +2444,7 @@ struct skge_port {
struct net_device_stats net_stats;
+ struct work_struct link_thread;
u8 rx_csum;
u8 blink_on;
u8 flow_control;