#include <linux/init.h>
#include <linux/arcdevice.h>
-
/* "do nothing" functions for protocol drivers */
static void null_rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
* 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 =
{
.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_raw_proto);
EXPORT_SYMBOL(arc_proto_null);
EXPORT_SYMBOL(arcnet_unregister_proto);
EXPORT_SYMBOL(arcnet_debug);
-EXPORT_SYMBOL(arcdev_setup);
EXPORT_SYMBOL(alloc_arcdev);
EXPORT_SYMBOL(arcnet_interrupt);
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)
#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;
* 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;
* 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)
+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;
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);
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)
struct arcnet_local *lp = (struct arcnet_local *) 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;
/* 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;
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;
}
/*
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int count, newmtu, error;
+ BUGMSG(D_INIT,"opened.");
+
if (!try_module_get(lp->hw.owner))
return -ENODEV;
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));
/* initialize buffers */
atomic_set(&lp->buf_lock, 1);
+
lp->next_buf = lp->first_free_buf = 0;
release_arcbuf(dev, 0);
release_arcbuf(dev, 1);
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 "
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);
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);
}
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
struct arc_rfc1201 *soft;
struct ArcProto *proto;
int txbuf;
+ unsigned long flags;
+ int freeskb = 0;
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;
/* We're busy transmitting a packet... */
netif_stop_queue(dev);
+ spin_lock_irqsave(&lp->lock, flags);
AINTMASK(0);
txbuf = get_arcbuf(dev);
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);
+ if (proto->continue_tx &&
+ proto->continue_tx(dev, txbuf)) {
+ BUGMSG(D_NORMAL,
+ "bug! continue_tx finished the first time! "
+ "(proto='%c')\n", proto->suffix);
}
}
lp->next_tx = txbuf;
- } else
- dev_kfree_skb(skb);
+ } else {
+ freeskb = 1;
+ }
+ 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());
+ spin_unlock_irqrestore(&lp->lock, flags);
+ if (freeskb) {
+ dev_kfree_skb(skb);
+ }
return 0; /* no need to try again */
}
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;
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;
}
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 {
}
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) {
BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
{
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();
+ spin_lock(&lp->lock);
+
/*
* RESET flag was enabled - if device is not running, we must clear it right
* away (but nothing else).
if (ASTATUS() & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
- spin_unlock(&arcnet_lock);
+ spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
boguscount = 5;
do {
status = ASTATUS();
+ diagstatus = (status >> 8) & 0xFF;
+
+ BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n",
+ __FILE__,__LINE__,__FUNCTION__,status);
didsomething = 0;
/*
}
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)
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;
}
}
/* 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);
BUGMSG(D_DURING, "not recon: clearing counters anyway.\n");
}
+
+ if(didsomething) {
+ retval |= IRQ_HANDLED;
+ }
}
while (--boguscount && didsomething);
udelay(1);
AINTMASK(lp->intmask);
- spin_unlock(&arcnet_lock);
- return IRQ_RETVAL(didsomething);
+ spin_unlock(&lp->lock);
+ return retval;
}
}
/* 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));
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]],