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

📄 s3c4510.c

📁 对于MAC WANG写的4510的驱动的修改,在uClinux环境下.转载
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * linux/deriver/net/s3c4510.c
 * Ethernet driver for Samsung 4510B
 * Copyright (C) 2002 Mac Wang <mac@os.nctu.edu.tw>
 * 
 * Revised by Zheng Geng email: gzheng@sohu.com 2004.4
 *  	fix the  s3c4510_rx to check if the BDMA is hang 
 *	Add set_mac_address to change mac address when up
*	fix other spinlock problems in other fuction
 */  


#include <linux/config.h>
#include <linux/module.h>

#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>       // printk()
#include <linux/slab.h>		// kmalloc()
#include <linux/errno.h>	// error codes
#include <linux/types.h>	// size_t
#include <linux/interrupt.h>	// mark_bh

#include <linux/in.h>
#include <linux/netdevice.h>    // net_device
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>

#include <asm/irq.h>
#include "s3c4510.h"

#undef DEBUG
#ifdef	DEBUG
#define TRACE(str, args...)	printk("S3C4510 eth: " str, ## args)
#else
#define TRACE(str, args...)
#endif


static int timeout = 100;	// tx watchdog ticks 100 = 1s
static char *version = "Samsung S3C4510 Ethernet driver version 0.1 (2002-02-20) <mac@os.nctu.edu.tw>\n";

/*
 * This structure is private to each device. It is used to pass
 * packets in and out, so there is place for a packet
 */
struct s3c4510_priv {
	struct net_device_stats stats;

	unsigned long tx_ptr;
	unsigned long gtx_ptr;
	unsigned long rx_ptr;

	// Frame Descriptor linked list for S3C4510 MAC, initialized by FD_init()
	volatile struct FrameDesc rx_fd[RX_FRAME_SIZE];
	volatile struct FrameDesc tx_fd[TX_FRAME_SIZE];

	// Frame Buffer for S3C4510 MAC
	volatile struct ethframe  rx_buf[RX_FRAME_SIZE];
	volatile struct ethframe  tx_buf[TX_FRAME_SIZE];
	
	spinlock_t lock;

	struct sk_buff *skb;
};

/* --------------------- *
 * MII support functions *
 * --------------------- */
void MIIWrite(unsigned long PhyInAddr, unsigned long PhyAddr, unsigned long PhyData)
{
	CSR_WRITE(STADATA, PhyData);
	CSR_WRITE(STACON, PhyInAddr | PhyAddr | MiiBusy | PHYREGWRITE);
	while(CSR_READ(STACON) & MiiBusy);
}

unsigned long MIIRead(unsigned long PhyInAddr, unsigned long PhyAddr)
{
	CSR_WRITE(STACON, PhyInAddr | PhyAddr | MiiBusy);
	while(CSR_READ(STACON) & MiiBusy);
	return CSR_READ(STADATA);
}

/*
 *
 */
void FD_Init(struct net_device *dev)
{
	struct s3c4510_priv *priv = (struct s3c4510_priv *) dev->priv;

	struct FrameDesc *FD_ptr;
	struct FrameDesc *FD_start_ptr;
	struct FrameDesc *FD_last_ptr = NULL;
	unsigned long FB_base;
	unsigned long i;

	// TxFDInitialize() in diag code
	// Get Frame descriptor's base address
	// +0x4000000 is for setting this area to non-cacheable area.
	CSR_WRITE(BDMATXPTR, (unsigned long) priv->tx_fd + 0x4000000);
	priv->gtx_ptr = priv->tx_ptr = CSR_READ(BDMATXPTR);

	// Get Transmit buffer base address.
	FB_base = (unsigned long) priv->tx_buf + 0x4000000;

	// Generate linked list.
	FD_start_ptr = FD_ptr = (struct FrameDesc *)priv->tx_ptr;
	FD_last_ptr = NULL;

	for(i = 0; i < TX_FRAME_SIZE; i++) {
		if(FD_last_ptr == NULL)
			FD_last_ptr = FD_ptr;
		else
			FD_last_ptr -> NextFrameDescriptor = (unsigned long)FD_ptr;

		FD_ptr->FrameDataPtr = (unsigned long)(FB_base & CPU_owner);
		FD_ptr->Reserved = 0;
		FD_ptr->StatusAndFrameLength = (unsigned long)0x0;
		FD_last_ptr = FD_ptr;
		FD_ptr++;
		FB_base += sizeof(struct ethframe);
	}

	//Make Frame descriptor to ring buffer type.
	FD_last_ptr->NextFrameDescriptor = (unsigned long)FD_start_ptr;

	// RxFDInitialize() in diag code
	// Get Frame descriptor's base address
	CSR_WRITE(BDMARXPTR, (unsigned long) priv->rx_fd + 0x4000000);
	priv->rx_ptr = CSR_READ(BDMARXPTR);

	// Get Transmit buffer base address
	FB_base = (unsigned long)priv->rx_buf + 0x4000000;

	// Generate linked list
	FD_start_ptr = FD_ptr = (struct FrameDesc *)priv->rx_ptr;
	FD_last_ptr = NULL;

	for(i = 0; i < RX_FRAME_SIZE; i++) {
		if(FD_last_ptr == NULL )
			FD_last_ptr = FD_ptr;
		else
			FD_last_ptr -> NextFrameDescriptor = (unsigned long)FD_ptr;

		FD_ptr->FrameDataPtr = (unsigned long)(FB_base | BDMA_owner);
		FD_ptr->Reserved = 0;
		FD_ptr->StatusAndFrameLength = (unsigned long)0x0;
		FD_ptr->NextFrameDescriptor = 0x0;

		FD_last_ptr = FD_ptr;
		FD_ptr++;
		FB_base += sizeof(struct ethframe);
	}   

	// Make Frame descriptor to ring buffer type.
	FD_last_ptr->NextFrameDescriptor = (unsigned long)FD_start_ptr;
}


/*
 * rx
 */
void s3c4510_rx(int irq, void *dev_id, struct pt_regs *regs)
{
//	int i;
	int len;
	unsigned char *data;
	struct sk_buff *skb;
	struct FrameDesc *FD_ptr;
	unsigned long CFD_ptr;
	unsigned long RxStat;
	unsigned long BDMAStat;
	struct net_device *dev = (struct net_device *) dev_id;
	struct s3c4510_priv *priv = (struct s3c4510_priv *) dev->priv;
	TRACE("rx\n");

	spin_lock(&priv->lock);

	// 1. Get current frame descriptor and status
	CFD_ptr = CSR_READ(BDMARXPTR);
	BDMAStat = CSR_READ(BDMASTAT);

	// 2. Clear BDMA status register bit by write 1
	CSR_WRITE(BDMASTAT, BDMAStat | S_BRxRDF);

	do {
		// 3. Check Null List Interrupt
		/*
		if(CSR_READ(BDMASTAT) & BRxNL) {
			CSR_WRITE(BDMASTAT, );
		}
		*/

		// 4. Get Rx Frame Descriptor
		FD_ptr = (struct FrameDesc *) priv->rx_ptr;
		RxStat = (FD_ptr->StatusAndFrameLength >> 16) & 0xffff;
		
		// 5. If Rx frame is good, then process received frame
		if(RxStat & Good){
			len = (FD_ptr->StatusAndFrameLength & 0xffff) - 4;
			data = (unsigned char *) FD_ptr->FrameDataPtr + 2;

			// 6. Get received frame to memory buffer
			skb = dev_alloc_skb(len+2);
			if(!skb) {
				printk("S3C4510 eth: low on mem - packet dropped\n");
				priv->stats.rx_dropped++;
				spin_unlock(&priv->lock);
				return;
			}
//			memcpy(skb_put(skb, len), data, len);
/*
			printk("len: %d\n", len);
			for(i = 0; i < len; i++)
			{
				printk("%3x", data[i]);
				if((i+1)%16==0)
					printk("\n");
			}
			printk("\n");
*/
			skb->dev = dev;
			skb_reserve(skb, 2);
			skb_put(skb, len);
			eth_copy_and_sum(skb, data, len, 0);
			skb->protocol = eth_type_trans(skb, dev);
			priv->stats.rx_packets++;
			priv->stats.rx_bytes += len;
			netif_rx(skb);
		}
		else {
			// 7. If Rx frame has error, then process err frame
			priv->stats.rx_errors++;
			if(RxStat & LongErr)
				priv->stats.rx_length_errors++;
			if(RxStat & OvMax)
				priv->stats.rx_over_errors++;
			if(RxStat & CRCErr)
				priv->stats.rx_crc_errors++;
			if(RxStat & AlignErr)
				priv->stats.rx_frame_errors++;
			if(RxStat & Overflow)
				priv->stats.rx_fifo_errors++;
			
		}
		// 8. Change ownership to BDMA for next use
		FD_ptr -> FrameDataPtr |= BDMA_owner;

		// Save Current Status and Frame Length field, and clear
		FD_ptr -> StatusAndFrameLength = 0x0;

		// 9. Get Next Frame Descriptor pointer to process
		priv->rx_ptr = (unsigned long)(FD_ptr -> NextFrameDescriptor);
	}while(CFD_ptr != priv->rx_ptr);

	// 10. Check Notowner status
	if(CSR_READ(BDMASTAT) & S_BRxNO) {
		CSR_WRITE(BDMASTAT, S_BRxNO);
	}

	//check if the BDMA is hang 
	if (! (CSR_READ(BDMARXCON) & BRxEn))
                CSR_WRITE(BDMARXCON, gBDMARXCON);
	
	spin_unlock(&priv->lock);
}

/*
 * tx
 */
void s3c4510_tx(int irq, void *dev_id, struct pt_regs *regs)
{
	struct FrameDesc *FD_ptr;
	unsigned long CFD_ptr;
	unsigned long *FB_ptr;
	unsigned long status;
	struct net_device *dev = (struct net_device *) dev_id;
	struct s3c4510_priv *priv = (struct s3c4510_priv *) dev->priv;
	TRACE("tx\n");

	spin_lock(&priv->lock);

	CFD_ptr = CSR_READ(BDMATXPTR);
	while(priv->gtx_ptr != CFD_ptr)
	{
		FD_ptr = (struct FrameDesc *) priv->gtx_ptr;
		FB_ptr = (unsigned long *) &FD_ptr->FrameDataPtr;

		if(!(*FB_ptr & BDMA_owner))
		{
			status = (FD_ptr->StatusAndFrameLength >> 16) & 0xffff;
			if(status & Comp) {
				priv->stats.tx_packets++;
			}
			else {
				priv->stats.tx_errors++;
				if(status & TxPar)
					priv->stats.tx_aborted_errors++;
				if(status & NCarr)

⌨️ 快捷键说明

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