diff options
author | Felix Fietkau <nbd@nbd.name> | 2016-05-21 22:16:56 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2016-05-22 16:04:37 +0200 |
commit | df98acc6a1252456608958fc17f7da3ae4cfb46c (patch) | |
tree | 2ed792928e0aa18d5dc3a8031b670629fa175167 /target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch | |
parent | e90245237c971cda70e9c1752e9bce4cc3cbef4f (diff) | |
download | upstream-df98acc6a1252456608958fc17f7da3ae4cfb46c.tar.gz upstream-df98acc6a1252456608958fc17f7da3ae4cfb46c.tar.bz2 upstream-df98acc6a1252456608958fc17f7da3ae4cfb46c.zip |
mvebu: backport upstream ethernet driver improvements and enable buffer manager support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch')
-rw-r--r-- | target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch b/target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch new file mode 100644 index 0000000000..636c6cf364 --- /dev/null +++ b/target/linux/mvebu/patches-4.4/033-net-mvneta-Associate-RX-queues-with-each-CPU.patch @@ -0,0 +1,278 @@ +From: Gregory CLEMENT <gregory.clement@free-electrons.com> +Date: Wed, 9 Dec 2015 18:23:49 +0100 +Subject: [PATCH] net: mvneta: Associate RX queues with each CPU + +We enable the percpu interrupt for all the CPU and we just associate a +CPU to a few queue at the neta level. The mapping between the CPUs and +the queues is static. The queues are associated to the CPU module the +number of CPUs. However currently we only use on RX queue for a given +Ethernet port. + +Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -110,9 +110,16 @@ + #define MVNETA_CPU_MAP(cpu) (0x2540 + ((cpu) << 2)) + #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff + #define MVNETA_CPU_TXQ_ACCESS_ALL_MASK 0x0000ff00 ++#define MVNETA_CPU_RXQ_ACCESS(rxq) BIT(rxq) + #define MVNETA_RXQ_TIME_COAL_REG(q) (0x2580 + ((q) << 2)) + +-/* Exception Interrupt Port/Queue Cause register */ ++/* Exception Interrupt Port/Queue Cause register ++ * ++ * Their behavior depend of the mapping done using the PCPX2Q ++ * registers. For a given CPU if the bit associated to a queue is not ++ * set, then for the register a read from this CPU will always return ++ * 0 and a write won't do anything ++ */ + + #define MVNETA_INTR_NEW_CAUSE 0x25a0 + #define MVNETA_INTR_NEW_MASK 0x25a4 +@@ -820,7 +827,13 @@ static void mvneta_port_up(struct mvneta + mvreg_write(pp, MVNETA_TXQ_CMD, q_map); + + /* Enable all initialized RXQs. */ +- mvreg_write(pp, MVNETA_RXQ_CMD, BIT(pp->rxq_def)); ++ for (queue = 0; queue < rxq_number; queue++) { ++ struct mvneta_rx_queue *rxq = &pp->rxqs[queue]; ++ ++ if (rxq->descs != NULL) ++ q_map |= (1 << queue); ++ } ++ mvreg_write(pp, MVNETA_RXQ_CMD, q_map); + } + + /* Stop the Ethernet port activity */ +@@ -1026,6 +1039,7 @@ static void mvneta_defaults_set(struct m + int cpu; + int queue; + u32 val; ++ int max_cpu = num_present_cpus(); + + /* Clear all Cause registers */ + mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); +@@ -1041,13 +1055,23 @@ static void mvneta_defaults_set(struct m + /* Enable MBUS Retry bit16 */ + mvreg_write(pp, MVNETA_MBUS_RETRY, 0x20); + +- /* Set CPU queue access map - all CPUs have access to all RX +- * queues and to all TX queues ++ /* Set CPU queue access map. CPUs are assigned to the RX ++ * queues modulo their number and all the TX queues are ++ * assigned to the CPU associated to the default RX queue. + */ +- for_each_present_cpu(cpu) +- mvreg_write(pp, MVNETA_CPU_MAP(cpu), +- (MVNETA_CPU_RXQ_ACCESS_ALL_MASK | +- MVNETA_CPU_TXQ_ACCESS_ALL_MASK)); ++ for_each_present_cpu(cpu) { ++ int rxq_map = 0, txq_map = 0; ++ int rxq; ++ ++ for (rxq = 0; rxq < rxq_number; rxq++) ++ if ((rxq % max_cpu) == cpu) ++ rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq); ++ ++ if (cpu == rxq_def) ++ txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK; ++ ++ mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map); ++ } + + /* Reset RX and TX DMAs */ + mvreg_write(pp, MVNETA_PORT_RX_RESET, MVNETA_PORT_RX_DMA_RESET); +@@ -2174,6 +2198,7 @@ static int mvneta_poll(struct napi_struc + { + int rx_done = 0; + u32 cause_rx_tx; ++ int rx_queue; + struct mvneta_port *pp = netdev_priv(napi->dev); + struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports); + +@@ -2205,8 +2230,15 @@ static int mvneta_poll(struct napi_struc + /* For the case where the last mvneta_poll did not process all + * RX packets + */ ++ rx_queue = fls(((cause_rx_tx >> 8) & 0xff)); ++ + cause_rx_tx |= port->cause_rx_tx; +- rx_done = mvneta_rx(pp, budget, &pp->rxqs[pp->rxq_def]); ++ ++ if (rx_queue) { ++ rx_queue = rx_queue - 1; ++ rx_done = mvneta_rx(pp, budget, &pp->rxqs[rx_queue]); ++ } ++ + budget -= rx_done; + + if (budget > 0) { +@@ -2419,19 +2451,27 @@ static void mvneta_cleanup_txqs(struct m + /* Cleanup all Rx queues */ + static void mvneta_cleanup_rxqs(struct mvneta_port *pp) + { +- mvneta_rxq_deinit(pp, &pp->rxqs[pp->rxq_def]); ++ int queue; ++ ++ for (queue = 0; queue < txq_number; queue++) ++ mvneta_rxq_deinit(pp, &pp->rxqs[queue]); + } + + + /* Init all Rx queues */ + static int mvneta_setup_rxqs(struct mvneta_port *pp) + { +- int err = mvneta_rxq_init(pp, &pp->rxqs[pp->rxq_def]); +- if (err) { +- netdev_err(pp->dev, "%s: can't create rxq=%d\n", +- __func__, pp->rxq_def); +- mvneta_cleanup_rxqs(pp); +- return err; ++ int queue; ++ ++ for (queue = 0; queue < rxq_number; queue++) { ++ int err = mvneta_rxq_init(pp, &pp->rxqs[queue]); ++ ++ if (err) { ++ netdev_err(pp->dev, "%s: can't create rxq=%d\n", ++ __func__, queue); ++ mvneta_cleanup_rxqs(pp); ++ return err; ++ } + } + + return 0; +@@ -2455,6 +2495,19 @@ static int mvneta_setup_txqs(struct mvne + return 0; + } + ++static void mvneta_percpu_unmask_interrupt(void *arg) ++{ ++ struct mvneta_port *pp = arg; ++ ++ /* All the queue are unmasked, but actually only the ones ++ * maped to this CPU will be unmasked ++ */ ++ mvreg_write(pp, MVNETA_INTR_NEW_MASK, ++ MVNETA_RX_INTR_MASK_ALL | ++ MVNETA_TX_INTR_MASK_ALL | ++ MVNETA_MISCINTR_INTR_MASK); ++} ++ + static void mvneta_start_dev(struct mvneta_port *pp) + { + unsigned int cpu; +@@ -2472,11 +2525,10 @@ static void mvneta_start_dev(struct mvne + napi_enable(&port->napi); + } + +- /* Unmask interrupts */ +- mvreg_write(pp, MVNETA_INTR_NEW_MASK, +- MVNETA_RX_INTR_MASK(rxq_number) | +- MVNETA_TX_INTR_MASK(txq_number) | +- MVNETA_MISCINTR_INTR_MASK); ++ /* Unmask interrupts. It has to be done from each CPU */ ++ for_each_online_cpu(cpu) ++ smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, ++ pp, true); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, + MVNETA_CAUSE_PHY_STATUS_CHANGE | + MVNETA_CAUSE_LINK_CHANGE | +@@ -2752,22 +2804,35 @@ static void mvneta_percpu_disable(void * + + static void mvneta_percpu_elect(struct mvneta_port *pp) + { +- int online_cpu_idx, cpu, i = 0; ++ int online_cpu_idx, max_cpu, cpu, i = 0; + + online_cpu_idx = pp->rxq_def % num_online_cpus(); ++ max_cpu = num_present_cpus(); + + for_each_online_cpu(cpu) { +- if (i == online_cpu_idx) +- /* Enable per-CPU interrupt on the one CPU we +- * just elected ++ int rxq_map = 0, txq_map = 0; ++ int rxq; ++ ++ for (rxq = 0; rxq < rxq_number; rxq++) ++ if ((rxq % max_cpu) == cpu) ++ rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq); ++ ++ if (i == online_cpu_idx) { ++ /* Map the default receive queue and transmit ++ * queue to the elected CPU + */ +- smp_call_function_single(cpu, mvneta_percpu_enable, +- pp, true); +- else +- /* Disable per-CPU interrupt on all the other CPU */ +- smp_call_function_single(cpu, mvneta_percpu_disable, +- pp, true); ++ rxq_map |= MVNETA_CPU_RXQ_ACCESS(pp->rxq_def); ++ txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK; ++ } ++ mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map); ++ ++ /* Update the interrupt mask on each CPU according the ++ * new mapping ++ */ ++ smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, ++ pp, true); + i++; ++ + } + }; + +@@ -2802,12 +2867,22 @@ static int mvneta_percpu_notifier(struct + mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + napi_enable(&port->napi); + ++ ++ /* Enable per-CPU interrupts on the CPU that is ++ * brought up. ++ */ ++ smp_call_function_single(cpu, mvneta_percpu_enable, ++ pp, true); ++ + /* Enable per-CPU interrupt on the one CPU we care + * about. + */ + mvneta_percpu_elect(pp); + +- /* Unmask all ethernet port interrupts */ ++ /* Unmask all ethernet port interrupts, as this ++ * notifier is called for each CPU then the CPU to ++ * Queue mapping is applied ++ */ + mvreg_write(pp, MVNETA_INTR_NEW_MASK, + MVNETA_RX_INTR_MASK(rxq_number) | + MVNETA_TX_INTR_MASK(txq_number) | +@@ -2858,7 +2933,7 @@ static int mvneta_percpu_notifier(struct + static int mvneta_open(struct net_device *dev) + { + struct mvneta_port *pp = netdev_priv(dev); +- int ret; ++ int ret, cpu; + + pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu); + pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) + +@@ -2888,8 +2963,13 @@ static int mvneta_open(struct net_device + */ + mvneta_percpu_disable(pp); + +- /* Elect a CPU to handle our RX queue interrupt */ +- mvneta_percpu_elect(pp); ++ /* Enable per-CPU interrupt on all the CPU to handle our RX ++ * queue interrupts ++ */ ++ for_each_online_cpu(cpu) ++ smp_call_function_single(cpu, mvneta_percpu_enable, ++ pp, true); ++ + + /* Register a CPU notifier to handle the case where our CPU + * might be taken offline. |