diff options
Diffstat (limited to 'drivers/net/sunqe.c')
| -rw-r--r-- | drivers/net/sunqe.c | 468 |
1 files changed, 219 insertions, 249 deletions
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 1f2323be60d4..9da6d5b87173 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | /* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $ | 1 | /* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. |
| 2 | * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. | ||
| 3 | * Once again I am out to prove that every ethernet | 2 | * Once again I am out to prove that every ethernet |
| 4 | * controller out there can be most efficiently programmed | 3 | * controller out there can be most efficiently programmed |
| 5 | * if you make it look like a LANCE. | 4 | * if you make it look like a LANCE. |
| 6 | * | 5 | * |
| 7 | * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com) | 6 | * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net) |
| 8 | */ | 7 | */ |
| 9 | 8 | ||
| 10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| @@ -41,9 +40,9 @@ | |||
| 41 | #include "sunqe.h" | 40 | #include "sunqe.h" |
| 42 | 41 | ||
| 43 | #define DRV_NAME "sunqe" | 42 | #define DRV_NAME "sunqe" |
| 44 | #define DRV_VERSION "3.0" | 43 | #define DRV_VERSION "4.0" |
| 45 | #define DRV_RELDATE "8/24/03" | 44 | #define DRV_RELDATE "June 23, 2006" |
| 46 | #define DRV_AUTHOR "David S. Miller (davem@redhat.com)" | 45 | #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" |
| 47 | 46 | ||
| 48 | static char version[] = | 47 | static char version[] = |
| 49 | DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; | 48 | DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; |
| @@ -755,298 +754,269 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) | |||
| 755 | qecp->gregs + GLOB_RSIZE); | 754 | qecp->gregs + GLOB_RSIZE); |
| 756 | } | 755 | } |
| 757 | 756 | ||
| 758 | /* Four QE's per QEC card. */ | 757 | static u8 __init qec_get_burst(struct device_node *dp) |
| 759 | static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev) | ||
| 760 | { | 758 | { |
| 761 | static unsigned version_printed; | ||
| 762 | struct net_device *qe_devs[4]; | ||
| 763 | struct sunqe *qeps[4]; | ||
| 764 | struct sbus_dev *qesdevs[4]; | ||
| 765 | struct sbus_dev *child; | ||
| 766 | struct sunqec *qecp = NULL; | ||
| 767 | u8 bsizes, bsizes_more; | 759 | u8 bsizes, bsizes_more; |
| 768 | int i, j, res = -ENOMEM; | ||
| 769 | 760 | ||
| 770 | for (i = 0; i < 4; i++) { | 761 | /* Find and set the burst sizes for the QEC, since it |
| 771 | qe_devs[i] = alloc_etherdev(sizeof(struct sunqe)); | 762 | * does the actual dma for all 4 channels. |
| 772 | if (!qe_devs[i]) | 763 | */ |
| 773 | goto out; | 764 | bsizes = of_getintprop_default(dp, "burst-sizes", 0xff); |
| 774 | } | 765 | bsizes &= 0xff; |
| 766 | bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff); | ||
| 775 | 767 | ||
| 776 | if (version_printed++ == 0) | 768 | if (bsizes_more != 0xff) |
| 777 | printk(KERN_INFO "%s", version); | 769 | bsizes &= bsizes_more; |
| 770 | if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || | ||
| 771 | (bsizes & DMA_BURST32)==0) | ||
| 772 | bsizes = (DMA_BURST32 - 1); | ||
| 778 | 773 | ||
| 779 | for (i = 0; i < 4; i++) { | 774 | return bsizes; |
| 780 | qeps[i] = (struct sunqe *) qe_devs[i]->priv; | 775 | } |
| 781 | for (j = 0; j < 6; j++) | ||
| 782 | qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j]; | ||
| 783 | qeps[i]->channel = i; | ||
| 784 | spin_lock_init(&qeps[i]->lock); | ||
| 785 | } | ||
| 786 | 776 | ||
| 787 | qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL); | 777 | static struct sunqec * __init get_qec(struct sbus_dev *child_sdev) |
| 788 | if (qecp == NULL) | 778 | { |
| 789 | goto out1; | 779 | struct sbus_dev *qec_sdev = child_sdev->parent; |
| 790 | qecp->qec_sdev = sdev; | 780 | struct sunqec *qecp; |
| 791 | 781 | ||
| 792 | for (i = 0; i < 4; i++) { | 782 | for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) { |
| 793 | qecp->qes[i] = qeps[i]; | 783 | if (qecp->qec_sdev == qec_sdev) |
| 794 | qeps[i]->dev = qe_devs[i]; | 784 | break; |
| 795 | qeps[i]->parent = qecp; | ||
| 796 | } | 785 | } |
| 786 | if (!qecp) { | ||
| 787 | qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL); | ||
| 788 | if (qecp) { | ||
| 789 | u32 ctrl; | ||
| 790 | |||
| 791 | qecp->qec_sdev = qec_sdev; | ||
| 792 | qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0, | ||
| 793 | GLOB_REG_SIZE, | ||
| 794 | "QEC Global Registers"); | ||
| 795 | if (!qecp->gregs) | ||
| 796 | goto fail; | ||
| 797 | |||
| 798 | /* Make sure the QEC is in MACE mode. */ | ||
| 799 | ctrl = sbus_readl(qecp->gregs + GLOB_CTRL); | ||
| 800 | ctrl &= 0xf0000000; | ||
| 801 | if (ctrl != GLOB_CTRL_MMODE) { | ||
| 802 | printk(KERN_ERR "qec: Not in MACE mode!\n"); | ||
| 803 | goto fail; | ||
| 804 | } | ||
| 797 | 805 | ||
| 798 | res = -ENODEV; | 806 | if (qec_global_reset(qecp->gregs)) |
| 807 | goto fail; | ||
| 799 | 808 | ||
| 800 | for (i = 0, child = sdev->child; i < 4; i++, child = child->next) { | 809 | qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node); |
| 801 | /* Link in channel */ | ||
| 802 | j = prom_getintdefault(child->prom_node, "channel#", -1); | ||
| 803 | if (j == -1) | ||
| 804 | goto out2; | ||
| 805 | qesdevs[j] = child; | ||
| 806 | } | ||
| 807 | 810 | ||
| 808 | for (i = 0; i < 4; i++) | 811 | qec_init_once(qecp, qec_sdev); |
| 809 | qeps[i]->qe_sdev = qesdevs[i]; | ||
| 810 | 812 | ||
| 811 | /* Now map in the registers, QEC globals first. */ | 813 | if (request_irq(qec_sdev->irqs[0], &qec_interrupt, |
| 812 | qecp->gregs = sbus_ioremap(&sdev->resource[0], 0, | 814 | SA_SHIRQ, "qec", (void *) qecp)) { |
| 813 | GLOB_REG_SIZE, "QEC Global Registers"); | 815 | printk(KERN_ERR "qec: Can't register irq.\n"); |
| 814 | if (!qecp->gregs) { | 816 | goto fail; |
| 815 | printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n"); | 817 | } |
| 816 | goto out2; | ||
| 817 | } | ||
| 818 | 818 | ||
| 819 | /* Make sure the QEC is in MACE mode. */ | 819 | qecp->next_module = root_qec_dev; |
| 820 | if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) { | 820 | root_qec_dev = qecp; |
| 821 | printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n"); | 821 | } |
| 822 | goto out3; | ||
| 823 | } | 822 | } |
| 824 | 823 | ||
| 825 | /* Reset the QEC. */ | 824 | return qecp; |
| 826 | if (qec_global_reset(qecp->gregs)) | ||
| 827 | goto out3; | ||
| 828 | 825 | ||
| 829 | /* Find and set the burst sizes for the QEC, since it does | 826 | fail: |
| 830 | * the actual dma for all 4 channels. | 827 | if (qecp->gregs) |
| 831 | */ | 828 | sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); |
| 832 | bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff); | 829 | kfree(qecp); |
| 833 | bsizes &= 0xff; | 830 | return NULL; |
| 834 | bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff); | 831 | } |
| 835 | 832 | ||
| 836 | if (bsizes_more != 0xff) | 833 | static int __init qec_ether_init(struct sbus_dev *sdev) |
| 837 | bsizes &= bsizes_more; | 834 | { |
| 838 | if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || | 835 | static unsigned version_printed; |
| 839 | (bsizes & DMA_BURST32)==0) | 836 | struct net_device *dev; |
| 840 | bsizes = (DMA_BURST32 - 1); | 837 | struct sunqe *qe; |
| 838 | struct sunqec *qecp; | ||
| 839 | int i, res; | ||
| 841 | 840 | ||
| 842 | qecp->qec_bursts = bsizes; | 841 | if (version_printed++ == 0) |
| 842 | printk(KERN_INFO "%s", version); | ||
| 843 | 843 | ||
| 844 | /* Perform one time QEC initialization, we never touch the QEC | 844 | dev = alloc_etherdev(sizeof(struct sunqe)); |
| 845 | * globals again after this. | 845 | if (!dev) |
| 846 | */ | 846 | return -ENOMEM; |
| 847 | qec_init_once(qecp, sdev); | ||
| 848 | |||
| 849 | for (i = 0; i < 4; i++) { | ||
| 850 | struct sunqe *qe = qeps[i]; | ||
| 851 | /* Map in QEC per-channel control registers. */ | ||
| 852 | qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, | ||
| 853 | CREG_REG_SIZE, "QEC Channel Registers"); | ||
| 854 | if (!qe->qcregs) { | ||
| 855 | printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i); | ||
| 856 | goto out4; | ||
| 857 | } | ||
| 858 | 847 | ||
| 859 | /* Map in per-channel AMD MACE registers. */ | 848 | qe = netdev_priv(dev); |
| 860 | qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, | ||
| 861 | MREGS_REG_SIZE, "QE MACE Registers"); | ||
| 862 | if (!qe->mregs) { | ||
| 863 | printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i); | ||
| 864 | goto out4; | ||
| 865 | } | ||
| 866 | 849 | ||
| 867 | qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, | 850 | i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); |
| 868 | PAGE_SIZE, | 851 | if (i == -1) { |
| 869 | &qe->qblock_dvma); | 852 | struct sbus_dev *td = sdev->parent->child; |
| 870 | qe->buffers = sbus_alloc_consistent(qe->qe_sdev, | 853 | i = 0; |
| 871 | sizeof(struct sunqe_buffers), | 854 | while (td != sdev) { |
| 872 | &qe->buffers_dvma); | 855 | td = td->next; |
| 873 | if (qe->qe_block == NULL || qe->qblock_dvma == 0 || | 856 | i++; |
| 874 | qe->buffers == NULL || qe->buffers_dvma == 0) { | ||
| 875 | goto out4; | ||
| 876 | } | 857 | } |
| 877 | |||
| 878 | /* Stop this QE. */ | ||
| 879 | qe_stop(qe); | ||
| 880 | } | 858 | } |
| 859 | qe->channel = i; | ||
| 860 | spin_lock_init(&qe->lock); | ||
| 861 | |||
| 862 | res = -ENODEV; | ||
| 863 | qecp = get_qec(sdev); | ||
| 864 | if (!qecp) | ||
| 865 | goto fail; | ||
| 881 | 866 | ||
| 882 | for (i = 0; i < 4; i++) { | 867 | qecp->qes[qe->channel] = qe; |
| 883 | SET_MODULE_OWNER(qe_devs[i]); | 868 | qe->dev = dev; |
| 884 | qe_devs[i]->open = qe_open; | 869 | qe->parent = qecp; |
| 885 | qe_devs[i]->stop = qe_close; | 870 | qe->qe_sdev = sdev; |
| 886 | qe_devs[i]->hard_start_xmit = qe_start_xmit; | ||
| 887 | qe_devs[i]->get_stats = qe_get_stats; | ||
| 888 | qe_devs[i]->set_multicast_list = qe_set_multicast; | ||
| 889 | qe_devs[i]->tx_timeout = qe_tx_timeout; | ||
| 890 | qe_devs[i]->watchdog_timeo = 5*HZ; | ||
| 891 | qe_devs[i]->irq = sdev->irqs[0]; | ||
| 892 | qe_devs[i]->dma = 0; | ||
| 893 | qe_devs[i]->ethtool_ops = &qe_ethtool_ops; | ||
| 894 | } | ||
| 895 | 871 | ||
| 896 | /* QEC receives interrupts from each QE, then it sends the actual | 872 | res = -ENOMEM; |
| 897 | * IRQ to the cpu itself. Since QEC is the single point of | 873 | qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, |
| 898 | * interrupt for all QE channels we register the IRQ handler | 874 | CREG_REG_SIZE, "QEC Channel Registers"); |
| 899 | * for it now. | 875 | if (!qe->qcregs) { |
| 900 | */ | 876 | printk(KERN_ERR "qe: Cannot map channel registers.\n"); |
| 901 | if (request_irq(sdev->irqs[0], &qec_interrupt, | 877 | goto fail; |
| 902 | SA_SHIRQ, "QuadEther", (void *) qecp)) { | ||
| 903 | printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n"); | ||
| 904 | res = -EAGAIN; | ||
| 905 | goto out4; | ||
| 906 | } | 878 | } |
| 907 | 879 | ||
| 908 | for (i = 0; i < 4; i++) { | 880 | qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, |
| 909 | if (register_netdev(qe_devs[i]) != 0) | 881 | MREGS_REG_SIZE, "QE MACE Registers"); |
| 910 | goto out5; | 882 | if (!qe->mregs) { |
| 883 | printk(KERN_ERR "qe: Cannot map MACE registers.\n"); | ||
| 884 | goto fail; | ||
| 911 | } | 885 | } |
| 912 | 886 | ||
| 913 | /* Report the QE channels. */ | 887 | qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, |
| 914 | for (i = 0; i < 4; i++) { | 888 | PAGE_SIZE, |
| 915 | printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i); | 889 | &qe->qblock_dvma); |
| 916 | for (j = 0; j < 6; j++) | 890 | qe->buffers = sbus_alloc_consistent(qe->qe_sdev, |
| 917 | printk ("%2.2x%c", | 891 | sizeof(struct sunqe_buffers), |
| 918 | qe_devs[i]->dev_addr[j], | 892 | &qe->buffers_dvma); |
| 919 | j == 5 ? ' ': ':'); | 893 | if (qe->qe_block == NULL || qe->qblock_dvma == 0 || |
| 920 | printk("\n"); | 894 | qe->buffers == NULL || qe->buffers_dvma == 0) |
| 921 | } | 895 | goto fail; |
| 896 | |||
| 897 | /* Stop this QE. */ | ||
| 898 | qe_stop(qe); | ||
| 899 | |||
| 900 | SET_MODULE_OWNER(dev); | ||
| 901 | SET_NETDEV_DEV(dev, &sdev->ofdev.dev); | ||
| 902 | |||
| 903 | dev->open = qe_open; | ||
| 904 | dev->stop = qe_close; | ||
| 905 | dev->hard_start_xmit = qe_start_xmit; | ||
| 906 | dev->get_stats = qe_get_stats; | ||
| 907 | dev->set_multicast_list = qe_set_multicast; | ||
| 908 | dev->tx_timeout = qe_tx_timeout; | ||
| 909 | dev->watchdog_timeo = 5*HZ; | ||
| 910 | dev->irq = sdev->irqs[0]; | ||
| 911 | dev->dma = 0; | ||
| 912 | dev->ethtool_ops = &qe_ethtool_ops; | ||
| 913 | |||
| 914 | res = register_netdev(dev); | ||
| 915 | if (res) | ||
| 916 | goto fail; | ||
| 917 | |||
| 918 | dev_set_drvdata(&sdev->ofdev.dev, qe); | ||
| 919 | |||
| 920 | printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel); | ||
| 921 | for (i = 0; i < 6; i++) | ||
| 922 | printk ("%2.2x%c", | ||
| 923 | dev->dev_addr[i], | ||
| 924 | i == 5 ? ' ': ':'); | ||
| 925 | printk("\n"); | ||
| 922 | 926 | ||
| 923 | /* We are home free at this point, link the qe's into | ||
| 924 | * the master list for later driver exit. | ||
| 925 | */ | ||
| 926 | qecp->next_module = root_qec_dev; | ||
| 927 | root_qec_dev = qecp; | ||
| 928 | 927 | ||
| 929 | return 0; | 928 | return 0; |
| 930 | 929 | ||
| 931 | out5: | 930 | fail: |
| 932 | while (i--) | 931 | if (qe->qcregs) |
| 933 | unregister_netdev(qe_devs[i]); | 932 | sbus_iounmap(qe->qcregs, CREG_REG_SIZE); |
| 934 | free_irq(sdev->irqs[0], (void *)qecp); | 933 | if (qe->mregs) |
| 935 | out4: | 934 | sbus_iounmap(qe->mregs, MREGS_REG_SIZE); |
| 936 | for (i = 0; i < 4; i++) { | 935 | if (qe->qe_block) |
| 937 | struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; | 936 | sbus_free_consistent(qe->qe_sdev, |
| 938 | 937 | PAGE_SIZE, | |
| 939 | if (qe->qcregs) | 938 | qe->qe_block, |
| 940 | sbus_iounmap(qe->qcregs, CREG_REG_SIZE); | 939 | qe->qblock_dvma); |
| 941 | if (qe->mregs) | 940 | if (qe->buffers) |
| 942 | sbus_iounmap(qe->mregs, MREGS_REG_SIZE); | 941 | sbus_free_consistent(qe->qe_sdev, |
| 943 | if (qe->qe_block) | 942 | sizeof(struct sunqe_buffers), |
| 944 | sbus_free_consistent(qe->qe_sdev, | 943 | qe->buffers, |
| 945 | PAGE_SIZE, | 944 | qe->buffers_dvma); |
| 946 | qe->qe_block, | 945 | |
| 947 | qe->qblock_dvma); | 946 | free_netdev(dev); |
| 948 | if (qe->buffers) | 947 | |
| 949 | sbus_free_consistent(qe->qe_sdev, | ||
| 950 | sizeof(struct sunqe_buffers), | ||
| 951 | qe->buffers, | ||
| 952 | qe->buffers_dvma); | ||
| 953 | } | ||
| 954 | out3: | ||
| 955 | sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); | ||
| 956 | out2: | ||
| 957 | kfree(qecp); | ||
| 958 | out1: | ||
| 959 | i = 4; | ||
| 960 | out: | ||
| 961 | while (i--) | ||
| 962 | free_netdev(qe_devs[i]); | ||
| 963 | return res; | 948 | return res; |
| 964 | } | 949 | } |
| 965 | 950 | ||
| 966 | static int __init qec_match(struct sbus_dev *sdev) | 951 | static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match) |
| 967 | { | 952 | { |
| 968 | struct sbus_dev *sibling; | 953 | struct sbus_dev *sdev = to_sbus_device(&dev->dev); |
| 969 | int i; | ||
| 970 | |||
| 971 | if (strcmp(sdev->prom_name, "qec") != 0) | ||
| 972 | return 0; | ||
| 973 | 954 | ||
| 974 | /* QEC can be parent of either QuadEthernet or BigMAC | 955 | return qec_ether_init(sdev); |
| 975 | * children. Do not confuse this with qfe/SUNW,qfe | ||
| 976 | * which is a quad-happymeal card and handled by | ||
| 977 | * a different driver. | ||
| 978 | */ | ||
| 979 | sibling = sdev->child; | ||
| 980 | for (i = 0; i < 4; i++) { | ||
| 981 | if (sibling == NULL) | ||
| 982 | return 0; | ||
| 983 | if (strcmp(sibling->prom_name, "qe") != 0) | ||
| 984 | return 0; | ||
| 985 | sibling = sibling->next; | ||
| 986 | } | ||
| 987 | return 1; | ||
| 988 | } | 956 | } |
| 989 | 957 | ||
| 990 | static int __init qec_probe(void) | 958 | static int __devexit qec_sbus_remove(struct of_device *dev) |
| 991 | { | 959 | { |
| 992 | struct net_device *dev = NULL; | 960 | struct sunqe *qp = dev_get_drvdata(&dev->dev); |
| 993 | struct sbus_bus *bus; | 961 | struct net_device *net_dev = qp->dev; |
| 994 | struct sbus_dev *sdev = NULL; | 962 | |
| 995 | static int called; | 963 | unregister_netdevice(net_dev); |
| 996 | int cards = 0, v; | 964 | |
| 997 | 965 | sbus_iounmap(qp->qcregs, CREG_REG_SIZE); | |
| 998 | root_qec_dev = NULL; | 966 | sbus_iounmap(qp->mregs, MREGS_REG_SIZE); |
| 999 | 967 | sbus_free_consistent(qp->qe_sdev, | |
| 1000 | if (called) | 968 | PAGE_SIZE, |
| 1001 | return -ENODEV; | 969 | qp->qe_block, |
| 1002 | called++; | 970 | qp->qblock_dvma); |
| 1003 | 971 | sbus_free_consistent(qp->qe_sdev, | |
| 1004 | for_each_sbus(bus) { | 972 | sizeof(struct sunqe_buffers), |
| 1005 | for_each_sbusdev(sdev, bus) { | 973 | qp->buffers, |
| 1006 | if (cards) | 974 | qp->buffers_dvma); |
| 1007 | dev = NULL; | 975 | |
| 1008 | 976 | free_netdev(net_dev); | |
| 1009 | if (qec_match(sdev)) { | 977 | |
| 1010 | cards++; | 978 | dev_set_drvdata(&dev->dev, NULL); |
| 1011 | if ((v = qec_ether_init(dev, sdev))) | 979 | |
| 1012 | return v; | ||
| 1013 | } | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | if (!cards) | ||
| 1017 | return -ENODEV; | ||
| 1018 | return 0; | 980 | return 0; |
| 1019 | } | 981 | } |
| 1020 | 982 | ||
| 1021 | static void __exit qec_cleanup(void) | 983 | static struct of_device_id qec_sbus_match[] = { |
| 984 | { | ||
| 985 | .name = "qe", | ||
| 986 | }, | ||
| 987 | {}, | ||
| 988 | }; | ||
| 989 | |||
| 990 | MODULE_DEVICE_TABLE(of, qec_sbus_match); | ||
| 991 | |||
| 992 | static struct of_platform_driver qec_sbus_driver = { | ||
| 993 | .name = "qec", | ||
| 994 | .match_table = qec_sbus_match, | ||
| 995 | .probe = qec_sbus_probe, | ||
| 996 | .remove = __devexit_p(qec_sbus_remove), | ||
| 997 | }; | ||
| 998 | |||
| 999 | static int __init qec_init(void) | ||
| 1000 | { | ||
| 1001 | return of_register_driver(&qec_sbus_driver, &sbus_bus_type); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static void __exit qec_exit(void) | ||
| 1022 | { | 1005 | { |
| 1023 | struct sunqec *next_qec; | 1006 | of_unregister_driver(&qec_sbus_driver); |
| 1024 | int i; | ||
| 1025 | 1007 | ||
| 1026 | while (root_qec_dev) { | 1008 | while (root_qec_dev) { |
| 1027 | next_qec = root_qec_dev->next_module; | 1009 | struct sunqec *next = root_qec_dev->next_module; |
| 1028 | 1010 | ||
| 1029 | /* Release all four QE channels, then the QEC itself. */ | 1011 | free_irq(root_qec_dev->qec_sdev->irqs[0], |
| 1030 | for (i = 0; i < 4; i++) { | 1012 | (void *) root_qec_dev); |
| 1031 | unregister_netdev(root_qec_dev->qes[i]->dev); | ||
| 1032 | sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE); | ||
| 1033 | sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE); | ||
| 1034 | sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, | ||
| 1035 | PAGE_SIZE, | ||
| 1036 | root_qec_dev->qes[i]->qe_block, | ||
| 1037 | root_qec_dev->qes[i]->qblock_dvma); | ||
| 1038 | sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, | ||
| 1039 | sizeof(struct sunqe_buffers), | ||
| 1040 | root_qec_dev->qes[i]->buffers, | ||
| 1041 | root_qec_dev->qes[i]->buffers_dvma); | ||
| 1042 | free_netdev(root_qec_dev->qes[i]->dev); | ||
| 1043 | } | ||
| 1044 | free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev); | ||
| 1045 | sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); | 1013 | sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); |
| 1014 | |||
| 1046 | kfree(root_qec_dev); | 1015 | kfree(root_qec_dev); |
| 1047 | root_qec_dev = next_qec; | 1016 | |
| 1017 | root_qec_dev = next; | ||
| 1048 | } | 1018 | } |
| 1049 | } | 1019 | } |
| 1050 | 1020 | ||
| 1051 | module_init(qec_probe); | 1021 | module_init(qec_init); |
| 1052 | module_exit(qec_cleanup); | 1022 | module_exit(qec_exit); |
