From patchwork Mon Jul 22 08:30:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Song, Elen" X-Patchwork-Id: 2831150 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 8A062C0319 for ; Mon, 22 Jul 2013 08:39:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E34A020189 for ; Mon, 22 Jul 2013 08:39:28 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5E58820124 for ; Mon, 22 Jul 2013 08:39:26 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1Bc0-0001um-Lp; Mon, 22 Jul 2013 08:36:58 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1BbI-0001K0-Ht; Mon, 22 Jul 2013 08:36:12 +0000 Received: from eusmtp01.atmel.com ([212.144.249.242]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1Bb8-0001JT-I2 for linux-arm-kernel@lists.infradead.org; Mon, 22 Jul 2013 08:36:03 +0000 Received: from apsmtp01.atmel.com (10.168.254.31) by eusmtp01.atmel.com (10.161.101.30) with Microsoft SMTP Server id 14.2.342.3; Mon, 22 Jul 2013 10:35:40 +0200 Received: from shaarm01.corp.atmel.com (10.168.254.13) by apsmtp01.atmel.com (10.168.254.31) with Microsoft SMTP Server id 14.2.342.3; Mon, 22 Jul 2013 16:37:39 +0800 From: Elen Song To: , , Subject: [PATCH 2/8 V3] serial: at91: use function pointer to choose pdc or pio Date: Mon, 22 Jul 2013 16:30:25 +0800 Message-ID: <1374481831-24573-3-git-send-email-elen.song@atmel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1374481831-24573-1-git-send-email-elen.song@atmel.com> References: <1374481831-24573-1-git-send-email-elen.song@atmel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130722_043603_011773_1468D170 X-CRM114-Status: GOOD ( 16.79 ) X-Spam-Score: -3.4 (---) Cc: gregkh@linuxfoundation.org, elen.song@atmel.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP use function pointer can avoid define atmel_use_pdc_tx/rx everywhere. (*prepare_rx/tx)() is in setup transfer stage. (*schedule_rx/tx)() is in tasklet schedule stage. (*release_rx/tx)() is used when shutdown the transfer. Signed-off-by: Elen Song --- drivers/tty/serial/atmel_serial.c | 203 ++++++++++++++++++++++++------------- 1 file changed, 130 insertions(+), 73 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 81a8807..ae61f2b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -155,6 +155,12 @@ struct atmel_uart_port { struct serial_rs485 rs485; /* rs485 settings */ unsigned int tx_done_mask; + int (*prepare_rx)(struct uart_port *port); + int (*prepare_tx)(struct uart_port *port); + void (*schedule_rx)(struct uart_port *port); + void (*schedule_tx)(struct uart_port *port); + void (*release_rx)(struct uart_port *port); + void (*release_tx)(struct uart_port *port); }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; @@ -658,6 +664,17 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) return pass_counter ? IRQ_HANDLED : IRQ_NONE; } +static void atmel_release_tx_pdc(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); +} + /* * Called from tasklet with ENDTX and TXBUFE interrupts disabled. */ @@ -710,6 +727,23 @@ static void atmel_tx_pdc(struct uart_port *port) uart_write_wakeup(port); } +static int atmel_prepare_tx_pdc(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + struct circ_buf *xmit = &port->state->xmit; + + pdc->buf = xmit->buf; + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + pdc->dma_size = UART_XMIT_SIZE; + pdc->ofs = 0; + + return 0; +} + static void atmel_rx_from_ring(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -778,6 +812,22 @@ static void atmel_rx_from_ring(struct uart_port *port) spin_lock(&port->lock); } +static void atmel_release_rx_pdc(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_FROM_DEVICE); + kfree(pdc->buf); + } +} + static void atmel_rx_from_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -855,6 +905,45 @@ static void atmel_rx_from_pdc(struct uart_port *port) UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } +static int atmel_prepare_rx_pdc(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); + if (pdc->buf == NULL) { + if (i != 0) { + dma_unmap_single(port->dev, + atmel_port->pdc_rx[0].dma_addr, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + kfree(atmel_port->pdc_rx[0].buf); + } + atmel_port->use_pdc_rx = 0; + return -ENOMEM; + } + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + pdc->dma_size = PDC_BUFFER_SIZE; + pdc->ofs = 0; + } + + atmel_port->pdc_rx_idx = 0; + + UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); + UART_PUT_RCR(port, PDC_BUFFER_SIZE); + + UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); + UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + + return 0; +} + /* * tasklet handling tty stuff outside the interrupt handler. */ @@ -868,10 +957,7 @@ static void atmel_tasklet_func(unsigned long data) /* The interrupt handler does not take the lock */ spin_lock(&port->lock); - if (atmel_use_pdc_tx(port)) - atmel_tx_pdc(port); - else - atmel_tx_chars(port); + atmel_port->schedule_tx(port); status = atmel_port->irq_status; status_change = status ^ atmel_port->irq_status_prev; @@ -893,14 +979,36 @@ static void atmel_tasklet_func(unsigned long data) atmel_port->irq_status_prev = status; } - if (atmel_use_pdc_rx(port)) - atmel_rx_from_pdc(port); - else - atmel_rx_from_ring(port); + atmel_port->schedule_rx(port); spin_unlock(&port->lock); } +static void atmel_set_ops(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_pdc_rx(port)) { + atmel_port->prepare_rx = &atmel_prepare_rx_pdc; + atmel_port->schedule_rx = &atmel_rx_from_pdc; + atmel_port->release_rx = &atmel_release_rx_pdc; + } else { + atmel_port->prepare_rx = NULL; + atmel_port->schedule_rx = &atmel_rx_from_ring; + atmel_port->release_rx = NULL; + } + + if (atmel_use_pdc_tx(port)) { + atmel_port->prepare_tx = &atmel_prepare_tx_pdc; + atmel_port->schedule_tx = &atmel_tx_pdc; + atmel_port->release_tx = &atmel_release_tx_pdc; + } else { + atmel_port->prepare_tx = NULL; + atmel_port->schedule_tx = &atmel_tx_chars; + atmel_port->release_tx = NULL; + } +} + /* * Perform initialization and enable port for reception */ @@ -930,53 +1038,17 @@ static int atmel_startup(struct uart_port *port) /* * Initialize DMA (if necessary) */ - if (atmel_use_pdc_rx(port)) { - int i; - - for (i = 0; i < 2; i++) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; - - pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); - if (pdc->buf == NULL) { - if (i != 0) { - dma_unmap_single(port->dev, - atmel_port->pdc_rx[0].dma_addr, - PDC_BUFFER_SIZE, - DMA_FROM_DEVICE); - kfree(atmel_port->pdc_rx[0].buf); - } - free_irq(port->irq, port); - return -ENOMEM; - } - pdc->dma_addr = dma_map_single(port->dev, - pdc->buf, - PDC_BUFFER_SIZE, - DMA_FROM_DEVICE); - pdc->dma_size = PDC_BUFFER_SIZE; - pdc->ofs = 0; - } - - atmel_port->pdc_rx_idx = 0; - - UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); - UART_PUT_RCR(port, PDC_BUFFER_SIZE); - - UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); - UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + if (atmel_port->prepare_rx) { + retval = atmel_port->prepare_rx(port); + if (retval < 0) + atmel_set_ops(port); } - if (atmel_use_pdc_tx(port)) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; - pdc->buf = xmit->buf; - pdc->dma_addr = dma_map_single(port->dev, - pdc->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - pdc->dma_size = UART_XMIT_SIZE; - pdc->ofs = 0; + if (atmel_port->prepare_tx) { + retval = atmel_port->prepare_tx(port); + if (retval < 0) + atmel_set_ops(port); } - /* * If there is a specific "open" function (to register * control line interrupts) @@ -1031,27 +1103,10 @@ static void atmel_shutdown(struct uart_port *port) /* * Shut-down the DMA. */ - if (atmel_use_pdc_rx(port)) { - int i; - - for (i = 0; i < 2; i++) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; - - dma_unmap_single(port->dev, - pdc->dma_addr, - pdc->dma_size, - DMA_FROM_DEVICE); - kfree(pdc->buf); - } - } - if (atmel_use_pdc_tx(port)) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - - dma_unmap_single(port->dev, - pdc->dma_addr, - pdc->dma_size, - DMA_TO_DEVICE); - } + if (atmel_port->release_rx) + atmel_port->release_rx(port); + if (atmel_port->release_tx) + atmel_port->release_tx(port); /* * Disable all interrupts, port and break condition. @@ -1473,6 +1528,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port, atmel_port->rs485 = pdata->rs485; } + atmel_set_ops(port); + port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; port->ops = &atmel_pops;