📄 arcnet.c
字号:
#endif /* Shut down the card */ /* Disable TX if we need to */ if (lp->en_dis_able_TX) (*lp->en_dis_able_TX)(dev, 0); (*lp->arcnet_reset)(dev, 3); /* reset IRQ won't run if START=0 */#if 0 lp->intmask=0; SETMASK; /* no IRQ's (except RESET, of course) */ ACOMMAND(NOTXcmd); /* stop transmit */ ACOMMAND(NORXcmd); /* disable receive */#endif /* reset more flags */ dev->interrupt=0;#ifdef CONFIG_ARCNET_ETH lp->edev->interrupt=0;#endif#ifdef CONFIG_ARCNET_1051 lp->sdev->interrupt=0;#endif /* do NOT free lp->adev!! It's static! */ lp->adev=NULL;#ifdef CONFIG_ARCNET_ETH /* free the ethernet-encap protocol device */ lp->edev->priv=NULL; unregister_netdevice(lp->edev); kfree(lp->edev->name); kfree(lp->edev); lp->edev=NULL;#endif#ifdef CONFIG_ARCNET_1051 /* free the RFC1051-encap protocol device */ lp->sdev->priv=NULL; unregister_netdevice(lp->sdev); kfree(lp->sdev->name); kfree(lp->sdev); lp->sdev=NULL;#endif /* Update the statistics here. (not necessary in ARCnet) */ /* Decrease the use count */ (*lp->openclose_device)(0); return 0;}/**************************************************************************** * * * Transmitter routines * * * ****************************************************************************//* Generic error checking routine for arcnet??_send_packet */static intarcnet_send_packet_bad(struct sk_buff *skb, struct device *dev){ struct arcnet_local *lp = (struct arcnet_local *)dev->priv; BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n", ARCSTATUS,lp->intx); if (lp->in_txhandler) { BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n"); lp->stats.tx_dropped++; return 1; } if (lp->intx>1) { BUGMSG(D_NORMAL,"send_packet called while intx!\n"); lp->stats.tx_dropped++; return 1; } if (test_bit(0, (int *)&dev->tbusy)) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; int status=ARCSTATUS; if (tickssofar < TX_TIMEOUT) { BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n", status,tickssofar,lp->outgoing.skb, lp->outgoing.numsegs, lp->outgoing.segnum); return 1; } lp->intmask &= ~TXFREEflag; SETMASK; if (status&TXFREEflag) /* transmit _DID_ finish */ { BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", status,tickssofar,lp->intmask,lp->lasttrans_dest); lp->stats.tx_errors++; } else { BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", status,tickssofar,lp->intmask,lp->lasttrans_dest); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; ACOMMAND(NOTXcmd); } if (lp->outgoing.skb) { dev_kfree_skb(lp->outgoing.skb); lp->stats.tx_dropped++; } lp->outgoing.skb=NULL;#ifdef CONFIG_ARCNET_ETH lp->edev->tbusy=0;#endif#ifdef CONFIG_ARCNET_1051 lp->sdev->tbusy=0;#endif if (!test_and_clear_bit(0,(int *)&dev->tbusy)) BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n"); lp->txready=0; lp->sending=0; return 1; } if (lp->txready) /* transmit already in progress! */ { BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n", ARCSTATUS); lp->intmask &= ~TXFREEflag; SETMASK; ACOMMAND(NOTXcmd); /* abort current send */ (*lp->inthandler)(dev); /* fake an interrupt */ lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; lp->txready=0; /* we definitely need this line! */ return 1; } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (int *)&lp->adev->tbusy)) { BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", ARCSTATUS,lp->intx,jiffies-dev->trans_start); lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; return -EBUSY; }#ifdef CONFIG_ARCNET_1051 lp->sdev->tbusy=1;#endif#ifdef CONFIG_ARCNET_ETH lp->edev->tbusy=1;#endif return 0;}/* Called by the kernel in order to transmit a packet. */static intarcnetA_send_packet(struct sk_buff *skb, struct device *dev){ struct arcnet_local *lp = (struct arcnet_local *)dev->priv; int bad,oldmask=0; struct Outgoing *out=&(lp->outgoing); lp->intx++; oldmask |= lp->intmask; lp->intmask=0; SETMASK; bad=arcnet_send_packet_bad(skb,dev); if (bad) { lp->intx--; lp->intmask=oldmask; SETMASK; return bad; } /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ lp->intmask = oldmask & ~TXFREEflag; SETMASK; out->length = 1 < skb->len ? skb->len : 1; out->hdr=(struct ClientData*)skb->data; out->skb=skb; BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx"); out->hdr->sequence=(lp->sequence++); /* fits in one packet? */ if (out->length-EXTRA_CLIENTDATA<=XMTU) { BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n", out->length,out->hdr->split_flag); if (out->hdr->split_flag) BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n", out->hdr->split_flag); out->numsegs=1; out->segnum=1; (*lp->prepare_tx)(dev, ((char *)out->hdr)+EXTRA_CLIENTDATA, sizeof(struct ClientData)-EXTRA_CLIENTDATA, ((char *)skb->data)+sizeof(struct ClientData), out->length-sizeof(struct ClientData), out->hdr->daddr,1,0); /* done right away */ lp->stats.tx_bytes += out->skb->len; dev_kfree_skb(out->skb); out->skb=NULL; if (arcnet_go_tx(dev,1)) { /* inform upper layers */ arcnet_tx_done(dev, lp); } } else /* too big for one - split it */ { int maxsegsize=XMTU-4; out->data=(u_char *)skb->data + sizeof(struct ClientData); out->dataleft=out->length-sizeof(struct ClientData); out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize; out->segnum=0; BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n", out->length,out->numsegs); /* if a packet waiting, launch it */ arcnet_go_tx(dev,1); if (!lp->txready) { /* prepare a packet, launch it and prepare * another. */ arcnetA_continue_tx(dev); if (arcnet_go_tx(dev,1)) { arcnetA_continue_tx(dev); arcnet_go_tx(dev,1); } } /* if segnum==numsegs, the transmission is finished; * free the skb right away. */ if (out->segnum==out->numsegs) { /* transmit completed */ out->segnum++; if (out->skb) { lp->stats.tx_bytes += skb->len; dev_kfree_skb(out->skb); } out->skb=NULL; } } dev->trans_start=jiffies; lp->intx--; /* make sure we didn't ignore a TX IRQ while we were in here */ lp->intmask |= TXFREEflag; SETMASK; return 0;}/* After an RFC1201 split packet has been set up, this function calls * arcnetAS_prepare_tx to load the next segment into the card. This function * does NOT automatically call arcnet_go_tx. */void arcnetA_continue_tx(struct device *dev){ struct arcnet_local *lp = (struct arcnet_local *)dev->priv; int maxsegsize=XMTU-4; struct Outgoing *out=&(lp->outgoing); BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n", ARCSTATUS,lp->intx,lp->in_txhandler,lp->intmask); if (lp->txready) { BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n"); return; } if (out->segnum>=out->numsegs) { BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n", out->segnum+1,out->numsegs); } if (!out->segnum) /* first packet */ out->hdr->split_flag=((out->numsegs-2)<<1)+1; else out->hdr->split_flag=out->segnum<<1; out->seglen=maxsegsize; if (out->seglen>out->dataleft) out->seglen=out->dataleft; BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n", out->segnum+1,out->seglen,out->numsegs, out->length,out->hdr->split_flag); (*lp->prepare_tx)(dev,((char *)out->hdr)+EXTRA_CLIENTDATA, sizeof(struct ClientData)-EXTRA_CLIENTDATA, out->data,out->seglen,out->hdr->daddr,1,0); out->dataleft-=out->seglen; out->data+=out->seglen; out->segnum++;}/* Actually start transmitting a packet that was placed in the card's * buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started. * * This should probably always be called with the INTMASK register set to 0, * so go_tx is not called recursively. * * The enable_irq flag determines whether to actually write INTMASK value * to the card; TXFREEflag is always OR'ed into the memory variable either * way. */int arcnet_go_tx(struct device *dev,int enable_irq){ struct arcnet_local *lp=(struct arcnet_local *)dev->priv; BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n", ARCSTATUS,lp->intmask,lp->txready,lp->sending); if (lp->sending || !lp->txready) { if (enable_irq && lp->sending) { lp->intmask |= TXFREEflag; SETMASK; } return 0; } /* start sending */ ACOMMAND(TXcmd|(lp->txready<<3)); lp->stats.tx_packets++; lp->txready=0; lp->sending++; lp->lasttrans_dest=lp->lastload_dest; lp->lastload_dest=0; lp->intmask |= TXFREEflag; if (enable_irq) SETMASK; return 1;}/**************************************************************************** * * * Interrupt handler * * * ****************************************************************************//* The typical workload of the driver: Handle the network interface * interrupts. Establish which device needs attention, and call the correct * chipset interrupt handler. */voidarcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs){ struct device *dev = dev_id; struct arcnet_local *lp; if (dev==NULL) { BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); return; } BUGMSG(D_DURING,"in arcnet_interrupt\n"); lp=(struct arcnet_local *)dev->priv; if (!lp) { BUGMSG(D_DURING, "arcnet: irq ignored.\n"); return; } /* RESET flag was enabled - if !dev->start, we must clear it right * away (but nothing else) since inthandler() is never called. */ if (!dev->start) { if (ARCSTATUS & RESETflag) ACOMMAND(CFLAGScmd|RESETclear); return; } if (test_and_set_bit(0, (int *)&dev->interrupt)) { BUGMSG(D_NORMAL,"DRIVER PROBLEM! Nested arcnet interrupts!\n"); return; /* don't even try. */ }#ifdef CONFIG_ARCNET_1051 if (lp->sdev) lp->sdev->interrupt=1;#endif#ifdef CONFIG_ARCNET_ETH if (lp->edev) lp->edev->interrupt=1;#endif /* Call the "real" interrupt handler. */ (*lp->inthandler)(dev);#ifdef CONFIG_ARCNET_ETH if (lp->edev) lp->edev->interrupt=0;#endif#ifdef CONFIG_ARCNET_1051 if (lp->sdev) lp->sdev->interrupt=0;#endif if (!test_and_clear_bit(0, (int *)&dev->interrupt)) BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n");}void arcnet_tx_done(struct device *dev, struct arcnet_local *lp){ if (dev->tbusy) {#ifdef CONFIG_ARCNET_ETH lp->edev->tbusy=0;#endif#ifdef CONFIG_ARCNET_1051 lp->sdev->tbusy=0;#endif if (!test_and_clear_bit(0, (int *)&dev->tbusy)) BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy" " flag!\n"); mark_bh(NET_BH); }}/**************************************************************************** * * * Receiver routines * * * ****************************************************************************//* * This is a generic packet receiver that calls arcnet??_rx depending on the * protocol ID found. */void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr){ struct device *dev=lp->adev; BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n", saddr,daddr,length); /* call the right receiver for the protocol */ switch (arcsoft[0]) { case ARC_P_IP: case ARC_P_ARP: case ARC_P_RARP: case ARC_P_IPX: case ARC_P_NOVELL_EC: arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr); break;#ifdef CONFIG_ARCNET_ETH case ARC_P_ETHER: arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr); break;#endif#ifdef CONFIG_ARCNET_1051 case ARC_P_IP_RFC1051: case ARC_P_ARP_RFC1051: arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -