aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2008-05-02 19:49:29 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-02 19:49:29 -0400
commit7c5026aa9b81dd45df8d3f4e0be73e485976a8b6 (patch)
tree09b0e14566d630f1b8d3225b6fda0c2a862519e9 /drivers/net/tg3.c
parent109115e1991824b88306b374b763d6857b292aeb (diff)
tg3: Add link state reporting to UMP firmware
All variants of the 5714, 5715, and 5780 offer a feature called the "Universal Management Port". This feature is implemented in firmware and is largely transparent to the driver, except... It turns out that the UMP firmware needs to know the current status of the link. Because the firmware cannot touch the PHY registers while the driver is in control of the device, it needs the driver to report link status changes through an additional handshaking mechanism. Without this handshake, it has been observed in the field that the UMP firmware will not operate correctly. This patch implements the new handshake with the UMP firmware. Since the handshake uses the same mechanism ASF heartbeats use, code was added to detect and wait for completion of a pending previous event. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c85
1 files changed, 75 insertions, 10 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index bf376b32450e..3ba6c52fed4e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1656,12 +1656,76 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
1656 return 0; 1656 return 0;
1657} 1657}
1658 1658
1659/* tp->lock is held. */
1660static void tg3_wait_for_event_ack(struct tg3 *tp)
1661{
1662 int i;
1663
1664 /* Wait for up to 2.5 milliseconds */
1665 for (i = 0; i < 250000; i++) {
1666 if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
1667 break;
1668 udelay(10);
1669 }
1670}
1671
1672/* tp->lock is held. */
1673static void tg3_ump_link_report(struct tg3 *tp)
1674{
1675 u32 reg;
1676 u32 val;
1677
1678 if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
1679 !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
1680 return;
1681
1682 tg3_wait_for_event_ack(tp);
1683
1684 tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
1685
1686 tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
1687
1688 val = 0;
1689 if (!tg3_readphy(tp, MII_BMCR, &reg))
1690 val = reg << 16;
1691 if (!tg3_readphy(tp, MII_BMSR, &reg))
1692 val |= (reg & 0xffff);
1693 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
1694
1695 val = 0;
1696 if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
1697 val = reg << 16;
1698 if (!tg3_readphy(tp, MII_LPA, &reg))
1699 val |= (reg & 0xffff);
1700 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
1701
1702 val = 0;
1703 if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
1704 if (!tg3_readphy(tp, MII_CTRL1000, &reg))
1705 val = reg << 16;
1706 if (!tg3_readphy(tp, MII_STAT1000, &reg))
1707 val |= (reg & 0xffff);
1708 }
1709 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
1710
1711 if (!tg3_readphy(tp, MII_PHYADDR, &reg))
1712 val = reg << 16;
1713 else
1714 val = 0;
1715 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
1716
1717 val = tr32(GRC_RX_CPU_EVENT);
1718 val |= GRC_RX_CPU_DRIVER_EVENT;
1719 tw32_f(GRC_RX_CPU_EVENT, val);
1720}
1721
1659static void tg3_link_report(struct tg3 *tp) 1722static void tg3_link_report(struct tg3 *tp)
1660{ 1723{
1661 if (!netif_carrier_ok(tp->dev)) { 1724 if (!netif_carrier_ok(tp->dev)) {
1662 if (netif_msg_link(tp)) 1725 if (netif_msg_link(tp))
1663 printk(KERN_INFO PFX "%s: Link is down.\n", 1726 printk(KERN_INFO PFX "%s: Link is down.\n",
1664 tp->dev->name); 1727 tp->dev->name);
1728 tg3_ump_link_report(tp);
1665 } else if (netif_msg_link(tp)) { 1729 } else if (netif_msg_link(tp)) {
1666 printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n", 1730 printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
1667 tp->dev->name, 1731 tp->dev->name,
@@ -1679,6 +1743,7 @@ static void tg3_link_report(struct tg3 *tp)
1679 "on" : "off", 1743 "on" : "off",
1680 (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? 1744 (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
1681 "on" : "off"); 1745 "on" : "off");
1746 tg3_ump_link_report(tp);
1682 } 1747 }
1683} 1748}
1684 1749
@@ -5500,19 +5565,17 @@ static void tg3_stop_fw(struct tg3 *tp)
5500 if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && 5565 if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
5501 !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { 5566 !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
5502 u32 val; 5567 u32 val;
5503 int i; 5568
5569 /* Wait for RX cpu to ACK the previous event. */
5570 tg3_wait_for_event_ack(tp);
5504 5571
5505 tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW); 5572 tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
5506 val = tr32(GRC_RX_CPU_EVENT); 5573 val = tr32(GRC_RX_CPU_EVENT);
5507 val |= (1 << 14); 5574 val |= GRC_RX_CPU_DRIVER_EVENT;
5508 tw32(GRC_RX_CPU_EVENT, val); 5575 tw32(GRC_RX_CPU_EVENT, val);
5509 5576
5510 /* Wait for RX cpu to ACK the event. */ 5577 /* Wait for RX cpu to ACK this event. */
5511 for (i = 0; i < 100; i++) { 5578 tg3_wait_for_event_ack(tp);
5512 if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
5513 break;
5514 udelay(1);
5515 }
5516 } 5579 }
5517} 5580}
5518 5581
@@ -7402,14 +7465,16 @@ static void tg3_timer(unsigned long __opaque)
7402 if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { 7465 if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
7403 u32 val; 7466 u32 val;
7404 7467
7468 tg3_wait_for_event_ack(tp);
7469
7405 tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, 7470 tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
7406 FWCMD_NICDRV_ALIVE3); 7471 FWCMD_NICDRV_ALIVE3);
7407 tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); 7472 tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
7408 /* 5 seconds timeout */ 7473 /* 5 seconds timeout */
7409 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); 7474 tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
7410 val = tr32(GRC_RX_CPU_EVENT); 7475 val = tr32(GRC_RX_CPU_EVENT);
7411 val |= (1 << 14); 7476 val |= GRC_RX_CPU_DRIVER_EVENT;
7412 tw32(GRC_RX_CPU_EVENT, val); 7477 tw32_f(GRC_RX_CPU_EVENT, val);
7413 } 7478 }
7414 tp->asf_counter = tp->asf_multiplier; 7479 tp->asf_counter = tp->asf_multiplier;
7415 } 7480 }