📄 bagetlance.c
字号:
/* $Id$ * bagetlance.c: Ethernet driver for VME Lance cards on Baget/MIPS * This code stealed and adopted from linux/drivers/net/atarilance.c * See that for author info * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov *//* * Driver code for Baget/Lance taken from atarilance.c, which also * works well in case of Besta. Most significant changes made here * related with 16BIT-only access to A24 space. */static char *version = "bagetlance.c: v1.1 11/10/98\n";#include <linux/module.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/baget/baget.h>#define BAGET_LANCE_IRQ BAGET_IRQ_MASK(0xdf)/* * Define following if you don't need 16BIT-only access to Lance memory * (Normally BAGET needs it) */#undef NORMAL_MEM_ACCESS /* Debug level: * 0 = silent, print only serious errors * 1 = normal, print error messages * 2 = debug, print debug infos * 3 = debug, print even more debug infos (packet data) */#define LANCE_DEBUG 1 #ifdef LANCE_DEBUGstatic int lance_debug = LANCE_DEBUG;#elsestatic int lance_debug = 1;#endifMODULE_PARM(lance_debug, "i");MODULE_PARM_DESC(lance_debug, "Lance debug level (0-3)");MODULE_LICENSE("GPL");/* Print debug messages on probing? */#undef LANCE_DEBUG_PROBE#define DPRINTK(n,a) \ do { \ if (lance_debug >= n) \ printk a; \ } while( 0 )#ifdef LANCE_DEBUG_PROBE# define PROBE_PRINT(a) printk a#else# define PROBE_PRINT(a)#endif/* These define the number of Rx and Tx buffers as log2. (Only powers * of two are valid) * Much more rx buffers (32) are reserved than tx buffers (8), since receiving * is more time critical then sending and packets may have to remain in the * board's memory when main memory is low. *//* Baget Lance has 64K on-board memory, so it looks we can't increase buffer quantity (40*1.5K is about 64K) */#define TX_LOG_RING_SIZE 3#define RX_LOG_RING_SIZE 5/* These are the derived values */#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE)#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5)#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE)#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5)#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)/* The LANCE Rx and Tx ring descriptors. */struct lance_rx_head { volatile unsigned short base; /* Low word of base addr */#ifdef NORMAL_MEM_ACCESS /* Following two fields are joined into one short to guarantee 16BIT access to Baget lance registers */ volatile unsigned char flag; unsigned char base_hi; /* High word of base addr (unused) */#else/* Following macros are used as replecements to 8BIT fields */#define GET_FLAG(h) (((h)->flag_base_hi >> 8) & 0xff)#define SET_FLAG(h,f) (h)->flag_base_hi = ((h)->flag_base_hi & 0xff) | \ (((unsigned)(f)) << 8) volatile unsigned short flag_base_hi; #endif volatile short buf_length; /* This length is 2s complement! */ volatile short msg_length; /* This length is "normal". */};struct lance_tx_head { volatile unsigned short base; /* Low word of base addr */#ifdef NORMAL_MEM_ACCESS /* See comments above about 8BIT-access Baget A24-space problems */ volatile unsigned char flag; unsigned char base_hi; /* High word of base addr (unused) */#else volatile unsigned short flag_base_hi;#endif volatile short length; /* Length is 2s complement! */ volatile short misc;};struct ringdesc { volatile unsigned short adr_lo; /* Low 16 bits of address */#ifdef NORMAL_MEM_ACCESS /* See comments above about 8BIT-access Bage A24-space problems */ unsigned char len; /* Length bits */ unsigned char adr_hi; /* High 8 bits of address (unused) */#else volatile unsigned short len_adr_hi;#endif};/* The LANCE initialization block, described in databook. */struct lance_init_block { unsigned short mode; /* Pre-set mode */ unsigned char hwaddr[6]; /* Physical ethernet address */ unsigned filter[2]; /* Multicast filter (unused). */ /* Receive and transmit ring base, along with length bits. */ struct ringdesc rx_ring; struct ringdesc tx_ring;};/* The whole layout of the Lance shared memory */struct lance_memory { struct lance_init_block init; struct lance_tx_head tx_head[TX_RING_SIZE]; struct lance_rx_head rx_head[RX_RING_SIZE]; char packet_area[0]; /* packet data follow after the * init block and the ring * descriptors and are located * at runtime */};/* RieblCard specifics: * The original TOS driver for these cards reserves the area from offset * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the * Ethernet address there, and the magic for verifying the data's validity. * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe * is reserved for the interrupt vector number. */#define RIEBL_RSVD_START 0xee70#define RIEBL_RSVD_END 0xeec0#define RIEBL_MAGIC 0x09051990#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a))#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e))#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe))/* This is a default address for the old RieblCards without a battery * that have no ethernet address at boot time. 00:00:36:04 is the * prefix for Riebl cards, the 00:00 at the end is arbitrary. */static unsigned char OldRieblDefHwaddr[6] = { 0x00, 0x00, 0x36, 0x04, 0x00, 0x00};/* I/O registers of the Lance chip */struct lance_ioreg {/* base+0x0 */ volatile unsigned short data;/* base+0x2 */ volatile unsigned short addr; unsigned char _dummy1[3];/* base+0x7 */ volatile unsigned char ivec; unsigned char _dummy2[5];/* base+0xd */ volatile unsigned char eeprom; unsigned char _dummy3;/* base+0xf */ volatile unsigned char mem;};/* Types of boards this driver supports */enum lance_type { OLD_RIEBL, /* old Riebl card without battery */ NEW_RIEBL, /* new Riebl card with battery */ PAM_CARD /* PAM card with EEPROM */};static char *lance_names[] = { "Riebl-Card (without battery)", "Riebl-Card (with battery)", "PAM intern card"};/* The driver's private device structure */struct lance_private { enum lance_type cardtype; struct lance_ioreg *iobase; struct lance_memory *mem; int cur_rx, cur_tx; /* The next free ring entry */ int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, const void *, size_t ); struct net_device_stats stats;/* These two must be longs for set_bit() */ long tx_full; long lock;};/* I/O register access macros */#define MEM lp->mem#define DREG IO->data#define AREG IO->addr#define REGA(a) ( AREG = (a), DREG )/* Definitions for packet buffer access: */#define PKT_BUF_SZ 1544/* Get the address of a packet buffer corresponding to a given buffer head */#define PKTBUF_ADDR(head) (((unsigned char *)(MEM)) + (head)->base)/* Possible memory/IO addresses for probing */struct lance_addr { unsigned long memaddr; unsigned long ioaddr; int slow_flag;} lance_addr_list[] = { { BAGET_LANCE_MEM_BASE, BAGET_LANCE_IO_BASE, 1 } /* Baget Lance */};#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))#define LANCE_HI_BASE (0xff & (BAGET_LANCE_MEM_BASE >> 16))/* Definitions for the Lance *//* tx_head flags */#define TMD1_ENP 0x01 /* end of packet */#define TMD1_STP 0x02 /* start of packet */#define TMD1_DEF 0x04 /* deferred */#define TMD1_ONE 0x08 /* one retry needed */#define TMD1_MORE 0x10 /* more than one retry needed */#define TMD1_ERR 0x40 /* error summary */#define TMD1_OWN 0x80 /* ownership (set: chip owns) */#define TMD1_OWN_CHIP TMD1_OWN#define TMD1_OWN_HOST 0/* tx_head misc field */#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */#define TMD3_RTRY 0x0400 /* failed after 16 retries */#define TMD3_LCAR 0x0800 /* carrier lost */#define TMD3_LCOL 0x1000 /* late collision */#define TMD3_UFLO 0x4000 /* underflow (late memory) */#define TMD3_BUFF 0x8000 /* buffering error (no ENP) *//* rx_head flags */#define RMD1_ENP 0x01 /* end of packet */#define RMD1_STP 0x02 /* start of packet */#define RMD1_BUFF 0x04 /* buffer error */#define RMD1_CRC 0x08 /* CRC error */#define RMD1_OFLO 0x10 /* overflow */#define RMD1_FRAM 0x20 /* framing error */#define RMD1_ERR 0x40 /* error summary */#define RMD1_OWN 0x80 /* ownership (set: ship owns) */#define RMD1_OWN_CHIP RMD1_OWN#define RMD1_OWN_HOST 0/* register names */#define CSR0 0 /* mode/status */#define CSR1 1 /* init block addr (low) */#define CSR2 2 /* init block addr (high) */#define CSR3 3 /* misc */#define CSR8 8 /* address filter */#define CSR15 15 /* promiscuous mode *//* CSR0 *//* (R=readable, W=writeable, S=set on write, C=clear on write) */#define CSR0_INIT 0x0001 /* initialize (RS) */#define CSR0_STRT 0x0002 /* start (RS) */#define CSR0_STOP 0x0004 /* stop (RS) */#define CSR0_TDMD 0x0008 /* transmit demand (RS) */#define CSR0_TXON 0x0010 /* transmitter on (R) */#define CSR0_RXON 0x0020 /* receiver on (R) */#define CSR0_INEA 0x0040 /* interrupt enable (RW) */#define CSR0_INTR 0x0080 /* interrupt active (R) */#define CSR0_IDON 0x0100 /* initialization done (RC) */#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */#define CSR0_MERR 0x0800 /* memory error (RC) */#define CSR0_MISS 0x1000 /* missed frame (RC) */#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */#define CSR0_ERR 0x8000 /* error (RC) *//* CSR3 */#define CSR3_BCON 0x0001 /* byte control */#define CSR3_ACON 0 // fixme: 0x0002 /* ALE control */#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) *//***************************** Prototypes *****************************/static int addr_accessible( volatile void *regp, int wordflag, int writeflag );static int lance_probe1( struct net_device *dev, struct lance_addr *init_rec );static int lance_open( struct net_device *dev );static void lance_init_ring( struct net_device *dev );static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );static int lance_rx( struct net_device *dev );static int lance_close( struct net_device *dev );static struct net_device_stats *lance_get_stats( struct net_device *dev );static void set_multicast_list( struct net_device *dev );static int lance_set_mac_address( struct net_device *dev, void *addr );/************************* End of Prototypes **************************//* Network traffic statistic (bytes) */int lance_stat = 0;static void update_lance_stat (int len) { lance_stat += len;}/* This function is used to access Baget/Lance memory to avoid 8/32BIT access to VAC A24 space ALL memcpy calls was chenged to this function to avoid dbe problems Don't confuse with function name -- it stays from original code*/void *slow_memcpy( void *dst, const void *src, size_t len ){ unsigned long to = (unsigned long)dst; unsigned long from = (unsigned long)src; unsigned long to_end = to +len; /* Unaligned flags */ int odd_from = from & 1; int odd_to = to & 1; int odd_to_end = to_end & 1; /* Align for 16BIT-access first */ register unsigned short *from_a = (unsigned short*) (from & ~1); register unsigned short *to_a = (unsigned short*) (to & ~1); register unsigned short *to_end_a = (unsigned short*) (to_end & ~1); /* Caching values -- not in loop invariant */ register unsigned short from_v; register unsigned short to_v; /* Invariant is: from_a and to_a are pointers before or exactly to currently copying byte */ if (odd_to) { /* First byte unaligned case */ from_v = *from_a; to_v = *to_a; to_v &= ~0xff; to_v |= 0xff & (from_v >> (odd_from ? 0 : 8)); *to_a++ = to_v; if (odd_from) from_a++; } if (odd_from == odd_to) { /* Same parity */ while (to_a + 7 < to_end_a) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; __asm__ __volatile__( ".set\tnoreorder\n\t" ".set\tnoat\n\t" "lh\t%2,0(%1)\n\t" "nop\n\t" "lh\t%3,2(%1)\n\t" "sh\t%2,0(%0)\n\t" "lh\t%4,4(%1)\n\t" "sh\t%3,2(%0)\n\t" "lh\t%5,6(%1)\n\t" "sh\t%4,4(%0)\n\t" "lh\t%2,8(%1)\n\t" "sh\t%5,6(%0)\n\t" "lh\t%3,10(%1)\n\t" "sh\t%2,8(%0)\n\t" "lh\t%4,12(%1)\n\t" "sh\t%3,10(%0)\n\t" "lh\t%5,14(%1)\n\t" "sh\t%4,12(%0)\n\t" "nop\n\t" "sh\t%5,14(%0)\n\t" ".set\tat\n\t" ".set\treorder" :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) :"0" (to_a), "1" (from_a) :"memory"); to_a += 8; from_a += 8; } while (to_a < to_end_a) { *to_a++ = *from_a++; } } else { /* Different parity */ from_v = *from_a; while (to_a < to_end_a) { unsigned short from_v_next; from_v_next = *++from_a; *to_a++ = ((from_v & 0xff)<<8) | ((from_v_next>>8) & 0xff); from_v = from_v_next; } } if (odd_to_end) { /* Last byte unaligned case */ to_v = *to_a;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -