* Re: Netpoll checksum issue
2006-04-23 11:34 ` Herbert Xu
@ 2006-04-24 5:42 ` Aubrey
2006-04-24 7:46 ` Aubrey
2006-04-24 10:22 ` Herbert Xu
0 siblings, 2 replies; 11+ messages in thread
From: Aubrey @ 2006-04-24 5:42 UTC (permalink / raw)
To: Herbert Xu; +Cc: Stephen Hemminger, netdev
[-- Attachment #1: Type: text/plain, Size: 1532 bytes --]
On 4/23/06, Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Thu, Apr 20, 2006 at 09:54:54AM +0800, Aubrey wrote:
> Please send me a copy of the driver source that you were using when
> this happened.
The driver is attached.
> Could you please add a printk in checksum_udp to print out the pertinent
> values such as the expected checksum and actual checksum?
>
It seems not only "checksum_udp" in "netpoll", a few other routines
will call "__skb_checksum_complete", So the routine
"__skb_checksum_complete" must be ok.
And,
The routine "csum_tcpudp_nofold" should be ok, too. Because it's
called by many other routines, too.
But, I don't understand, why assign "psum=csum_tcpudp_nofold()" to
"skb->csum", and make "__skb_checksum_complete" to do the checksum?
Thanks for your any hints
Regards,
-Aubrey
================================================================
static int checksum_udp(struct sk_buff *skb, struct udphdr *uh,
unsigned short ulen, u32 saddr, u32 daddr)
{
unsigned int psum;
if (uh->check == 0 || skb->ip_summed == CHECKSUM_UNNECESSARY)
return 0;
psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
if (skb->ip_summed == CHECKSUM_HW &&
!(u16)csum_fold(csum_add(psum, skb->csum)))
return 0;
skb->csum = psum;
return __skb_checksum_complete(skb);
}
==================================================================
[-- Attachment #2: bfin_mac.c --]
[-- Type: text/plain, Size: 21501 bytes --]
static const char version[] =
"bf53mac.c: v1.0, Aug 27 2005 by Luke Yang <luke.yang@analog.com>\n";
/* Debugging level */
#ifndef BF537MAC_DEBUG
#define BF537MAC_DEBUG 0
#endif
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/crc32.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include "bfin_mac.h"
#include <asm/irq.h>
#include <asm/blackfin.h>
#include <asm/delay.h>
MODULE_LICENSE("GPL");
#define CARDNAME "bfin_mac"
static void desc_list_free(void);
/* transmit net_dma_desc numbers */
#define INIT_DESC_NUM 12
#define MAX_DESC_NUM 64
#define MAX_RX_DESC_NUM 8
/* pointers to maintain transmit list */
struct net_dma_desc *tx_list_head;
struct net_dma_desc *tx_list_tail;
struct net_dma_desc *rx_list_head;
struct net_dma_desc *rx_list_tail;
struct net_dma_desc *current_rx_ptr;
struct net_dma_desc *current_tx_ptr;
int current_desc_num;
extern unsigned long l1_data_A_sram_alloc(unsigned long size);
extern unsigned long l1_data_A_sram_free(unsigned long size);
extern void get_bf537_ether_addr(char *addr);
static int desc_list_init(void)
{
struct net_dma_desc *tmp_desc;
int i;
dma_addr_t dma_handle;
/* init tx_list */
if (current_desc_num == 0) {
for (i=0;i < INIT_DESC_NUM;i++) {
tmp_desc = (struct net_dma_desc *)dma_alloc_coherent(NULL, sizeof(struct net_dma_desc), &dma_handle , GFP_DMA);
//tmp_desc = (struct net_dma_desc *)l1_data_A_sram_alloc(sizeof(struct net_dma_desc));
if (tmp_desc == NULL)
goto error;
else
memset(tmp_desc,0,sizeof(tmp_desc));
if (i == 0) {
tx_list_head = tmp_desc;
tx_list_tail = tmp_desc;
}
tmp_desc->desc_a.start_addr = (unsigned long)tmp_desc->packet;
tmp_desc->desc_a.x_count = 0;
tmp_desc->desc_a.config.b_DMA_EN = 0; //disabled
tmp_desc->desc_a.config.b_WNR = 0; //read from memory
tmp_desc->desc_a.config.b_WDSIZE = 2; //wordsize is 32 bits
tmp_desc->desc_a.config.b_NDSIZE = 6; //6 half words is desc size.
tmp_desc->desc_a.config.b_FLOW = 7; //large desc flow
tmp_desc->desc_a.next_dma_desc = &(tmp_desc->desc_b);
tmp_desc->desc_b.start_addr = (unsigned long)(&(tmp_desc->status));
tmp_desc->desc_b.x_count = 0;
tmp_desc->desc_b.config.b_DMA_EN = 1; //disabled
tmp_desc->desc_b.config.b_WNR = 1; //write to memory
tmp_desc->desc_b.config.b_WDSIZE = 2; //wordsize is 32 bits
tmp_desc->desc_b.config.b_DI_EN = 0; //disable interrupt
tmp_desc->desc_b.config.b_NDSIZE = 6;
tmp_desc->desc_b.config.b_FLOW = 7; //stop mode
tx_list_tail->desc_b.next_dma_desc = &(tmp_desc->desc_a);
tx_list_tail->next = tmp_desc;
tx_list_tail = tmp_desc;
}
tx_list_tail->next = tx_list_head; /* tx_list is a circle */
tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
current_desc_num = INIT_DESC_NUM;
current_tx_ptr = tx_list_head;
}
/* init rx_list */
for (i = 0; i < MAX_RX_DESC_NUM; i++) {
//tmp_desc = (struct net_dma_desc *)dma_alloc_coherent(NULL, sizeof(struct net_dma_desc), &dma_handle , GFP_DMA);
tmp_desc = (struct net_dma_desc *)l1_data_A_sram_alloc(sizeof(struct net_dma_desc));
if (tmp_desc == NULL)
goto error;
else
memset(tmp_desc,0,sizeof(tmp_desc));
if (i == 0) {
rx_list_head = tmp_desc;
rx_list_tail = tmp_desc;
}
tmp_desc->desc_a.start_addr = (unsigned long)tmp_desc->packet;
tmp_desc->desc_a.x_count = 0;
tmp_desc->desc_a.config.b_DMA_EN = 1; //enabled
tmp_desc->desc_a.config.b_WNR = 1; //Write to memory
tmp_desc->desc_a.config.b_WDSIZE = 2; //wordsize is 32 bits
tmp_desc->desc_a.config.b_NDSIZE = 6; //6 half words is desc size.
tmp_desc->desc_a.config.b_FLOW = 7; //large desc flow
tmp_desc->desc_a.next_dma_desc = &(tmp_desc->desc_b);
tmp_desc->desc_b.start_addr = (unsigned long)(&(tmp_desc->status));
tmp_desc->desc_b.x_count = 0;
tmp_desc->desc_b.config.b_DMA_EN = 1; //enabled
tmp_desc->desc_b.config.b_WNR = 1; //Write to memory
tmp_desc->desc_b.config.b_WDSIZE = 2; //wordsize is 32 bits
tmp_desc->desc_b.config.b_NDSIZE = 6;
tmp_desc->desc_b.config.b_DI_EN = 1; //enable interrupt
tmp_desc->desc_b.config.b_FLOW = 7; //stop
rx_list_tail->desc_b.next_dma_desc = &(tmp_desc->desc_a);
rx_list_tail->next = tmp_desc;
rx_list_tail = tmp_desc;
}
rx_list_tail->next = rx_list_head; /* rx_list is a circle */
rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
current_rx_ptr = rx_list_head;
return 0;
error:
desc_list_free();
printk("bf537mac: kmalloc failed. \n");
return -ENOMEM;
}
static void desc_list_free(void)
{
struct net_dma_desc *tmp_desc;
int i;
dma_addr_t dma_handle = 0;
tmp_desc = tx_list_head;
for (i = 0; i < INIT_DESC_NUM; i++) {
if (tmp_desc != NULL)
dma_free_coherent(NULL, sizeof(struct net_dma_desc), tmp_desc, dma_handle);
tmp_desc = tmp_desc->next;
}
tmp_desc = rx_list_head;
for (i = 0; i < MAX_RX_DESC_NUM; i++) {
if (tmp_desc != NULL)
l1_data_A_sram_free((unsigned long)tmp_desc);
tmp_desc = tmp_desc->next;
}
}
/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
//
//Set FER regs to MUX in Ethernet pins
//
static void SetupPinMux(void)
{
unsigned int fer_val;
// FER reg bug work-around
// read it once
fer_val = *pPORTH_FER;
fer_val = 0xffff;
// write it twice to the same value
*pPORTH_FER = fer_val;
*pPORTH_FER = fer_val;
}
//
//Wait until the previous MDC/MDIO transaction has completed
//
static void PollMdcDone(void)
{
// poll the STABUSY bit
while((*pEMAC_STAADD) & STABUSY) {};
}
//
//Read an off-chip register in a PHY through the MDC/MDIO port
//
static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr)
{
PollMdcDone();
*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | STABUSY; // read mode
PollMdcDone();
return (u16)*pEMAC_STADAT;
}
//
//Write an off-chip register in a PHY through the MDC/MDIO port
//
static void RawWrPHYReg(u16 PHYAddr, u16 RegAddr, u32 Data)
{
*pEMAC_STADAT = Data;
*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
STAOP | STABUSY; //write mode
PollMdcDone();
}
static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u32 Data)
{
PollMdcDone();
RawWrPHYReg(PHYAddr,RegAddr,Data);
}
//
//set up the phy
//
static int bf537mac_setphy(struct net_device *dev)
{
u16 phydat;
u32 sysctl;
struct bf537mac_local *lp = netdev_priv(dev);
//printk("bf537_mac: start settting up phy\n");
//Program PHY registers
phydat = 0;
// issue a reset
RawWrPHYReg(lp->PhyAddr, PHYREG_MODECTL, 0x8000);
// wait half a second
udelay(500);
phydat = RdPHYReg(lp->PhyAddr, PHYREG_MODECTL);
// advertise flow control supported
phydat = RdPHYReg(lp->PhyAddr, PHYREG_ANAR);
phydat |= (1 << 10);
WrPHYReg(lp->PhyAddr, PHYREG_ANAR, phydat);
phydat = 0;
if (lp->Negotiate) {
phydat |= 0x1000;// enable auto negotiation
} else {
if (lp->FullDuplex) {
phydat |= (1 << 8);// full duplex
} else {
phydat &= (~(1 << 8));// half duplex
}
if (!lp->Port10) {
phydat |= (1 << 13);// 100 Mbps
} else {
phydat &= (~(1 << 13));// 10 Mbps
}
}
if (lp->Loopback) {
phydat |= (1 << 14);// enable TX->RX loopback
//WrPHYReg(lp->PhyAddr, PHYREG_MODECTL, phydat);
}
WrPHYReg(lp->PhyAddr, PHYREG_MODECTL, phydat);
udelay(500);
phydat = RdPHYReg(lp->PhyAddr, PHYREG_MODECTL);
// check for SMSC PHY
if ((RdPHYReg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) && ((RdPHYReg(lp->PhyAddr, PHYREG_PHYID2)&0xfff0 ) == 0xC0A0)) {
// we have SMSC PHY so reqest interrupt on link down condition
WrPHYReg(lp->PhyAddr, 30, 0x0ff); // enable interrupts
// enable PHY_INT
sysctl = *pEMAC_SYSCTL;
sysctl |= 0x1;
//*pEMAC_SYSCTL = sysctl;
}
}
/**************************************************************************/
void SetupSystemRegs(struct net_device *dev)
{
int PHYADDR;
unsigned short sysctl, phydat;
struct bf537mac_local *lp = netdev_priv(dev);
PHYADDR = lp->PhyAddr;
/* Enable PHY output */
*pVR_CTL |= PHYCLKOE;
/* MDC = 2.5 MHz */
sysctl = SET_MDCDIV(24);
/* Odd word alignment for Receive Frame DMA word */
/* Configure checksum support and rcve frame word alignment */
sysctl |= RXDWA;
*pEMAC_SYSCTL = sysctl;
/* auto negotiation on */
/* full duplex */
/* 100 Mbps */
phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
WrPHYReg(PHYADDR, PHYREG_MODECTL, phydat);
//*pEMAC_MMC_CTL = RSTC | CROLL | MMCE;
*pEMAC_MMC_CTL = RSTC | CROLL;
/* Initialize the TX DMA channel registers */
*pDMA2_X_COUNT = 0;
*pDMA2_X_MODIFY = 4;
*pDMA2_Y_COUNT = 0;
*pDMA2_Y_MODIFY = 0;
/* Initialize the RX DMA channel registers */
*pDMA1_X_COUNT = 0;
*pDMA1_X_MODIFY = 4;
*pDMA1_Y_COUNT = 0;
*pDMA1_Y_MODIFY = 0;
}
void SetupMacAddr(u8 *mac_addr)
{
// this depends on a little-endian machine
*pEMAC_ADDRLO = *(u32 *)&mac_addr[0];
*pEMAC_ADDRHI = *(u16 *)&mac_addr[4];
}
static void adjust_tx_list(void)
{
int i = 0;
/* current's next can not be the head, otherwise the dma will not stop as we want */
if (current_tx_ptr->next->next == tx_list_head) {
while (tx_list_head->status.status_word == 0) {
udelay(100);
i++;
if (i == 10) {
//printk("tx list error!\n");
i = 0;
tx_list_head->desc_a.config.b_DMA_EN = 0;
tx_list_head = tx_list_head->next;
break;
}
}
}
if ((tx_list_head->status.status_word != 0)) {
tx_list_head->status.status_word = 0;
tx_list_head->desc_a.config.b_DMA_EN = 0;
tx_list_head = tx_list_head->next;
}
}
static int bf537mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
unsigned int data;
/* warning: printk in this function may cause error */
// Is skb->data always 16-bit aligned? Do we need to memcpy((char *)(tail->packet + 2),skb->data,len)?
if ( (((unsigned int)(skb->data))%4) == 2 ) {
//move skb->data to current_tx_ptr payload
data = (unsigned int)(skb->data);
data -= 2;
*((unsigned short *)data) = (unsigned short)(skb->len);
current_tx_ptr->desc_a.start_addr = (unsigned long)data;
blackfin_dcache_invalidate_range(data, (data+(skb->len)) + 2); //this is important!
} else {
*((unsigned short *)(current_tx_ptr->packet)) = (unsigned short)(skb->len);
memcpy((char *)(current_tx_ptr->packet + 2),skb->data,(skb->len));
current_tx_ptr->desc_a.start_addr = (unsigned long)current_tx_ptr->packet;
/*why we need to invalidate uncached memory? */
blackfin_dcache_invalidate_range((unsigned int)current_tx_ptr->packet, (unsigned int)(current_tx_ptr->packet + skb->len) + 2);
}
current_tx_ptr->desc_a.config.b_DMA_EN = 1; //enable this packet's dma
if (*pDMA2_IRQ_STATUS & 0x08) { //tx dma is running, just return
goto out;
} else { //tx dma is not running
*pDMA2_NEXT_DESC_PTR = (&(current_tx_ptr->desc_a));
*pDMA2_CONFIG = *((unsigned short *)(&(current_tx_ptr->desc_a.config)));; // dma enabled, read from memory, size is 6
// Turn on the EMAC tx
*pEMAC_OPMODE |= TE;
}
out:
adjust_tx_list();
current_tx_ptr = current_tx_ptr->next;
dev->trans_start = jiffies;
lp->stats.tx_packets++;
lp->stats.tx_bytes += (skb->len);
dev_kfree_skb(skb);
//printk("sending one...\n");
return 0;
}
static void bf537mac_rx(struct net_device *dev, unsigned char *pkt, int len)
{
struct sk_buff *skb;
struct bf537mac_local *lp = netdev_priv(dev);
skb = dev_alloc_skb(len + 2);
if (!skb) {
printk(KERN_NOTICE "bf537mac rx: low on mem - packet dropped\n");
lp->stats.rx_dropped++;
goto out;
}
skb_reserve(skb, 2);
/*
if (len >= 300) {
printk("going to copy the big packet\n");
for (i=0;i<len;i++){
printk("%.2x-",((unsigned char *)pkt)[i]);
if (((i%8)==0) && (i!=0)) printk("\n");
}
printk("\n");
}
*/
memcpy(skb_put(skb, len), pkt+2, len);
dev->last_rx = jiffies;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
lp->stats.rx_packets++;
lp->stats.rx_bytes += len;
out:
return;
}
/* interrupt routine to handle rx and error signal */
static irqreturn_t bf537mac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
unsigned short len;
// printk("in mac_int\n");
get_one_packet:
if (current_rx_ptr->status.status_word == 0) { // no more new packet received
*pDMA1_IRQ_STATUS |= DMA_DONE|DMA_ERR;
//printk("now return..\n");
return IRQ_HANDLED;
}
len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
bf537mac_rx(dev, (char *)(current_rx_ptr->packet), len);
current_rx_ptr->status.status_word = 0x00000000;
current_rx_ptr = current_rx_ptr->next;
goto get_one_packet;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void bf537mac_poll(struct net_device* dev)
{
disable_irq(IRQ_MAC_RX);
bf537mac_interrupt(IRQ_MAC_RX, dev, NULL);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
static void bf537mac_reset(void)
{
unsigned int opmode;
opmode = *pEMAC_OPMODE;
opmode &= (~RE);
opmode &= (~TE);
/* Turn off the EMAC */
*pEMAC_OPMODE &= opmode;
}
/*
* Enable Interrupts, Receive, and Transmit
*/
static int bf537mac_enable(struct net_device *dev)
{
u32 opmode;
//u32 pkt_status;
//printk("%s: %s\n", dev->name, __FUNCTION__);
/* Set RX DMA */
*pDMA1_NEXT_DESC_PTR = &(rx_list_head->desc_a);
*pDMA1_CONFIG = *((unsigned short *)(&(rx_list_head->desc_a.config)));
/* Wait MII done */
PollMdcDone();
/* We enable only RX here */
/* ASTP : Enable Automatic Pad Stripping
PR : Promiscuous Mode for test
PSF : Receive frames with total length less than 64 bytes.
FDMODE : Full Duplex Mode
LB : Internal Loopback for test
RE : Receiver Enable */
opmode = FDMODE|PSF;
opmode |= RE;
/* Turn on the EMAC rx */
*pEMAC_OPMODE = opmode;
return 0;
}
/* Our watchdog timed out. Called by the networking layer */
static void bf537mac_timeout(struct net_device *dev)
{
//printk("%s: %s\n", dev->name, __FUNCTION__);
bf537mac_reset();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
bf537mac_enable(dev);
/* We can accept TX packets again */
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
/*
* Get the current statistics.
* This may be called with the card open or closed.
*/
static struct net_device_stats *bf537mac_query_statistics(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
//printk("%s: %s\n", dev->name, __FUNCTION__);
return &lp->stats;
}
/*
* This routine will, depending on the values passed to it,
* either make it accept multicast packets, go into
* promiscuous mode (for TCPDUMP and cousins) or accept
* a select set of multicast packets
*/
static void bf537mac_set_multicast_list(struct net_device *dev)
{
u32 sysctl;
if (dev->flags & IFF_PROMISC) {
printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
sysctl = *pEMAC_OPMODE;
sysctl |= RAF;
*pEMAC_OPMODE = sysctl;
} else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) {
/* accept all multicast */
sysctl = *pEMAC_OPMODE;
sysctl |= PAM;
*pEMAC_OPMODE = sysctl;
} else if (dev->mc_count) {
/* set multicast */
} else {
/* clear promisc or multicast mode */
sysctl = *pEMAC_OPMODE;
sysctl &= ~(RAF | PAM);
*pEMAC_OPMODE = sysctl;
}
}
/*
* this puts the device in an inactive state
*/
static void bf537mac_shutdown(struct net_device *dev)
{
/* Turn off the EMAC */
*pEMAC_OPMODE = 0x00000000;
/* Turn off the EMAC RX DMA */
*pDMA1_CONFIG = 0x0000;
*pDMA2_CONFIG = 0x0000;
}
/*
* Open and Initialize the interface
*
* Set up everything, reset the card, etc..
*/
static int bf537mac_open(struct net_device *dev)
{
//printk("%s: %s\n", dev->name, __FUNCTION__);
/*
* Check that the address is valid. If its not, refuse
* to bring the device up. The user must specify an
* address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
*/
if (!is_valid_ether_addr(dev->dev_addr)) {
printk((KERN_DEBUG "bf537mac_open: no valid ethernet hw addr\n"));
return -EINVAL;
}
/* initial rx and tx list */
desc_list_init();
bf537mac_setphy(dev);
SetupSystemRegs(dev);
bf537mac_reset();
bf537mac_enable(dev);
printk("bf537_mac: hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
return 0;
}
/*
*
* this makes the board clean up everything that it can
* and not talk to the outside world. Caused by
* an 'ifconfig ethX down'
*/
static int bf537mac_close(struct net_device *dev)
{
//printk("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
netif_carrier_off(dev);
/* clear everything */
bf537mac_shutdown(dev);
/* free the rx/tx buffers */
desc_list_free();
return 0;
}
static int __init bf537mac_probe(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
int retval;
/* Grab the MAC address in the MAC */
*(u32 *)(&(dev->dev_addr[0])) = *pEMAC_ADDRLO;
*(u16 *)(&(dev->dev_addr[4])) = (u16)*pEMAC_ADDRHI;
/* probe mac */
/*todo: how to proble? which is revision_register */
*pEMAC_ADDRLO = 0x12345678;
if (*pEMAC_ADDRLO != 0x12345678) {
//printk("bf537_mac: can't detect bf537 mac!\n");
retval = -ENODEV;
goto err_out;
}
/*Is it valid? (Did bootloader initialize it?)*/
if (!is_valid_ether_addr(dev->dev_addr)) {
/* Grab the MAC from the board somehow - this is done in the
arch/blackfin/boards/bf537/boardname.c */
get_bf537_ether_addr(dev->dev_addr);
}
/* If still not valid, get a random one */
if (!is_valid_ether_addr(dev->dev_addr)) {
random_ether_addr(dev->dev_addr);
}
SetupMacAddr(dev->dev_addr);
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
dev->open = bf537mac_open;
dev->stop = bf537mac_close;
dev->hard_start_xmit = bf537mac_hard_start_xmit;
dev->tx_timeout = bf537mac_timeout;
dev->get_stats = bf537mac_query_statistics;
dev->set_multicast_list = bf537mac_set_multicast_list;
// dev->ethtool_ops = &bf537mac_ethtool_ops;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = bf537mac_poll;
#endif
/* fill in some of the fields */
lp->version = 1;
lp->PhyAddr = 0x01;
lp->CLKIN = 25;
lp->FullDuplex = 0;
lp->Negotiate = 1;
lp->FlowControl = 0;
// set the GPIO pins to Ethernet mode
SetupPinMux();
/* now, enable interrupts */
/* register irq handler */
if (request_irq(IRQ_MAC_RX, bf537mac_interrupt, SA_INTERRUPT|SA_SHIRQ, "BFIN537_MAC_RX",dev)) {
printk("Unable to attach BlackFin MAC RX interrupt\n");
return -EBUSY;
}
retval = register_netdev(dev);
if (retval == 0) {
/* now, print out the card info, in a short format.. */
printk(KERN_INFO "Blackfin 537 mac net device registered.\n");
}
err_out:
return retval;
}
static int bf537mac_drv_probe(struct device *dev)
{
struct net_device *ndev;
int ret=0;
ndev = alloc_etherdev(sizeof(struct bf537mac_local));
if (!ndev) {
printk("%s: could not allocate device.\n", CARDNAME);
ret = -ENOMEM;
return ret;
}
ret = bf537mac_probe(ndev);
if (ret != 0) {
dev_set_drvdata(dev, NULL);
free_netdev(ndev);
printk("%s: not found (%d).\n", CARDNAME, ret);
}
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, dev);
dev_set_drvdata(dev, ndev);
//printk("bf537_mac: probe finished\n");
return ret;
}
static int bf537mac_drv_remove(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
dev_set_drvdata(dev, NULL);
unregister_netdev(ndev);
free_irq(IRQ_MAC_RX, ndev);
free_netdev(ndev);
return 0;
}
static int bf537mac_drv_suspend(struct device *dev, u32 state, u32 level)
{
return 0;
}
static int bf537mac_drv_resume(struct device *dev, u32 level)
{
return 0;
}
static struct device_driver bf537mac_driver = {
.name = CARDNAME,
.bus = &platform_bus_type,
.probe = bf537mac_drv_probe,
.remove = bf537mac_drv_remove,
.suspend = bf537mac_drv_suspend,
.resume = bf537mac_drv_resume,
};
static int __init bf537mac_init(void)
{
return driver_register(&bf537mac_driver);
}
static void __exit bf537mac_cleanup(void)
{
driver_unregister(&bf537mac_driver);
}
module_init(bf537mac_init);
module_exit(bf537mac_cleanup);
[-- Attachment #3: bfin_mac.h --]
[-- Type: text/plain, Size: 3647 bytes --]
// -----------------------------------------------------------------------
// PHY REGISTER NAMES //
// -----------------------------------------------------------------------
#define PHYREG_MODECTL 0x0000
#define PHYREG_MODESTAT 0x0001
#define PHYREG_PHYID1 0x0002
#define PHYREG_PHYID2 0x0003
#define PHYREG_ANAR 0x0004
#define PHYREG_ANLPAR 0x0005
#define PHYREG_ANER 0x0006
#define PHYREG_NSR 0x0010
#define PHYREG_LBREMR 0x0011
#define PHYREG_REC 0x0012
#define PHYREG_10CFG 0x0013
#define PHYREG_PHY1_1 0x0014
#define PHYREG_PHY1_2 0x0015
#define PHYREG_PHY2 0x0016
#define PHYREG_TW_1 0x0017
#define PHYREG_TW_2 0x0018
#define PHYREG_TEST 0x0019
#define PHY_RESET 0x8000
#define PHY_ANEG_EN 0x1000
#define PHY_DUPLEX 0x0100
#define PHY_SPD_SET 0x2000
typedef struct _DMA_CONFIG
{
unsigned short b_DMA_EN:1; //Bit 0 : DMA Enable
unsigned short b_WNR:1; //Bit 1 : DMA Direction
unsigned short b_WDSIZE:2; //Bit 2 & 3 : DMA Tranfer Word size
unsigned short b_DMA2D:1; //Bit 4 : DMA Mode 2D or 1D
unsigned short b_RESTART:1; //Bit 5 : Retain the FIFO
unsigned short b_DI_SEL:1; //Bit 6 : Data Interrupt Timing Select
unsigned short b_DI_EN:1; //Bit 7 : Data Interrupt Enable
unsigned short b_NDSIZE:4; //Bit 8 to 11 : Flex descriptor Size
unsigned short b_FLOW:3; //Bit 12 to 14 : FLOW
} DMA_CONFIG_REG;
struct dma_descriptor {
struct dma_descriptor *next_dma_desc;
unsigned long start_addr;
DMA_CONFIG_REG config;
unsigned short x_count;
};
/*
struct status_area {
unsigned short ip_hdr_chksum; // the IP header checksum
unsigned short ip_payload_chksum; // the IP header and payload checksum
unsigned long status_word; // the frame status word
};
*/
struct status_area {
unsigned long status_word; // the frame status word
};
/* use two descriptors for a packet */
struct net_dma_desc {
struct net_dma_desc *next;
struct dma_descriptor desc_a;
struct dma_descriptor desc_b;
volatile unsigned char packet[1560];
volatile struct status_area status;
};
struct bf537mac_local {
/*
* these are things that the kernel wants me to keep, so users
* can find out semi-useless statistics of how well the card is
* performing
*/
struct net_device_stats stats;
int version;
int FlowEnabled; // record if data flow is active
int EtherIntIVG; // IVG for the ethernet interrupt
int RXIVG; // IVG for the RX completion
int TXIVG; // IVG for the TX completion
int PhyAddr; // PHY address
int OpMode; // set these bits n the OPMODE regs
int Port10; // set port speed to 10 Mbit/s
int GenChksums; // IP checksums to be calculated
int NoRcveLnth; // dont insert recv length at start of buffer
int StripPads; // remove trailing pad bytes
int FullDuplex; // set full duplex mode
int Negotiate; // enable auto negotiation
int Loopback; // loopback at the PHY
int Cache; // Buffers may be cached
int FlowControl; // flow control active
int CLKIN; // clock in value in MHZ
unsigned short IntMask; // interrupt mask
unsigned char Mac[6]; // MAC address of the board
};
^ permalink raw reply [flat|nested] 11+ messages in thread