Commit 23ecc4bde21f0ccb38f4b53cadde7fc5d67d68e3
Committed by
David S. Miller
1 parent
755fae0ac4
Exists in
master
and in
39 other branches
net: ll_temac: fix checksum offload logic
The current checksum offload code does not work and this corrects that functionality. It also updates the interrupt coallescing initialization so than there are fewer interrupts and performance is increased. Signed-off-by: Brian Hill <brian.hill@xilinx.com> Signed-off-by: John Linn <john.linn@xilinx.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 63 additions and 24 deletions Side-by-side Diff
drivers/net/ll_temac.h
... | ... | @@ -295,6 +295,10 @@ |
295 | 295 | |
296 | 296 | #define MULTICAST_CAM_TABLE_NUM 4 |
297 | 297 | |
298 | +/* TEMAC Synthesis features */ | |
299 | +#define TEMAC_FEATURE_RX_CSUM (1 << 0) | |
300 | +#define TEMAC_FEATURE_TX_CSUM (1 << 1) | |
301 | + | |
298 | 302 | /* TX/RX CURDESC_PTR points to first descriptor */ |
299 | 303 | /* TX/RX TAILDESC_PTR points to last descriptor in linked list */ |
300 | 304 | |
... | ... | @@ -353,6 +357,7 @@ |
353 | 357 | struct mutex indirect_mutex; |
354 | 358 | u32 options; /* Current options word */ |
355 | 359 | int last_link; |
360 | + unsigned int temac_features; | |
356 | 361 | |
357 | 362 | /* Buffer descriptors */ |
358 | 363 | struct cdmac_bd *tx_bd_v; |
drivers/net/ll_temac_main.c
... | ... | @@ -245,7 +245,7 @@ |
245 | 245 | CHNL_CTRL_IRQ_COAL_EN); |
246 | 246 | /* 0x10220483 */ |
247 | 247 | /* 0x00100483 */ |
248 | - lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 | | |
248 | + lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 | | |
249 | 249 | CHNL_CTRL_IRQ_EN | |
250 | 250 | CHNL_CTRL_IRQ_DLY_EN | |
251 | 251 | CHNL_CTRL_IRQ_COAL_EN | |
... | ... | @@ -574,6 +574,10 @@ |
574 | 574 | if (cur_p->app4) |
575 | 575 | dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); |
576 | 576 | cur_p->app0 = 0; |
577 | + cur_p->app1 = 0; | |
578 | + cur_p->app2 = 0; | |
579 | + cur_p->app3 = 0; | |
580 | + cur_p->app4 = 0; | |
577 | 581 | |
578 | 582 | ndev->stats.tx_packets++; |
579 | 583 | ndev->stats.tx_bytes += cur_p->len; |
... | ... | @@ -589,6 +593,29 @@ |
589 | 593 | netif_wake_queue(ndev); |
590 | 594 | } |
591 | 595 | |
596 | +static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) | |
597 | +{ | |
598 | + struct cdmac_bd *cur_p; | |
599 | + int tail; | |
600 | + | |
601 | + tail = lp->tx_bd_tail; | |
602 | + cur_p = &lp->tx_bd_v[tail]; | |
603 | + | |
604 | + do { | |
605 | + if (cur_p->app0) | |
606 | + return NETDEV_TX_BUSY; | |
607 | + | |
608 | + tail++; | |
609 | + if (tail >= TX_BD_NUM) | |
610 | + tail = 0; | |
611 | + | |
612 | + cur_p = &lp->tx_bd_v[tail]; | |
613 | + num_frag--; | |
614 | + } while (num_frag >= 0); | |
615 | + | |
616 | + return 0; | |
617 | +} | |
618 | + | |
592 | 619 | static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
593 | 620 | { |
594 | 621 | struct temac_local *lp = netdev_priv(ndev); |
... | ... | @@ -603,7 +630,7 @@ |
603 | 630 | start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; |
604 | 631 | cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; |
605 | 632 | |
606 | - if (cur_p->app0 & STS_CTRL_APP0_CMPLT) { | |
633 | + if (temac_check_tx_bd_space(lp, num_frag)) { | |
607 | 634 | if (!netif_queue_stopped(ndev)) { |
608 | 635 | netif_stop_queue(ndev); |
609 | 636 | return NETDEV_TX_BUSY; |
610 | 637 | |
611 | 638 | |
... | ... | @@ -613,29 +640,14 @@ |
613 | 640 | |
614 | 641 | cur_p->app0 = 0; |
615 | 642 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
616 | - const struct iphdr *ip = ip_hdr(skb); | |
617 | - int length = 0, start = 0, insert = 0; | |
643 | + unsigned int csum_start_off = skb_transport_offset(skb); | |
644 | + unsigned int csum_index_off = csum_start_off + skb->csum_offset; | |
618 | 645 | |
619 | - switch (ip->protocol) { | |
620 | - case IPPROTO_TCP: | |
621 | - start = sizeof(struct iphdr) + ETH_HLEN; | |
622 | - insert = sizeof(struct iphdr) + ETH_HLEN + 16; | |
623 | - length = ip->tot_len - sizeof(struct iphdr); | |
624 | - break; | |
625 | - case IPPROTO_UDP: | |
626 | - start = sizeof(struct iphdr) + ETH_HLEN; | |
627 | - insert = sizeof(struct iphdr) + ETH_HLEN + 6; | |
628 | - length = ip->tot_len - sizeof(struct iphdr); | |
629 | - break; | |
630 | - default: | |
631 | - break; | |
632 | - } | |
633 | - cur_p->app1 = ((start << 16) | insert); | |
634 | - cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr, | |
635 | - length, ip->protocol, 0); | |
636 | - skb->data[insert] = 0; | |
637 | - skb->data[insert + 1] = 0; | |
646 | + cur_p->app0 |= 1; /* TX Checksum Enabled */ | |
647 | + cur_p->app1 = (csum_start_off << 16) | csum_index_off; | |
648 | + cur_p->app2 = 0; /* initial checksum seed */ | |
638 | 649 | } |
650 | + | |
639 | 651 | cur_p->app0 |= STS_CTRL_APP0_SOP; |
640 | 652 | cur_p->len = skb_headlen(skb); |
641 | 653 | cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, |
... | ... | @@ -699,6 +711,15 @@ |
699 | 711 | skb->protocol = eth_type_trans(skb, ndev); |
700 | 712 | skb->ip_summed = CHECKSUM_NONE; |
701 | 713 | |
714 | + /* if we're doing rx csum offload, set it up */ | |
715 | + if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) && | |
716 | + (skb->protocol == __constant_htons(ETH_P_IP)) && | |
717 | + (skb->len > 64)) { | |
718 | + | |
719 | + skb->csum = cur_p->app3 & 0xFFFF; | |
720 | + skb->ip_summed = CHECKSUM_COMPLETE; | |
721 | + } | |
722 | + | |
702 | 723 | netif_rx(skb); |
703 | 724 | |
704 | 725 | ndev->stats.rx_packets++; |
... | ... | @@ -883,6 +904,7 @@ |
883 | 904 | struct temac_local *lp; |
884 | 905 | struct net_device *ndev; |
885 | 906 | const void *addr; |
907 | + __be32 *p; | |
886 | 908 | int size, rc = 0; |
887 | 909 | |
888 | 910 | /* Init network device structure */ |
... | ... | @@ -925,6 +947,18 @@ |
925 | 947 | dev_err(&op->dev, "could not map temac regs.\n"); |
926 | 948 | goto nodev; |
927 | 949 | } |
950 | + | |
951 | + /* Setup checksum offload, but default to off if not specified */ | |
952 | + lp->temac_features = 0; | |
953 | + p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL); | |
954 | + if (p && be32_to_cpu(*p)) { | |
955 | + lp->temac_features |= TEMAC_FEATURE_TX_CSUM; | |
956 | + /* Can checksum TCP/UDP over IPv4. */ | |
957 | + ndev->features |= NETIF_F_IP_CSUM; | |
958 | + } | |
959 | + p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL); | |
960 | + if (p && be32_to_cpu(*p)) | |
961 | + lp->temac_features |= TEMAC_FEATURE_RX_CSUM; | |
928 | 962 | |
929 | 963 | /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ |
930 | 964 | np = of_parse_phandle(op->node, "llink-connected", 0); |