From eb1e93a10ef5bedfc15d1404dc6a2c46d843cde9 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:41:55 +0200 Subject: [PATCH 1/7] net: mvpp2: fix MVPP21_ISR_RXQ_GROUP_REG definition The MVPP21_ISR_RXQ_GROUP_REG register is not indexed by rxq, but by port, so we fix the parameter name accordingly. There are no functional changes. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 48d21c1e09f27..4b36a153328a7 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -185,7 +185,7 @@ /* Interrupt Cause and Mask registers */ #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) #define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0 -#define MVPP21_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) +#define MVPP21_ISR_RXQ_GROUP_REG(port) (0x5400 + 4 * (port)) #define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400 #define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf From b5635ad2e4906e8f8bd3ab145059ce413c03a7ad Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:41:56 +0200 Subject: [PATCH 2/7] net: mvpp2: remove RX queue group reset code The RX queue group allocation is anyway re-done later in mvpp2_port_init(), so resetting it in mvpp2_init() is not very useful, and will be annoying as we are going to rework the RX queue group allocation logic. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 4b36a153328a7..537d2b4adef32 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -6845,23 +6845,6 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) /* Rx Fifo Init */ mvpp2_rx_fifo_init(priv); - /* Reset Rx queue group interrupt configuration */ - for (i = 0; i < MVPP2_MAX_PORTS; i++) { - if (priv->hw_version == MVPP21) { - mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(i), - rxq_number); - continue; - } else { - u32 val; - - val = (i << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET); - mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); - - val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); - mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); - } - } - if (priv->hw_version == MVPP21) writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT, priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG); From 09f8397553a24c66e0141ec57f2c1801acd4e4a0 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:41:57 +0200 Subject: [PATCH 3/7] net: mvpp2: introduce per-port nrxqs/ntxqs variables Currently, the global variables rxq_number and txq_number hold the number of per-port TXQs and RXQs. Until now, such numbers were constant regardless of the driver configuration. As we are going to introduce different modes for TX and RX queues, these numbers will depend on the configuration (PPv2.1 vs. PPv2.2, exact queue distribution logic). Therefore, as a preparation, we move the number of RXQs and TXQs in the 'struct mvpp2_port' structure, next to the RXQs and TXQs descriptor arrays. For now, they remain initialized to the same default values as rxq_number/txq_number used to be initialized, but this will change in future commits. The only non-mechanical change in this patch is that the check to verify hardware constraints on the number of RXQs and TXQs is moved from mvpp2_probe() to mvpp2_port_probe(), since it's now in mvpp2_port_probe() that we initialize the per-port count of RXQ and TXQ. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 83 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 537d2b4adef32..84908aa883749 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -768,7 +768,9 @@ struct mvpp2_port { void __iomem *base; struct mvpp2_rx_queue **rxqs; + unsigned int nrxqs; struct mvpp2_tx_queue **txqs; + unsigned int ntxqs; struct net_device *dev; int pkt_size; @@ -1062,13 +1064,6 @@ struct mvpp2_bm_pool { u32 port_map; }; -/* Static declaractions */ - -/* Number of RXQs used by single port */ -static int rxq_number = MVPP2_DEFAULT_RXQ; -/* Number of TXQs used by single port */ -static int txq_number = MVPP2_MAX_TXQ; - #define MVPP2_DRIVER_NAME "mvpp2" #define MVPP2_DRIVER_VERSION "1.0" @@ -4070,7 +4065,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) port->pool_long->port_map |= (1 << port->id); - for (rxq = 0; rxq < rxq_number; rxq++) + for (rxq = 0; rxq < port->nrxqs; rxq++) mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id); } @@ -4084,7 +4079,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) port->pool_short->port_map |= (1 << port->id); - for (rxq = 0; rxq < rxq_number; rxq++) + for (rxq = 0; rxq < port->nrxqs; rxq++) mvpp2_rxq_short_pool_set(port, rxq, port->pool_short->id); } @@ -4376,7 +4371,7 @@ static void mvpp2_defaults_set(struct mvpp2_port *port) MVPP2_RX_LOW_LATENCY_PKT_SIZE(256)); /* Enable Rx cache snoop */ - for (lrxq = 0; lrxq < rxq_number; lrxq++) { + for (lrxq = 0; lrxq < port->nrxqs; lrxq++) { queue = port->rxqs[lrxq]->id; val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); val |= MVPP2_SNOOP_PKT_SIZE_MASK | @@ -4394,7 +4389,7 @@ static void mvpp2_ingress_enable(struct mvpp2_port *port) u32 val; int lrxq, queue; - for (lrxq = 0; lrxq < rxq_number; lrxq++) { + for (lrxq = 0; lrxq < port->nrxqs; lrxq++) { queue = port->rxqs[lrxq]->id; val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); val &= ~MVPP2_RXQ_DISABLE_MASK; @@ -4407,7 +4402,7 @@ static void mvpp2_ingress_disable(struct mvpp2_port *port) u32 val; int lrxq, queue; - for (lrxq = 0; lrxq < rxq_number; lrxq++) { + for (lrxq = 0; lrxq < port->nrxqs; lrxq++) { queue = port->rxqs[lrxq]->id; val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); val |= MVPP2_RXQ_DISABLE_MASK; @@ -4426,7 +4421,7 @@ static void mvpp2_egress_enable(struct mvpp2_port *port) /* Enable all initialized TXs. */ qmap = 0; - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { struct mvpp2_tx_queue *txq = port->txqs[queue]; if (txq->descs) @@ -4712,7 +4707,7 @@ static void mvpp2_txq_sent_counter_clear(void *arg) struct mvpp2_port *port = arg; int queue; - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { int id = port->txqs[queue]->id; mvpp2_percpu_read(port->priv, smp_processor_id(), @@ -4753,7 +4748,7 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val); } - for (txq = 0; txq < txq_number; txq++) { + for (txq = 0; txq < port->ntxqs; txq++) { val = mvpp2_read(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq)); size = val & MVPP2_TXQ_TOKEN_SIZE_MAX; @@ -5229,7 +5224,7 @@ static void mvpp2_cleanup_txqs(struct mvpp2_port *port) val |= MVPP2_TX_PORT_FLUSH_MASK(port->id); mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val); - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { txq = port->txqs[queue]; mvpp2_txq_clean(port, txq); mvpp2_txq_deinit(port, txq); @@ -5246,7 +5241,7 @@ static void mvpp2_cleanup_rxqs(struct mvpp2_port *port) { int queue; - for (queue = 0; queue < rxq_number; queue++) + for (queue = 0; queue < port->nrxqs; queue++) mvpp2_rxq_deinit(port, port->rxqs[queue]); } @@ -5255,7 +5250,7 @@ static int mvpp2_setup_rxqs(struct mvpp2_port *port) { int queue, err; - for (queue = 0; queue < rxq_number; queue++) { + for (queue = 0; queue < port->nrxqs; queue++) { err = mvpp2_rxq_init(port, port->rxqs[queue]); if (err) goto err_cleanup; @@ -5273,7 +5268,7 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port) struct mvpp2_tx_queue *txq; int queue, err; - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { txq = port->txqs[queue]; err = mvpp2_txq_init(port, txq); if (err) @@ -5385,7 +5380,7 @@ static void mvpp2_tx_proc_cb(unsigned long data) port_pcpu->timer_scheduled = false; /* Process all the Tx queues */ - cause = (1 << txq_number) - 1; + cause = (1 << port->ntxqs) - 1; tx_todo = mvpp2_tx_done(port, cause); /* Set the timer in case not all the packets were processed */ @@ -6228,7 +6223,7 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, struct mvpp2_port *port = netdev_priv(dev); int queue; - for (queue = 0; queue < rxq_number; queue++) { + for (queue = 0; queue < port->nrxqs; queue++) { struct mvpp2_rx_queue *rxq = port->rxqs[queue]; rxq->time_coal = c->rx_coalesce_usecs; @@ -6237,7 +6232,7 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, mvpp2_rx_time_coal_set(port, rxq); } - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { struct mvpp2_tx_queue *txq = port->txqs[queue]; txq->done_pkts_coal = c->tx_max_coalesced_frames; @@ -6373,15 +6368,20 @@ static int mvpp2_port_init(struct mvpp2_port *port) struct mvpp2_txq_pcpu *txq_pcpu; int queue, cpu, err; - if (port->first_rxq + rxq_number > + /* Checks for hardware constraints */ + if (port->first_rxq + port->nrxqs > MVPP2_MAX_PORTS * priv->max_port_rxqs) return -EINVAL; + if (port->nrxqs % 4 || (port->nrxqs > priv->max_port_rxqs) || + (port->ntxqs > MVPP2_MAX_TXQ)) + return -EINVAL; + /* Disable port */ mvpp2_egress_disable(port); mvpp2_port_disable(port); - port->txqs = devm_kcalloc(dev, txq_number, sizeof(*port->txqs), + port->txqs = devm_kcalloc(dev, port->ntxqs, sizeof(*port->txqs), GFP_KERNEL); if (!port->txqs) return -ENOMEM; @@ -6389,7 +6389,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) /* Associate physical Tx queues to this port and initialize. * The mapping is predefined. */ - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { int queue_phy_id = mvpp2_txq_phys(port->id, queue); struct mvpp2_tx_queue *txq; @@ -6416,7 +6416,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) port->txqs[queue] = txq; } - port->rxqs = devm_kcalloc(dev, rxq_number, sizeof(*port->rxqs), + port->rxqs = devm_kcalloc(dev, port->nrxqs, sizeof(*port->rxqs), GFP_KERNEL); if (!port->rxqs) { err = -ENOMEM; @@ -6424,7 +6424,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) } /* Allocate and initialize Rx queue for this port */ - for (queue = 0; queue < rxq_number; queue++) { + for (queue = 0; queue < port->nrxqs; queue++) { struct mvpp2_rx_queue *rxq; /* Map physical Rx queue to port's logical Rx queue */ @@ -6444,19 +6444,19 @@ static int mvpp2_port_init(struct mvpp2_port *port) /* Configure Rx queue group interrupt for this port */ if (priv->hw_version == MVPP21) { mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id), - rxq_number); + port->nrxqs); } else { u32 val; val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET); mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); - val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); + val = (port->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); } /* Create Rx descriptor rings */ - for (queue = 0; queue < rxq_number; queue++) { + for (queue = 0; queue < port->nrxqs; queue++) { struct mvpp2_rx_queue *rxq = port->rxqs[queue]; rxq->size = port->rx_ring_size; @@ -6484,7 +6484,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) return 0; err_free_percpu: - for (queue = 0; queue < txq_number; queue++) { + for (queue = 0; queue < port->ntxqs; queue++) { if (!port->txqs[queue]) continue; free_percpu(port->txqs[queue]->pcpu); @@ -6505,12 +6505,16 @@ static int mvpp2_port_probe(struct platform_device *pdev, const char *dt_mac_addr; const char *mac_from; char hw_mac_addr[ETH_ALEN]; + unsigned int ntxqs, nrxqs; u32 id; int features; int phy_mode; int err, i, cpu; - dev = alloc_etherdev_mqs(sizeof(*port), txq_number, rxq_number); + ntxqs = MVPP2_MAX_TXQ; + nrxqs = MVPP2_DEFAULT_RXQ; + + dev = alloc_etherdev_mqs(sizeof(*port), ntxqs, nrxqs); if (!dev) return -ENOMEM; @@ -6540,6 +6544,8 @@ static int mvpp2_port_probe(struct platform_device *pdev, dev->ethtool_ops = &mvpp2_eth_tool_ops; port = netdev_priv(dev); + port->ntxqs = ntxqs; + port->nrxqs = nrxqs; port->irq = irq_of_parse_and_map(port_node, 0); if (port->irq <= 0) { @@ -6553,7 +6559,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->priv = priv; port->id = id; if (priv->hw_version == MVPP21) - port->first_rxq = port->id * rxq_number; + port->first_rxq = port->id * port->nrxqs; else port->first_rxq = port->id * priv->max_port_rxqs; @@ -6662,7 +6668,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, err_free_port_pcpu: free_percpu(port->pcpu); err_free_txq_pcpu: - for (i = 0; i < txq_number; i++) + for (i = 0; i < port->ntxqs; i++) free_percpu(port->txqs[i]->pcpu); err_free_stats: free_percpu(port->stats); @@ -6683,7 +6689,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port) of_node_put(port->phy_node); free_percpu(port->pcpu); free_percpu(port->stats); - for (i = 0; i < txq_number; i++) + for (i = 0; i < port->ntxqs; i++) free_percpu(port->txqs[i]->pcpu); irq_dispose_mapping(port->irq); free_netdev(port->dev); @@ -6800,13 +6806,6 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) int err, i; u32 val; - /* Checks for hardware constraints */ - if (rxq_number % 4 || (rxq_number > priv->max_port_rxqs) || - (txq_number > MVPP2_MAX_TXQ)) { - dev_err(&pdev->dev, "invalid queue size parameter\n"); - return -EINVAL; - } - /* MBUS windows configuration */ dram_target_info = mv_mbus_dram_info(); if (dram_target_info) From df089aa0acd75bb605e4cce72982942173e742ad Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:41:58 +0200 Subject: [PATCH 4/7] net: mvpp2: move from cpu-centric naming to "software thread" naming The PPv2.2 IP has a concept of "software thread", with all registers of the PPv2.2 mapped 8 times, for concurrent accesses by 8 "software threads". In addition, interrupts on RX queues are associated to such "software thread". For most cases, we map a "software thread" to the more conventional concept of CPU, but we will soon have one exception: we will have a model where we have one TX interrupt per CPU (each using one software thread), and all RX events mapped to another software thread (associated to another interrupt). In preparation for this change, it makes sense to change the naming from MVPP2_MAX_CPUS to MVPP2_MAX_THREADS, and plan for 8 software threads instead of 4 currently. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 84908aa883749..af38a215f0e00 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -685,7 +685,7 @@ enum mvpp2_prs_l3_cast { #define MVPP21_ADDR_SPACE_SZ 0 #define MVPP22_ADDR_SPACE_SZ SZ_64K -#define MVPP2_MAX_CPUS 4 +#define MVPP2_MAX_THREADS 8 enum mvpp2_bm_type { MVPP2_BM_FREE, @@ -701,11 +701,12 @@ struct mvpp2 { void __iomem *lms_base; void __iomem *iface_base; - /* On PPv2.2, each CPU can access the base register through a - * separate address space, each 64 KB apart from each - * other. + /* On PPv2.2, each "software thread" can access the base + * register through a separate address space, each 64 KB apart + * from each other. Typically, such address spaces will be + * used per CPU. */ - void __iomem *cpu_base[MVPP2_MAX_CPUS]; + void __iomem *swth_base[MVPP2_MAX_THREADS]; /* Common clocks */ struct clk *pp_clk; @@ -1071,12 +1072,12 @@ struct mvpp2_bm_pool { static void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data) { - writel(data, priv->cpu_base[0] + offset); + writel(data, priv->swth_base[0] + offset); } static u32 mvpp2_read(struct mvpp2 *priv, u32 offset) { - return readl(priv->cpu_base[0] + offset); + return readl(priv->swth_base[0] + offset); } /* These accessors should be used to access: @@ -1118,13 +1119,13 @@ static u32 mvpp2_read(struct mvpp2 *priv, u32 offset) static void mvpp2_percpu_write(struct mvpp2 *priv, int cpu, u32 offset, u32 data) { - writel(data, priv->cpu_base[cpu] + offset); + writel(data, priv->swth_base[cpu] + offset); } static u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu, u32 offset) { - return readl(priv->cpu_base[cpu] + offset); + return readl(priv->swth_base[cpu] + offset); } static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port, @@ -6874,7 +6875,7 @@ static int mvpp2_probe(struct platform_device *pdev) struct mvpp2 *priv; struct resource *res; void __iomem *base; - int port_count, cpu; + int port_count, i; int err; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -6901,12 +6902,12 @@ static int mvpp2_probe(struct platform_device *pdev) return PTR_ERR(priv->iface_base); } - for_each_present_cpu(cpu) { + for (i = 0; i < MVPP2_MAX_THREADS; i++) { u32 addr_space_sz; addr_space_sz = (priv->hw_version == MVPP21 ? MVPP21_ADDR_SPACE_SZ : MVPP22_ADDR_SPACE_SZ); - priv->cpu_base[cpu] = base + cpu * addr_space_sz; + priv->swth_base[i] = base + i * addr_space_sz; } if (priv->hw_version == MVPP21) From 591f4cfab38a6e69573210b21c0554e1acbbd532 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:41:59 +0200 Subject: [PATCH 5/7] net: mvpp2: introduce queue_vector concept In preparation to the introduction of TX interrupts and improved RX queue distribution, this commit introduces the concept of "queue vector". A queue vector represents a number of RX and/or TX queues, and an associated NAPI instance and interrupt. This commit currently only creates a single queue_vector, so there are no changes in behavior, but it paves the way for additional queue_vector in the next commits. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 223 ++++++++++++++++++++------- 1 file changed, 169 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index af38a215f0e00..1bf327271cee3 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -686,6 +686,7 @@ enum mvpp2_prs_l3_cast { #define MVPP22_ADDR_SPACE_SZ SZ_64K #define MVPP2_MAX_THREADS 8 +#define MVPP2_MAX_QVECS MVPP2_MAX_THREADS enum mvpp2_bm_type { MVPP2_BM_FREE, @@ -753,6 +754,18 @@ struct mvpp2_port_pcpu { struct tasklet_struct tx_done_tasklet; }; +struct mvpp2_queue_vector { + int irq; + struct napi_struct napi; + enum { MVPP2_QUEUE_VECTOR_SHARED, MVPP2_QUEUE_VECTOR_PRIVATE } type; + int sw_thread_id; + u16 sw_thread_mask; + int first_rxq; + int nrxqs; + u32 pending_cause_rx; + struct mvpp2_port *port; +}; + struct mvpp2_port { u8 id; @@ -761,8 +774,6 @@ struct mvpp2_port { */ int gop_id; - int irq; - struct mvpp2 *priv; /* Per-port registers' base address */ @@ -776,9 +787,6 @@ struct mvpp2_port { int pkt_size; - u32 pending_cause_rx; - struct napi_struct napi; - /* Per-CPU port control */ struct mvpp2_port_pcpu __percpu *pcpu; @@ -800,6 +808,9 @@ struct mvpp2_port { /* Index of first port's physical RXQ */ u8 first_rxq; + + struct mvpp2_queue_vector qvecs[MVPP2_MAX_QVECS]; + unsigned int nqvecs; }; /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the @@ -4121,22 +4132,40 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) static inline void mvpp2_interrupts_enable(struct mvpp2_port *port) { - int cpu, cpu_mask = 0; + int i, sw_thread_mask = 0; + + for (i = 0; i < port->nqvecs; i++) + sw_thread_mask |= port->qvecs[i].sw_thread_mask; - for_each_present_cpu(cpu) - cpu_mask |= 1 << cpu; mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), - MVPP2_ISR_ENABLE_INTERRUPT(cpu_mask)); + MVPP2_ISR_ENABLE_INTERRUPT(sw_thread_mask)); } static inline void mvpp2_interrupts_disable(struct mvpp2_port *port) { - int cpu, cpu_mask = 0; + int i, sw_thread_mask = 0; + + for (i = 0; i < port->nqvecs; i++) + sw_thread_mask |= port->qvecs[i].sw_thread_mask; + + mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), + MVPP2_ISR_DISABLE_INTERRUPT(sw_thread_mask)); +} + +static inline void mvpp2_qvec_interrupt_enable(struct mvpp2_queue_vector *qvec) +{ + struct mvpp2_port *port = qvec->port; - for_each_present_cpu(cpu) - cpu_mask |= 1 << cpu; mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), - MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask)); + MVPP2_ISR_ENABLE_INTERRUPT(qvec->sw_thread_mask)); +} + +static inline void mvpp2_qvec_interrupt_disable(struct mvpp2_queue_vector *qvec) +{ + struct mvpp2_port *port = qvec->port; + + mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), + MVPP2_ISR_DISABLE_INTERRUPT(qvec->sw_thread_mask)); } /* Mask the current CPU's Rx/Tx interrupts @@ -5287,11 +5316,11 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port) /* The callback for per-port interrupt */ static irqreturn_t mvpp2_isr(int irq, void *dev_id) { - struct mvpp2_port *port = (struct mvpp2_port *)dev_id; + struct mvpp2_queue_vector *qv = dev_id; - mvpp2_interrupts_disable(port); + mvpp2_qvec_interrupt_disable(qv); - napi_schedule(&port->napi); + napi_schedule(&qv->napi); return IRQ_HANDLED; } @@ -5494,8 +5523,8 @@ static u32 mvpp2_skb_tx_csum(struct mvpp2_port *port, struct sk_buff *skb) } /* Main rx processing */ -static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, - struct mvpp2_rx_queue *rxq) +static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + int rx_todo, struct mvpp2_rx_queue *rxq) { struct net_device *dev = port->dev; int rx_received; @@ -5573,7 +5602,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, skb->protocol = eth_type_trans(skb, dev); mvpp2_rx_csum(port, rx_status, skb); - napi_gro_receive(&port->napi, skb); + napi_gro_receive(napi, skb); } if (rcvd_pkts) { @@ -5782,8 +5811,11 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) u32 cause_rx_tx, cause_rx, cause_misc; int rx_done = 0; struct mvpp2_port *port = netdev_priv(napi->dev); + struct mvpp2_queue_vector *qv; int cpu = smp_processor_id(); + qv = container_of(napi, struct mvpp2_queue_vector, napi); + /* Rx/Tx cause register * * Bits 0-15: each bit indicates received packets on the Rx queue @@ -5812,7 +5844,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; /* Process RX packets */ - cause_rx |= port->pending_cause_rx; + cause_rx |= qv->pending_cause_rx; while (cause_rx && budget > 0) { int count; struct mvpp2_rx_queue *rxq; @@ -5821,7 +5853,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) if (!rxq) break; - count = mvpp2_rx(port, budget, rxq); + count = mvpp2_rx(port, napi, budget, rxq); rx_done += count; budget -= count; if (budget > 0) { @@ -5837,9 +5869,9 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) cause_rx = 0; napi_complete_done(napi, rx_done); - mvpp2_interrupts_enable(port); + mvpp2_qvec_interrupt_enable(qv); } - port->pending_cause_rx = cause_rx; + qv->pending_cause_rx = cause_rx; return rx_done; } @@ -5847,11 +5879,13 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) static void mvpp2_start_dev(struct mvpp2_port *port) { struct net_device *ndev = port->dev; + int i; mvpp2_gmac_max_rx_size_set(port); mvpp2_txp_max_tx_size_set(port); - napi_enable(&port->napi); + for (i = 0; i < port->nqvecs; i++) + napi_enable(&port->qvecs[i].napi); /* Enable interrupts on all CPUs */ mvpp2_interrupts_enable(port); @@ -5865,6 +5899,7 @@ static void mvpp2_start_dev(struct mvpp2_port *port) static void mvpp2_stop_dev(struct mvpp2_port *port) { struct net_device *ndev = port->dev; + int i; /* Stop new packets from arriving to RXQs */ mvpp2_ingress_disable(port); @@ -5874,7 +5909,8 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) /* Disable interrupts on all CPUs */ mvpp2_interrupts_disable(port); - napi_disable(&port->napi); + for (i = 0; i < port->nqvecs; i++) + napi_disable(&port->qvecs[i].napi); netif_carrier_off(port->dev); netif_tx_stop_all_queues(port->dev); @@ -5960,6 +5996,40 @@ static void mvpp2_phy_disconnect(struct mvpp2_port *port) phy_disconnect(ndev->phydev); } +static int mvpp2_irqs_init(struct mvpp2_port *port) +{ + int err, i; + + for (i = 0; i < port->nqvecs; i++) { + struct mvpp2_queue_vector *qv = port->qvecs + i; + + err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv); + if (err) + goto err; + } + + return 0; +err: + for (i = 0; i < port->nqvecs; i++) { + struct mvpp2_queue_vector *qv = port->qvecs + i; + + free_irq(qv->irq, qv); + } + + return err; +} + +static void mvpp2_irqs_deinit(struct mvpp2_port *port) +{ + int i; + + for (i = 0; i < port->nqvecs; i++) { + struct mvpp2_queue_vector *qv = port->qvecs + i; + + free_irq(qv->irq, qv); + } +} + static int mvpp2_open(struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); @@ -6002,9 +6072,9 @@ static int mvpp2_open(struct net_device *dev) goto err_cleanup_rxqs; } - err = request_irq(port->irq, mvpp2_isr, 0, dev->name, port); + err = mvpp2_irqs_init(port); if (err) { - netdev_err(port->dev, "cannot request IRQ %d\n", port->irq); + netdev_err(port->dev, "cannot init IRQs\n"); goto err_cleanup_txqs; } @@ -6023,7 +6093,7 @@ static int mvpp2_open(struct net_device *dev) return 0; err_free_irq: - free_irq(port->irq, port); + mvpp2_irqs_deinit(port); err_cleanup_txqs: mvpp2_cleanup_txqs(port); err_cleanup_rxqs: @@ -6043,7 +6113,7 @@ static int mvpp2_stop(struct net_device *dev) /* Mask interrupts on all CPUs */ on_each_cpu(mvpp2_interrupts_mask, port, 1); - free_irq(port->irq, port); + mvpp2_irqs_deinit(port); for_each_present_cpu(cpu) { port_pcpu = per_cpu_ptr(port->pcpu, cpu); @@ -6361,6 +6431,66 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = { .set_link_ksettings = phy_ethtool_set_link_ksettings, }; +static int mvpp2_queue_vectors_init(struct mvpp2_port *port, + struct device_node *port_node) +{ + struct mvpp2_queue_vector *v = &port->qvecs[0]; + + v->first_rxq = 0; + v->nrxqs = port->nrxqs; + v->type = MVPP2_QUEUE_VECTOR_SHARED; + v->sw_thread_id = 0; + v->sw_thread_mask = *cpumask_bits(cpu_online_mask); + v->port = port; + v->irq = irq_of_parse_and_map(port_node, 0); + if (v->irq <= 0) + return -EINVAL; + netif_napi_add(port->dev, &v->napi, mvpp2_poll, + NAPI_POLL_WEIGHT); + + port->nqvecs = 1; + + return 0; +} + +static void mvpp2_queue_vectors_deinit(struct mvpp2_port *port) +{ + int i; + + for (i = 0; i < port->nqvecs; i++) + irq_dispose_mapping(port->qvecs[i].irq); +} + +/* Configure Rx queue group interrupt for this port */ +static void mvpp2_rx_irqs_setup(struct mvpp2_port *port) +{ + struct mvpp2 *priv = port->priv; + u32 val; + int i; + + if (priv->hw_version == MVPP21) { + mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id), + port->nrxqs); + return; + } + + /* Handle the more complicated PPv2.2 case */ + for (i = 0; i < port->nqvecs; i++) { + struct mvpp2_queue_vector *qv = port->qvecs + i; + + if (!qv->nrxqs) + continue; + + val = qv->sw_thread_id; + val |= port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET; + mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); + + val = qv->first_rxq; + val |= qv->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET; + mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); + } +} + /* Initialize port HW */ static int mvpp2_port_init(struct mvpp2_port *port) { @@ -6442,19 +6572,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) port->rxqs[queue] = rxq; } - /* Configure Rx queue group interrupt for this port */ - if (priv->hw_version == MVPP21) { - mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id), - port->nrxqs); - } else { - u32 val; - - val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET); - mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); - - val = (port->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); - mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); - } + mvpp2_rx_irqs_setup(port); /* Create Rx descriptor rings */ for (queue = 0; queue < port->nrxqs; queue++) { @@ -6545,14 +6663,13 @@ static int mvpp2_port_probe(struct platform_device *pdev, dev->ethtool_ops = &mvpp2_eth_tool_ops; port = netdev_priv(dev); + port->dev = dev; port->ntxqs = ntxqs; port->nrxqs = nrxqs; - port->irq = irq_of_parse_and_map(port_node, 0); - if (port->irq <= 0) { - err = -EINVAL; + err = mvpp2_queue_vectors_init(port, port_node); + if (err) goto err_free_netdev; - } if (of_property_read_bool(port_node, "marvell,loopback")) port->flags |= MVPP2_F_LOOPBACK; @@ -6572,14 +6689,14 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(port->base)) { err = PTR_ERR(port->base); - goto err_free_irq; + goto err_deinit_qvecs; } } else { if (of_property_read_u32(port_node, "gop-port-id", &port->gop_id)) { err = -EINVAL; dev_err(&pdev->dev, "missing gop-port-id value\n"); - goto err_free_irq; + goto err_deinit_qvecs; } port->base = priv->iface_base + MVPP22_GMAC_BASE(port->gop_id); @@ -6589,7 +6706,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats); if (!port->stats) { err = -ENOMEM; - goto err_free_irq; + goto err_deinit_qvecs; } dt_mac_addr = of_get_mac_address(port_node); @@ -6610,7 +6727,6 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->tx_ring_size = MVPP2_MAX_TXD; port->rx_ring_size = MVPP2_MAX_RXD; - port->dev = dev; SET_NETDEV_DEV(dev, &pdev->dev); err = mvpp2_port_init(port); @@ -6645,7 +6761,6 @@ static int mvpp2_port_probe(struct platform_device *pdev, (unsigned long)dev); } - netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT); features = NETIF_F_SG | NETIF_F_IP_CSUM; dev->features = features | NETIF_F_RXCSUM; dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO; @@ -6673,8 +6788,8 @@ static int mvpp2_port_probe(struct platform_device *pdev, free_percpu(port->txqs[i]->pcpu); err_free_stats: free_percpu(port->stats); -err_free_irq: - irq_dispose_mapping(port->irq); +err_deinit_qvecs: + mvpp2_queue_vectors_deinit(port); err_free_netdev: of_node_put(phy_node); free_netdev(dev); @@ -6692,7 +6807,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port) free_percpu(port->stats); for (i = 0; i < port->ntxqs; i++) free_percpu(port->txqs[i]->pcpu); - irq_dispose_mapping(port->irq); + mvpp2_queue_vectors_deinit(port); free_netdev(port->dev); } From 213f428f5056affa627056a5953eec58e3adf5a3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:42:00 +0200 Subject: [PATCH 6/7] net: mvpp2: add support for TX interrupts and RX queue distribution modes This commit adds the support for two related features: - Support for TX interrupts, with one interrupt for each CPU - Support for different RX queue distribution modes MVPP2_QDIST_SINGLE_MODE where a single interrupt, shared by all CPUs, receives the RX events, and MVPP2_QDIST_MULTI_MODE, where the per-CPU interrupts used for TX events are also used for RX events. Since additional interrupts are needed, an update to the Device Tree binding is needed. However, backward compatibility is preserved with the old Device Tree binding, by gracefully degrading to the original behavior, with only one RX interrupt, and TX completion being handled by an hrtimer. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 275 ++++++++++++++++++++++++--- 1 file changed, 246 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 1bf327271cee3..39bc8fbbdd650 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -120,6 +120,9 @@ #define MVPP2_TXQ_DESC_ADDR_REG 0x2084 #define MVPP2_TXQ_DESC_SIZE_REG 0x2088 #define MVPP2_TXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_TXQ_THRESH_REG 0x2094 +#define MVPP2_TXQ_THRESH_OFFSET 16 +#define MVPP2_TXQ_THRESH_MASK 0x3fff #define MVPP2_AGGR_TXQ_UPDATE_REG 0x2090 #define MVPP2_TXQ_INDEX_REG 0x2098 #define MVPP2_TXQ_PREF_BUF_REG 0x209c @@ -183,6 +186,9 @@ #define MVPP22_AXI_CODE_DOMAIN_SYSTEM 3 /* Interrupt Cause and Mask registers */ +#define MVPP2_ISR_TX_THRESHOLD_REG(port) (0x5140 + 4 * (port)) +#define MVPP2_MAX_ISR_TX_THRESHOLD 0xfffff0 + #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) #define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0 #define MVPP21_ISR_RXQ_GROUP_REG(port) (0x5400 + 4 * (port)) @@ -206,6 +212,7 @@ #define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port)) #define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff #define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000 +#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET 16 #define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24) #define MVPP2_CAUSE_FCS_ERR_MASK BIT(25) #define MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK BIT(26) @@ -372,6 +379,7 @@ /* Coalescing */ #define MVPP2_TXDONE_COAL_PKTS_THRESH 15 #define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL +#define MVPP2_TXDONE_COAL_USEC 1000 #define MVPP2_RX_COAL_PKTS 32 #define MVPP2_RX_COAL_USEC 100 @@ -811,6 +819,9 @@ struct mvpp2_port { struct mvpp2_queue_vector qvecs[MVPP2_MAX_QVECS]; unsigned int nqvecs; + bool has_tx_irqs; + + u32 tx_time_coal; }; /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the @@ -1076,6 +1087,15 @@ struct mvpp2_bm_pool { u32 port_map; }; +/* Queue modes */ +#define MVPP2_QDIST_SINGLE_MODE 0 +#define MVPP2_QDIST_MULTI_MODE 1 + +static int queue_mode = MVPP2_QDIST_SINGLE_MODE; + +module_param(queue_mode, int, 0444); +MODULE_PARM_DESC(queue_mode, "Set queue_mode (single=0, multi=1)"); + #define MVPP2_DRIVER_NAME "mvpp2" #define MVPP2_DRIVER_VERSION "1.0" @@ -4187,11 +4207,40 @@ static void mvpp2_interrupts_mask(void *arg) static void mvpp2_interrupts_unmask(void *arg) { struct mvpp2_port *port = arg; + u32 val; + + val = MVPP2_CAUSE_MISC_SUM_MASK | + MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + if (port->has_tx_irqs) + val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; mvpp2_percpu_write(port->priv, smp_processor_id(), - MVPP2_ISR_RX_TX_MASK_REG(port->id), - (MVPP2_CAUSE_MISC_SUM_MASK | - MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)); + MVPP2_ISR_RX_TX_MASK_REG(port->id), val); +} + +static void +mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask) +{ + u32 val; + int i; + + if (port->priv->hw_version != MVPP22) + return; + + if (mask) + val = 0; + else + val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + + for (i = 0; i < port->nqvecs; i++) { + struct mvpp2_queue_vector *v = port->qvecs + i; + + if (v->type != MVPP2_QUEUE_VECTOR_SHARED) + continue; + + mvpp2_percpu_write(port->priv, v->sw_thread_id, + MVPP2_ISR_RX_TX_MASK_REG(port->id), val); + } } /* Port configuration routines */ @@ -4812,6 +4861,23 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, put_cpu(); } +/* For some reason in the LSP this is done on each CPU. Why ? */ +static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq) +{ + int cpu = get_cpu(); + u32 val; + + if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK) + txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK; + + val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET); + mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_THRESH_REG, val); + + put_cpu(); +} + static u32 mvpp2_usec_to_cycles(u32 usec, unsigned long clk_hz) { u64 tmp = (u64)clk_hz * usec; @@ -4848,6 +4914,22 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val); } +static void mvpp2_tx_time_coal_set(struct mvpp2_port *port) +{ + unsigned long freq = port->priv->tclk; + u32 val = mvpp2_usec_to_cycles(port->tx_time_coal, freq); + + if (val > MVPP2_MAX_ISR_TX_THRESHOLD) { + port->tx_time_coal = + mvpp2_cycles_to_usec(MVPP2_MAX_ISR_TX_THRESHOLD, freq); + + /* re-evaluate to get actual register value */ + val = mvpp2_usec_to_cycles(port->tx_time_coal, freq); + } + + mvpp2_write(port->priv, MVPP2_ISR_TX_THRESHOLD_REG(port->id), val); +} + /* Free Tx queue skbuffs */ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, @@ -4906,7 +4988,8 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, netif_tx_wake_queue(nq); } -static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause) +static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, + int cpu) { struct mvpp2_tx_queue *txq; struct mvpp2_txq_pcpu *txq_pcpu; @@ -4917,7 +5000,7 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause) if (!txq) break; - txq_pcpu = this_cpu_ptr(txq->pcpu); + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); if (txq_pcpu->count) { mvpp2_txq_done(port, txq, txq_pcpu); @@ -5305,6 +5388,14 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port) goto err_cleanup; } + if (port->has_tx_irqs) { + mvpp2_tx_time_coal_set(port); + for (queue = 0; queue < port->ntxqs; queue++) { + txq = port->txqs[queue]; + mvpp2_tx_pkts_coal_set(port, txq); + } + } + on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1); return 0; @@ -5411,7 +5502,7 @@ static void mvpp2_tx_proc_cb(unsigned long data) /* Process all the Tx queues */ cause = (1 << port->ntxqs) - 1; - tx_todo = mvpp2_tx_done(port, cause); + tx_todo = mvpp2_tx_done(port, cause, smp_processor_id()); /* Set the timer in case not all the packets were processed */ if (tx_todo) @@ -5787,7 +5878,8 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) mvpp2_txq_done(port, txq, txq_pcpu); /* Set the timer in case not all frags were processed */ - if (txq_pcpu->count <= frags && txq_pcpu->count > 0) { + if (!port->has_tx_irqs && txq_pcpu->count <= frags && + txq_pcpu->count > 0) { struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu); mvpp2_timer_set(port_pcpu); @@ -5808,7 +5900,7 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause) static int mvpp2_poll(struct napi_struct *napi, int budget) { - u32 cause_rx_tx, cause_rx, cause_misc; + u32 cause_rx_tx, cause_rx, cause_tx, cause_misc; int rx_done = 0; struct mvpp2_port *port = netdev_priv(napi->dev); struct mvpp2_queue_vector *qv; @@ -5826,11 +5918,10 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) * * Each CPU has its own Rx/Tx cause register */ - cause_rx_tx = mvpp2_percpu_read(port->priv, cpu, + cause_rx_tx = mvpp2_percpu_read(port->priv, qv->sw_thread_id, MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); - cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; - cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK; + cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK; if (cause_misc) { mvpp2_cause_error(port->dev, cause_misc); @@ -5841,9 +5932,15 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK); } - cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; + if (cause_tx) { + cause_tx >>= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET; + mvpp2_tx_done(port, cause_tx, qv->sw_thread_id); + } /* Process RX packets */ + cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + cause_rx <<= qv->first_rxq; cause_rx |= qv->pending_cause_rx; while (cause_rx && budget > 0) { int count; @@ -6006,6 +6103,10 @@ static int mvpp2_irqs_init(struct mvpp2_port *port) err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv); if (err) goto err; + + if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) + irq_set_affinity_hint(qv->irq, + cpumask_of(qv->sw_thread_id)); } return 0; @@ -6013,6 +6114,7 @@ static int mvpp2_irqs_init(struct mvpp2_port *port) for (i = 0; i < port->nqvecs; i++) { struct mvpp2_queue_vector *qv = port->qvecs + i; + irq_set_affinity_hint(qv->irq, NULL); free_irq(qv->irq, qv); } @@ -6026,6 +6128,7 @@ static void mvpp2_irqs_deinit(struct mvpp2_port *port) for (i = 0; i < port->nqvecs; i++) { struct mvpp2_queue_vector *qv = port->qvecs + i; + irq_set_affinity_hint(qv->irq, NULL); free_irq(qv->irq, qv); } } @@ -6087,6 +6190,7 @@ static int mvpp2_open(struct net_device *dev) /* Unmask interrupts on all CPUs */ on_each_cpu(mvpp2_interrupts_unmask, port, 1); + mvpp2_shared_interrupt_mask_unmask(port, false); mvpp2_start_dev(port); @@ -6112,14 +6216,17 @@ static int mvpp2_stop(struct net_device *dev) /* Mask interrupts on all CPUs */ on_each_cpu(mvpp2_interrupts_mask, port, 1); + mvpp2_shared_interrupt_mask_unmask(port, true); mvpp2_irqs_deinit(port); - for_each_present_cpu(cpu) { - port_pcpu = per_cpu_ptr(port->pcpu, cpu); + if (!port->has_tx_irqs) { + for_each_present_cpu(cpu) { + port_pcpu = per_cpu_ptr(port->pcpu, cpu); - hrtimer_cancel(&port_pcpu->tx_done_timer); - port_pcpu->timer_scheduled = false; - tasklet_kill(&port_pcpu->tx_done_tasklet); + hrtimer_cancel(&port_pcpu->tx_done_timer); + port_pcpu->timer_scheduled = false; + tasklet_kill(&port_pcpu->tx_done_tasklet); + } } mvpp2_cleanup_rxqs(port); mvpp2_cleanup_txqs(port); @@ -6303,10 +6410,18 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, mvpp2_rx_time_coal_set(port, rxq); } + if (port->has_tx_irqs) { + port->tx_time_coal = c->tx_coalesce_usecs; + mvpp2_tx_time_coal_set(port); + } + for (queue = 0; queue < port->ntxqs; queue++) { struct mvpp2_tx_queue *txq = port->txqs[queue]; txq->done_pkts_coal = c->tx_max_coalesced_frames; + + if (port->has_tx_irqs) + mvpp2_tx_pkts_coal_set(port, txq); } return 0; @@ -6431,8 +6546,11 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = { .set_link_ksettings = phy_ethtool_set_link_ksettings, }; -static int mvpp2_queue_vectors_init(struct mvpp2_port *port, - struct device_node *port_node) +/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that + * had a single IRQ defined per-port. + */ +static int mvpp2_simple_queue_vectors_init(struct mvpp2_port *port, + struct device_node *port_node) { struct mvpp2_queue_vector *v = &port->qvecs[0]; @@ -6453,6 +6571,66 @@ static int mvpp2_queue_vectors_init(struct mvpp2_port *port, return 0; } +static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port, + struct device_node *port_node) +{ + struct mvpp2_queue_vector *v; + int i, ret; + + port->nqvecs = num_possible_cpus(); + if (queue_mode == MVPP2_QDIST_SINGLE_MODE) + port->nqvecs += 1; + + for (i = 0; i < port->nqvecs; i++) { + char irqname[16]; + + v = port->qvecs + i; + + v->port = port; + v->type = MVPP2_QUEUE_VECTOR_PRIVATE; + v->sw_thread_id = i; + v->sw_thread_mask = BIT(i); + + snprintf(irqname, sizeof(irqname), "tx-cpu%d", i); + + if (queue_mode == MVPP2_QDIST_MULTI_MODE) { + v->first_rxq = i * MVPP2_DEFAULT_RXQ; + v->nrxqs = MVPP2_DEFAULT_RXQ; + } else if (queue_mode == MVPP2_QDIST_SINGLE_MODE && + i == (port->nqvecs - 1)) { + v->first_rxq = 0; + v->nrxqs = port->nrxqs; + v->type = MVPP2_QUEUE_VECTOR_SHARED; + strncpy(irqname, "rx-shared", sizeof(irqname)); + } + + v->irq = of_irq_get_byname(port_node, irqname); + if (v->irq <= 0) { + ret = -EINVAL; + goto err; + } + + netif_napi_add(port->dev, &v->napi, mvpp2_poll, + NAPI_POLL_WEIGHT); + } + + return 0; + +err: + for (i = 0; i < port->nqvecs; i++) + irq_dispose_mapping(port->qvecs[i].irq); + return ret; +} + +static int mvpp2_queue_vectors_init(struct mvpp2_port *port, + struct device_node *port_node) +{ + if (port->has_tx_irqs) + return mvpp2_multi_queue_vectors_init(port, port_node); + else + return mvpp2_simple_queue_vectors_init(port, port_node); +} + static void mvpp2_queue_vectors_deinit(struct mvpp2_port *port) { int i; @@ -6512,6 +6690,8 @@ static int mvpp2_port_init(struct mvpp2_port *port) mvpp2_egress_disable(port); mvpp2_port_disable(port); + port->tx_time_coal = MVPP2_TXDONE_COAL_USEC; + port->txqs = devm_kcalloc(dev, port->ntxqs, sizeof(*port->txqs), GFP_KERNEL); if (!port->txqs) @@ -6611,6 +6791,30 @@ static int mvpp2_port_init(struct mvpp2_port *port) return err; } +/* Checks if the port DT description has the TX interrupts + * described. On PPv2.1, there are no such interrupts. On PPv2.2, + * there are available, but we need to keep support for old DTs. + */ +static bool mvpp2_port_has_tx_irqs(struct mvpp2 *priv, + struct device_node *port_node) +{ + char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1", + "tx-cpu2", "tx-cpu3" }; + int ret, i; + + if (priv->hw_version == MVPP21) + return false; + + for (i = 0; i < 5; i++) { + ret = of_property_match_string(port_node, "interrupt-names", + irqs[i]); + if (ret < 0) + return false; + } + + return true; +} + /* Ports initialization */ static int mvpp2_port_probe(struct platform_device *pdev, struct device_node *port_node, @@ -6625,13 +6829,22 @@ static int mvpp2_port_probe(struct platform_device *pdev, const char *mac_from; char hw_mac_addr[ETH_ALEN]; unsigned int ntxqs, nrxqs; + bool has_tx_irqs; u32 id; int features; int phy_mode; int err, i, cpu; + has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node); + + if (!has_tx_irqs) + queue_mode = MVPP2_QDIST_SINGLE_MODE; + ntxqs = MVPP2_MAX_TXQ; - nrxqs = MVPP2_DEFAULT_RXQ; + if (priv->hw_version == MVPP22 && queue_mode == MVPP2_QDIST_MULTI_MODE) + nrxqs = MVPP2_DEFAULT_RXQ * num_possible_cpus(); + else + nrxqs = MVPP2_DEFAULT_RXQ; dev = alloc_etherdev_mqs(sizeof(*port), ntxqs, nrxqs); if (!dev) @@ -6666,6 +6879,8 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->dev = dev; port->ntxqs = ntxqs; port->nrxqs = nrxqs; + port->priv = priv; + port->has_tx_irqs = has_tx_irqs; err = mvpp2_queue_vectors_init(port, port_node); if (err) @@ -6674,7 +6889,6 @@ static int mvpp2_port_probe(struct platform_device *pdev, if (of_property_read_bool(port_node, "marvell,loopback")) port->flags |= MVPP2_F_LOOPBACK; - port->priv = priv; port->id = id; if (priv->hw_version == MVPP21) port->first_rxq = port->id * port->nrxqs; @@ -6749,16 +6963,19 @@ static int mvpp2_port_probe(struct platform_device *pdev, goto err_free_txq_pcpu; } - for_each_present_cpu(cpu) { - port_pcpu = per_cpu_ptr(port->pcpu, cpu); + if (!port->has_tx_irqs) { + for_each_present_cpu(cpu) { + port_pcpu = per_cpu_ptr(port->pcpu, cpu); - hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL_PINNED); - port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb; - port_pcpu->timer_scheduled = false; + hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb; + port_pcpu->timer_scheduled = false; - tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb, - (unsigned long)dev); + tasklet_init(&port_pcpu->tx_done_tasklet, + mvpp2_tx_proc_cb, + (unsigned long)dev); + } } features = NETIF_F_SG | NETIF_F_IP_CSUM; From 5d3ecb24b5363f5249b78792409e879ec5ec7922 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 3 Aug 2017 10:42:01 +0200 Subject: [PATCH 7/7] dt-bindings: net: marvell-pp2: update interrupt-names with TX interrupts The PPv2.2 unit has several interrupts used for TX completion notification. This commit updates the Device Tree binding describing this HW block to mention such interrupts. While at it, we update the example to use a recent Device Tree example, that uses interrupts going through the ICU, and not to the GIC directly. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- .../devicetree/bindings/net/marvell-pp2.txt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell-pp2.txt b/Documentation/devicetree/bindings/net/marvell-pp2.txt index 6b4956beff8c4..8918ad3ccf148 100644 --- a/Documentation/devicetree/bindings/net/marvell-pp2.txt +++ b/Documentation/devicetree/bindings/net/marvell-pp2.txt @@ -41,6 +41,10 @@ Optional properties (port): - marvell,loopback: port is loopback mode - phy: a phandle to a phy node defining the PHY address (as the reg property, a single integer). +- interrupt-names: if more than a single interrupt for rx is given, must + be the name associated to the interrupts listed. Valid + names are: "tx-cpu0", "tx-cpu1", "tx-cpu2", "tx-cpu3", + "rx-shared". Example for marvell,armada-375-pp2: @@ -80,19 +84,37 @@ cpm_ethernet: ethernet@0 { clock-names = "pp_clk", "gop_clk", "gp_clk"; eth0: eth0 { - interrupts = ; + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; port-id = <0>; gop-port-id = <0>; }; eth1: eth1 { - interrupts = ; + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; port-id = <1>; gop-port-id = <2>; }; eth2: eth2 { - interrupts = ; + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; port-id = <2>; gop-port-id = <3>; };