2011-02-23 01:04:48

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 1/8] pch_uart: add multi-scatter processing

Currently, this driver can handle only single scatterlist.
Thus, it can't send data beyond FIFO size.

This patch enables this driver can handle multiple scatter list.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 117 +++++++++++++++++++++++++++++++----------
1 files changed, 89 insertions(+), 28 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 14a27c3..bd5e980 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -225,7 +225,8 @@ struct eg20t_port {
struct pch_dma_slave param_rx;
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
- struct scatterlist sg_tx;
+ struct scatterlist *sg_tx_p;
+ int nent;
struct scatterlist sg_rx;
int tx_dma_use;
void *rx_buf_virt;
@@ -594,16 +595,20 @@ static void pch_dma_rx_complete(void *arg)
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+ int count;

if (!tty) {
pr_debug("%s:tty is busy now", __func__);
return;
}

- if (dma_push_rx(priv, priv->trigger_level))
+ dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE);
+ count = dma_push_rx(priv, priv->trigger_level);
+ if (count)
tty_flip_buffer_push(tty);
-
tty_kref_put(tty);
+ async_tx_ack(priv->desc_rx);
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
}

static void pch_dma_tx_complete(void *arg)
@@ -611,13 +616,21 @@ static void pch_dma_tx_complete(void *arg)
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
+ struct scatterlist *sg = priv->sg_tx_p;
+ int i;

- xmit->tail += sg_dma_len(&priv->sg_tx);
+ for (i = 0; i < priv->nent; i++, sg++) {
+ xmit->tail += sg_dma_len(sg);
+ port->icount.tx += sg_dma_len(sg);
+ }
xmit->tail &= UART_XMIT_SIZE - 1;
- port->icount.tx += sg_dma_len(&priv->sg_tx);
-
async_tx_ack(priv->desc_tx);
+ dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE);
priv->tx_dma_use = 0;
+ priv->nent = 0;
+ kfree(priv->sg_tx_p);
+ if (uart_circ_chars_pending(xmit))
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
}

static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
@@ -681,7 +694,7 @@ static int dma_handle_rx(struct eg20t_port *priv)

sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */

- sg_dma_len(sg) = priv->fifo_size;
+ sg_dma_len(sg) = priv->trigger_level;

sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
@@ -691,7 +704,8 @@ static int dma_handle_rx(struct eg20t_port *priv)

desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
sg, 1, DMA_FROM_DEVICE,
- DMA_PREP_INTERRUPT);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
if (!desc)
return 0;

@@ -730,6 +744,9 @@ static unsigned int handle_tx(struct eg20t_port *priv)
fifo_size--;
}
size = min(xmit->head - xmit->tail, fifo_size);
+ if (size < 0)
+ size = fifo_size;
+
tx_size = pop_tx(priv, xmit->buf, size);
if (tx_size > 0) {
ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
@@ -739,8 +756,10 @@ static unsigned int handle_tx(struct eg20t_port *priv)

priv->tx_empty = tx_empty;

- if (tx_empty)
+ if (tx_empty) {
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ uart_write_wakeup(port);
+ }

return PCH_UART_HANDLED_TX_INT;
}
@@ -749,11 +768,16 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
- struct scatterlist *sg = &priv->sg_tx;
+ struct scatterlist *sg;
int nent;
int fifo_size;
int tx_empty;
struct dma_async_tx_descriptor *desc;
+ int num;
+ int i;
+ int bytes;
+ int size;
+ int rem;

if (!priv->start_tx) {
pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
@@ -771,37 +795,68 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
fifo_size--;
}

- pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ bytes = min((int)CIRC_CNT(xmit->head, xmit->tail,
+ UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE));
+ if (!bytes) {
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ uart_write_wakeup(port);
+ return 0;
+ }
+
+ if (bytes > fifo_size) {
+ num = bytes / fifo_size + 1;
+ size = fifo_size;
+ rem = bytes % fifo_size;
+ } else {
+ num = 1;
+ size = bytes;
+ rem = bytes;
+ }

priv->tx_dma_use = 1;

- sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
+ priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+
+ sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
+ sg = priv->sg_tx_p;

- sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
- UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
+ for (i = 0; i < num; i++, sg++) {
+ if (i == (num - 1))
+ sg_set_page(sg, virt_to_page(xmit->buf),
+ rem, fifo_size * i);
+ else
+ sg_set_page(sg, virt_to_page(xmit->buf),
+ size, fifo_size * i);
+ }

- nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
+ sg = priv->sg_tx_p;
+ nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE);
if (!nent) {
pr_err("%s:dma_map_sg Failed\n", __func__);
return 0;
}
-
- sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
- sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
- sg->offset;
- sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
- UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
- xmit->tail, UART_XMIT_SIZE));
+ priv->nent = nent;
+
+ for (i = 0; i < nent; i++, sg++) {
+ sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
+ fifo_size * i;
+ sg_dma_address(sg) = (sg_dma_address(sg) &
+ ~(UART_XMIT_SIZE - 1)) + sg->offset;
+ if (i == (nent - 1))
+ sg_dma_len(sg) = rem;
+ else
+ sg_dma_len(sg) = size;
+ }

desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
- sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ priv->sg_tx_p, nent, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
pr_err("%s:device_prep_slave_sg Failed\n", __func__);
return 0;
}
-
- dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
-
+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
priv->desc_tx = desc;
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
@@ -856,10 +911,16 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
}
break;
case PCH_UART_IID_RDR: /* Received Data Ready */
- if (priv->use_dma)
+ if (priv->use_dma) {
+ pch_uart_hal_disable_interrupt(priv,
+ PCH_UART_HAL_RX_INT);
ret = dma_handle_rx(priv);
- else
+ if (!ret)
+ pch_uart_hal_enable_interrupt(priv,
+ PCH_UART_HAL_RX_INT);
+ } else {
ret = handle_rx(priv);
+ }
break;
case PCH_UART_IID_RDR_TO: /* Received Data Ready
(FIFO Timeout) */
--
1.7.3.4


2011-02-23 01:04:50

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 2/8] pch_uart: add spin_lock_init

Currently, spin_lock is not initialized.
Thus, add spin_lock_init().

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index bd5e980..9c631ab 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1369,6 +1369,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.line = num++;
priv->trigger = PCH_UART_HAL_TRIGGER_M;

+ spin_lock_init(&priv->port.lock);
+
pci_set_drvdata(pdev, priv);
pch_uart_hal_request(pdev, fifosize, base_baud);

--
1.7.3.4

2011-02-23 01:04:52

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 6/8] pch_uart: fix auto flow control miss-setting issue

Currently, auto-flow control setting processing is not set correctly.
This patch fixes the issue.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 19 +++++++++++++------
1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 7179202..d937157 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -217,6 +217,7 @@ struct eg20t_port {
struct pch_uart_buffer rxbuf;
unsigned int dmsr;
unsigned int fcr;
+ unsigned int mcr;
unsigned int use_dma;
unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx;
@@ -1006,7 +1007,6 @@ static unsigned int pch_uart_get_mctrl(struct uart_port *port)
static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 mcr = 0;
- unsigned int dat;
struct eg20t_port *priv = container_of(port, struct eg20t_port, port);

if (mctrl & TIOCM_DTR)
@@ -1016,11 +1016,11 @@ static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;

- if (mctrl) {
- dat = pch_uart_get_mctrl(port);
- dat |= mcr;
- iowrite8(dat, priv->membase + UART_MCR);
- }
+ if (priv->mcr & UART_MCR_AFE)
+ mcr |= UART_MCR_AFE;
+
+ if (mctrl)
+ iowrite8(mcr, priv->membase + UART_MCR);
}

static void pch_uart_stop_tx(struct uart_port *port)
@@ -1214,6 +1214,13 @@ static void pch_uart_set_termios(struct uart_port *port,
} else {
parity = PCH_UART_HAL_PARITY_NONE;
}
+
+ /* Only UART0 has auto hardware flow function */
+ if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
+ priv->mcr |= UART_MCR_AFE;
+ else
+ priv->mcr &= ~UART_MCR_AFE;
+
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */

baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
--
1.7.3.4

2011-02-23 01:05:23

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 7/8] pch_uart: fix exclusive access issue

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index d937157..c525178 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -635,8 +635,7 @@ static void pch_dma_tx_complete(void *arg)
priv->tx_dma_use = 0;
priv->nent = 0;
kfree(priv->sg_tx_p);
- if (uart_circ_chars_pending(xmit))
- pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
}

static int pop_tx(struct eg20t_port *priv, int size)
@@ -792,6 +791,14 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
return 0;
}

+ if (priv->tx_dma_use) {
+ dev_dbg(priv->port.dev, "%s:Tx is not completed. (%lu)\n",
+ __func__, jiffies);
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ priv->tx_empty = 1;
+ return 0;
+ }
+
fifo_size = max(priv->fifo_size, 1);
tx_empty = 1;
if (pop_tx_x(priv, xmit->buf)) {
--
1.7.3.4

2011-02-23 01:05:21

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 8/8] pch_uart: Fix DMA channel miss-setting issue.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 59 ++++++++++++++++++++++++++++++++--------
1 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c525178..7aba41f 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -234,6 +234,36 @@ struct eg20t_port {
dma_addr_t rx_buf_dma;
};

+/**
+ * struct pch_uart_driver_data - private data structure for UART-DMA
+ * @port_type: The number of DMA channel
+ * @line_no: UART port line number (0, 1, 2...)
+ */
+struct pch_uart_driver_data {
+ int port_type;
+ int line_no;
+};
+
+enum pch_uart_num_t {
+ pch_et20t_uart0 = 0,
+ pch_et20t_uart1,
+ pch_et20t_uart2,
+ pch_et20t_uart3,
+ pch_ml7213_uart0,
+ pch_ml7213_uart1,
+ pch_ml7213_uart2,
+};
+
+static struct pch_uart_driver_data drv_dat[] = {
+ [pch_et20t_uart0] = {PCH_UART_8LINE, 0},
+ [pch_et20t_uart1] = {PCH_UART_2LINE, 1},
+ [pch_et20t_uart2] = {PCH_UART_2LINE, 2},
+ [pch_et20t_uart3] = {PCH_UART_2LINE, 3},
+ [pch_ml7213_uart0] = {PCH_UART_8LINE, 0},
+ [pch_ml7213_uart1] = {PCH_UART_2LINE, 1},
+ [pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
+};
+
static unsigned int default_baud = 9600;
static const int trigger_level_256[4] = { 1, 64, 128, 224 };
static const int trigger_level_64[4] = { 1, 16, 32, 56 };
@@ -567,7 +597,8 @@ static void pch_request_dma(struct uart_port *port)
/* Set Tx DMA */
param = &priv->param_tx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = priv->port.line;
+ param->chan_id = priv->port.line * 2; /* Tx = 0, 2, 4, ... */
+
param->tx_reg = port->mapbase + UART_TX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
@@ -580,7 +611,8 @@ static void pch_request_dma(struct uart_port *port)
/* Set Rx DMA */
param = &priv->param_rx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
+ param->chan_id = priv->port.line * 2 + 1; /* Rx = Tx + 1 */
+
param->rx_reg = port->mapbase + UART_RX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
@@ -1357,8 +1389,11 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
unsigned int mapbase;
unsigned char *rxbuf;
int fifosize, base_baud;
- static int num;
- int port_type = id->driver_data;
+ int port_type;
+ struct pch_uart_driver_data *board;
+
+ board = &drv_dat[id->driver_data];
+ port_type = board->port_type;

priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
if (priv == NULL)
@@ -1403,7 +1438,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.ops = &pch_uart_ops;
priv->port.flags = UPF_BOOT_AUTOCONF;
priv->port.fifosize = fifosize;
- priv->port.line = num++;
+ priv->port.line = board->line_no;
priv->trigger = PCH_UART_HAL_TRIGGER_M;

spin_lock_init(&priv->port.lock);
@@ -1481,19 +1516,19 @@ static int pch_uart_pci_resume(struct pci_dev *pdev)

static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
- .driver_data = PCH_UART_8LINE},
+ .driver_data = pch_et20t_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
- .driver_data = PCH_UART_2LINE},
+ .driver_data = pch_et20t_uart1},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
- .driver_data = PCH_UART_2LINE},
+ .driver_data = pch_et20t_uart2},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
- .driver_data = PCH_UART_2LINE},
+ .driver_data = pch_et20t_uart3},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8027),
- .driver_data = PCH_UART_8LINE},
+ .driver_data = pch_ml7213_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8028),
- .driver_data = PCH_UART_2LINE},
+ .driver_data = pch_ml7213_uart1},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8029),
- .driver_data = PCH_UART_2LINE},
+ .driver_data = pch_ml7213_uart2},
{0,},
};

--
1.7.3.4

2011-02-23 01:05:53

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 3/8] pch_uart : Reduce memcpy

Reduce memcpy for performance improvement.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 9c631ab..d4bcbce 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -389,7 +389,7 @@ static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
return get_msr(priv, priv->membase);
}

-static int pch_uart_hal_write(struct eg20t_port *priv,
+static void pch_uart_hal_write(struct eg20t_port *priv,
const unsigned char *buf, int tx_size)
{
int i;
@@ -399,7 +399,6 @@ static int pch_uart_hal_write(struct eg20t_port *priv,
thr = buf[i++];
iowrite8(thr, priv->membase + PCH_UART_THR);
}
- return i;
}

static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
@@ -633,7 +632,7 @@ static void pch_dma_tx_complete(void *arg)
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
}

-static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
+static int pop_tx(struct eg20t_port *priv, int size)
{
int count = 0;
struct uart_port *port = &priv->port;
@@ -646,7 +645,7 @@ static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
int cnt_to_end =
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
int sz = min(size - count, cnt_to_end);
- memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
+ pch_uart_hal_write(priv, &xmit->buf[xmit->tail], sz);
xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
count += sz;
} while (!uart_circ_empty(xmit) && count < size);
@@ -722,7 +721,6 @@ static unsigned int handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
- int ret;
int fifo_size;
int tx_size;
int size;
@@ -747,10 +745,9 @@ static unsigned int handle_tx(struct eg20t_port *priv)
if (size < 0)
size = fifo_size;

- tx_size = pop_tx(priv, xmit->buf, size);
+ tx_size = pop_tx(priv, size);
if (tx_size > 0) {
- ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
- port->icount.tx += ret;
+ port->icount.tx += tx_size;
tx_empty = 0;
}

--
1.7.3.4

2011-02-23 01:05:54

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 4/8] pch_uart : Use dev_xxx not pr_xxx

For easy to understad which port the message is out,
replace pr_xxx with dev_xxx.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 77 ++++++++++++++++++++++++++---------------
1 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index d4bcbce..6807f61 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -281,7 +281,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,

div = DIV_ROUND(priv->base_baud / 16, baud);
if (div < 0 || USHRT_MAX <= div) {
- pr_err("Invalid Baud(div=0x%x)\n", div);
+ dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
return -EINVAL;
}

@@ -289,17 +289,17 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
dlm = ((unsigned int)div >> 8) & 0x00FFU;

if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
- pr_err("Invalid parity(0x%x)\n", parity);
+ dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity);
return -EINVAL;
}

if (bits & ~PCH_UART_LCR_WLS) {
- pr_err("Invalid bits(0x%x)\n", bits);
+ dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits);
return -EINVAL;
}

if (stb & ~PCH_UART_LCR_STB) {
- pr_err("Invalid STB(0x%x)\n", stb);
+ dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb);
return -EINVAL;
}

@@ -307,7 +307,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
lcr |= bits;
lcr |= stb;

- pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+ dev_dbg(priv->port.dev, "%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
__func__, baud, div, lcr, jiffies);
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
iowrite8(dll, priv->membase + PCH_UART_DLL);
@@ -321,7 +321,8 @@ static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
unsigned int flag)
{
if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
- pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
+ dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n",
+ __func__, flag);
return -EINVAL;
}

@@ -340,17 +341,20 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
u8 fcr;

if (dmamode & ~PCH_UART_FCR_DMS) {
- pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
+ dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n",
+ __func__, dmamode);
return -EINVAL;
}

if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
- pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
+ dev_err(priv->port.dev, "%s:Invalid FIFO SIZE(0x%x)\n",
+ __func__, fifo_size);
return -EINVAL;
}

if (trigger & ~PCH_UART_FCR_RFTL) {
- pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
+ dev_err(priv->port.dev, "%s:Invalid TRIGGER(0x%x)\n",
+ __func__, trigger);
return -EINVAL;
}

@@ -454,7 +458,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
port = &priv->port;
tty = tty_port_tty_get(&port->state->port);
if (!tty) {
- pr_debug("%s:tty is busy now", __func__);
+ dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return -EBUSY;
}

@@ -471,8 +475,8 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
struct uart_port *port = &priv->port;

if (port->x_char) {
- pr_debug("%s:X character send %02x (%lu)\n", __func__,
- port->x_char, jiffies);
+ dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n",
+ __func__, port->x_char, jiffies);
buf[0] = port->x_char;
port->x_char = 0;
ret = 1;
@@ -492,7 +496,7 @@ static int dma_push_rx(struct eg20t_port *priv, int size)
port = &priv->port;
tty = tty_port_tty_get(&port->state->port);
if (!tty) {
- pr_debug("%s:tty is busy now", __func__);
+ dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return 0;
}

@@ -566,7 +570,8 @@ static void pch_request_dma(struct uart_port *port)
param->tx_reg = port->mapbase + UART_TX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
- pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
+ __func__);
return;
}
priv->chan_tx = chan;
@@ -578,7 +583,8 @@ static void pch_request_dma(struct uart_port *port)
param->rx_reg = port->mapbase + UART_RX;
chan = dma_request_channel(mask, filter, param);
if (!chan) {
- pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
+ __func__);
dma_release_channel(priv->chan_tx);
return;
}
@@ -597,7 +603,7 @@ static void pch_dma_rx_complete(void *arg)
int count;

if (!tty) {
- pr_debug("%s:tty is busy now", __func__);
+ dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
return;
}

@@ -651,7 +657,7 @@ static int pop_tx(struct eg20t_port *priv, int size)
} while (!uart_circ_empty(xmit) && count < size);

pop_tx_end:
- pr_debug("%d characters. Remained %d characters. (%lu)\n",
+ dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n",
count, size - count, jiffies);

return count;
@@ -727,7 +733,8 @@ static unsigned int handle_tx(struct eg20t_port *priv)
int tx_empty;

if (!priv->start_tx) {
- pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
+ __func__, jiffies);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
priv->tx_empty = 1;
return 0;
@@ -777,7 +784,8 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
int rem;

if (!priv->start_tx) {
- pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
+ __func__, jiffies);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
priv->tx_empty = 1;
return 0;
@@ -796,6 +804,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
xmit->tail, UART_XMIT_SIZE));
if (!bytes) {
+ dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
uart_write_wakeup(port);
return 0;
@@ -811,6 +820,9 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
rem = bytes;
}

+ dev_dbg(priv->port.dev, "%s num=%d size=%d rem=%d\n",
+ __func__, num, size, rem);
+
priv->tx_dma_use = 1;

priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
@@ -830,7 +842,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
sg = priv->sg_tx_p;
nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE);
if (!nent) {
- pr_err("%s:dma_map_sg Failed\n", __func__);
+ dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
return 0;
}
priv->nent = nent;
@@ -850,7 +862,8 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
priv->sg_tx_p, nent, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
- pr_err("%s:device_prep_slave_sg Failed\n", __func__);
+ dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
+ __func__);
return 0;
}
dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
@@ -934,7 +947,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = PCH_UART_HANDLED_MS_INT;
break;
default: /* Never junp to this label */
- pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
+ dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
+ iid, jiffies);
ret = -1;
break;
}
@@ -1023,9 +1037,13 @@ static void pch_uart_start_tx(struct uart_port *port)

priv = container_of(port, struct eg20t_port, port);

- if (priv->use_dma)
- if (priv->tx_dma_use)
+ if (priv->use_dma) {
+ if (priv->tx_dma_use) {
+ dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n",
+ __func__);
return;
+ }
+ }

priv->start_tx = 1;
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
@@ -1141,7 +1159,8 @@ static void pch_uart_shutdown(struct uart_port *port)
ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
if (ret)
- pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
+ dev_err(priv->port.dev,
+ "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);

if (priv->use_dma_flag)
pch_free_dma(port);
@@ -1262,17 +1281,19 @@ static int pch_uart_verify_port(struct uart_port *port,

priv = container_of(port, struct eg20t_port, port);
if (serinfo->flags & UPF_LOW_LATENCY) {
- pr_info("PCH UART : Use PIO Mode (without DMA)\n");
+ dev_info(priv->port.dev,
+ "PCH UART : Use PIO Mode (without DMA)\n");
priv->use_dma = 0;
serinfo->flags &= ~UPF_LOW_LATENCY;
} else {
#ifndef CONFIG_PCH_DMA
- pr_err("%s : PCH DMA is not Loaded.\n", __func__);
+ dev_err(priv->port.dev, "%s : PCH DMA is not Loaded.\n",
+ __func__);
return -EOPNOTSUPP;
#endif
priv->use_dma = 1;
priv->use_dma_flag = 1;
- pr_info("PCH UART : Use DMA Mode\n");
+ dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
}

return 0;
--
1.7.3.4

2011-02-23 01:05:51

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH linux-next 5/8] pch_uart: fix uart clock setting issue

Currently, uart clock is not set correctly.
This patch fixes the issue.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/tty/serial/pch_uart.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 6807f61..7179202 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1088,7 +1088,12 @@ static int pch_uart_startup(struct uart_port *port)

priv = container_of(port, struct eg20t_port, port);
priv->tx_empty = 1;
- port->uartclk = priv->base_baud;
+
+ if (port->uartclk)
+ priv->base_baud = port->uartclk;
+ else
+ port->uartclk = priv->base_baud;
+
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
ret = pch_uart_hal_set_line(priv, default_baud,
PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
--
1.7.3.4