void kbasep_8401_workaround_term(kbase_device *kbdev) { kbasep_js_device_data *js_devdata; int i; u16 restored_as; OSK_ASSERT(kbdev); OSK_ASSERT(kbdev->workaround_kctx); js_devdata = &kbdev->js_data; for(i = 0; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++) { osk_kunmap(kbdev->workaround_compute_job_pa[i], kbdev->workaround_compute_job_va[i]); } kbase_phy_pages_free(kbdev, &kbdev->workaround_kctx->pgd_allocator, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa); kbase_destroy_context(kbdev->workaround_kctx); kbdev->workaround_kctx = NULL; /* Free up the workaround address space */ kbdev->nr_hw_address_spaces++; if ( kbdev->nr_user_address_spaces == (kbdev->nr_hw_address_spaces - 1) ) { /* Only update nr_user_address_spaces if it was unchanged - to ensure * HW workarounds that have modified this will still work */ ++(kbdev->nr_user_address_spaces); } OSK_ASSERT( kbdev->nr_user_address_spaces <= kbdev->nr_hw_address_spaces ); /* Recalculate the free address spaces bit-pattern */ restored_as = (1U << kbdev->nr_hw_address_spaces); js_devdata->as_free |= restored_as; }
static base_jd_event_code kbase_dump_cpu_gpu_time(kbase_jd_atom *katom) { kbase_va_region *reg; osk_phy_addr addr; u64 pfn; u32 offset; char *page; struct timespec ts; base_dump_cpu_gpu_counters data; u64 system_time; u64 cycle_counter; mali_addr64 jc = katom->jc; kbase_context *kctx = katom->kctx; u32 hi1, hi2; memset(&data, 0, sizeof(data)); kbase_pm_context_active(kctx->kbdev); /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */ do { hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL); cycle_counter = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL); hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL); cycle_counter |= (((u64)hi1) << 32); } while (hi1 != hi2); /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */ do { hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL); system_time = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_LO), NULL); hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL); system_time |= (((u64)hi1) << 32); } while (hi1 != hi2); /* Record the CPU's idea of current time */ getnstimeofday(&ts); kbase_pm_context_idle(kctx->kbdev); data.sec = ts.tv_sec; data.usec = ts.tv_nsec / 1000; data.system_time = system_time; data.cycle_counter = cycle_counter; pfn = jc >> 12; offset = jc & 0xFFF; if (offset > 0x1000-sizeof(data)) { /* Wouldn't fit in the page */ return BASE_JD_EVENT_JOB_CANCELLED; } reg = kbase_region_tracker_find_region_enclosing_address(kctx, jc); if (!reg) { return BASE_JD_EVENT_JOB_CANCELLED; } if (! (reg->flags & KBASE_REG_GPU_WR) ) { /* Region is not writable by GPU so we won't write to it either */ return BASE_JD_EVENT_JOB_CANCELLED; } if (!reg->phy_pages) { return BASE_JD_EVENT_JOB_CANCELLED; } addr = reg->phy_pages[pfn - reg->start_pfn]; if (!addr) { return BASE_JD_EVENT_JOB_CANCELLED; } page = osk_kmap(addr); if (!page) { return BASE_JD_EVENT_JOB_CANCELLED; } memcpy(page+offset, &data, sizeof(data)); osk_sync_to_cpu(addr+offset, page+offset, sizeof(data)); osk_kunmap(addr, page); return BASE_JD_EVENT_DONE; }
mali_error kbasep_8401_workaround_init(kbase_device *kbdev) { kbase_context *workaround_kctx; u32 count; int i; OSK_ASSERT(kbdev); OSK_ASSERT(kbdev->workaround_kctx == NULL); /* For this workaround we reserve one address space to allow us to * submit a special job independent of other contexts */ kbdev->nr_address_spaces--; workaround_kctx = kbase_create_context(kbdev); if(!workaround_kctx) { return MALI_ERROR_FUNCTION_FAILED; } /* Allocate the pages required to contain the job */ count = kbase_phy_pages_alloc(workaround_kctx->kbdev, &workaround_kctx->pgd_allocator, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa); if(count < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT) { goto page_release; } /* Get virtual address of mapped memory and write a compute job for each page */ for(i = 0; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++) { kbdev->workaround_compute_job_va[i] = osk_kmap(kbdev->workaround_compute_job_pa[i]); if(NULL == kbdev->workaround_compute_job_va[i]) { goto page_free; } /* Generate the compute job data */ kbasep_8401_workaround_update_job_pointers((u32*)kbdev->workaround_compute_job_va[i], i); } /* Insert pages to the gpu mmu. */ kbase_mmu_insert_pages(workaround_kctx, /* vpfn = page number */ (u64)WORKAROUND_PAGE_OFFSET, /* physical address */ kbdev->workaround_compute_job_pa, /* number of pages */ KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, /* flags */ KBASE_REG_CPU_RW|KBASE_REG_GPU_RW); kbdev->workaround_kctx = workaround_kctx; return MALI_ERROR_NONE; page_free: while(i--) { osk_kunmap(kbdev->workaround_compute_job_pa[i], kbdev->workaround_compute_job_va[i]); } page_release: kbase_phy_pages_free(kbdev, &workaround_kctx->pgd_allocator, count, kbdev->workaround_compute_job_pa); kbase_destroy_context(workaround_kctx); return MALI_ERROR_FUNCTION_FAILED; }
mali_error kbasep_8401_workaround_init(kbase_device *kbdev) { kbasep_js_device_data *js_devdata; kbase_context *workaround_kctx; u32 count; int i; u16 as_present_mask; OSK_ASSERT(kbdev); OSK_ASSERT(kbdev->workaround_kctx == NULL); js_devdata = &kbdev->js_data; /* For this workaround we reserve one address space to allow us to * submit a special job independent of other contexts */ --(kbdev->nr_hw_address_spaces); if ( kbdev->nr_user_address_spaces == (kbdev->nr_hw_address_spaces + 1) ) { /* Only update nr_user_address_spaces if it was unchanged - to ensure * HW workarounds that have modified this will still work */ --(kbdev->nr_user_address_spaces); } OSK_ASSERT( kbdev->nr_user_address_spaces <= kbdev->nr_hw_address_spaces ); /* Recalculate the free address spaces bit-pattern */ as_present_mask = (1U << kbdev->nr_hw_address_spaces) - 1; js_devdata->as_free &= as_present_mask; workaround_kctx = kbase_create_context(kbdev); if(!workaround_kctx) { return MALI_ERROR_FUNCTION_FAILED; } /* Allocate the pages required to contain the job */ count = kbase_phy_pages_alloc(workaround_kctx->kbdev, &workaround_kctx->pgd_allocator, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa); if(count < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT) { goto page_release; } /* Get virtual address of mapped memory and write a compute job for each page */ for(i = 0; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++) { kbdev->workaround_compute_job_va[i] = osk_kmap(kbdev->workaround_compute_job_pa[i]); if(NULL == kbdev->workaround_compute_job_va[i]) { goto page_free; } /* Generate the compute job data */ kbasep_8401_workaround_update_job_pointers((u32*)kbdev->workaround_compute_job_va[i], i); } /* Insert pages to the gpu mmu. */ kbase_mmu_insert_pages(workaround_kctx, /* vpfn = page number */ (u64)WORKAROUND_PAGE_OFFSET, /* physical address */ kbdev->workaround_compute_job_pa, /* number of pages */ KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, /* flags */ KBASE_REG_GPU_RD|KBASE_REG_CPU_RD|KBASE_REG_CPU_WR|KBASE_REG_GPU_WR); kbdev->workaround_kctx = workaround_kctx; return MALI_ERROR_NONE; page_free: while(i--) { osk_kunmap(kbdev->workaround_compute_job_pa[i], kbdev->workaround_compute_job_va[i]); } page_release: kbase_phy_pages_free(kbdev, &workaround_kctx->pgd_allocator, count, kbdev->workaround_compute_job_pa); kbase_destroy_context(workaround_kctx); return MALI_ERROR_FUNCTION_FAILED; }
static base_jd_event_code kbase_dump_cpu_gpu_time(kbase_context *kctx, mali_addr64 jc) { kbase_va_region *reg; osk_phy_addr addr; u64 pfn; u32 offset; char *page; osk_timeval tv; base_dump_cpu_gpu_counters data; u64 system_time; u64 cycle_counter; u32 hi1, hi2; OSK_MEMSET(&data, 0, sizeof(data)); /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */ do { hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL); cycle_counter = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL); hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL); cycle_counter |= (((u64)hi1) << 32); } while (hi1 != hi2); /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */ do { hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL); system_time = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_LO), NULL); hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL); system_time |= (((u64)hi1) << 32); } while (hi1 != hi2); /* Record the CPU's idea of current time */ osk_gettimeofday(&tv); data.sec = tv.tv_sec; data.usec = tv.tv_usec; data.system_time = system_time; data.cycle_counter = cycle_counter; pfn = jc >> 12; offset = jc & 0xFFF; if (offset > 0x1000-sizeof(data)) { /* Wouldn't fit in the page */ return BASE_JD_EVENT_JOB_CANCELLED; } reg = kbase_region_lookup(kctx, jc); if (!reg) { return BASE_JD_EVENT_JOB_CANCELLED; } if (! (reg->flags & KBASE_REG_GPU_RW) ) { /* Region is not writable by GPU so we won't write to it either */ return BASE_JD_EVENT_JOB_CANCELLED; } if (!reg->phy_pages) { return BASE_JD_EVENT_JOB_CANCELLED; } addr = reg->phy_pages[pfn - reg->start_pfn]; if (!addr) { return BASE_JD_EVENT_JOB_CANCELLED; } page = osk_kmap(addr); if (!page) { return BASE_JD_EVENT_JOB_CANCELLED; } memcpy(page+offset, &data, sizeof(data)); osk_kunmap(addr, page); return BASE_JD_EVENT_DONE; }