⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hamachi.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : 		(((dev->mtu+26+7) & ~7) + 2 + 16));	/* Initialize all Rx descriptors. */	for (i = 0; i < RX_RING_SIZE; i++) {		hmp->rx_ring[i].status_n_length = 0;		hmp->rx_skbuff[i] = 0;	}	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);		hmp->rx_skbuff[i] = skb;		if (skb == NULL)			break;		skb->dev = dev;         /* Mark as being used by this device. */		skb_reserve(skb, 2); /* 16 byte align the IP header. */                hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 			skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));		/* -2 because it doesn't REALLY have that first 2 bytes -KDU */		hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 			DescEndPacket | DescIntr | (hmp->rx_buf_sz -2));	}	hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);	hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);	for (i = 0; i < TX_RING_SIZE; i++) {		hmp->tx_skbuff[i] = 0;		hmp->tx_ring[i].status_n_length = 0;	}	/* Mark the last entry of the ring */	hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);	return;}#ifdef TX_CHECKSUM#define csum_add(it, val) \do { \    it += (u16) (val); \    if (it & 0xffff0000) { \	it &= 0xffff; \	++it; \    } \} while (0)    /* printk("add %04x --> %04x\n", val, it); \ *//* uh->len already network format, do not swap */#define pseudo_csum_udp(sum,ih,uh) do { \    sum = 0; \    csum_add(sum, (ih)->saddr >> 16); \    csum_add(sum, (ih)->saddr & 0xffff); \    csum_add(sum, (ih)->daddr >> 16); \    csum_add(sum, (ih)->daddr & 0xffff); \    csum_add(sum, __constant_htons(IPPROTO_UDP)); \    csum_add(sum, (uh)->len); \} while (0)/* swap len */#define pseudo_csum_tcp(sum,ih,len) do { \    sum = 0; \    csum_add(sum, (ih)->saddr >> 16); \    csum_add(sum, (ih)->saddr & 0xffff); \    csum_add(sum, (ih)->daddr >> 16); \    csum_add(sum, (ih)->daddr & 0xffff); \    csum_add(sum, __constant_htons(IPPROTO_TCP)); \    csum_add(sum, htons(len)); \} while (0)#endifstatic int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct hamachi_private *hmp = dev->priv;	unsigned entry;	u16 status;	/* Ok, now make sure that the queue has space before trying to 		add another skbuff.  if we return non-zero the scheduler		should interpret this as a queue full and requeue the buffer		for later.	 */	if (hmp->tx_full) {		/* We should NEVER reach this point -KDU */		printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx);		/* Wake the potentially-idle transmit channel. */		/* If we don't need to read status, DON'T -KDU */		status=readw(dev->base_addr + TxStatus);		if( !(status & 0x0001) || (status & 0x0002))			writew(0x0001, dev->base_addr + TxCmd);		return 1;	} 	/* Caution: the write order is important here, set the field	   with the "ownership" bits last. */	/* Calculate the next Tx descriptor entry. */	entry = hmp->cur_tx % TX_RING_SIZE;	hmp->tx_skbuff[entry] = skb;#ifdef TX_CHECKSUM	{	    /* tack on checksum tag */	    u32 tagval = 0;	    struct ethhdr *eh = (struct ethhdr *)skb->data;	    if (eh->h_proto == __constant_htons(ETH_P_IP)) {		struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN);		if (ih->protocol == IPPROTO_UDP) {		    struct udphdr *uh		      = (struct udphdr *)((char *)ih + ih->ihl*4);		    u32 offset = ((unsigned char *)uh + 6) - skb->data;		    u32 pseudo;		    pseudo_csum_udp(pseudo, ih, uh);		    pseudo = htons(pseudo);		    printk("udp cksum was %04x, sending pseudo %04x\n",		      uh->check, pseudo);		    uh->check = 0;  /* zero out uh->check before card calc */		    /*		     * start at 14 (skip ethhdr), store at offset (uh->check),		     * use pseudo value given.		     */		    tagval = (14 << 24) | (offset << 16) | pseudo;		} else if (ih->protocol == IPPROTO_TCP) {		    printk("tcp, no auto cksum\n");		}	    }	    *(u32 *)skb_push(skb, 8) = tagval;	}#endif        hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 		skb->data, skb->len, PCI_DMA_TODEVICE));    	/* Hmmmm, could probably put a DescIntr on these, but the way		the driver is currently coded makes Tx interrupts unnecessary		since the clearing of the Tx ring is handled by the start_xmit		routine.  This organization helps mitigate the interrupts a		bit and probably renders the max_tx_latency param useless.				Update: Putting a DescIntr bit on all of the descriptors and		mitigating interrupt frequency with the tx_min_pkt parameter. -KDU	*/	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */		hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn |			DescEndPacket | DescEndRing | DescIntr | skb->len);	else		hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn |			DescEndPacket | DescIntr | skb->len);	hmp->cur_tx++;	/* Non-x86 Todo: explicitly flush cache lines here. */	/* Wake the potentially-idle transmit channel. */	/* If we don't need to read status, DON'T -KDU */	status=readw(dev->base_addr + TxStatus);	if( !(status & 0x0001) || (status & 0x0002))		writew(0x0001, dev->base_addr + TxCmd);	/* Immediately before returning, let's clear as many entries as we can. */	hamachi_tx(dev);	/* We should kick the bottom half here, since we are not accepting	 * interrupts with every packet.  i.e. realize that Gigabit ethernet	 * can transmit faster than ordinary machines can load packets;	 * hence, any packet that got put off because we were in the transmit	 * routine should IMMEDIATELY get a chance to be re-queued. -KDU	 */	if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) 		netif_wake_queue(dev);  /* Typical path */	else {		hmp->tx_full = 1;		netif_stop_queue(dev);	}	dev->trans_start = jiffies;	if (hamachi_debug > 4) {		printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",			   dev->name, hmp->cur_tx, entry);	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs){	struct net_device *dev = dev_instance;	struct hamachi_private *hmp;	long ioaddr, boguscnt = max_interrupt_work;#ifndef final_version			/* Can never occur. */	if (dev == NULL) {		printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq);		return;	}#endif	ioaddr = dev->base_addr;	hmp = dev->priv;	spin_lock(&hmp->lock);	do {		u32 intr_status = readl(ioaddr + InterruptClear);		if (hamachi_debug > 4)			printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n",				   dev->name, intr_status);		if (intr_status == 0)			break;		if (intr_status & IntrRxDone)			hamachi_rx(dev);		if (intr_status & IntrTxDone){			/* This code should RARELY need to execute. After all, this is			 * a gigabit link, it should consume packets as fast as we put			 * them in AND we clear the Tx ring in hamachi_start_xmit().			 */ 			if (hmp->tx_full){				for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){					int entry = hmp->dirty_tx % TX_RING_SIZE;					struct sk_buff *skb;					if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 						break;					skb = hmp->tx_skbuff[entry];					/* Free the original skb. */					if (skb){						pci_unmap_single(hmp->pci_dev, 							hmp->tx_ring[entry].addr, 							skb->len,							PCI_DMA_TODEVICE);						dev_kfree_skb_irq(skb);						hmp->tx_skbuff[entry] = 0;					}					hmp->tx_ring[entry].status_n_length = 0;					if (entry >= TX_RING_SIZE-1)  						hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 							cpu_to_le32(DescEndRing);					hmp->stats.tx_packets++;				}				if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){					/* The ring is no longer full */					hmp->tx_full = 0;					netif_wake_queue(dev);				}			} else {				netif_wake_queue(dev);			}		}		/* Abnormal error summary/uncommon events handlers. */		if (intr_status &			(IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr |			 LinkChange | NegotiationChange | StatsMax))			hamachi_error(dev, intr_status);		if (--boguscnt < 0) {			printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n",				   dev->name, intr_status);			break;		}	} while (1);	if (hamachi_debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, readl(ioaddr + IntrStatus));#ifndef final_version	/* Code that should never be run!  Perhaps remove after testing.. */	{		static int stopit = 10;		if (dev->start == 0  &&  --stopit < 0) {			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",				   dev->name);			free_irq(irq, dev);		}	}#endif	spin_unlock(&hmp->lock);}#ifdef TX_CHECKSUM/* * Copied from eth_type_trans(), with reduced header, since we don't * get it on RX, only on TX. */static unsigned short hamachi_eth_type_trans(struct sk_buff *skb,  struct net_device *dev){	struct ethhdr *eth;	unsigned char *rawp;		skb->mac.raw=skb->data;	skb_pull(skb,dev->hard_header_len-8);  /* artificially enlarged on tx */	eth= skb->mac.ethernet;		if(*eth->h_dest&1)	{		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)			skb->pkt_type=PACKET_BROADCAST;		else			skb->pkt_type=PACKET_MULTICAST;	}		/*	 *	This ALLMULTI check should be redundant by 1.4	 *	so don't forget to remove it.	 *	 *	Seems, you forgot to remove it. All silly devices	 *	seems to set IFF_PROMISC.	 */	 	else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))	{		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))			skb->pkt_type=PACKET_OTHERHOST;	}		if (ntohs(eth->h_proto) >= 1536)		return eth->h_proto;			rawp = skb->data;		/*	 *	This is a magic hack to spot IPX packets. Older Novell breaks	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This	 *	won't work for fault tolerant netware but does for the rest.	 */	if (*(unsigned short *)rawp == 0xFFFF)		return htons(ETH_P_802_3);			/*	 *	Real 802.2 LLC	 */	return htons(ETH_P_802_2);}#endif  /* TX_CHECKSUM *//* This routine is logically part of the interrupt handler, but seperated   for clarity and better register allocation. */static int hamachi_rx(struct net_device *dev){	struct hamachi_private *hmp = dev->priv;	int entry = hmp->cur_rx % RX_RING_SIZE;	int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx;	if (hamachi_debug > 4) {		printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n",			   entry, hmp->rx_ring[entry].status_n_length);	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while (1) {		struct hamachi_desc *desc = &(hmp->rx_ring[entry]);		u32 desc_status = le32_to_cpu(desc->status_n_length);		u16 data_size = desc_status;	/* Implicit truncate */		u8 *buf_addr; 		s32 frame_status;				if (desc_status & DescOwn)			break;		pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, 			PCI_DMA_FROMDEVICE);		buf_addr = (u8 *)hmp->rx_ring + entry*sizeof(*desc);		frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));		if (hamachi_debug > 4)			printk(KERN_DEBUG "  hamachi_rx() status was %8.8x.\n",				frame_status);		if (--boguscnt < 0)			break;		if ( ! (desc_status & DescEndPacket)) {			printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "				   "multiple buffers, entry %#x length %d status %4.4x!\n",				   dev->name, hmp->cur_rx, data_size, desc_status);			printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",				   dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]);			printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n",				   dev->name,				   hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0xffff0000,				   hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0x0000ffff,				   hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length);			hmp->stats.rx_length_errors++;		} /* else  Omit for prototype errata??? */		if (frame_status & 0x00380000) {			/* There was an error. */

⌨️ 快捷键说明

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