From: "David H. Lynch Jr." <dhlii@dlasys.net>
To: Yoshio Kashiwagi <kashiwagi@co-nss.co.jp>
Cc: linuxppc-embedded <linuxppc-embedded@ozlabs.org>
Subject: Re: Xilinx PowerPC
Date: Sat, 17 May 2008 11:36:47 -0400 [thread overview]
Message-ID: <482EFB8F.9090402@dlasys.net> (raw)
In-Reply-To: <JM200804230904046.2598203@co-nss.co.jp>
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. <dhlii@dlasys.net
>>>
>> 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 dhlii@dlasys.net 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
>> Linuxppc-embedded@ozlabs.org
>> 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 kashiwagi@co-nss.co.jp HTTP http://www.co-nss.co.jp/
> ------------------------------------------------------------------
>
>
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net 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
next prev parent reply other threads:[~2008-05-17 15:36 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <480BA36D.1080000@dlasys.net>
[not found] ` <fa686aa40804201314m27caf4fau72956df9dd5d350d@mail.gmail.com>
[not found] ` <480BA821.2030109@dlasys.net>
[not found] ` <fa686aa40804201548o503e9b19p4081cec653a1acd2@mail.gmail.com>
2008-04-20 23:48 ` Xilinx PowerPC David H. Lynch Jr.
2008-04-22 22:15 ` Koss, Mike (Mission Systems)
2008-04-23 21:37 ` David H. Lynch Jr.
2008-04-23 0:04 ` Yoshio Kashiwagi
2008-04-23 21:43 ` David H. Lynch Jr.
2008-05-17 15:36 ` David H. Lynch Jr. [this message]
2008-05-18 2:13 ` Yoshio Kashiwagi
2008-05-19 3:27 ` David H. Lynch Jr.
2008-05-19 4:09 ` Grant Likely
2008-05-19 4:09 ` Grant Likely
2008-05-19 4:18 ` Yoshio Kashiwagi
2008-05-19 4:59 ` Grant Likely
2008-02-21 6:58 David H. Lynch Jr.
2008-02-21 17:50 ` Stephen Neuendorffer
2008-02-21 19:02 ` Grant Likely
2008-02-22 17:23 ` Alan Casey
2008-02-22 18:11 ` Stephen Neuendorffer
2008-02-22 18:58 ` Alan Casey
2008-02-22 19:07 ` Stephen Neuendorffer
[not found] ` <47BF43CF.5050102@dlasys.lcl>
2008-02-22 22:05 ` Stephen Neuendorffer
2008-03-02 18:25 ` Michal Simek
2008-03-03 19:53 ` Stephen Neuendorffer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=482EFB8F.9090402@dlasys.net \
--to=dhlii@dlasys.net \
--cc=kashiwagi@co-nss.co.jp \
--cc=linuxppc-embedded@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.