Commit 09b03b6c authored by Vitaly Bordug's avatar Vitaly Bordug Committed by Paul Mackerras

[PATCH] ppc32 CPM_UART: Fixed odd address translations

Current address translation methods can produce wrong results, because
virt_to_bus and vice versa may not produce correct offsets on dma-allocated
memory. The right way is, while tracking both phys and virt address of the
window that has been allocated for boffer descriptors, and use those
numbers to compute the offset and make translation properly.
Signed-off-by: default avatarVitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 4427d6bf
...@@ -66,6 +66,7 @@ struct uart_cpm_port { ...@@ -66,6 +66,7 @@ struct uart_cpm_port {
uint dp_addr; uint dp_addr;
void *mem_addr; void *mem_addr;
dma_addr_t dma_addr; dma_addr_t dma_addr;
u32 mem_size;
/* helpers */ /* helpers */
int baud; int baud;
int bits; int bits;
...@@ -92,4 +93,36 @@ void scc2_lineif(struct uart_cpm_port *pinfo); ...@@ -92,4 +93,36 @@ void scc2_lineif(struct uart_cpm_port *pinfo);
void scc3_lineif(struct uart_cpm_port *pinfo); void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo); void scc4_lineif(struct uart_cpm_port *pinfo);
/*
virtual to phys transtalion
*/
static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
{
int offset;
u32 val = (u32)addr;
/* sane check */
if ((val >= (u32)pinfo->mem_addr) &&
(val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
offset = val - (u32)pinfo->mem_addr;
return pinfo->dma_addr+offset;
}
printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val);
return 0;
}
static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
{
int offset;
u32 val = addr;
/* sane check */
if ((val >= pinfo->dma_addr) &&
(val<(pinfo->dma_addr + pinfo->mem_size))) {
offset = val - (u32)pinfo->dma_addr;
return (void*)(pinfo->mem_addr+offset);
}
printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val);
return 0;
}
#endif /* CPM_UART_H */ #endif /* CPM_UART_H */
...@@ -72,19 +72,6 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); ...@@ -72,19 +72,6 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/ /**************************************************************/
static inline unsigned long cpu2cpm_addr(void *addr)
{
if ((unsigned long)addr >= CPM_ADDR)
return (unsigned long)addr;
return virt_to_bus(addr);
}
static inline void *cpm2cpu_addr(unsigned long addr)
{
if (addr >= CPM_ADDR)
return (void *)addr;
return bus_to_virt(addr);
}
/* Place-holder for board-specific stuff */ /* Place-holder for board-specific stuff */
struct platform_device* __attribute__ ((weak)) __init struct platform_device* __attribute__ ((weak)) __init
...@@ -290,7 +277,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) ...@@ -290,7 +277,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
} }
/* get pointer */ /* get pointer */
cp = cpm2cpu_addr(bdp->cbd_bufaddr); cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
/* loop through the buffer */ /* loop through the buffer */
while (i-- > 0) { while (i-- > 0) {
...@@ -633,7 +620,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) ...@@ -633,7 +620,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */ /* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur; bdp = pinfo->tx_cur;
p = cpm2cpu_addr(bdp->cbd_bufaddr); p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*p++ = port->x_char; *p++ = port->x_char;
bdp->cbd_datlen = 1; bdp->cbd_datlen = 1;
...@@ -660,7 +647,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) ...@@ -660,7 +647,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
count = 0; count = 0;
p = cpm2cpu_addr(bdp->cbd_bufaddr); p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
while (count < pinfo->tx_fifosize) { while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail]; *p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
...@@ -709,12 +696,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) ...@@ -709,12 +696,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr; mem_addr = pinfo->mem_addr;
bdp = pinfo->rx_cur = pinfo->rx_bd_base; bdp = pinfo->rx_cur = pinfo->rx_bd_base;
for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
mem_addr += pinfo->rx_fifosize; mem_addr += pinfo->rx_fifosize;
} }
bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
/* Set the physical address of the host memory /* Set the physical address of the host memory
...@@ -724,12 +711,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) ...@@ -724,12 +711,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
bdp = pinfo->tx_cur = pinfo->tx_bd_base; bdp = pinfo->tx_cur = pinfo->tx_bd_base;
for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_INTRPT; bdp->cbd_sc = BD_SC_INTRPT;
mem_addr += pinfo->tx_fifosize; mem_addr += pinfo->tx_fifosize;
} }
bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
} }
...@@ -1099,7 +1086,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, ...@@ -1099,7 +1086,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* If the buffer address is in the CPM DPRAM, don't * If the buffer address is in the CPM DPRAM, don't
* convert it. * convert it.
*/ */
cp = cpm2cpu_addr(bdp->cbd_bufaddr); cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = *s; *cp = *s;
...@@ -1116,7 +1103,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, ...@@ -1116,7 +1103,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
while ((bdp->cbd_sc & BD_SC_READY) != 0) while ((bdp->cbd_sc & BD_SC_READY) != 0)
; ;
cp = cpm2cpu_addr(bdp->cbd_bufaddr); cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = 13; *cp = 13;
bdp->cbd_datlen = 1; bdp->cbd_datlen = 1;
......
...@@ -144,7 +144,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) ...@@ -144,7 +144,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */ /* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */ /* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
dma_addr = 0; dma_addr = (u32)mem_addr;
} else } else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL); GFP_KERNEL);
...@@ -157,8 +157,9 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) ...@@ -157,8 +157,9 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
} }
pinfo->dp_addr = dp_offset; pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr; pinfo->mem_addr = mem_addr; /* virtual address*/
pinfo->dma_addr = dma_addr; pinfo->dma_addr = dma_addr; /* physical address*/
pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr; pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
......
...@@ -209,8 +209,10 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) ...@@ -209,8 +209,10 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con) if (is_con) {
mem_addr = alloc_bootmem(memsz); mem_addr = alloc_bootmem(memsz);
dma_addr = mem_addr;
}
else else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL); GFP_KERNEL);
...@@ -225,6 +227,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) ...@@ -225,6 +227,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->dp_addr = dp_offset; pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr; pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr; pinfo->dma_addr = dma_addr;
pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr; pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment