X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Farcnet%2Farcnet.c;h=4e91dab1f17f330ee4c5108e22c62e20f17c09d0;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=57c1b7d2d36252857f95f8278a78d2d80983cc00;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 57c1b7d2d..4e91dab1f 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -44,7 +44,6 @@ #define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n" #include -#include #include #include #include @@ -52,7 +51,7 @@ #include #include #include - +#include /* "do nothing" functions for protocol drivers */ static void null_rx(struct net_device *dev, int bufnum, @@ -62,6 +61,7 @@ static int null_build_header(struct sk_buff *skb, struct net_device *dev, static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum); +static void arcnet_rx(struct net_device *dev, int bufnum); /* * one ArcProto per possible proto ID. None of the elements of @@ -69,29 +69,30 @@ static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, * arc_proto_default instead. It also must not be NULL; if you would like * to set it to NULL, set it to &arc_proto_null instead. */ -struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto; + struct ArcProto *arc_proto_map[256], *arc_proto_default, + *arc_bcast_proto, *arc_raw_proto; -struct ArcProto arc_proto_null = +static struct ArcProto arc_proto_null = { .suffix = '?', .mtu = XMTU, + .is_ip = 0, .rx = null_rx, .build_header = null_build_header, .prepare_tx = null_prepare_tx, + .continue_tx = NULL, + .ack_tx = NULL }; -static spinlock_t arcnet_lock = SPIN_LOCK_UNLOCKED; - /* Exported function prototypes */ int arcnet_debug = ARCNET_DEBUG; EXPORT_SYMBOL(arc_proto_map); EXPORT_SYMBOL(arc_proto_default); EXPORT_SYMBOL(arc_bcast_proto); -EXPORT_SYMBOL(arc_proto_null); +EXPORT_SYMBOL(arc_raw_proto); EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); -EXPORT_SYMBOL(arcdev_setup); EXPORT_SYMBOL(alloc_arcdev); EXPORT_SYMBOL(arcnet_interrupt); @@ -108,7 +109,7 @@ static struct net_device_stats *arcnet_get_stats(struct net_device *dev); static int go_tx(struct net_device *dev); static int debug = ARCNET_DEBUG; -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_LICENSE("GPL"); static int __init arcnet_init(void) @@ -117,7 +118,7 @@ static int __init arcnet_init(void) arcnet_debug = debug; - printk(VERSION); + printk("arcnet loaded.\n"); #ifdef ALPHA_WARNING BUGLVL(D_EXTRA) { @@ -131,7 +132,7 @@ static int __init arcnet_init(void) #endif /* initialize the protocol map */ - arc_proto_default = arc_bcast_proto = &arc_proto_null; + arc_raw_proto = arc_proto_default = arc_bcast_proto = &arc_proto_null; for (count = 0; count < 256; count++) arc_proto_map[count] = arc_proto_default; @@ -155,7 +156,8 @@ module_exit(arcnet_exit); * Dump the contents of an sk_buff */ #if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) +void arcnet_dump_skb(struct net_device *dev, + struct sk_buff *skb, char *desc) { int i; @@ -176,18 +178,22 @@ EXPORT_SYMBOL(arcnet_dump_skb); * Dump the contents of an ARCnet buffer */ #if (ARCNET_DEBUG_MAX & (D_RX | D_TX)) -void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc) +static void arcnet_dump_packet(struct net_device *dev, int bufnum, + char *desc, int take_arcnet_lock) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int i, length; - unsigned long flags; + unsigned long flags = 0; static uint8_t buf[512]; /* hw.copy_from_card expects IRQ context so take the IRQ lock to keep it single threaded */ - spin_lock_irqsave(&arcnet_lock, flags); + if(take_arcnet_lock) + spin_lock_irqsave(&lp->lock, flags); + lp->hw.copy_from_card(dev, bufnum, 0, buf, 512); - spin_unlock_irqrestore(&arcnet_lock, flags); + if(take_arcnet_lock) + spin_unlock_irqrestore(&lp->lock, flags); /* if the offset[0] byte is nonzero, this is a 256-byte packet */ length = (buf[2] ? 256 : 512); @@ -202,7 +208,10 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc) } -EXPORT_SYMBOL(arcnet_dump_packet); +#else + +#define arcnet_dump_packet(dev, bufnum, desc,take_arcnet_lock) do { } while (0) + #endif @@ -219,6 +228,8 @@ void arcnet_unregister_proto(struct ArcProto *proto) arc_proto_default = &arc_proto_null; if (arc_bcast_proto == proto) arc_bcast_proto = arc_proto_default; + if (arc_raw_proto == proto) + arc_raw_proto = arc_proto_default; for (count = 0; count < 256; count++) { if (arc_proto_map[count] == proto) @@ -236,7 +247,7 @@ void arcnet_unregister_proto(struct ArcProto *proto) */ static void release_arcbuf(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int i; lp->buf_queue[lp->first_free_buf++] = bufnum; @@ -245,7 +256,7 @@ static void release_arcbuf(struct net_device *dev, int bufnum) BUGLVL(D_DURING) { BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ", bufnum); - for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5) BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); BUGMSG2(D_DURING, "\n"); } @@ -258,11 +269,14 @@ static void release_arcbuf(struct net_device *dev, int bufnum) */ static int get_arcbuf(struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int buf = -1, i; - if (!atomic_dec_and_test(&lp->buf_lock)) /* already in this function */ - BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", lp->buf_lock.counter); + if (!atomic_dec_and_test(&lp->buf_lock)) { + /* already in this function */ + BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", + lp->buf_lock.counter); + } else { /* we can continue */ if (lp->next_buf >= 5) lp->next_buf -= 5; @@ -278,7 +292,7 @@ static int get_arcbuf(struct net_device *dev) BUGLVL(D_DURING) { BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf); - for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5) BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); BUGMSG2(D_DURING, "\n"); } @@ -305,14 +319,14 @@ static int choose_mtu(void) /* Setup a struct device for ARCnet. */ -void arcdev_setup(struct net_device *dev) +static void arcdev_setup(struct net_device *dev) { dev->type = ARPHRD_ARCNET; dev->hard_header_len = sizeof(struct archdr); dev->mtu = choose_mtu(); dev->addr_len = ARCNET_ALEN; - dev->tx_queue_len = 30; + dev->tx_queue_len = 100; dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ dev->watchdog_timeo = TX_TIMEOUT; @@ -334,8 +348,16 @@ void arcdev_setup(struct net_device *dev) struct net_device *alloc_arcdev(char *name) { - return alloc_netdev(sizeof(struct arcnet_local), - name && *name ? name : "arc%d", arcdev_setup); + struct net_device *dev; + + dev = alloc_netdev(sizeof(struct arcnet_local), + name && *name ? name : "arc%d", arcdev_setup); + if(dev) { + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + spin_lock_init(&lp->lock); + } + + return dev; } /* @@ -348,9 +370,11 @@ struct net_device *alloc_arcdev(char *name) */ static int arcnet_open(struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int count, newmtu, error; + BUGMSG(D_INIT,"opened."); + if (!try_module_get(lp->hw.owner)) return -ENODEV; @@ -377,6 +401,8 @@ static int arcnet_open(struct net_device *dev) if (newmtu < dev->mtu) dev->mtu = newmtu; + BUGMSG(D_INIT, "arcnet_open: mtu: %d.\n", dev->mtu); + /* autodetect the encapsulation for each host. */ memset(lp->default_proto, 0, sizeof(lp->default_proto)); @@ -390,6 +416,7 @@ static int arcnet_open(struct net_device *dev) /* initialize buffers */ atomic_set(&lp->buf_lock, 1); + lp->next_buf = lp->first_free_buf = 0; release_arcbuf(dev, 0); release_arcbuf(dev, 1); @@ -401,7 +428,8 @@ static int arcnet_open(struct net_device *dev) lp->rfc1201.sequence = 1; /* bring up the hardware driver */ - lp->hw.open(dev); + if (lp->hw.open) + lp->hw.open(dev); if (dev->dev_addr[0] == 0) BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " @@ -410,17 +438,24 @@ static int arcnet_open(struct net_device *dev) BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " "DOS networking programs!\n"); - if (ASTATUS() & RESETflag) + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + if (ASTATUS() & RESETflag) { + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); ACOMMAND(CFLAGScmd | RESETclear); + } + + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); /* make sure we're ready to receive IRQ's. */ AINTMASK(0); udelay(1); /* give it time to set the mask before * we reset it again. (may not even be * necessary) */ + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); lp->intmask = NORXflag | RECONflag; AINTMASK(lp->intmask); + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); netif_start_queue(dev); @@ -435,7 +470,7 @@ static int arcnet_open(struct net_device *dev) /* The inverse routine to arcnet_open - shuts down the card. */ static int arcnet_close(struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; netif_stop_queue(dev); @@ -456,7 +491,7 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; uint8_t _daddr, proto_num; struct ArcProto *proto; @@ -466,32 +501,41 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, daddr ? *(uint8_t *) daddr : -1, type, type, len); - if (len != skb->len) + if (skb->len!=0 && len != skb->len) BUGMSG(D_NORMAL, "arcnet_header: Yikes! skb->len(%d) != len(%d)!\n", skb->len, len); - /* - * if the dest addr isn't provided, we can't choose an encapsulation! - * Store the packet type (eg. ETH_P_IP) for now, and we'll push on a - * real header when we do rebuild_header. - */ - if (!daddr) { + + /* Type is host order - ? */ + if(type == ETH_P_ARCNET) { + proto = arc_raw_proto; + BUGMSG(D_DEBUG, "arc_raw_proto used. proto='%c'\n",proto->suffix); + _daddr = daddr ? *(uint8_t *) daddr : 0; + } + else if (!daddr) { + /* + * if the dest addr isn't provided, we can't choose an encapsulation! + * Store the packet type (eg. ETH_P_IP) for now, and we'll push on a + * real header when we do rebuild_header. + */ *(uint16_t *) skb_push(skb, 2) = type; if (skb->nh.raw - skb->mac.raw != 2) BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n", - skb->nh.raw - skb->mac.raw); + (int)(skb->nh.raw - skb->mac.raw)); return -2; /* return error -- can't transmit yet! */ } - /* otherwise, we can just add the header as usual. */ - _daddr = *(uint8_t *) daddr; - proto_num = lp->default_proto[_daddr]; - proto = arc_proto_map[proto_num]; - BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n", - proto_num, proto->suffix); - if (proto == &arc_proto_null && arc_bcast_proto != proto) { - BUGMSG(D_DURING, "actually, let's use '%c' instead.\n", - arc_bcast_proto->suffix); - proto = arc_bcast_proto; + else { + /* otherwise, we can just add the header as usual. */ + _daddr = *(uint8_t *) daddr; + proto_num = lp->default_proto[_daddr]; + proto = arc_proto_map[proto_num]; + BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n", + proto_num, proto->suffix); + if (proto == &arc_proto_null && arc_bcast_proto != proto) { + BUGMSG(D_DURING, "actually, let's use '%c' instead.\n", + arc_bcast_proto->suffix); + proto = arc_bcast_proto; + } } return proto->build_header(skb, dev, type, _daddr); } @@ -505,7 +549,7 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, static int arcnet_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int status = 0; /* default is failure */ unsigned short type; uint8_t daddr=0; @@ -514,10 +558,11 @@ static int arcnet_rebuild_header(struct sk_buff *skb) if (skb->nh.raw - skb->mac.raw != 2) { BUGMSG(D_NORMAL, "rebuild_header: shouldn't be here! (hdrsize=%d)\n", - skb->nh.raw - skb->mac.raw); + (int)(skb->nh.raw - skb->mac.raw)); return 0; } type = *(uint16_t *) skb_pull(skb, 2); + BUGMSG(D_DURING, "rebuild header for protocol %Xh\n", type); if (type == ETH_P_IP) { #ifdef CONFIG_INET @@ -549,15 +594,17 @@ static int arcnet_rebuild_header(struct sk_buff *skb) /* Called by the kernel in order to transmit a packet. */ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; struct archdr *pkt; struct arc_rfc1201 *soft; struct ArcProto *proto; int txbuf; + unsigned long flags; + int freeskb, retval; BUGMSG(D_DURING, - "transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n", - ASTATUS(), lp->cur_tx, lp->next_tx, skb->len); + "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n", + ASTATUS(), lp->cur_tx, lp->next_tx, skb->len,skb->protocol); pkt = (struct archdr *) skb->data; soft = &pkt->soft.rfc1201; @@ -571,45 +618,63 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) { BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n"); dev_kfree_skb(skb); - return 0; /* don't try again */ + return NETDEV_TX_OK; /* don't try again */ } /* We're busy transmitting a packet... */ netif_stop_queue(dev); + spin_lock_irqsave(&lp->lock, flags); AINTMASK(0); - - txbuf = get_arcbuf(dev); + if(lp->next_tx == -1) + txbuf = get_arcbuf(dev); + else { + txbuf = -1; + } if (txbuf != -1) { - if (proto->prepare_tx(dev, pkt, skb->len, txbuf)) { - /* done right away */ + if (proto->prepare_tx(dev, pkt, skb->len, txbuf) && + !proto->ack_tx) { + /* done right away and we don't want to acknowledge + the package later - forget about it now */ lp->stats.tx_bytes += skb->len; - dev_kfree_skb(skb); + freeskb = 1; } else { /* do it the 'split' way */ lp->outgoing.proto = proto; lp->outgoing.skb = skb; lp->outgoing.pkt = pkt; - if (!proto->continue_tx) - BUGMSG(D_NORMAL, "bug! prep_tx==0, but no continue_tx!\n"); - else if (proto->continue_tx(dev, txbuf)) { - BUGMSG(D_NORMAL, - "bug! continue_tx finished the first time! " - "(proto='%c')\n", proto->suffix); + freeskb = 0; + + if (proto->continue_tx && + proto->continue_tx(dev, txbuf)) { + BUGMSG(D_NORMAL, + "bug! continue_tx finished the first time! " + "(proto='%c')\n", proto->suffix); } } - + retval = NETDEV_TX_OK; + dev->trans_start = jiffies; lp->next_tx = txbuf; - } else - dev_kfree_skb(skb); + } else { + retval = NETDEV_TX_BUSY; + freeskb = 0; + } + BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); /* make sure we didn't ignore a TX IRQ while we were in here */ AINTMASK(0); - lp->intmask |= TXFREEflag; + + BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); + lp->intmask |= TXFREEflag|EXCNAKflag; AINTMASK(lp->intmask); + BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); - return 0; /* no need to try again */ + spin_unlock_irqrestore(&lp->lock, flags); + if (freeskb) { + dev_kfree_skb(skb); + } + return retval; /* no need to try again */ } @@ -619,7 +684,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) */ static int go_tx(struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); @@ -627,7 +692,7 @@ static int go_tx(struct net_device *dev) if (lp->cur_tx != -1 || lp->next_tx == -1) return 0; - BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx"); + BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx", 0); lp->cur_tx = lp->next_tx; lp->next_tx = -1; @@ -635,11 +700,11 @@ static int go_tx(struct net_device *dev) /* start sending */ ACOMMAND(TXcmd | (lp->cur_tx << 3)); - dev->trans_start = jiffies; lp->stats.tx_packets++; lp->lasttrans_dest = lp->lastload_dest; lp->lastload_dest = 0; - lp->intmask |= TXFREEflag; + lp->excnak_pending = 0; + lp->intmask |= TXFREEflag|EXCNAKflag; return 1; } @@ -649,11 +714,11 @@ static int go_tx(struct net_device *dev) static void arcnet_timeout(struct net_device *dev) { unsigned long flags; - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; int status = ASTATUS(); char *msg; - spin_lock_irqsave(&arcnet_lock, flags); + spin_lock_irqsave(&lp->lock, flags); if (status & TXFREEflag) { /* transmit _DID_ finish */ msg = " - missed IRQ?"; } else { @@ -664,14 +729,14 @@ static void arcnet_timeout(struct net_device *dev) } lp->stats.tx_errors++; - /* make sure we didn't miss a TX IRQ */ + /* make sure we didn't miss a TX or a EXC NAK IRQ */ AINTMASK(0); - lp->intmask |= TXFREEflag; + lp->intmask |= TXFREEflag|EXCNAKflag; AINTMASK(lp->intmask); - spin_unlock_irqrestore(&arcnet_lock, flags); + spin_unlock_irqrestore(&lp->lock, flags); - if (jiffies - lp->last_timeout > 10*HZ) { + if (time_after(jiffies, lp->last_timeout + 10*HZ)) { BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n", msg, status, lp->intmask, lp->lasttrans_dest); lp->last_timeout = jiffies; @@ -687,22 +752,22 @@ static void arcnet_timeout(struct net_device *dev) * interrupts. Establish which device needs attention, and call the correct * chipset interrupt handler. */ -irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t arcnet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct arcnet_local *lp; - int recbuf, status, didsomething, boguscount; + int recbuf, status, diagstatus, didsomething, boguscount; + int retval = IRQ_NONE; BUGMSG(D_DURING, "\n"); BUGMSG(D_DURING, "in arcnet_interrupt\n"); - - spin_lock(&arcnet_lock); - lp = (struct arcnet_local *) dev->priv; - if (!lp) - BUG(); + lp = dev->priv; + BUG_ON(!lp); + spin_lock(&lp->lock); + /* * RESET flag was enabled - if device is not running, we must clear it right * away (but nothing else). @@ -711,7 +776,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (ASTATUS() & RESETflag) ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); - spin_unlock(&arcnet_lock); + spin_unlock(&lp->lock); return IRQ_HANDLED; } @@ -721,6 +786,10 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) boguscount = 5; do { status = ASTATUS(); + diagstatus = (status >> 8) & 0xFF; + + BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n", + __FILE__,__LINE__,__FUNCTION__,status); didsomething = 0; /* @@ -760,24 +829,55 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) } didsomething++; } + + if((diagstatus & EXCNAKflag)) { + BUGMSG(D_DURING, "EXCNAK IRQ (diagstat=%Xh)\n", + diagstatus); + + ACOMMAND(NOTXcmd); /* disable transmit */ + lp->excnak_pending = 1; + + ACOMMAND(EXCNAKclear); + lp->intmask &= ~(EXCNAKflag); + didsomething++; + } + + /* a transmit finished, and we're interested in it. */ if ((status & lp->intmask & TXFREEflag) || lp->timed_out) { - lp->intmask &= ~TXFREEflag; + lp->intmask &= ~(TXFREEflag|EXCNAKflag); BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status); - if (lp->cur_tx != -1 && !(status & TXACKflag) && !lp->timed_out) { - if (lp->lasttrans_dest != 0) { - BUGMSG(D_EXTRA, "transmit was not acknowledged! " - "(status=%Xh, dest=%02Xh)\n", - status, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } else { - BUGMSG(D_DURING, - "broadcast was not acknowledged; that's normal " - "(status=%Xh, dest=%02Xh)\n", - status, lp->lasttrans_dest); + if (lp->cur_tx != -1 && !lp->timed_out) { + if(!(status & TXACKflag)) { + if (lp->lasttrans_dest != 0) { + BUGMSG(D_EXTRA, + "transmit was not acknowledged! " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_carrier_errors++; + } else { + BUGMSG(D_DURING, + "broadcast was not acknowledged; that's normal " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + } + } + + if (lp->outgoing.proto && + lp->outgoing.proto->ack_tx) { + int ackstatus; + if(status & TXACKflag) + ackstatus=2; + else if(lp->excnak_pending) + ackstatus=1; + else + ackstatus=0; + + lp->outgoing.proto + ->ack_tx(dev, ackstatus); } } if (lp->cur_tx != -1) @@ -797,8 +897,11 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (lp->outgoing.proto->continue_tx(dev, txbuf)) { /* that was the last segment */ lp->stats.tx_bytes += lp->outgoing.skb->len; - dev_kfree_skb_irq(lp->outgoing.skb); - lp->outgoing.proto = NULL; + if(!lp->outgoing.proto->ack_tx) + { + dev_kfree_skb_irq(lp->outgoing.skb); + lp->outgoing.proto = NULL; + } } lp->next_tx = txbuf; } @@ -809,7 +912,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* now process the received packet, if any */ if (recbuf != -1) { - BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq"); + BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq", 0); arcnet_rx(dev, recbuf); release_arcbuf(dev, recbuf); @@ -822,6 +925,9 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n", status); + /* MYRECON bit is at bit 7 of diagstatus */ + if(diagstatus & 0x80) + BUGMSG(D_RECON,"Put out that recon myself\n"); /* is the RECON info empty or old? */ if (!lp->first_recon || !lp->last_recon || @@ -867,6 +973,10 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); } + + if(didsomething) { + retval |= IRQ_HANDLED; + } } while (--boguscount && didsomething); @@ -879,8 +989,8 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) udelay(1); AINTMASK(lp->intmask); - spin_unlock(&arcnet_lock); - return IRQ_RETVAL(didsomething); + spin_unlock(&lp->lock); + return retval; } @@ -888,9 +998,9 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) * This is a generic packet receiver that calls arcnet??_rx depending on the * protocol ID found. */ -void arcnet_rx(struct net_device *dev, int bufnum) +static void arcnet_rx(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; struct archdr pkt; struct arc_rfc1201 *soft; int length, ofs; @@ -907,7 +1017,7 @@ void arcnet_rx(struct net_device *dev, int bufnum) } /* get the full header, if possible */ - if (sizeof(pkt.soft) < length) + if (sizeof(pkt.soft) <= length) lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft)); else { memset(&pkt.soft, 0, sizeof(pkt.soft)); @@ -922,7 +1032,7 @@ void arcnet_rx(struct net_device *dev, int bufnum) lp->stats.rx_bytes += length + ARC_HDR_SIZE; /* call the right receiver for the protocol */ - if (arc_proto_map[soft->proto] != &arc_proto_null) { + if (arc_proto_map[soft->proto]->is_ip) { BUGLVL(D_PROTO) { struct ArcProto *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]], @@ -954,7 +1064,7 @@ void arcnet_rx(struct net_device *dev, int bufnum) */ static struct net_device_stats *arcnet_get_stats(struct net_device *dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; return &lp->stats; } @@ -971,7 +1081,7 @@ static void null_rx(struct net_device *dev, int bufnum, static int null_build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; BUGMSG(D_PROTO, "tx: can't build header for encap %02Xh; load a protocol driver.\n", @@ -986,7 +1096,7 @@ static int null_build_header(struct sk_buff *skb, struct net_device *dev, static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = dev->priv; struct arc_hardware newpkt; BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n");