diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2006-04-24 18:41:31 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-26 06:19:46 -0400 |
commit | 86a0f04387bfa814618bf0c2c8b203899c4fa5d2 (patch) | |
tree | efc0739a5eb89d4374c7365ef2dcbee44004987e /drivers/net/forcedeth.c | |
parent | bdf9c27d020ba50b42949c383c1956216c9fd522 (diff) |
[PATCH] forcedeth: fix initialization
This patch fixes the nic initialization. If the nic was in low power
mode, it brings it back to normal power. Also, it utilizes a new
hardware reset during the init.
I am resending based on feedback, I corrected the register size mapping
and delay after posted write.
Signed-Off-By: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 79 |
1 files changed, 67 insertions, 12 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7627a75f4f7c..9788b1ef2e7d 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -105,6 +105,7 @@ | |||
105 | * 0.50: 20 Jan 2006: Add 8021pq tagging support. | 105 | * 0.50: 20 Jan 2006: Add 8021pq tagging support. |
106 | * 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings. | 106 | * 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings. |
107 | * 0.52: 20 Jan 2006: Add MSI/MSIX support. | 107 | * 0.52: 20 Jan 2006: Add MSI/MSIX support. |
108 | * 0.53: 19 Mar 2006: Fix init from low power mode and add hw reset. | ||
108 | * | 109 | * |
109 | * Known bugs: | 110 | * Known bugs: |
110 | * We suspect that on some hardware no TX done interrupts are generated. | 111 | * We suspect that on some hardware no TX done interrupts are generated. |
@@ -116,7 +117,7 @@ | |||
116 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few | 117 | * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few |
117 | * superfluous timer interrupts from the nic. | 118 | * superfluous timer interrupts from the nic. |
118 | */ | 119 | */ |
119 | #define FORCEDETH_VERSION "0.52" | 120 | #define FORCEDETH_VERSION "0.53" |
120 | #define DRV_NAME "forcedeth" | 121 | #define DRV_NAME "forcedeth" |
121 | 122 | ||
122 | #include <linux/module.h> | 123 | #include <linux/module.h> |
@@ -160,6 +161,7 @@ | |||
160 | #define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ | 161 | #define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ |
161 | #define DEV_HAS_MSI 0x0040 /* device supports MSI */ | 162 | #define DEV_HAS_MSI 0x0040 /* device supports MSI */ |
162 | #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ | 163 | #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ |
164 | #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ | ||
163 | 165 | ||
164 | enum { | 166 | enum { |
165 | NvRegIrqStatus = 0x000, | 167 | NvRegIrqStatus = 0x000, |
@@ -203,6 +205,8 @@ enum { | |||
203 | #define NVREG_MISC1_HD 0x02 | 205 | #define NVREG_MISC1_HD 0x02 |
204 | #define NVREG_MISC1_FORCE 0x3b0f3c | 206 | #define NVREG_MISC1_FORCE 0x3b0f3c |
205 | 207 | ||
208 | NvRegMacReset = 0x3c, | ||
209 | #define NVREG_MAC_RESET_ASSERT 0x0F3 | ||
206 | NvRegTransmitterControl = 0x084, | 210 | NvRegTransmitterControl = 0x084, |
207 | #define NVREG_XMITCTL_START 0x01 | 211 | #define NVREG_XMITCTL_START 0x01 |
208 | NvRegTransmitterStatus = 0x088, | 212 | NvRegTransmitterStatus = 0x088, |
@@ -326,6 +330,10 @@ enum { | |||
326 | NvRegMSIXMap0 = 0x3e0, | 330 | NvRegMSIXMap0 = 0x3e0, |
327 | NvRegMSIXMap1 = 0x3e4, | 331 | NvRegMSIXMap1 = 0x3e4, |
328 | NvRegMSIXIrqStatus = 0x3f0, | 332 | NvRegMSIXIrqStatus = 0x3f0, |
333 | |||
334 | NvRegPowerState2 = 0x600, | ||
335 | #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 | ||
336 | #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 | ||
329 | }; | 337 | }; |
330 | 338 | ||
331 | /* Big endian: should work, but is untested */ | 339 | /* Big endian: should work, but is untested */ |
@@ -414,7 +422,8 @@ typedef union _ring_type { | |||
414 | #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) | 422 | #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) |
415 | 423 | ||
416 | /* Miscelaneous hardware related defines: */ | 424 | /* Miscelaneous hardware related defines: */ |
417 | #define NV_PCI_REGSZ 0x270 | 425 | #define NV_PCI_REGSZ_VER1 0x270 |
426 | #define NV_PCI_REGSZ_VER2 0x604 | ||
418 | 427 | ||
419 | /* various timeout delays: all in usec */ | 428 | /* various timeout delays: all in usec */ |
420 | #define NV_TXRX_RESET_DELAY 4 | 429 | #define NV_TXRX_RESET_DELAY 4 |
@@ -431,6 +440,7 @@ typedef union _ring_type { | |||
431 | #define NV_MIIBUSY_DELAY 50 | 440 | #define NV_MIIBUSY_DELAY 50 |
432 | #define NV_MIIPHY_DELAY 10 | 441 | #define NV_MIIPHY_DELAY 10 |
433 | #define NV_MIIPHY_DELAYMAX 10000 | 442 | #define NV_MIIPHY_DELAYMAX 10000 |
443 | #define NV_MAC_RESET_DELAY 64 | ||
434 | 444 | ||
435 | #define NV_WAKEUPPATTERNS 5 | 445 | #define NV_WAKEUPPATTERNS 5 |
436 | #define NV_WAKEUPMASKENTRIES 4 | 446 | #define NV_WAKEUPMASKENTRIES 4 |
@@ -552,6 +562,8 @@ struct fe_priv { | |||
552 | u32 desc_ver; | 562 | u32 desc_ver; |
553 | u32 txrxctl_bits; | 563 | u32 txrxctl_bits; |
554 | u32 vlanctl_bits; | 564 | u32 vlanctl_bits; |
565 | u32 driver_data; | ||
566 | u32 register_size; | ||
555 | 567 | ||
556 | void __iomem *base; | 568 | void __iomem *base; |
557 | 569 | ||
@@ -919,6 +931,24 @@ static void nv_txrx_reset(struct net_device *dev) | |||
919 | pci_push(base); | 931 | pci_push(base); |
920 | } | 932 | } |
921 | 933 | ||
934 | static void nv_mac_reset(struct net_device *dev) | ||
935 | { | ||
936 | struct fe_priv *np = netdev_priv(dev); | ||
937 | u8 __iomem *base = get_hwbase(dev); | ||
938 | |||
939 | dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name); | ||
940 | writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); | ||
941 | pci_push(base); | ||
942 | writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset); | ||
943 | pci_push(base); | ||
944 | udelay(NV_MAC_RESET_DELAY); | ||
945 | writel(0, base + NvRegMacReset); | ||
946 | pci_push(base); | ||
947 | udelay(NV_MAC_RESET_DELAY); | ||
948 | writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); | ||
949 | pci_push(base); | ||
950 | } | ||
951 | |||
922 | /* | 952 | /* |
923 | * nv_get_stats: dev->get_stats function | 953 | * nv_get_stats: dev->get_stats function |
924 | * Get latest stats value from the nic. | 954 | * Get latest stats value from the nic. |
@@ -1331,7 +1361,7 @@ static void nv_tx_timeout(struct net_device *dev) | |||
1331 | dev->name, (unsigned long)np->ring_addr, | 1361 | dev->name, (unsigned long)np->ring_addr, |
1332 | np->next_tx, np->nic_tx); | 1362 | np->next_tx, np->nic_tx); |
1333 | printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); | 1363 | printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); |
1334 | for (i=0;i<0x400;i+= 32) { | 1364 | for (i=0;i<=np->register_size;i+= 32) { |
1335 | printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", | 1365 | printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", |
1336 | i, | 1366 | i, |
1337 | readl(base + i + 0), readl(base + i + 4), | 1367 | readl(base + i + 0), readl(base + i + 4), |
@@ -2488,11 +2518,11 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2488 | } | 2518 | } |
2489 | 2519 | ||
2490 | #define FORCEDETH_REGS_VER 1 | 2520 | #define FORCEDETH_REGS_VER 1 |
2491 | #define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */ | ||
2492 | 2521 | ||
2493 | static int nv_get_regs_len(struct net_device *dev) | 2522 | static int nv_get_regs_len(struct net_device *dev) |
2494 | { | 2523 | { |
2495 | return FORCEDETH_REGS_SIZE; | 2524 | struct fe_priv *np = netdev_priv(dev); |
2525 | return np->register_size; | ||
2496 | } | 2526 | } |
2497 | 2527 | ||
2498 | static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) | 2528 | static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) |
@@ -2504,7 +2534,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void | |||
2504 | 2534 | ||
2505 | regs->version = FORCEDETH_REGS_VER; | 2535 | regs->version = FORCEDETH_REGS_VER; |
2506 | spin_lock_irq(&np->lock); | 2536 | spin_lock_irq(&np->lock); |
2507 | for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++) | 2537 | for (i = 0;i <= np->register_size/sizeof(u32); i++) |
2508 | rbuf[i] = readl(base + i*sizeof(u32)); | 2538 | rbuf[i] = readl(base + i*sizeof(u32)); |
2509 | spin_unlock_irq(&np->lock); | 2539 | spin_unlock_irq(&np->lock); |
2510 | } | 2540 | } |
@@ -2608,6 +2638,8 @@ static int nv_open(struct net_device *dev) | |||
2608 | dprintk(KERN_DEBUG "nv_open: begin\n"); | 2638 | dprintk(KERN_DEBUG "nv_open: begin\n"); |
2609 | 2639 | ||
2610 | /* 1) erase previous misconfiguration */ | 2640 | /* 1) erase previous misconfiguration */ |
2641 | if (np->driver_data & DEV_HAS_POWER_CNTRL) | ||
2642 | nv_mac_reset(dev); | ||
2611 | /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ | 2643 | /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ |
2612 | writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); | 2644 | writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); |
2613 | writel(0, base + NvRegMulticastAddrB); | 2645 | writel(0, base + NvRegMulticastAddrB); |
@@ -2878,6 +2910,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2878 | unsigned long addr; | 2910 | unsigned long addr; |
2879 | u8 __iomem *base; | 2911 | u8 __iomem *base; |
2880 | int err, i; | 2912 | int err, i; |
2913 | u32 powerstate; | ||
2881 | 2914 | ||
2882 | dev = alloc_etherdev(sizeof(struct fe_priv)); | 2915 | dev = alloc_etherdev(sizeof(struct fe_priv)); |
2883 | err = -ENOMEM; | 2916 | err = -ENOMEM; |
@@ -2910,6 +2943,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2910 | if (err < 0) | 2943 | if (err < 0) |
2911 | goto out_disable; | 2944 | goto out_disable; |
2912 | 2945 | ||
2946 | if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL)) | ||
2947 | np->register_size = NV_PCI_REGSZ_VER2; | ||
2948 | else | ||
2949 | np->register_size = NV_PCI_REGSZ_VER1; | ||
2950 | |||
2913 | err = -EINVAL; | 2951 | err = -EINVAL; |
2914 | addr = 0; | 2952 | addr = 0; |
2915 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 2953 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
@@ -2918,7 +2956,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2918 | pci_resource_len(pci_dev, i), | 2956 | pci_resource_len(pci_dev, i), |
2919 | pci_resource_flags(pci_dev, i)); | 2957 | pci_resource_flags(pci_dev, i)); |
2920 | if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && | 2958 | if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && |
2921 | pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { | 2959 | pci_resource_len(pci_dev, i) >= np->register_size) { |
2922 | addr = pci_resource_start(pci_dev, i); | 2960 | addr = pci_resource_start(pci_dev, i); |
2923 | break; | 2961 | break; |
2924 | } | 2962 | } |
@@ -2929,6 +2967,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2929 | goto out_relreg; | 2967 | goto out_relreg; |
2930 | } | 2968 | } |
2931 | 2969 | ||
2970 | /* copy of driver data */ | ||
2971 | np->driver_data = id->driver_data; | ||
2972 | |||
2932 | /* handle different descriptor versions */ | 2973 | /* handle different descriptor versions */ |
2933 | if (id->driver_data & DEV_HAS_HIGH_DMA) { | 2974 | if (id->driver_data & DEV_HAS_HIGH_DMA) { |
2934 | /* packet format 3: supports 40-bit addressing */ | 2975 | /* packet format 3: supports 40-bit addressing */ |
@@ -2986,7 +3027,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
2986 | } | 3027 | } |
2987 | 3028 | ||
2988 | err = -ENOMEM; | 3029 | err = -ENOMEM; |
2989 | np->base = ioremap(addr, NV_PCI_REGSZ); | 3030 | np->base = ioremap(addr, np->register_size); |
2990 | if (!np->base) | 3031 | if (!np->base) |
2991 | goto out_relreg; | 3032 | goto out_relreg; |
2992 | dev->base_addr = (unsigned long)np->base; | 3033 | dev->base_addr = (unsigned long)np->base; |
@@ -3062,6 +3103,20 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
3062 | writel(0, base + NvRegWakeUpFlags); | 3103 | writel(0, base + NvRegWakeUpFlags); |
3063 | np->wolenabled = 0; | 3104 | np->wolenabled = 0; |
3064 | 3105 | ||
3106 | if (id->driver_data & DEV_HAS_POWER_CNTRL) { | ||
3107 | u8 revision_id; | ||
3108 | pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id); | ||
3109 | |||
3110 | /* take phy and nic out of low power mode */ | ||
3111 | powerstate = readl(base + NvRegPowerState2); | ||
3112 | powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; | ||
3113 | if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || | ||
3114 | id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) && | ||
3115 | revision_id >= 0xA3) | ||
3116 | powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; | ||
3117 | writel(powerstate, base + NvRegPowerState2); | ||
3118 | } | ||
3119 | |||
3065 | if (np->desc_ver == DESC_VER_1) { | 3120 | if (np->desc_ver == DESC_VER_1) { |
3066 | np->tx_flags = NV_TX_VALID; | 3121 | np->tx_flags = NV_TX_VALID; |
3067 | } else { | 3122 | } else { |
@@ -3223,19 +3278,19 @@ static struct pci_device_id pci_tbl[] = { | |||
3223 | }, | 3278 | }, |
3224 | { /* MCP51 Ethernet Controller */ | 3279 | { /* MCP51 Ethernet Controller */ |
3225 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), | 3280 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), |
3226 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, | 3281 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, |
3227 | }, | 3282 | }, |
3228 | { /* MCP51 Ethernet Controller */ | 3283 | { /* MCP51 Ethernet Controller */ |
3229 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), | 3284 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), |
3230 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, | 3285 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, |
3231 | }, | 3286 | }, |
3232 | { /* MCP55 Ethernet Controller */ | 3287 | { /* MCP55 Ethernet Controller */ |
3233 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), | 3288 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), |
3234 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, | 3289 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL, |
3235 | }, | 3290 | }, |
3236 | { /* MCP55 Ethernet Controller */ | 3291 | { /* MCP55 Ethernet Controller */ |
3237 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), | 3292 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), |
3238 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, | 3293 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL, |
3239 | }, | 3294 | }, |
3240 | {0,}, | 3295 | {0,}, |
3241 | }; | 3296 | }; |