diff options
| -rw-r--r-- | drivers/net/ll_temac.h | 5 | ||||
| -rw-r--r-- | drivers/net/ll_temac_main.c | 82 |
2 files changed, 63 insertions, 24 deletions
diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h index c03358434acb..522abe2ff25a 100644 --- a/drivers/net/ll_temac.h +++ b/drivers/net/ll_temac.h | |||
| @@ -295,6 +295,10 @@ This option defaults to enabled (set) */ | |||
| 295 | 295 | ||
| 296 | #define MULTICAST_CAM_TABLE_NUM 4 | 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 | /* TX/RX CURDESC_PTR points to first descriptor */ | 302 | /* TX/RX CURDESC_PTR points to first descriptor */ |
| 299 | /* TX/RX TAILDESC_PTR points to last descriptor in linked list */ | 303 | /* TX/RX TAILDESC_PTR points to last descriptor in linked list */ |
| 300 | 304 | ||
| @@ -353,6 +357,7 @@ struct temac_local { | |||
| 353 | struct mutex indirect_mutex; | 357 | struct mutex indirect_mutex; |
| 354 | u32 options; /* Current options word */ | 358 | u32 options; /* Current options word */ |
| 355 | int last_link; | 359 | int last_link; |
| 360 | unsigned int temac_features; | ||
| 356 | 361 | ||
| 357 | /* Buffer descriptors */ | 362 | /* Buffer descriptors */ |
| 358 | struct cdmac_bd *tx_bd_v; | 363 | struct cdmac_bd *tx_bd_v; |
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 1bb6e605f64f..fbd07de2e088 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c | |||
| @@ -245,7 +245,7 @@ static int temac_dma_bd_init(struct net_device *ndev) | |||
| 245 | CHNL_CTRL_IRQ_COAL_EN); | 245 | CHNL_CTRL_IRQ_COAL_EN); |
| 246 | /* 0x10220483 */ | 246 | /* 0x10220483 */ |
| 247 | /* 0x00100483 */ | 247 | /* 0x00100483 */ |
| 248 | lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 | | 248 | lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 | |
| 249 | CHNL_CTRL_IRQ_EN | | 249 | CHNL_CTRL_IRQ_EN | |
| 250 | CHNL_CTRL_IRQ_DLY_EN | | 250 | CHNL_CTRL_IRQ_DLY_EN | |
| 251 | CHNL_CTRL_IRQ_COAL_EN | | 251 | CHNL_CTRL_IRQ_COAL_EN | |
| @@ -574,6 +574,10 @@ static void temac_start_xmit_done(struct net_device *ndev) | |||
| 574 | if (cur_p->app4) | 574 | if (cur_p->app4) |
| 575 | dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); | 575 | dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); |
| 576 | cur_p->app0 = 0; | 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 | ndev->stats.tx_packets++; | 582 | ndev->stats.tx_packets++; |
| 579 | ndev->stats.tx_bytes += cur_p->len; | 583 | ndev->stats.tx_bytes += cur_p->len; |
| @@ -589,6 +593,29 @@ static void temac_start_xmit_done(struct net_device *ndev) | |||
| 589 | netif_wake_queue(ndev); | 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 | static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 619 | static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
| 593 | { | 620 | { |
| 594 | struct temac_local *lp = netdev_priv(ndev); | 621 | struct temac_local *lp = netdev_priv(ndev); |
| @@ -603,7 +630,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
| 603 | start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; | 630 | start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; |
| 604 | cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; | 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 | if (!netif_queue_stopped(ndev)) { | 634 | if (!netif_queue_stopped(ndev)) { |
| 608 | netif_stop_queue(ndev); | 635 | netif_stop_queue(ndev); |
| 609 | return NETDEV_TX_BUSY; | 636 | return NETDEV_TX_BUSY; |
| @@ -613,29 +640,14 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
| 613 | 640 | ||
| 614 | cur_p->app0 = 0; | 641 | cur_p->app0 = 0; |
| 615 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 642 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 616 | const struct iphdr *ip = ip_hdr(skb); | 643 | unsigned int csum_start_off = skb_transport_offset(skb); |
| 617 | int length = 0, start = 0, insert = 0; | 644 | unsigned int csum_index_off = csum_start_off + skb->csum_offset; |
| 618 | 645 | ||
| 619 | switch (ip->protocol) { | 646 | cur_p->app0 |= 1; /* TX Checksum Enabled */ |
| 620 | case IPPROTO_TCP: | 647 | cur_p->app1 = (csum_start_off << 16) | csum_index_off; |
| 621 | start = sizeof(struct iphdr) + ETH_HLEN; | 648 | cur_p->app2 = 0; /* initial checksum seed */ |
| 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; | ||
| 638 | } | 649 | } |
| 650 | |||
| 639 | cur_p->app0 |= STS_CTRL_APP0_SOP; | 651 | cur_p->app0 |= STS_CTRL_APP0_SOP; |
| 640 | cur_p->len = skb_headlen(skb); | 652 | cur_p->len = skb_headlen(skb); |
| 641 | cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, | 653 | cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, |
| @@ -699,6 +711,15 @@ static void ll_temac_recv(struct net_device *ndev) | |||
| 699 | skb->protocol = eth_type_trans(skb, ndev); | 711 | skb->protocol = eth_type_trans(skb, ndev); |
| 700 | skb->ip_summed = CHECKSUM_NONE; | 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 | netif_rx(skb); | 723 | netif_rx(skb); |
| 703 | 724 | ||
| 704 | ndev->stats.rx_packets++; | 725 | ndev->stats.rx_packets++; |
| @@ -883,6 +904,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) | |||
| 883 | struct temac_local *lp; | 904 | struct temac_local *lp; |
| 884 | struct net_device *ndev; | 905 | struct net_device *ndev; |
| 885 | const void *addr; | 906 | const void *addr; |
| 907 | __be32 *p; | ||
| 886 | int size, rc = 0; | 908 | int size, rc = 0; |
| 887 | 909 | ||
| 888 | /* Init network device structure */ | 910 | /* Init network device structure */ |
| @@ -926,6 +948,18 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) | |||
| 926 | goto nodev; | 948 | goto nodev; |
| 927 | } | 949 | } |
| 928 | 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; | ||
| 962 | |||
| 929 | /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ | 963 | /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ |
| 930 | np = of_parse_phandle(op->node, "llink-connected", 0); | 964 | np = of_parse_phandle(op->node, "llink-connected", 0); |
| 931 | if (!np) { | 965 | if (!np) { |
