aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorJorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>2015-03-06 13:05:40 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-06 21:50:30 -0500
commit1c9be31015747b0a981804438b269cfb0f49aa8a (patch)
tree0b1beaa0949392969287ced39cc1f7925e981faa /drivers/tty/serial
parentf2ee6dfa0e8597eea8b98d240b0033994e20d215 (diff)
drivers/tty: amba: defer DMA probe until the DMA channel is required.
Fix a race condition that happens when device_initcall(pl011_dma_initicall) is executed before all the devices have been probed - this issue was observed on a hisi_6220 SoC (HiKey board from Linaro). The deferred driver probing framework relies on late_initcall to trigger deferred probes so it is just possible that, even with a valid DMA driver ready to be loaded, we fail to synchronize with it. The proposed implementation delays probing the DMA until dma_startup. As this is invoked on port startup and port resume - but DMA probing is only required once - we avoid calling multiple times using a new field in uart_amba_port to track this scenario. This commit allows for subsequent attempts to associate an external DMA if the DMA driver itself is not available (but present in the deferred probe pending list). Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/amba-pl011.c71
1 files changed, 17 insertions, 54 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 92783fc8a851..7b428e7652c5 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -167,6 +167,7 @@ struct uart_amba_port {
167 bool using_rx_dma; 167 bool using_rx_dma;
168 struct pl011_dmarx_data dmarx; 168 struct pl011_dmarx_data dmarx;
169 struct pl011_dmatx_data dmatx; 169 struct pl011_dmatx_data dmatx;
170 bool dma_probed;
170#endif 171#endif
171}; 172};
172 173
@@ -264,10 +265,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
264 } 265 }
265} 266}
266 267
267static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) 268static void pl011_dma_probe(struct uart_amba_port *uap)
268{ 269{
269 /* DMA is the sole user of the platform data right now */ 270 /* DMA is the sole user of the platform data right now */
270 struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); 271 struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
272 struct device *dev = uap->port.dev;
271 struct dma_slave_config tx_conf = { 273 struct dma_slave_config tx_conf = {
272 .dst_addr = uap->port.mapbase + UART01x_DR, 274 .dst_addr = uap->port.mapbase + UART01x_DR,
273 .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, 275 .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
@@ -278,9 +280,15 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
278 struct dma_chan *chan; 280 struct dma_chan *chan;
279 dma_cap_mask_t mask; 281 dma_cap_mask_t mask;
280 282
281 chan = dma_request_slave_channel(dev, "tx"); 283 uap->dma_probed = true;
284 chan = dma_request_slave_channel_reason(dev, "tx");
285 if (IS_ERR(chan)) {
286 if (PTR_ERR(chan) == -EPROBE_DEFER) {
287 dev_info(uap->port.dev, "DMA driver not ready\n");
288 uap->dma_probed = false;
289 return;
290 }
282 291
283 if (!chan) {
284 /* We need platform data */ 292 /* We need platform data */
285 if (!plat || !plat->dma_filter) { 293 if (!plat || !plat->dma_filter) {
286 dev_info(uap->port.dev, "no DMA platform data\n"); 294 dev_info(uap->port.dev, "no DMA platform data\n");
@@ -388,55 +396,8 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
388 } 396 }
389} 397}
390 398
391#ifndef MODULE
392/*
393 * Stack up the UARTs and let the above initcall be done at device
394 * initcall time, because the serial driver is called as an arch
395 * initcall, and at this time the DMA subsystem is not yet registered.
396 * At this point the driver will switch over to using DMA where desired.
397 */
398struct dma_uap {
399 struct list_head node;
400 struct uart_amba_port *uap;
401 struct device *dev;
402};
403
404static LIST_HEAD(pl011_dma_uarts);
405
406static int __init pl011_dma_initcall(void)
407{
408 struct list_head *node, *tmp;
409
410 list_for_each_safe(node, tmp, &pl011_dma_uarts) {
411 struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
412 pl011_dma_probe_initcall(dmau->dev, dmau->uap);
413 list_del(node);
414 kfree(dmau);
415 }
416 return 0;
417}
418
419device_initcall(pl011_dma_initcall);
420
421static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
422{
423 struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
424 if (dmau) {
425 dmau->uap = uap;
426 dmau->dev = dev;
427 list_add_tail(&dmau->node, &pl011_dma_uarts);
428 }
429}
430#else
431static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
432{
433 pl011_dma_probe_initcall(dev, uap);
434}
435#endif
436
437static void pl011_dma_remove(struct uart_amba_port *uap) 399static void pl011_dma_remove(struct uart_amba_port *uap)
438{ 400{
439 /* TODO: remove the initcall if it has not yet executed */
440 if (uap->dmatx.chan) 401 if (uap->dmatx.chan)
441 dma_release_channel(uap->dmatx.chan); 402 dma_release_channel(uap->dmatx.chan);
442 if (uap->dmarx.chan) 403 if (uap->dmarx.chan)
@@ -1022,6 +983,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
1022{ 983{
1023 int ret; 984 int ret;
1024 985
986 if (!uap->dma_probed)
987 pl011_dma_probe(uap);
988
1025 if (!uap->dmatx.chan) 989 if (!uap->dmatx.chan)
1026 return; 990 return;
1027 991
@@ -1143,7 +1107,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1143 1107
1144#else 1108#else
1145/* Blank functions if the DMA engine is not available */ 1109/* Blank functions if the DMA engine is not available */
1146static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) 1110static inline void pl011_dma_probe(struct uart_amba_port *uap)
1147{ 1111{
1148} 1112}
1149 1113
@@ -2280,7 +2244,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
2280 uap->port.flags = UPF_BOOT_AUTOCONF; 2244 uap->port.flags = UPF_BOOT_AUTOCONF;
2281 uap->port.line = i; 2245 uap->port.line = i;
2282 INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); 2246 INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
2283 pl011_dma_probe(&dev->dev, uap);
2284 2247
2285 /* Ensure interrupts from this UART are masked and cleared */ 2248 /* Ensure interrupts from this UART are masked and cleared */
2286 writew(0, uap->port.membase + UART011_IMSC); 2249 writew(0, uap->port.membase + UART011_IMSC);
@@ -2295,7 +2258,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
2295 if (!amba_reg.state) { 2258 if (!amba_reg.state) {
2296 ret = uart_register_driver(&amba_reg); 2259 ret = uart_register_driver(&amba_reg);
2297 if (ret < 0) { 2260 if (ret < 0) {
2298 pr_err("Failed to register AMBA-PL011 driver\n"); 2261 dev_err(&dev->dev,
2262 "Failed to register AMBA-PL011 driver\n");
2299 return ret; 2263 return ret;
2300 } 2264 }
2301 } 2265 }
@@ -2304,7 +2268,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
2304 if (ret) { 2268 if (ret) {
2305 amba_ports[i] = NULL; 2269 amba_ports[i] = NULL;
2306 uart_unregister_driver(&amba_reg); 2270 uart_unregister_driver(&amba_reg);
2307 pl011_dma_remove(uap);
2308 } 2271 }
2309 2272
2310 return ret; 2273 return ret;