diff options
Diffstat (limited to 'drivers/net/fs_enet/fs_enet-main.c')
| -rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 207 |
1 files changed, 129 insertions, 78 deletions
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f6abff5846b3..df62506a1787 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/bitops.h> | 37 | #include <linux/bitops.h> |
| 38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
| 39 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
| 40 | #include <linux/phy.h> | ||
| 40 | 41 | ||
| 41 | #include <linux/vmalloc.h> | 42 | #include <linux/vmalloc.h> |
| 42 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
| @@ -682,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq) | |||
| 682 | (*fep->ops->post_free_irq)(dev, irq); | 683 | (*fep->ops->post_free_irq)(dev, irq); |
| 683 | } | 684 | } |
| 684 | 685 | ||
| 685 | /**********************************************************************************/ | ||
| 686 | |||
| 687 | /* This interrupt occurs when the PHY detects a link change. */ | ||
| 688 | static irqreturn_t | ||
| 689 | fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 690 | { | ||
| 691 | struct net_device *dev = dev_id; | ||
| 692 | struct fs_enet_private *fep; | ||
| 693 | const struct fs_platform_info *fpi; | ||
| 694 | |||
| 695 | fep = netdev_priv(dev); | ||
| 696 | fpi = fep->fpi; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * Acknowledge the interrupt if possible. If we have not | ||
| 700 | * found the PHY yet we can't process or acknowledge the | ||
| 701 | * interrupt now. Instead we ignore this interrupt for now, | ||
| 702 | * which we can do since it is edge triggered. It will be | ||
| 703 | * acknowledged later by fs_enet_open(). | ||
| 704 | */ | ||
| 705 | if (!fep->phy) | ||
| 706 | return IRQ_NONE; | ||
| 707 | |||
| 708 | fs_mii_ack_int(dev); | ||
| 709 | fs_mii_link_status_change_check(dev, 0); | ||
| 710 | |||
| 711 | return IRQ_HANDLED; | ||
| 712 | } | ||
| 713 | |||
| 714 | static void fs_timeout(struct net_device *dev) | 686 | static void fs_timeout(struct net_device *dev) |
| 715 | { | 687 | { |
| 716 | struct fs_enet_private *fep = netdev_priv(dev); | 688 | struct fs_enet_private *fep = netdev_priv(dev); |
| @@ -722,10 +694,13 @@ static void fs_timeout(struct net_device *dev) | |||
| 722 | spin_lock_irqsave(&fep->lock, flags); | 694 | spin_lock_irqsave(&fep->lock, flags); |
| 723 | 695 | ||
| 724 | if (dev->flags & IFF_UP) { | 696 | if (dev->flags & IFF_UP) { |
| 697 | phy_stop(fep->phydev); | ||
| 725 | (*fep->ops->stop)(dev); | 698 | (*fep->ops->stop)(dev); |
| 726 | (*fep->ops->restart)(dev); | 699 | (*fep->ops->restart)(dev); |
| 700 | phy_start(fep->phydev); | ||
| 727 | } | 701 | } |
| 728 | 702 | ||
| 703 | phy_start(fep->phydev); | ||
| 729 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); | 704 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); |
| 730 | spin_unlock_irqrestore(&fep->lock, flags); | 705 | spin_unlock_irqrestore(&fep->lock, flags); |
| 731 | 706 | ||
| @@ -733,35 +708,112 @@ static void fs_timeout(struct net_device *dev) | |||
| 733 | netif_wake_queue(dev); | 708 | netif_wake_queue(dev); |
| 734 | } | 709 | } |
| 735 | 710 | ||
| 711 | /*----------------------------------------------------------------------------- | ||
| 712 | * generic link-change handler - should be sufficient for most cases | ||
| 713 | *-----------------------------------------------------------------------------*/ | ||
| 714 | static void generic_adjust_link(struct net_device *dev) | ||
| 715 | { | ||
| 716 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 717 | struct phy_device *phydev = fep->phydev; | ||
| 718 | int new_state = 0; | ||
| 719 | |||
| 720 | if (phydev->link) { | ||
| 721 | |||
| 722 | /* adjust to duplex mode */ | ||
| 723 | if (phydev->duplex != fep->oldduplex){ | ||
| 724 | new_state = 1; | ||
| 725 | fep->oldduplex = phydev->duplex; | ||
| 726 | } | ||
| 727 | |||
| 728 | if (phydev->speed != fep->oldspeed) { | ||
| 729 | new_state = 1; | ||
| 730 | fep->oldspeed = phydev->speed; | ||
| 731 | } | ||
| 732 | |||
| 733 | if (!fep->oldlink) { | ||
| 734 | new_state = 1; | ||
| 735 | fep->oldlink = 1; | ||
| 736 | netif_schedule(dev); | ||
| 737 | netif_carrier_on(dev); | ||
| 738 | netif_start_queue(dev); | ||
| 739 | } | ||
| 740 | |||
| 741 | if (new_state) | ||
| 742 | fep->ops->restart(dev); | ||
| 743 | |||
| 744 | } else if (fep->oldlink) { | ||
| 745 | new_state = 1; | ||
| 746 | fep->oldlink = 0; | ||
| 747 | fep->oldspeed = 0; | ||
| 748 | fep->oldduplex = -1; | ||
| 749 | netif_carrier_off(dev); | ||
| 750 | netif_stop_queue(dev); | ||
| 751 | } | ||
| 752 | |||
| 753 | if (new_state && netif_msg_link(fep)) | ||
| 754 | phy_print_status(phydev); | ||
| 755 | } | ||
| 756 | |||
| 757 | |||
| 758 | static void fs_adjust_link(struct net_device *dev) | ||
| 759 | { | ||
| 760 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 761 | unsigned long flags; | ||
| 762 | |||
| 763 | spin_lock_irqsave(&fep->lock, flags); | ||
| 764 | |||
| 765 | if(fep->ops->adjust_link) | ||
| 766 | fep->ops->adjust_link(dev); | ||
| 767 | else | ||
| 768 | generic_adjust_link(dev); | ||
| 769 | |||
| 770 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 771 | } | ||
| 772 | |||
| 773 | static int fs_init_phy(struct net_device *dev) | ||
| 774 | { | ||
| 775 | struct fs_enet_private *fep = netdev_priv(dev); | ||
| 776 | struct phy_device *phydev; | ||
| 777 | |||
| 778 | fep->oldlink = 0; | ||
| 779 | fep->oldspeed = 0; | ||
| 780 | fep->oldduplex = -1; | ||
| 781 | if(fep->fpi->bus_id) | ||
| 782 | phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); | ||
| 783 | else { | ||
| 784 | printk("No phy bus ID specified in BSP code\n"); | ||
| 785 | return -EINVAL; | ||
| 786 | } | ||
| 787 | if (IS_ERR(phydev)) { | ||
| 788 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | ||
| 789 | return PTR_ERR(phydev); | ||
| 790 | } | ||
| 791 | |||
| 792 | fep->phydev = phydev; | ||
| 793 | |||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | |||
| 736 | static int fs_enet_open(struct net_device *dev) | 798 | static int fs_enet_open(struct net_device *dev) |
| 737 | { | 799 | { |
| 738 | struct fs_enet_private *fep = netdev_priv(dev); | 800 | struct fs_enet_private *fep = netdev_priv(dev); |
| 739 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 740 | int r; | 801 | int r; |
| 802 | int err; | ||
| 741 | 803 | ||
| 742 | /* Install our interrupt handler. */ | 804 | /* Install our interrupt handler. */ |
| 743 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); | 805 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); |
| 744 | if (r != 0) { | 806 | if (r != 0) { |
| 745 | printk(KERN_ERR DRV_MODULE_NAME | 807 | printk(KERN_ERR DRV_MODULE_NAME |
| 746 | ": %s Could not allocate FEC IRQ!", dev->name); | 808 | ": %s Could not allocate FS_ENET IRQ!", dev->name); |
| 747 | return -EINVAL; | 809 | return -EINVAL; |
| 748 | } | 810 | } |
| 749 | 811 | ||
| 750 | /* Install our phy interrupt handler */ | 812 | err = fs_init_phy(dev); |
| 751 | if (fpi->phy_irq != -1) { | 813 | if(err) |
| 752 | 814 | return err; | |
| 753 | r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); | ||
| 754 | if (r != 0) { | ||
| 755 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 756 | ": %s Could not allocate PHY IRQ!", dev->name); | ||
| 757 | fs_free_irq(dev, fep->interrupt); | ||
| 758 | return -EINVAL; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | 815 | ||
| 762 | fs_mii_startup(dev); | 816 | phy_start(fep->phydev); |
| 763 | netif_carrier_off(dev); | ||
| 764 | fs_mii_link_status_change_check(dev, 1); | ||
| 765 | 817 | ||
| 766 | return 0; | 818 | return 0; |
| 767 | } | 819 | } |
| @@ -769,20 +821,19 @@ static int fs_enet_open(struct net_device *dev) | |||
| 769 | static int fs_enet_close(struct net_device *dev) | 821 | static int fs_enet_close(struct net_device *dev) |
| 770 | { | 822 | { |
| 771 | struct fs_enet_private *fep = netdev_priv(dev); | 823 | struct fs_enet_private *fep = netdev_priv(dev); |
| 772 | const struct fs_platform_info *fpi = fep->fpi; | ||
| 773 | unsigned long flags; | 824 | unsigned long flags; |
| 774 | 825 | ||
| 775 | netif_stop_queue(dev); | 826 | netif_stop_queue(dev); |
| 776 | netif_carrier_off(dev); | 827 | netif_carrier_off(dev); |
| 777 | fs_mii_shutdown(dev); | 828 | phy_stop(fep->phydev); |
| 778 | 829 | ||
| 779 | spin_lock_irqsave(&fep->lock, flags); | 830 | spin_lock_irqsave(&fep->lock, flags); |
| 780 | (*fep->ops->stop)(dev); | 831 | (*fep->ops->stop)(dev); |
| 781 | spin_unlock_irqrestore(&fep->lock, flags); | 832 | spin_unlock_irqrestore(&fep->lock, flags); |
| 782 | 833 | ||
| 783 | /* release any irqs */ | 834 | /* release any irqs */ |
| 784 | if (fpi->phy_irq != -1) | 835 | phy_disconnect(fep->phydev); |
| 785 | fs_free_irq(dev, fpi->phy_irq); | 836 | fep->phydev = NULL; |
| 786 | fs_free_irq(dev, fep->interrupt); | 837 | fs_free_irq(dev, fep->interrupt); |
| 787 | 838 | ||
| 788 | return 0; | 839 | return 0; |
| @@ -830,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
| 830 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 881 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
| 831 | { | 882 | { |
| 832 | struct fs_enet_private *fep = netdev_priv(dev); | 883 | struct fs_enet_private *fep = netdev_priv(dev); |
| 833 | unsigned long flags; | 884 | return phy_ethtool_gset(fep->phydev, cmd); |
| 834 | int rc; | ||
| 835 | |||
| 836 | spin_lock_irqsave(&fep->lock, flags); | ||
| 837 | rc = mii_ethtool_gset(&fep->mii_if, cmd); | ||
| 838 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 839 | |||
| 840 | return rc; | ||
| 841 | } | 885 | } |
| 842 | 886 | ||
| 843 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 887 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
| 844 | { | 888 | { |
| 845 | struct fs_enet_private *fep = netdev_priv(dev); | 889 | struct fs_enet_private *fep = netdev_priv(dev); |
| 846 | unsigned long flags; | 890 | phy_ethtool_sset(fep->phydev, cmd); |
| 847 | int rc; | 891 | return 0; |
| 848 | |||
| 849 | spin_lock_irqsave(&fep->lock, flags); | ||
| 850 | rc = mii_ethtool_sset(&fep->mii_if, cmd); | ||
| 851 | spin_unlock_irqrestore(&fep->lock, flags); | ||
| 852 | |||
| 853 | return rc; | ||
| 854 | } | 892 | } |
| 855 | 893 | ||
| 856 | static int fs_nway_reset(struct net_device *dev) | 894 | static int fs_nway_reset(struct net_device *dev) |
| 857 | { | 895 | { |
| 858 | struct fs_enet_private *fep = netdev_priv(dev); | 896 | return 0; |
| 859 | return mii_nway_restart(&fep->mii_if); | ||
| 860 | } | 897 | } |
| 861 | 898 | ||
| 862 | static u32 fs_get_msglevel(struct net_device *dev) | 899 | static u32 fs_get_msglevel(struct net_device *dev) |
| @@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
| 898 | return -EINVAL; | 935 | return -EINVAL; |
| 899 | 936 | ||
| 900 | spin_lock_irqsave(&fep->lock, flags); | 937 | spin_lock_irqsave(&fep->lock, flags); |
| 901 | rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); | 938 | rc = phy_mii_ioctl(fep->phydev, mii, cmd); |
| 902 | spin_unlock_irqrestore(&fep->lock, flags); | 939 | spin_unlock_irqrestore(&fep->lock, flags); |
| 903 | return rc; | 940 | return rc; |
| 904 | } | 941 | } |
| @@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev, | |||
| 1030 | } | 1067 | } |
| 1031 | registered = 1; | 1068 | registered = 1; |
| 1032 | 1069 | ||
| 1033 | err = fs_mii_connect(ndev); | ||
| 1034 | if (err != 0) { | ||
| 1035 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1036 | ": %s fs_mii_connect failed.\n", ndev->name); | ||
| 1037 | goto err; | ||
| 1038 | } | ||
| 1039 | 1070 | ||
| 1040 | return ndev; | 1071 | return ndev; |
| 1041 | 1072 | ||
| @@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev) | |||
| 1073 | 1104 | ||
| 1074 | fpi = fep->fpi; | 1105 | fpi = fep->fpi; |
| 1075 | 1106 | ||
| 1076 | fs_mii_disconnect(ndev); | ||
| 1077 | |||
| 1078 | unregister_netdev(ndev); | 1107 | unregister_netdev(ndev); |
| 1079 | 1108 | ||
| 1080 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | 1109 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), |
| @@ -1196,17 +1225,39 @@ static int __init fs_init(void) | |||
| 1196 | r = setup_immap(); | 1225 | r = setup_immap(); |
| 1197 | if (r != 0) | 1226 | if (r != 0) |
| 1198 | return r; | 1227 | return r; |
| 1199 | r = driver_register(&fs_enet_fec_driver); | 1228 | |
| 1229 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
| 1230 | /* let's insert mii stuff */ | ||
| 1231 | r = fs_enet_mdio_bb_init(); | ||
| 1232 | |||
| 1233 | if (r != 0) { | ||
| 1234 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1235 | "BB PHY init failed.\n"); | ||
| 1236 | return r; | ||
| 1237 | } | ||
| 1238 | r = driver_register(&fs_enet_fcc_driver); | ||
| 1200 | if (r != 0) | 1239 | if (r != 0) |
| 1201 | goto err; | 1240 | goto err; |
| 1241 | #endif | ||
| 1202 | 1242 | ||
| 1203 | r = driver_register(&fs_enet_fcc_driver); | 1243 | #ifdef CONFIG_FS_ENET_HAS_FEC |
| 1244 | r = fs_enet_mdio_fec_init(); | ||
| 1245 | if (r != 0) { | ||
| 1246 | printk(KERN_ERR DRV_MODULE_NAME | ||
| 1247 | "FEC PHY init failed.\n"); | ||
| 1248 | return r; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | r = driver_register(&fs_enet_fec_driver); | ||
| 1204 | if (r != 0) | 1252 | if (r != 0) |
| 1205 | goto err; | 1253 | goto err; |
| 1254 | #endif | ||
| 1206 | 1255 | ||
| 1256 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
| 1207 | r = driver_register(&fs_enet_scc_driver); | 1257 | r = driver_register(&fs_enet_scc_driver); |
| 1208 | if (r != 0) | 1258 | if (r != 0) |
| 1209 | goto err; | 1259 | goto err; |
| 1260 | #endif | ||
| 1210 | 1261 | ||
| 1211 | return 0; | 1262 | return 0; |
| 1212 | err: | 1263 | err: |
