Skip to content

Commit

Permalink
sky2: fe+ chip support
Browse files Browse the repository at this point in the history
Add support for newest Marvell chips.
The Yukon FE plus chip is found in some not yet released laptops.
Tested on hardware evaluation boards.

This version of the patch is for 2.6.23. It supersedes
the two previous patches that are sitting in netdev-2.6 (upstream branch).

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Stephen Hemminger authored and Jeff Garzik committed Sep 20, 2007
1 parent ea76e63 commit 05745c4
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 37 deletions.
136 changes: 103 additions & 33 deletions drivers/net/sky2.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,15 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
Expand All @@ -147,6 +150,7 @@ static const char *yukon2_name[] = {
"Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
"FE+", /* 0xb8 */
};

static void sky2_set_multicast(struct net_device *dev);
Expand Down Expand Up @@ -331,7 +335,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)

ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
if (sky2_is_copper(hw)) {
if (hw->chip_id == CHIP_ID_YUKON_FE) {
if (!(hw->flags & SKY2_HW_GIGABIT)) {
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
} else {
Expand Down Expand Up @@ -450,7 +454,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)

gma_write16(hw, port, GM_GP_CTRL, reg);

if (hw->chip_id != CHIP_ID_YUKON_FE)
if (hw->flags & SKY2_HW_GIGABIT)
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);

gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
Expand All @@ -474,6 +478,23 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
break;

case CHIP_ID_YUKON_FE_P:
/* Enable Link Partner Next Page */
ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
ctrl |= PHY_M_PC_ENA_LIP_NP;

/* disable Energy Detect and enable scrambler */
ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB);
gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);

/* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */
ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) |
PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) |
PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED);

gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
break;

case CHIP_ID_YUKON_XL:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);

Expand Down Expand Up @@ -543,7 +564,13 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)

/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
} else if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
hw->chip_rev == CHIP_REV_YU_FE2_A0) {
/* apply workaround for integrated resistors calibration */
gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17);
gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60);
} else if (hw->chip_id != CHIP_ID_YUKON_EX) {
/* no effect on Yukon-XL */
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);

if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
Expand Down Expand Up @@ -664,25 +691,25 @@ static void sky2_wol_init(struct sky2_port *sky2)

static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
{
if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
struct net_device *dev = hw->dev[port];

if (dev->mtu <= ETH_DATA_LEN)
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_STFW_ENA |
(hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
} else {
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
/* set Tx GMAC FIFO Almost Empty Threshold */
sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
(ECU_JUMBO_WM << 16) | ECU_AE_THR);
TX_JUMBO_DIS | TX_STFW_ENA);

else if (hw->chip_id != CHIP_ID_YUKON_EC_U)
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_STFW_ENA | TX_JUMBO_ENA);
else {
/* set Tx GMAC FIFO Almost Empty Threshold */
sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
(ECU_JUMBO_WM << 16) | ECU_AE_THR);

sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_JUMBO_ENA | TX_STFW_DIS);
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_JUMBO_ENA | TX_STFW_DIS);

/* Can't do offload because of lack of store/forward */
hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
| NETIF_F_ALL_CSUM);
} else
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_JUMBO_DIS | TX_STFW_ENA);
/* Can't do offload because of lack of store/forward */
dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
}
}

Expand Down Expand Up @@ -768,7 +795,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
if (hw->chip_id == CHIP_ID_YUKON_EX)
if (hw->chip_id == CHIP_ID_YUKON_EX ||
hw->chip_id == CHIP_ID_YUKON_FE_P)
rx_reg |= GMF_RX_OVER_ON;

sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
Expand All @@ -777,7 +805,12 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);

/* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */
sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
reg = RX_GMF_FL_THR_DEF + 1;
/* Another magic mystery workaround from sk98lin */
if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
hw->chip_rev == CHIP_REV_YU_FE2_A0)
reg = 0x178;
sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg);

/* Configure Tx MAC FIFO */
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
Expand Down Expand Up @@ -1704,8 +1737,12 @@ static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
if (hw->flags & SKY2_HW_FIBRE_PHY)
return SPEED_1000;

if (hw->chip_id == CHIP_ID_YUKON_FE)
return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
if (!(hw->flags & SKY2_HW_GIGABIT)) {
if (aux & PHY_M_PS_SPEED_100)
return SPEED_100;
else
return SPEED_10;
}

switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
Expand Down Expand Up @@ -1949,7 +1986,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;

if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE)
if (new_mtu > ETH_DATA_LEN &&
(hw->chip_id == CHIP_ID_YUKON_FE ||
hw->chip_id == CHIP_ID_YUKON_FE_P))
return -EINVAL;

if (!netif_running(dev)) {
Expand All @@ -1966,7 +2005,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)

synchronize_irq(hw->pdev->irq);

if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
if (!(hw->flags & SKY2_HW_RAMBUFFER))
sky2_set_tx_stfwd(hw, port);

ctl = gma_read16(hw, port, GM_GP_CTRL);
Expand Down Expand Up @@ -2205,7 +2244,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}

/* This chip reports checksum status differently */
if (hw->chip_id == CHIP_ID_YUKON_EX) {
if (hw->flags & SKY2_HW_NEW_LE) {
if (sky2->rx_csum &&
(le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
(le->css & CSS_TCPUDPCSOK))
Expand Down Expand Up @@ -2246,8 +2285,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
if (!sky2->rx_csum)
break;

if (hw->chip_id == CHIP_ID_YUKON_EX)
/* If this happens then driver assuming wrong format */
if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
if (net_ratelimit())
printk(KERN_NOTICE "%s: unexpected"
" checksum status\n",
dev->name);
break;
}

/* Both checksum counters are programmed to start at
* the same offset, so unless there is a problem they
Expand Down Expand Up @@ -2549,17 +2594,25 @@ static void sky2_netpoll(struct net_device *dev)
#endif

/* Chip internal frequency for clock calculations */
static inline u32 sky2_mhz(const struct sky2_hw *hw)
static u32 sky2_mhz(const struct sky2_hw *hw)
{
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
case CHIP_ID_YUKON_EX:
return 125; /* 125 Mhz */
return 125;

case CHIP_ID_YUKON_FE:
return 100; /* 100 Mhz */
default: /* YUKON_XL */
return 156; /* 156 Mhz */
return 100;

case CHIP_ID_YUKON_FE_P:
return 50;

case CHIP_ID_YUKON_XL:
return 156;

default:
BUG();
}
}

Expand Down Expand Up @@ -2623,6 +2676,12 @@ static int __devinit sky2_init(struct sky2_hw *hw)
hw->flags = SKY2_HW_RAMBUFFER;
break;

case CHIP_ID_YUKON_FE_P:
hw->flags = SKY2_HW_NEWER_PHY
| SKY2_HW_NEW_LE
| SKY2_HW_AUTO_TX_SUM
| SKY2_HW_ADV_POWER_CTL;
break;
default:
dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
hw->chip_id);
Expand Down Expand Up @@ -2827,7 +2886,9 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)

sky2->wol = wol->wolopts;

if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
hw->chip_id == CHIP_ID_YUKON_EX ||
hw->chip_id == CHIP_ID_YUKON_FE_P)
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);

Expand Down Expand Up @@ -3820,6 +3881,13 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->hw = hw;
sky2->msg_enable = netif_msg_init(debug, default_msg);

/* This chip has hardware problems that generates
* bogus PHY receive status so by default shut up the message.
*/
if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
hw->chip_rev == CHIP_REV_YU_FE2_A0)
sky2->msg_enable &= ~NETIF_MSG_RX_ERR;

/* Auto speed and flow control */
sky2->autoneg = AUTONEG_ENABLE;
sky2->flow_mode = FC_BOTH;
Expand Down Expand Up @@ -4189,7 +4257,9 @@ static int sky2_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D0, 0);

/* Re-enable all clocks */
if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
if (hw->chip_id == CHIP_ID_YUKON_EX ||
hw->chip_id == CHIP_ID_YUKON_EC_U ||
hw->chip_id == CHIP_ID_YUKON_FE_P)
sky2_pci_write32(hw, PCI_DEV_REG3, 0);

sky2_reset(hw);
Expand Down
18 changes: 14 additions & 4 deletions drivers/net/sky2.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,18 +470,24 @@ enum {
CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */

CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */
};
enum yukon_ec_rev {
CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */
CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */
CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */

};
enum yukon_ec_u_rev {
CHIP_REV_YU_EC_U_A0 = 1,
CHIP_REV_YU_EC_U_A1 = 2,
CHIP_REV_YU_EC_U_B0 = 3,

};
enum yukon_fe_rev {
CHIP_REV_YU_FE_A1 = 1,
CHIP_REV_YU_FE_A2 = 2,

};
enum yukon_fe_p_rev {
CHIP_REV_YU_FE2_A0 = 0,
};
enum yukon_ex_rev {
CHIP_REV_YU_EX_A0 = 1,
Expand Down Expand Up @@ -1729,6 +1735,10 @@ enum {
GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON,
};

/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */
enum {
TX_DYN_WM_ENA = 3, /* Yukon-FE+ specific */
};

/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */
enum {
Expand Down

0 comments on commit 05745c4

Please sign in to comment.