Provide an interface to 8250 driver to set DMA mode. It will be effective for the transfers through the port next time it will be opened. TBD: sysfs ABI documentation Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- Documentation/ABI/testing/sysfs-tty | 11 ++++ drivers/tty/serial/8250/8250_port.c | 110 +++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index 9eb3c2b..1dd68c9 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -154,3 +154,14 @@ Description: device specification. For example, when user sets 7bytes on 16550A, which has 1/4/8/14 bytes trigger, the RX trigger is automatically changed to 4 bytes. + +What: /sys/class/tty/ttyS0/skip_rxdma +What: /sys/class/tty/ttyS0/skip_txdma +Date: September 2016 +Contact: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> +Description: + Shows the current state of DMA use per channel or enforces PIO + mode. Users can show this value regardless of opening the + serial device file or not, though setting change is allowed + only on closed device. The change will be effective as of next + port opening. diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a00f2c3..14bfd7b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2904,14 +2904,120 @@ static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, serial8250_get_attr_rx_trig_bytes, serial8250_set_attr_rx_trig_bytes); +static ssize_t serial8250_get_attr_skip_rxdma(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + bool skip_rxdma; + + mutex_lock(&port->mutex); + skip_rxdma = !!(uport->quirks & UPQ_NO_DMA_RX); + mutex_unlock(&port->mutex); + + return snprintf(buf, PAGE_SIZE, "%c\n", skip_rxdma ? 'Y' : 'N'); +} + +static ssize_t serial8250_set_attr_skip_rxdma(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = up_to_u8250p(uport); + bool skip_rxdma; + int ret; + + if (!up->dma) + return -ENODEV; + + ret = kstrtobool(buf, &skip_rxdma); + if (ret < 0) + return ret; + + mutex_lock(&port->mutex); + if (up->dma->in_use) + count = -EBUSY; + else { + if (skip_rxdma) + uport->quirks |= UPQ_NO_DMA_RX; + else + uport->quirks &= ~UPQ_NO_DMA_RX; + } + mutex_unlock(&port->mutex); + + return count; +} + +static DEVICE_ATTR(skip_rxdma, S_IRUSR | S_IWUSR | S_IRGRP, + serial8250_get_attr_skip_rxdma, + serial8250_set_attr_skip_rxdma); + +static ssize_t serial8250_get_attr_skip_txdma(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + bool skip_txdma; + + mutex_lock(&port->mutex); + skip_txdma = !!(uport->quirks & UPQ_NO_DMA_TX); + mutex_unlock(&port->mutex); + + return snprintf(buf, PAGE_SIZE, "%c\n", skip_txdma ? 'Y' : 'N'); +} + +static ssize_t serial8250_set_attr_skip_txdma(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = up_to_u8250p(uport); + bool skip_txdma; + int ret; + + if (!up->dma) + return -ENODEV; + + ret = kstrtobool(buf, &skip_txdma); + if (ret < 0) + return ret; + + mutex_lock(&port->mutex); + if (up->dma->in_use) + count = -EBUSY; + else { + if (skip_txdma) + uport->quirks |= UPQ_NO_DMA_TX; + else + uport->quirks &= ~UPQ_NO_DMA_TX; + } + mutex_unlock(&port->mutex); + + return count; +} + +static DEVICE_ATTR(skip_txdma, S_IRUSR | S_IWUSR | S_IRGRP, + serial8250_get_attr_skip_txdma, + serial8250_set_attr_skip_txdma); + static struct attribute *serial8250_dev_attrs[] = { &dev_attr_rx_trig_bytes.attr, + &dev_attr_skip_rxdma.attr, + &dev_attr_skip_txdma.attr, NULL, - }; +}; static struct attribute_group serial8250_dev_attr_group = { .attrs = serial8250_dev_attrs, - }; +}; static void register_dev_spec_attr_grp(struct uart_8250_port *up) { -- 2.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html