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) */ |
