From 239a3b663647869330955ec59caac0100ef9b60a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:01 +0100 Subject: net: mvpp2: fix DMA address calculation in mvpp2_txq_inc_put() When TX descriptors are filled in, the buffer DMA address is split between the tx_desc->buf_phys_addr field (high-order bits) and tx_desc->packet_offset field (5 low-order bits). However, when we re-calculate the DMA address from the TX descriptor in mvpp2_txq_inc_put(), we do not take tx_desc->packet_offset into account. This means that when the DMA address is not aligned on a 32 bytes boundary, we end up calling dma_unmap_single() with a DMA address that was not the one returned by dma_map_single(). This inconsistency is detected by the kernel when DMA_API_DEBUG is enabled. We fix this problem by properly calculating the DMA address in mvpp2_txq_inc_put(). Cc: 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 c48632048f71..a6992ce34565 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -991,7 +991,7 @@ static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, txq_pcpu->buffs + txq_pcpu->txq_put_index; tx_buf->skb = skb; tx_buf->size = tx_desc->data_size; - tx_buf->phys = tx_desc->buf_phys_addr; + tx_buf->phys = tx_desc->buf_phys_addr + tx_desc->packet_offset; txq_pcpu->txq_put_index++; if (txq_pcpu->txq_put_index == txq_pcpu->size) txq_pcpu->txq_put_index = 0; -- cgit v1.2.3-70-g09d2 From d63f9e41f981722b11f42ea2b19798c00fcae0f9 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:02 +0100 Subject: net: mvpp2: remove useless arguments in mvpp2_rx_{pkts, time}_coal_set As noticed by Russell King, the last argument of mvpp2_rx_{pkts,time}_coal_set() is useless, since the packet/time coalescing value is already stored in the 'struct mvpp2_rx_queue *' passed as argument to these functions. So passing the packet/time value as an additional argument, and setting them again in the mvpp2_rx_queue structure is useles. This commit therefore gets rid of this additional argument, assuming the caller has assigned the appropriate value to rxq->pkts_coal or rxq->time_coal before calling the respective functions. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index a6992ce34565..dfeee9636c7a 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4379,27 +4379,23 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) * will be generated by HW. */ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, - struct mvpp2_rx_queue *rxq, u32 pkts) + struct mvpp2_rx_queue *rxq) { u32 val; - val = (pkts & MVPP2_OCCUPIED_THRESH_MASK); + val = (rxq->pkts_coal & MVPP2_OCCUPIED_THRESH_MASK); mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); mvpp2_write(port->priv, MVPP2_RXQ_THRESH_REG, val); - - rxq->pkts_coal = pkts; } /* Set the time delay in usec before Rx interrupt */ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port, - struct mvpp2_rx_queue *rxq, u32 usec) + struct mvpp2_rx_queue *rxq) { u32 val; - val = (port->priv->tclk / USEC_PER_SEC) * usec; + val = (port->priv->tclk / USEC_PER_SEC) * rxq->time_coal; mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val); - - rxq->time_coal = usec; } /* Free Tx queue skbuffs */ @@ -4543,8 +4539,8 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, mvpp2_rxq_offset_set(port, rxq->id, NET_SKB_PAD); /* Set coalescing pkts and time */ - mvpp2_rx_pkts_coal_set(port, rxq, rxq->pkts_coal); - mvpp2_rx_time_coal_set(port, rxq, rxq->time_coal); + mvpp2_rx_pkts_coal_set(port, rxq); + mvpp2_rx_time_coal_set(port, rxq); /* Add number of descriptors ready for receiving packets */ mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size); @@ -5801,8 +5797,8 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, rxq->time_coal = c->rx_coalesce_usecs; rxq->pkts_coal = c->rx_max_coalesced_frames; - mvpp2_rx_pkts_coal_set(port, rxq, rxq->pkts_coal); - mvpp2_rx_time_coal_set(port, rxq, rxq->time_coal); + mvpp2_rx_pkts_coal_set(port, rxq); + mvpp2_rx_time_coal_set(port, rxq); } for (queue = 0; queue < txq_number; queue++) { -- cgit v1.2.3-70-g09d2 From f8b0d5f8cc10f43642f97db6b37d60d765cff34a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:03 +0100 Subject: net: mvpp2: handle too large value handling in mvpp2_rx_pkts_coal_set() Currently, mvpp2_rx_pkts_coal_set() does the following to avoid setting a too large value for the RX coalescing by packet number: val = (pkts & MVPP2_OCCUPIED_THRESH_MASK); This means that if you set a value that is slightly higher the the maximum number of packets, you in fact get a very low value. It makes a lot more sense to simply check if the value is too high, and if it's too high, limit it to the maximum possible value. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index dfeee9636c7a..679811db51a1 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4381,11 +4381,12 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - u32 val; + if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK) + rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK; - val = (rxq->pkts_coal & MVPP2_OCCUPIED_THRESH_MASK); mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_write(port->priv, MVPP2_RXQ_THRESH_REG, val); + mvpp2_write(port->priv, MVPP2_RXQ_THRESH_REG, + rxq->pkts_coal); } /* Set the time delay in usec before Rx interrupt */ -- cgit v1.2.3-70-g09d2 From ab42676af052e6d3502b31c2dc6b07af08ff126f Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:04 +0100 Subject: net: mvpp2: handle too large value in mvpp2_rx_time_coal_set() When configuring the MVPP2_ISR_RX_THRESHOLD_REG with the RX coalescing time threshold, we do not check for the maximum allowed value supported by the driver, which means we might overflow and use a bogus value. This commit adds a check for this situation, and if a value higher than what is supported by the hardware is provided, then we use the maximum value supported by the hardware. In order to achieve this in a way that avoids overflow and rounding errors, we introduce two utility functions mvpp2_usec_to_cycles() and cycles_to_usec(). Many thanks to Russell King for suggesting this implementation. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 679811db51a1..47fb949178b1 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -154,6 +154,7 @@ /* Interrupt Cause and Mask registers */ #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) +#define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0 #define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) #define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port)) #define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff) @@ -4389,13 +4390,39 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, rxq->pkts_coal); } +static u32 mvpp2_usec_to_cycles(u32 usec, unsigned long clk_hz) +{ + u64 tmp = (u64)clk_hz * usec; + + do_div(tmp, USEC_PER_SEC); + + return tmp > U32_MAX ? U32_MAX : tmp; +} + +static u32 mvpp2_cycles_to_usec(u32 cycles, unsigned long clk_hz) +{ + u64 tmp = (u64)cycles * USEC_PER_SEC; + + do_div(tmp, clk_hz); + + return tmp > U32_MAX ? U32_MAX : tmp; +} + /* Set the time delay in usec before Rx interrupt */ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - u32 val; + unsigned long freq = port->priv->tclk; + u32 val = mvpp2_usec_to_cycles(rxq->time_coal, freq); + + if (val > MVPP2_MAX_ISR_RX_THRESHOLD) { + rxq->time_coal = + mvpp2_cycles_to_usec(MVPP2_MAX_ISR_RX_THRESHOLD, freq); + + /* re-evaluate to get actual register value */ + val = mvpp2_usec_to_cycles(rxq->time_coal, freq); + } - val = (port->priv->tclk / USEC_PER_SEC) * rxq->time_coal; mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val); } -- cgit v1.2.3-70-g09d2 From 36fb7435b6ac4d288a2d4deea8934f9456ab46b6 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:05 +0100 Subject: net: mvpp2: release reference to txq_cpu[] entry after unmapping The mvpp2_txq_bufs_free() function is called upon TX completion to DMA unmap TX buffers, and free the corresponding SKBs. It gets the references to the SKB to free and the DMA buffer to unmap from a per-CPU txq_pcpu data structure. However, the code currently increments the pointer to the next entry before doing the DMA unmap and freeing the SKB. It does not cause any visible problem because for a given SKB the TX completion is guaranteed to take place on the CPU where the TX was started. However, it is much more logical to increment the pointer to the next entry once the current entry has been completely unmapped/released. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 47fb949178b1..5d6b4edcc13b 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4437,13 +4437,12 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, struct mvpp2_txq_pcpu_buf *tx_buf = txq_pcpu->buffs + txq_pcpu->txq_get_index; - mvpp2_txq_inc_get(txq_pcpu); - dma_unmap_single(port->dev->dev.parent, tx_buf->phys, tx_buf->size, DMA_TO_DEVICE); - if (!tx_buf->skb) - continue; - dev_kfree_skb_any(tx_buf->skb); + if (tx_buf->skb) + dev_kfree_skb_any(tx_buf->skb); + + mvpp2_txq_inc_get(txq_pcpu); } } -- cgit v1.2.3-70-g09d2 From 5dfa9e8337b1c8a7e291929e676c167b6ea953e6 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:06 +0100 Subject: net: mvpp2: remove unused 'tx_skb' field of 'struct mvpp2_tx_queue' This commit remove a field of 'struct mvpp2_tx_queue' that is not used anywhere. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 5d6b4edcc13b..27699c8af3a1 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -823,9 +823,6 @@ struct mvpp2_tx_queue { /* Per-CPU control of physical Tx queues */ struct mvpp2_txq_pcpu __percpu *pcpu; - /* Array of transmitted skb */ - struct sk_buff **tx_skb; - u32 done_pkts_coal; /* Virtual address of thex Tx DMA descriptors array */ -- cgit v1.2.3-70-g09d2 From 7ef7e1d949cd517d30a3cc6c7f48bd017d81af6b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:07 +0100 Subject: net: mvpp2: drop useless fields in mvpp2_bm_pool and related code This commit drops dead code from the mvpp2 driver. The 'in_use' and 'in_use_thresh' fields of 'struct mvpp2_bm_pool' are incremented/decremented/initialized in various places. But they are only used in one place: if (is_recycle && (atomic_read(&bm_pool->in_use) < bm_pool->in_use_thresh)) return 0; However 'is_recycle', passed as argument to mvpp2_rx_refill() is always false. So in fact, this code is never reached, and the 'is_recycle' argument is useless. So let's drop this code. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 27699c8af3a1..1a51c71e156c 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -930,10 +930,6 @@ struct mvpp2_bm_pool { /* Ports using BM pool */ u32 port_map; - - /* Occupied buffers indicator */ - atomic_t in_use; - int in_use_thresh; }; struct mvpp2_buff_hdr { @@ -3399,7 +3395,6 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev, bm_pool->size = size; bm_pool->pkt_size = 0; bm_pool->buf_num = 0; - atomic_set(&bm_pool->in_use, 0); return 0; } @@ -3656,7 +3651,6 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, /* Update BM driver with number of buffers added to pool */ bm_pool->buf_num += i; - bm_pool->in_use_thresh = bm_pool->buf_num / 4; netdev_dbg(port->dev, "%s pool %d: pkt_size=%4d, buf_size=%4d, total_size=%4d\n", @@ -5014,23 +5008,18 @@ static void mvpp2_rx_csum(struct mvpp2_port *port, u32 status, /* Reuse skb if possible, or allocate a new skb and add it to BM pool */ static int mvpp2_rx_refill(struct mvpp2_port *port, - struct mvpp2_bm_pool *bm_pool, - u32 bm, int is_recycle) + struct mvpp2_bm_pool *bm_pool, u32 bm) { struct sk_buff *skb; dma_addr_t phys_addr; - if (is_recycle && - (atomic_read(&bm_pool->in_use) < bm_pool->in_use_thresh)) - return 0; - /* No recycle or too many buffers are in use, so allocate a new skb */ skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_ATOMIC); if (!skb) return -ENOMEM; mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)skb); - atomic_dec(&bm_pool->in_use); + return 0; } @@ -5156,7 +5145,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, skb = (struct sk_buff *)rx_desc->buf_cookie; - err = mvpp2_rx_refill(port, bm_pool, bm, 0); + err = mvpp2_rx_refill(port, bm_pool, bm); if (err) { netdev_err(port->dev, "failed to refill BM pools\n"); goto err_drop_frame; @@ -5167,7 +5156,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, rcvd_pkts++; rcvd_bytes += rx_bytes; - atomic_inc(&bm_pool->in_use); skb_reserve(skb, MVPP2_MH_SIZE); skb_put(skb, rx_bytes); -- cgit v1.2.3-70-g09d2 From 3eb2d9982288fbbbdc671af0fee4b9eb71d11b75 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:08 +0100 Subject: net: mvpp2: simplify mvpp2_bm_bufs_add() The mvpp2_bm_bufs_add() currently creates a fake cookie by calling mvpp2_bm_cookie_pool_set(), just to be able to call mvpp2_pool_refill(). But all what mvpp2_pool_refill() does is extract the pool ID from the cookie, and call mvpp2_bm_pool_put() with this ID. Instead of doing this convoluted thing, just call mvpp2_bm_pool_put() directly, since we have the BM pool ID. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 1a51c71e156c..2fcb0080d7f2 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3626,7 +3626,6 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, { struct sk_buff *skb; int i, buf_size, total_size; - u32 bm; dma_addr_t phys_addr; buf_size = MVPP2_RX_BUF_SIZE(bm_pool->pkt_size); @@ -3640,13 +3639,12 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, return 0; } - bm = mvpp2_bm_cookie_pool_set(0, bm_pool->id); for (i = 0; i < buf_num; i++) { skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_KERNEL); if (!skb) break; - mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)skb); + mvpp2_bm_pool_put(port, bm_pool->id, (u32)phys_addr, (u32)skb); } /* Update BM driver with number of buffers added to pool */ -- cgit v1.2.3-70-g09d2 From a8c249a71dca2992001ad582797c03fca0488d00 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:09 +0100 Subject: net: mvpp2: remove unused register definitions Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 2fcb0080d7f2..6341f344278c 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -253,10 +253,6 @@ #define MVPP2_SRC_ADDR_HIGH 0x28 #define MVPP2_PHY_AN_CFG0_REG 0x34 #define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7) -#define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * \ - 0x400 + (port) * 0x400) -#define MVPP2_MIB_LATE_COLLISION 0x7c -#define MVPP2_ISR_SUM_MASK_REG 0x220c #define MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG 0x305c #define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27 -- cgit v1.2.3-70-g09d2 From 31d7677b91307e2771b6922fd9920542a92d376d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:10 +0100 Subject: net: mvpp2: fix indentation of MVPP2_EXT_GLOBAL_CTRL_DEFAULT Signed-off-by: Thomas Petazzoni Acked-by: Russell King 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 6341f344278c..23f96e9c392f 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -254,7 +254,7 @@ #define MVPP2_PHY_AN_CFG0_REG 0x34 #define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7) #define MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG 0x305c -#define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27 +#define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27 /* Per-port registers */ #define MVPP2_GMAC_CTRL_0_REG 0x0 -- cgit v1.2.3-70-g09d2 From 8138affc4999bbe4ca5ed805b36f80b56354339e Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:11 +0100 Subject: net: mvpp2: simplify MVPP2_PRS_RI_* definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the MVPP2_PRS_RI_* definitions use the ~(value) syntax, which doesn't compile nicely on 64-bit. Moreover, those definitions are in fact unneeded, since they are always used in combination with a bit mask that ensures only the appropriate bits are modified. Therefore, such definitions should just be set to 0x0. In addition, as suggested by Russell King, we change the _MASK definitions to also use the BIT() macro so that it is clear they are related to the values defined afterwards. For example: #define MVPP2_PRS_RI_L2_CAST_MASK 0x600 #define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10)) #define MVPP2_PRS_RI_L2_MCAST BIT(9) #define MVPP2_PRS_RI_L2_BCAST BIT(10) becomes #define MVPP2_PRS_RI_L2_CAST_MASK (BIT(9) | BIT(10)) #define MVPP2_PRS_RI_L2_UCAST 0x0 #define MVPP2_PRS_RI_L2_MCAST BIT(9) #define MVPP2_PRS_RI_L2_BCAST BIT(10) Because the values (MVPP2_PRS_RI_L2_UCAST, MVPP2_PRS_RI_L2_MCAST and MVPP2_PRS_RI_L2_BCAST) are always applied with MVPP2_PRS_RI_L2_CAST_MASK, and therefore there is no need for MVPP2_PRS_RI_L2_UCAST to be defined as ~(BIT(9) | BIT(10)). It fixes the following warnings when building the driver on a 64-bit platform (which is not possible as of this commit, but will be enabled in a follow-up commit): drivers/net/ethernet/marvell/mvpp2.c: In function ‘mvpp2_prs_mac_promisc_set’: drivers/net/ethernet/marvell/mvpp2.c:524:33: warning: large integer implicitly truncated to unsigned type [-Woverflow] #define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10)) ^ drivers/net/ethernet/marvell/mvpp2.c:1459:33: note: in expansion of macro ‘MVPP2_PRS_RI_L2_UCAST’ mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L2_UCAST, Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 23f96e9c392f..ed4abb3d7e23 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -510,28 +510,28 @@ enum mvpp2_tag_type { /* Sram result info bits assignment */ #define MVPP2_PRS_RI_MAC_ME_MASK 0x1 #define MVPP2_PRS_RI_DSA_MASK 0x2 -#define MVPP2_PRS_RI_VLAN_MASK 0xc -#define MVPP2_PRS_RI_VLAN_NONE ~(BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_VLAN_MASK (BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_VLAN_NONE 0x0 #define MVPP2_PRS_RI_VLAN_SINGLE BIT(2) #define MVPP2_PRS_RI_VLAN_DOUBLE BIT(3) #define MVPP2_PRS_RI_VLAN_TRIPLE (BIT(2) | BIT(3)) #define MVPP2_PRS_RI_CPU_CODE_MASK 0x70 #define MVPP2_PRS_RI_CPU_CODE_RX_SPEC BIT(4) -#define MVPP2_PRS_RI_L2_CAST_MASK 0x600 -#define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10)) +#define MVPP2_PRS_RI_L2_CAST_MASK (BIT(9) | BIT(10)) +#define MVPP2_PRS_RI_L2_UCAST 0x0 #define MVPP2_PRS_RI_L2_MCAST BIT(9) #define MVPP2_PRS_RI_L2_BCAST BIT(10) #define MVPP2_PRS_RI_PPPOE_MASK 0x800 -#define MVPP2_PRS_RI_L3_PROTO_MASK 0x7000 -#define MVPP2_PRS_RI_L3_UN ~(BIT(12) | BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_PROTO_MASK (BIT(12) | BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_UN 0x0 #define MVPP2_PRS_RI_L3_IP4 BIT(12) #define MVPP2_PRS_RI_L3_IP4_OPT BIT(13) #define MVPP2_PRS_RI_L3_IP4_OTHER (BIT(12) | BIT(13)) #define MVPP2_PRS_RI_L3_IP6 BIT(14) #define MVPP2_PRS_RI_L3_IP6_EXT (BIT(12) | BIT(14)) #define MVPP2_PRS_RI_L3_ARP (BIT(13) | BIT(14)) -#define MVPP2_PRS_RI_L3_ADDR_MASK 0x18000 -#define MVPP2_PRS_RI_L3_UCAST ~(BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_L3_ADDR_MASK (BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_L3_UCAST 0x0 #define MVPP2_PRS_RI_L3_MCAST BIT(15) #define MVPP2_PRS_RI_L3_BCAST (BIT(15) | BIT(16)) #define MVPP2_PRS_RI_IP_FRAG_MASK 0x20000 -- cgit v1.2.3-70-g09d2 From 0e0372816b9cbd22c82e3e7cd36e8e74c58ba641 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:12 +0100 Subject: net: mvpp2: switch to build_skb() in the RX path This commit adapts the mvpp2 RX path to use the build_skb() method. Not only build_skb() is now the recommended mechanism, but it also simplifies the addition of support for the PPv2.2 variant. Indeed, without build_skb(), we have to keep track for each RX descriptor of the physical address of the packet buffer, and the virtual address of the SKB. However, in PPv2.2 running on 64 bits platform, there is not enough space in the descriptor to store the virtual address of the SKB. So having to take care only of the address of the packet buffer, and building the SKB upon reception helps in supporting PPv2.2. The implementation is fairly straightforward: - mvpp2_skb_alloc() is renamed to mvpp2_buf_alloc() and no longer allocates a SKB. Instead, it allocates a buffer using the new mvpp2_frag_alloc() function, with enough space for the data and SKB. - The initialization of the RX buffers in mvpp2_bm_bufs_add() as well as the refill of the RX buffers in mvpp2_rx_refill() is adjusted accordingly. - Finally, the mvpp2_rx() is modified to use build_skb(). Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 79 ++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index ed4abb3d7e23..735a04e7e66b 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -918,6 +918,7 @@ struct mvpp2_bm_pool { int buf_size; /* Packet size */ int pkt_size; + int frag_size; /* BPPE virtual base address */ u32 *virt_addr; @@ -3354,6 +3355,22 @@ static void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val); } +static void *mvpp2_frag_alloc(const struct mvpp2_bm_pool *pool) +{ + if (likely(pool->frag_size <= PAGE_SIZE)) + return netdev_alloc_frag(pool->frag_size); + else + return kmalloc(pool->frag_size, GFP_ATOMIC); +} + +static void mvpp2_frag_free(const struct mvpp2_bm_pool *pool, void *data) +{ + if (likely(pool->frag_size <= PAGE_SIZE)) + skb_free_frag(data); + else + kfree(data); +} + /* Buffer Manager configuration routines */ /* Create pool */ @@ -3428,7 +3445,8 @@ static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv, if (!vaddr) break; - dev_kfree_skb_any((struct sk_buff *)vaddr); + + mvpp2_frag_free(bm_pool, (void *)vaddr); } /* Update BM driver with number of buffers removed from pool */ @@ -3542,29 +3560,28 @@ static void mvpp2_rxq_short_pool_set(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val); } -/* Allocate skb for BM pool */ -static struct sk_buff *mvpp2_skb_alloc(struct mvpp2_port *port, - struct mvpp2_bm_pool *bm_pool, - dma_addr_t *buf_phys_addr, - gfp_t gfp_mask) +static void *mvpp2_buf_alloc(struct mvpp2_port *port, + struct mvpp2_bm_pool *bm_pool, + dma_addr_t *buf_phys_addr, + gfp_t gfp_mask) { - struct sk_buff *skb; dma_addr_t phys_addr; + void *data; - skb = __dev_alloc_skb(bm_pool->pkt_size, gfp_mask); - if (!skb) + data = mvpp2_frag_alloc(bm_pool); + if (!data) return NULL; - phys_addr = dma_map_single(port->dev->dev.parent, skb->head, + phys_addr = dma_map_single(port->dev->dev.parent, data, MVPP2_RX_BUF_SIZE(bm_pool->pkt_size), DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(port->dev->dev.parent, phys_addr))) { - dev_kfree_skb_any(skb); + mvpp2_frag_free(bm_pool, data); return NULL; } *buf_phys_addr = phys_addr; - return skb; + return data; } /* Set pool number in a BM cookie */ @@ -3620,9 +3637,9 @@ static void mvpp2_pool_refill(struct mvpp2_port *port, u32 bm, static int mvpp2_bm_bufs_add(struct mvpp2_port *port, struct mvpp2_bm_pool *bm_pool, int buf_num) { - struct sk_buff *skb; int i, buf_size, total_size; dma_addr_t phys_addr; + void *buf; buf_size = MVPP2_RX_BUF_SIZE(bm_pool->pkt_size); total_size = MVPP2_RX_TOTAL_SIZE(buf_size); @@ -3636,11 +3653,11 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, } for (i = 0; i < buf_num; i++) { - skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_KERNEL); - if (!skb) + buf = mvpp2_buf_alloc(port, bm_pool, &phys_addr, GFP_KERNEL); + if (!buf) break; - mvpp2_bm_pool_put(port, bm_pool->id, (u32)phys_addr, (u32)skb); + mvpp2_bm_pool_put(port, bm_pool->id, (u32)phys_addr, (u32)buf); } /* Update BM driver with number of buffers added to pool */ @@ -3696,6 +3713,9 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, port->priv, new_pool); new_pool->pkt_size = pkt_size; + new_pool->frag_size = + SKB_DATA_ALIGN(MVPP2_RX_BUF_SIZE(pkt_size)) + + MVPP2_SKB_SHINFO_SIZE; /* Allocate buffers for this pool */ num = mvpp2_bm_bufs_add(port, new_pool, pkts_num); @@ -3764,6 +3784,8 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) } port_pool->pkt_size = pkt_size; + port_pool->frag_size = SKB_DATA_ALIGN(MVPP2_RX_BUF_SIZE(pkt_size)) + + MVPP2_SKB_SHINFO_SIZE; num = mvpp2_bm_bufs_add(port, port_pool, pkts_num); if (num != pkts_num) { WARN(1, "pool %d: %d of %d allocated\n", @@ -5004,15 +5026,15 @@ static void mvpp2_rx_csum(struct mvpp2_port *port, u32 status, static int mvpp2_rx_refill(struct mvpp2_port *port, struct mvpp2_bm_pool *bm_pool, u32 bm) { - struct sk_buff *skb; dma_addr_t phys_addr; + void *buf; /* No recycle or too many buffers are in use, so allocate a new skb */ - skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_ATOMIC); - if (!skb) + buf = mvpp2_buf_alloc(port, bm_pool, &phys_addr, GFP_ATOMIC); + if (!buf) return -ENOMEM; - mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)skb); + mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)buf); return 0; } @@ -5104,14 +5126,17 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); struct mvpp2_bm_pool *bm_pool; struct sk_buff *skb; + unsigned int frag_size; dma_addr_t phys_addr; u32 bm, rx_status; int pool, rx_bytes, err; + void *data; rx_done++; rx_status = rx_desc->status; rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE; phys_addr = rx_desc->buf_phys_addr; + data = (void *)rx_desc->buf_cookie; bm = mvpp2_bm_cookie_build(rx_desc); pool = mvpp2_bm_cookie_pool_get(bm); @@ -5132,12 +5157,22 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, dev->stats.rx_errors++; mvpp2_rx_error(port, rx_desc); /* Return the buffer to the pool */ + mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr, rx_desc->buf_cookie); continue; } - skb = (struct sk_buff *)rx_desc->buf_cookie; + if (bm_pool->frag_size > PAGE_SIZE) + frag_size = 0; + else + frag_size = bm_pool->frag_size; + + skb = build_skb(data, frag_size); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); + goto err_drop_frame; + } err = mvpp2_rx_refill(port, bm_pool, bm); if (err) { @@ -5151,7 +5186,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, rcvd_pkts++; rcvd_bytes += rx_bytes; - skb_reserve(skb, MVPP2_MH_SIZE); + skb_reserve(skb, MVPP2_MH_SIZE + NET_SKB_PAD); skb_put(skb, rx_bytes); skb->protocol = eth_type_trans(skb, dev); mvpp2_rx_csum(port, rx_status, skb); -- cgit v1.2.3-70-g09d2 From d3158807e8d6d4877c36dba3d3c64d9c6671c1bc Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 21 Feb 2017 11:28:13 +0100 Subject: net: mvpp2: enable building on 64-bit platforms The mvpp2 is going to be extended to support the Marvell Armada 7K/8K platform, which is ARM64. As a preparation to this work, this commit enables building the mvpp2 driver on ARM64, by: - Adjusting the Kconfig dependency - Fixing the types used in the driver so that they are 32/64-bits compliant. We use dma_addr_t for DMA addresses, and unsigned long for virtual addresses. It is worth mentioning that after this commit, the driver is for now still only used on 32-bits platforms, and will only work on 32-bits platforms. Signed-off-by: Thomas Petazzoni Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/Kconfig | 3 +-- drivers/net/ethernet/marvell/mvpp2.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index f4b7cf18fb0f..d2555e8b947e 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -83,9 +83,8 @@ config MVNETA_BM config MVPP2 tristate "Marvell Armada 375 network interface support" - depends on MACH_ARMADA_375 || COMPILE_TEST + depends on ARCH_MVEBU || COMPILE_TEST depends on HAS_DMA - depends on !64BIT select MVMDIO ---help--- This driver supports the network interface units in the diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 735a04e7e66b..d00421b9ffea 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3388,7 +3388,8 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev, if (!bm_pool->virt_addr) return -ENOMEM; - if (!IS_ALIGNED((u32)bm_pool->virt_addr, MVPP2_BM_POOL_PTR_ALIGN)) { + if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr, + MVPP2_BM_POOL_PTR_ALIGN)) { dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr, bm_pool->phys_addr); dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n", @@ -3433,7 +3434,7 @@ static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv, for (i = 0; i < bm_pool->buf_num; i++) { dma_addr_t buf_phys_addr; - u32 vaddr; + unsigned long vaddr; /* Get buffer virtual address (indirect access) */ buf_phys_addr = mvpp2_read(priv, @@ -3596,14 +3597,15 @@ static inline u32 mvpp2_bm_cookie_pool_set(u32 cookie, int pool) } /* Get pool number from a BM cookie */ -static inline int mvpp2_bm_cookie_pool_get(u32 cookie) +static inline int mvpp2_bm_cookie_pool_get(unsigned long cookie) { return (cookie >> MVPP2_BM_COOKIE_POOL_OFFS) & 0xFF; } /* Release buffer to BM */ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, - u32 buf_phys_addr, u32 buf_virt_addr) + dma_addr_t buf_phys_addr, + unsigned long buf_virt_addr) { mvpp2_write(port->priv, MVPP2_BM_VIRT_RLS_REG, buf_virt_addr); mvpp2_write(port->priv, MVPP2_BM_PHY_RLS_REG(pool), buf_phys_addr); @@ -3611,7 +3613,8 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, /* Release multicast buffer */ static void mvpp2_bm_pool_mc_put(struct mvpp2_port *port, int pool, - u32 buf_phys_addr, u32 buf_virt_addr, + dma_addr_t buf_phys_addr, + unsigned long buf_virt_addr, int mc_id) { u32 val = 0; @@ -3626,7 +3629,8 @@ static void mvpp2_bm_pool_mc_put(struct mvpp2_port *port, int pool, /* Refill BM pool */ static void mvpp2_pool_refill(struct mvpp2_port *port, u32 bm, - u32 phys_addr, u32 cookie) + dma_addr_t phys_addr, + unsigned long cookie) { int pool = mvpp2_bm_cookie_pool_get(bm); @@ -3657,7 +3661,8 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, if (!buf) break; - mvpp2_bm_pool_put(port, bm_pool->id, (u32)phys_addr, (u32)buf); + mvpp2_bm_pool_put(port, bm_pool->id, phys_addr, + (unsigned long)buf); } /* Update BM driver with number of buffers added to pool */ @@ -5034,7 +5039,7 @@ static int mvpp2_rx_refill(struct mvpp2_port *port, if (!buf) return -ENOMEM; - mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)buf); + mvpp2_pool_refill(port, bm, phys_addr, (unsigned long)buf); return 0; } @@ -5076,10 +5081,10 @@ static void mvpp2_buff_hdr_rx(struct mvpp2_port *port, struct mvpp2_buff_hdr *buff_hdr; struct sk_buff *skb; u32 rx_status = rx_desc->status; - u32 buff_phys_addr; - u32 buff_virt_addr; - u32 buff_phys_addr_next; - u32 buff_virt_addr_next; + dma_addr_t buff_phys_addr; + unsigned long buff_virt_addr; + dma_addr_t buff_phys_addr_next; + unsigned long buff_virt_addr_next; int mc_id; int pool_id; @@ -5136,7 +5141,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, rx_status = rx_desc->status; rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE; phys_addr = rx_desc->buf_phys_addr; - data = (void *)rx_desc->buf_cookie; + data = (void *)(uintptr_t)rx_desc->buf_cookie; bm = mvpp2_bm_cookie_build(rx_desc); pool = mvpp2_bm_cookie_pool_get(bm); -- cgit v1.2.3-70-g09d2