summaryrefslogtreecommitdiff
path: root/cleopatre
diff options
context:
space:
mode:
authorsave2009-06-22 10:56:38 +0000
committersave2009-06-22 10:56:38 +0000
commit42e37165fcbc5e9549c8ff7cb1629ed43193456b (patch)
tree2bec63116dc4ce4089b1a39a8e4be7a8a7be71ea /cleopatre
parent317cf378a43fd688d21f66b553c305e6a7875c7a (diff)
[CLEO][LNXDRV]Added NAPI on Ethernet driver
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@4823 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cleopatre')
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c219
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504_hw.c5
2 files changed, 143 insertions, 81 deletions
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
index 584848ab0a..2724a65197 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
@@ -27,8 +27,8 @@
*/
#define DRV_NAME "Synop3504"
-#define DRV_VERSION "1.2"
-#define DRV_RELDATE "jun 16, 2009"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "jun 17, 2009"
//#define TRACE_FRAME 1
//#define TRACE(...) printk(DRV_NAME": " __VA_ARGS__)
@@ -114,6 +114,7 @@ struct net_priv
struct dma_tx tx;
struct dma_rx rx;
struct timer_list timer;
+ struct napi_struct napi;
};
#ifdef TRACE_FRAME
@@ -501,7 +502,7 @@ static int synop3504_autonegotiate(struct net_device *dev, int wait)
if(timeout <= 0)
{
- printk(DRV_NAME ": AutoNegotiation timed out after %d s for %s\n", AUTONEG_TIMEOUT, dev->name);
+ printk(KERN_WARNING DRV_NAME ": AutoNegotiation timed out after %d s for %s\n", AUTONEG_TIMEOUT, dev->name);
return -1;
}
else
@@ -552,7 +553,7 @@ static void synop3504_timer(unsigned long data)
}
else
{
- TRACE("%s: Link still down\n", dev->name);
+// TRACE("%s: Link still down\n", dev->name);
}
}
else
@@ -567,7 +568,7 @@ static void synop3504_timer(unsigned long data)
}
else
{
- TRACE("%s: Link still up\n", dev->name);
+// TRACE("%s: Link still up\n", dev->name);
}
}
mod_timer(&priv->timer, jiffies + TIMEOUT);
@@ -742,8 +743,7 @@ static int synop3504_ethtool_ioctl(struct net_device *dev, void *useraddr)
//Restart Auto-Negotiation
case ETHTOOL_NWAY_RST:
{
- //TODO
- return 0;
+ return synop3504_autonegotiate(dev, 1);
}
//Get link status
case ETHTOOL_GLINK:
@@ -813,11 +813,11 @@ static int synop3504_tx(struct sk_buff *skb, struct net_device *dev)
n = tx->head_ptr;
- //TODO:Check if the link is down
+ //Check if the link is down
status_mdio = mdio_read(dev, 0, MII_BMSR);
if((status_mdio & BMSR_LSTATUS) == 0)
{
- printk("AH AH Link still down\n");
+ printk(KERN_WARNING DRV_NAME "%s: TX error : Link still down\n", dev->name);
dev_kfree_skb_any(skb);
return 0;
}
@@ -826,6 +826,7 @@ static int synop3504_tx(struct sk_buff *skb, struct net_device *dev)
if((tx->skbs[n] != NULL) || (tx->ring[n].status.bf.dma_own))
{
netif_stop_queue(dev);
+ printk(KERN_WARNING DRV_NAME "%s: TX dropped DMA Queue full\n", dev->name);
priv->stats.tx_dropped++;
dev_kfree_skb_any(skb);
return 0;
@@ -865,8 +866,9 @@ static int synop3504_tx(struct sk_buff *skb, struct net_device *dev)
/**
* receive frame procedure.
* \param dev device structure.
+ * \param budget allocated budget.
*/
-static void synop3504_rx(struct net_device *dev)
+static void synop3504_rx(struct net_device *dev, int *budget)
{
struct sk_buff *new_skb;
struct sk_buff *skb;
@@ -875,9 +877,12 @@ static void synop3504_rx(struct net_device *dev)
struct dma_rx *rx = (struct dma_rx*)&priv->rx;
uint32_t n;
+ if(*budget == 0)
+ return;
+
TRACE("%s: Receive Done\n", dev->name);
- while(!rx->ring[rx->tail_ptr].status.bf.dma_own)
+ while((!rx->ring[rx->tail_ptr].status.bf.dma_own) && *budget)
{
n = rx->tail_ptr;
@@ -940,10 +945,9 @@ static void synop3504_rx(struct net_device *dev)
dev->last_rx = jiffies;
//Send RX packet to Linux
- if(netif_rx(skb) == NET_RX_DROP)
+ if(netif_receive_skb(skb) == NET_RX_DROP)
{
- //Linux buffers full
- printk(KERN_WARNING DRV_NAME ": %s: RX packet dropped\n", dev->name);
+ //Linux buffers full dropped by protocol
priv->stats.rx_dropped++;
}
@@ -970,6 +974,9 @@ reuse_buffer:
//Increase head pointer and check end of ring
if(++(rx->tail_ptr) >= RX_RING_SIZE)
rx->tail_ptr = 0;
+
+ //Decrease budget
+ (*budget)--;
}
}// synop3504_rx
@@ -985,7 +992,7 @@ static void synop3504_tx_done(struct net_device *dev)
TRACE("%s: Transmit Done (num=%d)\n", dev->name, tx->tail_ptr);
- if(!tx->ring[tx->tail_ptr].status.bf.dma_own)
+ while((tx->skbs[tx->tail_ptr] != NULL) && (!tx->ring[tx->tail_ptr].status.bf.dma_own))
{
n = tx->tail_ptr;
TRACE("Found\n");
@@ -1036,92 +1043,142 @@ static void synop3504_tx_done(struct net_device *dev)
}// synop3504_tx_done
/**
- * Receive frame procedure.
- * \param irq interrupt number.
- * \param dev device structure.
- * \param regs not used.
+ * Poll frame procedure.
+ * \param napi NAPI structure.
+ * \param budget max count of packets to receive.
* \return error code.
*/
-static irqreturn_t synop3504_interrupt(int irq, void * dev_id)
+static int synop3504_poll(struct napi_struct *napi, int budget)
{
- struct net_device *dev = (struct net_device*)dev_id;
+ struct net_device *dev = (struct net_device*)synop3504_device;
struct net_priv *priv = (struct net_priv*)dev->priv;
Synopsys *synop = &priv->synop;
SynopsysIntStatus status;
- //Get IRQ status
- SynopsysGetIntStatus(synop, &status);
+ do
+ {
+ //Get IRQ status
+ SynopsysGetIntStatus(synop, &status);
+ //Suppress rx, tx states and error bits (not needed in this function)
+ status.bf.rxState = 0;
+ status.bf.txState = 0;
+ status.bf.errorBits = 0;
- TRACE("%s: IRQ (status=0x%x)\n", dev->name, status.val);
+ TRACE("%s: IRQ (status=0x%x) ; budget=%d\n", dev->name, status.val, budget);
- if(status.val == 0)
- {
- return IRQ_HANDLED;
- }
+ if(status.val == 0)
+ break;
- //Normal Interrupt
- if(status.bf.intNormal)
- {
- //TX completed
- if(status.bf.intTxCompleted)
+ //Normal Interrupt
+ if(status.bf.intNormal)
{
- synop3504_tx_done(dev);
+ //TX completed
+ if(status.bf.intTxCompleted)
+ {
+ synop3504_tx_done(dev);
+
+ //Check the TX queue and re-enable it
+ if(netif_queue_stopped(dev))
+ {
+ netif_wake_queue(dev);
+ TRACE("%s: TX queue Waked Up\n", dev->name);
+ }
+ }
- //Check the TX queue and re-enable it
- if(netif_queue_stopped(dev))
+ //RX completed
+ if(status.bf.intRxCompleted)
{
- netif_wake_queue(dev);
- TRACE("%s: TX queue Waked Up\n", dev->name);
+ synop3504_rx(dev, &budget);
}
}
- //RX completed
- if(status.bf.intRxCompleted)
+ //AbNormal interrupt
+ if(status.bf.intAbnormal)
{
- synop3504_rx(dev);
+ //TX enter in stopped state
+ if(status.bf.intTxStopped)
+ {
+ netif_stop_queue(dev);
+ synop3504_txdesc_reset(dev);
+ TRACE("%s: TX queue Stopped\n", dev->name);
+ }
+
+ //TX underflow
+ if(status.bf.intTxUnderflow)
+ {
+ //Remove old buffers from TX descriptors
+ synop3504_tx_done(dev);
+ netif_start_queue(dev);
+ printk(KERN_ERR DRV_NAME ": %s: TX FIFO Error\n", dev->name);
+ }
+
+ //RX FIFO full
+ if(status.bf.intRxOverflow)
+ {
+ synop3504_rx(dev, &budget);
+ printk(KERN_ERR DRV_NAME ": %s: RX FIFO Error\n", dev->name);
+ }
+
+ //RX queue nearly full
+ if(status.bf.intRxNoBuffer)
+ {
+ //Refresh the rx dma
+ SynopsysRestartRx(synop);
+ printk(KERN_WARNING DRV_NAME ": %s: RX queue nearly Full\n", dev->name);
+ }
+
+ //Bus error
+ if(status.bf.intBusError)
+ {
+ printk(KERN_ERR DRV_NAME ": %s: Fatal BUS error (0x%x)\n", dev->name, status.bf.errorBits);
+ }
}
- }
+ } while(budget > 0);
- //AbNormal interrupt
- if(status.bf.intAbnormal)
+ if(status.val == 0)
{
- //TX enter in stopped state
- if(status.bf.intTxStopped)
- {
- netif_stop_queue(dev);
- synop3504_txdesc_reset(dev);
- TRACE("%s: TX queue Stopped\n", dev->name);
- }
+ netif_rx_complete(dev, &priv->napi);
+ //Enable interrupt
+ SynopsysEnableInt(synop);
+ return 0;
+ }
+ return 1;
+}// synop3504_poll
- //TX underflow
- if(status.bf.intTxUnderflow)
- {
- //Remove old buffers from TX descriptors
- synop3504_tx_done(dev);
- netif_start_queue(dev);
- printk(KERN_ERR DRV_NAME ": %s: TX FIFO Error\n", dev->name);
- }
+/**
+ * Receive frame procedure.
+ * \param irq interrupt number.
+ * \param dev device structure.
+ * \param regs not used.
+ * \return error code.
+ */
+static irqreturn_t synop3504_interrupt(int irq, void * dev_id)
+{
+ struct net_device *dev = (struct net_device*)dev_id;
+ struct net_priv *priv = NULL;
+ Synopsys *synop;
- //RX FIFO full
- if(status.bf.intRxOverflow)
- {
- synop3504_rx(dev);
- printk(KERN_ERR DRV_NAME ": %s: RX FIFO Error\n", dev->name);
- }
+ //Check pointer
+ if(dev == NULL)
+ return IRQ_NONE;
+ priv = (struct net_priv *)dev->priv;
+ if(priv == NULL)
+ return IRQ_NONE;
+ synop = &priv->synop;
+ if(synop == NULL)
+ return IRQ_NONE;
- //RX queue nearly full
- if(status.bf.intRxNoBuffer)
- {
- //Refresh the rx dma
- SynopsysRestartRx(synop);
- printk(KERN_WARNING DRV_NAME ": %s: RX queue nearly Full\n", dev->name);
- }
+ //Disable interrupt
+ SynopsysDisableInt(synop);
- //Bus error
- if(status.bf.intBusError)
- {
- printk(KERN_ERR DRV_NAME ": %s: Fatal BUS error (0x%x)\n", dev->name, status.bf.errorBits);
- }
+ //Prepare polling
+ if(netif_rx_schedule_prep(dev, &priv->napi))
+ {
+ __netif_rx_schedule(dev, &priv->napi);
+ }
+ else
+ {
+ printk(KERN_ERR DRV_NAME ": %s: ERROR interrupt while in poll\n", dev->name);
}
return IRQ_HANDLED;
@@ -1286,9 +1343,14 @@ static int synop3504_init(struct net_device *dev)
dev->hard_start_xmit = synop3504_tx;
dev->get_stats = synop3504_stats;
dev->set_multicast_list = synop3504_set_multicast;
+ dev->change_mtu = synop3504_change_mtu;
+ //TODO:
/* dev->tx_timeout = synop3504_tx_timeout; */
/* dev->watchdog_timeo = TX_TIMEOUT; */
- dev->change_mtu = synop3504_change_mtu;
+
+ //Set NAPI mode
+ netif_napi_add(dev, &priv->napi, &synop3504_poll, 64);
+ priv->napi.state=0;
//TODO:Setup MAC address for Linux (stored in NVRAM)
dev->dev_addr[0] = 0x00;
@@ -1318,6 +1380,7 @@ static int synop3504_init(struct net_device *dev)
*/
static int __init synop3504_module_init(void)
{
+ //TODO:Recode init process with platform device
int result;
struct net_device *dev;
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504_hw.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504_hw.c
index 60f357818e..f842843ef1 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504_hw.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504_hw.c
@@ -32,8 +32,8 @@
#include "synop3504_reg.h"
#include "synop3504_hw.h"
-#define TRACE(...) printk("Synop3504_hw:" __VA_ARGS__)
-//#define TRACE(...)
+//#define TRACE(...) printk("Synop3504_hw:" __VA_ARGS__)
+#define TRACE(...)
/**
* A not accurate delay.
@@ -275,7 +275,6 @@ void SynopsysGetIntStatus(Synopsys *synop, SynopsysIntStatus *status)
uint32_t st;
st = SynopsysReadDmaReg(synop, DmaStatus);
SynopsysWriteDmaReg(synop, DmaStatus, st);
- st &= (SynopsysReadDmaReg(synop, DmaInterrupt) | 0xFFFE0000);
status->val = st;
}