aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ps3_gelic_net.c
diff options
context:
space:
mode:
authorMasakazu Mokuno <mokuno@sm.sony.co.jp>2007-07-20 04:24:56 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-24 16:28:39 -0400
commit48544cc267da96a85e4d38aa1999a011229948d6 (patch)
tree0abb855ec54f74ce85207d6ba7585dc8e8d18796 /drivers/net/ps3_gelic_net.c
parentea6992aa1f6ed514fe450f46befa56d8d2b6a7fb (diff)
ps3: tx descriptor handling cleanup
gelic: TX descriptor handling cleanup - Emitted return value of NETDEV_TX_LOCKED when DMA map or kick failure. Now it would free the skb, update drop packet statistics and return OK. Requested from Jeff Garzik. - Enable tx queue if number of free descriptors are more than 2 - Fixed descriptor leak if dma map for second descriptor failed - Stopped calling xmit handler from interrupt handler in order to recheck tx queue. Instead, call appropriate helper functions. Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/ps3_gelic_net.c')
-rw-r--r--drivers/net/ps3_gelic_net.c124
1 files changed, 71 insertions, 53 deletions
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index f0610fba4c95..143d7bdf7874 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -408,22 +408,25 @@ static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop)
408 break; 408 break;
409 409
410 case GELIC_NET_DESCR_COMPLETE: 410 case GELIC_NET_DESCR_COMPLETE:
411 card->netdev_stats.tx_packets++; 411 if (tx_chain->tail->skb) {
412 card->netdev_stats.tx_bytes += 412 card->netdev_stats.tx_packets++;
413 tx_chain->tail->skb->len; 413 card->netdev_stats.tx_bytes +=
414 tx_chain->tail->skb->len;
415 }
414 break; 416 break;
415 417
416 case GELIC_NET_DESCR_CARDOWNED: 418 case GELIC_NET_DESCR_CARDOWNED:
417 /* pending tx request */ 419 /* pending tx request */
418 default: 420 default:
419 /* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */ 421 /* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */
420 goto out; 422 if (!stop)
423 goto out;
421 } 424 }
422 gelic_net_release_tx_descr(card, tx_chain->tail); 425 gelic_net_release_tx_descr(card, tx_chain->tail);
423 release = 1; 426 release ++;
424 } 427 }
425out: 428out:
426 if (!stop && release) 429 if (!stop && (2 < release))
427 netif_wake_queue(card->netdev); 430 netif_wake_queue(card->netdev);
428} 431}
429 432
@@ -660,19 +663,21 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
660{ 663{
661 dma_addr_t buf[2]; 664 dma_addr_t buf[2];
662 unsigned int vlan_len; 665 unsigned int vlan_len;
666 struct gelic_net_descr *sec_descr = descr->next;
663 667
664 if (skb->len < GELIC_NET_VLAN_POS) 668 if (skb->len < GELIC_NET_VLAN_POS)
665 return -EINVAL; 669 return -EINVAL;
666 670
667 memcpy(&descr->vlan, skb->data, GELIC_NET_VLAN_POS); 671 vlan_len = GELIC_NET_VLAN_POS;
672 memcpy(&descr->vlan, skb->data, vlan_len);
668 if (card->vlan_index != -1) { 673 if (card->vlan_index != -1) {
674 /* internal vlan tag used */
669 descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/ 675 descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
670 descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]); 676 descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
671 vlan_len = GELIC_NET_VLAN_POS + VLAN_HLEN; /* VLAN_HLEN=4 */ 677 vlan_len += VLAN_HLEN; /* added for above two lines */
672 } else 678 }
673 vlan_len = GELIC_NET_VLAN_POS; /* no vlan tag */
674 679
675 /* first descr */ 680 /* map data area */
676 buf[0] = dma_map_single(ctodev(card), &descr->vlan, 681 buf[0] = dma_map_single(ctodev(card), &descr->vlan,
677 vlan_len, DMA_TO_DEVICE); 682 vlan_len, DMA_TO_DEVICE);
678 683
@@ -683,20 +688,6 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
683 return -ENOMEM; 688 return -ENOMEM;
684 } 689 }
685 690
686 descr->buf_addr = buf[0];
687 descr->buf_size = vlan_len;
688 descr->skb = skb; /* not used */
689 descr->data_status = 0;
690 gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
691
692 /* second descr */
693 card->tx_chain.head = card->tx_chain.head->next;
694 descr->next_descr_addr = descr->next->bus_addr;
695 descr = descr->next;
696 if (gelic_net_get_descr_status(descr) != GELIC_NET_DESCR_NOT_IN_USE)
697 /* XXX will be removed */
698 dev_err(ctodev(card), "descr is not free!\n");
699
700 buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS, 691 buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
701 skb->len - GELIC_NET_VLAN_POS, 692 skb->len - GELIC_NET_VLAN_POS,
702 DMA_TO_DEVICE); 693 DMA_TO_DEVICE);
@@ -711,13 +702,24 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
711 return -ENOMEM; 702 return -ENOMEM;
712 } 703 }
713 704
714 descr->buf_addr = buf[1]; 705 /* first descr */
715 descr->buf_size = skb->len - GELIC_NET_VLAN_POS; 706 descr->buf_addr = buf[0];
716 descr->skb = skb; 707 descr->buf_size = vlan_len;
708 descr->skb = NULL; /* not used */
717 descr->data_status = 0; 709 descr->data_status = 0;
718 descr->next_descr_addr = 0; /* terminate hw descr */ 710 descr->next_descr_addr = descr->next->bus_addr;
719 gelic_net_set_txdescr_cmdstat(descr, skb, 0); 711 gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
720 712
713 /* second descr */
714 sec_descr->buf_addr = buf[1];
715 sec_descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
716 sec_descr->skb = skb;
717 sec_descr->data_status = 0;
718 sec_descr->next_descr_addr = 0; /* terminate hw descr */
719 gelic_net_set_txdescr_cmdstat(sec_descr, skb, 0);
720
721 /* bump free descriptor pointer */
722 card->tx_chain.head = sec_descr->next;
721 return 0; 723 return 0;
722} 724}
723 725
@@ -730,7 +732,7 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
730static int gelic_net_kick_txdma(struct gelic_net_card *card, 732static int gelic_net_kick_txdma(struct gelic_net_card *card,
731 struct gelic_net_descr *descr) 733 struct gelic_net_descr *descr)
732{ 734{
733 int status = -ENXIO; 735 int status = 0;
734 int count = 10; 736 int count = 10;
735 737
736 if (card->tx_dma_progress) 738 if (card->tx_dma_progress)
@@ -764,47 +766,62 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card,
764static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) 766static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
765{ 767{
766 struct gelic_net_card *card = netdev_priv(netdev); 768 struct gelic_net_card *card = netdev_priv(netdev);
767 struct gelic_net_descr *descr = NULL; 769 struct gelic_net_descr *descr;
768 int result; 770 int result;
769 unsigned long flags; 771 unsigned long flags;
770 772
771 spin_lock_irqsave(&card->tx_dma_lock, flags); 773 spin_lock_irqsave(&card->tx_dma_lock, flags);
772 774
773 gelic_net_release_tx_chain(card, 0); 775 gelic_net_release_tx_chain(card, 0);
774 if (!skb) 776
775 goto kick;
776 descr = gelic_net_get_next_tx_descr(card); 777 descr = gelic_net_get_next_tx_descr(card);
777 if (!descr) { 778 if (!descr) {
779 /*
780 * no more descriptors free
781 */
778 netif_stop_queue(netdev); 782 netif_stop_queue(netdev);
779 spin_unlock_irqrestore(&card->tx_dma_lock, flags); 783 spin_unlock_irqrestore(&card->tx_dma_lock, flags);
780 return NETDEV_TX_BUSY; 784 return NETDEV_TX_BUSY;
781 } 785 }
782 result = gelic_net_prepare_tx_descr_v(card, descr, skb);
783
784 if (result)
785 goto error;
786
787 card->tx_chain.head = card->tx_chain.head->next;
788 786
789 if (descr->prev) 787 result = gelic_net_prepare_tx_descr_v(card, descr, skb);
790 descr->prev->next_descr_addr = descr->bus_addr; 788 if (result) {
791kick: 789 /*
790 * DMA map failed. As chanses are that failure
791 * would continue, just release skb and return
792 */
793 card->netdev_stats.tx_dropped++;
794 dev_kfree_skb_any(skb);
795 spin_unlock_irqrestore(&card->tx_dma_lock, flags);
796 return NETDEV_TX_OK;
797 }
798 /*
799 * link this prepared descriptor to previous one
800 * to achieve high performance
801 */
802 descr->prev->next_descr_addr = descr->bus_addr;
792 /* 803 /*
793 * as hardware descriptor is modified in the above lines, 804 * as hardware descriptor is modified in the above lines,
794 * ensure that the hardware sees it 805 * ensure that the hardware sees it
795 */ 806 */
796 wmb(); 807 wmb();
797 if (gelic_net_kick_txdma(card, card->tx_chain.tail)) 808 if (gelic_net_kick_txdma(card, descr)) {
798 goto error; 809 /*
810 * kick failed.
811 * release descriptors which were just prepared
812 */
813 card->netdev_stats.tx_dropped++;
814 gelic_net_release_tx_descr(card, descr);
815 gelic_net_release_tx_descr(card, descr->next);
816 card->tx_chain.tail = descr->next->next;
817 dev_info(ctodev(card), "%s: kick failure\n", __func__);
818 } else {
819 /* OK, DMA started/reserved */
820 netdev->trans_start = jiffies;
821 }
799 822
800 netdev->trans_start = jiffies;
801 spin_unlock_irqrestore(&card->tx_dma_lock, flags); 823 spin_unlock_irqrestore(&card->tx_dma_lock, flags);
802 return NETDEV_TX_OK; 824 return NETDEV_TX_OK;
803
804error:
805 card->netdev_stats.tx_dropped++;
806 spin_unlock_irqrestore(&card->tx_dma_lock, flags);
807 return NETDEV_TX_LOCKED;
808} 825}
809 826
810/** 827/**
@@ -1025,9 +1042,10 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr)
1025 if (status & GELIC_NET_TXINT) { 1042 if (status & GELIC_NET_TXINT) {
1026 spin_lock_irqsave(&card->tx_dma_lock, flags); 1043 spin_lock_irqsave(&card->tx_dma_lock, flags);
1027 card->tx_dma_progress = 0; 1044 card->tx_dma_progress = 0;
1045 gelic_net_release_tx_chain(card, 0);
1046 /* kick outstanding tx descriptor if any */
1047 gelic_net_kick_txdma(card, card->tx_chain.tail);
1028 spin_unlock_irqrestore(&card->tx_dma_lock, flags); 1048 spin_unlock_irqrestore(&card->tx_dma_lock, flags);
1029 /* start pending DMA */
1030 gelic_net_xmit(NULL, netdev);
1031 } 1049 }
1032 return IRQ_HANDLED; 1050 return IRQ_HANDLED;
1033} 1051}