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 + -
显示快捷键?