|
@@ -167,6 +167,7 @@ struct uart_amba_port {
|
|
|
bool using_rx_dma;
|
|
|
struct pl011_dmarx_data dmarx;
|
|
|
struct pl011_dmatx_data dmatx;
|
|
|
+ bool dma_probed;
|
|
|
#endif
|
|
|
};
|
|
|
|
|
@@ -264,10 +265,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap)
|
|
|
+static void pl011_dma_probe(struct uart_amba_port *uap)
|
|
|
{
|
|
|
/* DMA is the sole user of the platform data right now */
|
|
|
struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
|
|
|
+ struct device *dev = uap->port.dev;
|
|
|
struct dma_slave_config tx_conf = {
|
|
|
.dst_addr = uap->port.mapbase + UART01x_DR,
|
|
|
.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 *
|
|
|
struct dma_chan *chan;
|
|
|
dma_cap_mask_t mask;
|
|
|
|
|
|
- chan = dma_request_slave_channel(dev, "tx");
|
|
|
+ uap->dma_probed = true;
|
|
|
+ chan = dma_request_slave_channel_reason(dev, "tx");
|
|
|
+ if (IS_ERR(chan)) {
|
|
|
+ if (PTR_ERR(chan) == -EPROBE_DEFER) {
|
|
|
+ dev_info(uap->port.dev, "DMA driver not ready\n");
|
|
|
+ uap->dma_probed = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (!chan) {
|
|
|
/* We need platform data */
|
|
|
if (!plat || !plat->dma_filter) {
|
|
|
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 *
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#ifndef MODULE
|
|
|
-/*
|
|
|
- * Stack up the UARTs and let the above initcall be done at device
|
|
|
- * initcall time, because the serial driver is called as an arch
|
|
|
- * initcall, and at this time the DMA subsystem is not yet registered.
|
|
|
- * At this point the driver will switch over to using DMA where desired.
|
|
|
- */
|
|
|
-struct dma_uap {
|
|
|
- struct list_head node;
|
|
|
- struct uart_amba_port *uap;
|
|
|
- struct device *dev;
|
|
|
-};
|
|
|
-
|
|
|
-static LIST_HEAD(pl011_dma_uarts);
|
|
|
-
|
|
|
-static int __init pl011_dma_initcall(void)
|
|
|
-{
|
|
|
- struct list_head *node, *tmp;
|
|
|
-
|
|
|
- list_for_each_safe(node, tmp, &pl011_dma_uarts) {
|
|
|
- struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
|
|
|
- pl011_dma_probe_initcall(dmau->dev, dmau->uap);
|
|
|
- list_del(node);
|
|
|
- kfree(dmau);
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-device_initcall(pl011_dma_initcall);
|
|
|
-
|
|
|
-static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
|
|
-{
|
|
|
- struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
|
|
|
- if (dmau) {
|
|
|
- dmau->uap = uap;
|
|
|
- dmau->dev = dev;
|
|
|
- list_add_tail(&dmau->node, &pl011_dma_uarts);
|
|
|
- }
|
|
|
-}
|
|
|
-#else
|
|
|
-static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
|
|
-{
|
|
|
- pl011_dma_probe_initcall(dev, uap);
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
static void pl011_dma_remove(struct uart_amba_port *uap)
|
|
|
{
|
|
|
- /* TODO: remove the initcall if it has not yet executed */
|
|
|
if (uap->dmatx.chan)
|
|
|
dma_release_channel(uap->dmatx.chan);
|
|
|
if (uap->dmarx.chan)
|
|
@@ -1022,6 +983,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ if (!uap->dma_probed)
|
|
|
+ pl011_dma_probe(uap);
|
|
|
+
|
|
|
if (!uap->dmatx.chan)
|
|
|
return;
|
|
|
|
|
@@ -1143,7 +1107,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
|
|
|
|
|
#else
|
|
|
/* Blank functions if the DMA engine is not available */
|
|
|
-static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
|
|
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
|
|
|
{
|
|
|
}
|
|
|
|
|
@@ -2280,7 +2244,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|
|
uap->port.flags = UPF_BOOT_AUTOCONF;
|
|
|
uap->port.line = i;
|
|
|
INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
|
|
|
- pl011_dma_probe(&dev->dev, uap);
|
|
|
|
|
|
/* Ensure interrupts from this UART are masked and cleared */
|
|
|
writew(0, uap->port.membase + UART011_IMSC);
|
|
@@ -2295,7 +2258,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|
|
if (!amba_reg.state) {
|
|
|
ret = uart_register_driver(&amba_reg);
|
|
|
if (ret < 0) {
|
|
|
- pr_err("Failed to register AMBA-PL011 driver\n");
|
|
|
+ dev_err(&dev->dev,
|
|
|
+ "Failed to register AMBA-PL011 driver\n");
|
|
|
return ret;
|
|
|
}
|
|
|
}
|
|
@@ -2304,7 +2268,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|
|
if (ret) {
|
|
|
amba_ports[i] = NULL;
|
|
|
uart_unregister_driver(&amba_reg);
|
|
|
- pl011_dma_remove(uap);
|
|
|
}
|
|
|
|
|
|
return ret;
|