Commit 158d7abd authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller

tg3: Add mdio bus registration

This patch introduces code to register and unregister the tg3 mdio bus
with the system.
Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarBenjamin Li <benli@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dd477003
...@@ -2228,6 +2228,7 @@ config VIA_VELOCITY ...@@ -2228,6 +2228,7 @@ config VIA_VELOCITY
config TIGON3 config TIGON3
tristate "Broadcom Tigon3 support" tristate "Broadcom Tigon3 support"
depends on PCI depends on PCI
select PHYLIB
help help
This driver supports Broadcom Tigon3 based gigabit Ethernet cards. This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/phy.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
...@@ -835,6 +836,115 @@ static int tg3_bmcr_reset(struct tg3 *tp) ...@@ -835,6 +836,115 @@ static int tg3_bmcr_reset(struct tg3 *tp)
return 0; return 0;
} }
static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
{
struct tg3 *tp = (struct tg3 *)bp->priv;
u32 val;
if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
return -EAGAIN;
if (tg3_readphy(tp, reg, &val))
return -EIO;
return val;
}
static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
{
struct tg3 *tp = (struct tg3 *)bp->priv;
if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
return -EAGAIN;
if (tg3_writephy(tp, reg, val))
return -EIO;
return 0;
}
static int tg3_mdio_reset(struct mii_bus *bp)
{
return 0;
}
static void tg3_mdio_start(struct tg3 *tp)
{
if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
mutex_lock(&tp->mdio_bus.mdio_lock);
tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
mutex_unlock(&tp->mdio_bus.mdio_lock);
}
tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
}
static void tg3_mdio_stop(struct tg3 *tp)
{
if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
mutex_lock(&tp->mdio_bus.mdio_lock);
tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
mutex_unlock(&tp->mdio_bus.mdio_lock);
}
}
static int tg3_mdio_init(struct tg3 *tp)
{
int i;
u32 reg;
struct mii_bus *mdio_bus = &tp->mdio_bus;
tg3_mdio_start(tp);
if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
(tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
return 0;
memset(mdio_bus, 0, sizeof(*mdio_bus));
mdio_bus->name = "tg3 mdio bus";
snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x",
(tp->pdev->bus->number << 8) | tp->pdev->devfn);
mdio_bus->priv = tp;
mdio_bus->dev = &tp->pdev->dev;
mdio_bus->read = &tg3_mdio_read;
mdio_bus->write = &tg3_mdio_write;
mdio_bus->reset = &tg3_mdio_reset;
mdio_bus->phy_mask = ~(1 << PHY_ADDR);
mdio_bus->irq = &tp->mdio_irq[0];
for (i = 0; i < PHY_MAX_ADDR; i++)
mdio_bus->irq[i] = PHY_POLL;
/* The bus registration will look for all the PHYs on the mdio bus.
* Unfortunately, it does not ensure the PHY is powered up before
* accessing the PHY ID registers. A chip reset is the
* quickest way to bring the device back to an operational state..
*/
if (tg3_readphy(tp, MII_BMCR, &reg) || (reg & BMCR_PDOWN))
tg3_bmcr_reset(tp);
i = mdiobus_register(mdio_bus);
if (!i)
tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
else
printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
tp->dev->name, i);
return i;
}
static void tg3_mdio_fini(struct tg3 *tp)
{
if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
mdiobus_unregister(&tp->mdio_bus);
tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
}
}
/* tp->lock is held. */ /* tp->lock is held. */
static void tg3_wait_for_event_ack(struct tg3 *tp) static void tg3_wait_for_event_ack(struct tg3 *tp)
{ {
...@@ -5386,6 +5496,8 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -5386,6 +5496,8 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_nvram_lock(tp); tg3_nvram_lock(tp);
tg3_mdio_stop(tp);
/* No matching tg3_nvram_unlock() after this because /* No matching tg3_nvram_unlock() after this because
* chip reset below will undo the nvram lock. * chip reset below will undo the nvram lock.
*/ */
...@@ -5537,6 +5649,8 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -5537,6 +5649,8 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32_f(MAC_MODE, 0); tw32_f(MAC_MODE, 0);
udelay(40); udelay(40);
tg3_mdio_start(tp);
err = tg3_poll_fw(tp); err = tg3_poll_fw(tp);
if (err) if (err)
return err; return err;
...@@ -7168,10 +7282,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ...@@ -7168,10 +7282,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(MAC_RX_MODE, tp->rx_mode); tw32_f(MAC_RX_MODE, tp->rx_mode);
udelay(10); udelay(10);
tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
tw32(MAC_LED_CTRL, tp->led_ctrl); tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
...@@ -11850,9 +11960,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) ...@@ -11850,9 +11960,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
tp->coalesce_mode |= HOSTCC_MODE_32BYTE; tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
/* Initialize MAC MI mode, polling disabled. */ err = tg3_mdio_init(tp);
tw32_f(MAC_MI_MODE, tp->mi_mode); if (err)
udelay(80); return err;
/* Initialize data/descriptor byte/word swapping. */ /* Initialize data/descriptor byte/word swapping. */
val = tr32(GRC_MODE); val = tr32(GRC_MODE);
...@@ -13052,6 +13162,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) ...@@ -13052,6 +13162,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
flush_scheduled_work(); flush_scheduled_work();
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
tg3_mdio_fini(tp);
unregister_netdev(dev); unregister_netdev(dev);
if (tp->aperegs) { if (tp->aperegs) {
iounmap(tp->aperegs); iounmap(tp->aperegs);
......
...@@ -2481,6 +2481,8 @@ struct tg3 { ...@@ -2481,6 +2481,8 @@ struct tg3 {
#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5761_5784_AX_FIXES 0x00000004
#define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_5701_DMA_BUG 0x00000008
#define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_USE_PHYLIB 0x00000010
#define TG3_FLG3_MDIOBUS_INITED 0x00000020
#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040
struct timer_list timer; struct timer_list timer;
u16 timer_counter; u16 timer_counter;
...@@ -2521,6 +2523,9 @@ struct tg3 { ...@@ -2521,6 +2523,9 @@ struct tg3 {
int msi_cap; int msi_cap;
int pcix_cap; int pcix_cap;
struct mii_bus mdio_bus;
int mdio_irq[PHY_MAX_ADDR];
/* PHY info */ /* PHY info */
u32 phy_id; u32 phy_id;
#define PHY_ID_MASK 0xfffffff0 #define PHY_ID_MASK 0xfffffff0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment