Subject: Re: Xilinx PowerPC

From: "David H. Lynch Jr." <[email-masked]>
Date: Sat, 17 May 2008 11:36:47 -0400

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.

Yoshio Kashiwagi wrote:
> 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-
>   
>> 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");
>
>
>   
>> 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.
>>
>>    
>>
>> Grant Likely wrote:
>>     
>>> On Sun, Apr 20, 2008 at 2:31 PM, David H. Lynch Jr. <[email-masked]
>>>       
>> wrote:
>>     
>>>   
>>>       
>>>> 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.
>>>
>>>   
>>>       
>>>>     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.
>>>
>>>   
>>>       
>> -- 
>> Dave Lynch                            DLA Systems
>> Software Development:                          Embedded Linux
>> 717.627.3770         [email-masked]       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
>>
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> [email-masked]
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>
>>     
> ※ ４月から所属・部署が変更になりました
> ------------------------------------------------------------------
> 柏木良夫
> 株式会社日新システムズ 東日本営業部
>
> 本      社 〒600-8482 京都市下京区堀川通四条下ル東側 堀川四条ビル
> TEL 075-344-7977 FAX 075-344-7887
> 東京事務所 〒101-0024 東京都千代田区神田和泉町1番地 神田和泉町ビル
> TEL 03-5825-2081 FAX 03-5821-1259
> E-Mail [email-masked] HTTP http://www.co-nss.co.jp/
> ------------------------------------------------------------------
>
>   

-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       [email-masked] 	  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