* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2011 Broadcom Corporation.
+ * Copyright (C) 2005-2012 Broadcom Corporation.
*
* Firmware is:
* Derived from proprietary unpublished source code,
#define TG3_RAW_IP_ALIGN 2
#define TG3_FW_UPDATE_TIMEOUT_SEC 5
+#define TG3_FW_UPDATE_FREQ_SEC (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
#define FIRMWARE_TG3 "tigon/tg3.bin"
#define FIRMWARE_TG3TSO "tigon/tg3_tso.bin"
}
/* tp->lock is held. */
-static void tg3_ump_link_report(struct tg3 *tp)
+static void tg3_phy_gather_ump_data(struct tg3 *tp, u32 *data)
{
- u32 reg;
- u32 val;
-
- if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
- return;
-
- tg3_wait_for_event_ack(tp);
-
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
-
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+ u32 reg, val;
val = 0;
if (!tg3_readphy(tp, MII_BMCR, ®))
val = reg << 16;
if (!tg3_readphy(tp, MII_BMSR, ®))
val |= (reg & 0xffff);
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+ *data++ = val;
val = 0;
if (!tg3_readphy(tp, MII_ADVERTISE, ®))
val = reg << 16;
if (!tg3_readphy(tp, MII_LPA, ®))
val |= (reg & 0xffff);
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+ *data++ = val;
val = 0;
if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
if (!tg3_readphy(tp, MII_STAT1000, ®))
val |= (reg & 0xffff);
}
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+ *data++ = val;
if (!tg3_readphy(tp, MII_PHYADDR, ®))
val = reg << 16;
else
val = 0;
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+ *data++ = val;
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+ u32 data[4];
+
+ if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
+ return;
+
+ tg3_phy_gather_ump_data(tp, data);
+
+ tg3_wait_for_event_ack(tp);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x0, data[0]);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x4, data[1]);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x8, data[2]);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0xc, data[3]);
tg3_generate_fw_event(tp);
}
(6 << TX_LENGTHS_IPG_SHIFT) |
(32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
- if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
- (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
+ if (phydev->link != tp->old_link ||
phydev->speed != tp->link_config.active_speed ||
phydev->duplex != tp->link_config.active_duplex ||
oldflowctrl != tp->link_config.active_flowctrl)
linkmesg = 1;
+ tp->old_link = phydev->link;
tp->link_config.active_speed = phydev->speed;
tp->link_config.active_duplex = phydev->duplex;
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
- phydev->speed = tp->link_config.orig_speed;
- phydev->duplex = tp->link_config.orig_duplex;
- phydev->autoneg = tp->link_config.orig_autoneg;
- phydev->advertising = tp->link_config.orig_advertising;
+ phydev->speed = tp->link_config.speed;
+ phydev->duplex = tp->link_config.duplex;
+ phydev->autoneg = tp->link_config.autoneg;
+ phydev->advertising = tp->link_config.advertising;
}
phy_start(phydev);
return 0;
}
-static int tg3_setup_phy(struct tg3 *, int);
-static int tg3_halt_cpu(struct tg3 *, u32);
-
static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
{
u32 val;
phy_addr = tg3_nvram_phys_addr(tp, offset);
- tw32(NVRAM_ADDR, phy_addr);
-
nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
if (page_off == 0 || i == 0)
if (i == (len - 4))
nvram_cmd |= NVRAM_CMD_LAST;
+ if ((nvram_cmd & NVRAM_CMD_FIRST) ||
+ !tg3_flag(tp, FLASH) ||
+ !tg3_flag(tp, 57765_PLUS))
+ tw32(NVRAM_ADDR, phy_addr);
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
!tg3_flag(tp, 5755_PLUS) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
return err;
}
+static int tg3_setup_phy(struct tg3 *, int);
+
static int tg3_power_down_prepare(struct tg3 *tp)
{
u32 misc_host_ctrl;
tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
- tp->link_config.orig_speed = phydev->speed;
- tp->link_config.orig_duplex = phydev->duplex;
- tp->link_config.orig_autoneg = phydev->autoneg;
- tp->link_config.orig_advertising = phydev->advertising;
+ tp->link_config.speed = phydev->speed;
+ tp->link_config.duplex = phydev->duplex;
+ tp->link_config.autoneg = phydev->autoneg;
+ tp->link_config.advertising = phydev->advertising;
advertising = ADVERTISED_TP |
ADVERTISED_Pause |
} else {
do_low_power = true;
- if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER))
tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
- tp->link_config.orig_speed = tp->link_config.speed;
- tp->link_config.orig_duplex = tp->link_config.duplex;
- tp->link_config.orig_autoneg = tp->link_config.autoneg;
- }
- if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
- tp->link_config.speed = SPEED_10;
- tp->link_config.duplex = DUPLEX_HALF;
- tp->link_config.autoneg = AUTONEG_ENABLE;
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
tg3_setup_phy(tp, 0);
- }
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
DUPLEX_HALF;
break;
}
- *speed = SPEED_INVALID;
- *duplex = DUPLEX_INVALID;
+ *speed = SPEED_UNKNOWN;
+ *duplex = DUPLEX_UNKNOWN;
break;
}
}
static void tg3_phy_copper_begin(struct tg3 *tp)
{
- u32 new_adv;
- int i;
+ if (tp->link_config.autoneg == AUTONEG_ENABLE ||
+ (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+ u32 adv, fc;
- if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
- new_adv = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full;
- if (tg3_flag(tp, WOL_SPEED_100MB))
- new_adv |= ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full;
-
- tg3_phy_autoneg_cfg(tp, new_adv,
- FLOW_CTRL_TX | FLOW_CTRL_RX);
- } else if (tp->link_config.speed == SPEED_INVALID) {
- if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
- tp->link_config.advertising &=
- ~(ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full);
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ adv = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full;
+ if (tg3_flag(tp, WOL_SPEED_100MB))
+ adv |= ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full;
- tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
- tp->link_config.flowctrl);
- } else {
- /* Asking for a specific link mode. */
- if (tp->link_config.speed == SPEED_1000) {
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv = ADVERTISED_1000baseT_Full;
- else
- new_adv = ADVERTISED_1000baseT_Half;
- } else if (tp->link_config.speed == SPEED_100) {
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv = ADVERTISED_100baseT_Full;
- else
- new_adv = ADVERTISED_100baseT_Half;
+ fc = FLOW_CTRL_TX | FLOW_CTRL_RX;
} else {
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv = ADVERTISED_10baseT_Full;
- else
- new_adv = ADVERTISED_10baseT_Half;
+ adv = tp->link_config.advertising;
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+ adv &= ~(ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full);
+
+ fc = tp->link_config.flowctrl;
}
- tg3_phy_autoneg_cfg(tp, new_adv,
- tp->link_config.flowctrl);
- }
+ tg3_phy_autoneg_cfg(tp, adv, fc);
- if (tp->link_config.autoneg == AUTONEG_DISABLE &&
- tp->link_config.speed != SPEED_INVALID) {
+ tg3_writephy(tp, MII_BMCR,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+ } else {
+ int i;
u32 bmcr, orig_bmcr;
tp->link_config.active_speed = tp->link_config.speed;
tg3_writephy(tp, MII_BMCR, bmcr);
udelay(40);
}
- } else {
- tg3_writephy(tp, MII_BMCR,
- BMCR_ANENABLE | BMCR_ANRESTART);
}
}
if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
return false;
- tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ if (tgtadv &&
+ (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
+ tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
+ tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL |
+ CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
+ } else {
+ tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ }
+
if (tg3_ctrl != tgtadv)
return false;
}
}
current_link_up = 0;
- current_speed = SPEED_INVALID;
- current_duplex = DUPLEX_INVALID;
+ current_speed = SPEED_UNKNOWN;
+ current_duplex = DUPLEX_UNKNOWN;
tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
tp->link_config.rmt_adv = 0;
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_1000MBPS_ON));
} else {
- tp->link_config.active_speed = SPEED_INVALID;
- tp->link_config.active_duplex = DUPLEX_INVALID;
+ tp->link_config.active_speed = SPEED_UNKNOWN;
+ tp->link_config.active_duplex = DUPLEX_UNKNOWN;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_TRAFFIC_OVERRIDE));
tg3_phy_reset(tp);
current_link_up = 0;
- current_speed = SPEED_INVALID;
- current_duplex = DUPLEX_INVALID;
+ current_speed = SPEED_UNKNOWN;
+ current_duplex = DUPLEX_UNKNOWN;
tp->link_config.rmt_adv = 0;
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
}
}
- netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
+ netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
tnapi->tx_cons = sw_idx;
/* Refill RX ring(s). */
if (!tg3_flag(tp, ENABLE_RSS)) {
+ /* Sync BD data before updating mailbox */
+ wmb();
+
if (work_mask & RXD_OPAQUE_RING_STD) {
tpr->rx_std_prod_idx = std_prod_idx &
tp->rx_std_ring_mask;
{
cancel_work_sync(&tp->reset_task);
tg3_flag_clear(tp, RESET_TASK_PENDING);
+ tg3_flag_clear(tp, TX_RECOVERY_PENDING);
}
static int tg3_poll_msix(struct napi_struct *napi, int budget)
((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0),
mss, vlan)) {
would_hit_hwbug = 1;
- /* Now loop through additional data fragments, and queue them. */
} else if (skb_shinfo(skb)->nr_frags > 0) {
u32 tmp_mss = mss;
!tg3_flag(tp, HW_TSO_3))
tmp_mss = 0;
+ /* Now loop through additional data
+ * fragments, and queue them.
+ */
last = skb_shinfo(skb)->nr_frags - 1;
for (i = 0; i <= last; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
}
skb_tx_timestamp(skb);
- netdev_sent_queue(tp->dev, skb->len);
+ netdev_tx_sent_queue(txq, skb->len);
+
+ /* Sync BD data before updating mailbox */
+ wmb();
/* Packets are ready, update Tx producer idx local and on card. */
tw32_tx_mbox(tnapi->prodmbox, entry);
dev_kfree_skb_any(skb);
}
+ netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j));
}
- netdev_reset_queue(tp->dev);
}
/* Initialize tx/rx rings for packet processing.
return 0;
}
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *,
- struct rtnl_link_stats64 *);
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *,
- struct tg3_ethtool_stats *);
+static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *);
+static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *);
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent)
if (tp->hw_stats) {
/* Save the stats across chip resets... */
- tg3_get_stats64(tp->dev, &tp->net_stats_prev),
+ tg3_get_nstats(tp, &tp->net_stats_prev);
tg3_get_estats(tp, &tp->estats_prev);
/* And make sure the next sample is new data */
int err = 0, skip_mac_1 = 0;
if (!is_valid_ether_addr(addr->sa_data))
- return -EINVAL;
+ return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (tg3_flag(tp, PCI_EXPRESS))
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
- rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR;
-
if (tg3_flag(tp, HW_TSO_1) ||
tg3_flag(tp, HW_TSO_2) ||
tg3_flag(tp, HW_TSO_3))
}
if (!tg3_flag(tp, USE_PHYLIB)) {
- if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
- tp->link_config.speed = tp->link_config.orig_speed;
- tp->link_config.duplex = tp->link_config.orig_duplex;
- tp->link_config.autoneg = tp->link_config.orig_autoneg;
- }
err = tg3_setup_phy(tp, 0);
if (err)
return tg3_reset_hw(tp, reset_phy);
}
-/* Restart hardware after configuration changes, self-test, etc.
- * Invoked with tp->lock held.
- */
-static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
- __releases(tp->lock)
- __acquires(tp->lock)
-{
- int err;
-
- err = tg3_init_hw(tp, reset_phy);
- if (err) {
- netdev_err(tp->dev,
- "Failed to re-initialize device, aborting\n");
- tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_full_unlock(tp);
- del_timer_sync(&tp->timer);
- tp->irq_sync = 0;
- tg3_napi_enable(tp);
- dev_close(tp->dev);
- tg3_full_lock(tp, 0);
- }
- return err;
-}
-
-static void tg3_reset_task(struct work_struct *work)
-{
- struct tg3 *tp = container_of(work, struct tg3, reset_task);
- int err;
-
- tg3_full_lock(tp, 0);
-
- if (!netif_running(tp->dev)) {
- tg3_flag_clear(tp, RESET_TASK_PENDING);
- tg3_full_unlock(tp);
- return;
- }
-
- tg3_full_unlock(tp);
-
- tg3_phy_stop(tp);
-
- tg3_netif_stop(tp);
-
- tg3_full_lock(tp, 1);
-
- if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
- tp->write32_tx_mbox = tg3_write32_tx_mbox;
- tp->write32_rx_mbox = tg3_write_flush_reg32;
- tg3_flag_set(tp, MBOX_WRITE_REORDER);
- tg3_flag_clear(tp, TX_RECOVERY_PENDING);
- }
-
- tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- err = tg3_init_hw(tp, 1);
- if (err)
- goto out;
-
- tg3_netif_start(tp);
-
-out:
- tg3_full_unlock(tp);
-
- if (!err)
- tg3_phy_start(tp);
-
- tg3_flag_clear(tp, RESET_TASK_PENDING);
-}
-
#define TG3_STAT_ADD32(PSTAT, REG) \
do { u32 __val = tr32(REG); \
(PSTAT)->low += __val; \
add_timer(&tp->timer);
}
+static void __devinit tg3_timer_init(struct tg3 *tp)
+{
+ if (tg3_flag(tp, TAGGED_STATUS) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ !tg3_flag(tp, 57765_CLASS))
+ tp->timer_offset = HZ;
+ else
+ tp->timer_offset = HZ / 10;
+
+ BUG_ON(tp->timer_offset > HZ);
+
+ tp->timer_multiplier = (HZ / tp->timer_offset);
+ tp->asf_multiplier = (HZ / tp->timer_offset) *
+ TG3_FW_UPDATE_FREQ_SEC;
+
+ init_timer(&tp->timer);
+ tp->timer.data = (unsigned long) tp;
+ tp->timer.function = tg3_timer;
+}
+
+static void tg3_timer_start(struct tg3 *tp)
+{
+ tp->asf_counter = tp->asf_multiplier;
+ tp->timer_counter = tp->timer_multiplier;
+
+ tp->timer.expires = jiffies + tp->timer_offset;
+ add_timer(&tp->timer);
+}
+
+static void tg3_timer_stop(struct tg3 *tp)
+{
+ del_timer_sync(&tp->timer);
+}
+
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+ __releases(tp->lock)
+ __acquires(tp->lock)
+{
+ int err;
+
+ err = tg3_init_hw(tp, reset_phy);
+ if (err) {
+ netdev_err(tp->dev,
+ "Failed to re-initialize device, aborting\n");
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ tg3_full_unlock(tp);
+ tg3_timer_stop(tp);
+ tp->irq_sync = 0;
+ tg3_napi_enable(tp);
+ dev_close(tp->dev);
+ tg3_full_lock(tp, 0);
+ }
+ return err;
+}
+
+static void tg3_reset_task(struct work_struct *work)
+{
+ struct tg3 *tp = container_of(work, struct tg3, reset_task);
+ int err;
+
+ tg3_full_lock(tp, 0);
+
+ if (!netif_running(tp->dev)) {
+ tg3_flag_clear(tp, RESET_TASK_PENDING);
+ tg3_full_unlock(tp);
+ return;
+ }
+
+ tg3_full_unlock(tp);
+
+ tg3_phy_stop(tp);
+
+ tg3_netif_stop(tp);
+
+ tg3_full_lock(tp, 1);
+
+ if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
+ tp->write32_tx_mbox = tg3_write32_tx_mbox;
+ tp->write32_rx_mbox = tg3_write_flush_reg32;
+ tg3_flag_set(tp, MBOX_WRITE_REORDER);
+ tg3_flag_clear(tp, TX_RECOVERY_PENDING);
+ }
+
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
+ err = tg3_init_hw(tp, 1);
+ if (err)
+ goto out;
+
+ tg3_netif_start(tp);
+
+out:
+ tg3_full_unlock(tp);
+
+ if (!err)
+ tg3_phy_start(tp);
+
+ tg3_flag_clear(tp, RESET_TASK_PENDING);
+}
+
static int tg3_request_irq(struct tg3 *tp, int irq_num)
{
irq_handler_t fn;
}
err = request_irq(tnapi->irq_vec, tg3_test_isr,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi);
+ IRQF_SHARED, dev->name, tnapi);
if (err)
return err;
if (err) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
- } else {
- if (tg3_flag(tp, TAGGED_STATUS) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- !tg3_flag(tp, 57765_CLASS))
- tp->timer_offset = HZ;
- else
- tp->timer_offset = HZ / 10;
-
- BUG_ON(tp->timer_offset > HZ);
- tp->timer_counter = tp->timer_multiplier =
- (HZ / tp->timer_offset);
- tp->asf_counter = tp->asf_multiplier =
- ((HZ / tp->timer_offset) * 2);
-
- init_timer(&tp->timer);
- tp->timer.expires = jiffies + tp->timer_offset;
- tp->timer.data = (unsigned long) tp;
- tp->timer.function = tg3_timer;
}
tg3_full_unlock(tp);
tg3_full_lock(tp, 0);
- add_timer(&tp->timer);
+ tg3_timer_start(tp);
tg3_flag_set(tp, INIT_COMPLETE);
tg3_enable_ints(tp);
netif_tx_stop_all_queues(dev);
- del_timer_sync(&tp->timer);
+ tg3_timer_stop(tp);
tg3_phy_stop(tp);
return ((u64)val->high << 32) | ((u64)val->low);
}
-static u64 calc_crc_errors(struct tg3 *tp)
+static u64 tg3_calc_crc_errors(struct tg3 *tp)
{
struct tg3_hw_stats *hw_stats = tp->hw_stats;
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
u32 val;
- spin_lock_bh(&tp->lock);
if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
tg3_writephy(tp, MII_TG3_TEST1,
val | MII_TG3_TEST1_CRC_EN);
tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
} else
val = 0;
- spin_unlock_bh(&tp->lock);
tp->phy_crc_errors += val;
estats->member = old_estats->member + \
get_stat64(&hw_stats->member)
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
- struct tg3_ethtool_stats *estats)
+static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats)
{
struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
- if (!hw_stats)
- return old_estats;
-
ESTAT_ADD(rx_octets);
ESTAT_ADD(rx_fragments);
ESTAT_ADD(rx_ucast_packets);
ESTAT_ADD(nic_tx_threshold_hit);
ESTAT_ADD(mbuf_lwm_thresh_hit);
-
- return estats;
}
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
+static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
{
- struct tg3 *tp = netdev_priv(dev);
struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
- if (!hw_stats)
- return old_stats;
-
stats->rx_packets = old_stats->rx_packets +
get_stat64(&hw_stats->rx_ucast_packets) +
get_stat64(&hw_stats->rx_mcast_packets) +
get_stat64(&hw_stats->tx_carrier_sense_errors);
stats->rx_crc_errors = old_stats->rx_crc_errors +
- calc_crc_errors(tp);
+ tg3_calc_crc_errors(tp);
stats->rx_missed_errors = old_stats->rx_missed_errors +
get_stat64(&hw_stats->rx_discards);
stats->rx_dropped = tp->rx_dropped;
stats->tx_dropped = tp->tx_dropped;
-
- return stats;
}
static int tg3_get_regs_len(struct net_device *dev)
cmd->eth_tp_mdix = ETH_TP_MDI;
}
} else {
- ethtool_cmd_speed_set(cmd, SPEED_INVALID);
- cmd->duplex = DUPLEX_INVALID;
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ cmd->duplex = DUPLEX_UNKNOWN;
cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
}
cmd->phy_address = tp->phy_addr;
if (cmd->autoneg == AUTONEG_ENABLE) {
tp->link_config.advertising = (cmd->advertising |
ADVERTISED_Autoneg);
- tp->link_config.speed = SPEED_INVALID;
- tp->link_config.duplex = DUPLEX_INVALID;
+ tp->link_config.speed = SPEED_UNKNOWN;
+ tp->link_config.duplex = DUPLEX_UNKNOWN;
} else {
tp->link_config.advertising = 0;
tp->link_config.speed = speed;
tp->link_config.duplex = cmd->duplex;
}
- tp->link_config.orig_speed = tp->link_config.speed;
- tp->link_config.orig_duplex = tp->link_config.duplex;
- tp->link_config.orig_autoneg = tp->link_config.autoneg;
-
if (netif_running(dev))
tg3_setup_phy(tp, 1);
if (!epause->autoneg)
tg3_setup_flow_control(tp, 0, 0);
} else {
- tp->link_config.orig_advertising &=
+ tp->link_config.advertising &=
~(ADVERTISED_Pause |
ADVERTISED_Asym_Pause);
- tp->link_config.orig_advertising |= newadv;
+ tp->link_config.advertising |= newadv;
}
} else {
int irq_sync = 0;
{
struct tg3 *tp = netdev_priv(dev);
- tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
+ if (tp->hw_stats)
+ tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
+ else
+ memset(tmp_stats, 0, sizeof(struct tg3_ethtool_stats));
}
static __be32 *tg3_vpd_readblock(struct tg3 *tp, u32 *vpdlen)
} else {
num_pkts = 1;
data_off = ETH_HLEN;
+
+ if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
+ tx_len > VLAN_ETH_FRAME_LEN)
+ base_flags |= TXD_FLAG_JMB_PKT;
}
for (i = data_off; i < tx_len; i++)
tnapi->tx_prod++;
+ /* Sync BD data before updating mailbox */
+ wmb();
+
tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod);
tr32_mailbox(tnapi->prodmbox);
{
int err = -EIO;
u32 eee_cap;
+ u32 jmb_pkt_sz = 9000;
+
+ if (tp->dma_limit)
+ jmb_pkt_sz = tp->dma_limit - ETH_HLEN;
eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP;
tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
data[0] |= TG3_STD_LOOPBACK_FAILED;
if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
- tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
data[0] |= TG3_JMB_LOOPBACK_FAILED;
tg3_mac_loopback(tp, false);
tg3_run_loopback(tp, ETH_FRAME_LEN, true))
data[1] |= TG3_TSO_LOOPBACK_FAILED;
if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
- tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
data[1] |= TG3_JMB_LOOPBACK_FAILED;
if (do_extlpbk) {
tg3_run_loopback(tp, ETH_FRAME_LEN, true))
data[2] |= TG3_TSO_LOOPBACK_FAILED;
if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
- tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
data[2] |= TG3_JMB_LOOPBACK_FAILED;
}
.set_rxfh_indir = tg3_set_rxfh_indir,
};
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (!tp->hw_stats)
+ return &tp->net_stats_prev;
+
+ spin_lock_bh(&tp->lock);
+ tg3_get_nstats(tp, stats);
+ spin_unlock_bh(&tp->lock);
+
+ return stats;
+}
+
static void tg3_set_rx_mode(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
static int tg3_change_mtu(struct net_device *dev, int new_mtu)
{
struct tg3 *tp = netdev_priv(dev);
- int err;
+ int err, reset_phy = 0;
if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
return -EINVAL;
tg3_set_mtu(dev, tp, new_mtu);
- err = tg3_restart_hw(tp, 0);
+ /* Reset PHY, otherwise the read DMA engine will be in a mode that
+ * breaks all requests to 256 bytes.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+ reset_phy = 1;
+
+ err = tg3_restart_hw(tp, reset_phy);
if (!err)
tg3_netif_start(tp);
adv |= ADVERTISED_FIBRE;
tp->link_config.advertising = adv;
- tp->link_config.speed = SPEED_INVALID;
- tp->link_config.duplex = DUPLEX_INVALID;
+ tp->link_config.speed = SPEED_UNKNOWN;
+ tp->link_config.duplex = DUPLEX_UNKNOWN;
tp->link_config.autoneg = AUTONEG_ENABLE;
- tp->link_config.active_speed = SPEED_INVALID;
- tp->link_config.active_duplex = DUPLEX_INVALID;
- tp->link_config.orig_speed = SPEED_INVALID;
- tp->link_config.orig_duplex = DUPLEX_INVALID;
- tp->link_config.orig_autoneg = AUTONEG_INVALID;
+ tp->link_config.active_speed = SPEED_UNKNOWN;
+ tp->link_config.active_duplex = DUPLEX_UNKNOWN;
+
+ tp->old_link = -1;
}
static int __devinit tg3_phy_probe(struct tg3 *tp)
return peer;
}
+static void __devinit tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
+{
+ tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+ u32 reg;
+
+ /* All devices that use the alternate
+ * ASIC REV location have a CPMU.
+ */
+ tg3_flag_set(tp, CPMU_PRESENT);
+
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+ reg = TG3PCI_GEN2_PRODID_ASICREV;
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786)
+ reg = TG3PCI_GEN15_PRODID_ASICREV;
+ else
+ reg = TG3PCI_PRODID_ASICREV;
+
+ pci_read_config_dword(tp->pdev, reg, &tp->pci_chip_rev_id);
+ }
+
+ /* Wrong chip ID in 5752 A0. This code can be removed later
+ * as A0 is not in production.
+ */
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+ tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ tg3_flag_set(tp, 5717_PLUS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+ tg3_flag_set(tp, 57765_CLASS);
+
+ if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
+ tg3_flag_set(tp, 57765_PLUS);
+
+ /* Intentionally exclude ASIC_REV_5906 */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+ tg3_flag(tp, 57765_PLUS))
+ tg3_flag_set(tp, 5755_PLUS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+ tg3_flag_set(tp, 5780_CLASS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
+ tg3_flag(tp, 5755_PLUS) ||
+ tg3_flag(tp, 5780_CLASS))
+ tg3_flag_set(tp, 5750_PLUS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+ tg3_flag(tp, 5750_PLUS))
+ tg3_flag_set(tp, 5705_PLUS);
+}
+
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
u32 misc_ctrl_reg;
pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
tp->misc_host_ctrl);
- tp->pci_chip_rev_id = (misc_ctrl_reg >>
- MISC_HOST_CTRL_CHIPREV_SHIFT);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
- u32 prod_id_asic_rev;
-
- if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
- pci_read_config_dword(tp->pdev,
- TG3PCI_GEN2_PRODID_ASICREV,
- &prod_id_asic_rev);
- else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786)
- pci_read_config_dword(tp->pdev,
- TG3PCI_GEN15_PRODID_ASICREV,
- &prod_id_asic_rev);
- else
- pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
- &prod_id_asic_rev);
-
- tp->pci_chip_rev_id = prod_id_asic_rev;
- }
-
- /* Wrong chip ID in 5752 A0. This code can be removed later
- * as A0 is not in production.
- */
- if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
- tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+ tg3_detect_asic_rev(tp, misc_ctrl_reg);
/* If we have 5702/03 A1 or A2 on certain ICH chipsets,
* we need to disable memory and use config. cycles
* Any tg3 device found behind the bridge will also need the 40-bit
* DMA workaround.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
- tg3_flag_set(tp, 5780_CLASS);
+ if (tg3_flag(tp, 5780_CLASS)) {
tg3_flag_set(tp, 40BIT_DMA_BUG);
tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
} else {
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
tp->pdev_peer = tg3_find_peer(tp);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
- tg3_flag_set(tp, 5717_PLUS);
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
- tg3_flag_set(tp, 57765_CLASS);
-
- if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
- tg3_flag_set(tp, 57765_PLUS);
-
- /* Intentionally exclude ASIC_REV_5906 */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
- tg3_flag(tp, 57765_PLUS))
- tg3_flag_set(tp, 5755_PLUS);
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
- tg3_flag(tp, 5755_PLUS) ||
- tg3_flag(tp, 5780_CLASS))
- tg3_flag_set(tp, 5750_PLUS);
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
- tg3_flag(tp, 5750_PLUS))
- tg3_flag_set(tp, 5705_PLUS);
-
/* Determine TSO capabilities */
if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
; /* Do nothing. HW bug. */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
tp->dma_limit = TG3_TX_BD_DMA_MAX_4K;
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
- tp->dma_limit = TG3_TX_BD_DMA_MAX_2K;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
tg3_flag_set(tp, PCI_EXPRESS);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
- int readrq = pcie_get_readrq(tp->pdev);
- if (readrq > 2048)
- pcie_set_readrq(tp->pdev, 2048);
- }
-
pci_read_config_word(tp->pdev,
pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
&lnkctl);
tg3_ape_lock_init(tp);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
- tg3_flag(tp, 57765_PLUS))
- tg3_flag_set(tp, CPMU_PRESENT);
-
/* Set up tp->grc_local_ctrl before calling
* tg3_pwrsrc_switch_to_vmain(). GPIO1 driven high
* will bring 5700's external PHY out of reset.
tg3_frob_aux_power(tp, false);
}
+ tg3_timer_init(tp);
+
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting\n");
tg3_phy_stop(tp);
tg3_netif_stop(tp);
- del_timer_sync(&tp->timer);
+ tg3_timer_stop(tp);
tg3_full_lock(tp, 1);
tg3_disable_ints(tp);
if (err2)
goto out;
- tp->timer.expires = jiffies + tp->timer_offset;
- add_timer(&tp->timer);
+ tg3_timer_start(tp);
netif_device_attach(dev);
tg3_netif_start(tp);
if (err)
goto out;
- tp->timer.expires = jiffies + tp->timer_offset;
- add_timer(&tp->timer);
+ tg3_timer_start(tp);
tg3_netif_start(tp);
tg3_netif_stop(tp);
- del_timer_sync(&tp->timer);
+ tg3_timer_stop(tp);
/* Want to make sure that the reset task doesn't run */
tg3_reset_task_cancel(tp);
- tg3_flag_clear(tp, TX_RECOVERY_PENDING);
netif_device_detach(netdev);
netif_device_attach(netdev);
- tp->timer.expires = jiffies + tp->timer_offset;
- add_timer(&tp->timer);
+ tg3_timer_start(tp);
tg3_netif_start(tp);