aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2010-05-31 05:18:57 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-01 03:15:49 -0400
commit3831861b4ad8fd0ad7110048eb3e155628799d2b (patch)
tree7c6b010e3cb67ba3c113fdf542368aa42390ac46 /drivers/net
parent0da529a7d996f100569040857ddf4d63a1b24e82 (diff)
r6040: implement phylib
This patch adds support for using phylib and adds the required mdiobus driver stubs. This allows for less code to be present in the driver and removes the PHY status specific timer which is now handled by phylib directly. Signed-off-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/r6040.c298
2 files changed, 145 insertions, 154 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2decc597bda7..fe113d0e9456 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1659,6 +1659,7 @@ config R6040
1659 depends on NET_PCI && PCI 1659 depends on NET_PCI && PCI
1660 select CRC32 1660 select CRC32
1661 select MII 1661 select MII
1662 select PHYLIB
1662 help 1663 help
1663 This is a driver for the R6040 Fast Ethernet MACs found in the 1664 This is a driver for the R6040 Fast Ethernet MACs found in the
1664 the RDC R-321x System-on-chips. 1665 the RDC R-321x System-on-chips.
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 9a251acf5ab8..6878511afc4e 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -44,6 +44,7 @@
44#include <linux/io.h> 44#include <linux/io.h>
45#include <linux/irq.h> 45#include <linux/irq.h>
46#include <linux/uaccess.h> 46#include <linux/uaccess.h>
47#include <linux/phy.h>
47 48
48#include <asm/processor.h> 49#include <asm/processor.h>
49 50
@@ -179,7 +180,6 @@ struct r6040_descriptor {
179 180
180struct r6040_private { 181struct r6040_private {
181 spinlock_t lock; /* driver lock */ 182 spinlock_t lock; /* driver lock */
182 struct timer_list timer;
183 struct pci_dev *pdev; 183 struct pci_dev *pdev;
184 struct r6040_descriptor *rx_insert_ptr; 184 struct r6040_descriptor *rx_insert_ptr;
185 struct r6040_descriptor *rx_remove_ptr; 185 struct r6040_descriptor *rx_remove_ptr;
@@ -189,13 +189,15 @@ struct r6040_private {
189 struct r6040_descriptor *tx_ring; 189 struct r6040_descriptor *tx_ring;
190 dma_addr_t rx_ring_dma; 190 dma_addr_t rx_ring_dma;
191 dma_addr_t tx_ring_dma; 191 dma_addr_t tx_ring_dma;
192 u16 tx_free_desc, phy_addr, phy_mode; 192 u16 tx_free_desc, phy_addr;
193 u16 mcr0, mcr1; 193 u16 mcr0, mcr1;
194 u16 switch_sig;
195 struct net_device *dev; 194 struct net_device *dev;
196 struct mii_if_info mii_if; 195 struct mii_bus *mii_bus;
197 struct napi_struct napi; 196 struct napi_struct napi;
198 void __iomem *base; 197 void __iomem *base;
198 struct phy_device *phydev;
199 int old_link;
200 int old_duplex;
199}; 201};
200 202
201static char version[] __devinitdata = KERN_INFO DRV_NAME 203static char version[] __devinitdata = KERN_INFO DRV_NAME
@@ -238,20 +240,30 @@ static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val
238 } 240 }
239} 241}
240 242
241static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg) 243static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
242{ 244{
245 struct net_device *dev = bus->priv;
243 struct r6040_private *lp = netdev_priv(dev); 246 struct r6040_private *lp = netdev_priv(dev);
244 void __iomem *ioaddr = lp->base; 247 void __iomem *ioaddr = lp->base;
245 248
246 return (r6040_phy_read(ioaddr, lp->phy_addr, reg)); 249 return r6040_phy_read(ioaddr, phy_addr, reg);
247} 250}
248 251
249static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val) 252static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
253 int reg, u16 value)
250{ 254{
255 struct net_device *dev = bus->priv;
251 struct r6040_private *lp = netdev_priv(dev); 256 struct r6040_private *lp = netdev_priv(dev);
252 void __iomem *ioaddr = lp->base; 257 void __iomem *ioaddr = lp->base;
253 258
254 r6040_phy_write(ioaddr, lp->phy_addr, reg, val); 259 r6040_phy_write(ioaddr, phy_addr, reg, value);
260
261 return 0;
262}
263
264static int r6040_mdiobus_reset(struct mii_bus *bus)
265{
266 return 0;
255} 267}
256 268
257static void r6040_free_txbufs(struct net_device *dev) 269static void r6040_free_txbufs(struct net_device *dev)
@@ -408,10 +420,9 @@ static void r6040_tx_timeout(struct net_device *dev)
408 void __iomem *ioaddr = priv->base; 420 void __iomem *ioaddr = priv->base;
409 421
410 netdev_warn(dev, "transmit timed out, int enable %4.4x " 422 netdev_warn(dev, "transmit timed out, int enable %4.4x "
411 "status %4.4x, PHY status %4.4x\n", 423 "status %4.4x\n",
412 ioread16(ioaddr + MIER), 424 ioread16(ioaddr + MIER),
413 ioread16(ioaddr + MISR), 425 ioread16(ioaddr + MISR));
414 r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
415 426
416 dev->stats.tx_errors++; 427 dev->stats.tx_errors++;
417 428
@@ -463,9 +474,6 @@ static int r6040_close(struct net_device *dev)
463 struct r6040_private *lp = netdev_priv(dev); 474 struct r6040_private *lp = netdev_priv(dev);
464 struct pci_dev *pdev = lp->pdev; 475 struct pci_dev *pdev = lp->pdev;
465 476
466 /* deleted timer */
467 del_timer_sync(&lp->timer);
468
469 spin_lock_irq(&lp->lock); 477 spin_lock_irq(&lp->lock);
470 napi_disable(&lp->napi); 478 napi_disable(&lp->napi);
471 netif_stop_queue(dev); 479 netif_stop_queue(dev);
@@ -495,64 +503,14 @@ static int r6040_close(struct net_device *dev)
495 return 0; 503 return 0;
496} 504}
497 505
498/* Status of PHY CHIP */
499static int r6040_phy_mode_chk(struct net_device *dev)
500{
501 struct r6040_private *lp = netdev_priv(dev);
502 void __iomem *ioaddr = lp->base;
503 int phy_dat;
504
505 /* PHY Link Status Check */
506 phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
507 if (!(phy_dat & 0x4))
508 phy_dat = 0x8000; /* Link Failed, full duplex */
509
510 /* PHY Chip Auto-Negotiation Status */
511 phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
512 if (phy_dat & 0x0020) {
513 /* Auto Negotiation Mode */
514 phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
515 phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
516 if (phy_dat & 0x140)
517 /* Force full duplex */
518 phy_dat = 0x8000;
519 else
520 phy_dat = 0;
521 } else {
522 /* Force Mode */
523 phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
524 if (phy_dat & 0x100)
525 phy_dat = 0x8000;
526 else
527 phy_dat = 0x0000;
528 }
529
530 return phy_dat;
531};
532
533static void r6040_set_carrier(struct mii_if_info *mii)
534{
535 if (r6040_phy_mode_chk(mii->dev)) {
536 /* autoneg is off: Link is always assumed to be up */
537 if (!netif_carrier_ok(mii->dev))
538 netif_carrier_on(mii->dev);
539 } else
540 r6040_phy_mode_chk(mii->dev);
541}
542
543static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 506static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
544{ 507{
545 struct r6040_private *lp = netdev_priv(dev); 508 struct r6040_private *lp = netdev_priv(dev);
546 struct mii_ioctl_data *data = if_mii(rq);
547 int rc;
548 509
549 if (!netif_running(dev)) 510 if (!lp->phydev)
550 return -EINVAL; 511 return -EINVAL;
551 spin_lock_irq(&lp->lock); 512
552 rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); 513 return phy_mii_ioctl(lp->phydev, if_mii(rq), cmd);
553 spin_unlock_irq(&lp->lock);
554 r6040_set_carrier(&lp->mii_if);
555 return rc;
556} 514}
557 515
558static int r6040_rx(struct net_device *dev, int limit) 516static int r6040_rx(struct net_device *dev, int limit)
@@ -751,26 +709,6 @@ static int r6040_up(struct net_device *dev)
751 if (ret) 709 if (ret)
752 return ret; 710 return ret;
753 711
754 /* Read the PHY ID */
755 lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
756
757 if (lp->switch_sig == ICPLUS_PHY_ID) {
758 r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
759 lp->phy_mode = 0x8000;
760 } else {
761 /* PHY Mode Check */
762 r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
763 r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
764
765 if (PHY_MODE == 0x3100)
766 lp->phy_mode = r6040_phy_mode_chk(dev);
767 else
768 lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
769 }
770
771 /* Set duplex mode */
772 lp->mcr0 |= lp->phy_mode;
773
774 /* improve performance (by RDC guys) */ 712 /* improve performance (by RDC guys) */
775 r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000)); 713 r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
776 r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000)); 714 r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
@@ -783,35 +721,6 @@ static int r6040_up(struct net_device *dev)
783 return 0; 721 return 0;
784} 722}
785 723
786/*
787 A periodic timer routine
788 Polling PHY Chip Link Status
789*/
790static void r6040_timer(unsigned long data)
791{
792 struct net_device *dev = (struct net_device *)data;
793 struct r6040_private *lp = netdev_priv(dev);
794 void __iomem *ioaddr = lp->base;
795 u16 phy_mode;
796
797 /* Polling PHY Chip Status */
798 if (PHY_MODE == 0x3100)
799 phy_mode = r6040_phy_mode_chk(dev);
800 else
801 phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
802
803 if (phy_mode != lp->phy_mode) {
804 lp->phy_mode = phy_mode;
805 lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
806 iowrite16(lp->mcr0, ioaddr);
807 }
808
809 /* Timer active again */
810 mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
811
812 /* Check media */
813 mii_check_media(&lp->mii_if, 1, 1);
814}
815 724
816/* Read/set MAC address routines */ 725/* Read/set MAC address routines */
817static void r6040_mac_address(struct net_device *dev) 726static void r6040_mac_address(struct net_device *dev)
@@ -873,10 +782,6 @@ static int r6040_open(struct net_device *dev)
873 napi_enable(&lp->napi); 782 napi_enable(&lp->napi);
874 netif_start_queue(dev); 783 netif_start_queue(dev);
875 784
876 /* set and active a timer process */
877 setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
878 if (lp->switch_sig != ICPLUS_PHY_ID)
879 mod_timer(&lp->timer, jiffies + HZ);
880 return 0; 785 return 0;
881} 786}
882 787
@@ -1015,40 +920,22 @@ static void netdev_get_drvinfo(struct net_device *dev,
1015static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 920static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1016{ 921{
1017 struct r6040_private *rp = netdev_priv(dev); 922 struct r6040_private *rp = netdev_priv(dev);
1018 int rc;
1019
1020 spin_lock_irq(&rp->lock);
1021 rc = mii_ethtool_gset(&rp->mii_if, cmd);
1022 spin_unlock_irq(&rp->lock);
1023 923
1024 return rc; 924 return phy_ethtool_gset(rp->phydev, cmd);
1025} 925}
1026 926
1027static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 927static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1028{ 928{
1029 struct r6040_private *rp = netdev_priv(dev); 929 struct r6040_private *rp = netdev_priv(dev);
1030 int rc;
1031
1032 spin_lock_irq(&rp->lock);
1033 rc = mii_ethtool_sset(&rp->mii_if, cmd);
1034 spin_unlock_irq(&rp->lock);
1035 r6040_set_carrier(&rp->mii_if);
1036
1037 return rc;
1038}
1039
1040static u32 netdev_get_link(struct net_device *dev)
1041{
1042 struct r6040_private *rp = netdev_priv(dev);
1043 930
1044 return mii_link_ok(&rp->mii_if); 931 return phy_ethtool_sset(rp->phydev, cmd);
1045} 932}
1046 933
1047static const struct ethtool_ops netdev_ethtool_ops = { 934static const struct ethtool_ops netdev_ethtool_ops = {
1048 .get_drvinfo = netdev_get_drvinfo, 935 .get_drvinfo = netdev_get_drvinfo,
1049 .get_settings = netdev_get_settings, 936 .get_settings = netdev_get_settings,
1050 .set_settings = netdev_set_settings, 937 .set_settings = netdev_set_settings,
1051 .get_link = netdev_get_link, 938 .get_link = ethtool_op_get_link,
1052}; 939};
1053 940
1054static const struct net_device_ops r6040_netdev_ops = { 941static const struct net_device_ops r6040_netdev_ops = {
@@ -1067,6 +954,79 @@ static const struct net_device_ops r6040_netdev_ops = {
1067#endif 954#endif
1068}; 955};
1069 956
957static void r6040_adjust_link(struct net_device *dev)
958{
959 struct r6040_private *lp = netdev_priv(dev);
960 struct phy_device *phydev = lp->phydev;
961 int status_changed = 0;
962 void __iomem *ioaddr = lp->base;
963
964 BUG_ON(!phydev);
965
966 if (lp->old_link != phydev->link) {
967 status_changed = 1;
968 lp->old_link = phydev->link;
969 }
970
971 /* reflect duplex change */
972 if (phydev->link && (lp->old_duplex != phydev->duplex)) {
973 lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
974 iowrite16(lp->mcr0, ioaddr);
975
976 status_changed = 1;
977 lp->old_duplex = phydev->duplex;
978 }
979
980 if (status_changed) {
981 pr_info("%s: link %s", dev->name, phydev->link ?
982 "UP" : "DOWN");
983 if (phydev->link)
984 pr_cont(" - %d/%s", phydev->speed,
985 DUPLEX_FULL == phydev->duplex ? "full" : "half");
986 pr_cont("\n");
987 }
988}
989
990static int r6040_mii_probe(struct net_device *dev)
991{
992 struct r6040_private *lp = netdev_priv(dev);
993 struct phy_device *phydev = NULL;
994
995 phydev = phy_find_first(lp->mii_bus);
996 if (!phydev) {
997 dev_err(&lp->pdev->dev, "no PHY found\n");
998 return -ENODEV;
999 }
1000
1001 phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
1002 0, PHY_INTERFACE_MODE_MII);
1003
1004 if (IS_ERR(phydev)) {
1005 dev_err(&lp->pdev->dev, "could not attach to PHY\n");
1006 return PTR_ERR(phydev);
1007 }
1008
1009 /* mask with MAC supported features */
1010 phydev->supported &= (SUPPORTED_10baseT_Half
1011 | SUPPORTED_10baseT_Full
1012 | SUPPORTED_100baseT_Half
1013 | SUPPORTED_100baseT_Full
1014 | SUPPORTED_Autoneg
1015 | SUPPORTED_MII
1016 | SUPPORTED_TP);
1017
1018 phydev->advertising = phydev->supported;
1019 lp->phydev = phydev;
1020 lp->old_link = 0;
1021 lp->old_duplex = -1;
1022
1023 dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
1024 "(mii_bus:phy_addr=%s)\n",
1025 phydev->drv->name, dev_name(&phydev->dev));
1026
1027 return 0;
1028}
1029
1070static int __devinit r6040_init_one(struct pci_dev *pdev, 1030static int __devinit r6040_init_one(struct pci_dev *pdev,
1071 const struct pci_device_id *ent) 1031 const struct pci_device_id *ent)
1072{ 1032{
@@ -1077,6 +1037,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
1077 static int card_idx = -1; 1037 static int card_idx = -1;
1078 int bar = 0; 1038 int bar = 0;
1079 u16 *adrp; 1039 u16 *adrp;
1040 int i;
1080 1041
1081 printk("%s\n", version); 1042 printk("%s\n", version);
1082 1043
@@ -1163,7 +1124,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
1163 /* Init RDC private data */ 1124 /* Init RDC private data */
1164 lp->mcr0 = 0x1002; 1125 lp->mcr0 = 0x1002;
1165 lp->phy_addr = phy_table[card_idx]; 1126 lp->phy_addr = phy_table[card_idx];
1166 lp->switch_sig = 0;
1167 1127
1168 /* The RDC-specific entries in the device structure. */ 1128 /* The RDC-specific entries in the device structure. */
1169 dev->netdev_ops = &r6040_netdev_ops; 1129 dev->netdev_ops = &r6040_netdev_ops;
@@ -1171,28 +1131,54 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
1171 dev->watchdog_timeo = TX_TIMEOUT; 1131 dev->watchdog_timeo = TX_TIMEOUT;
1172 1132
1173 netif_napi_add(dev, &lp->napi, r6040_poll, 64); 1133 netif_napi_add(dev, &lp->napi, r6040_poll, 64);
1174 lp->mii_if.dev = dev; 1134
1175 lp->mii_if.mdio_read = r6040_mdio_read; 1135 lp->mii_bus = mdiobus_alloc();
1176 lp->mii_if.mdio_write = r6040_mdio_write; 1136 if (!lp->mii_bus) {
1177 lp->mii_if.phy_id = lp->phy_addr; 1137 dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
1178 lp->mii_if.phy_id_mask = 0x1f;
1179 lp->mii_if.reg_num_mask = 0x1f;
1180
1181 /* Check the vendor ID on the PHY, if 0xffff assume none attached */
1182 if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
1183 dev_err(&pdev->dev, "Failed to detect an attached PHY\n");
1184 err = -ENODEV;
1185 goto err_out_unmap; 1138 goto err_out_unmap;
1186 } 1139 }
1187 1140
1141 lp->mii_bus->priv = dev;
1142 lp->mii_bus->read = r6040_mdiobus_read;
1143 lp->mii_bus->write = r6040_mdiobus_write;
1144 lp->mii_bus->reset = r6040_mdiobus_reset;
1145 lp->mii_bus->name = "r6040_eth_mii";
1146 snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
1147 lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
1148 if (!lp->mii_bus->irq) {
1149 dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
1150 goto err_out_mdio;
1151 }
1152
1153 for (i = 0; i < PHY_MAX_ADDR; i++)
1154 lp->mii_bus->irq[i] = PHY_POLL;
1155
1156 err = mdiobus_register(lp->mii_bus);
1157 if (err) {
1158 dev_err(&pdev->dev, "failed to register MII bus\n");
1159 goto err_out_mdio_irq;
1160 }
1161
1162 err = r6040_mii_probe(dev);
1163 if (err) {
1164 dev_err(&pdev->dev, "failed to probe MII bus\n");
1165 goto err_out_mdio_unregister;
1166 }
1167
1188 /* Register net device. After this dev->name assign */ 1168 /* Register net device. After this dev->name assign */
1189 err = register_netdev(dev); 1169 err = register_netdev(dev);
1190 if (err) { 1170 if (err) {
1191 dev_err(&pdev->dev, "Failed to register net device\n"); 1171 dev_err(&pdev->dev, "Failed to register net device\n");
1192 goto err_out_unmap; 1172 goto err_out_mdio_unregister;
1193 } 1173 }
1194 return 0; 1174 return 0;
1195 1175
1176err_out_mdio_unregister:
1177 mdiobus_unregister(lp->mii_bus);
1178err_out_mdio_irq:
1179 kfree(lp->mii_bus->irq);
1180err_out_mdio:
1181 mdiobus_free(lp->mii_bus);
1196err_out_unmap: 1182err_out_unmap:
1197 pci_iounmap(pdev, ioaddr); 1183 pci_iounmap(pdev, ioaddr);
1198err_out_free_res: 1184err_out_free_res:
@@ -1206,8 +1192,12 @@ err_out:
1206static void __devexit r6040_remove_one(struct pci_dev *pdev) 1192static void __devexit r6040_remove_one(struct pci_dev *pdev)
1207{ 1193{
1208 struct net_device *dev = pci_get_drvdata(pdev); 1194 struct net_device *dev = pci_get_drvdata(pdev);
1195 struct r6040_private *lp = netdev_priv(dev);
1209 1196
1210 unregister_netdev(dev); 1197 unregister_netdev(dev);
1198 mdiobus_unregister(lp->mii_bus);
1199 kfree(lp->mii_bus->irq);
1200 mdiobus_free(lp->mii_bus);
1211 pci_release_regions(pdev); 1201 pci_release_regions(pdev);
1212 free_netdev(dev); 1202 free_netdev(dev);
1213 pci_disable_device(pdev); 1203 pci_disable_device(pdev);