OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [net/] [open_eth.c] - Rev 1765

Compare with Previous | Blame | View Log

/*
 * Ethernet driver for Open Ethernet Controller (www.opencores.org).
 *      Copyright (c) 2002 Simon Srot (simons@opencores.org)
 *
 * Based on:
 *
 * Ethernet driver for Motorola MPC8xx.
 *      Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
 *
 * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
 *
 *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
 *
 * Rigt now XXBUFF_PREALLOC must be used, bacause MAC does not 
 * handle unaligned buffers yet.  Also the cache inhibit calls
 * should be used some day.
 *
 */
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
 
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/bitops.h>
#include <asm/board.h>
 
#include "open_eth.h"
 
#define net_device device
#define __pa(x) (x)
#define __va(x) (x)
#define __clear_user(add,len) memset((add),0,(len))
 
#define DEBUG 1
 
#define RXBUFF_PREALLOC	1
#define TXBUFF_PREALLOC	1
 
//#define SRAM_BUFF	1
//#define SRAM_BUFF_BASE	(FBMEM_BASE_ADD + 0x80000)
 
/* The transmitter timeout
 */
#define TX_TIMEOUT	(2*HZ)
 
/* Buffer number (must be 2^n) 
 */
#define OETH_RXBD_NUM		8
#define OETH_TXBD_NUM		8
#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
 
/* Buffer size 
 */
#define OETH_RX_BUFF_SIZE	2048
#define OETH_TX_BUFF_SIZE	2048
 
/* How many buffers per page 
 */
#define OETH_RX_BUFF_PPGAE	(PAGE_SIZE/OETH_RX_BUFF_SIZE)
#define OETH_TX_BUFF_PPGAE	(PAGE_SIZE/OETH_TX_BUFF_SIZE)
 
/* How many pages is needed for buffers 
 */
#define OETH_RX_BUFF_PAGE_NUM	(OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
#define OETH_TX_BUFF_PAGE_NUM	(OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
 
/* Buffer size  (if not XXBUF_PREALLOC 
 */
#define MAX_FRAME_SIZE		1518
 
/* The buffer descriptors track the ring buffers.   
 */
struct oeth_private {
	struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
	struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
 
	ushort	tx_next;			/* Next buffer to be sent */
	ushort	tx_last;			/* Next buffer to be checked if packet sent */
	ushort	tx_full;			/* Buffer ring fuul indicator */
	ushort	rx_cur;				/* Next buffer to be checked if packet received */
 
	oeth_regs	*regs;			/* Address of controller registers. */
	oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
	oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
 
	struct enet_statistics stats;
};
 
static int oeth_open(struct net_device *dev);
static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void oeth_rx(struct net_device *dev);
static void oeth_tx(struct net_device *dev);
static void oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int oeth_close(struct net_device *dev);
static struct enet_statistics *oeth_get_stats(struct net_device *dev);
static void oeth_set_multicast_list(struct net_device *dev);
static void oeth_set_mac_add(struct device *dev, void *addr);
static int calc_crc(char *mac_addr);
 
/* __PHX__ fixme for more ehternet drivers */
#ifdef CONFIG_OETH_UNKNOWN_TX_NEXT
static int tx_next = -1;
#endif
 
#if DEBUG
static void
oeth_print_packet(unsigned long add, int len)
{
	int i;
 
	_print("ipacket: add = %x len = %d\n", add, len);
	for(i = 0; i < len; i++) {
  		if(!(i % 16))
    			_print("\n");
  		_print(" %.2x", *(((unsigned char *)add) + i));
	}
	_print("\n");
}
#endif
 
static int
oeth_open(struct net_device *dev)
{
 
	oeth_regs *regs = (oeth_regs *)dev->base_addr;
 
	struct oeth_private *cep = (struct oeth_private *)dev->priv;
#ifdef CONFIG_OETH_UNKNOWN_TX_NEXT
        if (tx_next != -1) {
                cep->tx_next = tx_next;
        }
#endif
 
#ifndef RXBUFF_PREALLOC
	struct  sk_buff *skb;
	volatile oeth_bd *rx_bd;
	int i;
 
	rx_bd = cep->rx_bd_base;
 
	for(i = 0; i < OETH_RXBD_NUM; i++) {
 
		skb = dev_alloc_skb(MAX_FRAME_SIZE);
 
		if (skb == NULL)
			rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
		else
			rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
 
		cep->rx_skbuff[i] = skb;
 
		rx_bd[i].addr = (unsigned long)skb->tail;
	}
	rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
#endif
 
	/* Install our interrupt handler.
	 */
	request_irq(IRQ_ETH_0, oeth_interrupt, 0, "eth", (void *)dev);
 
	/* Enable receiver and transmiter 
	 */
	regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
 
	return 0;
}
 
static int
oeth_close(struct net_device *dev)
{
	struct oeth_private *cep = (struct oeth_private *)dev->priv;
	oeth_regs *regs = (oeth_regs *)dev->base_addr;
	volatile oeth_bd *bdp;
	int i;
 
	/* Free interrupt hadler 
	 */
	free_irq(IRQ_ETH_0, (void *)dev);
 
	/* Disable receiver and transmitesr 
	 */
	regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);	
 
	bdp = cep->rx_bd_base;
	for (i = 0; i < OETH_RXBD_NUM; i++) {
		bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
		bdp++;
	}
 
	bdp = cep->tx_bd_base;
	for (i = 0; i < OETH_TXBD_NUM; i++) {
		bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
		bdp++;
	}
 
#ifndef RXBUFF_PREALLOC
 
	/* Free all alocated rx buffers 
	 */
	for (i = 0; i < OETH_RXBD_NUM; i++) {
 
		if (cep->rx_skbuff[i] != NULL)
			dev_kfree_skb(cep->rx_skbuff[i], FREE_READ);
 
	}
#endif
#ifndef TXBUFF_PREALLOC
 
	/* Free all alocated tx buffers 
	 */
	for (i = 0; i < OETH_TXBD_NUM; i++) {
 
		if (cep->tx_skbuff[i] != NULL)
			dev_kfree_skb(cep->tx_skbuff[i], FREE_WRITE);
	}
#endif
 
#ifdef CONFIG_OETH_UNKNOWN_TX_NEXT      
        tx_next = cep->tx_next;
#endif
	return 0;
}
 
static int
oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct oeth_private *cep = (struct oeth_private *)dev->priv;
	volatile oeth_bd *bdp;
	unsigned long flags;
 
	/* Fill in a Tx ring entry 
	 */
	bdp = cep->tx_bd_base + cep->tx_next;
 
	if (cep->tx_full) {
 
		/* All transmit buffers are full.  Bail out.
		 */
		printk("%s: tx queue full!.\n", dev->name);
		return 1;
	}
 
	/* Clear all of the status flags.
	 */
	bdp->len_status &= ~OETH_TX_BD_STATS;
 
	/* If the frame is short, tell CPM to pad it.
	 */
	if (skb->len <= ETH_ZLEN)
		bdp->len_status |= OETH_TX_BD_PAD;
	else
		bdp->len_status &= ~OETH_TX_BD_PAD;
 
#if DEBUG
	_print("TX\n");
	oeth_print_packet(skb->data, skb->len);
#endif
 
#ifdef TXBUFF_PREALLOC
 
	/* Copy data in preallocated buffer */
	if (skb->len > OETH_TX_BUFF_SIZE) {
		printk("%s: tx frame too long!.\n", dev->name);
		return 1;
	}
	else
		memcpy((unsigned char *)bdp->addr, skb->data, skb->len);
 
	bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
 
	dev_kfree_skb(skb, FREE_WRITE);
#else
	/* Set buffer length and buffer pointer.
	 */
	bdp->len_status = (bdp->len_status & 0x0000ffff) | (skb->len << 16);
	bdp->addr = (uint)__pa(skb->data);
 
	/* Save skb pointer.
	 */
	cep->tx_skbuff[cep->tx_next] = skb;
#endif
 
	cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK;
 
	save_flags(flags); cli();
 
	if (cep->tx_next == cep->tx_last)
		cep->tx_full = 1;
 
	/* Send it on its way.  Tell controller its ready, interrupt when done,
	 * and to put the CRC on the end.
	 */
	bdp->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
 
	dev->trans_start = jiffies;
 
	restore_flags(flags);
 
	return 0;
}
 
/* The interrupt handler.
 */
static void
oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct	net_device *dev = dev_id;
	volatile struct	oeth_private *cep;
	uint	int_events;
 
	cep = (struct oeth_private *)dev->priv;
 
	/* Get the interrupt events that caused us to be here.
	 */
	int_events = cep->regs->int_src;
	cep->regs->int_src = int_events;
 
	/* Handle receive event in its own function.
	 */
	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
		oeth_rx(dev_id);
 
	/* Handle transmit event in its own function.
	 */
	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
		oeth_tx(dev_id);
	    	mark_bh(NET_BH);
	}
 
	/* Check for receive busy, i.e. packets coming but no place to
	 * put them. 
	 */
	if (int_events & OETH_INT_BUSY) {
		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
			oeth_rx(dev_id);
	}
 
	return;
}
 
 
static void
oeth_tx(struct net_device *dev)
{
	struct	oeth_private *cep;
	volatile oeth_bd *bdp;
 
#ifndef TXBUFF_PREALLOC
	struct	sk_buff *skb;
#endif
 
	cep = (struct oeth_private *)dev->priv;
 
	for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) {
 
		bdp = cep->tx_bd_base + cep->tx_last;
 
		if ((bdp->len_status & OETH_TX_BD_READY) || 
			((cep->tx_last == cep->tx_next) && !cep->tx_full))
			break;
 
		/* Check status for errors
		 */
		if (bdp->len_status & OETH_TX_BD_LATECOL)
			cep->stats.tx_window_errors++;
		if (bdp->len_status & OETH_TX_BD_RETLIM)
			cep->stats.tx_aborted_errors++;
		if (bdp->len_status & OETH_TX_BD_UNDERRUN)
			cep->stats.tx_fifo_errors++;
		if (bdp->len_status & OETH_TX_BD_CARRIER)
			cep->stats.tx_carrier_errors++;
		if (bdp->len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM | OETH_TX_BD_UNDERRUN))
			cep->stats.tx_errors++;
 
		cep->stats.tx_packets++;
		cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
 
#ifndef TXBUFF_PREALLOC
		skb = cep->tx_skbuff[cep->tx_last];
 
		/* Free the sk buffer associated with this last transmit.
		*/
		dev_kfree_skb(skb, FREE_WRITE);
#endif
 
		if (cep->tx_full)
			cep->tx_full = 0;
	}
}
 
static void
oeth_rx(struct net_device *dev)
{
	struct	oeth_private *cep;
	volatile oeth_bd *bdp;
	struct	sk_buff *skb;
	int	pkt_len;
	int	bad = 0;
#ifndef RXBUFF_PREALLOC
	struct	sk_buff *small_skb;
#endif
 
	cep = (struct oeth_private *)dev->priv;
 
	/* First, grab all of the stats for the incoming packet.
	 * These get messed up if we get called due to a busy condition.
	 */
	for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) {
 
		bdp = cep->rx_bd_base + cep->rx_cur;
 
#ifndef RXBUFF_PREALLOC
		skb = cep->rx_skbuff[cep->rx_cur];
 
		if (skb == NULL) {
 
			skb = dev_alloc_skb(MAX_FRAME_SIZE);
 
			if (skb != NULL)
			{
				bdp->addr = (unsigned long) skb->tail;
				bdp->len_status |= OETH_RX_BD_EMPTY;
			}
 
			continue;
		}
#endif
 
		if (bdp->len_status & OETH_RX_BD_EMPTY)
			break;
 
		/* Check status for errors.
		 */
		if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
			cep->stats.rx_length_errors++;
			bad = 1;
		}
		if (bdp->len_status & OETH_RX_BD_DRIBBLE) {
			cep->stats.rx_frame_errors++;
			bad = 1;
		}
		if (bdp->len_status & OETH_RX_BD_CRCERR) {
			cep->stats.rx_crc_errors++;
			bad = 1;
		}
		if (bdp->len_status & OETH_RX_BD_OVERRUN) {
			cep->stats.rx_crc_errors++;
			bad = 1;
		}
		if (bdp->len_status & OETH_RX_BD_MISS) {
 
		}
		if (bdp->len_status & OETH_RX_BD_LATECOL) {
			cep->stats.rx_frame_errors++;
			bad = 1;
		}
 
 
		if (bad) {
 
			bdp->len_status &= ~OETH_RX_BD_STATS;
      bdp->len_status |= OETH_RX_BD_EMPTY;
 
			continue;
		}
 
		/* Process the incoming frame.
		 */
		pkt_len = bdp->len_status >> 16;
 
#ifdef RXBUFF_PREALLOC
		skb = dev_alloc_skb(pkt_len);
 
		if (skb == NULL) {
			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
			cep->stats.rx_dropped++;
		}
		else {
			skb->dev = dev;
#if DEBUG
			_print("RX\n");
			oeth_print_packet(bdp->addr, pkt_len);
#endif
			memcpy(skb_put(skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
			skb->protocol = eth_type_trans(skb,dev);
			netif_rx(skb);
			cep->stats.rx_packets++;
		}
 
		bdp->len_status &= ~OETH_RX_BD_STATS;
		bdp->len_status |= OETH_RX_BD_EMPTY;
#else
 
		if (pkt_len < 128) {
 
			small_skb = dev_alloc_skb(pkt_len);
 
			if (small_skb) {
				small_skb->dev = dev;
#if DEBUG
				_print("RX short\n");
                                oeth_print_packet(bdp->addr, bdp->len_status >> 16);
#endif
                                memcpy(skb_put(small_skb, pkt_len), (unsigned char *)__va(bdp->addr), pkt_len);
                                small_skb->protocol = eth_type_trans(small_skb,dev);
                                netif_rx(small_skb);
				cep->stats.rx_packets++;
			}
			else {
				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
	                        cep->stats.rx_dropped++;
			}
 
			bdp->len_status &= ~OETH_RX_BD_STATS;
			bdp->len_status |= OETH_RX_BD_EMPTY;
		}
		else {
        		skb->dev = dev;
			skb_put(skb, bdp->len_status >> 16);
			skb->protocol = eth_type_trans(skb,dev);
			netif_rx(skb);
			cep->stats.rx_packets++;
#if DEBUG
			_print("RX long\n");
                        oeth_print_packet(bdp->addr, bdp->len_status >> 16);
#endif
 
			skb = dev_alloc_skb(MAX_FRAME_SIZE);
 
			bdp->len_status &= ~OETH_RX_BD_STATS;
 
			if (skb) {
				cep->rx_skbuff[cep->rx_cur] = skb;
 
				bdp->addr = (unsigned long)skb->tail;
				bdp->len_status |= OETH_RX_BD_EMPTY;
			}
			else {
				cep->rx_skbuff[cep->rx_cur] = NULL;	
			}
		}
#endif
	}
}
 
static int calc_crc(char *mac_addr)
{
	int result = 0;
	return (result & 0x3f);
}
 
static struct enet_statistics *oeth_get_stats(struct net_device *dev)
{
        struct oeth_private *cep = (struct oeth_private *)dev->priv;
 
        return &cep->stats;
}
 
static void oeth_set_multicast_list(struct net_device *dev)
{
	struct	oeth_private *cep;
	struct	dev_mc_list *dmi;
	volatile oeth_regs *regs;
	int	i;
 
	cep = (struct oeth_private *)dev->priv;
 
	/* Get pointer of controller registers.
	 */
	regs = (oeth_regs *)dev->base_addr;
 
	if (dev->flags & IFF_PROMISC) {
 
		/* Log any net taps. 
		 */
		printk("%s: Promiscuous mode enabled.\n", dev->name);
		regs->moder |= OETH_MODER_PRO;
	} else {
 
		regs->moder &= ~OETH_MODER_PRO;
 
		if (dev->flags & IFF_ALLMULTI) {
 
			/* Catch all multicast addresses, so set the
			 * filter to all 1's.
			 */
			regs->hash_addr0 = 0xffffffff;
			regs->hash_addr1 = 0xffffffff;
		}
		else if (dev->mc_count) {
 
			/* Clear filter and add the addresses in the list.
			 */
			regs->hash_addr0 = 0x00000000;
			regs->hash_addr0 = 0x00000000;
 
			dmi = dev->mc_list;
 
			for (i = 0; i < dev->mc_count; i++) {
 
				int hash_b;
 
				/* Only support group multicast for now.
				 */
				if (!(dmi->dmi_addr[0] & 1))
					continue;
 
				hash_b = calc_crc(dmi->dmi_addr); 
				if(hash_b >= 32)
					regs->hash_addr1 |= 1 << (hash_b - 32);
				else
					regs->hash_addr0 |= 1 << hash_b;
			}
		}
	}
}
 
static void oeth_set_mac_add(struct net_device *dev, void *p)
{
	struct sockaddr *addr=p;
	volatile oeth_regs *regs;
 
	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 
	regs = (oeth_regs *)dev->base_addr;
 
	regs->mac_addr1 = 	addr->sa_data[0] << 8 	| 
				addr->sa_data[1];
        regs->mac_addr0 = 	addr->sa_data[2] << 24 	| 
				addr->sa_data[3] << 16 	| 
				addr->sa_data[4] << 8 	| 
				addr->sa_data[5];	
}
 
/* Initialize the Open Ethernet MAC.
 */
int oeth_probe(struct net_device *dev)
{
	struct oeth_private *cep;
	volatile oeth_regs *regs;
	volatile oeth_bd *tx_bd, *rx_bd;
	int i, j, k;
#ifdef SRAM_BUFF
	unsigned long mem_addr = SRAM_BUFF_BASE;
#else
	unsigned long mem_addr;
#endif
 
	cep = (struct oeth_private *)dev->priv;
 
	/* Allocate a new 'dev' if needed. 
	 */
	if (dev == NULL) {
		/*
		 * Don't allocate the private data here, it is done later
		 * This makes it easier to free the memory when this driver
		 * is used as a module.
		 */
		dev = init_etherdev(0, 0);
		if (dev == NULL)
			return -ENOMEM;
	}
 
	/* Initialize the device structure. 
	 */
	if (dev->priv == NULL) {
		cep = (struct oeth_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
		dev->priv = cep;
		if (dev->priv == NULL)
			return -ENOMEM;
	}
 
	__clear_user(cep,sizeof(*cep));
 
	/* Get pointer ethernet controller configuration registers.
	 */
	cep->regs = (oeth_regs *)(OETH_REG_BASE);
	regs = (oeth_regs *)(OETH_REG_BASE);
 
	/* Reset the controller.
	 */
	regs->moder = OETH_MODER_RST;	/* Reset ON */
	regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
 
	/* Setting TXBD base to OETH_TXBD_NUM.
	 */
	regs->tx_bd_num = OETH_TXBD_NUM;
 
	/* Initialize TXBD pointer
	 */
	cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE;
	tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
 
	/* Initialize RXBD pointer
	 */
	cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
	rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
 
	/* Initialize transmit pointers.
	 */
	cep->rx_cur = 0;
#ifdef CONFIG_OETH_UNKNOWN_TX_NEXT
        /* the first time use value passed by bootloader
         * __PHX__ fixme, this woun't work if you have this compiled as module
         */
        {
                int tmp_next = *((int *)(0x00000000));
 
                /* sanity check */
                if ((tmp_next >= 0) && (tmp_next < OETH_TXBD_NUM))
                        cep->tx_next = tmp_next;
                else {
                        printk(KERN_WARNING "open_eth: illegal number of TX buffer descriptors passed (%d), using default (if you did not use ethernet before starting linux this is ok)\n",
                               tmp_next);
                        cep->tx_next = 0;
                }
        }
#else
        /* or read it from eth register, or set it to 0 in eth */
	cep->tx_next = 0;
#endif
	cep->tx_last = 0;
	cep->tx_full = 0;
 
	/* Set min/max packet length 
	 */
	regs->packet_len = 0x00400600;
 
	/* Set IPGT register to recomended value 
	 */
	regs->ipgt = 0x00000012;
 
	/* Set IPGR1 register to recomended value 
	 */
	regs->ipgr1 = 0x0000000c;
 
	/* Set IPGR2 register to recomended value 
	 */
	regs->ipgr2 = 0x00000012;
 
	/* Set COLLCONF register to recomended value 
	 */
	regs->collconf = 0x000f003f;
 
	/* Set control module mode 
	 */
#if 0
	regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
#else
	regs->ctrlmoder = 0;
#endif
 
  /* Set PHY to show Tx status, Rx status and Link status */
  regs->miiaddress = 20<<8;
  regs->miitx_data = 0x1422;
  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
 
#ifdef TXBUFF_PREALLOC
 
	/* Initialize TXBDs.
	 */
	for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
 
#ifndef SRAM_BUFF
		mem_addr = __get_free_page(GFP_KERNEL);
#endif
 
		for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
			tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
			tx_bd[k].addr = __pa(mem_addr);
			mem_addr += OETH_TX_BUFF_SIZE;
		}
	}
	tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
#else
 
 	/* Initialize TXBDs.
	 */
	for(i = 0; i < OETH_TXBD_NUM; i++) {
 
		cep->tx_skbuff[i] = NULL;
 
		tx_bd[i].len_status = (0 << 16) | OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
		tx_bd[i].addr = 0;
	}
	tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
#endif
 
#ifdef RXBUFF_PREALLOC
 
	/* Initialize RXBDs.
	 */
	for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
 
#ifndef SRAM_BUFF
		mem_addr = __get_free_page(GFP_KERNEL);
#endif
 
		for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) {
			rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
			rx_bd[k].addr = __pa(mem_addr);
			mem_addr += OETH_RX_BUFF_SIZE;
		}
	}
	rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
 
#else
	/* Initialize RXBDs.
	 */
	for(i = 0; i < OETH_RXBD_NUM; i++) {
 
 
		rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ;
 
		cep->rx_skbuff[i] = NULL;
 
		rx_bd[i].addr = 0;
	}
	rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
 
#endif
 
	/* Set default ethernet station address.
	 */
	dev->dev_addr[0] = MACADDR0;
	dev->dev_addr[1] = MACADDR1;
	dev->dev_addr[2] = MACADDR2;
	dev->dev_addr[3] = MACADDR3;
	dev->dev_addr[4] = MACADDR4;
	dev->dev_addr[5] = MACADDR5;
 
	regs->mac_addr1 = MACADDR0 << 8 | MACADDR1;
	regs->mac_addr0 = MACADDR2 << 24 | MACADDR3 << 16 | MACADDR4 << 8 | MACADDR5;
 
	/* Clear all pending interrupts 
	 */
	regs->int_src = 0xffffffff;
 
	/* Promisc, IFG, CRCEn
	 */
	regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
 
	/* Enable interrupt sources.
	 */
	regs->int_mask = OETH_INT_MASK_TXB 	| 
			OETH_INT_MASK_TXE 	| 
			OETH_INT_MASK_RXF 	| 
			OETH_INT_MASK_RXE 	|
			OETH_INT_MASK_BUSY 	|
			OETH_INT_MASK_TXC	|
			OETH_INT_MASK_RXC;
 
	/* Fill in the fields of the device structure with ethernet values. 
	 */
	ether_setup(dev);
 
	dev->base_addr = (unsigned long)OETH_REG_BASE;
 
	/* The Open Ethernet specific entries in the device structure. 
	 */
	dev->open = oeth_open;
	dev->hard_start_xmit = oeth_start_xmit;
	dev->stop = oeth_close;
	dev->get_stats = oeth_get_stats;
	dev->set_multicast_list = oeth_set_multicast_list;
	dev->set_mac_address = oeth_set_mac_add;
 
	printk("%s: Open Ethernet Core Version 1.0\n", dev->name);
 
	return 0;
}
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.