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

📄 myri_sbus.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* myri_sbus.h: MyriCOM MyriNET SBUS card driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */static char *version =        "myri_sbus.c:v1.0 10/Dec/96 David S. Miller (davem@caipfs.rutgers.edu)\n";#include <linux/module.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include <asm/byteorder.h>#include <asm/idprom.h>#include <asm/sbus.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/auxio.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <net/dst.h>#include <net/arp.h>#include <net/sock.h>#include <net/ipv6.h>#include <asm/checksum.h>#include "myri_sbus.h"#include "myri_code.h"/* #define DEBUG_DETECT *//* #define DEBUG_IRQ *//* #define DEBUG_TRANSMIT *//* #define DEBUG_RECEIVE *//* #define DEBUG_HEADER */#ifdef DEBUG_DETECT#define DET(x)   printk x#else#define DET(x)#endif#ifdef DEBUG_IRQ#define DIRQ(x)  printk x#else#define DIRQ(x)#endif#ifdef DEBUG_TRANSMIT#define DTX(x)  printk x#else#define DTX(x)#endif#ifdef DEBUG_RECEIVE#define DRX(x)  printk x#else#define DRX(x)#endif#ifdef DEBUG_HEADER#define DHDR(x) printk x#else#define DHDR(x)#endif#ifdef MODULEstatic struct myri_eth *root_myri_dev = NULL;#endifstatic inline void myri_reset_off(struct lanai_regs *lp, struct myri_control *cregs){	lp->eimask = 0;			/* Clear IRQ mask.          */	cregs->ctrl = CONTROL_ROFF;	/* Turn RESET function off. */}static inline void myri_reset_on(struct myri_control *cregs){	cregs->ctrl = CONTROL_RON;	/* Enable RESET function.   */	cregs->ctrl = CONTROL_DIRQ;	/* Disable IRQ's.           */}static inline void myri_disable_irq(struct lanai_regs *lp, struct myri_control *cregs){	cregs->ctrl = CONTROL_DIRQ;	lp->eimask = 0;	lp->istat = ISTAT_HOST;}static inline void myri_enable_irq(struct lanai_regs *lp, struct myri_control *cregs){	cregs->ctrl = CONTROL_EIRQ;	lp->eimask = ISTAT_HOST;}static inline void bang_the_chip(struct myri_eth *mp){	struct myri_shmem *shmem	= mp->shmem;	struct myri_control *cregs	= mp->cregs;	shmem->send = 1;	cregs->ctrl = CONTROL_WON;}static inline int myri_do_handshake(struct myri_eth *mp){	struct myri_shmem *shmem	= mp->shmem;	struct myri_control *cregs	= mp->cregs;	struct myri_channel *chan	= &shmem->channel;	int tick 			= 0;	DET(("myri_do_handshake: "));	if(chan->state == STATE_READY) {		DET(("Already STATE_READY, failed.\n"));		return -1;	/* We're hosed... */	}	myri_disable_irq(mp->lregs, cregs);	while(tick++ <= 25) {		unsigned int softstate;		/* Wake it up. */		DET(("shakedown, CONTROL_WON, "));		shmem->shakedown = 1;		cregs->ctrl = CONTROL_WON;		softstate = chan->state;		DET(("chanstate[%08x] ", softstate));		if(softstate == STATE_READY) {			DET(("wakeup successful, "));			break;		}		if(softstate != STATE_WFN) {			DET(("not WFN setting that, "));			chan->state = STATE_WFN;		}		udelay(20);	}	myri_enable_irq(mp->lregs, cregs);	if(tick > 25) {		DET(("25 ticks we lose, failure.\n"));		return -1;	}	DET(("success\n"));	return 0;}static inline int myri_load_lanai(struct myri_eth *mp){	struct device		*dev = mp->dev;	struct myri_shmem	*shmem = mp->shmem;	unsigned char		*rptr;	int 			i;	myri_disable_irq(mp->lregs, mp->cregs);	myri_reset_on(mp->cregs);	rptr = (unsigned char *) mp->lanai;	for(i = 0; i < mp->eeprom.ramsz; i++)		rptr[i] = 0;	if(mp->eeprom.cpuvers >= CPUVERS_3_0)		mp->lregs->cval = mp->eeprom.cval;	/* Load executable code. */	for(i = 0; i < sizeof(lanai4_code); i++)		rptr[(lanai4_code_off * 2) + i] = lanai4_code[i];	/* Load data segment. */	for(i = 0; i < sizeof(lanai4_data); i++)		rptr[(lanai4_data_off * 2) + i] = lanai4_data[i];	/* Set device address. */	shmem->addr[0] = shmem->addr[1] = 0;	for(i = 0; i < 6; i++)		shmem->addr[i + 2] = dev->dev_addr[i];	/* Set SBUS bursts and interrupt mask. */	shmem->burst = ((mp->myri_bursts & 0xf8) >> 3);	shmem->imask = SHMEM_IMASK_RX;	/* Release the LANAI. */	myri_disable_irq(mp->lregs, mp->cregs);	myri_reset_off(mp->lregs, mp->cregs);	myri_disable_irq(mp->lregs, mp->cregs);	/* Wait for the reset to complete. */	for(i = 0; i < 5000; i++) {		if(shmem->channel.state != STATE_READY)			break;		else			udelay(10);	}	if(i == 5000)		printk("myricom: Chip would not reset after firmware load.\n");	i = myri_do_handshake(mp);	if(i)		printk("myricom: Handshake with LANAI failed.\n");	if(mp->eeprom.cpuvers == CPUVERS_4_0)		mp->lregs->vers = 0;	return i;}static void myri_clean_rings(struct myri_eth *mp){	struct sendq *sq = mp->sq;	struct recvq *rq = mp->rq;	int i;	rq->tail = rq->head = 0;	for(i = 0; i < (RX_RING_SIZE+1); i++) {		if(mp->rx_skbs[i] != NULL) {			dev_kfree_skb(mp->rx_skbs[i]);			mp->rx_skbs[i] = NULL;		}	}	mp->tx_old = sq->tail = sq->head = 0;	for(i = 0; i < TX_RING_SIZE; i++) {		if(mp->tx_skbs[i] != NULL) {			dev_kfree_skb(mp->tx_skbs[i]);			mp->tx_skbs[i] = NULL;		}	}}static void myri_init_rings(struct myri_eth *mp, int from_irq){	struct recvq *rq = mp->rq;	struct myri_rxd *rxd = &rq->myri_rxd[0];	struct device *dev = mp->dev;	int gfp_flags = GFP_KERNEL;	int i;	if(from_irq || in_interrupt())		gfp_flags = GFP_ATOMIC;	myri_clean_rings(mp);	for(i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = myri_alloc_skb(RX_ALLOC_SIZE, gfp_flags);		if(!skb)			continue;		mp->rx_skbs[i] = skb;		skb->dev = dev;		skb_put(skb, RX_ALLOC_SIZE);		rxd[i].myri_scatters[0].addr = sbus_dvma_addr(skb->data);		rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;		rxd[i].ctx = i;		rxd[i].num_sg = 1;	}	rq->head = 0;	rq->tail = RX_RING_SIZE;}static int myri_init(struct myri_eth *mp, int from_irq){	myri_init_rings(mp, from_irq);	return 0;}static void myri_is_not_so_happy(struct myri_eth *mp){}#ifdef DEBUG_HEADERstatic void dump_ehdr(struct ethhdr *ehdr){	printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"	       "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",	       ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],	       ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],	       ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],	       ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],	       ehdr->h_proto);}static void dump_ehdr_and_myripad(unsigned char *stuff){	struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2);	printk("pad[%02x:%02x]", stuff[0], stuff[1]);	printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"	       "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",	       ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],	       ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],	       ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],	       ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],	       ehdr->h_proto);}#endifstatic inline void myri_tx(struct myri_eth *mp, struct device *dev){	struct sendq *sq	= mp->sq;	int entry		= mp->tx_old;	int limit		= sq->head;	DTX(("entry[%d] limit[%d] ", entry, limit));	if(entry == limit)		return;	while(entry != limit) {		struct sk_buff *skb = mp->tx_skbs[entry];		DTX(("SKB[%d] ", entry));		dev_kfree_skb(skb);		mp->tx_skbs[entry] = NULL;		mp->enet_stats.tx_packets++;		entry = NEXT_TX(entry);	}	mp->tx_old = entry;}/* Determine the packet's protocol ID. The rule here is that we  * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. */static unsigned short myri_type_trans(struct sk_buff *skb, struct device *dev){	struct ethhdr *eth;	unsigned char *rawp;		skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);	skb_pull(skb, dev->hard_header_len);	eth = skb->mac.ethernet;	#ifdef DEBUG_HEADER	DHDR(("myri_type_trans: "));	dump_ehdr(eth);#endif	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;	} 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);}static inline void myri_rx(struct myri_eth *mp, struct device *dev){	struct recvq *rq	= mp->rq;	struct recvq *rqa	= mp->rqack;	int entry		= rqa->head;	int limit		= rqa->tail;	int drops;	DRX(("entry[%d] limit[%d] ", entry, limit));	if(entry == limit)		return;	drops = 0;	DRX(("\n"));	while(entry != limit) {		struct myri_rxd *rxdack = &rqa->myri_rxd[entry];		unsigned int csum	= rxdack->csum;		int len			= rxdack->myri_scatters[0].len;		int index		= rxdack->ctx;		struct myri_rxd *rxd	= &rq->myri_rxd[rq->tail];		struct sk_buff *skb	= mp->rx_skbs[index];		/* Ack it. */		rqa->head = NEXT_RX(entry);		/* Check for errors. */		DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));		if((len < (ETH_HLEN + MYRI_PAD_LEN)) || (skb->data[0] != MYRI_PAD_LEN)) {			DRX(("ERROR["));			mp->enet_stats.rx_errors++;			if(len < (ETH_HLEN + MYRI_PAD_LEN)) {				DRX(("BAD_LENGTH] "));				mp->enet_stats.rx_length_errors++;			} else {				DRX(("NO_PADDING] "));				mp->enet_stats.rx_frame_errors++;			}			/* Return it to the LANAI. */	drop_it:			drops++;			DRX(("DROP "));			mp->enet_stats.rx_dropped++;			rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data);			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;			rxd->ctx = index;			rxd->num_sg = 1;			rq->tail = NEXT_RX(rq->tail);			goto next;		}#ifdef NEED_DMA_SYNCHRONIZATION		mmu_sync_dma(sbus_dvma_addr(skb->data),			     skb->len, mp->myri_sbus_dev->my_bus);#endif		DRX(("len[%d] ", len));		if(len > RX_COPY_THRESHOLD) {			struct sk_buff *new_skb;			DRX(("BIGBUFF "));			new_skb = myri_alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC);			if(!new_skb) {				DRX(("skb_alloc(FAILED) "));				goto drop_it;			}			mp->rx_skbs[index] = new_skb;			new_skb->dev = dev;			skb_put(new_skb, RX_ALLOC_SIZE);			rxd->myri_scatters[0].addr = sbus_dvma_addr(new_skb->data);			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;			rxd->ctx = index;			rxd->num_sg = 1;			rq->tail = NEXT_RX(rq->tail);			/* Trim the original skb for the netif. */			DRX(("trim(%d) ", len));			skb_trim(skb, len);		} else {			struct sk_buff *copy_skb = dev_alloc_skb(len);			DRX(("SMALLBUFF "));			if(!copy_skb) {				DRX(("dev_alloc_skb(FAILED) "));				goto drop_it;			}			copy_skb->dev = dev;			DRX(("resv_and_put "));			skb_put(copy_skb, len);			memcpy(copy_skb->data, skb->data, len);			/* Reuse original ring buffer. */			DRX(("reuse "));			rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data);			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;			rxd->ctx = index;			rxd->num_sg = 1;			rq->tail = NEXT_RX(rq->tail);			skb = copy_skb;		}		/* Just like the happy meal we get checksums from this card. */		skb->csum = csum;		skb->ip_summed = CHECKSUM_UNNECESSARY; /* XXX */		skb->protocol = myri_type_trans(skb, dev);		DRX(("prot[%04x] netif_rx ", skb->protocol));		netif_rx(skb);		mp->enet_stats.rx_packets++;	next:		DRX(("NEXT\n"));		entry = NEXT_RX(entry);	}}static void myri_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev		= (struct device *) dev_id;	struct myri_eth *mp		= (struct myri_eth *) dev->priv;	struct lanai_regs *lregs	= mp->lregs;	struct myri_channel *chan	= &mp->shmem->channel;	unsigned int status;	status = lregs->istat;	DIRQ(("myri_interrupt: status[%08x] ", status));	if(status & ISTAT_HOST) {		unsigned int softstate;		DIRQ(("IRQ_DISAB "));		myri_disable_irq(lregs, mp->cregs);		dev->interrupt = 1;		softstate = chan->state;		DIRQ(("state[%08x] ", softstate));		if(softstate != STATE_READY) {			DIRQ(("myri_not_so_happy "));			myri_is_not_so_happy(mp);		}		DIRQ(("\nmyri_rx: "));		myri_rx(mp, dev);		DIRQ(("\nistat=ISTAT_HOST "));		lregs->istat = ISTAT_HOST;		dev->interrupt = 0;		DIRQ(("IRQ_ENAB "));		myri_enable_irq(lregs, mp->cregs);	}	DIRQ(("\n"));}static int myri_open(struct device *dev){	struct myri_eth *mp = (struct myri_eth *) dev->priv;	return myri_init(mp, in_interrupt());}static int myri_close(struct device *dev){	struct myri_eth *mp = (struct myri_eth *) dev->priv;	myri_clean_rings(mp);	return 0;}static int myri_start_xmit(struct sk_buff *skb, struct device *dev){	struct myri_eth *mp = (struct myri_eth *) dev->priv;	struct sendq *sq = mp->sq;	struct myri_txd *txd;	unsigned char *srcptr;	unsigned long flags;	unsigned int head, tail;	int len, entry;	DTX(("myri_start_xmit: "));

⌨️ 快捷键说明

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