LCOV - code coverage report
Current view: top level - drivers/tty/serial/8250 - 8250_dma.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 144 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 7 0.0 %
Branches: 0 58 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0+
       2                 :            : /*
       3                 :            :  * 8250_dma.c - DMA Engine API support for 8250.c
       4                 :            :  *
       5                 :            :  * Copyright (C) 2013 Intel Corporation
       6                 :            :  */
       7                 :            : #include <linux/tty.h>
       8                 :            : #include <linux/tty_flip.h>
       9                 :            : #include <linux/serial_reg.h>
      10                 :            : #include <linux/dma-mapping.h>
      11                 :            : 
      12                 :            : #include "8250.h"
      13                 :            : 
      14                 :          0 : static void __dma_tx_complete(void *param)
      15                 :            : {
      16                 :          0 :         struct uart_8250_port   *p = param;
      17                 :          0 :         struct uart_8250_dma    *dma = p->dma;
      18                 :          0 :         struct circ_buf         *xmit = &p->port.state->xmit;
      19                 :          0 :         unsigned long   flags;
      20                 :          0 :         int             ret;
      21                 :            : 
      22                 :          0 :         dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
      23                 :            :                                 UART_XMIT_SIZE, DMA_TO_DEVICE);
      24                 :            : 
      25                 :          0 :         spin_lock_irqsave(&p->port.lock, flags);
      26                 :            : 
      27                 :          0 :         dma->tx_running = 0;
      28                 :            : 
      29                 :          0 :         xmit->tail += dma->tx_size;
      30                 :          0 :         xmit->tail &= UART_XMIT_SIZE - 1;
      31                 :          0 :         p->port.icount.tx += dma->tx_size;
      32                 :            : 
      33         [ #  # ]:          0 :         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
      34                 :          0 :                 uart_write_wakeup(&p->port);
      35                 :            : 
      36                 :          0 :         ret = serial8250_tx_dma(p);
      37         [ #  # ]:          0 :         if (ret)
      38         [ #  # ]:          0 :                 serial8250_set_THRI(p);
      39                 :            : 
      40                 :          0 :         spin_unlock_irqrestore(&p->port.lock, flags);
      41                 :          0 : }
      42                 :            : 
      43                 :          0 : static void __dma_rx_complete(void *param)
      44                 :            : {
      45                 :          0 :         struct uart_8250_port   *p = param;
      46                 :          0 :         struct uart_8250_dma    *dma = p->dma;
      47                 :          0 :         struct tty_port         *tty_port = &p->port.state->port;
      48                 :          0 :         struct dma_tx_state     state;
      49                 :          0 :         int                     count;
      50                 :            : 
      51                 :          0 :         dma->rx_running = 0;
      52                 :          0 :         dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
      53                 :            : 
      54                 :          0 :         count = dma->rx_size - state.residue;
      55                 :            : 
      56                 :          0 :         tty_insert_flip_string(tty_port, dma->rx_buf, count);
      57                 :          0 :         p->port.icount.rx += count;
      58                 :            : 
      59                 :          0 :         tty_flip_buffer_push(tty_port);
      60                 :          0 : }
      61                 :            : 
      62                 :          0 : int serial8250_tx_dma(struct uart_8250_port *p)
      63                 :            : {
      64                 :          0 :         struct uart_8250_dma            *dma = p->dma;
      65                 :          0 :         struct circ_buf                 *xmit = &p->port.state->xmit;
      66                 :          0 :         struct dma_async_tx_descriptor  *desc;
      67                 :          0 :         int ret;
      68                 :            : 
      69         [ #  # ]:          0 :         if (dma->tx_running)
      70                 :            :                 return 0;
      71                 :            : 
      72   [ #  #  #  # ]:          0 :         if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
      73                 :            :                 /* We have been called from __dma_tx_complete() */
      74                 :          0 :                 serial8250_rpm_put_tx(p);
      75                 :          0 :                 return 0;
      76                 :            :         }
      77                 :            : 
      78                 :          0 :         dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
      79                 :            : 
      80                 :          0 :         desc = dmaengine_prep_slave_single(dma->txchan,
      81                 :          0 :                                            dma->tx_addr + xmit->tail,
      82                 :            :                                            dma->tx_size, DMA_MEM_TO_DEV,
      83                 :            :                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
      84         [ #  # ]:          0 :         if (!desc) {
      85                 :          0 :                 ret = -EBUSY;
      86                 :          0 :                 goto err;
      87                 :            :         }
      88                 :            : 
      89                 :          0 :         dma->tx_running = 1;
      90                 :          0 :         desc->callback = __dma_tx_complete;
      91                 :          0 :         desc->callback_param = p;
      92                 :            : 
      93                 :          0 :         dma->tx_cookie = dmaengine_submit(desc);
      94                 :            : 
      95                 :          0 :         dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
      96                 :            :                                    UART_XMIT_SIZE, DMA_TO_DEVICE);
      97                 :            : 
      98                 :          0 :         dma_async_issue_pending(dma->txchan);
      99         [ #  # ]:          0 :         if (dma->tx_err) {
     100                 :          0 :                 dma->tx_err = 0;
     101         [ #  # ]:          0 :                 serial8250_clear_THRI(p);
     102                 :            :         }
     103                 :            :         return 0;
     104                 :            : err:
     105                 :          0 :         dma->tx_err = 1;
     106                 :          0 :         return ret;
     107                 :            : }
     108                 :            : 
     109                 :          0 : int serial8250_rx_dma(struct uart_8250_port *p)
     110                 :            : {
     111                 :          0 :         struct uart_8250_dma            *dma = p->dma;
     112                 :          0 :         struct dma_async_tx_descriptor  *desc;
     113                 :            : 
     114         [ #  # ]:          0 :         if (dma->rx_running)
     115                 :            :                 return 0;
     116                 :            : 
     117                 :          0 :         desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
     118                 :            :                                            dma->rx_size, DMA_DEV_TO_MEM,
     119                 :            :                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
     120         [ #  # ]:          0 :         if (!desc)
     121                 :            :                 return -EBUSY;
     122                 :            : 
     123                 :          0 :         dma->rx_running = 1;
     124                 :          0 :         desc->callback = __dma_rx_complete;
     125                 :          0 :         desc->callback_param = p;
     126                 :            : 
     127                 :          0 :         dma->rx_cookie = dmaengine_submit(desc);
     128                 :            : 
     129                 :          0 :         dma_async_issue_pending(dma->rxchan);
     130                 :            : 
     131                 :          0 :         return 0;
     132                 :            : }
     133                 :            : 
     134                 :          0 : void serial8250_rx_dma_flush(struct uart_8250_port *p)
     135                 :            : {
     136                 :          0 :         struct uart_8250_dma *dma = p->dma;
     137                 :            : 
     138         [ #  # ]:          0 :         if (dma->rx_running) {
     139         [ #  # ]:          0 :                 dmaengine_pause(dma->rxchan);
     140                 :          0 :                 __dma_rx_complete(p);
     141         [ #  # ]:          0 :                 dmaengine_terminate_async(dma->rxchan);
     142                 :            :         }
     143                 :          0 : }
     144                 :            : EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
     145                 :            : 
     146                 :          0 : int serial8250_request_dma(struct uart_8250_port *p)
     147                 :            : {
     148                 :          0 :         struct uart_8250_dma    *dma = p->dma;
     149                 :          0 :         phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
     150         [ #  # ]:          0 :                                   dma->rx_dma_addr : p->port.mapbase;
     151                 :          0 :         phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
     152         [ #  # ]:          0 :                                   dma->tx_dma_addr : p->port.mapbase;
     153                 :          0 :         dma_cap_mask_t          mask;
     154                 :          0 :         struct dma_slave_caps   caps;
     155                 :          0 :         int                     ret;
     156                 :            : 
     157                 :            :         /* Default slave configuration parameters */
     158                 :          0 :         dma->rxconf.direction                = DMA_DEV_TO_MEM;
     159                 :          0 :         dma->rxconf.src_addr_width   = DMA_SLAVE_BUSWIDTH_1_BYTE;
     160                 :          0 :         dma->rxconf.src_addr         = rx_dma_addr + UART_RX;
     161                 :            : 
     162                 :          0 :         dma->txconf.direction                = DMA_MEM_TO_DEV;
     163                 :          0 :         dma->txconf.dst_addr_width   = DMA_SLAVE_BUSWIDTH_1_BYTE;
     164                 :          0 :         dma->txconf.dst_addr         = tx_dma_addr + UART_TX;
     165                 :            : 
     166                 :          0 :         dma_cap_zero(mask);
     167                 :          0 :         dma_cap_set(DMA_SLAVE, mask);
     168                 :            : 
     169                 :            :         /* Get a channel for RX */
     170                 :          0 :         dma->rxchan = dma_request_slave_channel_compat(mask,
     171                 :            :                                                        dma->fn, dma->rx_param,
     172                 :            :                                                        p->port.dev, "rx");
     173         [ #  # ]:          0 :         if (!dma->rxchan)
     174                 :            :                 return -ENODEV;
     175                 :            : 
     176                 :            :         /* 8250 rx dma requires dmaengine driver to support pause/terminate */
     177                 :          0 :         ret = dma_get_slave_caps(dma->rxchan, &caps);
     178         [ #  # ]:          0 :         if (ret)
     179                 :          0 :                 goto release_rx;
     180   [ #  #  #  # ]:          0 :         if (!caps.cmd_pause || !caps.cmd_terminate ||
     181         [ #  # ]:          0 :             caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
     182                 :          0 :                 ret = -EINVAL;
     183                 :          0 :                 goto release_rx;
     184                 :            :         }
     185                 :            : 
     186         [ #  # ]:          0 :         dmaengine_slave_config(dma->rxchan, &dma->rxconf);
     187                 :            : 
     188                 :            :         /* Get a channel for TX */
     189                 :          0 :         dma->txchan = dma_request_slave_channel_compat(mask,
     190                 :            :                                                        dma->fn, dma->tx_param,
     191                 :            :                                                        p->port.dev, "tx");
     192         [ #  # ]:          0 :         if (!dma->txchan) {
     193                 :          0 :                 ret = -ENODEV;
     194                 :          0 :                 goto release_rx;
     195                 :            :         }
     196                 :            : 
     197                 :            :         /* 8250 tx dma requires dmaengine driver to support terminate */
     198                 :          0 :         ret = dma_get_slave_caps(dma->txchan, &caps);
     199         [ #  # ]:          0 :         if (ret)
     200                 :          0 :                 goto err;
     201         [ #  # ]:          0 :         if (!caps.cmd_terminate) {
     202                 :          0 :                 ret = -EINVAL;
     203                 :          0 :                 goto err;
     204                 :            :         }
     205                 :            : 
     206         [ #  # ]:          0 :         dmaengine_slave_config(dma->txchan, &dma->txconf);
     207                 :            : 
     208                 :            :         /* RX buffer */
     209         [ #  # ]:          0 :         if (!dma->rx_size)
     210                 :          0 :                 dma->rx_size = PAGE_SIZE;
     211                 :            : 
     212                 :          0 :         dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
     213                 :            :                                         &dma->rx_addr, GFP_KERNEL);
     214         [ #  # ]:          0 :         if (!dma->rx_buf) {
     215                 :          0 :                 ret = -ENOMEM;
     216                 :          0 :                 goto err;
     217                 :            :         }
     218                 :            : 
     219                 :            :         /* TX buffer */
     220                 :          0 :         dma->tx_addr = dma_map_single(dma->txchan->device->dev,
     221                 :            :                                         p->port.state->xmit.buf,
     222                 :            :                                         UART_XMIT_SIZE,
     223                 :            :                                         DMA_TO_DEVICE);
     224                 :          0 :         if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
     225                 :          0 :                 dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
     226                 :            :                                   dma->rx_buf, dma->rx_addr);
     227                 :          0 :                 ret = -ENOMEM;
     228                 :          0 :                 goto err;
     229                 :            :         }
     230                 :            : 
     231                 :            :         dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
     232                 :            : 
     233                 :            :         return 0;
     234                 :          0 : err:
     235                 :          0 :         dma_release_channel(dma->txchan);
     236                 :          0 : release_rx:
     237                 :          0 :         dma_release_channel(dma->rxchan);
     238                 :          0 :         return ret;
     239                 :            : }
     240                 :            : EXPORT_SYMBOL_GPL(serial8250_request_dma);
     241                 :            : 
     242                 :          0 : void serial8250_release_dma(struct uart_8250_port *p)
     243                 :            : {
     244                 :          0 :         struct uart_8250_dma *dma = p->dma;
     245                 :            : 
     246         [ #  # ]:          0 :         if (!dma)
     247                 :            :                 return;
     248                 :            : 
     249                 :            :         /* Release RX resources */
     250                 :          0 :         dmaengine_terminate_sync(dma->rxchan);
     251                 :          0 :         dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
     252                 :            :                           dma->rx_addr);
     253                 :          0 :         dma_release_channel(dma->rxchan);
     254                 :          0 :         dma->rxchan = NULL;
     255                 :            : 
     256                 :            :         /* Release TX resources */
     257                 :          0 :         dmaengine_terminate_sync(dma->txchan);
     258                 :          0 :         dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
     259                 :            :                          UART_XMIT_SIZE, DMA_TO_DEVICE);
     260                 :          0 :         dma_release_channel(dma->txchan);
     261                 :          0 :         dma->txchan = NULL;
     262                 :          0 :         dma->tx_running = 0;
     263                 :            : 
     264                 :          0 :         dev_dbg_ratelimited(p->port.dev, "dma channels released\n");
     265                 :            : }
     266                 :            : EXPORT_SYMBOL_GPL(serial8250_release_dma);

Generated by: LCOV version 1.14