Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arcnet: add err_skb package for package status feedback

We need to track the status of our queued packages. This way the driving
process knows if failed packages need to be retransmitted. For this
purpose we queue the transferred/failed packages back into the err_skb
message queue added with some status information.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michael Grzeschik and committed by
David S. Miller
05fcd31c 65344ba9

+68 -10
+4
drivers/net/arcnet/arcdevice.h
··· 269 269 270 270 struct timer_list timer; 271 271 272 + struct net_device *dev; 273 + int reply_status; 274 + struct tasklet_struct reply_tasklet; 275 + 272 276 /* 273 277 * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of 274 278 * which can be used for either sending or receiving. The new dynamic
+64 -10
drivers/net/arcnet/arcnet.c
··· 51 51 #include <net/arp.h> 52 52 #include <linux/init.h> 53 53 #include <linux/jiffies.h> 54 + #include <linux/errqueue.h> 54 55 55 56 #include <linux/leds.h> 56 57 ··· 392 391 } 393 392 } 394 393 394 + static void arcnet_reply_tasklet(unsigned long data) 395 + { 396 + struct arcnet_local *lp = (struct arcnet_local *)data; 397 + 398 + struct sk_buff *ackskb, *skb; 399 + struct sock_exterr_skb *serr; 400 + struct sock *sk; 401 + int ret; 402 + 403 + local_irq_disable(); 404 + skb = lp->outgoing.skb; 405 + if (!skb || !skb->sk) { 406 + local_irq_enable(); 407 + return; 408 + } 409 + 410 + sock_hold(skb->sk); 411 + sk = skb->sk; 412 + ackskb = skb_clone_sk(skb); 413 + sock_put(skb->sk); 414 + 415 + if (!ackskb) { 416 + local_irq_enable(); 417 + return; 418 + } 419 + 420 + serr = SKB_EXT_ERR(ackskb); 421 + memset(serr, 0, sizeof(*serr)); 422 + serr->ee.ee_errno = ENOMSG; 423 + serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS; 424 + serr->ee.ee_data = skb_shinfo(skb)->tskey; 425 + serr->ee.ee_info = lp->reply_status; 426 + 427 + /* finally erasing outgoing skb */ 428 + dev_kfree_skb(lp->outgoing.skb); 429 + lp->outgoing.skb = NULL; 430 + 431 + ackskb->dev = lp->dev; 432 + 433 + ret = sock_queue_err_skb(sk, ackskb); 434 + if (ret) 435 + kfree_skb(ackskb); 436 + 437 + local_irq_enable(); 438 + }; 439 + 395 440 struct net_device *alloc_arcdev(const char *name) 396 441 { 397 442 struct net_device *dev; ··· 448 401 if (dev) { 449 402 struct arcnet_local *lp = netdev_priv(dev); 450 403 404 + lp->dev = dev; 451 405 spin_lock_init(&lp->lock); 452 406 init_timer(&lp->timer); 453 407 lp->timer.data = (unsigned long) dev; ··· 483 435 arc_cont(D_PROTO, "%c", arc_proto_map[count]->suffix); 484 436 arc_cont(D_PROTO, "\n"); 485 437 } 438 + 439 + tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet, 440 + (unsigned long)lp); 486 441 487 442 arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n"); 488 443 ··· 577 526 578 527 netif_stop_queue(dev); 579 528 netif_carrier_off(dev); 529 + 530 + tasklet_kill(&lp->reply_tasklet); 580 531 581 532 /* flush TX and disable RX */ 582 533 lp->hw.intmask(dev, 0); ··· 688 635 txbuf = -1; 689 636 690 637 if (txbuf != -1) { 638 + lp->outgoing.skb = skb; 691 639 if (proto->prepare_tx(dev, pkt, skb->len, txbuf) && 692 640 !proto->ack_tx) { 693 641 /* done right away and we don't want to acknowledge 694 642 * the package later - forget about it now 695 643 */ 696 644 dev->stats.tx_bytes += skb->len; 697 - dev_kfree_skb(skb); 698 645 } else { 699 646 /* do it the 'split' way */ 700 647 lp->outgoing.proto = proto; ··· 895 842 896 843 /* a transmit finished, and we're interested in it. */ 897 844 if ((status & lp->intmask & TXFREEflag) || lp->timed_out) { 845 + int ackstatus; 898 846 lp->intmask &= ~(TXFREEflag | EXCNAKflag); 847 + 848 + if (status & TXACKflag) 849 + ackstatus = 2; 850 + else if (lp->excnak_pending) 851 + ackstatus = 1; 852 + else 853 + ackstatus = 0; 899 854 900 855 arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n", 901 856 status); ··· 927 866 928 867 if (lp->outgoing.proto && 929 868 lp->outgoing.proto->ack_tx) { 930 - int ackstatus; 931 - 932 - if (status & TXACKflag) 933 - ackstatus = 2; 934 - else if (lp->excnak_pending) 935 - ackstatus = 1; 936 - else 937 - ackstatus = 0; 938 - 939 869 lp->outgoing.proto 940 870 ->ack_tx(dev, ackstatus); 941 871 } 872 + lp->reply_status = ackstatus; 873 + tasklet_hi_schedule(&lp->reply_tasklet); 942 874 } 943 875 if (lp->cur_tx != -1) 944 876 release_arcbuf(dev, lp->cur_tx);