[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: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Vitaly Bordug and committed by
Paul Mackerras
09b03b6c 4427d6bf

+50 -26
+33
drivers/serial/cpm_uart/cpm_uart.h
··· 66 66 uint dp_addr; 67 67 void *mem_addr; 68 68 dma_addr_t dma_addr; 69 + u32 mem_size; 69 70 /* helpers */ 70 71 int baud; 71 72 int bits; ··· 92 91 void scc2_lineif(struct uart_cpm_port *pinfo); 93 92 void scc3_lineif(struct uart_cpm_port *pinfo); 94 93 void scc4_lineif(struct uart_cpm_port *pinfo); 94 + 95 + /* 96 + virtual to phys transtalion 97 + */ 98 + static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo) 99 + { 100 + int offset; 101 + u32 val = (u32)addr; 102 + /* sane check */ 103 + if ((val >= (u32)pinfo->mem_addr) && 104 + (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { 105 + offset = val - (u32)pinfo->mem_addr; 106 + return pinfo->dma_addr+offset; 107 + } 108 + printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); 109 + return 0; 110 + } 111 + 112 + static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo) 113 + { 114 + int offset; 115 + u32 val = addr; 116 + /* sane check */ 117 + if ((val >= pinfo->dma_addr) && 118 + (val<(pinfo->dma_addr + pinfo->mem_size))) { 119 + offset = val - (u32)pinfo->dma_addr; 120 + return (void*)(pinfo->mem_addr+offset); 121 + } 122 + printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); 123 + return 0; 124 + } 125 + 95 126 96 127 #endif /* CPM_UART_H */
+9 -22
drivers/serial/cpm_uart/cpm_uart_core.c
··· 72 72 73 73 /**************************************************************/ 74 74 75 - static inline unsigned long cpu2cpm_addr(void *addr) 76 - { 77 - if ((unsigned long)addr >= CPM_ADDR) 78 - return (unsigned long)addr; 79 - return virt_to_bus(addr); 80 - } 81 - 82 - static inline void *cpm2cpu_addr(unsigned long addr) 83 - { 84 - if (addr >= CPM_ADDR) 85 - return (void *)addr; 86 - return bus_to_virt(addr); 87 - } 88 75 89 76 /* Place-holder for board-specific stuff */ 90 77 struct platform_device* __attribute__ ((weak)) __init ··· 277 290 } 278 291 279 292 /* get pointer */ 280 - cp = cpm2cpu_addr(bdp->cbd_bufaddr); 293 + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); 281 294 282 295 /* loop through the buffer */ 283 296 while (i-- > 0) { ··· 620 633 /* Pick next descriptor and fill from buffer */ 621 634 bdp = pinfo->tx_cur; 622 635 623 - p = cpm2cpu_addr(bdp->cbd_bufaddr); 636 + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); 624 637 625 638 *p++ = port->x_char; 626 639 bdp->cbd_datlen = 1; ··· 647 660 648 661 while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { 649 662 count = 0; 650 - p = cpm2cpu_addr(bdp->cbd_bufaddr); 663 + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); 651 664 while (count < pinfo->tx_fifosize) { 652 665 *p++ = xmit->buf[xmit->tail]; 653 666 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ··· 696 709 mem_addr = pinfo->mem_addr; 697 710 bdp = pinfo->rx_cur = pinfo->rx_bd_base; 698 711 for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { 699 - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); 712 + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); 700 713 bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; 701 714 mem_addr += pinfo->rx_fifosize; 702 715 } 703 716 704 - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); 717 + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); 705 718 bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; 706 719 707 720 /* Set the physical address of the host memory ··· 711 724 mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); 712 725 bdp = pinfo->tx_cur = pinfo->tx_bd_base; 713 726 for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { 714 - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); 727 + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); 715 728 bdp->cbd_sc = BD_SC_INTRPT; 716 729 mem_addr += pinfo->tx_fifosize; 717 730 } 718 731 719 - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); 732 + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); 720 733 bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; 721 734 } 722 735 ··· 1086 1099 * If the buffer address is in the CPM DPRAM, don't 1087 1100 * convert it. 1088 1101 */ 1089 - cp = cpm2cpu_addr(bdp->cbd_bufaddr); 1102 + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); 1090 1103 1091 1104 *cp = *s; 1092 1105 ··· 1103 1116 while ((bdp->cbd_sc & BD_SC_READY) != 0) 1104 1117 ; 1105 1118 1106 - cp = cpm2cpu_addr(bdp->cbd_bufaddr); 1119 + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); 1107 1120 1108 1121 *cp = 13; 1109 1122 bdp->cbd_datlen = 1;
+4 -3
drivers/serial/cpm_uart/cpm_uart_cpm1.c
··· 144 144 /* was hostalloc but changed cause it blows away the */ 145 145 /* large tlb mapping when pinning the kernel area */ 146 146 mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); 147 - dma_addr = 0; 147 + dma_addr = (u32)mem_addr; 148 148 } else 149 149 mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, 150 150 GFP_KERNEL); ··· 157 157 } 158 158 159 159 pinfo->dp_addr = dp_offset; 160 - pinfo->mem_addr = mem_addr; 161 - pinfo->dma_addr = dma_addr; 160 + pinfo->mem_addr = mem_addr; /* virtual address*/ 161 + pinfo->dma_addr = dma_addr; /* physical address*/ 162 + pinfo->mem_size = memsz; 162 163 163 164 pinfo->rx_buf = mem_addr; 164 165 pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+4 -1
drivers/serial/cpm_uart/cpm_uart_cpm2.c
··· 209 209 210 210 memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + 211 211 L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); 212 - if (is_con) 212 + if (is_con) { 213 213 mem_addr = alloc_bootmem(memsz); 214 + dma_addr = mem_addr; 215 + } 214 216 else 215 217 mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, 216 218 GFP_KERNEL); ··· 227 225 pinfo->dp_addr = dp_offset; 228 226 pinfo->mem_addr = mem_addr; 229 227 pinfo->dma_addr = dma_addr; 228 + pinfo->mem_size = memsz; 230 229 231 230 pinfo->rx_buf = mem_addr; 232 231 pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos