diff options
-rw-r--r-- | drivers/net/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.c | 126 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.h | 6 |
3 files changed, 133 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 372f25716b5b..b86ccd2ecd5b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2488,6 +2488,7 @@ config NETXEN_NIC | |||
2488 | config PASEMI_MAC | 2488 | config PASEMI_MAC |
2489 | tristate "PA Semi 1/10Gbit MAC" | 2489 | tristate "PA Semi 1/10Gbit MAC" |
2490 | depends on PPC64 && PCI | 2490 | depends on PPC64 && PCI |
2491 | select PHYLIB | ||
2491 | help | 2492 | help |
2492 | This driver supports the on-chip 1/10Gbit Ethernet controller on | 2493 | This driver supports the on-chip 1/10Gbit Ethernet controller on |
2493 | PA Semi's PWRficient line of chips. | 2494 | PA Semi's PWRficient line of chips. |
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4c6d34d6989c..78b127c404e9 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
@@ -606,6 +606,114 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) | |||
606 | return IRQ_HANDLED; | 606 | return IRQ_HANDLED; |
607 | } | 607 | } |
608 | 608 | ||
609 | static void pasemi_adjust_link(struct net_device *dev) | ||
610 | { | ||
611 | struct pasemi_mac *mac = netdev_priv(dev); | ||
612 | int msg; | ||
613 | unsigned int flags; | ||
614 | unsigned int new_flags; | ||
615 | |||
616 | if (!mac->phydev->link) { | ||
617 | /* If no link, MAC speed settings don't matter. Just report | ||
618 | * link down and return. | ||
619 | */ | ||
620 | if (mac->link && netif_msg_link(mac)) | ||
621 | printk(KERN_INFO "%s: Link is down.\n", dev->name); | ||
622 | |||
623 | netif_carrier_off(dev); | ||
624 | mac->link = 0; | ||
625 | |||
626 | return; | ||
627 | } else | ||
628 | netif_carrier_on(dev); | ||
629 | |||
630 | pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); | ||
631 | new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | | ||
632 | PAS_MAC_CFG_PCFG_TSR_M); | ||
633 | |||
634 | if (!mac->phydev->duplex) | ||
635 | new_flags |= PAS_MAC_CFG_PCFG_HD; | ||
636 | |||
637 | switch (mac->phydev->speed) { | ||
638 | case 1000: | ||
639 | new_flags |= PAS_MAC_CFG_PCFG_SPD_1G | | ||
640 | PAS_MAC_CFG_PCFG_TSR_1G; | ||
641 | break; | ||
642 | case 100: | ||
643 | new_flags |= PAS_MAC_CFG_PCFG_SPD_100M | | ||
644 | PAS_MAC_CFG_PCFG_TSR_100M; | ||
645 | break; | ||
646 | case 10: | ||
647 | new_flags |= PAS_MAC_CFG_PCFG_SPD_10M | | ||
648 | PAS_MAC_CFG_PCFG_TSR_10M; | ||
649 | break; | ||
650 | default: | ||
651 | printk("Unsupported speed %d\n", mac->phydev->speed); | ||
652 | } | ||
653 | |||
654 | /* Print on link or speed/duplex change */ | ||
655 | msg = mac->link != mac->phydev->link || flags != new_flags; | ||
656 | |||
657 | mac->duplex = mac->phydev->duplex; | ||
658 | mac->speed = mac->phydev->speed; | ||
659 | mac->link = mac->phydev->link; | ||
660 | |||
661 | if (new_flags != flags) | ||
662 | pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags); | ||
663 | |||
664 | if (msg && netif_msg_link(mac)) | ||
665 | printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n", | ||
666 | dev->name, mac->speed, mac->duplex ? "full" : "half"); | ||
667 | } | ||
668 | |||
669 | static int pasemi_mac_phy_init(struct net_device *dev) | ||
670 | { | ||
671 | struct pasemi_mac *mac = netdev_priv(dev); | ||
672 | struct device_node *dn, *phy_dn; | ||
673 | struct phy_device *phydev; | ||
674 | unsigned int phy_id; | ||
675 | const phandle *ph; | ||
676 | const unsigned int *prop; | ||
677 | struct resource r; | ||
678 | int ret; | ||
679 | |||
680 | dn = pci_device_to_OF_node(mac->pdev); | ||
681 | ph = get_property(dn, "phy-handle", NULL); | ||
682 | if (!ph) | ||
683 | return -ENODEV; | ||
684 | phy_dn = of_find_node_by_phandle(*ph); | ||
685 | |||
686 | prop = get_property(phy_dn, "reg", NULL); | ||
687 | ret = of_address_to_resource(phy_dn->parent, 0, &r); | ||
688 | if (ret) | ||
689 | goto err; | ||
690 | |||
691 | phy_id = *prop; | ||
692 | snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id); | ||
693 | |||
694 | of_node_put(phy_dn); | ||
695 | |||
696 | mac->link = 0; | ||
697 | mac->speed = 0; | ||
698 | mac->duplex = -1; | ||
699 | |||
700 | phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); | ||
701 | |||
702 | if (IS_ERR(phydev)) { | ||
703 | printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); | ||
704 | return PTR_ERR(phydev); | ||
705 | } | ||
706 | |||
707 | mac->phydev = phydev; | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | err: | ||
712 | of_node_put(phy_dn); | ||
713 | return -ENODEV; | ||
714 | } | ||
715 | |||
716 | |||
609 | static int pasemi_mac_open(struct net_device *dev) | 717 | static int pasemi_mac_open(struct net_device *dev) |
610 | { | 718 | { |
611 | struct pasemi_mac *mac = netdev_priv(dev); | 719 | struct pasemi_mac *mac = netdev_priv(dev); |
@@ -678,6 +786,13 @@ static int pasemi_mac_open(struct net_device *dev) | |||
678 | 786 | ||
679 | pasemi_mac_replenish_rx_ring(dev); | 787 | pasemi_mac_replenish_rx_ring(dev); |
680 | 788 | ||
789 | ret = pasemi_mac_phy_init(dev); | ||
790 | /* Some configs don't have PHYs (XAUI etc), so don't complain about | ||
791 | * failed init due to -ENODEV. | ||
792 | */ | ||
793 | if (ret && ret != -ENODEV) | ||
794 | dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); | ||
795 | |||
681 | netif_start_queue(dev); | 796 | netif_start_queue(dev); |
682 | netif_poll_enable(dev); | 797 | netif_poll_enable(dev); |
683 | 798 | ||
@@ -708,6 +823,9 @@ static int pasemi_mac_open(struct net_device *dev) | |||
708 | goto out_rx_int; | 823 | goto out_rx_int; |
709 | } | 824 | } |
710 | 825 | ||
826 | if (mac->phydev) | ||
827 | phy_start(mac->phydev); | ||
828 | |||
711 | return 0; | 829 | return 0; |
712 | 830 | ||
713 | out_rx_int: | 831 | out_rx_int: |
@@ -731,6 +849,11 @@ static int pasemi_mac_close(struct net_device *dev) | |||
731 | unsigned int stat; | 849 | unsigned int stat; |
732 | int retries; | 850 | int retries; |
733 | 851 | ||
852 | if (mac->phydev) { | ||
853 | phy_stop(mac->phydev); | ||
854 | phy_disconnect(mac->phydev); | ||
855 | } | ||
856 | |||
734 | netif_stop_queue(dev); | 857 | netif_stop_queue(dev); |
735 | 858 | ||
736 | /* Clean out any pending buffers */ | 859 | /* Clean out any pending buffers */ |
@@ -1028,6 +1151,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1028 | 1151 | ||
1029 | mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); | 1152 | mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); |
1030 | 1153 | ||
1154 | /* Enable most messages by default */ | ||
1155 | mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; | ||
1156 | |||
1031 | err = register_netdev(dev); | 1157 | err = register_netdev(dev); |
1032 | 1158 | ||
1033 | if (err) { | 1159 | if (err) { |
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 6539de1c2f23..8bc0cea8b145 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/ethtool.h> | 24 | #include <linux/ethtool.h> |
25 | #include <linux/netdevice.h> | 25 | #include <linux/netdevice.h> |
26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
27 | #include <linux/phy.h> | ||
27 | 28 | ||
28 | struct pasemi_mac_txring { | 29 | struct pasemi_mac_txring { |
29 | spinlock_t lock; | 30 | spinlock_t lock; |
@@ -54,6 +55,7 @@ struct pasemi_mac { | |||
54 | struct pci_dev *pdev; | 55 | struct pci_dev *pdev; |
55 | struct pci_dev *dma_pdev; | 56 | struct pci_dev *dma_pdev; |
56 | struct pci_dev *iob_pdev; | 57 | struct pci_dev *iob_pdev; |
58 | struct phy_device *phydev; | ||
57 | struct net_device_stats stats; | 59 | struct net_device_stats stats; |
58 | 60 | ||
59 | /* Pointer to the cacheable per-channel status registers */ | 61 | /* Pointer to the cacheable per-channel status registers */ |
@@ -75,8 +77,12 @@ struct pasemi_mac { | |||
75 | struct pasemi_mac_rxring *rx; | 77 | struct pasemi_mac_rxring *rx; |
76 | unsigned long tx_irq; | 78 | unsigned long tx_irq; |
77 | unsigned long rx_irq; | 79 | unsigned long rx_irq; |
80 | int link; | ||
81 | int speed; | ||
82 | int duplex; | ||
78 | 83 | ||
79 | unsigned int msg_enable; | 84 | unsigned int msg_enable; |
85 | char phy_id[BUS_ID_SIZE]; | ||
80 | }; | 86 | }; |
81 | 87 | ||
82 | /* Software status descriptor (desc_info) */ | 88 | /* Software status descriptor (desc_info) */ |