Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: imx: Add DMA buffer configuration via DT

In order to optimize serial communication (performance/throughput VS
latency), we may need to tweak DMA period number and size. This adds
DT properties to configure those values before initialising DMA.
The defaults will stay the same as before.

[update documentation and commit message, rebase to current master,
switch back to DT instead of sysfs]

Signed-off-by: Fabien Lahoudere <fabien.lahoudere@collabora.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20210430175038.103226-2-sebastian.reichel@collabora.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Fabien Lahoudere and committed by
Greg Kroah-Hartman
db0a196b 910cc953

+30 -7
+12
Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml
··· 71 71 received, and that the peripheral should invert its input using the 72 72 INVR registers. 73 73 74 + fsl,dma-info: 75 + $ref: /schemas/types.yaml#/definitions/uint32-array 76 + minItems: 2 77 + maxItems: 2 78 + description: | 79 + First cell contains the size of DMA buffer chunks, second cell contains 80 + the amount of chunks used for the device. Multiplying both numbers is 81 + the total size of memory used for receiving data. 82 + When not being configured the system will use default settings, which 83 + are sensible for most use cases. If you need low latency processing on 84 + slow connections this needs to be configured appropriately. 85 + 74 86 uart-has-rtscts: true 75 87 76 88 rs485-rts-delay: true
+18 -7
drivers/tty/serial/imx.c
··· 225 225 struct scatterlist rx_sgl, tx_sgl[2]; 226 226 void *rx_buf; 227 227 struct circ_buf rx_ring; 228 + unsigned int rx_buf_size; 229 + unsigned int rx_period_length; 228 230 unsigned int rx_periods; 229 231 dma_cookie_t rx_cookie; 230 232 unsigned int tx_bytes; ··· 1185 1183 } 1186 1184 } 1187 1185 1188 - /* RX DMA buffer periods */ 1189 - #define RX_DMA_PERIODS 16 1190 - #define RX_BUF_SIZE (RX_DMA_PERIODS * PAGE_SIZE / 4) 1191 - 1192 1186 static int imx_uart_start_rx_dma(struct imx_port *sport) 1193 1187 { 1194 1188 struct scatterlist *sgl = &sport->rx_sgl; ··· 1195 1197 1196 1198 sport->rx_ring.head = 0; 1197 1199 sport->rx_ring.tail = 0; 1198 - sport->rx_periods = RX_DMA_PERIODS; 1199 1200 1200 - sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); 1201 + sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size); 1201 1202 ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); 1202 1203 if (ret == 0) { 1203 1204 dev_err(dev, "DMA mapping error for RX.\n"); ··· 1313 1316 goto err; 1314 1317 } 1315 1318 1316 - sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); 1319 + sport->rx_buf_size = sport->rx_period_length * sport->rx_periods; 1320 + sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL); 1317 1321 if (!sport->rx_buf) { 1318 1322 ret = -ENOMEM; 1319 1323 goto err; ··· 2177 2179 return HRTIMER_NORESTART; 2178 2180 } 2179 2181 2182 + /* Default RX DMA buffer configuration */ 2183 + #define RX_DMA_PERIODS 16 2184 + #define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4) 2185 + 2180 2186 static int imx_uart_probe(struct platform_device *pdev) 2181 2187 { 2182 2188 struct device_node *np = pdev->dev.of_node; 2183 2189 struct imx_port *sport; 2184 2190 void __iomem *base; 2191 + u32 dma_buf_conf[2]; 2185 2192 int ret = 0; 2186 2193 u32 ucr1; 2187 2194 struct resource *res; ··· 2220 2217 2221 2218 if (of_get_property(np, "fsl,inverted-rx", NULL)) 2222 2219 sport->inverted_rx = 1; 2220 + 2221 + if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) { 2222 + sport->rx_period_length = dma_buf_conf[0]; 2223 + sport->rx_periods = dma_buf_conf[1]; 2224 + } else { 2225 + sport->rx_period_length = RX_DMA_PERIOD_LEN; 2226 + sport->rx_periods = RX_DMA_PERIODS; 2227 + } 2223 2228 2224 2229 if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { 2225 2230 dev_err(&pdev->dev, "serial%d out of range\n",