blob: f278a98ffc4b8ff6a4e3830edc2fb57f186bea8a [file] [log] [blame]
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Simon Spooner - Dec 2009 - Original version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/in.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/init.h>
#include <linux/inetdevice.h>
#include <linux/inet.h>
#include <linux/proc_fs.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
#include <linux/platform_device.h>
#include "xtemac.h"
#define DRIVER_NAME "xilinx_temac"
#define TX_RING_LEN 2
#define RX_RING_LEN 32
/* Prototypes */
int xtemac_open(struct net_device *);
int xtemac_tx(struct sk_buff *, struct net_device *);
void xtemac_tx_timeout(struct net_device *);
void xtemac_set_multicast_list (struct net_device *);
void xtemac_tx_timeout(struct net_device *);
struct net_device_stats * xtemac_stats(struct net_device *);
int xtemac_stop(struct net_device *);
int xtemac_set_address(struct net_device *, void *);
void print_phy_status2(unsigned int );
void print_packet(unsigned int, unsigned char *);
static int read_proc(char *sysbuf, char **start, off_t off, int count, int *eof, void *data);
static int write_proc(char *sysbuf, char ** buffer, off_t count, int l_sysbuf, int zero);
struct proc_dir_entry *myproc;
static const struct net_device_ops xtemac_netdev_ops = {
.ndo_open = xtemac_open,
.ndo_stop = xtemac_stop,
.ndo_start_xmit = xtemac_tx,
.ndo_set_multicast_list = xtemac_set_multicast_list,
.ndo_tx_timeout = xtemac_tx_timeout,
.ndo_set_mac_address= xtemac_set_address,
.ndo_get_stats = xtemac_stats,
// .ndo_do_ioctl = aa3_emac_ioctl;
// .ndo_change_mtu = aa3_emac_change_mtu, FIXME: not allowed
};
struct xtemac_stats
{
unsigned int rx_packets;
unsigned int rx_bytes;
};
struct xtemac_ptr
{
struct xtemac_bridge bridge;
struct xtemac_configuration config;
struct xtemac_address_filter addrFilter;
struct xtemac_bridge_extn bridgeExtn;
};
volatile struct xtemac_ptr *xtemac = (volatile struct xtemac_ptr *)XTEMAC_BASE;
volatile struct xtemac_priv
{
struct net_device_stats stats;
spinlock_t lock;
unsigned char address[6];
unsigned int RxEntries;
unsigned int RxCurrent;
struct sk_buff *tx_skb;
struct net_device *ndev; // This device.
void * tx_buff; // Area packets TX from
void * rx_buff; // Area packets DMA into
unsigned int rx_len;
struct xtemac_stats phy_stats; // PHY stats.
};
volatile unsigned int debug=0;
void XEMAC_mdio_write (volatile struct xtemac_ptr *,unsigned int, unsigned int , unsigned int);
void xtemac_update_stats(struct xtemac_priv * ap);
unsigned int XEMAC_mdio_read ( volatile struct xtemac_ptr * , unsigned int, unsigned int, volatile unsigned int *);
extern struct sockaddr mac_addr; /* Intialised while
* processing parameters in
* setup.c */
/****************************/
/* XTEMAC interrupt handler */
/***************************/
static irqreturn_t
xtemac_emac_intr(int irq, void *dev_instance)
{
volatile unsigned int status;
struct xtemac_priv *priv = netdev_priv(dev_instance);
struct sk_buff *skb;
status = arc_read_uncached_32(&xtemac->bridge.intrStsReg);
if(status & INTR_STATUS_MDIO_BIT_POS)
{
if(debug)
printk("TEMAC MDIO INT\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg, INTR_STATUS_MDIO_BIT_POS);
}
if(status & INTR_STATUS_RX_ERROR_BIT_POS)
{
printk("TEMAC RX_ERROR\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg, INTR_STATUS_RX_ERROR_BIT_POS);
arc_write_uncached_32(&xtemac->bridgeExtn.intrEnableReg, ENABLE_ALL_INTR & (~ENABLE_RX_OVERRUN_INTR));
printk("intrEnableReg = %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.intrEnableReg));
}
if(status & INTR_STATUS_TX_ERROR_BIT_POS)
{
printk("TEMAC TX ERROR\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg ,INTR_STATUS_TX_ERROR_BIT_POS);
}
if(status & INTR_STATUS_DMA_TX_ERROR_BIT_POS)
{
printk("TEMAC DMA TX ERROR\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg, INTR_STATUS_DMA_TX_ERROR_BIT_POS);
}
if(status & INTR_STATUS_DMA_RX_ERROR_BIT_POS)
{
printk("TEMAC DMA RX ERROR\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg, INTR_STATUS_DMA_RX_ERROR_BIT_POS);
}
// RX FIFO DMA'd to main memory.
// ack the interrupt
// invalidate the cache line
// setup an SKB and pass in the packet into the kernel.
// re-enable RX interrupts to allow next packet in.
if(status & INTR_STATUS_DMA_RX_COMPLETE_BIT_POS)
{
if(debug)
printk("TEMAC DMA RX COMPLETE\n");
arc_write_uncached_32(&xtemac->bridge.dmaRxClrReg, 1);
// arc_write_uncached_32(&xtemac->bridge.intrClrReg, INTR_STATUS_DMA_RX_COMPLETE_BIT_POS);
arc_write_uncached_32(&xtemac->bridgeExtn.intrEnableReg,ENABLE_ALL_INTR & (~ENABLE_RX_OVERRUN_INTR));
priv->stats.rx_packets++;
flush_and_inv_dcache_range(priv->rx_buff, priv->rx_buff +priv->rx_len);
// was in
skb=alloc_skb(priv->rx_len + 32, GFP_ATOMIC);
skb_reserve(skb,NET_IP_ALIGN); // Align header
memcpy(skb->data, priv->rx_buff, priv->rx_len);
#if 0
printk("RX:");
print_packet(priv->rx_len, priv->rx_buff);
printk("\n");
#endif
skb_put(skb,priv->rx_len);
skb->dev = dev_instance;
skb->protocol = eth_type_trans(skb,dev_instance);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
}
// TX FIFO DMA'd out.
// ack the interrupt, reset the TX buffer
if(status & INTR_STATUS_DMA_TX_COMPLETE_BIT_POS)
{
if(debug)
printk("TEMAC DMA TX COMPLETE\n");
arc_write_uncached_32(&xtemac->bridge.dmaTxClrReg , 1);
priv->tx_skb = 0;
}
// Receive a packet.
// Start to DMA into a physically contiguous buffer.
// Switch off RX interrupts until DMA complete.
if(status & INTR_STATUS_RCV_INTR_BIT_POS )
{
if(debug)
printk("TEMAC RCV INTR\n");
arc_write_uncached_32(&xtemac->bridge.intrClrReg , INTR_STATUS_RCV_INTR_BIT_POS);
// arc_write_uncached_32(&xtemac->config.rxCtrl1Reg, 0); // Disable RX
arc_write_uncached_32(&xtemac->bridgeExtn.intrEnableReg , ENABLE_ALL_INTR & (~ENABLE_PKT_RECV_INTR ) & (~ENABLE_RX_OVERRUN_INTR) );
priv->rx_len = arc_read_uncached_32(&xtemac->bridgeExtn.sizeReg);
arc_write_uncached_32(&xtemac->bridge.dmaRxAddrReg , priv->rx_buff);
inv_dcache_range(priv->rx_buff, priv->rx_buff + priv->rx_len);
arc_write_uncached_32(&xtemac->bridge.dmaRxCmdReg , (priv->rx_len << 8 | DMA_READ_COMMAND));
}
// Handle an RX FIFO overrun.
// ack the interrupt, handle this as a regular RX and DMA
// the packet into the RX buffer
if(status & INTR_STATUS_RX_OVRN_INTR_BIT_POS)
{
printk("TEMAC RX OVERRUN\n");
arc_write_uncached_32(&xtemac->bridge.dmaRxClrReg,1);
arc_write_uncached_32(&xtemac->bridge.intrClrReg , INTR_STATUS_RX_OVRN_INTR_BIT_POS);
arc_write_uncached_32(&xtemac->config.rxCtrl1Reg,0);
arc_write_uncached_32(&xtemac->bridge.txFifoRxFifoRstReg, RESET_TX_RX_FIFO);
arc_write_uncached_32(&xtemac->bridge.txFifoRxFifoRstReg, 0);
}
return IRQ_HANDLED;
}
/***************/
/* XTEAMC open */
/***************/
int
xtemac_open(struct net_device * dev)
{
unsigned int speed;
unsigned int temp;
// OK, now switch on the hardware.
arc_write_uncached_32(&xtemac->config.rxCtrl1Reg,RESET_FIFO);
arc_write_uncached_32(&xtemac->bridgeExtn.intrEnableReg,0);
arc_write_uncached_32(&xtemac->bridge.intrClrReg , CLEAR_INTR_REG);
arc_write_uncached_32(&xtemac->bridge.txFifoRxFifoRstReg, RESET_TX_RX_FIFO);
arc_write_uncached_32(&xtemac->bridge.txFifoRxFifoRstReg,0);
request_irq(dev->irq, xtemac_emac_intr, 0, dev->name, dev);
arc_write_uncached_32(&xtemac->config.rxCtrl1Reg , ENABLE_RX );//| HALF_DUPLEX);
arc_write_uncached_32(&xtemac->config.txCtrlReg , ENABLE_TX); // | HALF_DUPLEX);
// arc_write_uncached_32(&xtemac->config.macModeConfigReg, 0x40000000); // 100mbit
arc_write_uncached_32(&xtemac->config.macModeConfigReg, SET_100MBPS_MODE); // 100mbit
// Probe the Phy to see what speed is negotiated.
printk("Setup phy\n");
XEMAC_mdio_read(xtemac, BSP_XEMAC1_PHY_ID,MV_88E1111_STATUS2_REG, &speed);
printk("Phy setup\n");
print_phy_status2(speed);
myproc = create_proc_entry("temac", 0644, NULL);
if (myproc)
{
myproc->read_proc = read_proc;
myproc->write_proc = write_proc;
}
printk("TEMAC Opened\n");
// Enable Address Filter
xtemac->addrFilter.addrFilterModeReg= ENABLE_ADDR_FILTER;
printk("XTEMAC - Address filter enabled\n");
// Set the mac address
xtemac_set_address(dev,&mac_addr);
// Reset the transceiver
printk("XTEMAC - Reset the transceiver\n");
XEMAC_mdio_write(xtemac,BSP_XEMAC1_PHY_ID , MV_88E1111_CTRL_REG, MV_88E1111_CTRL_RESET);
do {
XEMAC_mdio_read(xtemac,BSP_XEMAC1_PHY_ID,MV_88E1111_CTRL_REG, &temp);
} while(temp & MV_88E1111_CTRL_RESET);
printk("XTEMAC - Transceiver reset\n");
/* Advertise capabilities */
temp = MV_88E1111_AUTONEG_ADV_100BTX_FULL | MV_88E1111_AUTONEG_ADV_100BTX | AUTONEG_ADV_IEEE_8023;
XEMAC_mdio_write(xtemac, BSP_XEMAC1_PHY_ID, MV_88E1111_AUTONEG_ADV_REG, temp);
printk("XTEMAC - Advertise capabilities\n");
// Autonegotiate the connection
XEMAC_mdio_write(xtemac,BSP_XEMAC1_PHY_ID,MV_88E1111_CTRL_REG, (MV_88E1111_CTRL_AUTONEG | MV_88E1111_CTRL_RESTART_AUTO));
// Wait for autoneg to complete
do {
XEMAC_mdio_read(xtemac,BSP_XEMAC1_PHY_ID,MV_88E1111_STATUS_REG, &temp);
} while( !(temp & MV_88E1111_STATUS_COMPLETE));
printk("XTEMAC - Autonegotiate complete\n");
XEMAC_mdio_read(xtemac,BSP_XEMAC1_PHY_ID,MV_88E1111_STATUS2_REG, &temp);
if (temp & MV_88E1111_STATUS2_FULL)
printk("XTEMAC - Full Duplex\n");
else
printk("XTEMAC - Not Full Duplex\n");
// Go !
arc_write_uncached_32(&xtemac->bridgeExtn.intrEnableReg , ENABLE_ALL_INTR & (~ENABLE_RX_OVERRUN_INTR)); // (ENABLE_ALL_INTR & (~ENABLE_RX_OVERRUN_INTR) & (~ENABLE_MDIO_INTR)));
return 0;
}
/* XTEMAC close routine */
int
xtemac_stop(struct net_device * dev)
{
return 0;
}
/* XTEMAC ioctl commands */
int
xtemac_ioctl(struct net_device * dev, struct ifreq * rq, int cmd)
{
printk("ioctl called\n");
/* FIXME :: not ioctls yet :( */
return (-EOPNOTSUPP);
}
/* XTEMAC transmit routine */
int
xtemac_tx(struct sk_buff * skb, struct net_device * dev)
{
//printk("Transmit...\n");
struct xtemac_priv *priv = netdev_priv(dev);
unsigned int tx_space;
if(priv->tx_skb)
{
// printk("Dropping due to previous TX not complete\n");
return NETDEV_TX_BUSY;
}
tx_space = arc_read_uncached_32(&xtemac->bridge.macTxFIFOStatusReg);
if(tx_space < skb->len)
{
// printk("Dropping due to not enough room in the TXFIFO\n");
return NETDEV_TX_BUSY; // not enough space in the TX FIFO, throw away
}
memcpy(priv->tx_buff, skb->data, skb->len);
// print_packet(skb->len, priv->tx_buff);
// printk("\n");
flush_and_inv_dcache_range(priv->tx_buff, priv->tx_buff + skb->len);
arc_write_uncached_32(&xtemac->bridge.dmaTxAddrReg , priv->tx_buff);
arc_write_uncached_32(&xtemac->bridge.dmaTxCmdReg , (skb->len <<8 | DMA_WRITE_COMMAND | DMA_START_OF_PACKET | DMA_END_OF_PACKET));
priv->stats.tx_packets++;
priv->tx_skb = skb;
dev_kfree_skb(priv->tx_skb);
return(0);
}
/* the transmission timeout function */
void
xtemac_tx_timeout(struct net_device * dev)
{
printk("transmission timed out\n");
printk(KERN_CRIT "transmission timeout\n");
return;
}
/* the set multicast list method */
void
xtemac_set_multicast_list(struct net_device * dev)
{
printk("set multicast list called\n");
return;
}
// XTEMAC MAC address set.
int
xtemac_set_address(struct net_device * dev, void *p)
{
int i;
struct sockaddr *addr = p;
unsigned int temp;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
memcpy(mac_addr.sa_data, addr->sa_data, dev->addr_len); // store the mac address.
printk(KERN_INFO "MAC address set to ");
for (i = 0; i < 6; i++)
printk("%02x:", dev->dev_addr[i]);
printk("\n");
temp = dev->dev_addr[3];
temp = ((temp << 8) | (dev->dev_addr[2]));
temp = ((temp << 8) | (dev->dev_addr[1]));
temp = ((temp << 8) | (dev->dev_addr[0]));
arc_write_uncached_32(&xtemac->addrFilter.unicastAddr0Reg ,temp);
temp = dev->dev_addr[5];
temp = ((temp << 8) | (dev->dev_addr[4]));
arc_write_uncached_32(&xtemac->addrFilter.unicastAddr1Reg, temp);
return 0;
}
void xtemac_update_stats( struct xtemac_priv *ap)
{
//
// Code to read the current stats from the XTEMAC and add to ap->stats
//
}
struct net_device_stats *
xtemac_stats(struct net_device * dev)
{
unsigned long flags;
struct xtemac_priv *ap = netdev_priv(dev);
spin_lock_irqsave(&ap->lock, flags);
xtemac_update_stats(ap);
spin_unlock_irqrestore(&ap->lock, flags);
return (&ap->stats);
}
static int __devinit xtemac_probe(struct platform_device *dev)
{
struct net_device *ndev;
struct xtemac_priv *priv;
unsigned int rc;
printk("Probing...\n");
// Setup a new netdevice
ndev = alloc_etherdev(sizeof(struct xtemac_priv));
if (!ndev)
{
printk("Failed to allocated net device\n");
return -ENOMEM;
}
dev_set_drvdata(dev,ndev);
ndev->irq = 6;
xtemac_set_address(dev,&mac_addr);
priv = netdev_priv(ndev);
priv->ndev = ndev;
priv->tx_skb = 0;
ndev->netdev_ops = &xtemac_netdev_ops;
ndev->watchdog_timeo = (400*HZ/1000);
ndev->flags &= ~IFF_MULTICAST;
// Setup RX buffer
priv->rx_buff = kmalloc(4096,GFP_ATOMIC | GFP_DMA);
priv->tx_buff = kmalloc(4096,GFP_ATOMIC | GFP_DMA);
printk("RX Buffer @ %x , TX Buffer @ %x\n", (unsigned int)priv->rx_buff,(unsigned int) priv->tx_buff);
if(!priv->rx_buff || !priv->tx_buff)
{
printk("Failed to alloc FIFO buffers\n");
return -ENOMEM;
}
spin_lock_init(&((struct xtemac_priv *) netdev_priv(ndev))->lock);
// Register net device with kernel, now ifconfig should see the device
rc = register_netdev(ndev);
if (rc)
{
printk("Didn't register the netdev.\n");
return(rc);
}
return(0);
}
static void xtemac_remove(struct net_device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
unregister_netdev(ndev);
}
void print_packet(unsigned int len, unsigned char * packet)
{
unsigned int n;
printk("Printing packet\nLen = %u\n", len);
for(n=0;n<len;n++)
{
if(! (n %20))
printk("\n");
printk("%02x-",*packet++);
}
printk("\n");
}
void print_phy_status2(unsigned int status)
{
printk("Status is %x\n", status);
if(status & MV_88E1111_STATUS2_FULL)
printk("Full duplex\n");
if(status & MV_88E1111_STATUS2_LINK_UP)
printk("Link up\n");
if(status & MV_88E1111_STATUS2_100)
printk("100Mbps\n");
if(status & MV_88E1111_STATUS2_1000)
printk("1000Mbps\n");
}
void XEMAC_mdio_write
(
/* [IN] the device physical address */
volatile struct xtemac_ptr *dev_ptr,
/* [IN] The device physical address */
unsigned int phy_addr,
/* [IN] the register index (0-31)*/
unsigned int reg_index,
/* [IN] The data to be written to register */
unsigned int data
)
{ /* Body */
unsigned int value;
arc_write_uncached_32(&dev_ptr->config.mgmtConfigReg, MDIO_ENABLE);
arc_write_uncached_32(&dev_ptr->bridgeExtn.phyAddrReg, phy_addr);
arc_write_uncached_32((&dev_ptr->bridgeExtn.macMDIOReg + reg_index), data);
value = arc_read_uncached_32(&dev_ptr->bridgeExtn.intrRawStsReg);
while (!(value & INTR_STATUS_MDIO_BIT_POS))
{
value = arc_read_uncached_32(&dev_ptr->bridgeExtn.intrRawStsReg);
}
arc_write_uncached_32(&dev_ptr->bridge.intrClrReg, INTR_STATUS_MDIO_BIT_POS);
// printk("Finished MDIO write\n");
} /* Endbody */
/* [IN] The device physical address */
/* [IN] the register index (0-31)*/
/* [IN]/[OUT] The data pointer */
unsigned int XEMAC_mdio_read ( volatile struct xtemac_ptr * dev_ptr,
unsigned int phy_addr,
unsigned int reg_index,
volatile unsigned int * data_ptr
)
{
unsigned int value = 0;
unsigned int count=0;
arc_write_uncached_32(&dev_ptr->config.mgmtConfigReg , MDIO_ENABLE);
arc_write_uncached_32(&dev_ptr->bridgeExtn.phyAddrReg , phy_addr);
*data_ptr = arc_read_uncached_32(&dev_ptr->bridgeExtn.macMDIOReg + reg_index);
value = arc_read_uncached_32(&dev_ptr->bridgeExtn.intrRawStsReg);
while (!(value & INTR_STATUS_MDIO_BIT_POS))
{
count++;
value = arc_read_uncached_32(&dev_ptr->bridgeExtn.intrRawStsReg);
}
arc_write_uncached_32(&dev_ptr->bridge.intrClrReg , INTR_STATUS_MDIO_BIT_POS);
// printk("read MDIO status in %x counts\n", count);
return 0;
}
static int read_proc(char *sysbuf, char **start,
off_t off, int count, int *eof, void *data)
{
int len;
unsigned int status;
unsigned int perid;
unsigned int dma_tx_status_reg;
unsigned int dma_rx_status_reg;
unsigned int intr_enable_reg;
status = arc_read_uncached_32(&xtemac->bridge.intrStsReg);
perid = arc_read_uncached_32(&xtemac->bridge.idReg);
dma_tx_status_reg = arc_read_uncached_32(&xtemac->bridge.dmaTxStsReg);
dma_rx_status_reg = arc_read_uncached_32(&xtemac->bridge.dmaRxStsReg);
intr_enable_reg = arc_read_uncached_32(&xtemac->bridgeExtn.intrEnableReg);
len = sprintf(sysbuf, "\nARC AA5 TEMAC STATISTICS\n");
len += sprintf(sysbuf + len, "------------------------\n");
len += sprintf(sysbuf + len, "Base address of bridge regs %x\n", (unsigned int)&xtemac->bridge);
len += sprintf(sysbuf + len, "idReg %x\n", arc_read_uncached_32(&xtemac->bridge.idReg));
len += sprintf(sysbuf + len, "dmaTxCmdReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaTxCmdReg));
len += sprintf(sysbuf + len, "dmaTxAddrReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaTxAddrReg));
len += sprintf(sysbuf + len, "dmaTxStsReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaTxStsReg));
len += sprintf(sysbuf + len, "dmaTxClrReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaTxClrReg));
len += sprintf(sysbuf + len, "macTxFIFOStatusReg %x\n", arc_read_uncached_32(&xtemac->bridge.macTxFIFOStatusReg));
len += sprintf(sysbuf + len, "dmaRxCmdReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaRxCmdReg));
len += sprintf(sysbuf + len, "dmaRxAddrReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaRxAddrReg));
len += sprintf(sysbuf + len, "dmaRxStsReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaRxStsReg));
len += sprintf(sysbuf + len, "dmaRxClrReg %x\n", arc_read_uncached_32(&xtemac->bridge.dmaRxClrReg));
len += sprintf(sysbuf + len, "txFifoRxFifoRstReg %x\n", arc_read_uncached_32(&xtemac->bridge.txFifoRxFifoRstReg));
len += sprintf(sysbuf + len, "intrStsReg %x\n", arc_read_uncached_32(&xtemac->bridge.intrStsReg));
// len += sprintf(sysbuf + len, "intrClrReg %x\n", arc_read_uncached_32(&xtemac->bridge.intrClrReg));
len += sprintf(sysbuf + len, "pioDataCountReg %x\n", arc_read_uncached_32(&xtemac->bridge.pioDataCountReg));
len += sprintf(sysbuf + len, "arbSelReg %x\n", arc_read_uncached_32(&xtemac->bridge.arbSelReg));
// len += sprintf(sysbuf + len, "dataReg %x\n", arc_read_uncached_32(&xtemac->bridge.dataReg));
// Config regs
len += sprintf(sysbuf + len, "\n\nConfig regs @ %x\n", (unsigned int)&xtemac->config);
len += sprintf(sysbuf + len, "rxCtrl0Reg %x\n", arc_read_uncached_32(&xtemac->config.rxCtrl0Reg));
len += sprintf(sysbuf + len, "rxCtrl1Reg %x\n", arc_read_uncached_32(&xtemac->config.rxCtrl1Reg));
len += sprintf(sysbuf + len, "txCtrlReg %x\n", arc_read_uncached_32(&xtemac->config.txCtrlReg));
len += sprintf(sysbuf + len, "flowCtrlConfigReg %x\n", arc_read_uncached_32(&xtemac->config.flowCtrlConfigReg));
len += sprintf(sysbuf + len, "macModeConfigReg %x\n", arc_read_uncached_32(&xtemac->config.macModeConfigReg));
len += sprintf(sysbuf + len, "rgmsgmiiConfigReg %x\n", arc_read_uncached_32(&xtemac->config.rgmsgmiiConfigReg));
len += sprintf(sysbuf + len, "mgmtConfigReg %x\n", arc_read_uncached_32(&xtemac->config.mgmtConfigReg));
// Filter regs
len += sprintf(sysbuf + len, "\n\naddrFilter regs @ %x\n", (unsigned int)&xtemac->addrFilter);
len += sprintf(sysbuf + len, "unicastAddr0Reg %x\n", arc_read_uncached_32(&xtemac->addrFilter.unicastAddr0Reg));
len += sprintf(sysbuf + len, "unicastAddr1Reg %x\n", arc_read_uncached_32(&xtemac->addrFilter.unicastAddr1Reg));
len += sprintf(sysbuf + len, "genAddrTableAccess0Reg %x\n", arc_read_uncached_32(&xtemac->addrFilter.genAddrTableAccess0Reg));
len += sprintf(sysbuf + len, "genAddrTableAccess1Reg %x\n", arc_read_uncached_32(&xtemac->addrFilter.genAddrTableAccess1Reg));
len += sprintf(sysbuf + len, "addrFilterModeReg %x\n", arc_read_uncached_32(&xtemac->addrFilter.addrFilterModeReg));
//Bridge Extn
len += sprintf(sysbuf + len, "\n\nBridgeExtn regs @ %x\n", (unsigned int)&xtemac->bridgeExtn);
len += sprintf(sysbuf + len, "sizeReg %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.sizeReg));
len += sprintf(sysbuf + len, "phyAddrReg %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.phyAddrReg));
len += sprintf(sysbuf + len, "intrEnableReg %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.intrEnableReg));
len += sprintf(sysbuf + len, "IntrRawStsReg %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.intrRawStsReg));
// len += sprintf(sysbuf + len, "macMDIOReg %x\n", arc_read_uncached_32(&xtemac->bridgeExtn.macMDIOReg));
return (len);
}
static int write_proc(char *sysbuf, char ** buffer, off_t count, int l_sysbuf, int zero)
{
volatile unsigned int reg;
volatile unsigned int val;
char from_proc[80]; // bad, buffer overflow !
if(copy_from_user(from_proc, buffer, count))
return -EFAULT;
from_proc[count-1]=0;
/* First character indicates read or write */
if(from_proc[0]=='w')
{ /* WRITE AUX REG */
sscanf(from_proc, "w%x=%x", &reg, &val);
printk("writing %x to %x\n", val,reg);
arc_write_uncached_32(reg, val);
}
else if (from_proc[0]=='d')
{
debug = ~debug; // invert debug status.
}
return count;
}
static struct platform_driver xtemac_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = xtemac_probe,
.remove = xtemac_remove
};
int __init
xtemac_module_init(void)
{
printk("*** Init XTEMAC ***\n");
return platform_driver_register(&xtemac_driver);
}
void __exit
xtemac_module_cleanup(void)
{
return;
}
module_init(xtemac_module_init);
module_exit(xtemac_module_cleanup);