mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-30 13:26:41 +07:00
serial: at91: use function pointer to choose pdc or pio
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 <elen.song@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
64e22ebe49
commit
a930e52875
@ -154,6 +154,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];
|
||||
@ -657,6 +663,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.
|
||||
*/
|
||||
@ -709,6 +726,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);
|
||||
@ -777,6 +811,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);
|
||||
@ -854,6 +904,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.
|
||||
*/
|
||||
@ -867,10 +956,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;
|
||||
@ -892,14 +978,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
|
||||
*/
|
||||
@ -929,53 +1037,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_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_rx) {
|
||||
retval = atmel_port->prepare_rx(port);
|
||||
if (retval < 0)
|
||||
atmel_set_ops(port);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1030,27 +1102,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 int 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;
|
||||
|
Loading…
Reference in New Issue
Block a user