arcnet.c

来自「linux 内核源代码」· C语言 代码 · 共 1,123 行 · 第 1/3 页

C
1,123
字号
{	struct arcnet_local *lp = dev->priv;	int count, newmtu, error;	BUGMSG(D_INIT,"opened.");	if (!try_module_get(lp->hw.owner))		return -ENODEV;	BUGLVL(D_PROTO) {		int count;		BUGMSG(D_PROTO, "protocol map (default is '%c'): ",		       arc_proto_default->suffix);		for (count = 0; count < 256; count++)			BUGMSG2(D_PROTO, "%c", arc_proto_map[count]->suffix);		BUGMSG2(D_PROTO, "\n");	}	BUGMSG(D_INIT, "arcnet_open: resetting card.\n");	/* try to put the card in a defined state - if it fails the first	 * time, actually reset it.	 */	error = -ENODEV;	if (ARCRESET(0) && ARCRESET(1))		goto out_module_put;	newmtu = choose_mtu();	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));	/* the broadcast address is special - use the 'bcast' protocol */	for (count = 0; count < 256; count++) {		if (arc_proto_map[count] == arc_bcast_proto) {			lp->default_proto[0] = count;			break;		}	}	/* initialize buffers */	atomic_set(&lp->buf_lock, 1);	lp->next_buf = lp->first_free_buf = 0;	release_arcbuf(dev, 0);	release_arcbuf(dev, 1);	release_arcbuf(dev, 2);	release_arcbuf(dev, 3);	lp->cur_tx = lp->next_tx = -1;	lp->cur_rx = -1;	lp->rfc1201.sequence = 1;	/* bring up the hardware driver */	if (lp->hw.open)		lp->hw.open(dev);	if (dev->dev_addr[0] == 0)		BUGMSG(D_NORMAL, "WARNING!  Station address 00 is reserved "		       "for broadcasts!\n");	else if (dev->dev_addr[0] == 255)		BUGMSG(D_NORMAL, "WARNING!  Station address FF may confuse "		       "DOS networking programs!\n");	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);	return 0; out_module_put:	module_put(lp->hw.owner);	return error;}/* The inverse routine to arcnet_open - shuts down the card. */static int arcnet_close(struct net_device *dev){	struct arcnet_local *lp = dev->priv;	netif_stop_queue(dev);	/* flush TX and disable RX */	AINTMASK(0);	ACOMMAND(NOTXcmd);	/* stop transmit */	ACOMMAND(NORXcmd);	/* disable receive */	mdelay(1);	/* shut down the card */	lp->hw.close(dev);	module_put(lp->hw.owner);	return 0;}static int arcnet_header(struct sk_buff *skb, struct net_device *dev,			 unsigned short type, const void *daddr,			 const void *saddr, unsigned len){	const struct arcnet_local *lp = netdev_priv(dev);	uint8_t _daddr, proto_num;	struct ArcProto *proto;	BUGMSG(D_DURING,	    "create header from %d to %d; protocol %d (%Xh); size %u.\n",	       saddr ? *(uint8_t *) saddr : -1,	       daddr ? *(uint8_t *) daddr : -1,	       type, type, len);	if (skb->len!=0 && len != skb->len)		BUGMSG(D_NORMAL, "arcnet_header: Yikes!  skb->len(%d) != len(%d)!\n",		       skb->len, len);  	/* 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;		/*		 * XXX: Why not use skb->mac_len?		 */		if (skb->network_header - skb->mac_header != 2)			BUGMSG(D_NORMAL, "arcnet_header: Yikes!  diff (%d) is not 2!\n",			       (int)(skb->network_header - skb->mac_header));		return -2;	/* return error -- can't transmit yet! */	}	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);}/*  * Rebuild the ARCnet hard header. This is called after an ARP (or in the * future other address resolution) has completed on this sk_buff. We now * let ARP fill in the destination field. */static int arcnet_rebuild_header(struct sk_buff *skb){	struct net_device *dev = skb->dev;	struct arcnet_local *lp = dev->priv;	int status = 0;		/* default is failure */	unsigned short type;	uint8_t daddr=0;	struct ArcProto *proto;	/*	 * XXX: Why not use skb->mac_len?	 */	if (skb->network_header - skb->mac_header != 2) {		BUGMSG(D_NORMAL,		       "rebuild_header: shouldn't be here! (hdrsize=%d)\n",		       (int)(skb->network_header - skb->mac_header));		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		BUGMSG(D_DURING, "rebuild header for ethernet protocol %Xh\n", type);		status = arp_find(&daddr, skb) ? 1 : 0;		BUGMSG(D_DURING, " rebuilt: dest is %d; protocol %Xh\n",		       daddr, type);#endif	} else {		BUGMSG(D_NORMAL,		       "I don't understand ethernet protocol %Xh addresses!\n", type);		lp->stats.tx_errors++;		lp->stats.tx_aborted_errors++;	}	/* if we couldn't resolve the address... give up. */	if (!status)		return 0;	/* add the _real_ header this time! */	proto = arc_proto_map[lp->default_proto[daddr]];	proto->build_header(skb, dev, type, daddr);	return 1;		/* success */}/* 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 = 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, protocol %x)\n",	       ASTATUS(), lp->cur_tx, lp->next_tx, skb->len,skb->protocol);	pkt = (struct archdr *) skb->data;	soft = &pkt->soft.rfc1201;	proto = arc_proto_map[soft->proto];	BUGMSG(D_SKB_SIZE, "skb: transmitting %d bytes to %02X\n",		skb->len, pkt->hard.dest);	BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx");	/* fits in one packet? */	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 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);	if(lp->next_tx == -1)		txbuf = get_arcbuf(dev);	else {		txbuf = -1;	}	if (txbuf != -1) {		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;			freeskb = 1;		} else {			/* do it the 'split' way */			lp->outgoing.proto = proto;			lp->outgoing.skb = skb;			lp->outgoing.pkt = pkt;			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 {		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);	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 retval;		/* no need to try again */}/* * Actually start transmitting a packet that was loaded into a buffer * by prepare_tx.  This should _only_ be called by the interrupt handler. */static int go_tx(struct net_device *dev){	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);	if (lp->cur_tx != -1 || lp->next_tx == -1)		return 0;	BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx", 0);	lp->cur_tx = lp->next_tx;	lp->next_tx = -1;	/* start sending */	ACOMMAND(TXcmd | (lp->cur_tx << 3));	lp->stats.tx_packets++;	lp->lasttrans_dest = lp->lastload_dest;	lp->lastload_dest = 0;	lp->excnak_pending = 0;	lp->intmask |= TXFREEflag|EXCNAKflag;	return 1;}/* Called by the kernel when transmit times out */static void arcnet_timeout(struct net_device *dev){	unsigned long flags;	struct arcnet_local *lp = dev->priv;	int status = ASTATUS();	char *msg;	spin_lock_irqsave(&lp->lock, flags);	if (status & TXFREEflag) {	/* transmit _DID_ finish */		msg = " - missed IRQ?";	} else {		msg = "";		lp->stats.tx_aborted_errors++;		lp->timed_out = 1;		ACOMMAND(NOTXcmd | (lp->cur_tx << 3));	}	lp->stats.tx_errors++;	/* make sure we didn't miss a TX or a EXC NAK IRQ */	AINTMASK(0);	lp->intmask |= TXFREEflag|EXCNAKflag;	AINTMASK(lp->intmask);		spin_unlock_irqrestore(&lp->lock, flags);	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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?