/* * Copyright 2008 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * Copyright 2009 Jerome Glisse. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher * Jerome Glisse */ #include <drm/radeon_drm.h> #include "radeon.h" #include "radeon_trace.h" /* * GPUVM * GPUVM is similar to the legacy gart on older asics, however * rather than there being a single global gart table * for the entire GPU, there are multiple VM page tables active * at any given time. The VM page tables can contain a mix * vram pages and system memory pages and system memory pages * can be mapped as snooped (cached system pages) or unsnooped * (uncached system pages). * Each VM has an ID associated with it and there is a page table * associated with each VMID. When execting a command buffer, * the kernel tells the ring what VMID to use for that command * buffer. VMIDs are allocated dynamically as commands are submitted. * The userspace drivers maintain their own address space and the kernel * sets up their pages tables accordingly when they submit their * command buffers and a VMID is assigned. * Cayman/Trinity support up to 8 active VMs at any given time; * SI supports 16. */ /** * radeon_vm_num_pdes - return the number of page directory entries * * @rdev: radeon_device pointer * * Calculate the number of page directory entries (cayman+). */ static unsigned radeon_vm_num_pdes(struct radeon_device *rdev) { … } /** * radeon_vm_directory_size - returns the size of the page directory in bytes * * @rdev: radeon_device pointer * * Calculate the size of the page directory in bytes (cayman+). */ static unsigned radeon_vm_directory_size(struct radeon_device *rdev) { … } /** * radeon_vm_manager_init - init the vm manager * * @rdev: radeon_device pointer * * Init the vm manager (cayman+). * Returns 0 for success, error for failure. */ int radeon_vm_manager_init(struct radeon_device *rdev) { … } /** * radeon_vm_manager_fini - tear down the vm manager * * @rdev: radeon_device pointer * * Tear down the VM manager (cayman+). */ void radeon_vm_manager_fini(struct radeon_device *rdev) { … } /** * radeon_vm_get_bos - add the vm BOs to a validation list * * @rdev: radeon_device pointer * @vm: vm providing the BOs * @head: head of validation list * * Add the page directory to the list of BOs to * validate for command submission (cayman+). */ struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev, struct radeon_vm *vm, struct list_head *head) { … } /** * radeon_vm_grab_id - allocate the next free VMID * * @rdev: radeon_device pointer * @vm: vm to allocate id for * @ring: ring we want to submit job to * * Allocate an id for the vm (cayman+). * Returns the fence we need to sync to (if any). * * Global and local mutex must be locked! */ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, struct radeon_vm *vm, int ring) { … } /** * radeon_vm_flush - hardware flush the vm * * @rdev: radeon_device pointer * @vm: vm we want to flush * @ring: ring to use for flush * @updates: last vm update that is waited for * * Flush the vm (cayman+). * * Global and local mutex must be locked! */ void radeon_vm_flush(struct radeon_device *rdev, struct radeon_vm *vm, int ring, struct radeon_fence *updates) { … } /** * radeon_vm_fence - remember fence for vm * * @rdev: radeon_device pointer * @vm: vm we want to fence * @fence: fence to remember * * Fence the vm (cayman+). * Set the fence used to protect page table and id. * * Global and local mutex must be locked! */ void radeon_vm_fence(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_fence *fence) { … } /** * radeon_vm_bo_find - find the bo_va for a specific vm & bo * * @vm: requested vm * @bo: requested buffer object * * Find @bo inside the requested vm (cayman+). * Search inside the @bos vm list for the requested vm * Returns the found bo_va or NULL if none is found * * Object has to be reserved! */ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, struct radeon_bo *bo) { … } /** * radeon_vm_bo_add - add a bo to a specific vm * * @rdev: radeon_device pointer * @vm: requested vm * @bo: radeon buffer object * * Add @bo into the requested vm (cayman+). * Add @bo to the list of bos associated with the vm * Returns newly added bo_va or NULL for failure * * Object has to be reserved! */ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo) { … } /** * radeon_vm_set_pages - helper to call the right asic function * * @rdev: radeon_device pointer * @ib: indirect buffer to fill with commands * @pe: addr of the page entry * @addr: dst addr to write into pe * @count: number of page entries to update * @incr: increase next addr by incr bytes * @flags: hw access flags * * Traces the parameters and calls the right asic functions * to setup the page table using the DMA. */ static void radeon_vm_set_pages(struct radeon_device *rdev, struct radeon_ib *ib, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint32_t flags) { … } /** * radeon_vm_clear_bo - initially clear the page dir/table * * @rdev: radeon_device pointer * @bo: bo to clear */ static int radeon_vm_clear_bo(struct radeon_device *rdev, struct radeon_bo *bo) { … } /** * radeon_vm_bo_set_addr - set bos virtual address inside a vm * * @rdev: radeon_device pointer * @bo_va: bo_va to store the address * @soffset: requested offset of the buffer in the VM address space * @flags: attributes of pages (read/write/valid/etc.) * * Set offset of @bo_va (cayman+). * Validate and set the offset requested within the vm address space. * Returns 0 for success, error for failure. * * Object has to be reserved and gets unreserved by this function! */ int radeon_vm_bo_set_addr(struct radeon_device *rdev, struct radeon_bo_va *bo_va, uint64_t soffset, uint32_t flags) { … } /** * radeon_vm_map_gart - get the physical address of a gart page * * @rdev: radeon_device pointer * @addr: the unmapped addr * * Look up the physical address of the page that the pte resolves * to (cayman+). * Returns the physical address of the page. */ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) { … } /** * radeon_vm_page_flags - translate page flags to what the hw uses * * @flags: flags comming from userspace * * Translate the flags the userspace ABI uses to hw flags. */ static uint32_t radeon_vm_page_flags(uint32_t flags) { … } /** * radeon_vm_update_page_directory - make sure that page directory is valid * * @rdev: radeon_device pointer * @vm: requested vm * * Allocates new page tables if necessary * and updates the page directory (cayman+). * Returns 0 for success, error for failure. * * Global and local mutex must be locked! */ int radeon_vm_update_page_directory(struct radeon_device *rdev, struct radeon_vm *vm) { … } /** * radeon_vm_frag_ptes - add fragment information to PTEs * * @rdev: radeon_device pointer * @ib: IB for the update * @pe_start: first PTE to handle * @pe_end: last PTE to handle * @addr: addr those PTEs should point to * @flags: hw mapping flags * * Global and local mutex must be locked! */ static void radeon_vm_frag_ptes(struct radeon_device *rdev, struct radeon_ib *ib, uint64_t pe_start, uint64_t pe_end, uint64_t addr, uint32_t flags) { … } /** * radeon_vm_update_ptes - make sure that page tables are valid * * @rdev: radeon_device pointer * @vm: requested vm * @ib: indirect buffer to use for the update * @start: start of GPU address range * @end: end of GPU address range * @dst: destination address to map to * @flags: mapping flags * * Update the page tables in the range @start - @end (cayman+). * * Global and local mutex must be locked! */ static int radeon_vm_update_ptes(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_ib *ib, uint64_t start, uint64_t end, uint64_t dst, uint32_t flags) { … } /** * radeon_vm_fence_pts - fence page tables after an update * * @vm: requested vm * @start: start of GPU address range * @end: end of GPU address range * @fence: fence to use * * Fence the page tables in the range @start - @end (cayman+). * * Global and local mutex must be locked! */ static void radeon_vm_fence_pts(struct radeon_vm *vm, uint64_t start, uint64_t end, struct radeon_fence *fence) { … } /** * radeon_vm_bo_update - map a bo into the vm page table * * @rdev: radeon_device pointer * @bo_va: radeon buffer virtual address object * @mem: ttm mem * * Fill in the page table entries for @bo (cayman+). * Returns 0 for success, -EINVAL for failure. * * Object have to be reserved and mutex must be locked! */ int radeon_vm_bo_update(struct radeon_device *rdev, struct radeon_bo_va *bo_va, struct ttm_resource *mem) { … } /** * radeon_vm_clear_freed - clear freed BOs in the PT * * @rdev: radeon_device pointer * @vm: requested vm * * Make sure all freed BOs are cleared in the PT. * Returns 0 for success. * * PTs have to be reserved and mutex must be locked! */ int radeon_vm_clear_freed(struct radeon_device *rdev, struct radeon_vm *vm) { … } /** * radeon_vm_clear_invalids - clear invalidated BOs in the PT * * @rdev: radeon_device pointer * @vm: requested vm * * Make sure all invalidated BOs are cleared in the PT. * Returns 0 for success. * * PTs have to be reserved and mutex must be locked! */ int radeon_vm_clear_invalids(struct radeon_device *rdev, struct radeon_vm *vm) { … } /** * radeon_vm_bo_rmv - remove a bo to a specific vm * * @rdev: radeon_device pointer * @bo_va: requested bo_va * * Remove @bo_va->bo from the requested vm (cayman+). * * Object have to be reserved! */ void radeon_vm_bo_rmv(struct radeon_device *rdev, struct radeon_bo_va *bo_va) { … } /** * radeon_vm_bo_invalidate - mark the bo as invalid * * @rdev: radeon_device pointer * @bo: radeon buffer object * * Mark @bo as invalid (cayman+). */ void radeon_vm_bo_invalidate(struct radeon_device *rdev, struct radeon_bo *bo) { … } /** * radeon_vm_init - initialize a vm instance * * @rdev: radeon_device pointer * @vm: requested vm * * Init @vm fields (cayman+). */ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) { … } /** * radeon_vm_fini - tear down a vm instance * * @rdev: radeon_device pointer * @vm: requested vm * * Tear down @vm (cayman+). * Unbind the VM and remove all bos from the vm bo list */ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) { … }