#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"
(6 << TX_LENGTHS_IPG_SHIFT) |
(32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
- if ((phydev->link && tp->link_config.active_speed == SPEED_UNKNOWN) ||
- (!phydev->link && tp->link_config.active_speed != SPEED_UNKNOWN) ||
+ 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;
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_UNKNOWN) {
- 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_UNKNOWN) {
+ 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);
}
}
}
}
- 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_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);
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;
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)
} 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);
tp->link_config.autoneg = AUTONEG_ENABLE;
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)
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_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);