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: |