提交 68c90166 编写于 作者: M Mark Brown 提交者: Jeff Garzik

natsemi: Add support for using MII port with no PHY

This patch provides code paths which allow the natsemi driver to use the
external MII port on the chip but ignore any PHYs that may be attached to it.
The link state will be left as it was when the driver started and can be
configured via ethtool.  Any PHYs that are present can be accessed via the MII
ioctl()s.

This is useful for systems where the device is connected without a PHY
or where either information or actions outside the scope of the driver
are required in order to use the PHYs.
Signed-Off-By: NMark Brown <broonie@sirena.org.uk>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 208491d8
...@@ -568,6 +568,8 @@ struct netdev_private { ...@@ -568,6 +568,8 @@ struct netdev_private {
u32 intr_status; u32 intr_status;
/* Do not touch the nic registers */ /* Do not touch the nic registers */
int hands_off; int hands_off;
/* Don't pay attention to the reported link state. */
int ignore_phy;
/* external phy that is used: only valid if dev->if_port != PORT_TP */ /* external phy that is used: only valid if dev->if_port != PORT_TP */
int mii; int mii;
int phy_addr_external; int phy_addr_external;
...@@ -696,7 +698,10 @@ static void __devinit natsemi_init_media (struct net_device *dev) ...@@ -696,7 +698,10 @@ static void __devinit natsemi_init_media (struct net_device *dev)
struct netdev_private *np = netdev_priv(dev); struct netdev_private *np = netdev_priv(dev);
u32 tmp; u32 tmp;
netif_carrier_off(dev); if (np->ignore_phy)
netif_carrier_on(dev);
else
netif_carrier_off(dev);
/* get the initial settings from hardware */ /* get the initial settings from hardware */
tmp = mdio_read(dev, MII_BMCR); tmp = mdio_read(dev, MII_BMCR);
...@@ -806,8 +811,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -806,8 +811,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np->hands_off = 0; np->hands_off = 0;
np->intr_status = 0; np->intr_status = 0;
np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size; np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
np->ignore_phy = 0;
/* Initial port: /* Initial port:
* - If configured to ignore the PHY set up for external.
* - If the nic was configured to use an external phy and if find_mii * - If the nic was configured to use an external phy and if find_mii
* finds a phy: use external port, first phy that replies. * finds a phy: use external port, first phy that replies.
* - Otherwise: internal port. * - Otherwise: internal port.
...@@ -815,7 +822,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -815,7 +822,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
* The address would be used to access a phy over the mii bus, but * The address would be used to access a phy over the mii bus, but
* the internal phy is accessed through mapped registers. * the internal phy is accessed through mapped registers.
*/ */
if (readl(ioaddr + ChipConfig) & CfgExtPhy) if (np->ignore_phy || readl(ioaddr + ChipConfig) & CfgExtPhy)
dev->if_port = PORT_MII; dev->if_port = PORT_MII;
else else
dev->if_port = PORT_TP; dev->if_port = PORT_TP;
...@@ -825,7 +832,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -825,7 +832,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if (dev->if_port != PORT_TP) { if (dev->if_port != PORT_TP) {
np->phy_addr_external = find_mii(dev); np->phy_addr_external = find_mii(dev);
if (np->phy_addr_external == PHY_ADDR_NONE) { /* If we're ignoring the PHY it doesn't matter if we can't
* find one. */
if (!np->ignore_phy && np->phy_addr_external == PHY_ADDR_NONE) {
dev->if_port = PORT_TP; dev->if_port = PORT_TP;
np->phy_addr_external = PHY_ADDR_INTERNAL; np->phy_addr_external = PHY_ADDR_INTERNAL;
} }
...@@ -891,6 +900,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -891,6 +900,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
printk("%02x, IRQ %d", dev->dev_addr[i], irq); printk("%02x, IRQ %d", dev->dev_addr[i], irq);
if (dev->if_port == PORT_TP) if (dev->if_port == PORT_TP)
printk(", port TP.\n"); printk(", port TP.\n");
else if (np->ignore_phy)
printk(", port MII, ignoring PHY\n");
else else
printk(", port MII, phy ad %d.\n", np->phy_addr_external); printk(", port MII, phy ad %d.\n", np->phy_addr_external);
} }
...@@ -1571,9 +1582,13 @@ static void check_link(struct net_device *dev) ...@@ -1571,9 +1582,13 @@ static void check_link(struct net_device *dev)
{ {
struct netdev_private *np = netdev_priv(dev); struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev); void __iomem * ioaddr = ns_ioaddr(dev);
int duplex; int duplex = np->duplex;
u16 bmsr; u16 bmsr;
/* If we are ignoring the PHY then don't try reading it. */
if (np->ignore_phy)
goto propagate_state;
/* The link status field is latched: it remains low after a temporary /* The link status field is latched: it remains low after a temporary
* link failure until it's read. We need the current link status, * link failure until it's read. We need the current link status,
* thus read twice. * thus read twice.
...@@ -1585,7 +1600,7 @@ static void check_link(struct net_device *dev) ...@@ -1585,7 +1600,7 @@ static void check_link(struct net_device *dev)
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
if (netif_msg_link(np)) if (netif_msg_link(np))
printk(KERN_NOTICE "%s: link down.\n", printk(KERN_NOTICE "%s: link down.\n",
dev->name); dev->name);
netif_carrier_off(dev); netif_carrier_off(dev);
undo_cable_magic(dev); undo_cable_magic(dev);
} }
...@@ -1609,6 +1624,7 @@ static void check_link(struct net_device *dev) ...@@ -1609,6 +1624,7 @@ static void check_link(struct net_device *dev)
duplex = 1; duplex = 1;
} }
propagate_state:
/* if duplex is set then bit 28 must be set, too */ /* if duplex is set then bit 28 must be set, too */
if (duplex ^ !!(np->rx_config & RxAcceptTx)) { if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
if (netif_msg_link(np)) if (netif_msg_link(np))
...@@ -2818,6 +2834,15 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -2818,6 +2834,15 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EINVAL; return -EINVAL;
} }
/*
* If we're ignoring the PHY then autoneg and the internal
* transciever are really not going to work so don't let the
* user select them.
*/
if (np->ignore_phy && (ecmd->autoneg == AUTONEG_ENABLE ||
ecmd->port == PORT_TP))
return -EINVAL;
/* /*
* maxtxpkt, maxrxpkt: ignored for now. * maxtxpkt, maxrxpkt: ignored for now.
* *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册