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

📄 myri_sbus.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* myri_sbus.h: MyriCOM MyriNET SBUS card driver. * * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) */static char *version =        "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\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 void myri_reset_off(unsigned long lp, unsigned long cregs){	/* Clear IRQ mask. */	sbus_writel(0, lp + LANAI_EIMASK);	/* Turn RESET function off. */	sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL);}static void myri_reset_on(unsigned long cregs){	/* Enable RESET function. */	sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL);	/* Disable IRQ's. */	sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);}static void myri_disable_irq(unsigned long lp, unsigned long cregs){	sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);	sbus_writel(0, lp + LANAI_EIMASK);	sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT);}static void myri_enable_irq(unsigned long lp, unsigned long cregs){	sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL);	sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK);}static inline void bang_the_chip(struct myri_eth *mp){	struct myri_shmem *shmem	= mp->shmem;	unsigned long cregs		= mp->cregs;	sbus_writel(1, &shmem->send);	sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);}static int myri_do_handshake(struct myri_eth *mp){	struct myri_shmem *shmem	= mp->shmem;	unsigned long cregs = mp->cregs;	struct myri_channel *chan	= &shmem->channel;	int tick 			= 0;	DET(("myri_do_handshake: "));	if (sbus_readl(&chan->state) == STATE_READY) {		DET(("Already STATE_READY, failed.\n"));		return -1;	/* We're hosed... */	}	myri_disable_irq(mp->lregs, cregs);	while (tick++ <= 25) {		u32 softstate;		/* Wake it up. */		DET(("shakedown, CONTROL_WON, "));		sbus_writel(1, &shmem->shakedown);		sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);		softstate = sbus_readl(&chan->state);		DET(("chanstate[%08x] ", softstate));		if (softstate == STATE_READY) {			DET(("wakeup successful, "));			break;		}		if (softstate != STATE_WFN) {			DET(("not WFN setting that, "));			sbus_writel(STATE_WFN, &chan->state);		}		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 int myri_load_lanai(struct myri_eth *mp){	struct net_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++)		sbus_writeb(0, &rptr[i]);	if (mp->eeprom.cpuvers >= CPUVERS_3_0)		sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL);	/* Load executable code. */	for (i = 0; i < sizeof(lanai4_code); i++)		sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]);	/* Load data segment. */	for (i = 0; i < sizeof(lanai4_data); i++)		sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]);	/* Set device address. */	sbus_writeb(0, &shmem->addr[0]);	sbus_writeb(0, &shmem->addr[1]);	for (i = 0; i < 6; i++)		sbus_writeb(dev->dev_addr[i],			    &shmem->addr[i + 2]);	/* Set SBUS bursts and interrupt mask. */	sbus_writel(((mp->myri_bursts & 0xf8) >> 3), &shmem->burst);	sbus_writel(SHMEM_IMASK_RX, &shmem->imask);	/* 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 (sbus_readl(&shmem->channel.state) != STATE_READY)			break;		else			udelay(10);	}	if (i == 5000)		printk(KERN_ERR "myricom: Chip would not reset after firmware load.\n");	i = myri_do_handshake(mp);	if (i)		printk(KERN_ERR "myricom: Handshake with LANAI failed.\n");	if (mp->eeprom.cpuvers == CPUVERS_4_0)		sbus_writel(0, mp->lregs + LANAI_VERS);	return i;}static void myri_clean_rings(struct myri_eth *mp){	struct sendq *sq = mp->sq;	struct recvq *rq = mp->rq;	int i;	sbus_writel(0, &rq->tail);	sbus_writel(0, &rq->head);	for (i = 0; i < (RX_RING_SIZE+1); i++) {		if (mp->rx_skbs[i] != NULL) {			struct myri_rxd *rxd = &rq->myri_rxd[i];			u32 dma_addr;			dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);			sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);			dev_kfree_skb(mp->rx_skbs[i]);			mp->rx_skbs[i] = NULL;		}	}	mp->tx_old = 0;	sbus_writel(0, &sq->tail);	sbus_writel(0, &sq->head);	for (i = 0; i < TX_RING_SIZE; i++) {		if (mp->tx_skbs[i] != NULL) {			struct sk_buff *skb = mp->tx_skbs[i];			struct myri_txd *txd = &sq->myri_txd[i];			u32 dma_addr;			dma_addr = sbus_readl(&txd->myri_gathers[0].addr);			sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);			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 net_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);		u32 dma_addr;		if (!skb)			continue;		mp->rx_skbs[i] = skb;		skb->dev = dev;		skb_put(skb, RX_ALLOC_SIZE);		dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);		sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);		sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);		sbus_writel(i, &rxd[i].ctx);		sbus_writel(1, &rxd[i].num_sg);	}	sbus_writel(0, &rq->head);	sbus_writel(RX_RING_SIZE, &rq->tail);}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 void myri_tx(struct myri_eth *mp, struct net_device *dev){	struct sendq *sq	= mp->sq;	int entry		= mp->tx_old;	int limit		= sbus_readl(&sq->head);	DTX(("entry[%d] limit[%d] ", entry, limit));	if (entry == limit)		return;	while (entry != limit) {		struct sk_buff *skb = mp->tx_skbs[entry];		u32 dma_addr;		DTX(("SKB[%d] ", entry));		dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);		sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);		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 net_device *dev){	struct ethhdr *eth;	unsigned char *rawp;	

⌨️ 快捷键说明

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