Skip to content

Commit 23ecc4b

Browse files
Brian Hilldavem330
authored andcommitted
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 <[email protected]> Signed-off-by: John Linn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 755fae0 commit 23ecc4b

File tree

2 files changed

+63
-24
lines changed

2 files changed

+63
-24
lines changed

drivers/net/ll_temac.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ This option defaults to enabled (set) */
295295

296296
#define MULTICAST_CAM_TABLE_NUM 4
297297

298+
/* TEMAC Synthesis features */
299+
#define TEMAC_FEATURE_RX_CSUM (1 << 0)
300+
#define TEMAC_FEATURE_TX_CSUM (1 << 1)
301+
298302
/* TX/RX CURDESC_PTR points to first descriptor */
299303
/* TX/RX TAILDESC_PTR points to last descriptor in linked list */
300304

@@ -353,6 +357,7 @@ struct temac_local {
353357
struct mutex indirect_mutex;
354358
u32 options; /* Current options word */
355359
int last_link;
360+
unsigned int temac_features;
356361

357362
/* Buffer descriptors */
358363
struct cdmac_bd *tx_bd_v;

drivers/net/ll_temac_main.c

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
245245
CHNL_CTRL_IRQ_COAL_EN);
246246
/* 0x10220483 */
247247
/* 0x00100483 */
248-
lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
248+
lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
249249
CHNL_CTRL_IRQ_EN |
250250
CHNL_CTRL_IRQ_DLY_EN |
251251
CHNL_CTRL_IRQ_COAL_EN |
@@ -574,6 +574,10 @@ static void temac_start_xmit_done(struct net_device *ndev)
574574
if (cur_p->app4)
575575
dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
576576
cur_p->app0 = 0;
577+
cur_p->app1 = 0;
578+
cur_p->app2 = 0;
579+
cur_p->app3 = 0;
580+
cur_p->app4 = 0;
577581

578582
ndev->stats.tx_packets++;
579583
ndev->stats.tx_bytes += cur_p->len;
@@ -589,6 +593,29 @@ static void temac_start_xmit_done(struct net_device *ndev)
589593
netif_wake_queue(ndev);
590594
}
591595

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+
592619
static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
593620
{
594621
struct temac_local *lp = netdev_priv(ndev);
@@ -603,7 +630,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
603630
start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
604631
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
605632

606-
if (cur_p->app0 & STS_CTRL_APP0_CMPLT) {
633+
if (temac_check_tx_bd_space(lp, num_frag)) {
607634
if (!netif_queue_stopped(ndev)) {
608635
netif_stop_queue(ndev);
609636
return NETDEV_TX_BUSY;
@@ -613,29 +640,14 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
613640

614641
cur_p->app0 = 0;
615642
if (skb->ip_summed == CHECKSUM_PARTIAL) {
616-
const struct iphdr *ip = ip_hdr(skb);
617-
int length = 0, start = 0, insert = 0;
618-
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;
643+
unsigned int csum_start_off = skb_transport_offset(skb);
644+
unsigned int csum_index_off = csum_start_off + skb->csum_offset;
645+
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 */
638649
}
650+
639651
cur_p->app0 |= STS_CTRL_APP0_SOP;
640652
cur_p->len = skb_headlen(skb);
641653
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)
699711
skb->protocol = eth_type_trans(skb, ndev);
700712
skb->ip_summed = CHECKSUM_NONE;
701713

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+
702723
netif_rx(skb);
703724

704725
ndev->stats.rx_packets++;
@@ -883,6 +904,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
883904
struct temac_local *lp;
884905
struct net_device *ndev;
885906
const void *addr;
907+
__be32 *p;
886908
int size, rc = 0;
887909

888910
/* Init network device structure */
@@ -926,6 +948,18 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
926948
goto nodev;
927949
}
928950

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+
929963
/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
930964
np = of_parse_phandle(op->node, "llink-connected", 0);
931965
if (!np) {

0 commit comments

Comments
 (0)