From 68c90166e4aaa15ddcdd4778ad30bfb8b32534be Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 19 Feb 2007 20:15:39 +0000 Subject: 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: Mark Brown Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index ffa0afd2edd..4e21f5510b9 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -568,6 +568,8 @@ struct netdev_private { u32 intr_status; /* Do not touch the nic registers */ 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 */ int mii; int phy_addr_external; @@ -696,7 +698,10 @@ static void __devinit natsemi_init_media (struct net_device *dev) struct netdev_private *np = netdev_priv(dev); 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 */ tmp = mdio_read(dev, MII_BMCR); @@ -806,8 +811,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np->hands_off = 0; np->intr_status = 0; np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size; + np->ignore_phy = 0; /* 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 * finds a phy: use external port, first phy that replies. * - Otherwise: internal port. @@ -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 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; else dev->if_port = PORT_TP; @@ -825,7 +832,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (dev->if_port != PORT_TP) { 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; np->phy_addr_external = PHY_ADDR_INTERNAL; } @@ -891,6 +900,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, printk("%02x, IRQ %d", dev->dev_addr[i], irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); + else if (np->ignore_phy) + printk(", port MII, ignoring PHY\n"); else printk(", port MII, phy ad %d.\n", np->phy_addr_external); } @@ -1571,9 +1582,13 @@ static void check_link(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - int duplex; + int duplex = np->duplex; 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 * link failure until it's read. We need the current link status, * thus read twice. @@ -1585,7 +1600,7 @@ static void check_link(struct net_device *dev) if (netif_carrier_ok(dev)) { if (netif_msg_link(np)) printk(KERN_NOTICE "%s: link down.\n", - dev->name); + dev->name); netif_carrier_off(dev); undo_cable_magic(dev); } @@ -1609,6 +1624,7 @@ static void check_link(struct net_device *dev) duplex = 1; } +propagate_state: /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { if (netif_msg_link(np)) @@ -2818,6 +2834,15 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) 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. * -- cgit v1.2.3-18-g5258