Commit fba4ed03 authored by Sandeep Gopalpet's avatar Sandeep Gopalpet Committed by David S. Miller

gianfar: Add Multiple Queue Support

This patch introduces multiple Tx and Rx queues.
The incoming packets can be classified into different queues
based on filer rules (out of scope of this patch). The number
of queues enabled will be based on a DTS entries fsl,num_tx_queues
and fsl,num_rx_queues.

Although we are enabling multiple queues, the interrupt coalescing
is on per device level (etsec-1.7 doesn't support multiple rxics
and txics).
Signed-off-by: default avatarSandeep Gopalpet <Sandeep.Kumar@freescale.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f4983704
This diff is collapsed.
......@@ -75,6 +75,10 @@
extern const char gfar_driver_name[];
extern const char gfar_driver_version[];
/* MAXIMUM NUMBER OF QUEUES SUPPORTED */
#define MAX_TX_QS 0x8
#define MAX_RX_QS 0x8
/* These need to be powers of 2 for this driver */
#define DEFAULT_TX_RING_SIZE 256
#define DEFAULT_RX_RING_SIZE 256
......@@ -172,12 +176,63 @@ extern const char gfar_driver_version[];
#define MINFLR_INIT_SETTINGS 0x00000040
/* Tqueue control */
#define TQUEUE_EN0 0x00008000
#define TQUEUE_EN1 0x00004000
#define TQUEUE_EN2 0x00002000
#define TQUEUE_EN3 0x00001000
#define TQUEUE_EN4 0x00000800
#define TQUEUE_EN5 0x00000400
#define TQUEUE_EN6 0x00000200
#define TQUEUE_EN7 0x00000100
#define TQUEUE_EN_ALL 0x0000FF00
#define TR03WT_WT0_MASK 0xFF000000
#define TR03WT_WT1_MASK 0x00FF0000
#define TR03WT_WT2_MASK 0x0000FF00
#define TR03WT_WT3_MASK 0x000000FF
#define TR47WT_WT4_MASK 0xFF000000
#define TR47WT_WT5_MASK 0x00FF0000
#define TR47WT_WT6_MASK 0x0000FF00
#define TR47WT_WT7_MASK 0x000000FF
/* Rqueue control */
#define RQUEUE_EX0 0x00800000
#define RQUEUE_EX1 0x00400000
#define RQUEUE_EX2 0x00200000
#define RQUEUE_EX3 0x00100000
#define RQUEUE_EX4 0x00080000
#define RQUEUE_EX5 0x00040000
#define RQUEUE_EX6 0x00020000
#define RQUEUE_EX7 0x00010000
#define RQUEUE_EX_ALL 0x00FF0000
#define RQUEUE_EN0 0x00000080
#define RQUEUE_EN1 0x00000040
#define RQUEUE_EN2 0x00000020
#define RQUEUE_EN3 0x00000010
#define RQUEUE_EN4 0x00000008
#define RQUEUE_EN5 0x00000004
#define RQUEUE_EN6 0x00000002
#define RQUEUE_EN7 0x00000001
#define RQUEUE_EN_ALL 0x000000FF
/* Init to do tx snooping for buffers and descriptors */
#define DMACTRL_INIT_SETTINGS 0x000000c3
#define DMACTRL_GRS 0x00000010
#define DMACTRL_GTS 0x00000008
#define TSTAT_CLEAR_THALT 0x80000000
#define TSTAT_CLEAR_THALT_ALL 0xFF000000
#define TSTAT_CLEAR_THALT 0x80000000
#define TSTAT_CLEAR_THALT0 0x80000000
#define TSTAT_CLEAR_THALT1 0x40000000
#define TSTAT_CLEAR_THALT2 0x20000000
#define TSTAT_CLEAR_THALT3 0x10000000
#define TSTAT_CLEAR_THALT4 0x08000000
#define TSTAT_CLEAR_THALT5 0x04000000
#define TSTAT_CLEAR_THALT6 0x02000000
#define TSTAT_CLEAR_THALT7 0x01000000
/* Interrupt coalescing macros */
#define IC_ICEN 0x80000000
......@@ -228,6 +283,13 @@ extern const char gfar_driver_version[];
#define TCTRL_IPCSEN 0x00004000
#define TCTRL_TUCSEN 0x00002000
#define TCTRL_VLINS 0x00001000
#define TCTRL_THDF 0x00000800
#define TCTRL_RFCPAUSE 0x00000010
#define TCTRL_TFCPAUSE 0x00000008
#define TCTRL_TXSCHED_MASK 0x00000006
#define TCTRL_TXSCHED_INIT 0x00000000
#define TCTRL_TXSCHED_PRIO 0x00000002
#define TCTRL_TXSCHED_WRRS 0x00000004
#define TCTRL_INIT_CSUM (TCTRL_TUCSEN | TCTRL_IPCSEN)
#define IEVENT_INIT_CLEAR 0xffffffff
......@@ -700,6 +762,8 @@ struct gfar {
#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200
#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400
#define DEFAULT_MAPPING 0xFF
/**
* struct gfar_priv_tx_q - per tx queue structure
* @txlock: per queue tx spin lock
......@@ -743,7 +807,6 @@ struct gfar_priv_tx_q {
/**
* struct gfar_priv_rx_q - per rx queue structure
* @rxlock: per queue rx spin lock
* @napi: the napi poll function
* @rx_skbuff: skb pointers
* @skb_currx: currently use skb pointer
* @rx_bd_base: First rx buffer descriptor
......@@ -757,8 +820,8 @@ struct gfar_priv_tx_q {
struct gfar_priv_rx_q {
spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
struct napi_struct napi;
struct sk_buff ** rx_skbuff;
dma_addr_t rx_bd_dma_base;
struct rxbd8 *rx_bd_base;
struct rxbd8 *cur_rx;
struct net_device *dev;
......@@ -772,6 +835,7 @@ struct gfar_priv_rx_q {
/**
* struct gfar_priv_grp - per group structure
* @napi: the napi poll function
* @priv: back pointer to the priv structure
* @regs: the ioremapped register space for this group
* @grp_id: group id for this group
......@@ -785,8 +849,17 @@ struct gfar_priv_rx_q {
struct gfar_priv_grp {
spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
struct napi_struct napi;
struct gfar_private *priv;
struct gfar __iomem *regs;
unsigned int rx_bit_map;
unsigned int tx_bit_map;
unsigned int num_tx_queues;
unsigned int num_rx_queues;
unsigned int rstat;
unsigned int tstat;
unsigned int imask;
unsigned int ievent;
unsigned int interruptTransmit;
unsigned int interruptReceive;
unsigned int interruptError;
......@@ -807,13 +880,21 @@ struct gfar_priv_grp {
*/
struct gfar_private {
/* Indicates how many tx, rx queues are enabled */
unsigned int num_tx_queues;
unsigned int num_rx_queues;
/* The total tx and rx ring size for the enabled queues */
unsigned int total_tx_ring_size;
unsigned int total_rx_ring_size;
struct device_node *node;
struct net_device *ndev;
struct of_device *ofdev;
struct gfar_priv_grp gfargrp;
struct gfar_priv_tx_q *tx_queue;
struct gfar_priv_rx_q *rx_queue;
struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
/* RX per device parameters */
unsigned int rx_buffer_size;
......@@ -844,6 +925,7 @@ struct gfar_private {
unsigned char rx_csum_enable:1,
extended_hash:1,
bd_stash_en:1,
rx_filer_enable:1,
wol_en:1; /* Wake-on-LAN enabled */
unsigned short padding;
......@@ -874,6 +956,10 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
out_be32(addr, val);
}
extern void lock_rx_qs(struct gfar_private *priv);
extern void lock_tx_qs(struct gfar_private *priv);
extern void unlock_rx_qs(struct gfar_private *priv);
extern void unlock_tx_qs(struct gfar_private *priv);
extern irqreturn_t gfar_receive(int irq, void *dev_id);
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
......
......@@ -204,9 +204,11 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
if (NULL == phydev)
return -ENODEV;
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue;
tx_queue = priv->tx_queue[0];
rx_queue = priv->rx_queue[0];
/* etsec-1.7 and older versions have only one txic
* and rxic regs although they support multiple queues */
cmd->maxtxpkt = get_icft_value(tx_queue->txic);
cmd->maxrxpkt = get_icft_value(rx_queue->rxic);
......@@ -298,8 +300,8 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
if (NULL == priv->phydev)
return -ENODEV;
rx_queue = priv->rx_queue;
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue[0];
tx_queue = priv->tx_queue[0];
rxtime = get_ictt_value(rx_queue->rxic);
rxcount = get_icft_value(rx_queue->rxic);
......@@ -357,8 +359,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
return -EOPNOTSUPP;
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue;
tx_queue = priv->tx_queue[0];
rx_queue = priv->rx_queue[0];
/* Set up rx coalescing */
if ((cvals->rx_coalesce_usecs == 0) ||
......@@ -429,8 +431,8 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue;
tx_queue = priv->tx_queue[0];
rx_queue = priv->rx_queue[0];
rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE;
rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE;
......@@ -453,9 +455,7 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
int err = 0;
int err = 0, i = 0;
if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
return -EINVAL;
......@@ -475,37 +475,41 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
return -EINVAL;
}
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue;
if (dev->flags & IFF_UP) {
unsigned long flags;
/* Halt TX and RX, and process the frames which
* have already been received */
spin_lock_irqsave(&tx_queue->txlock, flags);
spin_lock(&rx_queue->rxlock);
local_irq_save(flags);
lock_tx_qs(priv);
lock_rx_qs(priv);
gfar_halt(dev);
spin_unlock(&rx_queue->rxlock);
spin_unlock_irqrestore(&tx_queue->txlock, flags);
unlock_rx_qs(priv);
unlock_tx_qs(priv);
local_irq_restore(flags);
gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
for (i = 0; i < priv->num_rx_queues; i++)
gfar_clean_rx_ring(priv->rx_queue[i],
priv->rx_queue[i]->rx_ring_size);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
}
/* Change the size */
rx_queue->rx_ring_size = rvals->rx_pending;
tx_queue->tx_ring_size = rvals->tx_pending;
tx_queue->num_txbdfree = tx_queue->tx_ring_size;
for (i = 0; i < priv->num_rx_queues; i++) {
priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
priv->tx_queue[i]->num_txbdfree = priv->tx_queue[i]->tx_ring_size;
}
/* Rebuild the rings with the new size */
if (dev->flags & IFF_UP) {
err = startup_gfar(dev);
netif_wake_queue(dev);
netif_tx_wake_all_queues(dev);
}
return err;
}
......@@ -513,29 +517,29 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_priv_rx_q *rx_queue = NULL;
struct gfar_priv_tx_q *tx_queue = NULL;
unsigned long flags;
int err = 0;
int err = 0, i = 0;
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
return -EOPNOTSUPP;
tx_queue = priv->tx_queue;
rx_queue = priv->rx_queue;
if (dev->flags & IFF_UP) {
/* Halt TX and RX, and process the frames which
* have already been received */
spin_lock_irqsave(&tx_queue->txlock, flags);
spin_lock(&rx_queue->rxlock);
local_irq_save(flags);
lock_tx_qs(priv);
lock_rx_qs(priv);
gfar_halt(dev);
spin_unlock(&rx_queue->rxlock);
spin_unlock_irqrestore(&tx_queue->txlock, flags);
unlock_tx_qs(priv);
unlock_rx_qs(priv);
local_irq_save(flags);
gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
for (i = 0; i < priv->num_rx_queues; i++)
gfar_clean_rx_ring(priv->rx_queue[i],
priv->rx_queue[i]->rx_ring_size);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
......@@ -547,7 +551,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
if (dev->flags & IFF_UP) {
err = startup_gfar(dev);
netif_wake_queue(dev);
netif_tx_wake_all_queues(dev);
}
return err;
}
......
......@@ -51,7 +51,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_rx_q *rx_queue = NULL;
int new_setting = 0;
u32 temp;
unsigned long flags;
......@@ -59,7 +58,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING))
return count;
rx_queue = priv->rx_queue;
/* Find out the new setting */
if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
......@@ -70,7 +68,9 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
else
return count;
spin_lock_irqsave(&rx_queue->rxlock, flags);
local_irq_save(flags);
lock_rx_qs(priv);
/* Set the new stashing value */
priv->bd_stash_en = new_setting;
......@@ -84,7 +84,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
gfar_write(&regs->attr, temp);
spin_unlock_irqrestore(&rx_queue->rxlock, flags);
unlock_rx_qs(priv);
local_irq_restore(flags);
return count;
}
......@@ -105,7 +106,6 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_rx_q *rx_queue = NULL;
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
......@@ -113,9 +113,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
return count;
rx_queue = priv->rx_queue;
local_irq_save(flags);
lock_rx_qs(priv);
spin_lock_irqsave(&rx_queue->rxlock, flags);
if (length > priv->rx_buffer_size)
goto out;
......@@ -140,7 +140,8 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
gfar_write(&regs->attr, temp);
out:
spin_unlock_irqrestore(&rx_queue->rxlock, flags);
unlock_rx_qs(priv);
local_irq_restore(flags);
return count;
}
......@@ -164,7 +165,6 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_rx_q *rx_queue = NULL;
unsigned short index = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
......@@ -172,9 +172,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
return count;
rx_queue = priv->rx_queue;
local_irq_save(flags);
lock_rx_qs(priv);
spin_lock_irqsave(&rx_queue->rxlock, flags);
if (index > priv->rx_stash_size)
goto out;
......@@ -189,7 +189,8 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
gfar_write(&regs->attreli, flags);
out:
spin_unlock_irqrestore(&rx_queue->rxlock, flags);
unlock_rx_qs(priv);
local_irq_restore(flags);
return count;
}
......@@ -212,7 +213,6 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_tx_q *tx_queue = NULL;
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
......@@ -220,9 +220,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
if (length > GFAR_MAX_FIFO_THRESHOLD)
return count;
tx_queue = priv->tx_queue;
spin_lock_irqsave(&tx_queue->txlock, flags);
local_irq_save(flags);
lock_tx_qs(priv);
priv->fifo_threshold = length;
......@@ -231,7 +230,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
temp |= length;
gfar_write(&regs->fifo_tx_thr, temp);
spin_unlock_irqrestore(&tx_queue->txlock, flags);
unlock_tx_qs(priv);
local_irq_restore(flags);
return count;
}
......@@ -253,7 +253,6 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_tx_q *tx_queue = NULL;
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
......@@ -261,8 +260,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
if (num > GFAR_MAX_FIFO_STARVE)
return count;
tx_queue = priv->tx_queue;
spin_lock_irqsave(&tx_queue->txlock, flags);
local_irq_save(flags);
lock_tx_qs(priv);
priv->fifo_starve = num;
......@@ -271,7 +270,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
temp |= num;
gfar_write(&regs->fifo_tx_starve, temp);
spin_unlock_irqrestore(&tx_queue->txlock, flags);
unlock_tx_qs(priv);
local_irq_restore(flags);
return count;
}
......@@ -294,7 +294,6 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
{
struct gfar_private *priv = netdev_priv(to_net_dev(dev));
struct gfar __iomem *regs = priv->gfargrp.regs;
struct gfar_priv_tx_q *tx_queue = NULL;
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
......@@ -302,8 +301,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
if (num > GFAR_MAX_FIFO_STARVE_OFF)
return count;
tx_queue = priv->tx_queue;
spin_lock_irqsave(&tx_queue->txlock, flags);
local_irq_save(flags);
lock_tx_qs(priv);
priv->fifo_starve_off = num;
......@@ -312,7 +311,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
temp |= num;
gfar_write(&regs->fifo_tx_starve_shutoff, temp);
spin_unlock_irqrestore(&tx_queue->txlock, flags);
unlock_tx_qs(priv);
local_irq_restore(flags);
return count;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment