Skip to content

Commit 070246e

Browse files
jh-hsddavem330
authored andcommitted
net: stmmac: Fix for mismatched host/device DMA address width
Currently DMA address width is either read from a RO device register or force set from the platform data. This breaks DMA when the host DMA address width is <=32it but the device is >32bit. Right now the driver may decide to use a 2nd DMA descriptor for another buffer (happens in case of TSO xmit) assuming that 32bit addressing is used due to platform configuration but the device will still use both descriptor addresses as one address. This can be observed with the Intel EHL platform driver that sets 32bit for addr64 but the MAC reports 40bit. The TX queue gets stuck in case of TCP with iptables NAT configuration on TSO packets. The logic should be like this: Whatever we do on the host side (memory allocation GFP flags) should happen with the host DMA width, whenever we decide how to set addresses on the device registers we must use the device DMA address width. This patch renames the platform address width field from addr64 (term used in device datasheet) to host_addr and uses this value exclusively for host side operations while all chip operations consider the device DMA width as read from the device register. Fixes: 7cfc448 ("stmmac: intel: Configure EHL PSE0 GbE and PSE1 GbE to 32 bits DMA addressing") Signed-off-by: Jochen Henneberg <jh@henneberg-systemdesign.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 543887d commit 070246e

File tree

6 files changed

+22
-19
lines changed

6 files changed

+22
-19
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ struct dma_features {
418418
unsigned int frpbs;
419419
unsigned int frpes;
420420
unsigned int addr64;
421+
unsigned int host_dma_width;
421422
unsigned int rssen;
422423
unsigned int vlhash;
423424
unsigned int sphen;

drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ static int imx_dwmac_probe(struct platform_device *pdev)
288288
goto err_parse_dt;
289289
}
290290

291-
plat_dat->addr64 = dwmac->ops->addr_width;
291+
plat_dat->host_dma_width = dwmac->ops->addr_width;
292292
plat_dat->init = imx_dwmac_init;
293293
plat_dat->exit = imx_dwmac_exit;
294294
plat_dat->clks_config = imx_dwmac_clks_config;

drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ static int ehl_pse0_common_data(struct pci_dev *pdev,
684684

685685
intel_priv->is_pse = true;
686686
plat->bus_id = 2;
687-
plat->addr64 = 32;
687+
plat->host_dma_width = 32;
688688

689689
plat->clk_ptp_rate = 200000000;
690690

@@ -725,7 +725,7 @@ static int ehl_pse1_common_data(struct pci_dev *pdev,
725725

726726
intel_priv->is_pse = true;
727727
plat->bus_id = 3;
728-
plat->addr64 = 32;
728+
plat->host_dma_width = 32;
729729

730730
plat->clk_ptp_rate = 200000000;
731731

drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
591591
plat->use_phy_wol = priv_plat->mac_wol ? 0 : 1;
592592
plat->riwt_off = 1;
593593
plat->maxmtu = ETH_DATA_LEN;
594-
plat->addr64 = priv_plat->variant->dma_bit_mask;
594+
plat->host_dma_width = priv_plat->variant->dma_bit_mask;
595595
plat->bsp_priv = priv_plat;
596596
plat->init = mediatek_dwmac_init;
597597
plat->clks_config = mediatek_dwmac_clks_config;

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv,
14311431
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
14321432
gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
14331433

1434-
if (priv->dma_cap.addr64 <= 32)
1434+
if (priv->dma_cap.host_dma_width <= 32)
14351435
gfp |= GFP_DMA32;
14361436

14371437
if (!buf->page) {
@@ -4587,7 +4587,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
45874587
unsigned int entry = rx_q->dirty_rx;
45884588
gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
45894589

4590-
if (priv->dma_cap.addr64 <= 32)
4590+
if (priv->dma_cap.host_dma_width <= 32)
45914591
gfp |= GFP_DMA32;
45924592

45934593
while (dirty-- > 0) {
@@ -6205,7 +6205,7 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
62056205
seq_printf(seq, "\tFlexible RX Parser: %s\n",
62066206
priv->dma_cap.frpsel ? "Y" : "N");
62076207
seq_printf(seq, "\tEnhanced Addressing: %d\n",
6208-
priv->dma_cap.addr64);
6208+
priv->dma_cap.host_dma_width);
62096209
seq_printf(seq, "\tReceive Side Scaling: %s\n",
62106210
priv->dma_cap.rssen ? "Y" : "N");
62116211
seq_printf(seq, "\tVLAN Hash Filtering: %s\n",
@@ -7178,20 +7178,22 @@ int stmmac_dvr_probe(struct device *device,
71787178
dev_info(priv->device, "SPH feature enabled\n");
71797179
}
71807180

7181-
/* The current IP register MAC_HW_Feature1[ADDR64] only define
7182-
* 32/40/64 bit width, but some SOC support others like i.MX8MP
7183-
* support 34 bits but it map to 40 bits width in MAC_HW_Feature1[ADDR64].
7184-
* So overwrite dma_cap.addr64 according to HW real design.
7181+
/* Ideally our host DMA address width is the same as for the
7182+
* device. However, it may differ and then we have to use our
7183+
* host DMA width for allocation and the device DMA width for
7184+
* register handling.
71857185
*/
7186-
if (priv->plat->addr64)
7187-
priv->dma_cap.addr64 = priv->plat->addr64;
7186+
if (priv->plat->host_dma_width)
7187+
priv->dma_cap.host_dma_width = priv->plat->host_dma_width;
7188+
else
7189+
priv->dma_cap.host_dma_width = priv->dma_cap.addr64;
71887190

7189-
if (priv->dma_cap.addr64) {
7191+
if (priv->dma_cap.host_dma_width) {
71907192
ret = dma_set_mask_and_coherent(device,
7191-
DMA_BIT_MASK(priv->dma_cap.addr64));
7193+
DMA_BIT_MASK(priv->dma_cap.host_dma_width));
71927194
if (!ret) {
7193-
dev_info(priv->device, "Using %d bits DMA width\n",
7194-
priv->dma_cap.addr64);
7195+
dev_info(priv->device, "Using %d/%d bits DMA host/device width\n",
7196+
priv->dma_cap.host_dma_width, priv->dma_cap.addr64);
71957197

71967198
/*
71977199
* If more than 32 bits can be addressed, make sure to
@@ -7206,7 +7208,7 @@ int stmmac_dvr_probe(struct device *device,
72067208
goto error_hw_init;
72077209
}
72087210

7209-
priv->dma_cap.addr64 = 32;
7211+
priv->dma_cap.host_dma_width = 32;
72107212
}
72117213
}
72127214

include/linux/stmmac.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ struct plat_stmmacenet_data {
215215
int unicast_filter_entries;
216216
int tx_fifo_size;
217217
int rx_fifo_size;
218-
u32 addr64;
218+
u32 host_dma_width;
219219
u32 rx_queues_to_use;
220220
u32 tx_queues_to_use;
221221
u8 rx_sched_algorithm;

0 commit comments

Comments
 (0)