Skip to contentSkip to conversation

Xilinx PowerPC

DISCUSSION David H. Lynch Jr. 4 participants 11 messages Apr 20, 2008 – May 19, 2008 4 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw

Thanks,

I have alot of work to do on our stuff, I might as well see if I can
move to the powerpc tree at the same time.

BTW is there even the beginings of a non-xilinx lltemac driver out
there ? There were hints on the list, but I have not seen anything.

I would be happy to help advance the ball on anything anyone has
started.

Quoted 27 lines · Grant Likely
Quoted 9 lines · David H. Lynch Jr.

Thanks.

I am running linus's 2.6.25-rc9, but I can pull the Xilinx tree or
yours - when your server is up.

I can not find any Xilinx powerpc configs in arch/powerpc/config Do I just need to do a
make ARCH=powerpc menuconfig and create one from scratch ?

That's right; I haven't merged any defconfigs. Roll your own.

Quoted 3 lines

Is simpleboot in your tree or the xilinx tree, if can not find it
in Linus's ?

If you want to use the "simpleboot" wrapper; then you'll need to pull paulus' tree (Linus hasn't yet pulled his tree; but he probably will any moment now).

Cheers,
g.

Signature · 8 lines
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email protected] 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
#5 lore raw

I have the start of a lltemac based on the new XPS_LL_TEMAC from EDK 9.2. I'm currently in the process of upgrading my design to 9.2. So I will be very much interested in the driver working ;).

I'll see what I can get cleaned up and posted somewhere, if you'd like to take a look at it.

-- Mike

(sorry for the double post, if it happens but it seems that my last e-mail was blank per my records.)=20

-----Original Message-----
From: David H. Lynch Jr. [mailto:[email protected]]=20
Sent: Sunday, April 20, 2008 7:49 PM
To: Grant Likely
Cc: linuxppc-embedded
Subject: Re: Xilinx PowerPC

Thanks,

I have alot of work to do on our stuff, I might as well see if I can
move to the powerpc tree at the same time.

BTW is there even the beginings of a non-xilinx lltemac driver out
there ? There were hints on the list, but I have not seen anything.

I would be happy to help advance the ball on anything anyone has
started.

=20

Quoted 1 line · Grant Likely

On Sun, Apr 20, 2008 at 2:31 PM, David H. Lynch Jr. <[email protected]>

Quoted 18 lines · wrote:

=20

Quoted 9 lines

Thanks.

I am running linus's 2.6.25-rc9, but I can pull the Xilinx tree=20
or yours - when your server is up.

I can not find any Xilinx powerpc configs in arch/powerpc/config Do I just need to do a
make ARCH=3Dpowerpc menuconfig and create one from scratch ?
=20

That's right; I haven't merged any defconfigs. Roll your own.

=20

Quoted 3 lines

Is simpleboot in your tree or the xilinx tree, if can not find=20
it in Linus's ?
=20

Quoted 8 lines

If you want to use the "simpleboot" wrapper; then you'll need to pull=20 paulus' tree (Linus hasn't yet pulled his tree; but he probably will=20 any moment now).

Cheers,
g.

=20

--=20
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 [email protected] http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein

#6 lore raw

I would be ecstatic to look at/collaborate on what you have.
I do not care if you clean it up. It can not be harder to work with than my own code or the Xilinx code.

In the end I need Linux, GreenHills, as well as a lightweight stripped driver for a monitor and embedded mini-web server.
I have all the above for the older PLB TEMAC in FIFO mode, but we are moving to the LL TEMAC.

I started through the xilinx code and rapidly remembered how long it took to demacrofy the xilinx PLB TEMAC code down to a single source file with only
the code actually needed, and got depressed.

This is critical to us now, so I can put time into it.

If I can figure out how to bring up a git server on my hosting service I am willing to host work on this -
though one of the existing trees might be a better choice.

Quoted 70 lines · Mike (Mission Systems)

I have the start of a lltemac based on the new XPS_LL_TEMAC from EDK 9.2. I'm currently in the process of upgrading my design to 9.2. So I will be very much interested in the driver working ;).

I'll see what I can get cleaned up and posted somewhere, if you'd like to take a look at it.

-- Mike

(sorry for the double post, if it happens but it seems that my last e-mail was blank per my records.)

-----Original Message-----
From: David H. Lynch Jr. [mailto:[email protected]]
Sent: Sunday, April 20, 2008 7:49 PM
To: Grant Likely
Cc: linuxppc-embedded
Subject: Re: Xilinx PowerPC

Thanks,

I have alot of work to do on our stuff, I might as well see if I can
move to the powerpc tree at the same time.

BTW is there even the beginings of a non-xilinx lltemac driver out
there ? There were hints on the list, but I have not seen anything.

I would be happy to help advance the ball on anything anyone has
started.

Quoted 2 lines · Grant Likely

On Sun, Apr 20, 2008 at 2:31 PM, David H. Lynch Jr. <[email protected]>

Quoted 29 lines · wrote:
Quoted 12 lines

Thanks.

I am running linus's 2.6.25-rc9, but I can pull the Xilinx tree
or yours - when your server is up.

I can not find any Xilinx powerpc configs in arch/powerpc/config Do I just need to do a
make ARCH=powerpc menuconfig and create one from scratch ?

That's right; I haven't merged any defconfigs. Roll your own.

Quoted 4 lines

Is simpleboot in your tree or the xilinx tree, if can not find
it in Linus's ?

If you want to use the "simpleboot" wrapper; then you'll need to pull paulus' tree (Linus hasn't yet pulled his tree; but he probably will any moment now).

Cheers,
g.

Signature · 8 lines
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email protected] 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
#7 lore raw
In reply to David H. Lynch Jr.

Hi,

I am writing the Non-Xilinx XPS_LL_TEMAC driver.
Checksum offloading is incomplete although NAPI and KGDBOE are supported. Basic operation is working on EDK9.2 and EDK10.1.

Furthermore, although the simple Non-Interrupt version for u-boot is also written, it is not known where I should post.

Best Regards,

Yoshio Kashiwagi - Nissin Systems

/*
*
* Xilinx Gigabit System Referece Design Ethenet driver
*
* Driver for Xilinx Virtex-4FX Based Platform
*
* Author: Yoshio Kashiwagi
*
* Copyright (c) 2008 Nissin Systems Co.,Ltd.
*
* March 2008 created
*
* This program is free software; you can redistribute it and/or modify
it
* under the terms of the GNU General Public License as published by
the
* Free Software Foundation; either version 2 of the License, or (at
your
* option) any later version.
*
*/

#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/in.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <platforms/4xx/xparameters/xparameters.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/percpu.h>

#define S_DMA_CTRL_BASEADDR XPAR_LLTEMAC_0_LLINK_CONNECTED_BASEADDR
#define XPS_LLTEMAC_BASEADDR XPAR_LLTEMAC_0_BASEADDR

/* XPS_LL_TEMAC SDMA registers definition */

#define TX_NXTDESC_PTR      0x00
#define TX_CURBUF_ADDR      0x04
#define TX_CURBUF_LENGTH    0x08
#define TX_CURDESC_PTR      0x0c
#define TX_TAILDESC_PTR     0x10
#define TX_CHNL_CTRL        0x14

#define TX_IRQ_REG 0x18
#define TX_CHNL_STS 0x1c

#define RX_NXTDESC_PTR      0x20
#define RX_CURBUF_ADDR      0x24
#define RX_CURBUF_LENGTH    0x28
#define RX_CURDESC_PTR      0x2c
#define RX_TAILDESC_PTR     0x30
#define RX_CHNL_CTRL        0x34

#define RX_IRQ_REG 0x38
#define RX_CHNL_STS 0x3c

#define DMA_CONTROL_REG 0x40

/* XPS_LL_TEMAC direct registers definition */

#define TEMAC_RAF0      0x00
#define TEMAC_TPF0      0x04
#define TEMAC_IFGP0     0x08
#define TEMAC_IS0       0x0c
#define TEMAC_IP0       0x10
#define TEMAC_IE0       0x14
#define TEMAC_MSW0      0x20
#define TEMAC_LSW0      0x24
#define TEMAC_CTL0      0x28
#define TEMAC_RDY0      0x2c
#define XTE_RSE_MIIM_RR_MASK      0x0002
#define XTE_RSE_MIIM_WR_MASK      0x0004
#define XTE_RSE_CFG_RR_MASK       0x0020
#define XTE_RSE_CFG_WR_MASK       0x0040

/* XPS_LL_TEMAC indirect registers offset definition */

#define RCW0 0x200
#define RCW1 0x240
#define TC 0x280
#define FCC 0x2c0
#define EMMC 0x300
#define PHYC 0x320
#define MC 0x340

#define UAW0    0x380
#define UAW1    0x384
#define MAW0    0x388
#define MAW1    0x38c

#define AFM 0x390
#define TIS 0x3a0
#define TIE 0x3a4
#define MIIMWD 0x3b0
#define MIIMAI 0x3b4

#define CNTLREG_WRITE_ENABLE_MASK   0x8000
#define CNTLREG_EMAC1SEL_MASK       0x0400
#define CNTLREG_ADDRESSCODE_MASK    0x03ff

#define MDIO_ENABLE_MASK 0x40
#define MDIO_CLOCK_DIV_MASK 0x3F
#define MDIO_CLOCK_DIV_100MHz 0x28

#define ETHER_MTU 1500
#define EMAC_PHY_ID 7

/* CDMAC descriptor status bit definitions */

#define BDSTAT_ERROR_MASK 0x80000000
#define BDSTAT_INT_ON_END_MASK 0x40000000
#define BDSTAT_STOP_ON_END_MASK 0x20000000

#define BDSTAT_COMPLETED_MASK   0x10000000
#define BDSTAT_SOP_MASK         0x08000000
#define BDSTAT_EOP_MASK         0x04000000
#define BDSTAT_CHANBUSY_MASK    0x02000000
#define BDSTAT_CHANRESET_MASK   0x01000000

#define TEMAC_MAC_ADDR_SIZE 6
#define TEMAC_MTU 1500
#define TEMAC_JUMBO_MTU 9000
#define TEMAC_HDR_SIZE 14
#define TEMAC_HDR_VLAN_SIZE 18
#define TEMAC_TRL_SIZE 4
#define TEMAC_MAX_FRAME_SIZE (TEMAC_MTU + TEMAC_HDR_SIZE + TEMAC_
TRL_SIZE)
#define TEMAC_MAX_VLAN_FRAME_SIZE (TEMAC_MTU + TEMAC_HDR_VLAN_SIZE +
TEMAC_TRL_SIZE)
#define TEMAC_MAX_JUMBO_FRAME_SIZE (TEMAC_JUMBO_MTU + TEMAC_HDR_SIZE + TEMAC_TRL_SIZE)

#define TX_CONTROL_CALC_CSUM_MASK 1

#define SDMA_MASTER_IRQ     (1 << 7)
#define SDMA_COA_IRQ        (1)
#define SDMA_DLY_IRQ        (1 << 1)
#define SDMA_ERR_IRQ        (1 << 2)

#define ALIGNMENT 32
#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT)

#define MULTICAST_CAM_TABLE_NUM 4

#define TX_BD_NUM 64
#define RX_BD_NUM 128

#define XEM_MAX_FRAME_SIZE TEMAC_MAX_JUMBO_FRAME_SIZE

#define XILINX_GSRD3_NAPI

#define sdma_reg_write(dev, offset, value) (*(unsigned int *)(dev-> sdma_reg_base + offset) = value)
#define sdma_reg_read(dev, offset) (*(volatile unsigned int *)(dev-> sdma_reg_base + offset))
#define temac_reg_write(dev, offset, value) (*(unsigned int *)(dev-> temac_reg_base + offset) = value)
#define temac_reg_read(dev, offset) (*(volatile unsigned int *)(dev-> temac_reg_base + offset))

struct net_local {
    struct net_device_stats stats;
    struct net_device *next_dev;
    int index;
    unsigned int sdma_reg_base;
    unsigned int temac_reg_base;
    int tx_irq;
    int rx_irq;
    struct timer_list phy_timer;
};
typedef struct cdmac_bd_t {
    struct cdmac_bd_t *next_p;
    unsigned char *phys_buf_p;
    unsigned long buf_len;
    unsigned long app0;
    unsigned long app1;
    unsigned long app2;
    unsigned long app3;
    unsigned long app4;
} cdmac_bd ;
typedef struct cdmac_tx_bd_t {
    cdmac_bd tx_bd[TX_BD_NUM];
} cdmac_tx_bd ;
typedef struct cdmac_rx_bd_t {
    cdmac_bd rx_bd[RX_BD_NUM];
} cdmac_rx_bd ;

static cdmac_tx_bd *cdmac_tx_bd_virt_p;
static cdmac_rx_bd *cdmac_rx_bd_virt_p;
static cdmac_tx_bd *cdmac_tx_bd_phys_p;
static cdmac_rx_bd *cdmac_rx_bd_phys_p;

static struct sk_buff *rx_skb[RX_BD_NUM];

static volatile int cur_tx_bd = 0;
static volatile int next_tx_bd = 0;
static volatile int tail_tx_bd = 0;
static int cur_rx_bd = 0;

static struct net_device *dev_list = NULL;
static spinlock_t dev_lock;
static spinlock_t rcv_lock;
static spinlock_t xmt_lock;

static int xps_ll_temac_xmit(struct sk_buff *skb, struct net_device *dev) ;
static struct net_device_stats *xps_ll_temac_get_stats(struct net_device *dev);

static void xps_ll_temac_hostif_set(struct net_device *dev, int emac, int phy_addr, int reg_addr, int phy_data)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, phy_data);
    temac_reg_write(lp, TEMAC_CTL0, CNTLREG_WRITE_ENABLE_MASK | MIIMWD);
    temac_reg_write(lp, TEMAC_LSW0, ((phy_addr << 5) | (reg_addr)));
    temac_reg_write(lp, TEMAC_CTL0, CNTLREG_WRITE_ENABLE_MASK | MIIMAI | 
(emac << 10));
    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_MIIM_WR_MASK));
}

static unsigned int xps_ll_temac_hostif_get(struct net_device *dev, int emac, int phy_addr, int reg_addr)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, ((phy_addr << 5) | (reg_addr)));
    temac_reg_write(lp, TEMAC_CTL0, MIIMAI | (emac << 10));

    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_MIIM_RR_MASK));
    return temac_reg_read(lp, TEMAC_LSW0);
}

static void xps_ll_temac_indirect_set(struct net_device *dev, int emac, int reg_offset, int reg_data)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, reg_data);
    temac_reg_write(lp, TEMAC_CTL0, (CNTLREG_WRITE_ENABLE_MASK | (emac <

< 10) | reg_offset));

    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_CFG_WR_MASK));
}

static void xps_ll_temac_phy_ctrl(struct net_device *dev)

{
    unsigned int result;

    result = xps_ll_temac_hostif_get(dev, 0, EMAC_PHY_ID, 10);
    if((result & 0x0800) == 0x0800) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x80000000);
        printk("1000BASE-T/FD\n");
        return;
    }
    result = xps_ll_temac_hostif_get(dev, 0, EMAC_PHY_ID, 5);
    if((result & 0x0100) == 0x0100) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x40000000);
        printk("100BASE-T/FD\n");
    } else if((result & 0x0040) == 0x0040) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x00000000);
        printk("10BASE-T/FD\n");
    } else {
        printk("Half Duplex not supported\n");
    }
}

static int xps_ll_temac_set_address(struct net_device *dev, void *p)

{
    struct sockaddr *sa = p;

    memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);

    xps_ll_temac_indirect_set(dev, 0, UAW0, (dev->dev_addr[0] & 
0x000000ff) |
        ((dev->dev_addr[1] << 8) & 0x0000ff00) |
        ((dev->dev_addr[2] << 16)& 0x00ff0000) |
        ((dev->dev_addr[3] << 24) & 0xff000000));
    xps_ll_temac_indirect_set(dev, 0, UAW1, (dev->dev_addr[4] & 
0x000000ff) |
        ((dev->dev_addr[5] << 8) & 0x0000ff00));

    return 0;
}

static void __set_rx_mode (struct net_device *dev)

{
    unsigned long waddr_msw, waddr_lsw;
    int i;

    if(dev->flags & IFF_PROMISC) {
        printk(KERN_NOTICE "%s: Promiscuos mode enabled.\n", dev->name);

        xps_ll_temac_indirect_set(dev, 0, AFM, 0x80000000);
    }  else {
        struct dev_mc_list *mclist;
        for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
            i++, mclist = mclist->next) {

            if(i >= MULTICAST_CAM_TABLE_NUM) break;
            waddr_msw = ((mclist->dmi_addr[3] << 24) | (mclist->dmi_
addr[2] << 16) |
                (mclist->dmi_addr[1] << 8) | mclist->dmi_addr[0]);
            xps_ll_temac_indirect_set(dev, 0, MAW0, waddr_msw);
            waddr_lsw = ((mclist->dmi_addr[5] << 8) | mclist->dmi_addr[4]
);
            waddr_lsw |= (i << 16);
            xps_ll_temac_indirect_set(dev, 0, MAW1, waddr_lsw);
        }
    }
}

static void xps_ll_temac_set_rx_mode (struct net_device *dev)

{
    spin_lock(&dev_lock);
    __set_rx_mode(dev);
    spin_unlock(&dev_lock);
}

static int xps_ll_temac_xmit_done(struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    cdmac_bd *cur_p;
    unsigned int stat = 0;
    unsigned int flags;

    spin_lock_irqsave(&xmt_lock, flags);

    cur_p = &cdmac_tx_bd_virt_p->tx_bd[cur_tx_bd];
    stat = cur_p->app0;

    while(stat & BDSTAT_COMPLETED_MASK) {
        pci_unmap_single(NULL, (unsigned long)cur_p->phys_buf_p,
            cur_p->buf_len, PCI_DMA_TODEVICE);
        if (cur_p->app4)
            dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
        cur_p->app0 = 0;

        lp->stats.tx_packets++;
        lp->stats.tx_bytes += cur_p->buf_len;

        cur_tx_bd++;
        if (cur_tx_bd >= TX_BD_NUM) cur_tx_bd = 0;

        cur_p = &cdmac_tx_bd_virt_p->tx_bd[cur_tx_bd];
        stat = cur_p->app0;
    }

    spin_unlock_irqrestore(&xmt_lock, flags);

    if(netif_queue_stopped(dev)) {
        netif_wake_queue(dev);
    }
}

static int xps_ll_temac_xmit(struct sk_buff *skb, struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    cdmac_bd *cur_p, *start_p, *tail_p;
    int i;
    unsigned long num_frag;
    skb_frag_t *frag;

    spin_lock(&xmt_lock);

    num_frag = skb_shinfo(skb)->nr_frags;
    frag = &skb_shinfo(skb)->frags[0];
    start_p = &cdmac_tx_bd_phys_p->tx_bd[tail_tx_bd];
    cur_p = &cdmac_tx_bd_virt_p->tx_bd[tail_tx_bd];

    if(cur_p->app0 & BDSTAT_COMPLETED_MASK) {
        if(!netif_queue_stopped(dev)) {
            netif_stop_queue(dev);
            spin_unlock(&xmt_lock);
            return NETDEV_TX_BUSY;
        }
        return NETDEV_TX_BUSY;
    }

    cur_p->app0 = 0;
    if(skb->ip_summed == CHECKSUM_PARTIAL) {
        const struct iphdr *ip = skb->nh.iph;
        int length, start, insert, headlen;

        switch(ip->protocol) {
        case IPPROTO_TCP:
            start = sizeof(struct iphdr) + ETH_HLEN;
            insert = sizeof(struct iphdr) + ETH_HLEN + 16;
            length = ip->tot_len - sizeof(struct iphdr);
            headlen = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct 
tcphdr);
            break;
        case IPPROTO_UDP:
            start = sizeof(struct iphdr) + ETH_HLEN;
            insert = sizeof(struct iphdr) + ETH_HLEN + 6;
            length = ip->tot_len - sizeof(struct iphdr);
            headlen = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct 
udphdr);
            break;
        default:
            break;
        }
        cur_p->app1 = ((start << 16) | insert);
        cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr, 
            length, ip->protocol, 0);
        skb->data[insert] = 0;
        skb->data[insert + 1] = 0;
    }
    cur_p->app0 |= BDSTAT_SOP_MASK;
    cur_p->buf_len = skb_headlen(skb);
    cur_p->phys_buf_p = (unsigned char *)pci_map_single(NULL, skb->data, 
skb->len, PCI_DMA_TODEVICE);
    cur_p->app4 = (unsigned long)skb;

    for(i = 0;i < num_frag;i++) {
        tail_tx_bd++;
        if (tail_tx_bd >= TX_BD_NUM) tail_tx_bd = 0;

        cur_p = &cdmac_tx_bd_virt_p->tx_bd[tail_tx_bd];
        cur_p->phys_buf_p = (unsigned char *)pci_map_single(NULL,
            (void *)page_address(frag->page) + frag->page_offset, frag->
size, PCI_DMA_TODEVICE);
        cur_p->buf_len = frag->size;
        cur_p->app0 = 0;
        frag++;
    }
    cur_p->app0 |= BDSTAT_EOP_MASK;

    tail_p = &cdmac_tx_bd_phys_p->tx_bd[tail_tx_bd];
    tail_tx_bd++;
    if (tail_tx_bd >= TX_BD_NUM) tail_tx_bd = 0;

    if(!(sdma_reg_read(lp, TX_CHNL_STS) & 2)) {
        sdma_reg_write(lp, TX_CURDESC_PTR, start_p);
        sdma_reg_write(lp, TX_TAILDESC_PTR, tail_p);    // DMA start 
    } else {
    }

    spin_unlock(&xmt_lock);

    return 0;
}

static int xps_ll_temac_poll(struct net_device *dev, int *budget)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    struct sk_buff *skb, *new_skb;
    unsigned int bdstat;
    unsigned long align;
    cdmac_bd *cur_p, *tail_p;
    int length;
    unsigned long skb_vaddr;
    unsigned int flags;

    tail_p = &cdmac_rx_bd_phys_p->rx_bd[cur_rx_bd];
    cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];

    bdstat = cur_p->app0;
    while((bdstat & BDSTAT_COMPLETED_MASK) && *budget > 0) {

        skb = rx_skb[cur_rx_bd];
        length = cur_p->app4;

        skb_vaddr = virt_to_bus(skb->data);
        pci_unmap_single(NULL, skb_vaddr, length, PCI_DMA_FROMDEVICE);

        skb_put(skb, length);
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;

        netif_receive_skb(skb);
        dev->last_rx = jiffies;

        lp->stats.rx_packets++;
        lp->stats.rx_bytes += length;

        new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(new_skb == 0) {
            printk("no memory for new sk_buff\n");
            spin_unlock_irqrestore(&rcv_lock, flags);
            return -ENOMEM;
        }

        align = BUFFER_ALIGN(new_skb->data);
        if(align) skb_reserve(new_skb, align);

        cur_p->app0 = BDSTAT_INT_ON_END_MASK;
        cur_p->phys_buf_p = (unsigned char *)
                pci_map_single(NULL, new_skb->data,
                           XEM_MAX_FRAME_SIZE,
                           PCI_DMA_FROMDEVICE);
        cur_p->buf_len    = XEM_MAX_FRAME_SIZE;
        rx_skb[cur_rx_bd] = new_skb;

        cur_rx_bd++;
        if(cur_rx_bd >= RX_BD_NUM) cur_rx_bd = 0;

        cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];
        bdstat = cur_p->app0 ;
        (*budget)--;
    }

    netif_rx_complete(dev);
    sdma_reg_write(lp, RX_CHNL_CTRL,
        sdma_reg_read(lp, RX_CHNL_CTRL) | SDMA_MASTER_IRQ);
    sdma_reg_write(lp, RX_TAILDESC_PTR, tail_p);

    return 0;
}

static void xps_ll_temac_recv(struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    struct sk_buff *skb, *new_skb;
    unsigned int bdstat;
    unsigned long align;
    cdmac_bd *cur_p, *tail_p;
    int length;
    unsigned long skb_vaddr;
    unsigned int flags;

    spin_lock_irqsave(&rcv_lock, flags);

    tail_p = &cdmac_rx_bd_phys_p->rx_bd[cur_rx_bd];
    cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];

    bdstat = cur_p->app0;
    while((bdstat & BDSTAT_COMPLETED_MASK)) {

        skb = rx_skb[cur_rx_bd];
        length = cur_p->app4;

        skb_vaddr = virt_to_bus(skb->data);
        pci_unmap_single(NULL, skb_vaddr, length, PCI_DMA_FROMDEVICE);

        skb_put(skb, length);
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;

        netif_rx(skb);

        lp->stats.rx_packets++;
        lp->stats.rx_bytes += length;

        new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(new_skb == 0) {
            printk("no memory for new sk_buff\n");
            spin_unlock_irqrestore(&rcv_lock, flags);
            return;
        }

        align = BUFFER_ALIGN(new_skb->data);
        if(align) skb_reserve(new_skb, align);

        cur_p->app0 = BDSTAT_INT_ON_END_MASK;
        cur_p->phys_buf_p = (unsigned char *)
                    pci_map_single(NULL, new_skb->data,
                               XEM_MAX_FRAME_SIZE,
                               PCI_DMA_FROMDEVICE);
        cur_p->buf_len    = XEM_MAX_FRAME_SIZE;
        rx_skb[cur_rx_bd] = new_skb;

        cur_rx_bd++;
        if(cur_rx_bd >= RX_BD_NUM) cur_rx_bd = 0;

        cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];
        bdstat = cur_p->app0;
    }
    sdma_reg_write(lp, RX_TAILDESC_PTR, tail_p);

    spin_unlock_irqrestore(&rcv_lock, flags);
}

static irqreturn_t
xps_ll_temac_tx_int(int irq, void * dev_id, struct pt_regs *regs)

{
    unsigned int status;
    struct net_device *dev = (struct net_device *)dev_id;
    struct net_local *lp = (struct net_local *)dev->priv;

    status = sdma_reg_read(lp, TX_IRQ_REG);
    sdma_reg_write(lp, TX_IRQ_REG, status);

    if(status & 3) xps_ll_temac_xmit_done(dev);
    if(status & 0x080) printk("DMA error 0x%x\n", status);

    return IRQ_HANDLED;
}

static irqreturn_t
xps_ll_temac_rx_int(int irq, void * dev_id, struct pt_regs *regs)

{
    unsigned int status;
    struct net_device *dev = (struct net_device *)dev_id;
    struct net_local *lp = (struct net_local *)dev->priv;

    status = sdma_reg_read(lp, RX_IRQ_REG);
    sdma_reg_write(lp, RX_IRQ_REG, status);
#ifdef XPS_LL_TEMAC_NAPI
    if(status & 1) {
        if(likely(netif_rx_schedule_prep(dev))) {
            sdma_reg_write(lp, RX_CHNL_CTRL,
                sdma_reg_read(lp, RX_CHNL_CTRL) & ~SDMA_MASTER_IRQ);
            __netif_rx_schedule(dev);
        }
    }
#else
    if(status & 3) xps_ll_temac_recv(dev);

#endif

    return IRQ_HANDLED;
}

static void xps_ll_temac_netpoll(struct net_device *dev)

{
    //struct net_local *lp = (struct net_local *)dev->priv;

    disable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR);
    disable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR);

    xps_ll_temac_rx_int(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR, 
dev, 0);
    xps_ll_temac_tx_int(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR, 

dev, 0);

    enable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR);
    enable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR);
}

static struct net_device_stats *xps_ll_temac_get_stats(struct net_device *dev)

{
    return netdev_priv(dev);
}

static int xps_ll_temac_init_descriptor(void)

{
    struct sk_buff *skb;
    unsigned long align;
    int i;

    cdmac_tx_bd_virt_p = dma_alloc_coherent(NULL, sizeof(struct cdmac_

tx_bd_t),
(dma_addr_t *)&cdmac_tx_bd_phys_p, GFP_KERNEL);
cdmac_rx_bd_virt_p = dma_alloc_coherent(NULL, sizeof(struct cdmac_
rx_bd_t),

        (dma_addr_t *)&cdmac_rx_bd_phys_p, GFP_KERNEL);

    for(i = 0;i < TX_BD_NUM;i++) {
        memset((char *)&cdmac_tx_bd_virt_p->tx_bd[i], 0, sizeof(struct 
cdmac_bd_t));
        if(i == (TX_BD_NUM - 1)) {
            cdmac_tx_bd_virt_p->tx_bd[i].next_p =
                &cdmac_tx_bd_phys_p->tx_bd[0];
        } else {
            cdmac_tx_bd_virt_p->tx_bd[i].next_p =
                &cdmac_tx_bd_phys_p->tx_bd[i + 1];
        }
    }
    for(i = 0;i < RX_BD_NUM;i++) {
        memset((char *)&cdmac_rx_bd_virt_p->rx_bd[i], 0, sizeof(struct 
cdmac_bd_t));
        if(i == (RX_BD_NUM - 1)) {
            cdmac_rx_bd_virt_p->rx_bd[i].next_p =
                &cdmac_rx_bd_phys_p->rx_bd[0];
        } else {
            cdmac_rx_bd_virt_p->rx_bd[i].next_p =
                &cdmac_rx_bd_phys_p->rx_bd[i + 1];
        }
        skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(skb == 0) {
            printk("alloc_skb error %d\n", i);
            return -1;
        }
        rx_skb[i] = skb;
        align = BUFFER_ALIGN(skb->data);
        if(align) skb_reserve(skb, align);

        cdmac_rx_bd_virt_p->rx_bd[i].phys_buf_p =
            (unsigned char *)pci_map_single(NULL,
                skb->data, XEM_MAX_FRAME_SIZE,
                PCI_DMA_FROMDEVICE);
        cdmac_rx_bd_virt_p->rx_bd[i].buf_len = XEM_MAX_FRAME_SIZE;
        cdmac_rx_bd_virt_p->rx_bd[i].app0 = BDSTAT_INT_ON_END_MASK;
    }

    return 0;
}

static int xps_ll_temac_changemtu(struct net_device *dev, int newmtu)

{
        printk("[xilinx_enet]new MTU %d\n", newmtu);
        dev->mtu = newmtu;

        return 0;
}

static int xps_ll_temac_open(struct net_device *dev) {

    return 0;
}

static int xps_ll_temac_close(struct net_device *dev) {

    return 0;
}

static struct net_device **xps_ll_temacs;

static int __init xps_ll_temac_init_one(int index)

{
    struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
    struct net_local *lp;
    int err = 0;

    if (!dev) return -ENOMEM;

    sprintf(dev->name, "eth%d", index);

    /* Initialize the device structure. */
    dev->get_stats = xps_ll_temac_get_stats;
    dev->hard_start_xmit = xps_ll_temac_xmit;
    dev->open = xps_ll_temac_open;
    dev->stop = xps_ll_temac_close;
#ifdef XPS_LL_TEMAC_NAPI
    dev->poll = &xps_ll_temac_poll;
#endif
    dev->weight = 64;
    dev->set_multicast_list = &xps_ll_temac_set_rx_mode;
    dev->set_mac_address = xps_ll_temac_set_address;
    dev->poll_controller = xps_ll_temac_netpoll;

    SET_MODULE_OWNER(dev);
#if 1
//  dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
//      | NETIF_F_IP_CSUM;
    dev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
#else
    dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
        | NETIF_F_TSO | NETIF_F_IP_CSUM;

#endif

    ether_setup(dev);

    lp = (struct net_local *)dev->priv;
    memset(lp, 0, sizeof(struct net_local));
    lp->index = index;

    lp->next_dev = dev_list;
    lp->sdma_reg_base = ioremap(S_DMA_CTRL_BASEADDR, 128);
    lp->temac_reg_base = ioremap(XPS_LLTEMAC_BASEADDR, 128);

    dev_list = dev;

    dev->tx_queue_len = 0;
    dev->change_mtu = xps_ll_temac_changemtu;

    sdma_reg_write(lp, DMA_CONTROL_REG, 1);

    printk(KERN_INFO "%s: Xilinx Embedded Tri-Mode Ethernet MAC\n", dev-
Quoted 1 line

name);

    xps_ll_temac_init_descriptor();

    dev->dev_addr[0] = 0x00;
    dev->dev_addr[1] = 0x80;
    dev->dev_addr[2] = 0x49;
    dev->dev_addr[3] = 0x00;
    dev->dev_addr[4] = 0x00;
    dev->dev_addr[5] = 0x00;

    request_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR,
        &xps_ll_temac_tx_int, 0, dev->name, dev);
    request_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR,
        &xps_ll_temac_rx_int, 0, dev->name, dev);

    xps_ll_temac_indirect_set(dev, 0, MC, MDIO_ENABLE_MASK | MDIO_CLOCK_

DIV_100MHz);

    xps_ll_temac_indirect_set(dev, 0, RCW1, 0x10000000);    // Enable 
Receiver
    xps_ll_temac_indirect_set(dev, 0, TC, 0x10000000);  // Enable 
Transmitter
    xps_ll_temac_indirect_set(dev, 0, EMMC, 0x84000000);

    xps_ll_temac_indirect_set(dev, 0, UAW0, (dev->dev_addr[0] & 
0x000000ff) |
        ((dev->dev_addr[1] << 8) & 0x0000ff00) |
        ((dev->dev_addr[2] << 16)& 0x00ff0000) |
        ((dev->dev_addr[3] << 24) & 0xff000000));
    xps_ll_temac_indirect_set(dev, 0, UAW1, (dev->dev_addr[4] & 
0x000000ff) |
        ((dev->dev_addr[5] << 8) & 0x0000ff00));

    xps_ll_temac_indirect_set(dev, 0, AFM, 0x00000000);

    xps_ll_temac_phy_ctrl(dev);

    sdma_reg_write(lp, TX_CHNL_CTRL, 0x10220483);
    //sdma_reg_write(lp, TX_CHNL_CTRL, 0x00100483);
    sdma_reg_write(lp, RX_CHNL_CTRL, 0xff010283);

    sdma_reg_write(lp, RX_CURDESC_PTR, (unsigned int)&cdmac_rx_bd_phys_

p->rx_bd[0]);
sdma_reg_write(lp, RX_TAILDESC_PTR, (unsigned int)&cdmac_rx_bd_phys_
p->rx_bd[RX_BD_NUM - 1]);

    if ((err = register_netdev(dev))) {
        free_netdev(dev);
        dev = NULL;
    } else {
        xps_ll_temacs[index] = dev;
    }

    return 0;
}

static void xps_ll_temac_free_one(int index)

{
    unregister_netdev(xps_ll_temacs[index]);
    free_netdev(xps_ll_temacs[index]);
}

static int __init xps_ll_temac_init_module(void)

{
    int err = 0;

    xps_ll_temacs = kmalloc(sizeof(void *), GFP_KERNEL);

    if (!xps_ll_temacs) return -ENOMEM;

    spin_lock_init(&dev_lock);
    spin_lock_init(&rcv_lock);
    spin_lock_init(&xmt_lock);

    if((err = xps_ll_temac_init_one(0))) xps_ll_temac_free_one(0);

    return err;
}

static void __exit xps_ll_temac_cleanup_module(void)

{
    xps_ll_temac_free_one(0);
    kfree(xps_ll_temacs);
}

module_init(xps_ll_temac_init_module);
module_exit(xps_ll_temac_cleanup_module);
MODULE_LICENSE("GPL");

Quoted 3 lines

Thanks,

I have alot of work to do on our stuff, I might as well see if I

can

Quoted 5 lines

move to the powerpc tree at the same time.

BTW is there even the beginings of a non-xilinx lltemac driver out
there ? There were hints on the list, but I have not seen anything.

Quoted 12 lines

I would be happy to help advance the ball on anything anyone has
started.

Quoted 1 line · Grant Likely

On Sun, Apr 20, 2008 at 2:31 PM, David H. Lynch Jr. <[email protected]

Quoted 4 lines · wrote:
Quoted 4 lines

Thanks.

I am running linus's 2.6.25-rc9, but I can pull the Xilinx tree

or

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

yours - when your server is up.

I can not find any Xilinx powerpc configs in arch/powerpc/

config

Quoted 8 lines
Quoted 8 lines
Quoted 3 lines

Do I just need to do a
make ARCH=powerpc menuconfig and create one from scratch ?

That's right; I haven't merged any defconfigs. Roll your own.

Quoted 1 line

Is simpleboot in your tree or the xilinx tree, if can not find

it

Quoted 4 lines
Quoted 4 lines
Quoted 2 lines

in Linus's ?

If you want to use the "simpleboot" wrapper; then you'll need to

pull

Quoted 15 lines
Quoted 7 lines

paulus' tree (Linus hasn't yet pulled his tree; but he probably will any moment now).

Cheers,
g.

Signature · 5 lines
Dave Lynch                            DLA Systems
Software Development:                          Embedded Linux
717.627.3770         [email protected]       http://www.dlasys.net
fax: 1.253.369.9244                      Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies 

too numerous to list.

Quoted 2 lines

"Any intelligent fool can make things bigger and more complex... It

takes a touch of genius - and a lot of courage to move in the opposite direction."

Quoted 7 lines

Albert Einstein

_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

※ 4月から所属・部署が変更になりました
------------------------------------------------------------------
柏木良夫
株式会社日新システムズ 東日本営業部

本 社 〒600-8482 京都市下京区堀川通四条下ル東側 堀川四条ビル
TEL 075-344-7977 FAX 075-344-7887
東京事務所 〒101-0024 東京都千代田区神田和泉町1番地 神田和泉町ビル
TEL 03-5825-2081 FAX 03-5821-1259
E-Mail [email protected] HTTP http://www.co-nss.co.jp/
------------------------------------------------------------------

#8 lore raw

Thanks alot.
On quick review this looks great. I will see if I can get it working for me this weekend.

Quoted 12 lines · Yoshio Kashiwagi

Hi,

I am writing the Non-Xilinx XPS_LL_TEMAC driver.
Checksum offloading is incomplete although NAPI and KGDBOE are supported. Basic operation is working on EDK9.2 and EDK10.1.

Furthermore, although the simple Non-Interrupt version for u-boot is also written, it is not known where I should post.

Best Regards,

Yoshio Kashiwagi - Nissin Systems

Signature · 8 lines
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email protected] 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
#9 lore raw
In reply to Yoshio Kashiwagi

I was able to incorporate Yoshio's driver and make use of it.
It is a single file, fairly short, easy to understand, mostly conforming to linux kernel programming style. While it needs some work fo NAPI and OF, it is usable as it is.

I would be happy to see it form the starting point for a distribution LL TEMAC driver.

If Yoshio does not wish to put together a patch, for it I can, however, I have made some name changes and restructing to compare to my older PLB TEMAC.

Quoted 989 lines · Yoshio Kashiwagi

Hi,

I am writing the Non-Xilinx XPS_LL_TEMAC driver.
Checksum offloading is incomplete although NAPI and KGDBOE are supported. Basic operation is working on EDK9.2 and EDK10.1.

Furthermore, although the simple Non-Interrupt version for u-boot is also written, it is not known where I should post.

Best Regards,

Yoshio Kashiwagi - Nissin Systems

/*
*
* Xilinx Gigabit System Referece Design Ethenet driver
*
* Driver for Xilinx Virtex-4FX Based Platform
*
* Author: Yoshio Kashiwagi
*
* Copyright (c) 2008 Nissin Systems Co.,Ltd.
*
* March 2008 created
*
* This program is free software; you can redistribute it and/or modify
it
* under the terms of the GNU General Public License as published by
the
* Free Software Foundation; either version 2 of the License, or (at
your
* option) any later version.
*
*/

#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/in.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <platforms/4xx/xparameters/xparameters.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/percpu.h>

#define S_DMA_CTRL_BASEADDR XPAR_LLTEMAC_0_LLINK_CONNECTED_BASEADDR
#define XPS_LLTEMAC_BASEADDR XPAR_LLTEMAC_0_BASEADDR

/* XPS_LL_TEMAC SDMA registers definition */

#define TX_NXTDESC_PTR      0x00
#define TX_CURBUF_ADDR      0x04
#define TX_CURBUF_LENGTH    0x08
#define TX_CURDESC_PTR      0x0c
#define TX_TAILDESC_PTR     0x10
#define TX_CHNL_CTRL        0x14

#define TX_IRQ_REG 0x18
#define TX_CHNL_STS 0x1c

#define RX_NXTDESC_PTR      0x20
#define RX_CURBUF_ADDR      0x24
#define RX_CURBUF_LENGTH    0x28
#define RX_CURDESC_PTR      0x2c
#define RX_TAILDESC_PTR     0x30
#define RX_CHNL_CTRL        0x34

#define RX_IRQ_REG 0x38
#define RX_CHNL_STS 0x3c

#define DMA_CONTROL_REG 0x40

/* XPS_LL_TEMAC direct registers definition */

#define TEMAC_RAF0      0x00
#define TEMAC_TPF0      0x04
#define TEMAC_IFGP0     0x08
#define TEMAC_IS0       0x0c
#define TEMAC_IP0       0x10
#define TEMAC_IE0       0x14
#define TEMAC_MSW0      0x20
#define TEMAC_LSW0      0x24
#define TEMAC_CTL0      0x28
#define TEMAC_RDY0      0x2c
#define XTE_RSE_MIIM_RR_MASK      0x0002
#define XTE_RSE_MIIM_WR_MASK      0x0004
#define XTE_RSE_CFG_RR_MASK       0x0020
#define XTE_RSE_CFG_WR_MASK       0x0040

/* XPS_LL_TEMAC indirect registers offset definition */

#define RCW0 0x200
#define RCW1 0x240
#define TC 0x280
#define FCC 0x2c0
#define EMMC 0x300
#define PHYC 0x320
#define MC 0x340

#define UAW0    0x380
#define UAW1    0x384
#define MAW0    0x388
#define MAW1    0x38c

#define AFM 0x390
#define TIS 0x3a0
#define TIE 0x3a4
#define MIIMWD 0x3b0
#define MIIMAI 0x3b4

#define CNTLREG_WRITE_ENABLE_MASK   0x8000
#define CNTLREG_EMAC1SEL_MASK       0x0400
#define CNTLREG_ADDRESSCODE_MASK    0x03ff

#define MDIO_ENABLE_MASK 0x40
#define MDIO_CLOCK_DIV_MASK 0x3F
#define MDIO_CLOCK_DIV_100MHz 0x28

#define ETHER_MTU 1500
#define EMAC_PHY_ID 7

/* CDMAC descriptor status bit definitions */

#define BDSTAT_ERROR_MASK 0x80000000
#define BDSTAT_INT_ON_END_MASK 0x40000000
#define BDSTAT_STOP_ON_END_MASK 0x20000000

#define BDSTAT_COMPLETED_MASK   0x10000000
#define BDSTAT_SOP_MASK         0x08000000
#define BDSTAT_EOP_MASK         0x04000000
#define BDSTAT_CHANBUSY_MASK    0x02000000
#define BDSTAT_CHANRESET_MASK   0x01000000

#define TEMAC_MAC_ADDR_SIZE 6
#define TEMAC_MTU 1500
#define TEMAC_JUMBO_MTU 9000
#define TEMAC_HDR_SIZE 14
#define TEMAC_HDR_VLAN_SIZE 18
#define TEMAC_TRL_SIZE 4
#define TEMAC_MAX_FRAME_SIZE (TEMAC_MTU + TEMAC_HDR_SIZE + TEMAC_
TRL_SIZE)
#define TEMAC_MAX_VLAN_FRAME_SIZE (TEMAC_MTU + TEMAC_HDR_VLAN_SIZE +
TEMAC_TRL_SIZE)
#define TEMAC_MAX_JUMBO_FRAME_SIZE (TEMAC_JUMBO_MTU + TEMAC_HDR_SIZE + TEMAC_TRL_SIZE)

#define TX_CONTROL_CALC_CSUM_MASK 1

#define SDMA_MASTER_IRQ     (1 << 7)
#define SDMA_COA_IRQ        (1)
#define SDMA_DLY_IRQ        (1 << 1)
#define SDMA_ERR_IRQ        (1 << 2)

#define ALIGNMENT 32
#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT)

#define MULTICAST_CAM_TABLE_NUM 4

#define TX_BD_NUM 64
#define RX_BD_NUM 128

#define XEM_MAX_FRAME_SIZE TEMAC_MAX_JUMBO_FRAME_SIZE

#define XILINX_GSRD3_NAPI

#define sdma_reg_write(dev, offset, value) (*(unsigned int *)(dev-> sdma_reg_base + offset) = value)
#define sdma_reg_read(dev, offset) (*(volatile unsigned int *)(dev-> sdma_reg_base + offset))
#define temac_reg_write(dev, offset, value) (*(unsigned int *)(dev-> temac_reg_base + offset) = value)
#define temac_reg_read(dev, offset) (*(volatile unsigned int *)(dev-> temac_reg_base + offset))

struct net_local {
    struct net_device_stats stats;
    struct net_device *next_dev;
    int index;
    unsigned int sdma_reg_base;
    unsigned int temac_reg_base;
    int tx_irq;
    int rx_irq;
    struct timer_list phy_timer;
};
typedef struct cdmac_bd_t {
    struct cdmac_bd_t *next_p;
    unsigned char *phys_buf_p;
    unsigned long buf_len;
    unsigned long app0;
    unsigned long app1;
    unsigned long app2;
    unsigned long app3;
    unsigned long app4;
} cdmac_bd ;
typedef struct cdmac_tx_bd_t {
    cdmac_bd tx_bd[TX_BD_NUM];
} cdmac_tx_bd ;
typedef struct cdmac_rx_bd_t {
    cdmac_bd rx_bd[RX_BD_NUM];
} cdmac_rx_bd ;

static cdmac_tx_bd *cdmac_tx_bd_virt_p;
static cdmac_rx_bd *cdmac_rx_bd_virt_p;
static cdmac_tx_bd *cdmac_tx_bd_phys_p;
static cdmac_rx_bd *cdmac_rx_bd_phys_p;

static struct sk_buff *rx_skb[RX_BD_NUM];

static volatile int cur_tx_bd = 0;
static volatile int next_tx_bd = 0;
static volatile int tail_tx_bd = 0;
static int cur_rx_bd = 0;

static struct net_device *dev_list = NULL;
static spinlock_t dev_lock;
static spinlock_t rcv_lock;
static spinlock_t xmt_lock;

static int xps_ll_temac_xmit(struct sk_buff *skb, struct net_device *dev) ;
static struct net_device_stats *xps_ll_temac_get_stats(struct net_device *dev);

static void xps_ll_temac_hostif_set(struct net_device *dev, int emac, int phy_addr, int reg_addr, int phy_data)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, phy_data);
    temac_reg_write(lp, TEMAC_CTL0, CNTLREG_WRITE_ENABLE_MASK | MIIMWD);
    temac_reg_write(lp, TEMAC_LSW0, ((phy_addr << 5) | (reg_addr)));
    temac_reg_write(lp, TEMAC_CTL0, CNTLREG_WRITE_ENABLE_MASK | MIIMAI | 
(emac << 10));
    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_MIIM_WR_MASK));
}

static unsigned int xps_ll_temac_hostif_get(struct net_device *dev, int emac, int phy_addr, int reg_addr)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, ((phy_addr << 5) | (reg_addr)));
    temac_reg_write(lp, TEMAC_CTL0, MIIMAI | (emac << 10));

    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_MIIM_RR_MASK));
    return temac_reg_read(lp, TEMAC_LSW0);
}

static void xps_ll_temac_indirect_set(struct net_device *dev, int emac, int reg_offset, int reg_data)

{
    struct net_local *lp = (struct net_local *)dev->priv;

    temac_reg_write(lp, TEMAC_LSW0, reg_data);
    temac_reg_write(lp, TEMAC_CTL0, (CNTLREG_WRITE_ENABLE_MASK | (emac <

< 10) | reg_offset));

    while(!(temac_reg_read(lp, TEMAC_RDY0) & XTE_RSE_CFG_WR_MASK));
}

static void xps_ll_temac_phy_ctrl(struct net_device *dev)

{
    unsigned int result;

    result = xps_ll_temac_hostif_get(dev, 0, EMAC_PHY_ID, 10);
    if((result & 0x0800) == 0x0800) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x80000000);
        printk("1000BASE-T/FD\n");
        return;
    }
    result = xps_ll_temac_hostif_get(dev, 0, EMAC_PHY_ID, 5);
    if((result & 0x0100) == 0x0100) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x40000000);
        printk("100BASE-T/FD\n");
    } else if((result & 0x0040) == 0x0040) {
        xps_ll_temac_indirect_set(dev, 0, EMMC, 0x00000000);
        printk("10BASE-T/FD\n");
    } else {
        printk("Half Duplex not supported\n");
    }
}

static int xps_ll_temac_set_address(struct net_device *dev, void *p)

{
    struct sockaddr *sa = p;

    memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);

    xps_ll_temac_indirect_set(dev, 0, UAW0, (dev->dev_addr[0] & 
0x000000ff) |
        ((dev->dev_addr[1] << 8) & 0x0000ff00) |
        ((dev->dev_addr[2] << 16)& 0x00ff0000) |
        ((dev->dev_addr[3] << 24) & 0xff000000));
    xps_ll_temac_indirect_set(dev, 0, UAW1, (dev->dev_addr[4] & 
0x000000ff) |
        ((dev->dev_addr[5] << 8) & 0x0000ff00));

    return 0;
}

static void __set_rx_mode (struct net_device *dev)

{
    unsigned long waddr_msw, waddr_lsw;
    int i;

    if(dev->flags & IFF_PROMISC) {
        printk(KERN_NOTICE "%s: Promiscuos mode enabled.\n", dev->name);

        xps_ll_temac_indirect_set(dev, 0, AFM, 0x80000000);
    }  else {
        struct dev_mc_list *mclist;
        for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
            i++, mclist = mclist->next) {

            if(i >= MULTICAST_CAM_TABLE_NUM) break;
            waddr_msw = ((mclist->dmi_addr[3] << 24) | (mclist->dmi_
addr[2] << 16) |
                (mclist->dmi_addr[1] << 8) | mclist->dmi_addr[0]);
            xps_ll_temac_indirect_set(dev, 0, MAW0, waddr_msw);
            waddr_lsw = ((mclist->dmi_addr[5] << 8) | mclist->dmi_addr[4]
);
            waddr_lsw |= (i << 16);
            xps_ll_temac_indirect_set(dev, 0, MAW1, waddr_lsw);
        }
    }
}

static void xps_ll_temac_set_rx_mode (struct net_device *dev)

{
    spin_lock(&dev_lock);
    __set_rx_mode(dev);
    spin_unlock(&dev_lock);
}

static int xps_ll_temac_xmit_done(struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    cdmac_bd *cur_p;
    unsigned int stat = 0;
    unsigned int flags;

    spin_lock_irqsave(&xmt_lock, flags);

    cur_p = &cdmac_tx_bd_virt_p->tx_bd[cur_tx_bd];
    stat = cur_p->app0;

    while(stat & BDSTAT_COMPLETED_MASK) {
        pci_unmap_single(NULL, (unsigned long)cur_p->phys_buf_p,
            cur_p->buf_len, PCI_DMA_TODEVICE);
        if (cur_p->app4)
            dev_kfree_skb_irq((struct sk_buff *)cur_p->app4);
        cur_p->app0 = 0;

        lp->stats.tx_packets++;
        lp->stats.tx_bytes += cur_p->buf_len;

        cur_tx_bd++;
        if (cur_tx_bd >= TX_BD_NUM) cur_tx_bd = 0;

        cur_p = &cdmac_tx_bd_virt_p->tx_bd[cur_tx_bd];
        stat = cur_p->app0;
    }

    spin_unlock_irqrestore(&xmt_lock, flags);

    if(netif_queue_stopped(dev)) {
        netif_wake_queue(dev);
    }
}

static int xps_ll_temac_xmit(struct sk_buff *skb, struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    cdmac_bd *cur_p, *start_p, *tail_p;
    int i;
    unsigned long num_frag;
    skb_frag_t *frag;

    spin_lock(&xmt_lock);

    num_frag = skb_shinfo(skb)->nr_frags;
    frag = &skb_shinfo(skb)->frags[0];
    start_p = &cdmac_tx_bd_phys_p->tx_bd[tail_tx_bd];
    cur_p = &cdmac_tx_bd_virt_p->tx_bd[tail_tx_bd];

    if(cur_p->app0 & BDSTAT_COMPLETED_MASK) {
        if(!netif_queue_stopped(dev)) {
            netif_stop_queue(dev);
            spin_unlock(&xmt_lock);
            return NETDEV_TX_BUSY;
        }
        return NETDEV_TX_BUSY;
    }

    cur_p->app0 = 0;
    if(skb->ip_summed == CHECKSUM_PARTIAL) {
        const struct iphdr *ip = skb->nh.iph;
        int length, start, insert, headlen;

        switch(ip->protocol) {
        case IPPROTO_TCP:
            start = sizeof(struct iphdr) + ETH_HLEN;
            insert = sizeof(struct iphdr) + ETH_HLEN + 16;
            length = ip->tot_len - sizeof(struct iphdr);
            headlen = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct 
tcphdr);
            break;
        case IPPROTO_UDP:
            start = sizeof(struct iphdr) + ETH_HLEN;
            insert = sizeof(struct iphdr) + ETH_HLEN + 6;
            length = ip->tot_len - sizeof(struct iphdr);
            headlen = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct 
udphdr);
            break;
        default:
            break;
        }
        cur_p->app1 = ((start << 16) | insert);
        cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr, 
            length, ip->protocol, 0);
        skb->data[insert] = 0;
        skb->data[insert + 1] = 0;
    }
    cur_p->app0 |= BDSTAT_SOP_MASK;
    cur_p->buf_len = skb_headlen(skb);
    cur_p->phys_buf_p = (unsigned char *)pci_map_single(NULL, skb->data, 
skb->len, PCI_DMA_TODEVICE);
    cur_p->app4 = (unsigned long)skb;

    for(i = 0;i < num_frag;i++) {
        tail_tx_bd++;
        if (tail_tx_bd >= TX_BD_NUM) tail_tx_bd = 0;

        cur_p = &cdmac_tx_bd_virt_p->tx_bd[tail_tx_bd];
        cur_p->phys_buf_p = (unsigned char *)pci_map_single(NULL,
            (void *)page_address(frag->page) + frag->page_offset, frag->
size, PCI_DMA_TODEVICE);
        cur_p->buf_len = frag->size;
        cur_p->app0 = 0;
        frag++;
    }
    cur_p->app0 |= BDSTAT_EOP_MASK;

    tail_p = &cdmac_tx_bd_phys_p->tx_bd[tail_tx_bd];
    tail_tx_bd++;
    if (tail_tx_bd >= TX_BD_NUM) tail_tx_bd = 0;

    if(!(sdma_reg_read(lp, TX_CHNL_STS) & 2)) {
        sdma_reg_write(lp, TX_CURDESC_PTR, start_p);
        sdma_reg_write(lp, TX_TAILDESC_PTR, tail_p);    // DMA start 
    } else {
    }

    spin_unlock(&xmt_lock);

    return 0;
}

static int xps_ll_temac_poll(struct net_device *dev, int *budget)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    struct sk_buff *skb, *new_skb;
    unsigned int bdstat;
    unsigned long align;
    cdmac_bd *cur_p, *tail_p;
    int length;
    unsigned long skb_vaddr;
    unsigned int flags;

    tail_p = &cdmac_rx_bd_phys_p->rx_bd[cur_rx_bd];
    cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];

    bdstat = cur_p->app0;
    while((bdstat & BDSTAT_COMPLETED_MASK) && *budget > 0) {

        skb = rx_skb[cur_rx_bd];
        length = cur_p->app4;

        skb_vaddr = virt_to_bus(skb->data);
        pci_unmap_single(NULL, skb_vaddr, length, PCI_DMA_FROMDEVICE);

        skb_put(skb, length);
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;

        netif_receive_skb(skb);
        dev->last_rx = jiffies;

        lp->stats.rx_packets++;
        lp->stats.rx_bytes += length;

        new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(new_skb == 0) {
            printk("no memory for new sk_buff\n");
            spin_unlock_irqrestore(&rcv_lock, flags);
            return -ENOMEM;
        }

        align = BUFFER_ALIGN(new_skb->data);
        if(align) skb_reserve(new_skb, align);

        cur_p->app0 = BDSTAT_INT_ON_END_MASK;
        cur_p->phys_buf_p = (unsigned char *)
                pci_map_single(NULL, new_skb->data,
                           XEM_MAX_FRAME_SIZE,
                           PCI_DMA_FROMDEVICE);
        cur_p->buf_len    = XEM_MAX_FRAME_SIZE;
        rx_skb[cur_rx_bd] = new_skb;

        cur_rx_bd++;
        if(cur_rx_bd >= RX_BD_NUM) cur_rx_bd = 0;

        cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];
        bdstat = cur_p->app0 ;
        (*budget)--;
    }

    netif_rx_complete(dev);
    sdma_reg_write(lp, RX_CHNL_CTRL,
        sdma_reg_read(lp, RX_CHNL_CTRL) | SDMA_MASTER_IRQ);
    sdma_reg_write(lp, RX_TAILDESC_PTR, tail_p);

    return 0;
}

static void xps_ll_temac_recv(struct net_device *dev)

{
    struct net_local *lp = (struct net_local *)dev->priv;
    struct sk_buff *skb, *new_skb;
    unsigned int bdstat;
    unsigned long align;
    cdmac_bd *cur_p, *tail_p;
    int length;
    unsigned long skb_vaddr;
    unsigned int flags;

    spin_lock_irqsave(&rcv_lock, flags);

    tail_p = &cdmac_rx_bd_phys_p->rx_bd[cur_rx_bd];
    cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];

    bdstat = cur_p->app0;
    while((bdstat & BDSTAT_COMPLETED_MASK)) {

        skb = rx_skb[cur_rx_bd];
        length = cur_p->app4;

        skb_vaddr = virt_to_bus(skb->data);
        pci_unmap_single(NULL, skb_vaddr, length, PCI_DMA_FROMDEVICE);

        skb_put(skb, length);
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;

        netif_rx(skb);

        lp->stats.rx_packets++;
        lp->stats.rx_bytes += length;

        new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(new_skb == 0) {
            printk("no memory for new sk_buff\n");
            spin_unlock_irqrestore(&rcv_lock, flags);
            return;
        }

        align = BUFFER_ALIGN(new_skb->data);
        if(align) skb_reserve(new_skb, align);

        cur_p->app0 = BDSTAT_INT_ON_END_MASK;
        cur_p->phys_buf_p = (unsigned char *)
                    pci_map_single(NULL, new_skb->data,
                               XEM_MAX_FRAME_SIZE,
                               PCI_DMA_FROMDEVICE);
        cur_p->buf_len    = XEM_MAX_FRAME_SIZE;
        rx_skb[cur_rx_bd] = new_skb;

        cur_rx_bd++;
        if(cur_rx_bd >= RX_BD_NUM) cur_rx_bd = 0;

        cur_p = &cdmac_rx_bd_virt_p->rx_bd[cur_rx_bd];
        bdstat = cur_p->app0;
    }
    sdma_reg_write(lp, RX_TAILDESC_PTR, tail_p);

    spin_unlock_irqrestore(&rcv_lock, flags);
}

static irqreturn_t
xps_ll_temac_tx_int(int irq, void * dev_id, struct pt_regs *regs)

{
    unsigned int status;
    struct net_device *dev = (struct net_device *)dev_id;
    struct net_local *lp = (struct net_local *)dev->priv;

    status = sdma_reg_read(lp, TX_IRQ_REG);
    sdma_reg_write(lp, TX_IRQ_REG, status);

    if(status & 3) xps_ll_temac_xmit_done(dev);
    if(status & 0x080) printk("DMA error 0x%x\n", status);

    return IRQ_HANDLED;
}

static irqreturn_t
xps_ll_temac_rx_int(int irq, void * dev_id, struct pt_regs *regs)

{
    unsigned int status;
    struct net_device *dev = (struct net_device *)dev_id;
    struct net_local *lp = (struct net_local *)dev->priv;

    status = sdma_reg_read(lp, RX_IRQ_REG);
    sdma_reg_write(lp, RX_IRQ_REG, status);
#ifdef XPS_LL_TEMAC_NAPI
    if(status & 1) {
        if(likely(netif_rx_schedule_prep(dev))) {
            sdma_reg_write(lp, RX_CHNL_CTRL,
                sdma_reg_read(lp, RX_CHNL_CTRL) & ~SDMA_MASTER_IRQ);
            __netif_rx_schedule(dev);
        }
    }
#else
    if(status & 3) xps_ll_temac_recv(dev);

#endif

    return IRQ_HANDLED;
}

static void xps_ll_temac_netpoll(struct net_device *dev)

{
    //struct net_local *lp = (struct net_local *)dev->priv;

    disable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR);
    disable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR);

    xps_ll_temac_rx_int(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR, 
dev, 0);
    xps_ll_temac_tx_int(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR, 

dev, 0);

    enable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR);
    enable_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR);
}

static struct net_device_stats *xps_ll_temac_get_stats(struct net_device *dev)

{
    return netdev_priv(dev);
}

static int xps_ll_temac_init_descriptor(void)

{
    struct sk_buff *skb;
    unsigned long align;
    int i;

    cdmac_tx_bd_virt_p = dma_alloc_coherent(NULL, sizeof(struct cdmac_

tx_bd_t),
(dma_addr_t *)&cdmac_tx_bd_phys_p, GFP_KERNEL);
cdmac_rx_bd_virt_p = dma_alloc_coherent(NULL, sizeof(struct cdmac_
rx_bd_t),

        (dma_addr_t *)&cdmac_rx_bd_phys_p, GFP_KERNEL);

    for(i = 0;i < TX_BD_NUM;i++) {
        memset((char *)&cdmac_tx_bd_virt_p->tx_bd[i], 0, sizeof(struct 
cdmac_bd_t));
        if(i == (TX_BD_NUM - 1)) {
            cdmac_tx_bd_virt_p->tx_bd[i].next_p =
                &cdmac_tx_bd_phys_p->tx_bd[0];
        } else {
            cdmac_tx_bd_virt_p->tx_bd[i].next_p =
                &cdmac_tx_bd_phys_p->tx_bd[i + 1];
        }
    }
    for(i = 0;i < RX_BD_NUM;i++) {
        memset((char *)&cdmac_rx_bd_virt_p->rx_bd[i], 0, sizeof(struct 
cdmac_bd_t));
        if(i == (RX_BD_NUM - 1)) {
            cdmac_rx_bd_virt_p->rx_bd[i].next_p =
                &cdmac_rx_bd_phys_p->rx_bd[0];
        } else {
            cdmac_rx_bd_virt_p->rx_bd[i].next_p =
                &cdmac_rx_bd_phys_p->rx_bd[i + 1];
        }
        skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
        if(skb == 0) {
            printk("alloc_skb error %d\n", i);
            return -1;
        }
        rx_skb[i] = skb;
        align = BUFFER_ALIGN(skb->data);
        if(align) skb_reserve(skb, align);

        cdmac_rx_bd_virt_p->rx_bd[i].phys_buf_p =
            (unsigned char *)pci_map_single(NULL,
                skb->data, XEM_MAX_FRAME_SIZE,
                PCI_DMA_FROMDEVICE);
        cdmac_rx_bd_virt_p->rx_bd[i].buf_len = XEM_MAX_FRAME_SIZE;
        cdmac_rx_bd_virt_p->rx_bd[i].app0 = BDSTAT_INT_ON_END_MASK;
    }

    return 0;
}

static int xps_ll_temac_changemtu(struct net_device *dev, int newmtu)

{
        printk("[xilinx_enet]new MTU %d\n", newmtu);
        dev->mtu = newmtu;

        return 0;
}

static int xps_ll_temac_open(struct net_device *dev) {

    return 0;
}

static int xps_ll_temac_close(struct net_device *dev) {

    return 0;
}

static struct net_device **xps_ll_temacs;

static int __init xps_ll_temac_init_one(int index)

{
    struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
    struct net_local *lp;
    int err = 0;

    if (!dev) return -ENOMEM;

    sprintf(dev->name, "eth%d", index);

    /* Initialize the device structure. */
    dev->get_stats = xps_ll_temac_get_stats;
    dev->hard_start_xmit = xps_ll_temac_xmit;
    dev->open = xps_ll_temac_open;
    dev->stop = xps_ll_temac_close;
#ifdef XPS_LL_TEMAC_NAPI
    dev->poll = &xps_ll_temac_poll;
#endif
    dev->weight = 64;
    dev->set_multicast_list = &xps_ll_temac_set_rx_mode;
    dev->set_mac_address = xps_ll_temac_set_address;
    dev->poll_controller = xps_ll_temac_netpoll;

    SET_MODULE_OWNER(dev);
#if 1
//  dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
//      | NETIF_F_IP_CSUM;
    dev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
#else
    dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
        | NETIF_F_TSO | NETIF_F_IP_CSUM;

#endif

    ether_setup(dev);

    lp = (struct net_local *)dev->priv;
    memset(lp, 0, sizeof(struct net_local));
    lp->index = index;

    lp->next_dev = dev_list;
    lp->sdma_reg_base = ioremap(S_DMA_CTRL_BASEADDR, 128);
    lp->temac_reg_base = ioremap(XPS_LLTEMAC_BASEADDR, 128);

    dev_list = dev;

    dev->tx_queue_len = 0;
    dev->change_mtu = xps_ll_temac_changemtu;

    sdma_reg_write(lp, DMA_CONTROL_REG, 1);

    printk(KERN_INFO "%s: Xilinx Embedded Tri-Mode Ethernet MAC\n", dev-
Quoted 2 lines

name);

    xps_ll_temac_init_descriptor();

    dev->dev_addr[0] = 0x00;
    dev->dev_addr[1] = 0x80;
    dev->dev_addr[2] = 0x49;
    dev->dev_addr[3] = 0x00;
    dev->dev_addr[4] = 0x00;
    dev->dev_addr[5] = 0x00;

    request_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_TX_INTOUT_INTR,
        &xps_ll_temac_tx_int, 0, dev->name, dev);
    request_irq(XPAR_XPS_INTC_0_DDR_SDRAM_SDMA2_RX_INTOUT_INTR,
        &xps_ll_temac_rx_int, 0, dev->name, dev);

    xps_ll_temac_indirect_set(dev, 0, MC, MDIO_ENABLE_MASK | MDIO_CLOCK_

DIV_100MHz);

    xps_ll_temac_indirect_set(dev, 0, RCW1, 0x10000000);    // Enable 
Receiver
    xps_ll_temac_indirect_set(dev, 0, TC, 0x10000000);  // Enable 
Transmitter
    xps_ll_temac_indirect_set(dev, 0, EMMC, 0x84000000);

    xps_ll_temac_indirect_set(dev, 0, UAW0, (dev->dev_addr[0] & 
0x000000ff) |
        ((dev->dev_addr[1] << 8) & 0x0000ff00) |
        ((dev->dev_addr[2] << 16)& 0x00ff0000) |
        ((dev->dev_addr[3] << 24) & 0xff000000));
    xps_ll_temac_indirect_set(dev, 0, UAW1, (dev->dev_addr[4] & 
0x000000ff) |
        ((dev->dev_addr[5] << 8) & 0x0000ff00));

    xps_ll_temac_indirect_set(dev, 0, AFM, 0x00000000);

    xps_ll_temac_phy_ctrl(dev);

    sdma_reg_write(lp, TX_CHNL_CTRL, 0x10220483);
    //sdma_reg_write(lp, TX_CHNL_CTRL, 0x00100483);
    sdma_reg_write(lp, RX_CHNL_CTRL, 0xff010283);

    sdma_reg_write(lp, RX_CURDESC_PTR, (unsigned int)&cdmac_rx_bd_phys_

p->rx_bd[0]);
sdma_reg_write(lp, RX_TAILDESC_PTR, (unsigned int)&cdmac_rx_bd_phys_
p->rx_bd[RX_BD_NUM - 1]);

    if ((err = register_netdev(dev))) {
        free_netdev(dev);
        dev = NULL;
    } else {
        xps_ll_temacs[index] = dev;
    }

    return 0;
}

static void xps_ll_temac_free_one(int index)

{
    unregister_netdev(xps_ll_temacs[index]);
    free_netdev(xps_ll_temacs[index]);
}

static int __init xps_ll_temac_init_module(void)

{
    int err = 0;

    xps_ll_temacs = kmalloc(sizeof(void *), GFP_KERNEL);

    if (!xps_ll_temacs) return -ENOMEM;

    spin_lock_init(&dev_lock);
    spin_lock_init(&rcv_lock);
    spin_lock_init(&xmt_lock);

    if((err = xps_ll_temac_init_one(0))) xps_ll_temac_free_one(0);

    return err;
}

static void __exit xps_ll_temac_cleanup_module(void)

{
    xps_ll_temac_free_one(0);
    kfree(xps_ll_temacs);
}

module_init(xps_ll_temac_init_module);
module_exit(xps_ll_temac_cleanup_module);
MODULE_LICENSE("GPL");

Quoted 4 lines

Thanks,

I have alot of work to do on our stuff, I might as well see if I

can

Quoted 10 lines

move to the powerpc tree at the same time.

BTW is there even the beginings of a non-xilinx lltemac driver out
there ? There were hints on the list, but I have not seen anything.

I would be happy to help advance the ball on anything anyone has
started.

Quoted 12 lines
Quoted 2 lines · Grant Likely

On Sun, Apr 20, 2008 at 2:31 PM, David H. Lynch Jr. <[email protected]

Quoted 6 lines · wrote:
Quoted 6 lines

Thanks.

I am running linus's 2.6.25-rc9, but I can pull the Xilinx tree

or

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

yours - when your server is up.

I can not find any Xilinx powerpc configs in arch/powerpc/

config

Quoted 10 lines
Quoted 10 lines
Quoted 4 lines

Do I just need to do a
make ARCH=powerpc menuconfig and create one from scratch ?

That's right; I haven't merged any defconfigs. Roll your own.

Quoted 2 lines

Is simpleboot in your tree or the xilinx tree, if can not find

it

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

in Linus's ?

If you want to use the "simpleboot" wrapper; then you'll need to

pull

Quoted 15 lines
Quoted 8 lines

paulus' tree (Linus hasn't yet pulled his tree; but he probably will any moment now).

Cheers,
g.

Signature · 5 lines
Dave Lynch                            DLA Systems
Software Development:                          Embedded Linux
717.627.3770         [email protected]       http://www.dlasys.net
fax: 1.253.369.9244                      Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies 

too numerous to list.

Quoted 2 lines

"Any intelligent fool can make things bigger and more complex... It

takes a touch of genius - and a lot of courage to move in the opposite direction."

Quoted 8 lines

Albert Einstein

_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

※ 4月から所属・部署が変更になりました
------------------------------------------------------------------
柏木良夫
株式会社日新システムズ 東日本営業部

本 社 〒600-8482 京都市下京区堀川通四条下ル東側 堀川四条ビル
TEL 075-344-7977 FAX 075-344-7887
東京事務所 〒101-0024 東京都千代田区神田和泉町1番地 神田和泉町ビル
TEL 03-5825-2081 FAX 03-5821-1259
E-Mail [email protected] HTTP http://www.co-nss.co.jp/
------------------------------------------------------------------

Signature · 8 lines
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email protected] 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
#10 lore raw

David-san,

This driver must add some corrections, for example, Checksum-offloading is incomplete as you say it. As for me, it is very happy to obtain your cooperation. Let me know if I can be of any work for it.

Moreover, although I wrote the xps_ll_temac driver for u-boot of a very simple single SDMA descriptor, I have not got used and put in the contribution way.

Best Regards,
Yoshio Kashiwagi - Nissin Systems

Quoted 11 lines

I was able to incorporate Yoshio's driver and make use of it.
It is a single file, fairly short, easy to understand, mostly conforming to linux kernel programming style. While it needs some work fo NAPI and OF, it is usable as it is.

I would be happy to see it form the starting point for a distribution LL TEMAC driver.

If Yoshio does not wish to put together a patch, for it I can, however, I have made some name changes and restructing to compare to my older PLB TEMAC.

#11 lore raw

I am preparing my own version of Yoshio's driver. Since most of my changes are re-ordering, renaming, or other items of small consequence, I will leave Yoshio as the author - unless he prefers otherwise.

I hope to have it ready to submit as a patch in a few days. If Yoshio is unhappy with any of the changes I have made or chooses to submit his original code or some permutation I will withdrawl mine.

While adding OF checksum offloading, ... would be nice,
All I am looking to do is get something that can start its way into the kernel.
This driver is working for me - with very light testing so far.

If no one else is willing to Shepard something in, then I will try. Hints, clues, etc would be very much appreciated.
I presume that if this driver is acceptable here, the next step would be forwarding it to linux-netdev ?

Quoted 12 lines · Yoshio Kashiwagi

David-san,

This driver must add some corrections, for example, Checksum-offloading is incomplete as you say it. As for me, it is very happy to obtain your cooperation. Let me know if I can be of any work for it.

Moreover, although I wrote the xps_ll_temac driver for u-boot of a very simple single SDMA descriptor, I have not got used and put in the contribution way.

Best Regards,
Yoshio Kashiwagi - Nissin Systems

Signature · 8 lines
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email protected] 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
#12 lore raw
Quoted 13 lines · David H. Lynch Jr.

I am preparing my own version of Yoshio's driver. Since most of my changes are re-ordering, renaming, or other items of small consequence, I will leave Yoshio as the author - unless he prefers otherwise.

I hope to have it ready to submit as a patch in a few days. If Yoshio is unhappy with any of the changes I have made or chooses to submit his original code or some permutation I will withdrawl mine.

While adding OF checksum offloading, ... would be nice,
All I am looking to do is get something that can start its way into the kernel.
This driver is working for me - with very light testing so far.

Quoted 4 lines

If no one else is willing to Shepard something in, then I will try. Hints, clues, etc would be very much appreciated.
I presume that if this driver is acceptable here, the next step would be forwarding it to linux-netdev ?

When you have a patch ready, post it both to here (linuxppc-dev) and to netdev. I'll provide review and help. Most likely when it is ready it will go in through jgarzik's tree, but if Jeff prefers, it can go in via my Virtex tree. Make sure you're able to generate and send clean patches before you post it to the mailing lists (inline instead of attachment, no line wrapping, applies cleanly to head of tree). If you need help, email me directly, and you can even send test emails to me for me to check before posting to the list.

It doesn't have to be perfect before you submit, but you do need to be prepared to respond to comments quickly and expect to respin the patch several times.

Cheers,
g.

Quoted 26 lines
Quoted 6 lines · Yoshio Kashiwagi

David-san,

This driver must add some corrections, for example, Checksum-offloading is incomplete as you say it. As for me, it is very happy to obtain your cooperation. Let me know if I can be of any work for it.

Quoted 6 lines

Moreover, although I wrote the xps_ll_temac driver for u-boot of a very simple single SDMA descriptor, I have not got used and put in the contribution way.

Best Regards,
Yoshio Kashiwagi - Nissin Systems

--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 [email protected] http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction." Albert Einstein

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
#13 lore raw
In reply to David H. Lynch Jr.

David-san,

I posted this source code so that usage of SDMA could be shared. Probably this code will be able to be used also by Virtex-5 FXT. Since this source code is a reference level and start point as you say, it is happy that it is maintainable with people of this ML. I'll leave it in your hands about author.

Best Regards,
Yoshio Kashiwagi - Nissin Systems

Quoted 2 lines

I am preparing my own version of Yoshio's driver. Since most of my changes are re-ordering, renaming, or other items of small

consequence,

Quoted 8 lines

I will leave Yoshio as the author - unless he prefers otherwise.

I hope to have it ready to submit as a patch in a few days. If Yoshio is unhappy with any of the changes I have made or chooses to submit his original code or some permutation I will withdrawl mine.

While adding OF checksum offloading, ... would be nice, All I am looking to do is get something that can start its way into

the

Quoted 6 lines

kernel.
This driver is working for me - with very light testing so far.

If no one else is willing to Shepard something in, then I will try. Hints, clues, etc would be very much appreciated.
I presume that if this driver is acceptable here, the next step would

be

Quoted 6 lines

forwarding it to linux-netdev ?

Quoted 3 lines · Yoshio Kashiwagi

David-san,

This driver must add some corrections, for example, Checksum-

offloading

Quoted 4 lines
Quoted 4 lines

is incomplete as you say it. As for me, it is very happy to obtain your cooperation. Let me know if I can be of any work for it.

Moreover, although I wrote the xps_ll_temac driver for u-boot of a

very

Quoted 12 lines
Quoted 5 lines

simple single SDMA descriptor, I have not got used and put in the contribution way.

Best Regards,
Yoshio Kashiwagi - Nissin Systems

Signature · 5 lines
Dave Lynch                            DLA Systems
Software Development:                          Embedded Linux
717.627.3770         [email protected]       http://www.dlasys.net
fax: 1.253.369.9244                      Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies 

too numerous to list.

Quoted 2 lines

"Any intelligent fool can make things bigger and more complex... It

takes a touch of genius - and a lot of courage to move in the opposite direction."

Quoted 1 line

Albert Einstein

#14 lore raw
Quoted 7 lines · Yoshio Kashiwagi

David-san,

I posted this source code so that usage of SDMA could be shared. Probably this code will be able to be used also by Virtex-5 FXT. Since this source code is a reference level and start point as you say, it is happy that it is maintainable with people of this ML. I'll leave it in your hands about author.

It is probably appropriate for David to maintain your copyright notice at the top of the file. Also, you should provide your "signed-off-by" line to confirm that there are no legal issues with you contributing your code (see Documentation/SubmittingPatches for details). Email it to Dave, and he should preserve your signed-off-by line when he posts his modified patch.

Cheers,
g.

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.