Commit 71ce391d authored by Marcin Wojtas's avatar Marcin Wojtas Committed by David S. Miller

net: mvpp2: enable proper per-CPU TX buffers unmapping

mvpp2 driver allows usage of per-CPU TX processing. Once the packets are
prepared independetly on each CPU, the hardware enqueues the descriptors in
common TX queue. After they are sent, the buffers and associated sk_buffs
should be released on the corresponding CPU.

This is why a special index is maintained in order to point to the right data to
be released after transmission takes place. Each per-CPU TX queue comprise an
array of sent sk_buffs, freed in mvpp2_txq_bufs_free function. However, the
index was used there also for obtaining a descriptor (and therefore a buffer to
be DMA-unmapped) from common TX queue, which was wrong, because it was not
referring to the current CPU.

This commit enables proper unmapping of sent data buffers by indexing them in
per-CPU queues using a dedicated array for keeping their physical addresses.
Signed-off-by: default avatarMarcin Wojtas <mw@semihalf.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d53793c5
...@@ -776,6 +776,9 @@ struct mvpp2_txq_pcpu { ...@@ -776,6 +776,9 @@ struct mvpp2_txq_pcpu {
/* Array of transmitted skb */ /* Array of transmitted skb */
struct sk_buff **tx_skb; struct sk_buff **tx_skb;
/* Array of transmitted buffers' physical addresses */
dma_addr_t *tx_buffs;
/* Index of last TX DMA descriptor that was inserted */ /* Index of last TX DMA descriptor that was inserted */
int txq_put_index; int txq_put_index;
...@@ -961,9 +964,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu) ...@@ -961,9 +964,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
} }
static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu,
struct sk_buff *skb) struct sk_buff *skb,
struct mvpp2_tx_desc *tx_desc)
{ {
txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb; txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb;
if (skb)
txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] =
tx_desc->buf_phys_addr;
txq_pcpu->txq_put_index++; txq_pcpu->txq_put_index++;
if (txq_pcpu->txq_put_index == txq_pcpu->size) if (txq_pcpu->txq_put_index == txq_pcpu->size)
txq_pcpu->txq_put_index = 0; txq_pcpu->txq_put_index = 0;
...@@ -4392,8 +4399,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, ...@@ -4392,8 +4399,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
int i; int i;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
struct mvpp2_tx_desc *tx_desc = txq->descs + dma_addr_t buf_phys_addr =
txq_pcpu->txq_get_index; txq_pcpu->tx_buffs[txq_pcpu->txq_get_index];
struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index]; struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index];
mvpp2_txq_inc_get(txq_pcpu); mvpp2_txq_inc_get(txq_pcpu);
...@@ -4401,8 +4408,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, ...@@ -4401,8 +4408,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
if (!skb) if (!skb)
continue; continue;
dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr, dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
tx_desc->data_size, DMA_TO_DEVICE); skb_headlen(skb), DMA_TO_DEVICE);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
} }
...@@ -4634,12 +4641,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port, ...@@ -4634,12 +4641,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
txq_pcpu->tx_skb = kmalloc(txq_pcpu->size * txq_pcpu->tx_skb = kmalloc(txq_pcpu->size *
sizeof(*txq_pcpu->tx_skb), sizeof(*txq_pcpu->tx_skb),
GFP_KERNEL); GFP_KERNEL);
if (!txq_pcpu->tx_skb) { if (!txq_pcpu->tx_skb)
dma_free_coherent(port->dev->dev.parent, goto error;
txq->size * MVPP2_DESC_ALIGNED_SIZE,
txq->descs, txq->descs_phys); txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size *
return -ENOMEM; sizeof(dma_addr_t), GFP_KERNEL);
} if (!txq_pcpu->tx_buffs)
goto error;
txq_pcpu->count = 0; txq_pcpu->count = 0;
txq_pcpu->reserved_num = 0; txq_pcpu->reserved_num = 0;
...@@ -4648,6 +4656,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port, ...@@ -4648,6 +4656,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
} }
return 0; return 0;
error:
for_each_present_cpu(cpu) {
txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
kfree(txq_pcpu->tx_skb);
kfree(txq_pcpu->tx_buffs);
}
dma_free_coherent(port->dev->dev.parent,
txq->size * MVPP2_DESC_ALIGNED_SIZE,
txq->descs, txq->descs_phys);
return -ENOMEM;
} }
/* Free allocated TXQ resources */ /* Free allocated TXQ resources */
...@@ -4660,6 +4681,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, ...@@ -4660,6 +4681,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
for_each_present_cpu(cpu) { for_each_present_cpu(cpu) {
txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
kfree(txq_pcpu->tx_skb); kfree(txq_pcpu->tx_skb);
kfree(txq_pcpu->tx_buffs);
} }
if (txq->descs) if (txq->descs)
...@@ -5129,11 +5151,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb, ...@@ -5129,11 +5151,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
if (i == (skb_shinfo(skb)->nr_frags - 1)) { if (i == (skb_shinfo(skb)->nr_frags - 1)) {
/* Last descriptor */ /* Last descriptor */
tx_desc->command = MVPP2_TXD_L_DESC; tx_desc->command = MVPP2_TXD_L_DESC;
mvpp2_txq_inc_put(txq_pcpu, skb); mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
} else { } else {
/* Descriptor in the middle: Not First, Not Last */ /* Descriptor in the middle: Not First, Not Last */
tx_desc->command = 0; tx_desc->command = 0;
mvpp2_txq_inc_put(txq_pcpu, NULL); mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
} }
} }
...@@ -5199,12 +5221,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -5199,12 +5221,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
/* First and Last descriptor */ /* First and Last descriptor */
tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC; tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
tx_desc->command = tx_cmd; tx_desc->command = tx_cmd;
mvpp2_txq_inc_put(txq_pcpu, skb); mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
} else { } else {
/* First but not Last */ /* First but not Last */
tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE; tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE;
tx_desc->command = tx_cmd; tx_desc->command = tx_cmd;
mvpp2_txq_inc_put(txq_pcpu, NULL); mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
/* Continue with other skb fragments */ /* Continue with other skb fragments */
if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) { if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
......
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