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

📄 sunbmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: sunbmac.c,v 1.21 2000/10/22 16:08:38 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) */static char *version =        "sunbmac.c:v1.9 11/Sep/99 David S. Miller (davem@redhat.com)\n";#include <linux/module.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 <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include "sunbmac.h"#undef DEBUG_PROBE#undef DEBUG_TX#undef DEBUG_IRQ#ifdef DEBUG_PROBE#define DP(x)  printk x#else#define DP(x)#endif#ifdef DEBUG_TX#define DTX(x)  printk x#else#define DTX(x)#endif#ifdef DEBUG_IRQ#define DIRQ(x)  printk x#else#define DIRQ(x)#endifstatic struct bigmac *root_bigmac_dev = NULL;#define DEFAULT_JAMSIZE    4 /* Toe jam */#define QEC_RESET_TRIES 200static int qec_global_reset(unsigned long gregs){	int tries = QEC_RESET_TRIES;	sbus_writel(GLOB_CTRL_RESET, gregs + GLOB_CTRL);	while (--tries) {		if (sbus_readl(gregs + GLOB_CTRL) & GLOB_CTRL_RESET) {			udelay(20);			continue;		}		break;	}	if (tries)		return 0;	printk(KERN_ERR "BigMAC: Cannot reset the QEC.\n");	return -1;}static void qec_init(struct bigmac *bp){	unsigned long gregs = bp->gregs;	struct sbus_dev *qec_sdev = bp->qec_sdev;	u8 bsizes = bp->bigmac_bursts;	u32 regval;	/* 64byte bursts do not work at the moment, do	 * not even try to enable them.  -DaveM	 */	if (bsizes & DMA_BURST32)		regval = GLOB_CTRL_B32;	else		regval = GLOB_CTRL_B16;	sbus_writel(regval | GLOB_CTRL_BMODE, gregs + GLOB_CTRL);	sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);	/* All of memsize is given to bigmac. */	sbus_writel(qec_sdev->reg_addrs[1].reg_size,		    gregs + GLOB_MSIZE);	/* Half to the transmitter, half to the receiver. */	sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,		    gregs + GLOB_TSIZE);	sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,		    gregs + GLOB_RSIZE);}#define TX_RESET_TRIES     32#define RX_RESET_TRIES     32static void bigmac_tx_reset(unsigned long bregs){	int tries = TX_RESET_TRIES;	sbus_writel(0, bregs + BMAC_TXCFG);	/* The fifo threshold bit is read-only and does	 * not clear.  -DaveM	 */	while ((sbus_readl(bregs + BMAC_TXCFG) & ~(BIGMAC_TXCFG_FIFO)) != 0 &&	       --tries != 0)		udelay(20);	if (!tries) {		printk(KERN_ERR "BIGMAC: Transmitter will not reset.\n");		printk(KERN_ERR "BIGMAC: tx_cfg is %08x\n",		       sbus_readl(bregs + BMAC_TXCFG));	}}static void bigmac_rx_reset(unsigned long bregs){	int tries = RX_RESET_TRIES;	sbus_writel(0, bregs + BMAC_RXCFG);	while (sbus_readl(bregs + BMAC_RXCFG) && --tries)		udelay(20);	if (!tries) {		printk(KERN_ERR "BIGMAC: Receiver will not reset.\n");		printk(KERN_ERR "BIGMAC: rx_cfg is %08x\n",		       sbus_readl(bregs + BMAC_RXCFG));	}}/* Reset the transmitter and receiver. */static void bigmac_stop(struct bigmac *bp){	bigmac_tx_reset(bp->bregs);	bigmac_rx_reset(bp->bregs);}static void bigmac_get_counters(struct bigmac *bp, unsigned long bregs){	struct net_device_stats *stats = &bp->enet_stats;	stats->rx_crc_errors += sbus_readl(bregs + BMAC_RCRCECTR);	sbus_writel(0, bregs + BMAC_RCRCECTR);	stats->rx_frame_errors += sbus_readl(bregs + BMAC_UNALECTR);	sbus_writel(0, bregs + BMAC_UNALECTR);	stats->rx_length_errors += sbus_readl(bregs + BMAC_GLECTR);	sbus_writel(0, bregs + BMAC_GLECTR);	stats->tx_aborted_errors += sbus_readl(bregs + BMAC_EXCTR);	stats->collisions +=		(sbus_readl(bregs + BMAC_EXCTR) +		 sbus_readl(bregs + BMAC_LTCTR));	sbus_writel(0, bregs + BMAC_EXCTR);	sbus_writel(0, bregs + BMAC_LTCTR);}static void bigmac_clean_rings(struct bigmac *bp){	int i;	for (i = 0; i < RX_RING_SIZE; i++) {		if (bp->rx_skbs[i] != NULL) {			dev_kfree_skb_any(bp->rx_skbs[i]);			bp->rx_skbs[i] = NULL;		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (bp->tx_skbs[i] != NULL) {			dev_kfree_skb_any(bp->tx_skbs[i]);			bp->tx_skbs[i] = NULL;		}	}}static void bigmac_init_rings(struct bigmac *bp, int from_irq){	struct bmac_init_block *bb = bp->bmac_block;	struct net_device *dev = bp->dev;	int i, gfp_flags = GFP_KERNEL;	if (from_irq || in_interrupt())		gfp_flags = GFP_ATOMIC;	bp->rx_new = bp->rx_old = bp->tx_new = bp->tx_old = 0;	/* Free any skippy bufs left around in the rings. */	bigmac_clean_rings(bp);	/* Now get new skbufs for the receive ring. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb;		skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);		if (!skb)			continue;		bp->rx_skbs[i] = skb;		skb->dev = dev;		/* Because we reserve afterwards. */		skb_put(skb, ETH_FRAME_LEN);		skb_reserve(skb, 34);		bb->be_rxd[i].rx_addr =			sbus_map_single(bp->bigmac_sdev, skb->data,					RX_BUF_ALLOC_SIZE - 34,					SBUS_DMA_FROMDEVICE);		bb->be_rxd[i].rx_flags =			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));	}	for (i = 0; i < TX_RING_SIZE; i++)		bb->be_txd[i].tx_flags = bb->be_txd[i].tx_addr = 0;}#define MGMT_CLKON  (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB|MGMT_PAL_DCLOCK)#define MGMT_CLKOFF (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB)static void idle_transceiver(unsigned long tregs){	int i = 20;	while (i--) {		sbus_writel(MGMT_CLKOFF, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		sbus_writel(MGMT_CLKON, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);	}}static void write_tcvr_bit(struct bigmac *bp, unsigned long tregs, int bit){	if (bp->tcvr_type == internal) {		bit = (bit & 1) << 3;		sbus_writel(bit | (MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO),			    tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		sbus_writel(bit | MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK,			    tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);	} else if (bp->tcvr_type == external) {		bit = (bit & 1) << 2;		sbus_writel(bit | MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB,			    tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		sbus_writel(bit | MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB | MGMT_PAL_DCLOCK,			    tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);	} else {		printk(KERN_ERR "write_tcvr_bit: No transceiver type known!\n");	}}static int read_tcvr_bit(struct bigmac *bp, unsigned long tregs){	int retval = 0;	if (bp->tcvr_type == internal) {		sbus_writel(MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		sbus_writel(MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK,			    tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_INT_MDIO) >> 3;	} else if (bp->tcvr_type == external) {		sbus_writel(MGMT_PAL_INT_MDIO, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_EXT_MDIO) >> 2;	} else {		printk(KERN_ERR "read_tcvr_bit: No transceiver type known!\n");	}	return retval;}static int read_tcvr_bit2(struct bigmac *bp, unsigned long tregs){	int retval = 0;	if (bp->tcvr_type == internal) {		sbus_writel(MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_INT_MDIO) >> 3;		sbus_writel(MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);	} else if (bp->tcvr_type == external) {		sbus_writel(MGMT_PAL_INT_MDIO, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);		retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_EXT_MDIO) >> 2;		sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL);		sbus_readl(tregs + TCVR_MPAL);	} else {		printk(KERN_ERR "read_tcvr_bit2: No transceiver type known!\n");	}	return retval;}static void put_tcvr_byte(struct bigmac *bp,			  unsigned long tregs,			  unsigned int byte){	int shift = 4;	do {		write_tcvr_bit(bp, tregs, ((byte >> shift) & 1));		shift -= 1;	} while (shift >= 0);}static void bigmac_tcvr_write(struct bigmac *bp, unsigned long tregs,			      int reg, unsigned short val){	int shift;	reg &= 0xff;	val &= 0xffff;	switch(bp->tcvr_type) {	case internal:	case external:		break;	default:		printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");		return;	};	idle_transceiver(tregs);	write_tcvr_bit(bp, tregs, 0);	write_tcvr_bit(bp, tregs, 1);	write_tcvr_bit(bp, tregs, 0);	write_tcvr_bit(bp, tregs, 1);	put_tcvr_byte(bp, tregs,		      ((bp->tcvr_type == internal) ?		       BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL));	put_tcvr_byte(bp, tregs, reg);	write_tcvr_bit(bp, tregs, 1);	write_tcvr_bit(bp, tregs, 0);	shift = 15;	do {		write_tcvr_bit(bp, tregs, (val >> shift) & 1);		shift -= 1;	} while (shift >= 0);}static unsigned short bigmac_tcvr_read(struct bigmac *bp,				       unsigned long tregs,				       int reg){	unsigned short retval = 0;	reg &= 0xff;	switch(bp->tcvr_type) {	case internal:	case external:		break;	default:		printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");		return 0xffff;	};	idle_transceiver(tregs);	write_tcvr_bit(bp, tregs, 0);	write_tcvr_bit(bp, tregs, 1);	write_tcvr_bit(bp, tregs, 1);	write_tcvr_bit(bp, tregs, 0);	put_tcvr_byte(bp, tregs,		      ((bp->tcvr_type == internal) ?		       BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL));	put_tcvr_byte(bp, tregs, reg);	if (bp->tcvr_type == external) {		int shift = 15;		(void) read_tcvr_bit2(bp, tregs);		(void) read_tcvr_bit2(bp, tregs);		do {			int tmp;			tmp = read_tcvr_bit2(bp, tregs);			retval |= ((tmp & 1) << shift);			shift -= 1;		} while (shift >= 0);		(void) read_tcvr_bit2(bp, tregs);		(void) read_tcvr_bit2(bp, tregs);		(void) read_tcvr_bit2(bp, tregs);	} else {		int shift = 15;		(void) read_tcvr_bit(bp, tregs);		(void) read_tcvr_bit(bp, tregs);		do {			int tmp;			tmp = read_tcvr_bit(bp, tregs);			retval |= ((tmp & 1) << shift);

⌨️ 快捷键说明

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