diff options
Diffstat (limited to 'drivers/net/ethernet/aeroflex/greth.c')
-rw-r--r-- | drivers/net/ethernet/aeroflex/greth.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index 23578dfee249..3005155e412b 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c | |||
@@ -123,6 +123,12 @@ static inline void greth_enable_tx(struct greth_private *greth) | |||
123 | GRETH_REGORIN(greth->regs->control, GRETH_TXEN); | 123 | GRETH_REGORIN(greth->regs->control, GRETH_TXEN); |
124 | } | 124 | } |
125 | 125 | ||
126 | static inline void greth_enable_tx_and_irq(struct greth_private *greth) | ||
127 | { | ||
128 | wmb(); /* BDs must been written to memory before enabling TX */ | ||
129 | GRETH_REGORIN(greth->regs->control, GRETH_TXEN | GRETH_TXI); | ||
130 | } | ||
131 | |||
126 | static inline void greth_disable_tx(struct greth_private *greth) | 132 | static inline void greth_disable_tx(struct greth_private *greth) |
127 | { | 133 | { |
128 | GRETH_REGANDIN(greth->regs->control, ~GRETH_TXEN); | 134 | GRETH_REGANDIN(greth->regs->control, ~GRETH_TXEN); |
@@ -447,29 +453,30 @@ out: | |||
447 | return err; | 453 | return err; |
448 | } | 454 | } |
449 | 455 | ||
456 | static inline u16 greth_num_free_bds(u16 tx_last, u16 tx_next) | ||
457 | { | ||
458 | if (tx_next < tx_last) | ||
459 | return (tx_last - tx_next) - 1; | ||
460 | else | ||
461 | return GRETH_TXBD_NUM - (tx_next - tx_last) - 1; | ||
462 | } | ||
450 | 463 | ||
451 | static netdev_tx_t | 464 | static netdev_tx_t |
452 | greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) | 465 | greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) |
453 | { | 466 | { |
454 | struct greth_private *greth = netdev_priv(dev); | 467 | struct greth_private *greth = netdev_priv(dev); |
455 | struct greth_bd *bdp; | 468 | struct greth_bd *bdp; |
456 | u32 status = 0, dma_addr, ctrl; | 469 | u32 status, dma_addr; |
457 | int curr_tx, nr_frags, i, err = NETDEV_TX_OK; | 470 | int curr_tx, nr_frags, i, err = NETDEV_TX_OK; |
458 | unsigned long flags; | 471 | unsigned long flags; |
472 | u16 tx_last; | ||
459 | 473 | ||
460 | nr_frags = skb_shinfo(skb)->nr_frags; | 474 | nr_frags = skb_shinfo(skb)->nr_frags; |
475 | tx_last = greth->tx_last; | ||
476 | rmb(); /* tx_last is updated by the poll task */ | ||
461 | 477 | ||
462 | /* Clean TX Ring */ | 478 | if (greth_num_free_bds(tx_last, greth->tx_next) < nr_frags + 1) { |
463 | greth_clean_tx_gbit(dev); | ||
464 | |||
465 | if (greth->tx_free < nr_frags + 1) { | ||
466 | spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/ | ||
467 | ctrl = GRETH_REGLOAD(greth->regs->control); | ||
468 | /* Enable TX IRQ only if not already in poll() routine */ | ||
469 | if (ctrl & GRETH_RXI) | ||
470 | GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI); | ||
471 | netif_stop_queue(dev); | 479 | netif_stop_queue(dev); |
472 | spin_unlock_irqrestore(&greth->devlock, flags); | ||
473 | err = NETDEV_TX_BUSY; | 480 | err = NETDEV_TX_BUSY; |
474 | goto out; | 481 | goto out; |
475 | } | 482 | } |
@@ -488,6 +495,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) | |||
488 | /* Linear buf */ | 495 | /* Linear buf */ |
489 | if (nr_frags != 0) | 496 | if (nr_frags != 0) |
490 | status = GRETH_TXBD_MORE; | 497 | status = GRETH_TXBD_MORE; |
498 | else | ||
499 | status = GRETH_BD_IE; | ||
491 | 500 | ||
492 | if (skb->ip_summed == CHECKSUM_PARTIAL) | 501 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
493 | status |= GRETH_TXBD_CSALL; | 502 | status |= GRETH_TXBD_CSALL; |
@@ -545,14 +554,12 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) | |||
545 | 554 | ||
546 | /* Enable the descriptor chain by enabling the first descriptor */ | 555 | /* Enable the descriptor chain by enabling the first descriptor */ |
547 | bdp = greth->tx_bd_base + greth->tx_next; | 556 | bdp = greth->tx_bd_base + greth->tx_next; |
548 | greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN); | 557 | greth_write_bd(&bdp->stat, |
549 | greth->tx_next = curr_tx; | 558 | greth_read_bd(&bdp->stat) | GRETH_BD_EN); |
550 | greth->tx_free -= nr_frags + 1; | ||
551 | |||
552 | wmb(); | ||
553 | 559 | ||
554 | spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/ | 560 | spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/ |
555 | greth_enable_tx(greth); | 561 | greth->tx_next = curr_tx; |
562 | greth_enable_tx_and_irq(greth); | ||
556 | spin_unlock_irqrestore(&greth->devlock, flags); | 563 | spin_unlock_irqrestore(&greth->devlock, flags); |
557 | 564 | ||
558 | return NETDEV_TX_OK; | 565 | return NETDEV_TX_OK; |
@@ -648,7 +655,6 @@ static void greth_clean_tx(struct net_device *dev) | |||
648 | if (greth->tx_free > 0) { | 655 | if (greth->tx_free > 0) { |
649 | netif_wake_queue(dev); | 656 | netif_wake_queue(dev); |
650 | } | 657 | } |
651 | |||
652 | } | 658 | } |
653 | 659 | ||
654 | static inline void greth_update_tx_stats(struct net_device *dev, u32 stat) | 660 | static inline void greth_update_tx_stats(struct net_device *dev, u32 stat) |
@@ -670,20 +676,22 @@ static void greth_clean_tx_gbit(struct net_device *dev) | |||
670 | { | 676 | { |
671 | struct greth_private *greth; | 677 | struct greth_private *greth; |
672 | struct greth_bd *bdp, *bdp_last_frag; | 678 | struct greth_bd *bdp, *bdp_last_frag; |
673 | struct sk_buff *skb; | 679 | struct sk_buff *skb = NULL; |
674 | u32 stat; | 680 | u32 stat; |
675 | int nr_frags, i; | 681 | int nr_frags, i; |
682 | u16 tx_last; | ||
676 | 683 | ||
677 | greth = netdev_priv(dev); | 684 | greth = netdev_priv(dev); |
685 | tx_last = greth->tx_last; | ||
678 | 686 | ||
679 | while (greth->tx_free < GRETH_TXBD_NUM) { | 687 | while (tx_last != greth->tx_next) { |
680 | 688 | ||
681 | skb = greth->tx_skbuff[greth->tx_last]; | 689 | skb = greth->tx_skbuff[tx_last]; |
682 | 690 | ||
683 | nr_frags = skb_shinfo(skb)->nr_frags; | 691 | nr_frags = skb_shinfo(skb)->nr_frags; |
684 | 692 | ||
685 | /* We only clean fully completed SKBs */ | 693 | /* We only clean fully completed SKBs */ |
686 | bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags); | 694 | bdp_last_frag = greth->tx_bd_base + SKIP_TX(tx_last, nr_frags); |
687 | 695 | ||
688 | GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX); | 696 | GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX); |
689 | mb(); | 697 | mb(); |
@@ -692,14 +700,14 @@ static void greth_clean_tx_gbit(struct net_device *dev) | |||
692 | if (stat & GRETH_BD_EN) | 700 | if (stat & GRETH_BD_EN) |
693 | break; | 701 | break; |
694 | 702 | ||
695 | greth->tx_skbuff[greth->tx_last] = NULL; | 703 | greth->tx_skbuff[tx_last] = NULL; |
696 | 704 | ||
697 | greth_update_tx_stats(dev, stat); | 705 | greth_update_tx_stats(dev, stat); |
698 | dev->stats.tx_bytes += skb->len; | 706 | dev->stats.tx_bytes += skb->len; |
699 | 707 | ||
700 | bdp = greth->tx_bd_base + greth->tx_last; | 708 | bdp = greth->tx_bd_base + tx_last; |
701 | 709 | ||
702 | greth->tx_last = NEXT_TX(greth->tx_last); | 710 | tx_last = NEXT_TX(tx_last); |
703 | 711 | ||
704 | dma_unmap_single(greth->dev, | 712 | dma_unmap_single(greth->dev, |
705 | greth_read_bd(&bdp->addr), | 713 | greth_read_bd(&bdp->addr), |
@@ -708,21 +716,26 @@ static void greth_clean_tx_gbit(struct net_device *dev) | |||
708 | 716 | ||
709 | for (i = 0; i < nr_frags; i++) { | 717 | for (i = 0; i < nr_frags; i++) { |
710 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | 718 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
711 | bdp = greth->tx_bd_base + greth->tx_last; | 719 | bdp = greth->tx_bd_base + tx_last; |
712 | 720 | ||
713 | dma_unmap_page(greth->dev, | 721 | dma_unmap_page(greth->dev, |
714 | greth_read_bd(&bdp->addr), | 722 | greth_read_bd(&bdp->addr), |
715 | skb_frag_size(frag), | 723 | skb_frag_size(frag), |
716 | DMA_TO_DEVICE); | 724 | DMA_TO_DEVICE); |
717 | 725 | ||
718 | greth->tx_last = NEXT_TX(greth->tx_last); | 726 | tx_last = NEXT_TX(tx_last); |
719 | } | 727 | } |
720 | greth->tx_free += nr_frags+1; | ||
721 | dev_kfree_skb(skb); | 728 | dev_kfree_skb(skb); |
722 | } | 729 | } |
730 | if (skb) { /* skb is set only if the above while loop was entered */ | ||
731 | wmb(); | ||
732 | greth->tx_last = tx_last; | ||
723 | 733 | ||
724 | if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1))) | 734 | if (netif_queue_stopped(dev) && |
725 | netif_wake_queue(dev); | 735 | (greth_num_free_bds(tx_last, greth->tx_next) > |
736 | (MAX_SKB_FRAGS+1))) | ||
737 | netif_wake_queue(dev); | ||
738 | } | ||
726 | } | 739 | } |
727 | 740 | ||
728 | static int greth_rx(struct net_device *dev, int limit) | 741 | static int greth_rx(struct net_device *dev, int limit) |
@@ -965,16 +978,12 @@ static int greth_poll(struct napi_struct *napi, int budget) | |||
965 | greth = container_of(napi, struct greth_private, napi); | 978 | greth = container_of(napi, struct greth_private, napi); |
966 | 979 | ||
967 | restart_txrx_poll: | 980 | restart_txrx_poll: |
968 | if (netif_queue_stopped(greth->netdev)) { | ||
969 | if (greth->gbit_mac) | ||
970 | greth_clean_tx_gbit(greth->netdev); | ||
971 | else | ||
972 | greth_clean_tx(greth->netdev); | ||
973 | } | ||
974 | |||
975 | if (greth->gbit_mac) { | 981 | if (greth->gbit_mac) { |
982 | greth_clean_tx_gbit(greth->netdev); | ||
976 | work_done += greth_rx_gbit(greth->netdev, budget - work_done); | 983 | work_done += greth_rx_gbit(greth->netdev, budget - work_done); |
977 | } else { | 984 | } else { |
985 | if (netif_queue_stopped(greth->netdev)) | ||
986 | greth_clean_tx(greth->netdev); | ||
978 | work_done += greth_rx(greth->netdev, budget - work_done); | 987 | work_done += greth_rx(greth->netdev, budget - work_done); |
979 | } | 988 | } |
980 | 989 | ||
@@ -983,7 +992,8 @@ restart_txrx_poll: | |||
983 | spin_lock_irqsave(&greth->devlock, flags); | 992 | spin_lock_irqsave(&greth->devlock, flags); |
984 | 993 | ||
985 | ctrl = GRETH_REGLOAD(greth->regs->control); | 994 | ctrl = GRETH_REGLOAD(greth->regs->control); |
986 | if (netif_queue_stopped(greth->netdev)) { | 995 | if ((greth->gbit_mac && (greth->tx_last != greth->tx_next)) || |
996 | (!greth->gbit_mac && netif_queue_stopped(greth->netdev))) { | ||
987 | GRETH_REGSAVE(greth->regs->control, | 997 | GRETH_REGSAVE(greth->regs->control, |
988 | ctrl | GRETH_TXI | GRETH_RXI); | 998 | ctrl | GRETH_TXI | GRETH_RXI); |
989 | mask = GRETH_INT_RX | GRETH_INT_RE | | 999 | mask = GRETH_INT_RX | GRETH_INT_RE | |