Skip to content

Commit

Permalink
gianfar: Drop GFAR_MQ_POLLING support
Browse files Browse the repository at this point in the history
Gianfar used to enable all 8 Rx queues (DMA rings) per
ethernet device, even though the controller can only
support 2 interrupt lines at most.  This meant that
multiple Rx queues would have to be grouped per NAPI poll
routine, and the CPU would have to split the budget and
service them in a round robin manner.  The overhead of
this scheme proved to outweight the potential benefits.
The alternative was to introduce the "Single Queue" polling
mode, supporting one Rx queue per NAPI, which became the
default packet processing option and helped improve the
performance of the driver.
MQ_POLLING also relies on undocumeted device tree properties
to specify how to map the 8 Rx and Tx queues to a given
interrupt line (aka "interrupt group").  Using module parameters
to enable this mode wasn't an option either.  Long story short,
MQ_POLLING became obsolete, now it is just dead code, and no
one asked for it so far.
For the Tx queues, multi-queue support (more than 1 Tx queue
per CPU) could be revisited by adding tc MQPRIO support, but
again, one has to consider that there are only 2 interrupt lines.
So the NAPI poll routine would have to service multiple Tx rings.

Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Claudiu Manoil authored and David S. Miller committed Apr 16, 2021
1 parent 0e672f3 commit 8eda54c
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 176 deletions.
170 changes: 11 additions & 159 deletions drivers/net/ethernet/freescale/gianfar.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,7 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
if (priv->rx_filer_enable) {
rctrl |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
/* Program the RIR0 reg with the required distribution */
if (priv->poll_mode == GFAR_SQ_POLLING)
gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
else /* GFAR_MQ_POLLING */
gfar_write(&regs->rir0, DEFAULT_8RXQ_RIR0);
gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
}

/* Restore PROMISC mode */
Expand Down Expand Up @@ -521,29 +518,9 @@ static int gfar_parse_group(struct device_node *np,
grp->priv = priv;
spin_lock_init(&grp->grplock);
if (priv->mode == MQ_MG_MODE) {
u32 rxq_mask, txq_mask;
int ret;

/* One Q per interrupt group: Q0 to G0, Q1 to G1 */
grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);

ret = of_property_read_u32(np, "fsl,rx-bit-map", &rxq_mask);
if (!ret) {
grp->rx_bit_map = rxq_mask ?
rxq_mask : (DEFAULT_MAPPING >> priv->num_grps);
}

ret = of_property_read_u32(np, "fsl,tx-bit-map", &txq_mask);
if (!ret) {
grp->tx_bit_map = txq_mask ?
txq_mask : (DEFAULT_MAPPING >> priv->num_grps);
}

if (priv->poll_mode == GFAR_SQ_POLLING) {
/* One Q per interrupt group: Q0 to G0, Q1 to G1 */
grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
}
} else {
grp->rx_bit_map = 0xFF;
grp->tx_bit_map = 0xFF;
Expand Down Expand Up @@ -649,18 +626,15 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
u32 stash_len = 0;
u32 stash_idx = 0;
unsigned int num_tx_qs, num_rx_qs;
unsigned short mode, poll_mode;
unsigned short mode;

if (!np)
return -ENODEV;

if (of_device_is_compatible(np, "fsl,etsec2")) {
if (of_device_is_compatible(np, "fsl,etsec2"))
mode = MQ_MG_MODE;
poll_mode = GFAR_SQ_POLLING;
} else {
else
mode = SQ_SG_MODE;
poll_mode = GFAR_SQ_POLLING;
}

if (mode == SQ_SG_MODE) {
num_tx_qs = 1;
Expand All @@ -676,22 +650,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
return -EINVAL;
}

if (poll_mode == GFAR_SQ_POLLING) {
num_tx_qs = num_grps; /* one txq per int group */
num_rx_qs = num_grps; /* one rxq per int group */
} else { /* GFAR_MQ_POLLING */
u32 tx_queues, rx_queues;
int ret;

/* parse the num of HW tx and rx queues */
ret = of_property_read_u32(np, "fsl,num_tx_queues",
&tx_queues);
num_tx_qs = ret ? 1 : tx_queues;

ret = of_property_read_u32(np, "fsl,num_rx_queues",
&rx_queues);
num_rx_qs = ret ? 1 : rx_queues;
}
num_tx_qs = num_grps; /* one txq per int group */
num_rx_qs = num_grps; /* one rxq per int group */
}

if (num_tx_qs > MAX_TX_QS) {
Expand All @@ -717,7 +677,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
priv->ndev = dev;

priv->mode = mode;
priv->poll_mode = poll_mode;

priv->num_tx_queues = num_tx_qs;
netif_set_real_num_rx_queues(dev, num_rx_qs);
Expand Down Expand Up @@ -2691,106 +2650,6 @@ static int gfar_poll_tx_sq(struct napi_struct *napi, int budget)
return 0;
}

static int gfar_poll_rx(struct napi_struct *napi, int budget)
{
struct gfar_priv_grp *gfargrp =
container_of(napi, struct gfar_priv_grp, napi_rx);
struct gfar_private *priv = gfargrp->priv;
struct gfar __iomem *regs = gfargrp->regs;
struct gfar_priv_rx_q *rx_queue = NULL;
int work_done = 0, work_done_per_q = 0;
int i, budget_per_q = 0;
unsigned long rstat_rxf;
int num_act_queues;

/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived
*/
gfar_write(&regs->ievent, IEVENT_RX_MASK);

rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;

num_act_queues = bitmap_weight(&rstat_rxf, MAX_RX_QS);
if (num_act_queues)
budget_per_q = budget/num_act_queues;

for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
/* skip queue if not active */
if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
continue;

rx_queue = priv->rx_queue[i];
work_done_per_q =
gfar_clean_rx_ring(rx_queue, budget_per_q);
work_done += work_done_per_q;

/* finished processing this queue */
if (work_done_per_q < budget_per_q) {
/* clear active queue hw indication */
gfar_write(&regs->rstat,
RSTAT_CLEAR_RXF0 >> i);
num_act_queues--;

if (!num_act_queues)
break;
}
}

if (!num_act_queues) {
u32 imask;
napi_complete_done(napi, work_done);

/* Clear the halt bit in RSTAT */
gfar_write(&regs->rstat, gfargrp->rstat);

spin_lock_irq(&gfargrp->grplock);
imask = gfar_read(&regs->imask);
imask |= IMASK_RX_DEFAULT;
gfar_write(&regs->imask, imask);
spin_unlock_irq(&gfargrp->grplock);
}

return work_done;
}

static int gfar_poll_tx(struct napi_struct *napi, int budget)
{
struct gfar_priv_grp *gfargrp =
container_of(napi, struct gfar_priv_grp, napi_tx);
struct gfar_private *priv = gfargrp->priv;
struct gfar __iomem *regs = gfargrp->regs;
struct gfar_priv_tx_q *tx_queue = NULL;
int has_tx_work = 0;
int i;

/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived
*/
gfar_write(&regs->ievent, IEVENT_TX_MASK);

for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
tx_queue = priv->tx_queue[i];
/* run Tx cleanup to completion */
if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
gfar_clean_tx_ring(tx_queue);
has_tx_work = 1;
}
}

if (!has_tx_work) {
u32 imask;
napi_complete(napi);

spin_lock_irq(&gfargrp->grplock);
imask = gfar_read(&regs->imask);
imask |= IMASK_TX_DEFAULT;
gfar_write(&regs->imask, imask);
spin_unlock_irq(&gfargrp->grplock);
}

return 0;
}

/* GFAR error interrupt handler */
static irqreturn_t gfar_error(int irq, void *grp_id)
{
Expand Down Expand Up @@ -3348,17 +3207,10 @@ static int gfar_probe(struct platform_device *ofdev)

/* Register for napi ...We are registering NAPI for each grp */
for (i = 0; i < priv->num_grps; i++) {
if (priv->poll_mode == GFAR_SQ_POLLING) {
netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
netif_tx_napi_add(dev, &priv->gfargrp[i].napi_tx,
gfar_poll_tx_sq, 2);
} else {
netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
gfar_poll_rx, GFAR_DEV_WEIGHT);
netif_tx_napi_add(dev, &priv->gfargrp[i].napi_tx,
gfar_poll_tx, 2);
}
netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
netif_tx_napi_add(dev, &priv->gfargrp[i].napi_tx,
gfar_poll_tx_sq, 2);
}

if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
Expand Down
17 changes: 0 additions & 17 deletions drivers/net/ethernet/freescale/gianfar.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,22 +909,6 @@ enum {
MQ_MG_MODE
};

/* GFAR_SQ_POLLING: Single Queue NAPI polling mode
* The driver supports a single pair of RX/Tx queues
* per interrupt group (Rx/Tx int line). MQ_MG mode
* devices have 2 interrupt groups, so the device will
* have a total of 2 Tx and 2 Rx queues in this case.
* GFAR_MQ_POLLING: Multi Queue NAPI polling mode
* The driver supports all the 8 Rx and Tx HW queues
* each queue mapped by the Device Tree to one of
* the 2 interrupt groups. This mode implies significant
* processing overhead (CPU and controller level).
*/
enum gfar_poll_mode {
GFAR_SQ_POLLING = 0,
GFAR_MQ_POLLING
};

/*
* Per TX queue stats
*/
Expand Down Expand Up @@ -1105,7 +1089,6 @@ struct gfar_private {
unsigned long state;

unsigned short mode;
unsigned short poll_mode;
unsigned int num_tx_queues;
unsigned int num_rx_queues;
unsigned int num_grps;
Expand Down

0 comments on commit 8eda54c

Please sign in to comment.