diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/forcedeth.c | 197 |
1 files changed, 194 insertions, 3 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index eaf6de9a9dfa..2b8fbebd44ac 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
| @@ -165,6 +165,7 @@ | |||
| 165 | #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ | 165 | #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ |
| 166 | #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ | 166 | #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ |
| 167 | #define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ | 167 | #define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ |
| 168 | #define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */ | ||
| 168 | 169 | ||
| 169 | enum { | 170 | enum { |
| 170 | NvRegIrqStatus = 0x000, | 171 | NvRegIrqStatus = 0x000, |
| @@ -333,6 +334,33 @@ enum { | |||
| 333 | #define NVREG_POWERSTATE_D1 0x0001 | 334 | #define NVREG_POWERSTATE_D1 0x0001 |
| 334 | #define NVREG_POWERSTATE_D2 0x0002 | 335 | #define NVREG_POWERSTATE_D2 0x0002 |
| 335 | #define NVREG_POWERSTATE_D3 0x0003 | 336 | #define NVREG_POWERSTATE_D3 0x0003 |
| 337 | NvRegTxCnt = 0x280, | ||
| 338 | NvRegTxZeroReXmt = 0x284, | ||
| 339 | NvRegTxOneReXmt = 0x288, | ||
| 340 | NvRegTxManyReXmt = 0x28c, | ||
| 341 | NvRegTxLateCol = 0x290, | ||
| 342 | NvRegTxUnderflow = 0x294, | ||
| 343 | NvRegTxLossCarrier = 0x298, | ||
| 344 | NvRegTxExcessDef = 0x29c, | ||
| 345 | NvRegTxRetryErr = 0x2a0, | ||
| 346 | NvRegRxFrameErr = 0x2a4, | ||
| 347 | NvRegRxExtraByte = 0x2a8, | ||
| 348 | NvRegRxLateCol = 0x2ac, | ||
| 349 | NvRegRxRunt = 0x2b0, | ||
| 350 | NvRegRxFrameTooLong = 0x2b4, | ||
| 351 | NvRegRxOverflow = 0x2b8, | ||
| 352 | NvRegRxFCSErr = 0x2bc, | ||
| 353 | NvRegRxFrameAlignErr = 0x2c0, | ||
| 354 | NvRegRxLenErr = 0x2c4, | ||
| 355 | NvRegRxUnicast = 0x2c8, | ||
| 356 | NvRegRxMulticast = 0x2cc, | ||
| 357 | NvRegRxBroadcast = 0x2d0, | ||
| 358 | NvRegTxDef = 0x2d4, | ||
| 359 | NvRegTxFrame = 0x2d8, | ||
| 360 | NvRegRxCnt = 0x2dc, | ||
| 361 | NvRegTxPause = 0x2e0, | ||
| 362 | NvRegRxPause = 0x2e4, | ||
| 363 | NvRegRxDropFrame = 0x2e8, | ||
| 336 | NvRegVlanControl = 0x300, | 364 | NvRegVlanControl = 0x300, |
| 337 | #define NVREG_VLANCONTROL_ENABLE 0x2000 | 365 | #define NVREG_VLANCONTROL_ENABLE 0x2000 |
| 338 | NvRegMSIXMap0 = 0x3e0, | 366 | NvRegMSIXMap0 = 0x3e0, |
| @@ -481,6 +509,7 @@ typedef union _ring_type { | |||
| 481 | #define OOM_REFILL (1+HZ/20) | 509 | #define OOM_REFILL (1+HZ/20) |
| 482 | #define POLL_WAIT (1+HZ/100) | 510 | #define POLL_WAIT (1+HZ/100) |
| 483 | #define LINK_TIMEOUT (3*HZ) | 511 | #define LINK_TIMEOUT (3*HZ) |
| 512 | #define STATS_INTERVAL (10*HZ) | ||
| 484 | 513 | ||
| 485 | /* | 514 | /* |
| 486 | * desc_ver values: | 515 | * desc_ver values: |
| @@ -536,6 +565,75 @@ typedef union _ring_type { | |||
| 536 | #define NV_MSI_X_VECTOR_TX 0x1 | 565 | #define NV_MSI_X_VECTOR_TX 0x1 |
| 537 | #define NV_MSI_X_VECTOR_OTHER 0x2 | 566 | #define NV_MSI_X_VECTOR_OTHER 0x2 |
| 538 | 567 | ||
| 568 | /* statistics */ | ||
| 569 | struct nv_ethtool_str { | ||
| 570 | char name[ETH_GSTRING_LEN]; | ||
| 571 | }; | ||
| 572 | |||
| 573 | static const struct nv_ethtool_str nv_estats_str[] = { | ||
| 574 | { "tx_bytes" }, | ||
| 575 | { "tx_zero_rexmt" }, | ||
| 576 | { "tx_one_rexmt" }, | ||
| 577 | { "tx_many_rexmt" }, | ||
| 578 | { "tx_late_collision" }, | ||
| 579 | { "tx_fifo_errors" }, | ||
| 580 | { "tx_carrier_errors" }, | ||
| 581 | { "tx_excess_deferral" }, | ||
| 582 | { "tx_retry_error" }, | ||
| 583 | { "tx_deferral" }, | ||
| 584 | { "tx_packets" }, | ||
| 585 | { "tx_pause" }, | ||
| 586 | { "rx_frame_error" }, | ||
| 587 | { "rx_extra_byte" }, | ||
| 588 | { "rx_late_collision" }, | ||
| 589 | { "rx_runt" }, | ||
| 590 | { "rx_frame_too_long" }, | ||
| 591 | { "rx_over_errors" }, | ||
| 592 | { "rx_crc_errors" }, | ||
| 593 | { "rx_frame_align_error" }, | ||
| 594 | { "rx_length_error" }, | ||
| 595 | { "rx_unicast" }, | ||
| 596 | { "rx_multicast" }, | ||
| 597 | { "rx_broadcast" }, | ||
| 598 | { "rx_bytes" }, | ||
| 599 | { "rx_pause" }, | ||
| 600 | { "rx_drop_frame" }, | ||
| 601 | { "rx_packets" }, | ||
| 602 | { "rx_errors_total" } | ||
| 603 | }; | ||
| 604 | |||
| 605 | struct nv_ethtool_stats { | ||
| 606 | u64 tx_bytes; | ||
| 607 | u64 tx_zero_rexmt; | ||
| 608 | u64 tx_one_rexmt; | ||
| 609 | u64 tx_many_rexmt; | ||
| 610 | u64 tx_late_collision; | ||
| 611 | u64 tx_fifo_errors; | ||
| 612 | u64 tx_carrier_errors; | ||
| 613 | u64 tx_excess_deferral; | ||
| 614 | u64 tx_retry_error; | ||
| 615 | u64 tx_deferral; | ||
| 616 | u64 tx_packets; | ||
| 617 | u64 tx_pause; | ||
| 618 | u64 rx_frame_error; | ||
| 619 | u64 rx_extra_byte; | ||
| 620 | u64 rx_late_collision; | ||
| 621 | u64 rx_runt; | ||
| 622 | u64 rx_frame_too_long; | ||
| 623 | u64 rx_over_errors; | ||
| 624 | u64 rx_crc_errors; | ||
| 625 | u64 rx_frame_align_error; | ||
| 626 | u64 rx_length_error; | ||
| 627 | u64 rx_unicast; | ||
| 628 | u64 rx_multicast; | ||
| 629 | u64 rx_broadcast; | ||
| 630 | u64 rx_bytes; | ||
| 631 | u64 rx_pause; | ||
| 632 | u64 rx_drop_frame; | ||
| 633 | u64 rx_packets; | ||
| 634 | u64 rx_errors_total; | ||
| 635 | }; | ||
| 636 | |||
| 539 | /* | 637 | /* |
| 540 | * SMP locking: | 638 | * SMP locking: |
| 541 | * All hardware access under dev->priv->lock, except the performance | 639 | * All hardware access under dev->priv->lock, except the performance |
| @@ -554,6 +652,7 @@ struct fe_priv { | |||
| 554 | /* General data: | 652 | /* General data: |
| 555 | * Locking: spin_lock(&np->lock); */ | 653 | * Locking: spin_lock(&np->lock); */ |
| 556 | struct net_device_stats stats; | 654 | struct net_device_stats stats; |
| 655 | struct nv_ethtool_stats estats; | ||
| 557 | int in_shutdown; | 656 | int in_shutdown; |
| 558 | u32 linkspeed; | 657 | u32 linkspeed; |
| 559 | int duplex; | 658 | int duplex; |
| @@ -588,6 +687,7 @@ struct fe_priv { | |||
| 588 | unsigned int pkt_limit; | 687 | unsigned int pkt_limit; |
| 589 | struct timer_list oom_kick; | 688 | struct timer_list oom_kick; |
| 590 | struct timer_list nic_poll; | 689 | struct timer_list nic_poll; |
| 690 | struct timer_list stats_poll; | ||
| 591 | u32 nic_poll_irq; | 691 | u32 nic_poll_irq; |
| 592 | int rx_ring_size; | 692 | int rx_ring_size; |
| 593 | 693 | ||
| @@ -2471,6 +2571,56 @@ static void nv_poll_controller(struct net_device *dev) | |||
| 2471 | } | 2571 | } |
| 2472 | #endif | 2572 | #endif |
| 2473 | 2573 | ||
| 2574 | static void nv_do_stats_poll(unsigned long data) | ||
| 2575 | { | ||
| 2576 | struct net_device *dev = (struct net_device *) data; | ||
| 2577 | struct fe_priv *np = netdev_priv(dev); | ||
| 2578 | u8 __iomem *base = get_hwbase(dev); | ||
| 2579 | |||
| 2580 | np->estats.tx_bytes += readl(base + NvRegTxCnt); | ||
| 2581 | np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); | ||
| 2582 | np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); | ||
| 2583 | np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); | ||
| 2584 | np->estats.tx_late_collision += readl(base + NvRegTxLateCol); | ||
| 2585 | np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); | ||
| 2586 | np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); | ||
| 2587 | np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); | ||
| 2588 | np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); | ||
| 2589 | np->estats.tx_deferral += readl(base + NvRegTxDef); | ||
| 2590 | np->estats.tx_packets += readl(base + NvRegTxFrame); | ||
| 2591 | np->estats.tx_pause += readl(base + NvRegTxPause); | ||
| 2592 | np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); | ||
| 2593 | np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); | ||
| 2594 | np->estats.rx_late_collision += readl(base + NvRegRxLateCol); | ||
| 2595 | np->estats.rx_runt += readl(base + NvRegRxRunt); | ||
| 2596 | np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); | ||
| 2597 | np->estats.rx_over_errors += readl(base + NvRegRxOverflow); | ||
| 2598 | np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); | ||
| 2599 | np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); | ||
| 2600 | np->estats.rx_length_error += readl(base + NvRegRxLenErr); | ||
| 2601 | np->estats.rx_unicast += readl(base + NvRegRxUnicast); | ||
| 2602 | np->estats.rx_multicast += readl(base + NvRegRxMulticast); | ||
| 2603 | np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); | ||
| 2604 | np->estats.rx_bytes += readl(base + NvRegRxCnt); | ||
| 2605 | np->estats.rx_pause += readl(base + NvRegRxPause); | ||
| 2606 | np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); | ||
| 2607 | np->estats.rx_packets = | ||
| 2608 | np->estats.rx_unicast + | ||
| 2609 | np->estats.rx_multicast + | ||
| 2610 | np->estats.rx_broadcast; | ||
| 2611 | np->estats.rx_errors_total = | ||
| 2612 | np->estats.rx_crc_errors + | ||
| 2613 | np->estats.rx_over_errors + | ||
| 2614 | np->estats.rx_frame_error + | ||
| 2615 | (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + | ||
| 2616 | np->estats.rx_late_collision + | ||
| 2617 | np->estats.rx_runt + | ||
| 2618 | np->estats.rx_frame_too_long; | ||
| 2619 | |||
| 2620 | if (!np->in_shutdown) | ||
| 2621 | mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); | ||
| 2622 | } | ||
| 2623 | |||
| 2474 | static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | 2624 | static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
| 2475 | { | 2625 | { |
| 2476 | struct fe_priv *np = netdev_priv(dev); | 2626 | struct fe_priv *np = netdev_priv(dev); |
| @@ -3084,6 +3234,35 @@ static int nv_set_sg(struct net_device *dev, u32 data) | |||
| 3084 | return -EOPNOTSUPP; | 3234 | return -EOPNOTSUPP; |
| 3085 | } | 3235 | } |
| 3086 | 3236 | ||
| 3237 | static int nv_get_stats_count(struct net_device *dev) | ||
| 3238 | { | ||
| 3239 | struct fe_priv *np = netdev_priv(dev); | ||
| 3240 | |||
| 3241 | if (np->driver_data & DEV_HAS_STATISTICS) | ||
| 3242 | return (sizeof(struct nv_ethtool_stats)/sizeof(u64)); | ||
| 3243 | else | ||
| 3244 | return 0; | ||
| 3245 | } | ||
| 3246 | |||
| 3247 | static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer) | ||
| 3248 | { | ||
| 3249 | struct fe_priv *np = netdev_priv(dev); | ||
| 3250 | |||
| 3251 | /* update stats */ | ||
| 3252 | nv_do_stats_poll((unsigned long)dev); | ||
| 3253 | |||
| 3254 | memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64)); | ||
| 3255 | } | ||
| 3256 | |||
| 3257 | static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer) | ||
| 3258 | { | ||
| 3259 | switch (stringset) { | ||
| 3260 | case ETH_SS_STATS: | ||
| 3261 | memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str)); | ||
| 3262 | break; | ||
| 3263 | } | ||
| 3264 | } | ||
| 3265 | |||
| 3087 | static struct ethtool_ops ops = { | 3266 | static struct ethtool_ops ops = { |
| 3088 | .get_drvinfo = nv_get_drvinfo, | 3267 | .get_drvinfo = nv_get_drvinfo, |
| 3089 | .get_link = ethtool_op_get_link, | 3268 | .get_link = ethtool_op_get_link, |
| @@ -3107,6 +3286,9 @@ static struct ethtool_ops ops = { | |||
| 3107 | .set_tx_csum = nv_set_tx_csum, | 3286 | .set_tx_csum = nv_set_tx_csum, |
| 3108 | .get_sg = ethtool_op_get_sg, | 3287 | .get_sg = ethtool_op_get_sg, |
| 3109 | .set_sg = nv_set_sg, | 3288 | .set_sg = nv_set_sg, |
| 3289 | .get_strings = nv_get_strings, | ||
| 3290 | .get_stats_count = nv_get_stats_count, | ||
| 3291 | .get_ethtool_stats = nv_get_ethtool_stats, | ||
| 3110 | }; | 3292 | }; |
| 3111 | 3293 | ||
| 3112 | static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) | 3294 | static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) |
| @@ -3409,6 +3591,11 @@ static int nv_open(struct net_device *dev) | |||
| 3409 | } | 3591 | } |
| 3410 | if (oom) | 3592 | if (oom) |
| 3411 | mod_timer(&np->oom_kick, jiffies + OOM_REFILL); | 3593 | mod_timer(&np->oom_kick, jiffies + OOM_REFILL); |
| 3594 | |||
| 3595 | /* start statistics timer */ | ||
| 3596 | if (np->driver_data & DEV_HAS_STATISTICS) | ||
| 3597 | mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); | ||
| 3598 | |||
| 3412 | spin_unlock_irq(&np->lock); | 3599 | spin_unlock_irq(&np->lock); |
| 3413 | 3600 | ||
| 3414 | return 0; | 3601 | return 0; |
| @@ -3429,6 +3616,7 @@ static int nv_close(struct net_device *dev) | |||
| 3429 | 3616 | ||
| 3430 | del_timer_sync(&np->oom_kick); | 3617 | del_timer_sync(&np->oom_kick); |
| 3431 | del_timer_sync(&np->nic_poll); | 3618 | del_timer_sync(&np->nic_poll); |
| 3619 | del_timer_sync(&np->stats_poll); | ||
| 3432 | 3620 | ||
| 3433 | netif_stop_queue(dev); | 3621 | netif_stop_queue(dev); |
| 3434 | spin_lock_irq(&np->lock); | 3622 | spin_lock_irq(&np->lock); |
| @@ -3488,6 +3676,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
| 3488 | init_timer(&np->nic_poll); | 3676 | init_timer(&np->nic_poll); |
| 3489 | np->nic_poll.data = (unsigned long) dev; | 3677 | np->nic_poll.data = (unsigned long) dev; |
| 3490 | np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ | 3678 | np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ |
| 3679 | init_timer(&np->stats_poll); | ||
| 3680 | np->stats_poll.data = (unsigned long) dev; | ||
| 3681 | np->stats_poll.function = &nv_do_stats_poll; /* timer handler */ | ||
| 3491 | 3682 | ||
| 3492 | err = pci_enable_device(pci_dev); | 3683 | err = pci_enable_device(pci_dev); |
| 3493 | if (err) { | 3684 | if (err) { |
| @@ -3502,7 +3693,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
| 3502 | if (err < 0) | 3693 | if (err < 0) |
| 3503 | goto out_disable; | 3694 | goto out_disable; |
| 3504 | 3695 | ||
| 3505 | if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL)) | 3696 | if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS)) |
| 3506 | np->register_size = NV_PCI_REGSZ_VER2; | 3697 | np->register_size = NV_PCI_REGSZ_VER2; |
| 3507 | else | 3698 | else |
| 3508 | np->register_size = NV_PCI_REGSZ_VER1; | 3699 | np->register_size = NV_PCI_REGSZ_VER1; |
| @@ -3858,11 +4049,11 @@ static struct pci_device_id pci_tbl[] = { | |||
| 3858 | }, | 4049 | }, |
| 3859 | { /* MCP55 Ethernet Controller */ | 4050 | { /* MCP55 Ethernet Controller */ |
| 3860 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), | 4051 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), |
| 3861 | .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|DEV_HAS_PAUSEFRAME_TX, | 4052 | .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|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS, |
| 3862 | }, | 4053 | }, |
| 3863 | { /* MCP55 Ethernet Controller */ | 4054 | { /* MCP55 Ethernet Controller */ |
| 3864 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), | 4055 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), |
| 3865 | .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|DEV_HAS_PAUSEFRAME_TX, | 4056 | .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|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS, |
| 3866 | }, | 4057 | }, |
| 3867 | {0,}, | 4058 | {0,}, |
| 3868 | }; | 4059 | }; |
