Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Revert "staging: tidspbridge - remove custom mmu code from tiomap3430.c"

This reverts commit e7396e77d9e4230bf725b5807732cbca191d111f.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Omar Ramirez Luna <omar.ramirez@ti.com>

authored by

Felipe Contreras and committed by
Omar Ramirez Luna
ac8a139a 6c4c899e

+427
+2
drivers/staging/tidspbridge/core/_tiomap.h
··· 330 330 */ 331 331 u32 dw_dsp_ext_base_addr; /* See the comment above */ 332 332 u32 dw_api_reg_base; /* API mem map'd registers */ 333 + void __iomem *dw_dsp_mmu_base; /* DSP MMU Mapped registers */ 333 334 u32 dw_api_clk_base; /* CLK Registers */ 334 335 u32 dw_dsp_clk_m2_base; /* DSP Clock Module m2 */ 335 336 u32 dw_public_rhea; /* Pub Rhea */ ··· 356 355 357 356 /* TC Settings */ 358 357 bool tc_word_swap_on; /* Traffic Controller Word Swap */ 358 + struct pg_table_attrs *pt_attrs; 359 359 u32 dsp_per_clks; 360 360 }; 361 361
+425
drivers/staging/tidspbridge/core/tiomap3430.c
··· 116 116 static int bridge_dev_ctrl(struct bridge_dev_context *dev_context, 117 117 u32 dw_cmd, void *pargs); 118 118 static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt); 119 + static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa, 120 + u32 va, u32 size, 121 + struct hw_mmu_map_attrs_t *map_attrs); 122 + static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va, 123 + u32 size, struct hw_mmu_map_attrs_t *attrs); 124 + static int mem_map_vmalloc(struct bridge_dev_context *dev_context, 125 + u32 ul_mpu_addr, u32 virt_addr, 126 + u32 ul_num_bytes, 127 + struct hw_mmu_map_attrs_t *hw_attrs); 128 + 119 129 bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr); 130 + 131 + /* ----------------------------------- Globals */ 132 + 133 + /* Attributes of L2 page tables for DSP MMU */ 134 + struct page_info { 135 + u32 num_entries; /* Number of valid PTEs in the L2 PT */ 136 + }; 137 + 138 + /* Attributes used to manage the DSP MMU page tables */ 139 + struct pg_table_attrs { 140 + spinlock_t pg_lock; /* Critical section object handle */ 141 + 142 + u32 l1_base_pa; /* Physical address of the L1 PT */ 143 + u32 l1_base_va; /* Virtual address of the L1 PT */ 144 + u32 l1_size; /* Size of the L1 PT */ 145 + u32 l1_tbl_alloc_pa; 146 + /* Physical address of Allocated mem for L1 table. May not be aligned */ 147 + u32 l1_tbl_alloc_va; 148 + /* Virtual address of Allocated mem for L1 table. May not be aligned */ 149 + u32 l1_tbl_alloc_sz; 150 + /* Size of consistent memory allocated for L1 table. 151 + * May not be aligned */ 152 + 153 + u32 l2_base_pa; /* Physical address of the L2 PT */ 154 + u32 l2_base_va; /* Virtual address of the L2 PT */ 155 + u32 l2_size; /* Size of the L2 PT */ 156 + u32 l2_tbl_alloc_pa; 157 + /* Physical address of Allocated mem for L2 table. May not be aligned */ 158 + u32 l2_tbl_alloc_va; 159 + /* Virtual address of Allocated mem for L2 table. May not be aligned */ 160 + u32 l2_tbl_alloc_sz; 161 + /* Size of consistent memory allocated for L2 table. 162 + * May not be aligned */ 163 + 164 + u32 l2_num_pages; /* Number of allocated L2 PT */ 165 + /* Array [l2_num_pages] of L2 PT info structs */ 166 + struct page_info *pg_info; 167 + }; 120 168 121 169 /* 122 170 * This Bridge driver's function interface table. ··· 213 165 bridge_msg_register_notify, 214 166 bridge_msg_set_queue_id, 215 167 }; 168 + 169 + static inline void flush_all(struct bridge_dev_context *dev_context) 170 + { 171 + if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION || 172 + dev_context->dw_brd_state == BRD_HIBERNATION) 173 + wake_dsp(dev_context, NULL); 174 + 175 + hw_mmu_tlb_flush_all(dev_context->dw_dsp_mmu_base); 176 + } 177 + 178 + static void bad_page_dump(u32 pa, struct page *pg) 179 + { 180 + pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa); 181 + pr_emerg("Bad page state in process '%s'\n" 182 + "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n" 183 + "Backtrace:\n", 184 + current->comm, pg, (int)(2 * sizeof(unsigned long)), 185 + (unsigned long)pg->flags, pg->mapping, 186 + page_mapcount(pg), page_count(pg)); 187 + dump_stack(); 188 + } 216 189 217 190 /* 218 191 * ======== bridge_drv_entry ======== ··· 640 571 { 641 572 int status = 0; 642 573 struct bridge_dev_context *dev_context = dev_ctxt; 574 + struct pg_table_attrs *pt_attrs; 643 575 u32 dsp_pwr_state; 644 576 int i; 645 577 struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry; ··· 679 609 680 610 dsp_wdt_enable(false); 681 611 612 + /* This is a good place to clear the MMU page tables as well */ 613 + if (dev_context->pt_attrs) { 614 + pt_attrs = dev_context->pt_attrs; 615 + memset((u8 *) pt_attrs->l1_base_va, 0x00, pt_attrs->l1_size); 616 + memset((u8 *) pt_attrs->l2_base_va, 0x00, pt_attrs->l2_size); 617 + memset((u8 *) pt_attrs->pg_info, 0x00, 618 + (pt_attrs->l2_num_pages * sizeof(struct page_info))); 619 + } 682 620 /* Reset DSP */ 683 621 (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 684 622 OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); ··· 777 699 struct bridge_dev_context *dev_context = NULL; 778 700 s32 entry_ndx; 779 701 struct cfg_hostres *resources = config_param; 702 + struct pg_table_attrs *pt_attrs; 703 + u32 pg_tbl_pa; 704 + u32 pg_tbl_va; 705 + u32 align_size; 780 706 struct drv_data *drv_datap = dev_get_drvdata(bridge); 781 707 782 708 /* Allocate and initialize a data structure to contain the bridge driver ··· 811 729 if (!dev_context->dw_dsp_base_addr) 812 730 status = -EPERM; 813 731 732 + pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL); 733 + if (pt_attrs != NULL) { 734 + /* Assuming that we use only DSP's memory map 735 + * until 0x4000:0000 , we would need only 1024 736 + * L1 enties i.e L1 size = 4K */ 737 + pt_attrs->l1_size = 0x1000; 738 + align_size = pt_attrs->l1_size; 739 + /* Align sizes are expected to be power of 2 */ 740 + /* we like to get aligned on L1 table size */ 741 + pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l1_size, 742 + align_size, &pg_tbl_pa); 743 + 744 + /* Check if the PA is aligned for us */ 745 + if ((pg_tbl_pa) & (align_size - 1)) { 746 + /* PA not aligned to page table size , 747 + * try with more allocation and align */ 748 + mem_free_phys_mem((void *)pg_tbl_va, pg_tbl_pa, 749 + pt_attrs->l1_size); 750 + /* we like to get aligned on L1 table size */ 751 + pg_tbl_va = 752 + (u32) mem_alloc_phys_mem((pt_attrs->l1_size) * 2, 753 + align_size, &pg_tbl_pa); 754 + /* We should be able to get aligned table now */ 755 + pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa; 756 + pt_attrs->l1_tbl_alloc_va = pg_tbl_va; 757 + pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size * 2; 758 + /* Align the PA to the next 'align' boundary */ 759 + pt_attrs->l1_base_pa = 760 + ((pg_tbl_pa) + 761 + (align_size - 1)) & (~(align_size - 1)); 762 + pt_attrs->l1_base_va = 763 + pg_tbl_va + (pt_attrs->l1_base_pa - pg_tbl_pa); 764 + } else { 765 + /* We got aligned PA, cool */ 766 + pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa; 767 + pt_attrs->l1_tbl_alloc_va = pg_tbl_va; 768 + pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size; 769 + pt_attrs->l1_base_pa = pg_tbl_pa; 770 + pt_attrs->l1_base_va = pg_tbl_va; 771 + } 772 + if (pt_attrs->l1_base_va) 773 + memset((u8 *) pt_attrs->l1_base_va, 0x00, 774 + pt_attrs->l1_size); 775 + 776 + /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM + 777 + * L4 pages */ 778 + pt_attrs->l2_num_pages = ((DMMPOOLSIZE >> 20) + 6); 779 + pt_attrs->l2_size = HW_MMU_COARSE_PAGE_SIZE * 780 + pt_attrs->l2_num_pages; 781 + align_size = 4; /* Make it u32 aligned */ 782 + /* we like to get aligned on L1 table size */ 783 + pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l2_size, 784 + align_size, &pg_tbl_pa); 785 + pt_attrs->l2_tbl_alloc_pa = pg_tbl_pa; 786 + pt_attrs->l2_tbl_alloc_va = pg_tbl_va; 787 + pt_attrs->l2_tbl_alloc_sz = pt_attrs->l2_size; 788 + pt_attrs->l2_base_pa = pg_tbl_pa; 789 + pt_attrs->l2_base_va = pg_tbl_va; 790 + 791 + if (pt_attrs->l2_base_va) 792 + memset((u8 *) pt_attrs->l2_base_va, 0x00, 793 + pt_attrs->l2_size); 794 + 795 + pt_attrs->pg_info = kzalloc(pt_attrs->l2_num_pages * 796 + sizeof(struct page_info), GFP_KERNEL); 797 + dev_dbg(bridge, 798 + "L1 pa %x, va %x, size %x\n L2 pa %x, va " 799 + "%x, size %x\n", pt_attrs->l1_base_pa, 800 + pt_attrs->l1_base_va, pt_attrs->l1_size, 801 + pt_attrs->l2_base_pa, pt_attrs->l2_base_va, 802 + pt_attrs->l2_size); 803 + dev_dbg(bridge, "pt_attrs %p L2 NumPages %x pg_info %p\n", 804 + pt_attrs, pt_attrs->l2_num_pages, pt_attrs->pg_info); 805 + } 806 + if ((pt_attrs != NULL) && (pt_attrs->l1_base_va != 0) && 807 + (pt_attrs->l2_base_va != 0) && (pt_attrs->pg_info != NULL)) 808 + dev_context->pt_attrs = pt_attrs; 809 + else 810 + status = -ENOMEM; 811 + 814 812 if (!status) { 813 + spin_lock_init(&pt_attrs->pg_lock); 815 814 dev_context->tc_word_swap_on = drv_datap->tc_wordswapon; 815 + 816 + /* Set the Clock Divisor for the DSP module */ 817 + udelay(5); 818 + /* MMU address is obtained from the host 819 + * resources struct */ 820 + dev_context->dw_dsp_mmu_base = resources->dw_dmmu_base; 821 + } 822 + if (!status) { 816 823 dev_context->hdev_obj = hdev_obj; 817 824 /* Store current board state. */ 818 825 dev_context->dw_brd_state = BRD_UNKNOWN; ··· 911 740 /* Return ptr to our device state to the DSP API for storage */ 912 741 *dev_cntxt = dev_context; 913 742 } else { 743 + if (pt_attrs != NULL) { 744 + kfree(pt_attrs->pg_info); 745 + 746 + if (pt_attrs->l2_tbl_alloc_va) { 747 + mem_free_phys_mem((void *) 748 + pt_attrs->l2_tbl_alloc_va, 749 + pt_attrs->l2_tbl_alloc_pa, 750 + pt_attrs->l2_tbl_alloc_sz); 751 + } 752 + if (pt_attrs->l1_tbl_alloc_va) { 753 + mem_free_phys_mem((void *) 754 + pt_attrs->l1_tbl_alloc_va, 755 + pt_attrs->l1_tbl_alloc_pa, 756 + pt_attrs->l1_tbl_alloc_sz); 757 + } 758 + } 759 + kfree(pt_attrs); 914 760 kfree(dev_context); 915 761 } 916 762 func_end: ··· 995 807 */ 996 808 static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt) 997 809 { 810 + struct pg_table_attrs *pt_attrs; 998 811 int status = 0; 999 812 struct bridge_dev_context *dev_context = (struct bridge_dev_context *) 1000 813 dev_ctxt; ··· 1009 820 1010 821 /* first put the device to stop state */ 1011 822 bridge_brd_stop(dev_context); 823 + if (dev_context->pt_attrs) { 824 + pt_attrs = dev_context->pt_attrs; 825 + kfree(pt_attrs->pg_info); 826 + 827 + if (pt_attrs->l2_tbl_alloc_va) { 828 + mem_free_phys_mem((void *)pt_attrs->l2_tbl_alloc_va, 829 + pt_attrs->l2_tbl_alloc_pa, 830 + pt_attrs->l2_tbl_alloc_sz); 831 + } 832 + if (pt_attrs->l1_tbl_alloc_va) { 833 + mem_free_phys_mem((void *)pt_attrs->l1_tbl_alloc_va, 834 + pt_attrs->l1_tbl_alloc_pa, 835 + pt_attrs->l1_tbl_alloc_sz); 836 + } 837 + kfree(pt_attrs); 838 + 839 + } 1012 840 1013 841 if (dev_context->resources) { 1014 842 host_res = dev_context->resources; ··· 1319 1113 kfree(sgt); 1320 1114 1321 1115 return 0; 1116 + } 1117 + 1118 + /* 1119 + * ======== pte_update ======== 1120 + * This function calculates the optimum page-aligned addresses and sizes 1121 + * Caller must pass page-aligned values 1122 + */ 1123 + static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa, 1124 + u32 va, u32 size, 1125 + struct hw_mmu_map_attrs_t *map_attrs) 1126 + { 1127 + u32 i; 1128 + u32 all_bits; 1129 + u32 pa_curr = pa; 1130 + u32 va_curr = va; 1131 + u32 num_bytes = size; 1132 + struct bridge_dev_context *dev_context = dev_ctxt; 1133 + int status = 0; 1134 + u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB, 1135 + HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB 1136 + }; 1137 + 1138 + while (num_bytes && !status) { 1139 + /* To find the max. page size with which both PA & VA are 1140 + * aligned */ 1141 + all_bits = pa_curr | va_curr; 1142 + 1143 + for (i = 0; i < 4; i++) { 1144 + if ((num_bytes >= page_size[i]) && ((all_bits & 1145 + (page_size[i] - 1146 + 1)) == 0)) { 1147 + status = 1148 + pte_set(dev_context->pt_attrs, pa_curr, 1149 + va_curr, page_size[i], map_attrs); 1150 + pa_curr += page_size[i]; 1151 + va_curr += page_size[i]; 1152 + num_bytes -= page_size[i]; 1153 + /* Don't try smaller sizes. Hopefully we have 1154 + * reached an address aligned to a bigger page 1155 + * size */ 1156 + break; 1157 + } 1158 + } 1159 + } 1160 + 1161 + return status; 1162 + } 1163 + 1164 + /* 1165 + * ======== pte_set ======== 1166 + * This function calculates PTE address (MPU virtual) to be updated 1167 + * It also manages the L2 page tables 1168 + */ 1169 + static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va, 1170 + u32 size, struct hw_mmu_map_attrs_t *attrs) 1171 + { 1172 + u32 i; 1173 + u32 pte_val; 1174 + u32 pte_addr_l1; 1175 + u32 pte_size; 1176 + /* Base address of the PT that will be updated */ 1177 + u32 pg_tbl_va; 1178 + u32 l1_base_va; 1179 + /* Compiler warns that the next three variables might be used 1180 + * uninitialized in this function. Doesn't seem so. Working around, 1181 + * anyways. */ 1182 + u32 l2_base_va = 0; 1183 + u32 l2_base_pa = 0; 1184 + u32 l2_page_num = 0; 1185 + int status = 0; 1186 + 1187 + l1_base_va = pt->l1_base_va; 1188 + pg_tbl_va = l1_base_va; 1189 + if ((size == HW_PAGE_SIZE64KB) || (size == HW_PAGE_SIZE4KB)) { 1190 + /* Find whether the L1 PTE points to a valid L2 PT */ 1191 + pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va); 1192 + if (pte_addr_l1 <= (pt->l1_base_va + pt->l1_size)) { 1193 + pte_val = *(u32 *) pte_addr_l1; 1194 + pte_size = hw_mmu_pte_size_l1(pte_val); 1195 + } else { 1196 + return -EPERM; 1197 + } 1198 + spin_lock(&pt->pg_lock); 1199 + if (pte_size == HW_MMU_COARSE_PAGE_SIZE) { 1200 + /* Get the L2 PA from the L1 PTE, and find 1201 + * corresponding L2 VA */ 1202 + l2_base_pa = hw_mmu_pte_coarse_l1(pte_val); 1203 + l2_base_va = 1204 + l2_base_pa - pt->l2_base_pa + pt->l2_base_va; 1205 + l2_page_num = 1206 + (l2_base_pa - 1207 + pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE; 1208 + } else if (pte_size == 0) { 1209 + /* L1 PTE is invalid. Allocate a L2 PT and 1210 + * point the L1 PTE to it */ 1211 + /* Find a free L2 PT. */ 1212 + for (i = 0; (i < pt->l2_num_pages) && 1213 + (pt->pg_info[i].num_entries != 0); i++) 1214 + ;; 1215 + if (i < pt->l2_num_pages) { 1216 + l2_page_num = i; 1217 + l2_base_pa = pt->l2_base_pa + (l2_page_num * 1218 + HW_MMU_COARSE_PAGE_SIZE); 1219 + l2_base_va = pt->l2_base_va + (l2_page_num * 1220 + HW_MMU_COARSE_PAGE_SIZE); 1221 + /* Endianness attributes are ignored for 1222 + * HW_MMU_COARSE_PAGE_SIZE */ 1223 + status = 1224 + hw_mmu_pte_set(l1_base_va, l2_base_pa, va, 1225 + HW_MMU_COARSE_PAGE_SIZE, 1226 + attrs); 1227 + } else { 1228 + status = -ENOMEM; 1229 + } 1230 + } else { 1231 + /* Found valid L1 PTE of another size. 1232 + * Should not overwrite it. */ 1233 + status = -EPERM; 1234 + } 1235 + if (!status) { 1236 + pg_tbl_va = l2_base_va; 1237 + if (size == HW_PAGE_SIZE64KB) 1238 + pt->pg_info[l2_page_num].num_entries += 16; 1239 + else 1240 + pt->pg_info[l2_page_num].num_entries++; 1241 + dev_dbg(bridge, "PTE: L2 BaseVa %x, BasePa %x, PageNum " 1242 + "%x, num_entries %x\n", l2_base_va, 1243 + l2_base_pa, l2_page_num, 1244 + pt->pg_info[l2_page_num].num_entries); 1245 + } 1246 + spin_unlock(&pt->pg_lock); 1247 + } 1248 + if (!status) { 1249 + dev_dbg(bridge, "PTE: pg_tbl_va %x, pa %x, va %x, size %x\n", 1250 + pg_tbl_va, pa, va, size); 1251 + dev_dbg(bridge, "PTE: endianism %x, element_size %x, " 1252 + "mixed_size %x\n", attrs->endianism, 1253 + attrs->element_size, attrs->mixed_size); 1254 + status = hw_mmu_pte_set(pg_tbl_va, pa, va, size, attrs); 1255 + } 1256 + 1257 + return status; 1258 + } 1259 + 1260 + /* Memory map kernel VA -- memory allocated with vmalloc */ 1261 + static int mem_map_vmalloc(struct bridge_dev_context *dev_context, 1262 + u32 ul_mpu_addr, u32 virt_addr, 1263 + u32 ul_num_bytes, 1264 + struct hw_mmu_map_attrs_t *hw_attrs) 1265 + { 1266 + int status = 0; 1267 + struct page *page[1]; 1268 + u32 i; 1269 + u32 pa_curr; 1270 + u32 pa_next; 1271 + u32 va_curr; 1272 + u32 size_curr; 1273 + u32 num_pages; 1274 + u32 pa; 1275 + u32 num_of4k_pages; 1276 + u32 temp = 0; 1277 + 1278 + /* 1279 + * Do Kernel va to pa translation. 1280 + * Combine physically contiguous regions to reduce TLBs. 1281 + * Pass the translated pa to pte_update. 1282 + */ 1283 + num_pages = ul_num_bytes / PAGE_SIZE; /* PAGE_SIZE = OS page size */ 1284 + i = 0; 1285 + va_curr = ul_mpu_addr; 1286 + page[0] = vmalloc_to_page((void *)va_curr); 1287 + pa_next = page_to_phys(page[0]); 1288 + while (!status && (i < num_pages)) { 1289 + /* 1290 + * Reuse pa_next from the previous iteraion to avoid 1291 + * an extra va2pa call 1292 + */ 1293 + pa_curr = pa_next; 1294 + size_curr = PAGE_SIZE; 1295 + /* 1296 + * If the next page is physically contiguous, 1297 + * map it with the current one by increasing 1298 + * the size of the region to be mapped 1299 + */ 1300 + while (++i < num_pages) { 1301 + page[0] = 1302 + vmalloc_to_page((void *)(va_curr + size_curr)); 1303 + pa_next = page_to_phys(page[0]); 1304 + 1305 + if (pa_next == (pa_curr + size_curr)) 1306 + size_curr += PAGE_SIZE; 1307 + else 1308 + break; 1309 + 1310 + } 1311 + if (pa_next == 0) { 1312 + status = -ENOMEM; 1313 + break; 1314 + } 1315 + pa = pa_curr; 1316 + num_of4k_pages = size_curr / HW_PAGE_SIZE4KB; 1317 + while (temp++ < num_of4k_pages) { 1318 + get_page(PHYS_TO_PAGE(pa)); 1319 + pa += HW_PAGE_SIZE4KB; 1320 + } 1321 + status = pte_update(dev_context, pa_curr, virt_addr + 1322 + (va_curr - ul_mpu_addr), size_curr, 1323 + hw_attrs); 1324 + va_curr += size_curr; 1325 + } 1326 + /* 1327 + * In any case, flush the TLB 1328 + * This is called from here instead from pte_update to avoid unnecessary 1329 + * repetition while mapping non-contiguous physical regions of a virtual 1330 + * region 1331 + */ 1332 + flush_all(dev_context); 1333 + dev_dbg(bridge, "%s status %x\n", __func__, status); 1334 + return status; 1322 1335 } 1323 1336 1324 1337 /*