diff options
-rw-r--r-- | drivers/net/natsemi.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 109e80252488..223e0e6264ba 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c | |||
@@ -81,6 +81,8 @@ static const int multicast_filter_limit = 100; | |||
81 | Setting to > 1518 effectively disables this feature. */ | 81 | Setting to > 1518 effectively disables this feature. */ |
82 | static int rx_copybreak; | 82 | static int rx_copybreak; |
83 | 83 | ||
84 | static int dspcfg_workaround = 1; | ||
85 | |||
84 | /* Used to pass the media type, etc. | 86 | /* Used to pass the media type, etc. |
85 | Both 'options[]' and 'full_duplex[]' should exist for driver | 87 | Both 'options[]' and 'full_duplex[]' should exist for driver |
86 | interoperability. | 88 | interoperability. |
@@ -139,12 +141,14 @@ MODULE_LICENSE("GPL"); | |||
139 | module_param(mtu, int, 0); | 141 | module_param(mtu, int, 0); |
140 | module_param(debug, int, 0); | 142 | module_param(debug, int, 0); |
141 | module_param(rx_copybreak, int, 0); | 143 | module_param(rx_copybreak, int, 0); |
144 | module_param(dspcfg_workaround, int, 1); | ||
142 | module_param_array(options, int, NULL, 0); | 145 | module_param_array(options, int, NULL, 0); |
143 | module_param_array(full_duplex, int, NULL, 0); | 146 | module_param_array(full_duplex, int, NULL, 0); |
144 | MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); | 147 | MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); |
145 | MODULE_PARM_DESC(debug, "DP8381x default debug level"); | 148 | MODULE_PARM_DESC(debug, "DP8381x default debug level"); |
146 | MODULE_PARM_DESC(rx_copybreak, | 149 | MODULE_PARM_DESC(rx_copybreak, |
147 | "DP8381x copy breakpoint for copy-only-tiny-frames"); | 150 | "DP8381x copy breakpoint for copy-only-tiny-frames"); |
151 | MODULE_PARM_DESC(dspcfg_workaround, "DP8381x: control DspCfg workaround"); | ||
148 | MODULE_PARM_DESC(options, | 152 | MODULE_PARM_DESC(options, |
149 | "DP8381x: Bits 0-3: media type, bit 17: full duplex"); | 153 | "DP8381x: Bits 0-3: media type, bit 17: full duplex"); |
150 | MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); | 154 | MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); |
@@ -590,6 +594,7 @@ struct netdev_private { | |||
590 | u32 srr; | 594 | u32 srr; |
591 | /* expected DSPCFG value */ | 595 | /* expected DSPCFG value */ |
592 | u16 dspcfg; | 596 | u16 dspcfg; |
597 | int dspcfg_workaround; | ||
593 | /* parms saved in ethtool format */ | 598 | /* parms saved in ethtool format */ |
594 | u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ | 599 | u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ |
595 | u8 duplex; /* Duplex, half or full */ | 600 | u8 duplex; /* Duplex, half or full */ |
@@ -656,6 +661,56 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf); | |||
656 | static int netdev_get_eeprom(struct net_device *dev, u8 *buf); | 661 | static int netdev_get_eeprom(struct net_device *dev, u8 *buf); |
657 | static const struct ethtool_ops ethtool_ops; | 662 | static const struct ethtool_ops ethtool_ops; |
658 | 663 | ||
664 | #define NATSEMI_ATTR(_name) \ | ||
665 | static ssize_t natsemi_show_##_name(struct device *dev, \ | ||
666 | struct device_attribute *attr, char *buf); \ | ||
667 | static ssize_t natsemi_set_##_name(struct device *dev, \ | ||
668 | struct device_attribute *attr, \ | ||
669 | const char *buf, size_t count); \ | ||
670 | static DEVICE_ATTR(_name, 0644, natsemi_show_##_name, natsemi_set_##_name) | ||
671 | |||
672 | #define NATSEMI_CREATE_FILE(_dev, _name) \ | ||
673 | device_create_file(&_dev->dev, &dev_attr_##_name) | ||
674 | #define NATSEMI_REMOVE_FILE(_dev, _name) \ | ||
675 | device_create_file(&_dev->dev, &dev_attr_##_name) | ||
676 | |||
677 | NATSEMI_ATTR(dspcfg_workaround); | ||
678 | |||
679 | static ssize_t natsemi_show_dspcfg_workaround(struct device *dev, | ||
680 | struct device_attribute *attr, | ||
681 | char *buf) | ||
682 | { | ||
683 | struct netdev_private *np = netdev_priv(to_net_dev(dev)); | ||
684 | |||
685 | return sprintf(buf, "%s\n", np->dspcfg_workaround ? "on" : "off"); | ||
686 | } | ||
687 | |||
688 | static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, | ||
689 | struct device_attribute *attr, | ||
690 | const char *buf, size_t count) | ||
691 | { | ||
692 | struct netdev_private *np = netdev_priv(to_net_dev(dev)); | ||
693 | int new_setting; | ||
694 | u32 flags; | ||
695 | |||
696 | /* Find out the new setting */ | ||
697 | if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) | ||
698 | new_setting = 1; | ||
699 | else if (!strncmp("off", buf, count - 1) | ||
700 | || !strncmp("0", buf, count - 1)) | ||
701 | new_setting = 0; | ||
702 | else | ||
703 | return count; | ||
704 | |||
705 | spin_lock_irqsave(&np->lock, flags); | ||
706 | |||
707 | np->dspcfg_workaround = new_setting; | ||
708 | |||
709 | spin_unlock_irqrestore(&np->lock, flags); | ||
710 | |||
711 | return count; | ||
712 | } | ||
713 | |||
659 | static inline void __iomem *ns_ioaddr(struct net_device *dev) | 714 | static inline void __iomem *ns_ioaddr(struct net_device *dev) |
660 | { | 715 | { |
661 | return (void __iomem *) dev->base_addr; | 716 | return (void __iomem *) dev->base_addr; |
@@ -820,6 +875,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
820 | np->ignore_phy = 1; | 875 | np->ignore_phy = 1; |
821 | else | 876 | else |
822 | np->ignore_phy = 0; | 877 | np->ignore_phy = 0; |
878 | np->dspcfg_workaround = dspcfg_workaround; | ||
823 | 879 | ||
824 | /* Initial port: | 880 | /* Initial port: |
825 | * - If configured to ignore the PHY set up for external. | 881 | * - If configured to ignore the PHY set up for external. |
@@ -899,6 +955,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
899 | if (i) | 955 | if (i) |
900 | goto err_register_netdev; | 956 | goto err_register_netdev; |
901 | 957 | ||
958 | if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround)) | ||
959 | goto err_create_file; | ||
960 | |||
902 | if (netif_msg_drv(np)) { | 961 | if (netif_msg_drv(np)) { |
903 | printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", | 962 | printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", |
904 | dev->name, natsemi_pci_info[chip_idx].name, iostart, | 963 | dev->name, natsemi_pci_info[chip_idx].name, iostart, |
@@ -915,6 +974,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
915 | } | 974 | } |
916 | return 0; | 975 | return 0; |
917 | 976 | ||
977 | err_create_file: | ||
978 | unregister_netdev(dev); | ||
979 | |||
918 | err_register_netdev: | 980 | err_register_netdev: |
919 | iounmap(ioaddr); | 981 | iounmap(ioaddr); |
920 | 982 | ||
@@ -1727,7 +1789,8 @@ static void init_registers(struct net_device *dev) | |||
1727 | * It seems that a reference set for this chip went out with incorrect info, | 1789 | * It seems that a reference set for this chip went out with incorrect info, |
1728 | * and there exist boards that aren't quite right. An unexpected voltage | 1790 | * and there exist boards that aren't quite right. An unexpected voltage |
1729 | * drop can cause the PHY to get itself in a weird state (basically reset). | 1791 | * drop can cause the PHY to get itself in a weird state (basically reset). |
1730 | * NOTE: this only seems to affect revC chips. | 1792 | * NOTE: this only seems to affect revC chips. The user can disable |
1793 | * this check via dspcfg_workaround sysfs option. | ||
1731 | * 3) check of death of the RX path due to OOM | 1794 | * 3) check of death of the RX path due to OOM |
1732 | */ | 1795 | */ |
1733 | static void netdev_timer(unsigned long data) | 1796 | static void netdev_timer(unsigned long data) |
@@ -1753,7 +1816,7 @@ static void netdev_timer(unsigned long data) | |||
1753 | writew(1, ioaddr+PGSEL); | 1816 | writew(1, ioaddr+PGSEL); |
1754 | dspcfg = readw(ioaddr+DSPCFG); | 1817 | dspcfg = readw(ioaddr+DSPCFG); |
1755 | writew(0, ioaddr+PGSEL); | 1818 | writew(0, ioaddr+PGSEL); |
1756 | if (dspcfg != np->dspcfg) { | 1819 | if (np->dspcfg_workaround && dspcfg != np->dspcfg) { |
1757 | if (!netif_queue_stopped(dev)) { | 1820 | if (!netif_queue_stopped(dev)) { |
1758 | spin_unlock_irq(&np->lock); | 1821 | spin_unlock_irq(&np->lock); |
1759 | if (netif_msg_drv(np)) | 1822 | if (netif_msg_drv(np)) |
@@ -3157,6 +3220,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) | |||
3157 | struct net_device *dev = pci_get_drvdata(pdev); | 3220 | struct net_device *dev = pci_get_drvdata(pdev); |
3158 | void __iomem * ioaddr = ns_ioaddr(dev); | 3221 | void __iomem * ioaddr = ns_ioaddr(dev); |
3159 | 3222 | ||
3223 | NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround); | ||
3160 | unregister_netdev (dev); | 3224 | unregister_netdev (dev); |
3161 | pci_release_regions (pdev); | 3225 | pci_release_regions (pdev); |
3162 | iounmap(ioaddr); | 3226 | iounmap(ioaddr); |