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

📄 ae531xlnx.c

📁 atheros ar531x ethernet driver
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright © 2003 Atheros Communications, Inc.,  All Rights Reserved. *//* * Ethernet driver for Atheros' ae531x ethernet MAC. * This is a fairly generic driver, but it's intended * for use in typical Atheros products. */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/init.h>#include <linux/skbuff.h>#include <asm/io.h>#include "ar531xlnx.h"#include "ae531xreg.h"#include "ae531xmac.h"#include "ae531x.h"  #ifndef EXPORT_SYMTAB#define EXPORT_SYMTAB#endif#ifdef DEBUGvoid my_mvPhyShow(int ethUnit);#endifstatic struct ar531x_boarddata *ar531x_boardConfig=NULL;static char *radioConfig=NULL;#define AE531X_LAN_PORT 0#define AE531X_DEV_PER_MAC 1#define TIMER_WUT	(jiffies + HZ * AE531X_PHY_POLL_SECONDS)/* timer wakeup time : 2 second */#define CPU_PORT 5/* * ae531x_MAC_state contains driver-specific linux-specific per-MAC information. * The OSinfo member of ae531x_MAC_t points to one of these. */typedef struct ae531x_MAC_state {    int                         irq;    struct tq_struct            restart_task;    struct net_device_stats     stats;    struct ae531x_dev_sw_state  *dev_sw_state[AE531X_DEV_PER_MAC];    int                         primary_dev;    ae531x_MAC_t                MACInfo; /* hardware state */} ae531x_MAC_state_t;#define TX_TWO_BUF 1/* * ae531x_dev_sw_state contains driver-specific linux-specific per-device * information.  The net_device priv member points to one of these, and * this structure contains a pointer to the associated MAC information. */typedef struct ae531x_dev_sw_state {    int                     enetUnit;        /* system unit number "eth%d" */    int                     unit_on_MAC;     /* MAC-relative unit number */    struct net_device       *dev;    ae531x_MAC_state_t      *MAC_state;      /* underlying MAC hw/sw state */    struct timer_list timer;} ae531x_dev_sw_state_t;/* * Driver-independent linux-specific per-ethernet device software information. */static struct net_device *ae531x_MAC_dev[AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC];/* Driver-dependent per-MAC information */static ae531x_MAC_state_t per_MAC_info[AR531X_NUM_ENET_MAC];/* * Receive buffers need enough room to hold the following: * 1) a max MTU-sized packet.   * 2) space for an ethernet header * 3) room at the beginning of the receive buffer in order *    to facilitate cooperating drivers that need to PREpend *    data. * 4) Depending on configuration, we may need some additional *    room at the END of the rx buffer for phy-supplied *    trailers (if any). (c.f. CONFIG_VENETDEV) * * The DMA engine insists on 32-bit aligned RX buffers. * TBDXXX: With current code, the IP stack ends up looking * at misaligned headers with word operations.  The misaligned * reads are software-emulated via handle_adel_int.  We'd * rather align the buffers on a 16-bit boundary, but the * DMA engine doesn't permit it??? */ #define ETH_MAX_MTU 1518#ifdef HEADER_MODE#define AE531X_RX_BUF_SIZE \    (((RXBUFF_RESERVE + ETH_HLEN + ETH_MAX_MTU/* + PHY_HEADER_SIZE*/) + 3) & ~3)#else#define AE531X_RX_BUF_SIZE \    (((RXBUFF_RESERVE + ETH_HLEN + ETH_MAX_MTU + PHY_TRAILER_SIZE) + 3) & ~3)#endif /* Forward references to local functions */static void ae531x_TxReap(ae531x_MAC_state_t *MAC_state, int length);static int ae531x_phy_poll(void *data);static int ae531x_MAC_stop(struct net_device *dev);static int ae531x_MAC_open(struct net_device *dev);#ifdef CONFIG_VLAN_ROUTERstatic BOOL hwInit = FALSE;#endif /******************************************************************************** ae531x_MAC_poll checks for received packets, and sends data* up the stack.*/intae531x_MAC_poll(struct net_device *dev, int *budget){    struct sk_buff *skb;    struct sk_buff *newskb;    char *rxBufp;    int unused_length;    VIRT_ADDR   rxDesc;    int length;    ae531x_dev_sw_state_t *dev_sw_state;    ae531x_MAC_state_t *MAC_state;    ae531x_MAC_t *MACInfo;    u32 cmdsts;    int rx_limit;    int rx_received;    int rxDescCount;    struct net_device *rxdev;#ifdef CONFIG_VLAN_ROUTER    struct net_device *v_rxdev;    static int from;#endif         int early_stop;    int retval;#ifdef DEBUG	static int rxDescCountMax = 0;#endif    ARRIVE();    dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;    MAC_state = dev_sw_state->MAC_state;    MACInfo = &MAC_state->MACInfo;       rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota;        rx_received = 0;    rxDescCount = 0;    early_stop = 0;    do {        ae531x_AckIntr(MACInfo, DmaIntRxCompleted);        for(;!early_stop;) {            rxDesc = MACInfo->rxQueue.curDescAddr;            cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc));            AE531X_PRINT(AE531X_DEBUG_RX,                  ("examine rxDesc %p with cmdsts=0x%x\n",                   (void *)rxDesc, cmdsts));                if (cmdsts & DescOwnByDma) {                /* There's nothing left to process in the RX ring */                goto rx_all_done;            }            rxDescCount++;            AE531X_CONSUME_DESC((&MACInfo->rxQueue));                A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE);            /*  Process a packet */            length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN;            if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) ==                           (DescRxFirst | DescRxLast) ) {                /* Descriptor status indicates "NO errors" */                skb = AE531X_DESC_SWPTR_GET(rxDesc);                /*                 * Allocate a replacement skb.                 * We want to get another buffer ready for Rx ASAP.                 */                newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, &rxBufp, &unused_length);                if(newskb == NULL ) {                    /*                     * Give this descriptor back to the DMA engine,                     * and drop the received packet.                     */                    MAC_state->stats.rx_dropped++;                    AE531X_PRINT(AE531X_DEBUG_ERROR,                              ("Can't allocate new skb\n"));                } else {                    AE531X_DESC_BUFPTR_SET(rxDesc, virt_to_bus(rxBufp));                    AE531X_DESC_SWPTR_SET(rxDesc, newskb);                }                AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);                rxDesc = NULL; /* sanity -- cannot use rxDesc now */                sysWbFlush();                    if (newskb == NULL) {                    retval = 1;                    goto rx_no_skbs;                } else {                    /* Sync data cache w.r.t. DMA */                    A_DATA_CACHE_INVAL(skb->data, length);#ifdef CONFIG_VLAN_ROUTER         		phyDetermineSource(skb->data, length, &from);		rxdev = (struct net_device *)per_MAC_info[from].dev_sw_state[MAC_state->primary_dev]->dev;		    	MAC_state = &per_MAC_info[from];   #if 0    {    	int i;    	if((*(unsigned char*)(skb->data + 12) == 0x08 && *(unsigned char*)(skb->data + 13) == 0x06) ||    		(*(unsigned char*)(skb->data + 12) == 0x45 && *(unsigned char*)(skb->data + 13) == 0x00))    	{	    	printf("iface = %d poll length = %d \n",from, length);	    	for(i = 0; i< 16; i++)	    	{	    	   printf("0x%2.2x ", *(unsigned char*)(skb->data + i));	    	   if (i%16 == 0 && i != 0)	    	    printf("\n");	    			    	}	    	printf("\n");	}    }#endif 	    	#else                    rxdev = dev_sw_state->dev;#endif                  if (rxdev == NULL)                                   {                /*                 * We received a packet for a virtual enet device                 * that is no longer up.  Ignore it.                 */                   kfree_skb(skb);                   continue;                }                    /* Advance data pointer to show that there's data here */                   skb_put(skb, length);                    #ifdef CONFIG_VLAN_ROUTER#ifdef HEADER_MODE		   //skb_reserve(skb, PHY_HEADER_SIZE);		   //memmove(skb->data, skb->data+2, skb->len);		   //skb_trim(skb, (length - 2));		   skb->data += PHY_HEADER_SIZE;		   skb->len  -= PHY_HEADER_SIZE;	    #else					skb_trim(skb, length - PHY_TRAILER_SIZE);#endif 		    #endif                                        skb->protocol = eth_type_trans(skb, rxdev);                        skb->dev = rxdev;                                    skb->ip_summed = CHECKSUM_NONE;                    rxdev->last_rx = jiffies;                    rxdev->quota--;                    if (rx_limit-- < 0) {                        early_stop=1;                        /* We've done enough for now -- more later */                        AE531X_PRINT(AE531X_DEBUG_RX_STOP,                            ("Enet%d RX early stop.  Quota=%d rxDescCount=%d budget=%d\n",                             MACInfo->unit, dev->quota, rxDescCount, *budget));                    }                    rx_received++;                            /* Send the data up the stack */                    AE531X_PRINT(AE531X_DEBUG_RX,                              ("Send data up stack: skb=%p data=%p length=%d\n",                               (void *)skb, (void *)skb->data, length));                    netif_receive_skb(skb);                    MAC_state->stats.rx_packets++;                    MAC_state->stats.rx_bytes += length;                }            } else {                /* Descriptor status indicates ERRORS */                MAC_state->stats.rx_errors++;                    if (cmdsts & (DescRxRunt | DescRxLateColl)) {                    MAC_state->stats.collisions++;                }                    if (cmdsts & DescRxLengthError) {                    MAC_state->stats.rx_length_errors++;                }                    if (cmdsts & DescRxCrc) {                    MAC_state->stats.rx_crc_errors++;                }                    if (cmdsts & DescRxDribbling) {                    MAC_state->stats.rx_frame_errors++;                }								AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);                AE531X_PRINT(AE531X_DEBUG_ERROR,                          ("Bad receive.  rxDesc=%p  cmdsts=0x%8.8x\n",                           (void *)rxDesc, cmdsts));            }        }    } while ((!early_stop) &&             ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted);rx_all_done:    AE531X_PRINT(AE531X_DEBUG_RX,              ("rx done (%d)\n", rxDescCount));    *budget -= rxDescCount;    if (!early_stop) { 	        netif_rx_complete(dev);        ae531x_SetDmaReg(MACInfo, DmaIntrEnb,                     DmaIeRxCompleted | DmaIeRxNoBuffer);        ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0);    }        retval = early_stop;rx_no_skbs:    LEAVE();#ifdef DEBUG	if (rxDescCount > rxDescCountMax) {		printk("max rx %d\n", rxDescCount);		rxDescCountMax = rxDescCount;	}#endif    return retval;}/******************************************************************************** ae531x_restart stops all ethernet devices associated with a physical MAC,* then shuts down the MAC.  Then it re-opens all devices that were in use.* TBDXXX: needs testing!*/static voidae531x_restart(void *data){    ae531x_MAC_t *MACInfo = (ae531x_MAC_t *)data;    ae531x_MAC_state_t *MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;    struct net_device *saved_dev[AE531X_DEV_PER_MAC];    int i;    for (i=0; i<AE531X_DEV_PER_MAC; i++) {        if ((saved_dev[i] = MAC_state->dev_sw_state[i]->dev) != NULL) {            ae531x_MAC_stop(saved_dev[i]);        }    }    for (i=0; i<AE531X_DEV_PER_MAC; i++) {        if (saved_dev[i])            ae531x_MAC_open(saved_dev[i]);    }}/******************************************************************************** ae531x_MAC_intr handle interrupts from an ethernet MAC.* It checks MAC status registers, and dispatches as appropriate.*/voidae531x_MAC_intr(int cpl, void *dev_id, struct pt_regs *regs){	ae531x_MAC_state_t *MAC_state;	ae531x_MAC_t *MACInfo;	u32 regIsr;	u32 regImr;	u32 pendIntrs;	ARRIVE();	MACInfo = (ae531x_MAC_t *)dev_id;	MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;	for(;;) {		/* Clear any unhandled intr causes. */		ae531x_WriteDmaReg(MACInfo, DmaStatus, UnhandledIntrMask);		regIsr = ae531x_ReadDmaReg(MACInfo, DmaStatus);		regImr = ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);		pendIntrs = regIsr & regImr;		AE531X_PRINT(AE531X_DEBUG_INT,					 ("ethmac%d: intIsr=0x%8.8x intImr=0x%8.8x pendIntrs=0x%8.8x\n",					  MACInfo->unit, regIsr, regImr, pendIntrs ));		if ((pendIntrs & DmaAllIntCauseMask) == 0)			break;		if ((pendIntrs & DmaIntRxCompleted) ||			(pendIntrs & DmaIntRxNoBuffer)) {					if (netif_rx_schedule_prep(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev)) {							ae531x_ClearDmaReg(MACInfo,								   DmaIntrEnb,								   DmaIeRxCompleted | DmaIeRxNoBuffer);				ae531x_AckIntr(MACInfo,							   DmaIntRxCompleted | DmaIntRxNoBuffer);				(void)ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);								__netif_rx_schedule(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev);							} else {#if 0				AE531X_PRINT(AE531X_DEBUG_ERROR,							 ("%s: Interrupt (0x%8.8x/0x%8.8x) while in poll.  regs@%p, pc=%p, ra=%p\n",							  __FILE__,							  regIsr,							  ae531x_ReadDmaReg(MACInfo, DmaIntrEnb),							  (void *)regs,							  (void *)regs->cp0_epc,							  (void *)regs->regs[31]));#endif				ae531x_AckIntr(MACInfo,							   DmaIntRxCompleted | DmaIntRxNoBuffer);			}		}		if (pendIntrs &			(DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)) {			AE531X_PRINT(AE531X_DEBUG_ERROR,						 ("ethmac%d: TX Error Intr (0x%x)\n",						  MACInfo->unit, pendIntrs));			ae531x_AckIntr(MACInfo,						   (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow));		}		if (pendIntrs & DmaIntBusError) {			AE531X_PRINT(AE531X_DEBUG_ERROR,						 ("ethmac%d: DMA Bus Error Intr (0x%x)\n",						  MACInfo->unit, pendIntrs));			ae531x_AckIntr(MACInfo, DmaIntBusError);			/* Reset the chip, if it's not already being done */			if (ae531x_IsInResetMode(MACInfo)) {				goto intr_done;			}			ae531x_BeginResetMode(MACInfo);			schedule_task(&MAC_state->restart_task);		}		if (pendIntrs & DmaIntRxStopped) {			AE531X_PRINT(AE531X_DEBUG_ERROR,						 ("ethmac%d: RX Stopped Intr (0x%x)\n",						  MACInfo->unit, pendIntrs));			ae531x_AckIntr(MACInfo, DmaIntRxStopped);		}	}	 intr_done:	LEAVE();}/******************************************************************************** ae531x_MAC_get_stats returns statistics for a specified device*/static struct net_device_stats*ae531x_MAC_get_stats(struct net_device *dev){        ae531x_dev_sw_state_t *dev_sw_state;        ae531x_MAC_state_t *MAC_state;        ARRIVE();        dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;        MAC_state = dev_sw_state->MAC_state;        LEAVE();        return &MAC_state->stats;}#define AE531X_PHY_POLL_SECONDS 2#if CONFIG_AR531X_COBRA/******************************************************************************** ae531x_getMACInfo returns the MACInfo  of the interface given by unit */ae531x_MAC_t *ae531x_getMAcInfo(int ethUnit){  int i,j;  for(i=0;i<AR531X_NUM_ENET_MAC;++i) {    if(per_MAC_info[i].dev_sw_state) {      for(j=0;j<AE531X_DEV_PER_MAC;++j) {	 if(per_MAC_info[i].dev_sw_state[j]	    && per_MAC_info[i].dev_sw_state[j]->enetUnit == ethUnit)            return (&(per_MAC_info[i].MACInfo));      }    }

⌨️ 快捷键说明

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