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

📄 sunbmac.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu) */static char *version =        "sunbmac.c:v1.1 8/Dec/98 David S. Miller (davem@caipfs.rutgers.edu)\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/system.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)#endif#ifdef MODULEstatic struct bigmac *root_bigmac_dev = NULL;#endif#define DEFAULT_JAMSIZE    4 /* Toe jam */#define QEC_RESET_TRIES 200static inline int qec_global_reset(struct qe_globreg *gregs){	int tries = QEC_RESET_TRIES;	gregs->ctrl = GLOB_CTRL_RESET;	while(--tries) {		if(gregs->ctrl & GLOB_CTRL_RESET) {			udelay(20);			continue;		}		break;	}	if(tries)		return 0;	printk("BigMAC: Cannot reset the QEC.\n");	return -1;}static void qec_init(struct bigmac *bp){	struct qe_globreg *gregs = bp->gregs;	struct linux_sbus_device *qec_sdev = bp->qec_sbus_dev;	unsigned char bsizes = bp->bigmac_bursts;	unsigned int 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;	gregs->ctrl = regval | GLOB_CTRL_BMODE;	gregs->psize = GLOB_PSIZE_2048;	/* All of memsize is given to bigmac. */	gregs->msize = qec_sdev->reg_addrs[1].reg_size;	/* Half to the transmitter, half to the receiver. */	gregs->rsize = gregs->tsize = qec_sdev->reg_addrs[1].reg_size >> 1;}/* XXX auto negotiation on these things might not be pleasant... */#define TX_RESET_TRIES     32#define RX_RESET_TRIES     32static inline void bigmac_tx_reset(struct BIG_MAC_regs *bregs){	int tries = TX_RESET_TRIES;	bregs->tx_cfg = 0;	/* The fifo threshold bit is read-only and does	 * not clear.  -DaveM	 */	while((bregs->tx_cfg & ~(BIGMAC_TXCFG_FIFO)) != 0 &&	      --tries != 0)		udelay(20);	if(!tries) {		printk("BIGMAC: Transmitter will not reset.\n");		printk("BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg);	}}static inline void bigmac_rx_reset(struct BIG_MAC_regs *bregs){	int tries = RX_RESET_TRIES;	bregs->rx_cfg = 0;	while((bregs->rx_cfg) && --tries)		udelay(20);	if(!tries) {		printk("BIGMAC: Receiver will not reset.\n");		printk("BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg);	}}/* 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, struct BIG_MAC_regs *bregs){	struct enet_statistics *stats = &bp->enet_stats;	stats->rx_crc_errors += bregs->rcrce_ctr;	bregs->rcrce_ctr = 0;	stats->rx_frame_errors += bregs->unale_ctr;	bregs->unale_ctr = 0;	stats->rx_length_errors += bregs->gle_ctr;	bregs->gle_ctr = 0;	stats->tx_aborted_errors += bregs->ex_ctr;	stats->collisions += (bregs->ex_ctr + bregs->lt_ctr);	bregs->ex_ctr = bregs->lt_ctr = 0;}static inline 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(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(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 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 skippy bufs 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_dvma_addr(skb->data);		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;}#ifndef __sparc_v9__static void sun4c_bigmac_init_rings(struct bigmac *bp){	struct bmac_init_block *bb = bp->bmac_block;	__u32 bbufs_dvma = bp->s4c_buf_dvma;	int i;	bp->rx_new = bp->rx_old = bp->tx_new = bp->tx_old = 0;	for(i = 0; i < RX_RING_SIZE; i++) {		bb->be_rxd[i].rx_addr = bbufs_dvma + bbuf_offset(rx_buf, i);		bb->be_rxd[i].rx_flags =			(RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH));	}	for(i = 0; i < TX_RING_SIZE; i++)		bb->be_txd[i].tx_flags = bb->be_txd[i].tx_addr = 0;}#endif#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 inline void idle_transceiver(struct bmac_tcvr *tregs){	volatile unsigned int garbage;	int i = 20;	while(i--) {		tregs->mgmt_pal = MGMT_CLKOFF;		garbage = tregs->mgmt_pal;		tregs->mgmt_pal = MGMT_CLKON;		garbage = tregs->mgmt_pal;	}}static void write_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs, int bit){	volatile unsigned int garbage;	if(bp->tcvr_type == internal) {		bit = (bit & 1) << 3;		tregs->mgmt_pal = bit | (MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO);		garbage = tregs->mgmt_pal;		tregs->mgmt_pal = bit | (MGMT_PAL_OENAB |					 MGMT_PAL_EXT_MDIO |					 MGMT_PAL_DCLOCK);		garbage = tregs->mgmt_pal;	} else if(bp->tcvr_type == external) {		bit = (bit & 1) << 2;		tregs->mgmt_pal = bit | (MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB);		garbage = tregs->mgmt_pal;		tregs->mgmt_pal = bit | (MGMT_PAL_INT_MDIO |					 MGMT_PAL_OENAB |					 MGMT_PAL_DCLOCK);		garbage = tregs->mgmt_pal;	} else {		printk("write_tcvr_bit: No transceiver type known!\n");	}}static int read_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs){	volatile unsigned int garbage;	int retval = 0;	if(bp->tcvr_type == internal) {		tregs->mgmt_pal = MGMT_PAL_EXT_MDIO;		garbage = tregs->mgmt_pal;		tregs->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK;		garbage = tregs->mgmt_pal;		retval = (tregs->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;	} else if(bp->tcvr_type == external) {		tregs->mgmt_pal = MGMT_PAL_INT_MDIO;		garbage = tregs->mgmt_pal;		tregs->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK;		garbage = tregs->mgmt_pal;		retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;	} else {		printk("read_tcvr_bit: No transceiver type known!\n");	}	return retval;}static int read_tcvr_bit2(struct bigmac *bp, struct bmac_tcvr *tregs){	volatile unsigned int garbage;	int retval = 0;	if(bp->tcvr_type == internal) {		tregs->mgmt_pal = MGMT_PAL_EXT_MDIO;		garbage = tregs->mgmt_pal;		retval = (tregs->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3;		tregs->mgmt_pal = (MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK);		garbage = tregs->mgmt_pal;	} else if(bp->tcvr_type == external) {		tregs->mgmt_pal = MGMT_PAL_INT_MDIO;		garbage = tregs->mgmt_pal;		retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;		tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);		garbage = tregs->mgmt_pal;	} else {		printk("read_tcvr_bit2: No transceiver type known!\n");	}	return retval;}static inline void put_tcvr_byte(struct bigmac *bp,				 struct bmac_tcvr *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, struct bmac_tcvr *tregs,			      int reg, unsigned short val){	int shift;	reg &= 0xff;	val &= 0xffff;	switch(bp->tcvr_type) {	case internal:	case external:		break;	default:		printk("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,				       struct bmac_tcvr *tregs,				       int reg){	unsigned short retval = 0;	reg &= 0xff;	switch(bp->tcvr_type) {	case internal:	case external:		break;	default:		printk("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);			shift -= 1;		} while(shift >= 0);		(void) read_tcvr_bit(bp, tregs);		(void) read_tcvr_bit(bp, tregs);		(void) read_tcvr_bit(bp, tregs);	}	return retval;}static void bigmac_tcvr_init(struct bigmac *bp){	volatile unsigned int garbage;	struct bmac_tcvr *tregs = bp->tregs;	idle_transceiver(tregs);	tregs->mgmt_pal = (MGMT_PAL_INT_MDIO |			   MGMT_PAL_EXT_MDIO |			   MGMT_PAL_DCLOCK);	garbage = tregs->mgmt_pal;	/* Only the bit for the present transceiver (internal or	 * external) will stick, set them both and see what stays.	 */	tregs->mgmt_pal = (MGMT_PAL_INT_MDIO |			   MGMT_PAL_EXT_MDIO);	garbage = tregs->mgmt_pal;	udelay(20);	if(tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) {		bp->tcvr_type = external;		tregs->tcvr_pal = ~(TCVR_PAL_EXTLBACK |				    TCVR_PAL_MSENSE |				    TCVR_PAL_LTENABLE);		garbage = tregs->tcvr_pal;	} else if(tregs->mgmt_pal & MGMT_PAL_INT_MDIO) {		bp->tcvr_type = internal;		tregs->tcvr_pal = ~(TCVR_PAL_SERIAL |				    TCVR_PAL_EXTLBACK |				    TCVR_PAL_MSENSE |				    TCVR_PAL_LTENABLE);		garbage = tregs->tcvr_pal;	} else {		printk("BIGMAC: AIEEE, neither internal nor "		       "external MDIO available!\n");		printk("BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",		       tregs->mgmt_pal, tregs->tcvr_pal);	}}static int bigmac_init(struct bigmac *, int);static int try_next_permutation(struct bigmac *bp, struct bmac_tcvr *tregs){	if(bp->sw_bmcr & BMCR_SPEED100) {		int timeout;		/* Reset the PHY. */		bp->sw_bmcr	= (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK);		bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);		bp->sw_bmcr	= (BMCR_RESET);		bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);		timeout = 64;		while(--timeout) {			bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);			if((bp->sw_bmcr & BMCR_RESET) == 0)				break;

⌨️ 快捷键说明

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