mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 15:20:41 +00:00
tg3: Add mdio bus registration
This patch introduces code to register and unregister the tg3 mdio bus with the system. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dd47700310
commit
158d7abdae
3 changed files with 127 additions and 7 deletions
|
@ -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 @@
|
||||||
#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)
|
||||||
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 & 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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
#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 {
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue