add r6040 phylib support which allows to use the ip175c switch driver on ar525w
SVN-Revision: 21521
This commit is contained in:
parent
22eaf8b658
commit
58405b0509
3 changed files with 471 additions and 3 deletions
|
@ -16,7 +16,7 @@ LINUX_VERSION:=2.6.32.12
|
|||
|
||||
include $(INCLUDE_DIR)/target.mk
|
||||
|
||||
DEFAULT_PACKAGES += wpad-mini kmod-r6040 kmod-input-core \
|
||||
DEFAULT_PACKAGES += wpad-mini kmod-libphy kmod-r6040 kmod-input-core \
|
||||
kmod-input-polldev kmod-input-gpio-buttons kmod-button-hotplug \
|
||||
kmod-rdc321x-wdt
|
||||
|
||||
|
|
468
target/linux/rdc/patches-2.6.32/014-r6040_phylib_support.patch
Normal file
468
target/linux/rdc/patches-2.6.32/014-r6040_phylib_support.patch
Normal file
|
@ -0,0 +1,468 @@
|
|||
Index: linux-2.6.32.12/drivers/net/r6040.c
|
||||
===================================================================
|
||||
--- linux-2.6.32.12.orig/drivers/net/r6040.c 2010-05-20 10:19:41.000000000 +0200
|
||||
+++ linux-2.6.32.12/drivers/net/r6040.c 2010-05-20 10:28:48.000000000 +0200
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
+#include <linux/phy.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
@@ -180,7 +181,6 @@
|
||||
|
||||
struct r6040_private {
|
||||
spinlock_t lock; /* driver lock */
|
||||
- struct timer_list timer;
|
||||
struct pci_dev *pdev;
|
||||
struct r6040_descriptor *rx_insert_ptr;
|
||||
struct r6040_descriptor *rx_remove_ptr;
|
||||
@@ -190,13 +190,15 @@
|
||||
struct r6040_descriptor *tx_ring;
|
||||
dma_addr_t rx_ring_dma;
|
||||
dma_addr_t tx_ring_dma;
|
||||
- u16 tx_free_desc, phy_addr, phy_mode;
|
||||
+ u16 tx_free_desc, phy_addr;
|
||||
u16 mcr0, mcr1;
|
||||
- u16 switch_sig;
|
||||
struct net_device *dev;
|
||||
- struct mii_if_info mii_if;
|
||||
+ struct mii_bus *mii_bus;
|
||||
struct napi_struct napi;
|
||||
void __iomem *base;
|
||||
+ struct phy_device *phydev;
|
||||
+ int old_link;
|
||||
+ int old_duplex;
|
||||
};
|
||||
|
||||
static char version[] __devinitdata = KERN_INFO DRV_NAME
|
||||
@@ -239,20 +241,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
-static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg)
|
||||
+static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
|
||||
{
|
||||
+ struct net_device *dev = bus->priv;
|
||||
struct r6040_private *lp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = lp->base;
|
||||
|
||||
- return (r6040_phy_read(ioaddr, lp->phy_addr, reg));
|
||||
+ return r6040_phy_read(ioaddr, phy_addr, reg);
|
||||
}
|
||||
|
||||
-static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val)
|
||||
+static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr, int reg, u16 value)
|
||||
{
|
||||
+ struct net_device *dev = bus->priv;
|
||||
struct r6040_private *lp = netdev_priv(dev);
|
||||
void __iomem *ioaddr = lp->base;
|
||||
|
||||
- r6040_phy_write(ioaddr, lp->phy_addr, reg, val);
|
||||
+ r6040_phy_write(ioaddr, phy_addr, reg, value);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int r6040_mdiobus_reset(struct mii_bus *bus)
|
||||
+{
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void r6040_free_txbufs(struct net_device *dev)
|
||||
@@ -409,10 +420,9 @@
|
||||
void __iomem *ioaddr = priv->base;
|
||||
|
||||
printk(KERN_WARNING "%s: transmit timed out, int enable %4.4x "
|
||||
- "status %4.4x, PHY status %4.4x\n",
|
||||
+ "status %4.4x\n",
|
||||
dev->name, ioread16(ioaddr + MIER),
|
||||
- ioread16(ioaddr + MISR),
|
||||
- r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
|
||||
+ ioread16(ioaddr + MISR));
|
||||
|
||||
dev->stats.tx_errors++;
|
||||
|
||||
@@ -464,9 +474,6 @@
|
||||
struct r6040_private *lp = netdev_priv(dev);
|
||||
struct pci_dev *pdev = lp->pdev;
|
||||
|
||||
- /* deleted timer */
|
||||
- del_timer_sync(&lp->timer);
|
||||
-
|
||||
spin_lock_irq(&lp->lock);
|
||||
napi_disable(&lp->napi);
|
||||
netif_stop_queue(dev);
|
||||
@@ -496,64 +503,14 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* Status of PHY CHIP */
|
||||
-static int r6040_phy_mode_chk(struct net_device *dev)
|
||||
-{
|
||||
- struct r6040_private *lp = netdev_priv(dev);
|
||||
- void __iomem *ioaddr = lp->base;
|
||||
- int phy_dat;
|
||||
-
|
||||
- /* PHY Link Status Check */
|
||||
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
|
||||
- if (!(phy_dat & 0x4))
|
||||
- phy_dat = 0x8000; /* Link Failed, full duplex */
|
||||
-
|
||||
- /* PHY Chip Auto-Negotiation Status */
|
||||
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
|
||||
- if (phy_dat & 0x0020) {
|
||||
- /* Auto Negotiation Mode */
|
||||
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
|
||||
- phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
|
||||
- if (phy_dat & 0x140)
|
||||
- /* Force full duplex */
|
||||
- phy_dat = 0x8000;
|
||||
- else
|
||||
- phy_dat = 0;
|
||||
- } else {
|
||||
- /* Force Mode */
|
||||
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
|
||||
- if (phy_dat & 0x100)
|
||||
- phy_dat = 0x8000;
|
||||
- else
|
||||
- phy_dat = 0x0000;
|
||||
- }
|
||||
-
|
||||
- return phy_dat;
|
||||
-};
|
||||
-
|
||||
-static void r6040_set_carrier(struct mii_if_info *mii)
|
||||
-{
|
||||
- if (r6040_phy_mode_chk(mii->dev)) {
|
||||
- /* autoneg is off: Link is always assumed to be up */
|
||||
- if (!netif_carrier_ok(mii->dev))
|
||||
- netif_carrier_on(mii->dev);
|
||||
- } else
|
||||
- r6040_phy_mode_chk(mii->dev);
|
||||
-}
|
||||
-
|
||||
static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct r6040_private *lp = netdev_priv(dev);
|
||||
- struct mii_ioctl_data *data = if_mii(rq);
|
||||
- int rc;
|
||||
|
||||
- if (!netif_running(dev))
|
||||
+ if (!lp->phydev)
|
||||
return -EINVAL;
|
||||
- spin_lock_irq(&lp->lock);
|
||||
- rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
|
||||
- spin_unlock_irq(&lp->lock);
|
||||
- r6040_set_carrier(&lp->mii_if);
|
||||
- return rc;
|
||||
+
|
||||
+ return phy_mii_ioctl(lp->phydev, if_mii(rq), cmd);
|
||||
}
|
||||
|
||||
static int r6040_rx(struct net_device *dev, int limit)
|
||||
@@ -752,26 +709,6 @@
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- /* Read the PHY ID */
|
||||
- lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
|
||||
-
|
||||
- if (lp->switch_sig == ICPLUS_PHY_ID) {
|
||||
- r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
|
||||
- lp->phy_mode = 0x8000;
|
||||
- } else {
|
||||
- /* PHY Mode Check */
|
||||
- r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
|
||||
- r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
|
||||
-
|
||||
- if (PHY_MODE == 0x3100)
|
||||
- lp->phy_mode = r6040_phy_mode_chk(dev);
|
||||
- else
|
||||
- lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
|
||||
- }
|
||||
-
|
||||
- /* Set duplex mode */
|
||||
- lp->mcr0 |= lp->phy_mode;
|
||||
-
|
||||
/* improve performance (by RDC guys) */
|
||||
r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
|
||||
r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
|
||||
@@ -784,35 +721,6 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/*
|
||||
- A periodic timer routine
|
||||
- Polling PHY Chip Link Status
|
||||
-*/
|
||||
-static void r6040_timer(unsigned long data)
|
||||
-{
|
||||
- struct net_device *dev = (struct net_device *)data;
|
||||
- struct r6040_private *lp = netdev_priv(dev);
|
||||
- void __iomem *ioaddr = lp->base;
|
||||
- u16 phy_mode;
|
||||
-
|
||||
- /* Polling PHY Chip Status */
|
||||
- if (PHY_MODE == 0x3100)
|
||||
- phy_mode = r6040_phy_mode_chk(dev);
|
||||
- else
|
||||
- phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
|
||||
-
|
||||
- if (phy_mode != lp->phy_mode) {
|
||||
- lp->phy_mode = phy_mode;
|
||||
- lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
|
||||
- iowrite16(lp->mcr0, ioaddr);
|
||||
- }
|
||||
-
|
||||
- /* Timer active again */
|
||||
- mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
|
||||
-
|
||||
- /* Check media */
|
||||
- mii_check_media(&lp->mii_if, 1, 1);
|
||||
-}
|
||||
|
||||
/* Read/set MAC address routines */
|
||||
static void r6040_mac_address(struct net_device *dev)
|
||||
@@ -874,10 +782,6 @@
|
||||
napi_enable(&lp->napi);
|
||||
netif_start_queue(dev);
|
||||
|
||||
- /* set and active a timer process */
|
||||
- setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
|
||||
- if (lp->switch_sig != ICPLUS_PHY_ID)
|
||||
- mod_timer(&lp->timer, jiffies + HZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1020,40 +924,22 @@
|
||||
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct r6040_private *rp = netdev_priv(dev);
|
||||
- int rc;
|
||||
-
|
||||
- spin_lock_irq(&rp->lock);
|
||||
- rc = mii_ethtool_gset(&rp->mii_if, cmd);
|
||||
- spin_unlock_irq(&rp->lock);
|
||||
|
||||
- return rc;
|
||||
+ return phy_ethtool_gset(rp->phydev, cmd);
|
||||
}
|
||||
|
||||
static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct r6040_private *rp = netdev_priv(dev);
|
||||
- int rc;
|
||||
-
|
||||
- spin_lock_irq(&rp->lock);
|
||||
- rc = mii_ethtool_sset(&rp->mii_if, cmd);
|
||||
- spin_unlock_irq(&rp->lock);
|
||||
- r6040_set_carrier(&rp->mii_if);
|
||||
-
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
-static u32 netdev_get_link(struct net_device *dev)
|
||||
-{
|
||||
- struct r6040_private *rp = netdev_priv(dev);
|
||||
|
||||
- return mii_link_ok(&rp->mii_if);
|
||||
+ return phy_ethtool_sset(rp->phydev, cmd);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops netdev_ethtool_ops = {
|
||||
.get_drvinfo = netdev_get_drvinfo,
|
||||
.get_settings = netdev_get_settings,
|
||||
.set_settings = netdev_set_settings,
|
||||
- .get_link = netdev_get_link,
|
||||
+ .get_link = ethtool_op_get_link,
|
||||
};
|
||||
|
||||
static const struct net_device_ops r6040_netdev_ops = {
|
||||
@@ -1072,6 +958,86 @@
|
||||
#endif
|
||||
};
|
||||
|
||||
+static void r6040_adjust_link(struct net_device *dev)
|
||||
+{
|
||||
+ struct r6040_private *lp = netdev_priv(dev);
|
||||
+ struct phy_device *phydev = lp->phydev;
|
||||
+ int status_changed = 0;
|
||||
+ void __iomem *ioaddr = lp->base;
|
||||
+
|
||||
+ BUG_ON (!phydev);
|
||||
+
|
||||
+ if (lp->old_link != phydev->link) {
|
||||
+ status_changed = 1;
|
||||
+ lp->old_link = phydev->link;
|
||||
+ }
|
||||
+
|
||||
+ /* reflect duplex change */
|
||||
+ if (phydev->link && (lp->old_duplex != phydev->duplex)) {
|
||||
+ lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
|
||||
+ iowrite16(lp->mcr0, ioaddr);
|
||||
+
|
||||
+ status_changed = 1;
|
||||
+ lp->old_duplex = phydev->duplex;
|
||||
+ }
|
||||
+
|
||||
+ if (status_changed) {
|
||||
+ pr_info("%s: link %s", dev->name, phydev->link ?
|
||||
+ "UP" : "DOWN");
|
||||
+ if (phydev->link)
|
||||
+ pr_cont(" - %d/%s", phydev->speed,
|
||||
+ DUPLEX_FULL == phydev->duplex ? "full" : "half");
|
||||
+ pr_cont("\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int r6040_mii_probe(struct net_device *dev)
|
||||
+{
|
||||
+ struct r6040_private *lp = netdev_priv(dev);
|
||||
+ struct phy_device *phydev = NULL;
|
||||
+ int phy_addr;
|
||||
+
|
||||
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
|
||||
+ if (lp->mii_bus->phy_map[phy_addr]) {
|
||||
+ phydev = lp->mii_bus->phy_map[phy_addr];
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!phydev) {
|
||||
+ printk(KERN_ERR DRV_NAME "no PHY found\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
|
||||
+ 0, PHY_INTERFACE_MODE_MII);
|
||||
+
|
||||
+ if (IS_ERR(phydev)) {
|
||||
+ printk(KERN_ERR DRV_NAME "could not attach to PHY\n");
|
||||
+ return PTR_ERR(phydev);
|
||||
+ }
|
||||
+
|
||||
+ /* mask with MAC supported features */
|
||||
+ phydev->supported &= (SUPPORTED_10baseT_Half
|
||||
+ | SUPPORTED_10baseT_Full
|
||||
+ | SUPPORTED_100baseT_Half
|
||||
+ | SUPPORTED_100baseT_Full
|
||||
+ | SUPPORTED_Autoneg
|
||||
+ | SUPPORTED_MII
|
||||
+ | SUPPORTED_TP);
|
||||
+
|
||||
+ phydev->advertising = phydev->supported;
|
||||
+ lp->phydev = phydev;
|
||||
+ lp->old_link = 0;
|
||||
+ lp->old_duplex = -1;
|
||||
+
|
||||
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
|
||||
+ "(mii_bus:phy_addr=%s)\n", dev->name,
|
||||
+ phydev->drv->name, dev_name(&phydev->dev));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int __devinit r6040_init_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
@@ -1082,6 +1048,7 @@
|
||||
static int card_idx = -1;
|
||||
int bar = 0;
|
||||
u16 *adrp;
|
||||
+ int i;
|
||||
|
||||
printk("%s\n", version);
|
||||
|
||||
@@ -1169,7 +1136,6 @@
|
||||
/* Init RDC private data */
|
||||
lp->mcr0 = 0x1002;
|
||||
lp->phy_addr = phy_table[card_idx];
|
||||
- lp->switch_sig = 0;
|
||||
|
||||
/* The RDC-specific entries in the device structure. */
|
||||
dev->netdev_ops = &r6040_netdev_ops;
|
||||
@@ -1177,28 +1143,61 @@
|
||||
dev->watchdog_timeo = TX_TIMEOUT;
|
||||
|
||||
netif_napi_add(dev, &lp->napi, r6040_poll, 64);
|
||||
- lp->mii_if.dev = dev;
|
||||
- lp->mii_if.mdio_read = r6040_mdio_read;
|
||||
- lp->mii_if.mdio_write = r6040_mdio_write;
|
||||
- lp->mii_if.phy_id = lp->phy_addr;
|
||||
- lp->mii_if.phy_id_mask = 0x1f;
|
||||
- lp->mii_if.reg_num_mask = 0x1f;
|
||||
+
|
||||
+ lp->mii_bus = mdiobus_alloc();
|
||||
+ if (!lp->mii_bus) {
|
||||
+ printk(KERN_ERR DRV_NAME ": mdiobus_alloc failed\n");
|
||||
+ goto err_out_unmap;
|
||||
+ }
|
||||
+
|
||||
+ lp->mii_bus->priv = dev;
|
||||
+ lp->mii_bus->read = r6040_mdiobus_read;
|
||||
+ lp->mii_bus->write = r6040_mdiobus_write;
|
||||
+ lp->mii_bus->reset = r6040_mdiobus_reset;
|
||||
+ lp->mii_bus->name = "r6040_eth_mii";
|
||||
+ snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
|
||||
+ lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||||
+ if (!lp->mii_bus->irq) {
|
||||
+ printk(KERN_ERR DRV_NAME ": allocation failed\n");
|
||||
+ goto err_out_mdio;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < PHY_MAX_ADDR; i++)
|
||||
+ lp->mii_bus->irq[i] = PHY_POLL;
|
||||
+
|
||||
+ err = mdiobus_register(lp->mii_bus);
|
||||
+ if (err) {
|
||||
+ printk(KERN_ERR DRV_NAME ": failed to register MII bus\n");
|
||||
+ goto err_out_mdio_irq;
|
||||
+ }
|
||||
+
|
||||
+ err = r6040_mii_probe(dev);
|
||||
+ if (err) {
|
||||
+ printk(KERN_ERR DRV_NAME ": failed to probe MII bus\n");
|
||||
+ goto err_out_mdio_unregister;
|
||||
+ }
|
||||
|
||||
/* Check the vendor ID on the PHY, if 0xffff assume none attached */
|
||||
if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
|
||||
printk(KERN_ERR DRV_NAME ": Failed to detect an attached PHY\n");
|
||||
err = -ENODEV;
|
||||
- goto err_out_unmap;
|
||||
+ goto err_out_mdio_unregister;
|
||||
}
|
||||
|
||||
/* Register net device. After this dev->name assign */
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
|
||||
- goto err_out_unmap;
|
||||
+ goto err_out_mdio_unregister;
|
||||
}
|
||||
return 0;
|
||||
|
||||
+err_out_mdio_unregister:
|
||||
+ mdiobus_unregister(lp->mii_bus);
|
||||
+err_out_mdio_irq:
|
||||
+ kfree(lp->mii_bus->irq);
|
||||
+err_out_mdio:
|
||||
+ mdiobus_free(lp->mii_bus);
|
||||
err_out_unmap:
|
||||
pci_iounmap(pdev, ioaddr);
|
||||
err_out_free_res:
|
||||
@@ -1212,8 +1211,12 @@
|
||||
static void __devexit r6040_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
+ struct r6040_private *lp = netdev_priv(dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
+ mdiobus_unregister(lp->mii_bus);
|
||||
+ kfree(lp->mii_bus->irq);
|
||||
+ mdiobus_free(lp->mii_bus);
|
||||
pci_release_regions(pdev);
|
||||
free_netdev(dev);
|
||||
pci_disable_device(pdev);
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
|
||||
define Profile/ar525w
|
||||
NAME:=Airlink AR525W
|
||||
PACKAGES:=kmod-rt61-pci
|
||||
NAME:=Airlink AR525W
|
||||
PACKAGES:=kmod-rt61-pci kmod-switch-ip175c
|
||||
endef
|
||||
$(eval $(call Profile,ar525w))
|
||||
|
|
Loading…
Reference in a new issue