Merge branch 'drm-next-4.3' of git://people.freedesktop.org/~agd5f/linux into drm-next
amdgpu and radeon changes for 4.3. Highlights: - Fiji support for amdgpu. - CGS support for amdgpu. This is a new driver internal cross-component API. - Initial GPU scheduler for amdgpu. Still disabled by default. - Lots of bug fixes and optimizations * 'drm-next-4.3' of git://people.freedesktop.org/~agd5f/linux: (130 commits) drm/amdgpu: wait on page directory changes. v2 drm/amdgpu: Select BACKLIGHT_LCD_SUPPORT drm/radeon: Select BACKLIGHT_LCD_SUPPORT drm/amdgpu: cleanup sheduler rq handling v2 drm/amdgpu: move prepare work out of scheduler to cs_ioctl drm/amdgpu: fix unnecessary wake up drm/amdgpu: fix duplicated mapping invoke bug drm/amdgpu: drop bo_list_clone when no scheduler drm/amdgpu: disable GPU reset by default drm/amdgpu: fix type mismatch error drm/amdgpu: add reference for **fence drm/amdgpu: fix waiting for all fences before flipping drm/amdgpu: fix UVD return code checking drm/amdgpu: remove scheduler fence list v2 drm/amdgpu: remove amd_sched_wait_emit v2 drm/amdgpu: remove unecessary scheduler fence callbacks drm/amdgpu: fix scheduler fence implementation drm/amdgpu: don't grab dev->struct_mutex in pm functions drm/amdgpu: Don't take dev->struct_mutex in bo_force_delete drm/radeon: Don't take dev->struct_mutex in pm functions ...
This commit is contained in:
commit
e2a8986f3e
|
@ -128,6 +128,7 @@ config DRM_RADEON
|
|||
select POWER_SUPPLY
|
||||
select HWMON
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select INTERVAL_TREE
|
||||
help
|
||||
Choose this option if you have an ATI Radeon graphics card. There
|
||||
|
@ -151,6 +152,7 @@ config DRM_AMDGPU
|
|||
select POWER_SUPPLY
|
||||
select HWMON
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select INTERVAL_TREE
|
||||
help
|
||||
Choose this option if you have a recent AMD Radeon graphics card.
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/asic_reg \
|
||||
-Idrivers/gpu/drm/amd/include
|
||||
-Idrivers/gpu/drm/amd/include \
|
||||
-Idrivers/gpu/drm/amd/amdgpu \
|
||||
-Idrivers/gpu/drm/amd/scheduler
|
||||
|
||||
amdgpu-y := amdgpu_drv.o
|
||||
|
||||
|
@ -21,7 +23,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
|||
|
||||
# add asic specific block
|
||||
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o gmc_v7_0.o cik_ih.o kv_smc.o kv_dpm.o \
|
||||
ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o
|
||||
ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o \
|
||||
amdgpu_amdkfd_gfx_v7.o
|
||||
|
||||
amdgpu-y += \
|
||||
vi.o
|
||||
|
@ -43,6 +46,7 @@ amdgpu-y += \
|
|||
amdgpu_dpm.o \
|
||||
cz_smc.o cz_dpm.o \
|
||||
tonga_smc.o tonga_dpm.o \
|
||||
fiji_smc.o fiji_dpm.o \
|
||||
iceland_smc.o iceland_dpm.o
|
||||
|
||||
# add DCE block
|
||||
|
@ -74,9 +78,17 @@ amdgpu-y += \
|
|||
# add amdkfd interfaces
|
||||
amdgpu-y += \
|
||||
amdgpu_amdkfd.o \
|
||||
amdgpu_amdkfd_gfx_v7.o \
|
||||
amdgpu_amdkfd_gfx_v8.o
|
||||
|
||||
# add cgs
|
||||
amdgpu-y += amdgpu_cgs.o
|
||||
|
||||
# GPU scheduler
|
||||
amdgpu-y += \
|
||||
../scheduler/gpu_scheduler.o \
|
||||
../scheduler/sched_fence.o \
|
||||
amdgpu_sched.o
|
||||
|
||||
amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o
|
||||
amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
|
||||
amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
|
||||
|
|
|
@ -42,17 +42,19 @@
|
|||
#include <ttm/ttm_module.h>
|
||||
#include <ttm/ttm_execbuf_util.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
|
||||
#include "amd_shared.h"
|
||||
#include "amdgpu_family.h"
|
||||
#include "amdgpu_mode.h"
|
||||
#include "amdgpu_ih.h"
|
||||
#include "amdgpu_irq.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
#include "amdgpu_gds.h"
|
||||
|
||||
#include "gpu_scheduler.h"
|
||||
|
||||
/*
|
||||
* Modules parameters.
|
||||
*/
|
||||
|
@ -77,7 +79,11 @@ extern int amdgpu_bapm;
|
|||
extern int amdgpu_deep_color;
|
||||
extern int amdgpu_vm_size;
|
||||
extern int amdgpu_vm_block_size;
|
||||
extern int amdgpu_enable_scheduler;
|
||||
extern int amdgpu_sched_jobs;
|
||||
extern int amdgpu_sched_hw_submission;
|
||||
|
||||
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
|
||||
#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||
#define AMDGPU_FENCE_JIFFIES_TIMEOUT (HZ / 2)
|
||||
/* AMDGPU_IB_POOL_SIZE must be a power of 2 */
|
||||
|
@ -178,6 +184,7 @@ struct amdgpu_ring;
|
|||
struct amdgpu_semaphore;
|
||||
struct amdgpu_cs_parser;
|
||||
struct amdgpu_irq_src;
|
||||
struct amdgpu_fpriv;
|
||||
|
||||
enum amdgpu_cp_irq {
|
||||
AMDGPU_CP_IRQ_GFX_EOP = 0,
|
||||
|
@ -381,10 +388,10 @@ struct amdgpu_fence_driver {
|
|||
uint64_t sync_seq[AMDGPU_MAX_RINGS];
|
||||
atomic64_t last_seq;
|
||||
bool initialized;
|
||||
bool delayed_irq;
|
||||
struct amdgpu_irq_src *irq_src;
|
||||
unsigned irq_type;
|
||||
struct delayed_work lockup_work;
|
||||
wait_queue_head_t fence_queue;
|
||||
};
|
||||
|
||||
/* some special values for the owner field */
|
||||
|
@ -423,20 +430,18 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
|
|||
int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
|
||||
struct amdgpu_irq_src *irq_src,
|
||||
unsigned irq_type);
|
||||
void amdgpu_fence_driver_suspend(struct amdgpu_device *adev);
|
||||
void amdgpu_fence_driver_resume(struct amdgpu_device *adev);
|
||||
int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
|
||||
struct amdgpu_fence **fence);
|
||||
int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner,
|
||||
uint64_t seq, struct amdgpu_fence **fence);
|
||||
void amdgpu_fence_process(struct amdgpu_ring *ring);
|
||||
int amdgpu_fence_wait_next(struct amdgpu_ring *ring);
|
||||
int amdgpu_fence_wait_empty(struct amdgpu_ring *ring);
|
||||
unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring);
|
||||
|
||||
bool amdgpu_fence_signaled(struct amdgpu_fence *fence);
|
||||
int amdgpu_fence_wait(struct amdgpu_fence *fence, bool interruptible);
|
||||
int amdgpu_fence_wait_any(struct amdgpu_device *adev,
|
||||
signed long amdgpu_fence_wait_any(struct amdgpu_device *adev,
|
||||
struct amdgpu_fence **fences,
|
||||
bool intr);
|
||||
bool intr, long t);
|
||||
struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence);
|
||||
void amdgpu_fence_unref(struct amdgpu_fence **fence);
|
||||
|
||||
|
@ -481,7 +486,7 @@ static inline bool amdgpu_fence_is_earlier(struct amdgpu_fence *a,
|
|||
return a->seq < b->seq;
|
||||
}
|
||||
|
||||
int amdgpu_user_fence_emit(struct amdgpu_ring *ring, struct amdgpu_user_fence *user,
|
||||
int amdgpu_user_fence_emit(struct amdgpu_ring *ring, struct amdgpu_user_fence *user,
|
||||
void *owner, struct amdgpu_fence **fence);
|
||||
|
||||
/*
|
||||
|
@ -532,14 +537,16 @@ struct amdgpu_bo_va_mapping {
|
|||
struct amdgpu_bo_va {
|
||||
/* protected by bo being reserved */
|
||||
struct list_head bo_list;
|
||||
uint64_t addr;
|
||||
struct amdgpu_fence *last_pt_update;
|
||||
struct fence *last_pt_update;
|
||||
unsigned ref_count;
|
||||
|
||||
/* protected by vm mutex */
|
||||
struct list_head mappings;
|
||||
/* protected by vm mutex and spinlock */
|
||||
struct list_head vm_status;
|
||||
|
||||
/* mappings for this bo_va */
|
||||
struct list_head invalids;
|
||||
struct list_head valids;
|
||||
|
||||
/* constant after initialization */
|
||||
struct amdgpu_vm *vm;
|
||||
struct amdgpu_bo *bo;
|
||||
|
@ -697,8 +704,8 @@ struct amdgpu_sync {
|
|||
};
|
||||
|
||||
void amdgpu_sync_create(struct amdgpu_sync *sync);
|
||||
void amdgpu_sync_fence(struct amdgpu_sync *sync,
|
||||
struct amdgpu_fence *fence);
|
||||
int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync,
|
||||
struct fence *f);
|
||||
int amdgpu_sync_resv(struct amdgpu_device *adev,
|
||||
struct amdgpu_sync *sync,
|
||||
struct reservation_object *resv,
|
||||
|
@ -821,7 +828,9 @@ struct amdgpu_flip_work {
|
|||
uint64_t base;
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct amdgpu_bo *old_rbo;
|
||||
struct fence *fence;
|
||||
struct fence *excl;
|
||||
unsigned shared_count;
|
||||
struct fence **shared;
|
||||
};
|
||||
|
||||
|
||||
|
@ -844,6 +853,8 @@ struct amdgpu_ib {
|
|||
uint32_t gws_base, gws_size;
|
||||
uint32_t oa_base, oa_size;
|
||||
uint32_t flags;
|
||||
/* resulting sequence number */
|
||||
uint64_t sequence;
|
||||
};
|
||||
|
||||
enum amdgpu_ring_type {
|
||||
|
@ -854,11 +865,23 @@ enum amdgpu_ring_type {
|
|||
AMDGPU_RING_TYPE_VCE
|
||||
};
|
||||
|
||||
extern struct amd_sched_backend_ops amdgpu_sched_ops;
|
||||
|
||||
int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring,
|
||||
struct amdgpu_ib *ibs,
|
||||
unsigned num_ibs,
|
||||
int (*free_job)(struct amdgpu_cs_parser *),
|
||||
void *owner,
|
||||
struct fence **fence);
|
||||
|
||||
struct amdgpu_ring {
|
||||
struct amdgpu_device *adev;
|
||||
const struct amdgpu_ring_funcs *funcs;
|
||||
struct amdgpu_fence_driver fence_drv;
|
||||
struct amd_gpu_scheduler *scheduler;
|
||||
|
||||
spinlock_t fence_lock;
|
||||
struct mutex *ring_lock;
|
||||
struct amdgpu_bo *ring_obj;
|
||||
volatile uint32_t *ring;
|
||||
|
@ -892,6 +915,7 @@ struct amdgpu_ring {
|
|||
struct amdgpu_ctx *current_ctx;
|
||||
enum amdgpu_ring_type type;
|
||||
char name[16];
|
||||
bool is_pte_ring;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -943,18 +967,22 @@ struct amdgpu_vm {
|
|||
|
||||
struct rb_root va;
|
||||
|
||||
/* protecting invalidated and freed */
|
||||
/* protecting invalidated */
|
||||
spinlock_t status_lock;
|
||||
|
||||
/* BOs moved, but not yet updated in the PT */
|
||||
struct list_head invalidated;
|
||||
|
||||
/* BOs freed, but not yet updated in the PT */
|
||||
/* BOs cleared in the PT because of a move */
|
||||
struct list_head cleared;
|
||||
|
||||
/* BO mappings freed, but not yet updated in the PT */
|
||||
struct list_head freed;
|
||||
|
||||
/* contains the page directory */
|
||||
struct amdgpu_bo *page_directory;
|
||||
unsigned max_pde_used;
|
||||
struct fence *page_directory_fence;
|
||||
|
||||
/* array of page tables, one for each page directory entry */
|
||||
struct amdgpu_vm_pt *page_tables;
|
||||
|
@ -983,27 +1011,47 @@ struct amdgpu_vm_manager {
|
|||
* context related structures
|
||||
*/
|
||||
|
||||
struct amdgpu_ctx_state {
|
||||
uint64_t flags;
|
||||
uint32_t hangs;
|
||||
#define AMDGPU_CTX_MAX_CS_PENDING 16
|
||||
|
||||
struct amdgpu_ctx_ring {
|
||||
uint64_t sequence;
|
||||
struct fence *fences[AMDGPU_CTX_MAX_CS_PENDING];
|
||||
struct amd_sched_entity entity;
|
||||
};
|
||||
|
||||
struct amdgpu_ctx {
|
||||
/* call kref_get()before CS start and kref_put() after CS fence signaled */
|
||||
struct kref refcount;
|
||||
struct amdgpu_fpriv *fpriv;
|
||||
struct amdgpu_ctx_state state;
|
||||
uint32_t id;
|
||||
unsigned reset_counter;
|
||||
struct kref refcount;
|
||||
struct amdgpu_device *adev;
|
||||
unsigned reset_counter;
|
||||
spinlock_t ring_lock;
|
||||
struct amdgpu_ctx_ring rings[AMDGPU_MAX_RINGS];
|
||||
};
|
||||
|
||||
struct amdgpu_ctx_mgr {
|
||||
struct amdgpu_device *adev;
|
||||
struct idr ctx_handles;
|
||||
/* lock for IDR system */
|
||||
struct mutex lock;
|
||||
struct amdgpu_device *adev;
|
||||
struct mutex lock;
|
||||
/* protected by lock */
|
||||
struct idr ctx_handles;
|
||||
};
|
||||
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
||||
struct amdgpu_ctx *ctx);
|
||||
void amdgpu_ctx_fini(struct amdgpu_ctx *ctx);
|
||||
|
||||
struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id);
|
||||
int amdgpu_ctx_put(struct amdgpu_ctx *ctx);
|
||||
|
||||
uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
|
||||
struct fence *fence, uint64_t queued_seq);
|
||||
struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
|
||||
struct amdgpu_ring *ring, uint64_t seq);
|
||||
|
||||
int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp);
|
||||
|
||||
void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr);
|
||||
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr);
|
||||
|
||||
/*
|
||||
* file private structure
|
||||
*/
|
||||
|
@ -1012,7 +1060,7 @@ struct amdgpu_fpriv {
|
|||
struct amdgpu_vm vm;
|
||||
struct mutex bo_list_lock;
|
||||
struct idr bo_list_handles;
|
||||
struct amdgpu_ctx_mgr ctx_mgr;
|
||||
struct amdgpu_ctx_mgr ctx_mgr;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1029,6 +1077,8 @@ struct amdgpu_bo_list {
|
|||
struct amdgpu_bo_list_entry *array;
|
||||
};
|
||||
|
||||
struct amdgpu_bo_list *
|
||||
amdgpu_bo_list_clone(struct amdgpu_bo_list *list);
|
||||
struct amdgpu_bo_list *
|
||||
amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id);
|
||||
void amdgpu_bo_list_put(struct amdgpu_bo_list *list);
|
||||
|
@ -1205,6 +1255,14 @@ struct amdgpu_cs_parser {
|
|||
|
||||
/* user fence */
|
||||
struct amdgpu_user_fence uf;
|
||||
|
||||
struct amdgpu_ring *ring;
|
||||
struct mutex job_lock;
|
||||
struct work_struct job_work;
|
||||
int (*prepare_job)(struct amdgpu_cs_parser *sched_job);
|
||||
int (*run_job)(struct amdgpu_cs_parser *sched_job);
|
||||
int (*free_job)(struct amdgpu_cs_parser *sched_job);
|
||||
struct amd_sched_fence *s_fence;
|
||||
};
|
||||
|
||||
static inline u32 amdgpu_get_ib_value(struct amdgpu_cs_parser *p, uint32_t ib_idx, int idx)
|
||||
|
@ -1849,17 +1907,12 @@ struct amdgpu_atcs {
|
|||
struct amdgpu_atcs_functions functions;
|
||||
};
|
||||
|
||||
int amdgpu_ctx_alloc(struct amdgpu_device *adev,struct amdgpu_fpriv *fpriv,
|
||||
uint32_t *id,uint32_t flags);
|
||||
int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv,
|
||||
uint32_t id);
|
||||
/*
|
||||
* CGS
|
||||
*/
|
||||
void *amdgpu_cgs_create_device(struct amdgpu_device *adev);
|
||||
void amdgpu_cgs_destroy_device(void *cgs_device);
|
||||
|
||||
void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv);
|
||||
struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id);
|
||||
int amdgpu_ctx_put(struct amdgpu_ctx *ctx);
|
||||
|
||||
extern int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp);
|
||||
|
||||
/*
|
||||
* Core structure, functions and helpers.
|
||||
|
@ -1883,7 +1936,7 @@ struct amdgpu_device {
|
|||
struct rw_semaphore exclusive_lock;
|
||||
|
||||
/* ASIC */
|
||||
enum amdgpu_asic_type asic_type;
|
||||
enum amd_asic_type asic_type;
|
||||
uint32_t family;
|
||||
uint32_t rev_id;
|
||||
uint32_t external_rev_id;
|
||||
|
@ -1976,7 +2029,6 @@ struct amdgpu_device {
|
|||
struct amdgpu_irq_src hpd_irq;
|
||||
|
||||
/* rings */
|
||||
wait_queue_head_t fence_queue;
|
||||
unsigned fence_context;
|
||||
struct mutex ring_lock;
|
||||
unsigned num_rings;
|
||||
|
@ -2028,6 +2080,9 @@ struct amdgpu_device {
|
|||
|
||||
/* amdkfd interface */
|
||||
struct kfd_dev *kfd;
|
||||
|
||||
/* kernel conext for IB submission */
|
||||
struct amdgpu_ctx kernel_ctx;
|
||||
};
|
||||
|
||||
bool amdgpu_device_is_px(struct drm_device *dev);
|
||||
|
@ -2215,6 +2270,12 @@ void amdgpu_pci_config_reset(struct amdgpu_device *adev);
|
|||
bool amdgpu_card_posted(struct amdgpu_device *adev);
|
||||
void amdgpu_update_display_priority(struct amdgpu_device *adev);
|
||||
bool amdgpu_boot_test_post_card(struct amdgpu_device *adev);
|
||||
struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
struct amdgpu_ctx *ctx,
|
||||
struct amdgpu_ib *ibs,
|
||||
uint32_t num_ibs);
|
||||
|
||||
int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
|
||||
int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
|
||||
u32 ip_instance, u32 ring,
|
||||
|
@ -2278,8 +2339,8 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
|
|||
struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
struct list_head *head);
|
||||
struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
||||
struct amdgpu_sync *sync);
|
||||
void amdgpu_vm_flush(struct amdgpu_ring *ring,
|
||||
struct amdgpu_vm *vm,
|
||||
struct amdgpu_fence *updates);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_family.h"
|
||||
#include "amd_shared.h"
|
||||
#include <drm/drmP.h>
|
||||
#include "amdgpu.h"
|
||||
#include <linux/module.h>
|
||||
|
@ -50,9 +50,11 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev)
|
|||
#endif
|
||||
|
||||
switch (rdev->asic_type) {
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
case CHIP_KAVERI:
|
||||
kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions();
|
||||
break;
|
||||
#endif
|
||||
case CHIP_CARRIZO:
|
||||
kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions();
|
||||
break;
|
||||
|
|
|
@ -897,7 +897,7 @@ bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,
|
|||
if ((id == ASIC_INTERNAL_ENGINE_SS) ||
|
||||
(id == ASIC_INTERNAL_MEMORY_SS))
|
||||
ss->rate /= 100;
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
amdgpu_atombios_get_igp_ss_overrides(adev, ss, id);
|
||||
return true;
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ void amdgpu_atombios_set_memory_clock(struct amdgpu_device *adev,
|
|||
SET_MEMORY_CLOCK_PS_ALLOCATION args;
|
||||
int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */
|
||||
|
|
|
@ -42,7 +42,7 @@ static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size,
|
|||
r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence);
|
||||
if (r)
|
||||
goto exit_do_move;
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r)
|
||||
goto exit_do_move;
|
||||
amdgpu_fence_unref(&fence);
|
||||
|
|
|
@ -48,7 +48,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
|
|||
resource_size_t vram_base;
|
||||
resource_size_t size = 256 * 1024; /* ??? */
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU))
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
if (!amdgpu_card_posted(adev))
|
||||
return false;
|
||||
|
||||
|
@ -184,7 +184,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
|||
bool found = false;
|
||||
|
||||
/* ATRM is for the discrete card only */
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return false;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
|
@ -246,7 +246,7 @@ static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
|||
|
||||
static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return igp_read_bios_from_vram(adev);
|
||||
else
|
||||
return amdgpu_asic_read_disabled_bios(adev);
|
||||
|
|
|
@ -62,6 +62,39 @@ static int amdgpu_bo_list_create(struct amdgpu_fpriv *fpriv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct amdgpu_bo_list *
|
||||
amdgpu_bo_list_clone(struct amdgpu_bo_list *list)
|
||||
{
|
||||
struct amdgpu_bo_list *result;
|
||||
unsigned i;
|
||||
|
||||
result = kmalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
result->array = drm_calloc_large(list->num_entries,
|
||||
sizeof(struct amdgpu_bo_list_entry));
|
||||
if (!result->array) {
|
||||
kfree(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_init(&result->lock);
|
||||
result->gds_obj = list->gds_obj;
|
||||
result->gws_obj = list->gws_obj;
|
||||
result->oa_obj = list->oa_obj;
|
||||
result->has_userptr = list->has_userptr;
|
||||
result->num_entries = list->num_entries;
|
||||
|
||||
memcpy(result->array, list->array, list->num_entries *
|
||||
sizeof(struct amdgpu_bo_list_entry));
|
||||
|
||||
for (i = 0; i < result->num_entries; ++i)
|
||||
amdgpu_bo_ref(result->array[i].robj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id)
|
||||
{
|
||||
struct amdgpu_bo_list *list;
|
||||
|
|
|
@ -0,0 +1,838 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu.h"
|
||||
#include "cgs_linux.h"
|
||||
#include "atom.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
|
||||
struct amdgpu_cgs_device {
|
||||
struct cgs_device base;
|
||||
struct amdgpu_device *adev;
|
||||
};
|
||||
|
||||
#define CGS_FUNC_ADEV \
|
||||
struct amdgpu_device *adev = \
|
||||
((struct amdgpu_cgs_device *)cgs_device)->adev
|
||||
|
||||
static int amdgpu_cgs_gpu_mem_info(void *cgs_device, enum cgs_gpu_mem_type type,
|
||||
uint64_t *mc_start, uint64_t *mc_size,
|
||||
uint64_t *mem_size)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
switch(type) {
|
||||
case CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB:
|
||||
case CGS_GPU_MEM_TYPE__VISIBLE_FB:
|
||||
*mc_start = 0;
|
||||
*mc_size = adev->mc.visible_vram_size;
|
||||
*mem_size = adev->mc.visible_vram_size - adev->vram_pin_size;
|
||||
break;
|
||||
case CGS_GPU_MEM_TYPE__INVISIBLE_CONTIG_FB:
|
||||
case CGS_GPU_MEM_TYPE__INVISIBLE_FB:
|
||||
*mc_start = adev->mc.visible_vram_size;
|
||||
*mc_size = adev->mc.real_vram_size - adev->mc.visible_vram_size;
|
||||
*mem_size = *mc_size;
|
||||
break;
|
||||
case CGS_GPU_MEM_TYPE__GART_CACHEABLE:
|
||||
case CGS_GPU_MEM_TYPE__GART_WRITECOMBINE:
|
||||
*mc_start = adev->mc.gtt_start;
|
||||
*mc_size = adev->mc.gtt_size;
|
||||
*mem_size = adev->mc.gtt_size - adev->gart_pin_size;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_gmap_kmem(void *cgs_device, void *kmem,
|
||||
uint64_t size,
|
||||
uint64_t min_offset, uint64_t max_offset,
|
||||
cgs_handle_t *kmem_handle, uint64_t *mcaddr)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int ret;
|
||||
struct amdgpu_bo *bo;
|
||||
struct page *kmem_page = vmalloc_to_page(kmem);
|
||||
int npages = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
|
||||
struct sg_table *sg = drm_prime_pages_to_sg(&kmem_page, npages);
|
||||
ret = amdgpu_bo_create(adev, size, PAGE_SIZE, false,
|
||||
AMDGPU_GEM_DOMAIN_GTT, 0, sg, &bo);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = amdgpu_bo_reserve(bo, false);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
|
||||
/* pin buffer into GTT */
|
||||
ret = amdgpu_bo_pin_restricted(bo, AMDGPU_GEM_DOMAIN_GTT,
|
||||
min_offset, max_offset, mcaddr);
|
||||
amdgpu_bo_unreserve(bo);
|
||||
|
||||
*kmem_handle = (cgs_handle_t)bo;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_gunmap_kmem(void *cgs_device, cgs_handle_t kmem_handle)
|
||||
{
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)kmem_handle;
|
||||
|
||||
if (obj) {
|
||||
int r = amdgpu_bo_reserve(obj, false);
|
||||
if (likely(r == 0)) {
|
||||
amdgpu_bo_unpin(obj);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
}
|
||||
amdgpu_bo_unref(&obj);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_alloc_gpu_mem(void *cgs_device,
|
||||
enum cgs_gpu_mem_type type,
|
||||
uint64_t size, uint64_t align,
|
||||
uint64_t min_offset, uint64_t max_offset,
|
||||
cgs_handle_t *handle)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint16_t flags = 0;
|
||||
int ret = 0;
|
||||
uint32_t domain = 0;
|
||||
struct amdgpu_bo *obj;
|
||||
struct ttm_placement placement;
|
||||
struct ttm_place place;
|
||||
|
||||
if (min_offset > max_offset) {
|
||||
BUG_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* fail if the alignment is not a power of 2 */
|
||||
if (((align != 1) && (align & (align - 1)))
|
||||
|| size == 0 || align == 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
switch(type) {
|
||||
case CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB:
|
||||
case CGS_GPU_MEM_TYPE__VISIBLE_FB:
|
||||
flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
domain = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
if (max_offset > adev->mc.real_vram_size)
|
||||
return -EINVAL;
|
||||
place.fpfn = min_offset >> PAGE_SHIFT;
|
||||
place.lpfn = max_offset >> PAGE_SHIFT;
|
||||
place.flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
|
||||
TTM_PL_FLAG_VRAM;
|
||||
break;
|
||||
case CGS_GPU_MEM_TYPE__INVISIBLE_CONTIG_FB:
|
||||
case CGS_GPU_MEM_TYPE__INVISIBLE_FB:
|
||||
flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
|
||||
domain = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
if (adev->mc.visible_vram_size < adev->mc.real_vram_size) {
|
||||
place.fpfn =
|
||||
max(min_offset, adev->mc.visible_vram_size) >> PAGE_SHIFT;
|
||||
place.lpfn =
|
||||
min(max_offset, adev->mc.real_vram_size) >> PAGE_SHIFT;
|
||||
place.flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
|
||||
TTM_PL_FLAG_VRAM;
|
||||
}
|
||||
|
||||
break;
|
||||
case CGS_GPU_MEM_TYPE__GART_CACHEABLE:
|
||||
domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
place.fpfn = min_offset >> PAGE_SHIFT;
|
||||
place.lpfn = max_offset >> PAGE_SHIFT;
|
||||
place.flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
|
||||
break;
|
||||
case CGS_GPU_MEM_TYPE__GART_WRITECOMBINE:
|
||||
flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC;
|
||||
domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
place.fpfn = min_offset >> PAGE_SHIFT;
|
||||
place.lpfn = max_offset >> PAGE_SHIFT;
|
||||
place.flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT |
|
||||
TTM_PL_FLAG_UNCACHED;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
*handle = 0;
|
||||
|
||||
placement.placement = &place;
|
||||
placement.num_placement = 1;
|
||||
placement.busy_placement = &place;
|
||||
placement.num_busy_placement = 1;
|
||||
|
||||
ret = amdgpu_bo_create_restricted(adev, size, PAGE_SIZE,
|
||||
true, domain, flags,
|
||||
NULL, &placement, &obj);
|
||||
if (ret) {
|
||||
DRM_ERROR("(%d) bo create failed\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*handle = (cgs_handle_t)obj;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_import_gpu_mem(void *cgs_device, int dmabuf_fd,
|
||||
cgs_handle_t *handle)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int r;
|
||||
uint32_t dma_handle;
|
||||
struct drm_gem_object *obj;
|
||||
struct amdgpu_bo *bo;
|
||||
struct drm_device *dev = adev->ddev;
|
||||
struct drm_file *file_priv = NULL, *priv;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
list_for_each_entry(priv, &dev->filelist, lhead) {
|
||||
rcu_read_lock();
|
||||
if (priv->pid == get_pid(task_pid(current)))
|
||||
file_priv = priv;
|
||||
rcu_read_unlock();
|
||||
if (file_priv)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
r = dev->driver->prime_fd_to_handle(dev,
|
||||
file_priv, dmabuf_fd,
|
||||
&dma_handle);
|
||||
spin_lock(&file_priv->table_lock);
|
||||
|
||||
/* Check if we currently have a reference on the object */
|
||||
obj = idr_find(&file_priv->object_idr, dma_handle);
|
||||
if (obj == NULL) {
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
bo = gem_to_amdgpu_bo(obj);
|
||||
*handle = (cgs_handle_t)bo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_free_gpu_mem(void *cgs_device, cgs_handle_t handle)
|
||||
{
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)handle;
|
||||
|
||||
if (obj) {
|
||||
int r = amdgpu_bo_reserve(obj, false);
|
||||
if (likely(r == 0)) {
|
||||
amdgpu_bo_kunmap(obj);
|
||||
amdgpu_bo_unpin(obj);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
}
|
||||
amdgpu_bo_unref(&obj);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_gmap_gpu_mem(void *cgs_device, cgs_handle_t handle,
|
||||
uint64_t *mcaddr)
|
||||
{
|
||||
int r;
|
||||
u64 min_offset, max_offset;
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)handle;
|
||||
|
||||
WARN_ON_ONCE(obj->placement.num_placement > 1);
|
||||
|
||||
min_offset = obj->placements[0].fpfn << PAGE_SHIFT;
|
||||
max_offset = obj->placements[0].lpfn << PAGE_SHIFT;
|
||||
|
||||
r = amdgpu_bo_reserve(obj, false);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
r = amdgpu_bo_pin_restricted(obj, AMDGPU_GEM_DOMAIN_GTT,
|
||||
min_offset, max_offset, mcaddr);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_gunmap_gpu_mem(void *cgs_device, cgs_handle_t handle)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)handle;
|
||||
r = amdgpu_bo_reserve(obj, false);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
r = amdgpu_bo_unpin(obj);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_kmap_gpu_mem(void *cgs_device, cgs_handle_t handle,
|
||||
void **map)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)handle;
|
||||
r = amdgpu_bo_reserve(obj, false);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
r = amdgpu_bo_kmap(obj, map);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_kunmap_gpu_mem(void *cgs_device, cgs_handle_t handle)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_bo *obj = (struct amdgpu_bo *)handle;
|
||||
r = amdgpu_bo_reserve(obj, false);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
amdgpu_bo_kunmap(obj);
|
||||
amdgpu_bo_unreserve(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
static uint32_t amdgpu_cgs_read_register(void *cgs_device, unsigned offset)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
return RREG32(offset);
|
||||
}
|
||||
|
||||
static void amdgpu_cgs_write_register(void *cgs_device, unsigned offset,
|
||||
uint32_t value)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
WREG32(offset, value);
|
||||
}
|
||||
|
||||
static uint32_t amdgpu_cgs_read_ind_register(void *cgs_device,
|
||||
enum cgs_ind_reg space,
|
||||
unsigned index)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
switch (space) {
|
||||
case CGS_IND_REG__MMIO:
|
||||
return RREG32_IDX(index);
|
||||
case CGS_IND_REG__PCIE:
|
||||
return RREG32_PCIE(index);
|
||||
case CGS_IND_REG__SMC:
|
||||
return RREG32_SMC(index);
|
||||
case CGS_IND_REG__UVD_CTX:
|
||||
return RREG32_UVD_CTX(index);
|
||||
case CGS_IND_REG__DIDT:
|
||||
return RREG32_DIDT(index);
|
||||
case CGS_IND_REG__AUDIO_ENDPT:
|
||||
DRM_ERROR("audio endpt register access not implemented.\n");
|
||||
return 0;
|
||||
}
|
||||
WARN(1, "Invalid indirect register space");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_cgs_write_ind_register(void *cgs_device,
|
||||
enum cgs_ind_reg space,
|
||||
unsigned index, uint32_t value)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
switch (space) {
|
||||
case CGS_IND_REG__MMIO:
|
||||
return WREG32_IDX(index, value);
|
||||
case CGS_IND_REG__PCIE:
|
||||
return WREG32_PCIE(index, value);
|
||||
case CGS_IND_REG__SMC:
|
||||
return WREG32_SMC(index, value);
|
||||
case CGS_IND_REG__UVD_CTX:
|
||||
return WREG32_UVD_CTX(index, value);
|
||||
case CGS_IND_REG__DIDT:
|
||||
return WREG32_DIDT(index, value);
|
||||
case CGS_IND_REG__AUDIO_ENDPT:
|
||||
DRM_ERROR("audio endpt register access not implemented.\n");
|
||||
return;
|
||||
}
|
||||
WARN(1, "Invalid indirect register space");
|
||||
}
|
||||
|
||||
static uint8_t amdgpu_cgs_read_pci_config_byte(void *cgs_device, unsigned addr)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint8_t val;
|
||||
int ret = pci_read_config_byte(adev->pdev, addr, &val);
|
||||
if (WARN(ret, "pci_read_config_byte error"))
|
||||
return 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint16_t amdgpu_cgs_read_pci_config_word(void *cgs_device, unsigned addr)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint16_t val;
|
||||
int ret = pci_read_config_word(adev->pdev, addr, &val);
|
||||
if (WARN(ret, "pci_read_config_word error"))
|
||||
return 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t amdgpu_cgs_read_pci_config_dword(void *cgs_device,
|
||||
unsigned addr)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint32_t val;
|
||||
int ret = pci_read_config_dword(adev->pdev, addr, &val);
|
||||
if (WARN(ret, "pci_read_config_dword error"))
|
||||
return 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void amdgpu_cgs_write_pci_config_byte(void *cgs_device, unsigned addr,
|
||||
uint8_t value)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int ret = pci_write_config_byte(adev->pdev, addr, value);
|
||||
WARN(ret, "pci_write_config_byte error");
|
||||
}
|
||||
|
||||
static void amdgpu_cgs_write_pci_config_word(void *cgs_device, unsigned addr,
|
||||
uint16_t value)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int ret = pci_write_config_word(adev->pdev, addr, value);
|
||||
WARN(ret, "pci_write_config_word error");
|
||||
}
|
||||
|
||||
static void amdgpu_cgs_write_pci_config_dword(void *cgs_device, unsigned addr,
|
||||
uint32_t value)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int ret = pci_write_config_dword(adev->pdev, addr, value);
|
||||
WARN(ret, "pci_write_config_dword error");
|
||||
}
|
||||
|
||||
static const void *amdgpu_cgs_atom_get_data_table(void *cgs_device,
|
||||
unsigned table, uint16_t *size,
|
||||
uint8_t *frev, uint8_t *crev)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
uint16_t data_start;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(
|
||||
adev->mode_info.atom_context, table, size,
|
||||
frev, crev, &data_start))
|
||||
return (uint8_t*)adev->mode_info.atom_context->bios +
|
||||
data_start;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_atom_get_cmd_table_revs(void *cgs_device, unsigned table,
|
||||
uint8_t *frev, uint8_t *crev)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
|
||||
if (amdgpu_atom_parse_cmd_header(
|
||||
adev->mode_info.atom_context, table,
|
||||
frev, crev))
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_atom_exec_cmd_table(void *cgs_device, unsigned table,
|
||||
void *args)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
|
||||
return amdgpu_atom_execute_table(
|
||||
adev->mode_info.atom_context, table, args);
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_create_pm_request(void *cgs_device, cgs_handle_t *request)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_destroy_pm_request(void *cgs_device, cgs_handle_t request)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_set_pm_request(void *cgs_device, cgs_handle_t request,
|
||||
int active)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_pm_request_clock(void *cgs_device, cgs_handle_t request,
|
||||
enum cgs_clock clock, unsigned freq)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_pm_request_engine(void *cgs_device, cgs_handle_t request,
|
||||
enum cgs_engine engine, int powered)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int amdgpu_cgs_pm_query_clock_limits(void *cgs_device,
|
||||
enum cgs_clock clock,
|
||||
struct cgs_clock_limits *limits)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_set_camera_voltages(void *cgs_device, uint32_t mask,
|
||||
const uint32_t *voltages)
|
||||
{
|
||||
DRM_ERROR("not implemented");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
struct cgs_irq_params {
|
||||
unsigned src_id;
|
||||
cgs_irq_source_set_func_t set;
|
||||
cgs_irq_handler_func_t handler;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
static int cgs_set_irq_state(struct amdgpu_device *adev,
|
||||
struct amdgpu_irq_src *src,
|
||||
unsigned type,
|
||||
enum amdgpu_interrupt_state state)
|
||||
{
|
||||
struct cgs_irq_params *irq_params =
|
||||
(struct cgs_irq_params *)src->data;
|
||||
if (!irq_params)
|
||||
return -EINVAL;
|
||||
if (!irq_params->set)
|
||||
return -EINVAL;
|
||||
return irq_params->set(irq_params->private_data,
|
||||
irq_params->src_id,
|
||||
type,
|
||||
(int)state);
|
||||
}
|
||||
|
||||
static int cgs_process_irq(struct amdgpu_device *adev,
|
||||
struct amdgpu_irq_src *source,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
struct cgs_irq_params *irq_params =
|
||||
(struct cgs_irq_params *)source->data;
|
||||
if (!irq_params)
|
||||
return -EINVAL;
|
||||
if (!irq_params->handler)
|
||||
return -EINVAL;
|
||||
return irq_params->handler(irq_params->private_data,
|
||||
irq_params->src_id,
|
||||
entry->iv_entry);
|
||||
}
|
||||
|
||||
static const struct amdgpu_irq_src_funcs cgs_irq_funcs = {
|
||||
.set = cgs_set_irq_state,
|
||||
.process = cgs_process_irq,
|
||||
};
|
||||
|
||||
static int amdgpu_cgs_add_irq_source(void *cgs_device, unsigned src_id,
|
||||
unsigned num_types,
|
||||
cgs_irq_source_set_func_t set,
|
||||
cgs_irq_handler_func_t handler,
|
||||
void *private_data)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int ret = 0;
|
||||
struct cgs_irq_params *irq_params;
|
||||
struct amdgpu_irq_src *source =
|
||||
kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
|
||||
if (!source)
|
||||
return -ENOMEM;
|
||||
irq_params =
|
||||
kzalloc(sizeof(struct cgs_irq_params), GFP_KERNEL);
|
||||
if (!irq_params) {
|
||||
kfree(source);
|
||||
return -ENOMEM;
|
||||
}
|
||||
source->num_types = num_types;
|
||||
source->funcs = &cgs_irq_funcs;
|
||||
irq_params->src_id = src_id;
|
||||
irq_params->set = set;
|
||||
irq_params->handler = handler;
|
||||
irq_params->private_data = private_data;
|
||||
source->data = (void *)irq_params;
|
||||
ret = amdgpu_irq_add_id(adev, src_id, source);
|
||||
if (ret) {
|
||||
kfree(irq_params);
|
||||
kfree(source);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_irq_get(void *cgs_device, unsigned src_id, unsigned type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
return amdgpu_irq_get(adev, adev->irq.sources[src_id], type);
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_irq_put(void *cgs_device, unsigned src_id, unsigned type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
return amdgpu_irq_put(adev, adev->irq.sources[src_id], type);
|
||||
}
|
||||
|
||||
int amdgpu_cgs_set_clockgating_state(void *cgs_device,
|
||||
enum amd_ip_block_type block_type,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int i, r = -1;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
|
||||
if (adev->ip_blocks[i].type == block_type) {
|
||||
r = adev->ip_blocks[i].funcs->set_clockgating_state(
|
||||
(void *)adev,
|
||||
state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_cgs_set_powergating_state(void *cgs_device,
|
||||
enum amd_ip_block_type block_type,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
int i, r = -1;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_block_status[i].valid)
|
||||
continue;
|
||||
|
||||
if (adev->ip_blocks[i].type == block_type) {
|
||||
r = adev->ip_blocks[i].funcs->set_powergating_state(
|
||||
(void *)adev,
|
||||
state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t fw_type_convert(void *cgs_device, uint32_t fw_type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM;
|
||||
|
||||
switch (fw_type) {
|
||||
case CGS_UCODE_ID_SDMA0:
|
||||
result = AMDGPU_UCODE_ID_SDMA0;
|
||||
break;
|
||||
case CGS_UCODE_ID_SDMA1:
|
||||
result = AMDGPU_UCODE_ID_SDMA1;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_CE:
|
||||
result = AMDGPU_UCODE_ID_CP_CE;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_PFP:
|
||||
result = AMDGPU_UCODE_ID_CP_PFP;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_ME:
|
||||
result = AMDGPU_UCODE_ID_CP_ME;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_MEC:
|
||||
case CGS_UCODE_ID_CP_MEC_JT1:
|
||||
result = AMDGPU_UCODE_ID_CP_MEC1;
|
||||
break;
|
||||
case CGS_UCODE_ID_CP_MEC_JT2:
|
||||
if (adev->asic_type == CHIP_TONGA)
|
||||
result = AMDGPU_UCODE_ID_CP_MEC2;
|
||||
else if (adev->asic_type == CHIP_CARRIZO)
|
||||
result = AMDGPU_UCODE_ID_CP_MEC1;
|
||||
break;
|
||||
case CGS_UCODE_ID_RLC_G:
|
||||
result = AMDGPU_UCODE_ID_RLC_G;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Firmware type not supported\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_get_firmware_info(void *cgs_device,
|
||||
enum cgs_ucode_id type,
|
||||
struct cgs_firmware_info *info)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
|
||||
if (CGS_UCODE_ID_SMU != type) {
|
||||
uint64_t gpu_addr;
|
||||
uint32_t data_size;
|
||||
const struct gfx_firmware_header_v1_0 *header;
|
||||
enum AMDGPU_UCODE_ID id;
|
||||
struct amdgpu_firmware_info *ucode;
|
||||
|
||||
id = fw_type_convert(cgs_device, type);
|
||||
ucode = &adev->firmware.ucode[id];
|
||||
if (ucode->fw == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
gpu_addr = ucode->mc_addr;
|
||||
header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
data_size = le32_to_cpu(header->header.ucode_size_bytes);
|
||||
|
||||
if ((type == CGS_UCODE_ID_CP_MEC_JT1) ||
|
||||
(type == CGS_UCODE_ID_CP_MEC_JT2)) {
|
||||
gpu_addr += le32_to_cpu(header->jt_offset) << 2;
|
||||
data_size = le32_to_cpu(header->jt_size) << 2;
|
||||
}
|
||||
info->mc_addr = gpu_addr;
|
||||
info->image_size = data_size;
|
||||
info->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version);
|
||||
} else {
|
||||
char fw_name[30] = {0};
|
||||
int err = 0;
|
||||
uint32_t ucode_size;
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_TONGA:
|
||||
strcpy(fw_name, "amdgpu/tonga_smc.bin");
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("SMC firmware not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to request firmware\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = amdgpu_ucode_validate(adev->pm.fw);
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
|
||||
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
|
||||
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
|
||||
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
|
||||
src = (const uint8_t *)(adev->pm.fw->data +
|
||||
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
|
||||
info->version = adev->pm.fw_version;
|
||||
info->image_size = ucode_size;
|
||||
info->kptr = (void *)src;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cgs_ops amdgpu_cgs_ops = {
|
||||
amdgpu_cgs_gpu_mem_info,
|
||||
amdgpu_cgs_gmap_kmem,
|
||||
amdgpu_cgs_gunmap_kmem,
|
||||
amdgpu_cgs_alloc_gpu_mem,
|
||||
amdgpu_cgs_free_gpu_mem,
|
||||
amdgpu_cgs_gmap_gpu_mem,
|
||||
amdgpu_cgs_gunmap_gpu_mem,
|
||||
amdgpu_cgs_kmap_gpu_mem,
|
||||
amdgpu_cgs_kunmap_gpu_mem,
|
||||
amdgpu_cgs_read_register,
|
||||
amdgpu_cgs_write_register,
|
||||
amdgpu_cgs_read_ind_register,
|
||||
amdgpu_cgs_write_ind_register,
|
||||
amdgpu_cgs_read_pci_config_byte,
|
||||
amdgpu_cgs_read_pci_config_word,
|
||||
amdgpu_cgs_read_pci_config_dword,
|
||||
amdgpu_cgs_write_pci_config_byte,
|
||||
amdgpu_cgs_write_pci_config_word,
|
||||
amdgpu_cgs_write_pci_config_dword,
|
||||
amdgpu_cgs_atom_get_data_table,
|
||||
amdgpu_cgs_atom_get_cmd_table_revs,
|
||||
amdgpu_cgs_atom_exec_cmd_table,
|
||||
amdgpu_cgs_create_pm_request,
|
||||
amdgpu_cgs_destroy_pm_request,
|
||||
amdgpu_cgs_set_pm_request,
|
||||
amdgpu_cgs_pm_request_clock,
|
||||
amdgpu_cgs_pm_request_engine,
|
||||
amdgpu_cgs_pm_query_clock_limits,
|
||||
amdgpu_cgs_set_camera_voltages,
|
||||
amdgpu_cgs_get_firmware_info,
|
||||
amdgpu_cgs_set_powergating_state,
|
||||
amdgpu_cgs_set_clockgating_state
|
||||
};
|
||||
|
||||
static const struct cgs_os_ops amdgpu_cgs_os_ops = {
|
||||
amdgpu_cgs_import_gpu_mem,
|
||||
amdgpu_cgs_add_irq_source,
|
||||
amdgpu_cgs_irq_get,
|
||||
amdgpu_cgs_irq_put
|
||||
};
|
||||
|
||||
void *amdgpu_cgs_create_device(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_cgs_device *cgs_device =
|
||||
kmalloc(sizeof(*cgs_device), GFP_KERNEL);
|
||||
|
||||
if (!cgs_device) {
|
||||
DRM_ERROR("Couldn't allocate CGS device structure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cgs_device->base.ops = &amdgpu_cgs_ops;
|
||||
cgs_device->base.os_ops = &amdgpu_cgs_os_ops;
|
||||
cgs_device->adev = adev;
|
||||
|
||||
return cgs_device;
|
||||
}
|
||||
|
||||
void amdgpu_cgs_destroy_device(void *cgs_device)
|
||||
{
|
||||
kfree(cgs_device);
|
||||
}
|
|
@ -126,12 +126,54 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_job_work_func(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_cs_parser *sched_job =
|
||||
container_of(work, struct amdgpu_cs_parser,
|
||||
job_work);
|
||||
mutex_lock(&sched_job->job_lock);
|
||||
if (sched_job->free_job)
|
||||
sched_job->free_job(sched_job);
|
||||
mutex_unlock(&sched_job->job_lock);
|
||||
/* after processing job, free memory */
|
||||
fence_put(&sched_job->s_fence->base);
|
||||
kfree(sched_job);
|
||||
}
|
||||
struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
struct amdgpu_ctx *ctx,
|
||||
struct amdgpu_ib *ibs,
|
||||
uint32_t num_ibs)
|
||||
{
|
||||
struct amdgpu_cs_parser *parser;
|
||||
int i;
|
||||
|
||||
parser = kzalloc(sizeof(struct amdgpu_cs_parser), GFP_KERNEL);
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
parser->adev = adev;
|
||||
parser->filp = filp;
|
||||
parser->ctx = ctx;
|
||||
parser->ibs = ibs;
|
||||
parser->num_ibs = num_ibs;
|
||||
if (amdgpu_enable_scheduler) {
|
||||
mutex_init(&parser->job_lock);
|
||||
INIT_WORK(&parser->job_work, amdgpu_job_work_func);
|
||||
}
|
||||
for (i = 0; i < num_ibs; i++)
|
||||
ibs[i].ctx = ctx;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
{
|
||||
union drm_amdgpu_cs *cs = data;
|
||||
uint64_t *chunk_array_user;
|
||||
uint64_t *chunk_array = NULL;
|
||||
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
|
||||
struct amdgpu_bo_list *bo_list = NULL;
|
||||
unsigned size, i;
|
||||
int r = 0;
|
||||
|
||||
|
@ -143,17 +185,30 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
|||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
|
||||
bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
|
||||
if (!amdgpu_enable_scheduler)
|
||||
p->bo_list = bo_list;
|
||||
else {
|
||||
if (bo_list && !bo_list->has_userptr) {
|
||||
p->bo_list = amdgpu_bo_list_clone(bo_list);
|
||||
amdgpu_bo_list_put(bo_list);
|
||||
if (!p->bo_list)
|
||||
return -ENOMEM;
|
||||
} else if (bo_list && bo_list->has_userptr)
|
||||
p->bo_list = bo_list;
|
||||
else
|
||||
p->bo_list = NULL;
|
||||
}
|
||||
|
||||
/* get chunks */
|
||||
INIT_LIST_HEAD(&p->validated);
|
||||
chunk_array = kcalloc(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
|
||||
chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
|
||||
if (chunk_array == NULL) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
chunk_array_user = (uint64_t *)(unsigned long)(cs->in.chunks);
|
||||
chunk_array_user = (uint64_t __user *)(cs->in.chunks);
|
||||
if (copy_from_user(chunk_array, chunk_array_user,
|
||||
sizeof(uint64_t)*cs->in.num_chunks)) {
|
||||
r = -EFAULT;
|
||||
|
@ -161,7 +216,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
|||
}
|
||||
|
||||
p->nchunks = cs->in.num_chunks;
|
||||
p->chunks = kcalloc(p->nchunks, sizeof(struct amdgpu_cs_chunk),
|
||||
p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk),
|
||||
GFP_KERNEL);
|
||||
if (p->chunks == NULL) {
|
||||
r = -ENOMEM;
|
||||
|
@ -173,7 +228,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
|||
struct drm_amdgpu_cs_chunk user_chunk;
|
||||
uint32_t __user *cdata;
|
||||
|
||||
chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
|
||||
chunk_ptr = (void __user *)chunk_array[i];
|
||||
if (copy_from_user(&user_chunk, chunk_ptr,
|
||||
sizeof(struct drm_amdgpu_cs_chunk))) {
|
||||
r = -EFAULT;
|
||||
|
@ -183,7 +238,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
|||
p->chunks[i].length_dw = user_chunk.length_dw;
|
||||
|
||||
size = p->chunks[i].length_dw;
|
||||
cdata = (void __user *)(unsigned long)user_chunk.chunk_data;
|
||||
cdata = (void __user *)user_chunk.chunk_data;
|
||||
p->chunks[i].user_ptr = cdata;
|
||||
|
||||
p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t));
|
||||
|
@ -235,11 +290,10 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
p->ibs = kcalloc(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!p->ibs) {
|
||||
|
||||
p->ibs = kmalloc_array(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!p->ibs)
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(chunk_array);
|
||||
|
@ -415,18 +469,8 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a,
|
|||
return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs_parser_fini() - clean parser states
|
||||
* @parser: parser structure holding parsing context.
|
||||
* @error: error number
|
||||
*
|
||||
* If error is set than unvalidate buffer, otherwise just free memory
|
||||
* used by parsing context.
|
||||
**/
|
||||
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
|
||||
static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int error, bool backoff)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!error) {
|
||||
/* Sort the buffer list from the smallest to largest buffer,
|
||||
* which affects the order of buffers in the LRU list.
|
||||
|
@ -447,11 +491,19 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
|
|||
ttm_eu_backoff_reservation(&parser->ticket,
|
||||
&parser->validated);
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser)
|
||||
{
|
||||
unsigned i;
|
||||
if (parser->ctx)
|
||||
amdgpu_ctx_put(parser->ctx);
|
||||
if (parser->bo_list)
|
||||
amdgpu_bo_list_put(parser->bo_list);
|
||||
if (parser->bo_list) {
|
||||
if (amdgpu_enable_scheduler && !parser->bo_list->has_userptr)
|
||||
amdgpu_bo_list_free(parser->bo_list);
|
||||
else
|
||||
amdgpu_bo_list_put(parser->bo_list);
|
||||
}
|
||||
drm_free_large(parser->vm_bos);
|
||||
for (i = 0; i < parser->nchunks; i++)
|
||||
drm_free_large(parser->chunks[i].kdata);
|
||||
|
@ -462,6 +514,29 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
|
|||
kfree(parser->ibs);
|
||||
if (parser->uf.bo)
|
||||
drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base);
|
||||
|
||||
if (!amdgpu_enable_scheduler)
|
||||
kfree(parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs_parser_fini() - clean parser states
|
||||
* @parser: parser structure holding parsing context.
|
||||
* @error: error number
|
||||
*
|
||||
* If error is set than unvalidate buffer, otherwise just free memory
|
||||
* used by parsing context.
|
||||
**/
|
||||
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
|
||||
{
|
||||
amdgpu_cs_parser_fini_early(parser, error, backoff);
|
||||
amdgpu_cs_parser_fini_late(parser);
|
||||
}
|
||||
|
||||
static int amdgpu_cs_parser_free_job(struct amdgpu_cs_parser *sched_job)
|
||||
{
|
||||
amdgpu_cs_parser_fini_late(sched_job);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
|
||||
|
@ -476,12 +551,18 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_fence(adev, &p->ibs[0].sync, vm->page_directory_fence);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_vm_clear_freed(adev, vm);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (p->bo_list) {
|
||||
for (i = 0; i < p->bo_list->num_entries; i++) {
|
||||
struct fence *f;
|
||||
|
||||
/* ignore duplicates */
|
||||
bo = p->bo_list->array[i].robj;
|
||||
if (!bo)
|
||||
|
@ -495,7 +576,10 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_sync_fence(&p->ibs[0].sync, bo_va->last_pt_update);
|
||||
f = bo_va->last_pt_update;
|
||||
r = amdgpu_sync_fence(adev, &p->ibs[0].sync, f);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,9 +613,9 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
|
|||
goto out;
|
||||
}
|
||||
amdgpu_cs_sync_rings(parser);
|
||||
|
||||
r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs,
|
||||
parser->filp);
|
||||
if (!amdgpu_enable_scheduler)
|
||||
r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs,
|
||||
parser->filp);
|
||||
|
||||
out:
|
||||
mutex_unlock(&vm->mutex);
|
||||
|
@ -650,7 +734,6 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
|||
ib->oa_size = amdgpu_bo_size(oa);
|
||||
}
|
||||
}
|
||||
|
||||
/* wrap the last IB with user fence */
|
||||
if (parser->uf.bo) {
|
||||
struct amdgpu_ib *ib = &parser->ibs[parser->num_ibs - 1];
|
||||
|
@ -693,9 +776,9 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
|
|||
sizeof(struct drm_amdgpu_cs_chunk_dep);
|
||||
|
||||
for (j = 0; j < num_deps; ++j) {
|
||||
struct amdgpu_fence *fence;
|
||||
struct amdgpu_ring *ring;
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct fence *fence;
|
||||
|
||||
r = amdgpu_cs_get_ring(adev, deps[j].ip_type,
|
||||
deps[j].ip_instance,
|
||||
|
@ -707,50 +790,34 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
|
|||
if (ctx == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
r = amdgpu_fence_recreate(ring, p->filp,
|
||||
deps[j].handle,
|
||||
&fence);
|
||||
if (r) {
|
||||
fence = amdgpu_ctx_get_fence(ctx, ring,
|
||||
deps[j].handle);
|
||||
if (IS_ERR(fence)) {
|
||||
r = PTR_ERR(fence);
|
||||
amdgpu_ctx_put(ctx);
|
||||
return r;
|
||||
}
|
||||
|
||||
amdgpu_sync_fence(&ib->sync, fence);
|
||||
amdgpu_fence_unref(&fence);
|
||||
amdgpu_ctx_put(ctx);
|
||||
} else if (fence) {
|
||||
r = amdgpu_sync_fence(adev, &ib->sync, fence);
|
||||
fence_put(fence);
|
||||
amdgpu_ctx_put(ctx);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
static int amdgpu_cs_parser_prepare_job(struct amdgpu_cs_parser *sched_job)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
union drm_amdgpu_cs *cs = data;
|
||||
struct amdgpu_cs_parser parser;
|
||||
int r, i;
|
||||
struct amdgpu_cs_parser *parser = sched_job;
|
||||
struct amdgpu_device *adev = sched_job->adev;
|
||||
bool reserved_buffers = false;
|
||||
|
||||
down_read(&adev->exclusive_lock);
|
||||
if (!adev->accel_working) {
|
||||
up_read(&adev->exclusive_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
/* initialize parser */
|
||||
memset(&parser, 0, sizeof(struct amdgpu_cs_parser));
|
||||
parser.filp = filp;
|
||||
parser.adev = adev;
|
||||
r = amdgpu_cs_parser_init(&parser, data);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to initialize parser !\n");
|
||||
amdgpu_cs_parser_fini(&parser, r, false);
|
||||
up_read(&adev->exclusive_lock);
|
||||
r = amdgpu_cs_handle_lockup(adev, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_cs_parser_relocs(&parser);
|
||||
r = amdgpu_cs_parser_relocs(parser);
|
||||
if (r) {
|
||||
if (r != -ERESTARTSYS) {
|
||||
if (r == -ENOMEM)
|
||||
|
@ -762,30 +829,114 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
|||
|
||||
if (!r) {
|
||||
reserved_buffers = true;
|
||||
r = amdgpu_cs_ib_fill(adev, &parser);
|
||||
r = amdgpu_cs_ib_fill(adev, parser);
|
||||
}
|
||||
if (!r) {
|
||||
r = amdgpu_cs_dependencies(adev, parser);
|
||||
if (r)
|
||||
DRM_ERROR("Failed in the dependencies handling %d!\n", r);
|
||||
}
|
||||
if (r) {
|
||||
amdgpu_cs_parser_fini(parser, r, reserved_buffers);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!r)
|
||||
r = amdgpu_cs_dependencies(adev, &parser);
|
||||
for (i = 0; i < parser->num_ibs; i++)
|
||||
trace_amdgpu_cs(parser, i);
|
||||
|
||||
r = amdgpu_cs_ib_vm_chunk(adev, parser);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct amdgpu_ring *amdgpu_cs_parser_get_ring(
|
||||
struct amdgpu_device *adev,
|
||||
struct amdgpu_cs_parser *parser)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
struct amdgpu_cs_chunk *chunk;
|
||||
struct drm_amdgpu_cs_chunk_ib *chunk_ib;
|
||||
struct amdgpu_ring *ring;
|
||||
for (i = 0; i < parser->nchunks; i++) {
|
||||
chunk = &parser->chunks[i];
|
||||
chunk_ib = (struct drm_amdgpu_cs_chunk_ib *)chunk->kdata;
|
||||
|
||||
if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
|
||||
continue;
|
||||
|
||||
r = amdgpu_cs_get_ring(adev, chunk_ib->ip_type,
|
||||
chunk_ib->ip_instance, chunk_ib->ring,
|
||||
&ring);
|
||||
if (r)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return ring;
|
||||
}
|
||||
|
||||
int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
union drm_amdgpu_cs *cs = data;
|
||||
struct amdgpu_cs_parser *parser;
|
||||
int r;
|
||||
|
||||
down_read(&adev->exclusive_lock);
|
||||
if (!adev->accel_working) {
|
||||
up_read(&adev->exclusive_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
parser = amdgpu_cs_parser_create(adev, filp, NULL, NULL, 0);
|
||||
if (!parser)
|
||||
return -ENOMEM;
|
||||
r = amdgpu_cs_parser_init(parser, data);
|
||||
if (r) {
|
||||
amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
|
||||
DRM_ERROR("Failed to initialize parser !\n");
|
||||
amdgpu_cs_parser_fini(parser, r, false);
|
||||
up_read(&adev->exclusive_lock);
|
||||
r = amdgpu_cs_handle_lockup(adev, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
for (i = 0; i < parser.num_ibs; i++)
|
||||
trace_amdgpu_cs(&parser, i);
|
||||
if (amdgpu_enable_scheduler && parser->num_ibs) {
|
||||
struct amdgpu_ring * ring =
|
||||
amdgpu_cs_parser_get_ring(adev, parser);
|
||||
r = amdgpu_cs_parser_prepare_job(parser);
|
||||
if (r)
|
||||
goto out;
|
||||
parser->ring = ring;
|
||||
parser->free_job = amdgpu_cs_parser_free_job;
|
||||
mutex_lock(&parser->job_lock);
|
||||
r = amd_sched_push_job(ring->scheduler,
|
||||
&parser->ctx->rings[ring->idx].entity,
|
||||
parser,
|
||||
&parser->s_fence);
|
||||
if (r) {
|
||||
mutex_unlock(&parser->job_lock);
|
||||
goto out;
|
||||
}
|
||||
parser->ibs[parser->num_ibs - 1].sequence =
|
||||
amdgpu_ctx_add_fence(parser->ctx, ring,
|
||||
&parser->s_fence->base,
|
||||
parser->s_fence->v_seq);
|
||||
cs->out.handle = parser->s_fence->v_seq;
|
||||
list_sort(NULL, &parser->validated, cmp_size_smaller_first);
|
||||
ttm_eu_fence_buffer_objects(&parser->ticket,
|
||||
&parser->validated,
|
||||
&parser->s_fence->base);
|
||||
|
||||
r = amdgpu_cs_ib_vm_chunk(adev, &parser);
|
||||
if (r) {
|
||||
goto out;
|
||||
mutex_unlock(&parser->job_lock);
|
||||
up_read(&adev->exclusive_lock);
|
||||
return 0;
|
||||
}
|
||||
r = amdgpu_cs_parser_prepare_job(parser);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
cs->out.handle = parser.ibs[parser.num_ibs - 1].fence->seq;
|
||||
cs->out.handle = parser->ibs[parser->num_ibs - 1].sequence;
|
||||
out:
|
||||
amdgpu_cs_parser_fini(&parser, r, true);
|
||||
amdgpu_cs_parser_fini(parser, r, true);
|
||||
up_read(&adev->exclusive_lock);
|
||||
r = amdgpu_cs_handle_lockup(adev, r);
|
||||
return r;
|
||||
|
@ -806,30 +957,29 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data,
|
|||
union drm_amdgpu_wait_cs *wait = data;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout);
|
||||
struct amdgpu_fence *fence = NULL;
|
||||
struct amdgpu_ring *ring = NULL;
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct fence *fence;
|
||||
long r;
|
||||
|
||||
r = amdgpu_cs_get_ring(adev, wait->in.ip_type, wait->in.ip_instance,
|
||||
wait->in.ring, &ring);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ctx = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id);
|
||||
if (ctx == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
r = amdgpu_cs_get_ring(adev, wait->in.ip_type, wait->in.ip_instance,
|
||||
wait->in.ring, &ring);
|
||||
if (r) {
|
||||
amdgpu_ctx_put(ctx);
|
||||
return r;
|
||||
}
|
||||
fence = amdgpu_ctx_get_fence(ctx, ring, wait->in.handle);
|
||||
if (IS_ERR(fence))
|
||||
r = PTR_ERR(fence);
|
||||
else if (fence) {
|
||||
r = fence_wait_timeout(fence, true, timeout);
|
||||
fence_put(fence);
|
||||
} else
|
||||
r = 1;
|
||||
|
||||
r = amdgpu_fence_recreate(ring, filp, wait->in.handle, &fence);
|
||||
if (r) {
|
||||
amdgpu_ctx_put(ctx);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fence_wait_timeout(&fence->base, true, timeout);
|
||||
amdgpu_fence_unref(&fence);
|
||||
amdgpu_ctx_put(ctx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -864,7 +1014,16 @@ amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
|
|||
if (!reloc->bo_va)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(mapping, &reloc->bo_va->mappings, list) {
|
||||
list_for_each_entry(mapping, &reloc->bo_va->valids, list) {
|
||||
if (mapping->it.start > addr ||
|
||||
addr > mapping->it.last)
|
||||
continue;
|
||||
|
||||
*bo = reloc->bo_va->bo;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
list_for_each_entry(mapping, &reloc->bo_va->invalids, list) {
|
||||
if (mapping->it.start > addr ||
|
||||
addr > mapping->it.last)
|
||||
continue;
|
||||
|
|
|
@ -25,54 +25,107 @@
|
|||
#include <drm/drmP.h>
|
||||
#include "amdgpu.h"
|
||||
|
||||
static void amdgpu_ctx_do_release(struct kref *ref)
|
||||
int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
|
||||
struct amdgpu_ctx *ctx)
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
unsigned i, j;
|
||||
int r;
|
||||
|
||||
ctx = container_of(ref, struct amdgpu_ctx, refcount);
|
||||
mgr = &ctx->fpriv->ctx_mgr;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->adev = adev;
|
||||
kref_init(&ctx->refcount);
|
||||
spin_lock_init(&ctx->ring_lock);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
ctx->rings[i].sequence = 1;
|
||||
|
||||
idr_remove(&mgr->ctx_handles, ctx->id);
|
||||
kfree(ctx);
|
||||
if (amdgpu_enable_scheduler) {
|
||||
/* create context entity for each ring */
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
struct amd_sched_rq *rq;
|
||||
if (kernel)
|
||||
rq = &adev->rings[i]->scheduler->kernel_rq;
|
||||
else
|
||||
rq = &adev->rings[i]->scheduler->sched_rq;
|
||||
r = amd_sched_entity_init(adev->rings[i]->scheduler,
|
||||
&ctx->rings[i].entity,
|
||||
rq, amdgpu_sched_jobs);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < adev->num_rings) {
|
||||
for (j = 0; j < i; j++)
|
||||
amd_sched_entity_fini(adev->rings[j]->scheduler,
|
||||
&ctx->rings[j].entity);
|
||||
kfree(ctx);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_ctx_alloc(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t *id, uint32_t flags)
|
||||
void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
|
||||
{
|
||||
struct amdgpu_device *adev = ctx->adev;
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
for (j = 0; j < AMDGPU_CTX_MAX_CS_PENDING; ++j)
|
||||
fence_put(ctx->rings[i].fences[j]);
|
||||
|
||||
if (amdgpu_enable_scheduler) {
|
||||
for (i = 0; i < adev->num_rings; i++)
|
||||
amd_sched_entity_fini(adev->rings[i]->scheduler,
|
||||
&ctx->rings[i].entity);
|
||||
}
|
||||
}
|
||||
|
||||
static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
|
||||
struct amdgpu_fpriv *fpriv,
|
||||
uint32_t *id)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
|
||||
struct amdgpu_ctx *ctx;
|
||||
int r;
|
||||
|
||||
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
r = idr_alloc(&mgr->ctx_handles, ctx, 0, 0, GFP_KERNEL);
|
||||
r = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
|
||||
if (r < 0) {
|
||||
mutex_unlock(&mgr->lock);
|
||||
kfree(ctx);
|
||||
return r;
|
||||
}
|
||||
*id = (uint32_t)r;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->id = *id;
|
||||
ctx->fpriv = fpriv;
|
||||
kref_init(&ctx->refcount);
|
||||
r = amdgpu_ctx_init(adev, false, ctx);
|
||||
mutex_unlock(&mgr->lock);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t id)
|
||||
static void amdgpu_ctx_do_release(struct kref *ref)
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
|
||||
ctx = container_of(ref, struct amdgpu_ctx, refcount);
|
||||
|
||||
amdgpu_ctx_fini(ctx);
|
||||
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id)
|
||||
{
|
||||
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
|
||||
struct amdgpu_ctx *ctx;
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
ctx = idr_find(&mgr->ctx_handles, id);
|
||||
if (ctx) {
|
||||
idr_remove(&mgr->ctx_handles, id);
|
||||
kref_put(&ctx->refcount, amdgpu_ctx_do_release);
|
||||
mutex_unlock(&mgr->lock);
|
||||
return 0;
|
||||
|
@ -86,9 +139,13 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
|
|||
union drm_amdgpu_ctx_out *out)
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
unsigned reset_counter;
|
||||
|
||||
if (!fpriv)
|
||||
return -EINVAL;
|
||||
|
||||
mgr = &fpriv->ctx_mgr;
|
||||
mutex_lock(&mgr->lock);
|
||||
ctx = idr_find(&mgr->ctx_handles, id);
|
||||
if (!ctx) {
|
||||
|
@ -97,8 +154,8 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
/* TODO: these two are always zero */
|
||||
out->state.flags = ctx->state.flags;
|
||||
out->state.hangs = ctx->state.hangs;
|
||||
out->state.flags = 0x0;
|
||||
out->state.hangs = 0x0;
|
||||
|
||||
/* determine if a GPU reset has occured since the last call */
|
||||
reset_counter = atomic_read(&adev->gpu_reset_counter);
|
||||
|
@ -113,28 +170,11 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv)
|
||||
{
|
||||
struct idr *idp;
|
||||
struct amdgpu_ctx *ctx;
|
||||
uint32_t id;
|
||||
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
|
||||
idp = &mgr->ctx_handles;
|
||||
|
||||
idr_for_each_entry(idp,ctx,id) {
|
||||
if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
|
||||
DRM_ERROR("ctx (id=%ul) is still alive\n",ctx->id);
|
||||
}
|
||||
|
||||
mutex_destroy(&mgr->lock);
|
||||
}
|
||||
|
||||
int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
int r;
|
||||
uint32_t id;
|
||||
uint32_t flags;
|
||||
|
||||
union drm_amdgpu_ctx *args = data;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
|
@ -142,15 +182,14 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
r = 0;
|
||||
id = args->in.ctx_id;
|
||||
flags = args->in.flags;
|
||||
|
||||
switch (args->in.op) {
|
||||
case AMDGPU_CTX_OP_ALLOC_CTX:
|
||||
r = amdgpu_ctx_alloc(adev, fpriv, &id, flags);
|
||||
r = amdgpu_ctx_alloc(adev, fpriv, &id);
|
||||
args->out.alloc.ctx_id = id;
|
||||
break;
|
||||
case AMDGPU_CTX_OP_FREE_CTX:
|
||||
r = amdgpu_ctx_free(adev, fpriv, id);
|
||||
r = amdgpu_ctx_free(fpriv, id);
|
||||
break;
|
||||
case AMDGPU_CTX_OP_QUERY_STATE:
|
||||
r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
|
||||
|
@ -165,7 +204,12 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
|
|||
struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
|
||||
if (!fpriv)
|
||||
return NULL;
|
||||
|
||||
mgr = &fpriv->ctx_mgr;
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
ctx = idr_find(&mgr->ctx_handles, id);
|
||||
|
@ -177,17 +221,96 @@ struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
|
|||
|
||||
int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
|
||||
{
|
||||
struct amdgpu_fpriv *fpriv;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fpriv = ctx->fpriv;
|
||||
mgr = &fpriv->ctx_mgr;
|
||||
mutex_lock(&mgr->lock);
|
||||
kref_put(&ctx->refcount, amdgpu_ctx_do_release);
|
||||
mutex_unlock(&mgr->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
|
||||
struct fence *fence, uint64_t queued_seq)
|
||||
{
|
||||
struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
|
||||
uint64_t seq = 0;
|
||||
unsigned idx = 0;
|
||||
struct fence *other = NULL;
|
||||
|
||||
if (amdgpu_enable_scheduler)
|
||||
seq = queued_seq;
|
||||
else
|
||||
seq = cring->sequence;
|
||||
idx = seq % AMDGPU_CTX_MAX_CS_PENDING;
|
||||
other = cring->fences[idx];
|
||||
if (other) {
|
||||
signed long r;
|
||||
r = fence_wait_timeout(other, false, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0)
|
||||
DRM_ERROR("Error (%ld) waiting for fence!\n", r);
|
||||
}
|
||||
|
||||
fence_get(fence);
|
||||
|
||||
spin_lock(&ctx->ring_lock);
|
||||
cring->fences[idx] = fence;
|
||||
if (!amdgpu_enable_scheduler)
|
||||
cring->sequence++;
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
|
||||
fence_put(other);
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
|
||||
struct amdgpu_ring *ring, uint64_t seq)
|
||||
{
|
||||
struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
|
||||
struct fence *fence;
|
||||
uint64_t queued_seq;
|
||||
|
||||
spin_lock(&ctx->ring_lock);
|
||||
if (amdgpu_enable_scheduler)
|
||||
queued_seq = amd_sched_next_queued_seq(&cring->entity);
|
||||
else
|
||||
queued_seq = cring->sequence;
|
||||
|
||||
if (seq >= queued_seq) {
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
||||
if (seq + AMDGPU_CTX_MAX_CS_PENDING < queued_seq) {
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fence = fence_get(cring->fences[seq % AMDGPU_CTX_MAX_CS_PENDING]);
|
||||
spin_unlock(&ctx->ring_lock);
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
|
||||
{
|
||||
mutex_init(&mgr->lock);
|
||||
idr_init(&mgr->ctx_handles);
|
||||
}
|
||||
|
||||
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct idr *idp;
|
||||
uint32_t id;
|
||||
|
||||
idp = &mgr->ctx_handles;
|
||||
|
||||
idr_for_each_entry(idp, ctx, id) {
|
||||
if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
|
||||
DRM_ERROR("ctx %p is still alive\n", ctx);
|
||||
}
|
||||
|
||||
idr_destroy(&mgr->ctx_handles);
|
||||
mutex_destroy(&mgr->lock);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ static const char *amdgpu_asic_name[] = {
|
|||
"MULLINS",
|
||||
"TOPAZ",
|
||||
"TONGA",
|
||||
"FIJI",
|
||||
"CARRIZO",
|
||||
"LAST",
|
||||
};
|
||||
|
@ -63,7 +64,7 @@ bool amdgpu_device_is_px(struct drm_device *dev)
|
|||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_PX)
|
||||
if (adev->flags & AMD_IS_PX)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1160,6 +1161,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
|
|||
switch (adev->asic_type) {
|
||||
case CHIP_TOPAZ:
|
||||
case CHIP_TONGA:
|
||||
case CHIP_FIJI:
|
||||
case CHIP_CARRIZO:
|
||||
if (adev->asic_type == CHIP_CARRIZO)
|
||||
adev->family = AMDGPU_FAMILY_CZ;
|
||||
|
@ -1377,7 +1379,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
adev->ddev = ddev;
|
||||
adev->pdev = pdev;
|
||||
adev->flags = flags;
|
||||
adev->asic_type = flags & AMDGPU_ASIC_MASK;
|
||||
adev->asic_type = flags & AMD_ASIC_MASK;
|
||||
adev->is_atom_bios = false;
|
||||
adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT;
|
||||
adev->mc.gtt_size = 512 * 1024 * 1024;
|
||||
|
@ -1523,6 +1525,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_ctx_init(adev, true, &adev->kernel_ctx);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "failed to create kernel context (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_ib_ring_tests(adev);
|
||||
if (r)
|
||||
DRM_ERROR("ib ring test failed (%d).\n", r);
|
||||
|
@ -1584,6 +1591,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
|||
adev->shutdown = true;
|
||||
/* evict vram memory */
|
||||
amdgpu_bo_evict_vram(adev);
|
||||
amdgpu_ctx_fini(&adev->kernel_ctx);
|
||||
amdgpu_ib_pool_fini(adev);
|
||||
amdgpu_fence_driver_fini(adev);
|
||||
amdgpu_fbdev_fini(adev);
|
||||
|
@ -1627,8 +1635,7 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
|
|||
struct amdgpu_device *adev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_connector *connector;
|
||||
int i, r;
|
||||
bool force_completion = false;
|
||||
int r;
|
||||
|
||||
if (dev == NULL || dev->dev_private == NULL) {
|
||||
return -ENODEV;
|
||||
|
@ -1667,21 +1674,7 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
|
|||
/* evict vram memory */
|
||||
amdgpu_bo_evict_vram(adev);
|
||||
|
||||
/* wait for gpu to finish processing current batch */
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (!ring)
|
||||
continue;
|
||||
|
||||
r = amdgpu_fence_wait_empty(ring);
|
||||
if (r) {
|
||||
/* delay GPU reset to resume */
|
||||
force_completion = true;
|
||||
}
|
||||
}
|
||||
if (force_completion) {
|
||||
amdgpu_fence_driver_force_completion(adev);
|
||||
}
|
||||
amdgpu_fence_driver_suspend(adev);
|
||||
|
||||
r = amdgpu_suspend(adev);
|
||||
|
||||
|
@ -1739,6 +1732,8 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
|
|||
|
||||
r = amdgpu_resume(adev);
|
||||
|
||||
amdgpu_fence_driver_resume(adev);
|
||||
|
||||
r = amdgpu_ib_ring_tests(adev);
|
||||
if (r)
|
||||
DRM_ERROR("ib ring test failed (%d).\n", r);
|
||||
|
|
|
@ -35,6 +35,36 @@
|
|||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
static void amdgpu_flip_wait_fence(struct amdgpu_device *adev,
|
||||
struct fence **f)
|
||||
{
|
||||
struct amdgpu_fence *fence;
|
||||
long r;
|
||||
|
||||
if (*f == NULL)
|
||||
return;
|
||||
|
||||
fence = to_amdgpu_fence(*f);
|
||||
if (fence) {
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r == -EDEADLK) {
|
||||
up_read(&adev->exclusive_lock);
|
||||
r = amdgpu_gpu_reset(adev);
|
||||
down_read(&adev->exclusive_lock);
|
||||
}
|
||||
} else
|
||||
r = fence_wait(*f, false);
|
||||
|
||||
if (r)
|
||||
DRM_ERROR("failed to wait on page flip fence (%ld)!\n", r);
|
||||
|
||||
/* We continue with the page flip even if we failed to wait on
|
||||
* the fence, otherwise the DRM core and userspace will be
|
||||
* confused about which BO the CRTC is scanning out
|
||||
*/
|
||||
fence_put(*f);
|
||||
*f = NULL;
|
||||
}
|
||||
|
||||
static void amdgpu_flip_work_func(struct work_struct *__work)
|
||||
{
|
||||
|
@ -44,34 +74,13 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
|
|||
struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id];
|
||||
|
||||
struct drm_crtc *crtc = &amdgpuCrtc->base;
|
||||
struct amdgpu_fence *fence;
|
||||
unsigned long flags;
|
||||
int r;
|
||||
unsigned i;
|
||||
|
||||
down_read(&adev->exclusive_lock);
|
||||
if (work->fence) {
|
||||
fence = to_amdgpu_fence(work->fence);
|
||||
if (fence) {
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
if (r == -EDEADLK) {
|
||||
up_read(&adev->exclusive_lock);
|
||||
r = amdgpu_gpu_reset(adev);
|
||||
down_read(&adev->exclusive_lock);
|
||||
}
|
||||
} else
|
||||
r = fence_wait(work->fence, false);
|
||||
|
||||
if (r)
|
||||
DRM_ERROR("failed to wait on page flip fence (%d)!\n", r);
|
||||
|
||||
/* We continue with the page flip even if we failed to wait on
|
||||
* the fence, otherwise the DRM core and userspace will be
|
||||
* confused about which BO the CRTC is scanning out
|
||||
*/
|
||||
|
||||
fence_put(work->fence);
|
||||
work->fence = NULL;
|
||||
}
|
||||
amdgpu_flip_wait_fence(adev, &work->excl);
|
||||
for (i = 0; i < work->shared_count; ++i)
|
||||
amdgpu_flip_wait_fence(adev, &work->shared[i]);
|
||||
|
||||
/* We borrow the event spin lock for protecting flip_status */
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
|
@ -108,6 +117,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
|
|||
DRM_ERROR("failed to reserve buffer after flip\n");
|
||||
|
||||
drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
|
||||
kfree(work->shared);
|
||||
kfree(work);
|
||||
}
|
||||
|
||||
|
@ -127,7 +137,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
|
|||
unsigned long flags;
|
||||
u64 tiling_flags;
|
||||
u64 base;
|
||||
int r;
|
||||
int i, r;
|
||||
|
||||
work = kzalloc(sizeof *work, GFP_KERNEL);
|
||||
if (work == NULL)
|
||||
|
@ -167,7 +177,19 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv));
|
||||
r = reservation_object_get_fences_rcu(new_rbo->tbo.resv, &work->excl,
|
||||
&work->shared_count,
|
||||
&work->shared);
|
||||
if (unlikely(r != 0)) {
|
||||
amdgpu_bo_unreserve(new_rbo);
|
||||
DRM_ERROR("failed to get fences for buffer\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fence_get(work->excl);
|
||||
for (i = 0; i < work->shared_count; ++i)
|
||||
fence_get(work->shared[i]);
|
||||
|
||||
amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags);
|
||||
amdgpu_bo_unreserve(new_rbo);
|
||||
|
||||
|
@ -212,7 +234,10 @@ pflip_cleanup:
|
|||
|
||||
cleanup:
|
||||
drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
|
||||
fence_put(work->fence);
|
||||
fence_put(work->excl);
|
||||
for (i = 0; i < work->shared_count; ++i)
|
||||
fence_put(work->shared[i]);
|
||||
kfree(work->shared);
|
||||
kfree(work);
|
||||
|
||||
return r;
|
||||
|
|
|
@ -63,7 +63,7 @@ int amdgpu_disp_priority = 0;
|
|||
int amdgpu_hw_i2c = 0;
|
||||
int amdgpu_pcie_gen2 = -1;
|
||||
int amdgpu_msi = -1;
|
||||
int amdgpu_lockup_timeout = 10000;
|
||||
int amdgpu_lockup_timeout = 0;
|
||||
int amdgpu_dpm = -1;
|
||||
int amdgpu_smc_load_fw = 1;
|
||||
int amdgpu_aspm = -1;
|
||||
|
@ -75,6 +75,9 @@ int amdgpu_deep_color = 0;
|
|||
int amdgpu_vm_size = 8;
|
||||
int amdgpu_vm_block_size = -1;
|
||||
int amdgpu_exp_hw_support = 0;
|
||||
int amdgpu_enable_scheduler = 0;
|
||||
int amdgpu_sched_jobs = 16;
|
||||
int amdgpu_sched_hw_submission = 2;
|
||||
|
||||
MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
|
||||
module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
|
||||
|
@ -103,7 +106,7 @@ module_param_named(pcie_gen2, amdgpu_pcie_gen2, int, 0444);
|
|||
MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
|
||||
module_param_named(msi, amdgpu_msi, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
|
||||
MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default 0 = disable)");
|
||||
module_param_named(lockup_timeout, amdgpu_lockup_timeout, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
|
||||
|
@ -139,36 +142,45 @@ module_param_named(vm_block_size, amdgpu_vm_block_size, int, 0444);
|
|||
MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))");
|
||||
module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable, 0 = disable ((default))");
|
||||
module_param_named(enable_scheduler, amdgpu_enable_scheduler, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 16)");
|
||||
module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)");
|
||||
module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
/* Kaveri */
|
||||
{0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1306, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1309, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1306, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x1307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1309, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
{0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU},
|
||||
/* Bonaire */
|
||||
{0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
|
||||
{0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
|
||||
{0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
|
||||
{0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
|
||||
{0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
|
||||
{0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
|
||||
{0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
|
||||
{0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
|
||||
{0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
|
||||
{0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
|
||||
{0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
|
||||
|
@ -190,39 +202,39 @@ static struct pci_device_id pciidlist[] = {
|
|||
{0x1002, 0x67BA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
|
||||
{0x1002, 0x67BE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
|
||||
/* Kabini */
|
||||
{0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
{0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMD_IS_APU},
|
||||
/* mullins */
|
||||
{0x1002, 0x9850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9851, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9852, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9853, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9854, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9856, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9857, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9851, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9852, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9853, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9854, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9856, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9857, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x9859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
{0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
|
||||
#endif
|
||||
/* topaz */
|
||||
{0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
|
||||
|
@ -240,12 +252,14 @@ static struct pci_device_id pciidlist[] = {
|
|||
{0x1002, 0x6930, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
|
||||
{0x1002, 0x6938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
|
||||
{0x1002, 0x6939, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
|
||||
/* fiji */
|
||||
{0x1002, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_FIJI},
|
||||
/* carrizo */
|
||||
{0x1002, 0x9870, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9874, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9875, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9876, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9877, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
|
||||
{0x1002, 0x9870, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMD_IS_APU},
|
||||
{0x1002, 0x9874, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMD_IS_APU},
|
||||
{0x1002, 0x9875, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMD_IS_APU},
|
||||
{0x1002, 0x9876, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMD_IS_APU},
|
||||
{0x1002, 0x9877, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMD_IS_APU},
|
||||
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
@ -281,7 +295,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
|||
unsigned long flags = ent->driver_data;
|
||||
int ret;
|
||||
|
||||
if ((flags & AMDGPU_EXP_HW_SUPPORT) && !amdgpu_exp_hw_support) {
|
||||
if ((flags & AMD_EXP_HW_SUPPORT) && !amdgpu_exp_hw_support) {
|
||||
DRM_INFO("This hardware requires experimental hardware support.\n"
|
||||
"See modparam exp_hw_support\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "amdgpu_family.h"
|
||||
#include "amd_shared.h"
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
|
|
|
@ -126,7 +126,8 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
|
|||
(*fence)->ring = ring;
|
||||
(*fence)->owner = owner;
|
||||
fence_init(&(*fence)->base, &amdgpu_fence_ops,
|
||||
&adev->fence_queue.lock, adev->fence_context + ring->idx,
|
||||
&ring->fence_drv.fence_queue.lock,
|
||||
adev->fence_context + ring->idx,
|
||||
(*fence)->seq);
|
||||
amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
|
||||
(*fence)->seq,
|
||||
|
@ -135,38 +136,6 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_recreate - recreate a fence from an user fence
|
||||
*
|
||||
* @ring: ring the fence is associated with
|
||||
* @owner: creator of the fence
|
||||
* @seq: user fence sequence number
|
||||
* @fence: resulting amdgpu fence object
|
||||
*
|
||||
* Recreates a fence command from the user fence sequence number (all asics).
|
||||
* Returns 0 on success, -ENOMEM on failure.
|
||||
*/
|
||||
int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner,
|
||||
uint64_t seq, struct amdgpu_fence **fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
|
||||
if (seq > ring->fence_drv.sync_seq[ring->idx])
|
||||
return -EINVAL;
|
||||
|
||||
*fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL);
|
||||
if ((*fence) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
(*fence)->seq = seq;
|
||||
(*fence)->ring = ring;
|
||||
(*fence)->owner = owner;
|
||||
fence_init(&(*fence)->base, &amdgpu_fence_ops,
|
||||
&adev->fence_queue.lock, adev->fence_context + ring->idx,
|
||||
(*fence)->seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_check_signaled - callback from fence_queue
|
||||
*
|
||||
|
@ -196,9 +165,7 @@ static int amdgpu_fence_check_signaled(wait_queue_t *wait, unsigned mode, int fl
|
|||
else
|
||||
FENCE_TRACE(&fence->base, "was already signaled\n");
|
||||
|
||||
amdgpu_irq_put(adev, fence->ring->fence_drv.irq_src,
|
||||
fence->ring->fence_drv.irq_type);
|
||||
__remove_wait_queue(&adev->fence_queue, &fence->fence_wake);
|
||||
__remove_wait_queue(&fence->ring->fence_drv.fence_queue, &fence->fence_wake);
|
||||
fence_put(&fence->base);
|
||||
} else
|
||||
FENCE_TRACE(&fence->base, "pending\n");
|
||||
|
@ -299,14 +266,9 @@ static void amdgpu_fence_check_lockup(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fence_drv->delayed_irq && ring->adev->ddev->irq_enabled) {
|
||||
fence_drv->delayed_irq = false;
|
||||
amdgpu_irq_update(ring->adev, fence_drv->irq_src,
|
||||
fence_drv->irq_type);
|
||||
if (amdgpu_fence_activity(ring)) {
|
||||
wake_up_all(&ring->fence_drv.fence_queue);
|
||||
}
|
||||
|
||||
if (amdgpu_fence_activity(ring))
|
||||
wake_up_all(&ring->adev->fence_queue);
|
||||
else if (amdgpu_ring_is_lockup(ring)) {
|
||||
/* good news we believe it's a lockup */
|
||||
dev_warn(ring->adev->dev, "GPU lockup (current fence id "
|
||||
|
@ -316,7 +278,7 @@ static void amdgpu_fence_check_lockup(struct work_struct *work)
|
|||
|
||||
/* remember that we need an reset */
|
||||
ring->adev->needs_reset = true;
|
||||
wake_up_all(&ring->adev->fence_queue);
|
||||
wake_up_all(&ring->fence_drv.fence_queue);
|
||||
}
|
||||
up_read(&ring->adev->exclusive_lock);
|
||||
}
|
||||
|
@ -332,62 +294,8 @@ static void amdgpu_fence_check_lockup(struct work_struct *work)
|
|||
*/
|
||||
void amdgpu_fence_process(struct amdgpu_ring *ring)
|
||||
{
|
||||
uint64_t seq, last_seq, last_emitted;
|
||||
unsigned count_loop = 0;
|
||||
bool wake = false;
|
||||
|
||||
/* Note there is a scenario here for an infinite loop but it's
|
||||
* very unlikely to happen. For it to happen, the current polling
|
||||
* process need to be interrupted by another process and another
|
||||
* process needs to update the last_seq btw the atomic read and
|
||||
* xchg of the current process.
|
||||
*
|
||||
* More over for this to go in infinite loop there need to be
|
||||
* continuously new fence signaled ie amdgpu_fence_read needs
|
||||
* to return a different value each time for both the currently
|
||||
* polling process and the other process that xchg the last_seq
|
||||
* btw atomic read and xchg of the current process. And the
|
||||
* value the other process set as last seq must be higher than
|
||||
* the seq value we just read. Which means that current process
|
||||
* need to be interrupted after amdgpu_fence_read and before
|
||||
* atomic xchg.
|
||||
*
|
||||
* To be even more safe we count the number of time we loop and
|
||||
* we bail after 10 loop just accepting the fact that we might
|
||||
* have temporarly set the last_seq not to the true real last
|
||||
* seq but to an older one.
|
||||
*/
|
||||
last_seq = atomic64_read(&ring->fence_drv.last_seq);
|
||||
do {
|
||||
last_emitted = ring->fence_drv.sync_seq[ring->idx];
|
||||
seq = amdgpu_fence_read(ring);
|
||||
seq |= last_seq & 0xffffffff00000000LL;
|
||||
if (seq < last_seq) {
|
||||
seq &= 0xffffffff;
|
||||
seq |= last_emitted & 0xffffffff00000000LL;
|
||||
}
|
||||
|
||||
if (seq <= last_seq || seq > last_emitted) {
|
||||
break;
|
||||
}
|
||||
/* If we loop over we don't want to return without
|
||||
* checking if a fence is signaled as it means that the
|
||||
* seq we just read is different from the previous on.
|
||||
*/
|
||||
wake = true;
|
||||
last_seq = seq;
|
||||
if ((count_loop++) > 10) {
|
||||
/* We looped over too many time leave with the
|
||||
* fact that we might have set an older fence
|
||||
* seq then the current real last seq as signaled
|
||||
* by the hw.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq);
|
||||
|
||||
if (wake)
|
||||
wake_up_all(&ring->adev->fence_queue);
|
||||
if (amdgpu_fence_activity(ring))
|
||||
wake_up_all(&ring->fence_drv.fence_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -447,284 +355,49 @@ static bool amdgpu_fence_enable_signaling(struct fence *f)
|
|||
{
|
||||
struct amdgpu_fence *fence = to_amdgpu_fence(f);
|
||||
struct amdgpu_ring *ring = fence->ring;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
|
||||
if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq)
|
||||
return false;
|
||||
|
||||
if (down_read_trylock(&adev->exclusive_lock)) {
|
||||
amdgpu_irq_get(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
if (amdgpu_fence_activity(ring))
|
||||
wake_up_all_locked(&adev->fence_queue);
|
||||
|
||||
/* did fence get signaled after we enabled the sw irq? */
|
||||
if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq) {
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
up_read(&adev->exclusive_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
up_read(&adev->exclusive_lock);
|
||||
} else {
|
||||
/* we're probably in a lockup, lets not fiddle too much */
|
||||
if (amdgpu_irq_get_delayed(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type))
|
||||
ring->fence_drv.delayed_irq = true;
|
||||
amdgpu_fence_schedule_check(ring);
|
||||
}
|
||||
|
||||
fence->fence_wake.flags = 0;
|
||||
fence->fence_wake.private = NULL;
|
||||
fence->fence_wake.func = amdgpu_fence_check_signaled;
|
||||
__add_wait_queue(&adev->fence_queue, &fence->fence_wake);
|
||||
__add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake);
|
||||
fence_get(f);
|
||||
FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_signaled - check if a fence has signaled
|
||||
/*
|
||||
* amdgpu_ring_wait_seq_timeout - wait for seq of the specific ring to signal
|
||||
* @ring: ring to wait on for the seq number
|
||||
* @seq: seq number wait for
|
||||
*
|
||||
* @fence: amdgpu fence object
|
||||
*
|
||||
* Check if the requested fence has signaled (all asics).
|
||||
* Returns true if the fence has signaled or false if it has not.
|
||||
* return value:
|
||||
* 0: seq signaled, and gpu not hang
|
||||
* -EDEADL: GPU hang detected
|
||||
* -EINVAL: some paramter is not valid
|
||||
*/
|
||||
bool amdgpu_fence_signaled(struct amdgpu_fence *fence)
|
||||
static int amdgpu_fence_ring_wait_seq(struct amdgpu_ring *ring, uint64_t seq)
|
||||
{
|
||||
if (!fence)
|
||||
return true;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
bool signaled = false;
|
||||
|
||||
if (amdgpu_fence_seq_signaled(fence->ring, fence->seq)) {
|
||||
if (!fence_signal(&fence->base))
|
||||
FENCE_TRACE(&fence->base, "signaled from amdgpu_fence_signaled\n");
|
||||
return true;
|
||||
}
|
||||
BUG_ON(!ring);
|
||||
if (seq > ring->fence_drv.sync_seq[ring->idx])
|
||||
return -EINVAL;
|
||||
|
||||
return false;
|
||||
}
|
||||
if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
|
||||
return 0;
|
||||
|
||||
/**
|
||||
* amdgpu_fence_any_seq_signaled - check if any sequence number is signaled
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @seq: sequence numbers
|
||||
*
|
||||
* Check if the last signaled fence sequnce number is >= the requested
|
||||
* sequence number (all asics).
|
||||
* Returns true if any has signaled (current value is >= requested value)
|
||||
* or false if it has not. Helper function for amdgpu_fence_wait_seq.
|
||||
*/
|
||||
static bool amdgpu_fence_any_seq_signaled(struct amdgpu_device *adev, u64 *seq)
|
||||
{
|
||||
unsigned i;
|
||||
wait_event(ring->fence_drv.fence_queue, (
|
||||
(signaled = amdgpu_fence_seq_signaled(ring, seq))
|
||||
|| adev->needs_reset));
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
if (!adev->rings[i] || !seq[i])
|
||||
continue;
|
||||
|
||||
if (amdgpu_fence_seq_signaled(adev->rings[i], seq[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_wait_seq_timeout - wait for a specific sequence numbers
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @target_seq: sequence number(s) we want to wait for
|
||||
* @intr: use interruptable sleep
|
||||
* @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait
|
||||
*
|
||||
* Wait for the requested sequence number(s) to be written by any ring
|
||||
* (all asics). Sequnce number array is indexed by ring id.
|
||||
* @intr selects whether to use interruptable (true) or non-interruptable
|
||||
* (false) sleep when waiting for the sequence number. Helper function
|
||||
* for amdgpu_fence_wait_*().
|
||||
* Returns remaining time if the sequence number has passed, 0 when
|
||||
* the wait timeout, or an error for all other cases.
|
||||
* -EDEADLK is returned when a GPU lockup has been detected.
|
||||
*/
|
||||
static long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev,
|
||||
u64 *target_seq, bool intr,
|
||||
long timeout)
|
||||
{
|
||||
uint64_t last_seq[AMDGPU_MAX_RINGS];
|
||||
bool signaled;
|
||||
int i;
|
||||
long r;
|
||||
|
||||
if (timeout == 0) {
|
||||
return amdgpu_fence_any_seq_signaled(adev, target_seq);
|
||||
}
|
||||
|
||||
while (!amdgpu_fence_any_seq_signaled(adev, target_seq)) {
|
||||
|
||||
/* Save current sequence values, used to check for GPU lockups */
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
|
||||
if (!ring || !target_seq[i])
|
||||
continue;
|
||||
|
||||
last_seq[i] = atomic64_read(&ring->fence_drv.last_seq);
|
||||
trace_amdgpu_fence_wait_begin(adev->ddev, i, target_seq[i]);
|
||||
amdgpu_irq_get(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
}
|
||||
|
||||
if (intr) {
|
||||
r = wait_event_interruptible_timeout(adev->fence_queue, (
|
||||
(signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
|
||||
|| adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
|
||||
} else {
|
||||
r = wait_event_timeout(adev->fence_queue, (
|
||||
(signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
|
||||
|| adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
|
||||
}
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
|
||||
if (!ring || !target_seq[i])
|
||||
continue;
|
||||
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
trace_amdgpu_fence_wait_end(adev->ddev, i, target_seq[i]);
|
||||
}
|
||||
|
||||
if (unlikely(r < 0))
|
||||
return r;
|
||||
|
||||
if (unlikely(!signaled)) {
|
||||
|
||||
if (adev->needs_reset)
|
||||
return -EDEADLK;
|
||||
|
||||
/* we were interrupted for some reason and fence
|
||||
* isn't signaled yet, resume waiting */
|
||||
if (r)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
|
||||
if (!ring || !target_seq[i])
|
||||
continue;
|
||||
|
||||
if (last_seq[i] != atomic64_read(&ring->fence_drv.last_seq))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != AMDGPU_MAX_RINGS)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
if (!adev->rings[i] || !target_seq[i])
|
||||
continue;
|
||||
|
||||
if (amdgpu_ring_is_lockup(adev->rings[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < AMDGPU_MAX_RINGS) {
|
||||
/* good news we believe it's a lockup */
|
||||
dev_warn(adev->dev, "GPU lockup (waiting for "
|
||||
"0x%016llx last fence id 0x%016llx on"
|
||||
" ring %d)\n",
|
||||
target_seq[i], last_seq[i], i);
|
||||
|
||||
/* remember that we need an reset */
|
||||
adev->needs_reset = true;
|
||||
wake_up_all(&adev->fence_queue);
|
||||
return -EDEADLK;
|
||||
}
|
||||
|
||||
if (timeout < MAX_SCHEDULE_TIMEOUT) {
|
||||
timeout -= AMDGPU_FENCE_JIFFIES_TIMEOUT;
|
||||
if (timeout <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_wait - wait for a fence to signal
|
||||
*
|
||||
* @fence: amdgpu fence object
|
||||
* @intr: use interruptable sleep
|
||||
*
|
||||
* Wait for the requested fence to signal (all asics).
|
||||
* @intr selects whether to use interruptable (true) or non-interruptable
|
||||
* (false) sleep when waiting for the fence.
|
||||
* Returns 0 if the fence has passed, error for all other cases.
|
||||
*/
|
||||
int amdgpu_fence_wait(struct amdgpu_fence *fence, bool intr)
|
||||
{
|
||||
uint64_t seq[AMDGPU_MAX_RINGS] = {};
|
||||
long r;
|
||||
|
||||
seq[fence->ring->idx] = fence->seq;
|
||||
r = amdgpu_fence_wait_seq_timeout(fence->ring->adev, seq, intr, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fence_signal(&fence->base);
|
||||
if (!r)
|
||||
FENCE_TRACE(&fence->base, "signaled from fence_wait\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_wait_any - wait for a fence to signal on any ring
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @fences: amdgpu fence object(s)
|
||||
* @intr: use interruptable sleep
|
||||
*
|
||||
* Wait for any requested fence to signal (all asics). Fence
|
||||
* array is indexed by ring id. @intr selects whether to use
|
||||
* interruptable (true) or non-interruptable (false) sleep when
|
||||
* waiting for the fences. Used by the suballocator.
|
||||
* Returns 0 if any fence has passed, error for all other cases.
|
||||
*/
|
||||
int amdgpu_fence_wait_any(struct amdgpu_device *adev,
|
||||
struct amdgpu_fence **fences,
|
||||
bool intr)
|
||||
{
|
||||
uint64_t seq[AMDGPU_MAX_RINGS];
|
||||
unsigned i, num_rings = 0;
|
||||
long r;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
seq[i] = 0;
|
||||
|
||||
if (!fences[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seq[i] = fences[i]->seq;
|
||||
++num_rings;
|
||||
}
|
||||
|
||||
/* nothing to wait for ? */
|
||||
if (num_rings == 0)
|
||||
return -ENOENT;
|
||||
|
||||
r = amdgpu_fence_wait_seq_timeout(adev, seq, intr, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
if (signaled)
|
||||
return 0;
|
||||
else
|
||||
return -EDEADLK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -739,19 +412,12 @@ int amdgpu_fence_wait_any(struct amdgpu_device *adev,
|
|||
*/
|
||||
int amdgpu_fence_wait_next(struct amdgpu_ring *ring)
|
||||
{
|
||||
uint64_t seq[AMDGPU_MAX_RINGS] = {};
|
||||
long r;
|
||||
uint64_t seq = atomic64_read(&ring->fence_drv.last_seq) + 1ULL;
|
||||
|
||||
seq[ring->idx] = atomic64_read(&ring->fence_drv.last_seq) + 1ULL;
|
||||
if (seq[ring->idx] >= ring->fence_drv.sync_seq[ring->idx]) {
|
||||
/* nothing to wait for, last_seq is
|
||||
already the last emited fence */
|
||||
if (seq >= ring->fence_drv.sync_seq[ring->idx])
|
||||
return -ENOENT;
|
||||
}
|
||||
r = amdgpu_fence_wait_seq_timeout(ring->adev, seq, false, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 0;
|
||||
|
||||
return amdgpu_fence_ring_wait_seq(ring, seq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -766,23 +432,12 @@ int amdgpu_fence_wait_next(struct amdgpu_ring *ring)
|
|||
*/
|
||||
int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint64_t seq[AMDGPU_MAX_RINGS] = {};
|
||||
long r;
|
||||
uint64_t seq = ring->fence_drv.sync_seq[ring->idx];
|
||||
|
||||
seq[ring->idx] = ring->fence_drv.sync_seq[ring->idx];
|
||||
if (!seq[ring->idx])
|
||||
if (!seq)
|
||||
return 0;
|
||||
|
||||
r = amdgpu_fence_wait_seq_timeout(adev, seq, false, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0) {
|
||||
if (r == -EDEADLK)
|
||||
return -EDEADLK;
|
||||
|
||||
dev_err(adev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
|
||||
ring->idx, r);
|
||||
}
|
||||
return 0;
|
||||
return amdgpu_fence_ring_wait_seq(ring, seq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -933,9 +588,12 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
|
|||
ring->fence_drv.gpu_addr = adev->uvd.gpu_addr + index;
|
||||
}
|
||||
amdgpu_fence_write(ring, atomic64_read(&ring->fence_drv.last_seq));
|
||||
ring->fence_drv.initialized = true;
|
||||
amdgpu_irq_get(adev, irq_src, irq_type);
|
||||
|
||||
ring->fence_drv.irq_src = irq_src;
|
||||
ring->fence_drv.irq_type = irq_type;
|
||||
ring->fence_drv.initialized = true;
|
||||
|
||||
dev_info(adev->dev, "fence driver on ring %d use gpu addr 0x%016llx, "
|
||||
"cpu addr 0x%p\n", ring->idx,
|
||||
ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
|
||||
|
@ -966,6 +624,16 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
|
|||
INIT_DELAYED_WORK(&ring->fence_drv.lockup_work,
|
||||
amdgpu_fence_check_lockup);
|
||||
ring->fence_drv.ring = ring;
|
||||
|
||||
if (amdgpu_enable_scheduler) {
|
||||
ring->scheduler = amd_sched_create((void *)ring->adev,
|
||||
&amdgpu_sched_ops,
|
||||
ring->idx, 5, 0,
|
||||
amdgpu_sched_hw_submission);
|
||||
if (!ring->scheduler)
|
||||
DRM_ERROR("Failed to create scheduler on ring %d.\n",
|
||||
ring->idx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -982,7 +650,6 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
|
|||
*/
|
||||
int amdgpu_fence_driver_init(struct amdgpu_device *adev)
|
||||
{
|
||||
init_waitqueue_head(&adev->fence_queue);
|
||||
if (amdgpu_debugfs_fence_init(adev))
|
||||
dev_err(adev->dev, "fence debugfs file creation failed\n");
|
||||
|
||||
|
@ -1011,12 +678,77 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
|
|||
/* no need to trigger GPU reset as we are unloading */
|
||||
amdgpu_fence_driver_force_completion(adev);
|
||||
}
|
||||
wake_up_all(&adev->fence_queue);
|
||||
wake_up_all(&ring->fence_drv.fence_queue);
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
if (ring->scheduler)
|
||||
amd_sched_destroy(ring->scheduler);
|
||||
ring->fence_drv.initialized = false;
|
||||
}
|
||||
mutex_unlock(&adev->ring_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_driver_suspend - suspend the fence driver
|
||||
* for all possible rings.
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
*
|
||||
* Suspend the fence driver for all possible rings (all asics).
|
||||
*/
|
||||
void amdgpu_fence_driver_suspend(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
mutex_lock(&adev->ring_lock);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (!ring || !ring->fence_drv.initialized)
|
||||
continue;
|
||||
|
||||
/* wait for gpu to finish processing current batch */
|
||||
r = amdgpu_fence_wait_empty(ring);
|
||||
if (r) {
|
||||
/* delay GPU reset to resume */
|
||||
amdgpu_fence_driver_force_completion(adev);
|
||||
}
|
||||
|
||||
/* disable the interrupt */
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
}
|
||||
mutex_unlock(&adev->ring_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_driver_resume - resume the fence driver
|
||||
* for all possible rings.
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
*
|
||||
* Resume the fence driver for all possible rings (all asics).
|
||||
* Not all asics have all rings, so each asic will only
|
||||
* start the fence driver on the rings it has using
|
||||
* amdgpu_fence_driver_start_ring().
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
void amdgpu_fence_driver_resume(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&adev->ring_lock);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (!ring || !ring->fence_drv.initialized)
|
||||
continue;
|
||||
|
||||
/* enable the interrupt */
|
||||
amdgpu_irq_get(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
}
|
||||
mutex_unlock(&adev->ring_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_fence_driver_force_completion - force all fence waiter to complete
|
||||
*
|
||||
|
@ -1104,6 +836,22 @@ static inline bool amdgpu_test_signaled(struct amdgpu_fence *fence)
|
|||
return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
|
||||
}
|
||||
|
||||
static inline bool amdgpu_test_signaled_any(struct amdgpu_fence **fences)
|
||||
{
|
||||
int idx;
|
||||
struct amdgpu_fence *fence;
|
||||
|
||||
idx = 0;
|
||||
for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) {
|
||||
fence = fences[idx];
|
||||
if (fence) {
|
||||
if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct amdgpu_wait_cb {
|
||||
struct fence_cb base;
|
||||
struct task_struct *task;
|
||||
|
@ -1119,14 +867,35 @@ static void amdgpu_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
|
|||
static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,
|
||||
signed long t)
|
||||
{
|
||||
struct amdgpu_fence *array[AMDGPU_MAX_RINGS];
|
||||
struct amdgpu_fence *fence = to_amdgpu_fence(f);
|
||||
struct amdgpu_device *adev = fence->ring->adev;
|
||||
struct amdgpu_wait_cb cb;
|
||||
|
||||
cb.task = current;
|
||||
memset(&array[0], 0, sizeof(array));
|
||||
array[0] = fence;
|
||||
|
||||
if (fence_add_callback(f, &cb.base, amdgpu_fence_wait_cb))
|
||||
return t;
|
||||
return amdgpu_fence_wait_any(adev, array, intr, t);
|
||||
}
|
||||
|
||||
/* wait until any fence in array signaled */
|
||||
signed long amdgpu_fence_wait_any(struct amdgpu_device *adev,
|
||||
struct amdgpu_fence **array, bool intr, signed long t)
|
||||
{
|
||||
long idx = 0;
|
||||
struct amdgpu_wait_cb cb[AMDGPU_MAX_RINGS];
|
||||
struct amdgpu_fence *fence;
|
||||
|
||||
BUG_ON(!array);
|
||||
|
||||
for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) {
|
||||
fence = array[idx];
|
||||
if (fence) {
|
||||
cb[idx].task = current;
|
||||
if (fence_add_callback(&fence->base,
|
||||
&cb[idx].base, amdgpu_fence_wait_cb))
|
||||
return t; /* return if fence is already signaled */
|
||||
}
|
||||
}
|
||||
|
||||
while (t > 0) {
|
||||
if (intr)
|
||||
|
@ -1135,10 +904,10 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,
|
|||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
|
||||
/*
|
||||
* amdgpu_test_signaled must be called after
|
||||
* amdgpu_test_signaled_any must be called after
|
||||
* set_current_state to prevent a race with wake_up_process
|
||||
*/
|
||||
if (amdgpu_test_signaled(fence))
|
||||
if (amdgpu_test_signaled_any(array))
|
||||
break;
|
||||
|
||||
if (adev->needs_reset) {
|
||||
|
@ -1153,7 +922,13 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,
|
|||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
fence_remove_callback(f, &cb.base);
|
||||
|
||||
idx = 0;
|
||||
for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) {
|
||||
fence = array[idx];
|
||||
if (fence)
|
||||
fence_remove_callback(&fence->base, &cb[idx].base);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm,
|
|||
ib->fence = NULL;
|
||||
ib->user = NULL;
|
||||
ib->vm = vm;
|
||||
ib->ctx = NULL;
|
||||
ib->gds_base = 0;
|
||||
ib->gds_size = 0;
|
||||
ib->gws_base = 0;
|
||||
|
@ -142,6 +143,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
|
|||
struct amdgpu_ring *ring;
|
||||
struct amdgpu_ctx *ctx, *old_ctx;
|
||||
struct amdgpu_vm *vm;
|
||||
uint64_t sequence;
|
||||
unsigned i;
|
||||
int r = 0;
|
||||
|
||||
|
@ -165,9 +167,11 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
|
|||
|
||||
if (vm) {
|
||||
/* grab a vm id if necessary */
|
||||
struct amdgpu_fence *vm_id_fence = NULL;
|
||||
vm_id_fence = amdgpu_vm_grab_id(ibs->ring, ibs->vm);
|
||||
amdgpu_sync_fence(&ibs->sync, vm_id_fence);
|
||||
r = amdgpu_vm_grab_id(ibs->vm, ibs->ring, &ibs->sync);
|
||||
if (r) {
|
||||
amdgpu_ring_unlock_undo(ring);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_sync_rings(&ibs->sync, ring);
|
||||
|
@ -212,11 +216,18 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
|
|||
return r;
|
||||
}
|
||||
|
||||
sequence = amdgpu_enable_scheduler ? ib->sequence : 0;
|
||||
|
||||
if (!amdgpu_enable_scheduler && ib->ctx)
|
||||
ib->sequence = amdgpu_ctx_add_fence(ib->ctx, ring,
|
||||
&ib->fence->base,
|
||||
sequence);
|
||||
|
||||
/* wrap the last IB with fence */
|
||||
if (ib->user) {
|
||||
uint64_t addr = amdgpu_bo_gpu_offset(ib->user->bo);
|
||||
addr += ib->user->offset;
|
||||
amdgpu_ring_emit_fence(ring, addr, ib->fence->seq,
|
||||
amdgpu_ring_emit_fence(ring, addr, ib->sequence,
|
||||
AMDGPU_FENCE_FLAG_64BIT);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,8 @@ restart_ih:
|
|||
amdgpu_amdkfd_interrupt(adev,
|
||||
(const void *) &adev->irq.ih.ring[ring_index]);
|
||||
|
||||
entry.iv_entry = (const uint32_t *)
|
||||
&adev->irq.ih.ring[ring_index];
|
||||
amdgpu_ih_decode_iv(adev, &entry);
|
||||
adev->irq.ih.rptr &= adev->irq.ih.ptr_mask;
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ struct amdgpu_iv_entry {
|
|||
unsigned ring_id;
|
||||
unsigned vm_id;
|
||||
unsigned pas_id;
|
||||
const uint32_t *iv_entry;
|
||||
};
|
||||
|
||||
int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
|
||||
|
|
|
@ -272,6 +272,11 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
|
|||
|
||||
kfree(src->enabled_types);
|
||||
src->enabled_types = NULL;
|
||||
if (src->data) {
|
||||
kfree(src->data);
|
||||
kfree(src);
|
||||
adev->irq.sources[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ struct amdgpu_irq_src {
|
|||
unsigned num_types;
|
||||
atomic_t *enabled_types;
|
||||
const struct amdgpu_irq_src_funcs *funcs;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* provided by interrupt generating IP blocks */
|
||||
|
|
|
@ -96,8 +96,8 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
if ((amdgpu_runtime_pm != 0) &&
|
||||
amdgpu_has_atpx() &&
|
||||
((flags & AMDGPU_IS_APU) == 0))
|
||||
flags |= AMDGPU_IS_PX;
|
||||
((flags & AMD_IS_APU) == 0))
|
||||
flags |= AMD_IS_PX;
|
||||
|
||||
/* amdgpu_device_init should report only fatal error
|
||||
* like memory allocation failure or iomapping failure,
|
||||
|
@ -451,11 +451,11 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
|||
dev_info.num_hw_gfx_contexts = adev->gfx.config.max_hw_contexts;
|
||||
dev_info._pad = 0;
|
||||
dev_info.ids_flags = 0;
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
dev_info.ids_flags |= AMDGPU_IDS_FLAGS_FUSION;
|
||||
dev_info.virtual_address_offset = AMDGPU_VA_RESERVED_SIZE;
|
||||
dev_info.virtual_address_max = (uint64_t)adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
|
||||
dev_info.virtual_address_alignment = max(PAGE_SIZE, 0x10000UL);
|
||||
dev_info.virtual_address_alignment = max((int)PAGE_SIZE, AMDGPU_GPU_PAGE_SIZE);
|
||||
dev_info.pte_fragment_size = (1 << AMDGPU_LOG2_PAGES_PER_FRAG) *
|
||||
AMDGPU_GPU_PAGE_SIZE;
|
||||
dev_info.gart_page_size = AMDGPU_GPU_PAGE_SIZE;
|
||||
|
@ -527,10 +527,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
|
|||
mutex_init(&fpriv->bo_list_lock);
|
||||
idr_init(&fpriv->bo_list_handles);
|
||||
|
||||
/* init context manager */
|
||||
mutex_init(&fpriv->ctx_mgr.lock);
|
||||
idr_init(&fpriv->ctx_mgr.ctx_handles);
|
||||
fpriv->ctx_mgr.adev = adev;
|
||||
amdgpu_ctx_mgr_init(&fpriv->ctx_mgr);
|
||||
|
||||
file_priv->driver_priv = fpriv;
|
||||
|
||||
|
@ -571,8 +568,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
|||
idr_destroy(&fpriv->bo_list_handles);
|
||||
mutex_destroy(&fpriv->bo_list_lock);
|
||||
|
||||
/* release context */
|
||||
amdgpu_ctx_fini(fpriv);
|
||||
amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
|
||||
|
||||
kfree(fpriv);
|
||||
file_priv->driver_priv = NULL;
|
||||
|
|
|
@ -223,18 +223,6 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
|
|||
size_t acc_size;
|
||||
int r;
|
||||
|
||||
/* VI has a hw bug where VM PTEs have to be allocated in groups of 8.
|
||||
* do this as a temporary workaround
|
||||
*/
|
||||
if (!(domain & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA))) {
|
||||
if (adev->asic_type >= CHIP_TOPAZ) {
|
||||
if (byte_align & 0x7fff)
|
||||
byte_align = ALIGN(byte_align, 0x8000);
|
||||
if (size & 0x7fff)
|
||||
size = ALIGN(size, 0x8000);
|
||||
}
|
||||
}
|
||||
|
||||
page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
|
||||
|
@ -462,7 +450,7 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo)
|
|||
int amdgpu_bo_evict_vram(struct amdgpu_device *adev)
|
||||
{
|
||||
/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
|
||||
if (0 && (adev->flags & AMDGPU_IS_APU)) {
|
||||
if (0 && (adev->flags & AMD_IS_APU)) {
|
||||
/* Useless to evict on IGP chips */
|
||||
return 0;
|
||||
}
|
||||
|
@ -478,7 +466,6 @@ void amdgpu_bo_force_delete(struct amdgpu_device *adev)
|
|||
}
|
||||
dev_err(adev->dev, "Userspace still has active objects !\n");
|
||||
list_for_each_entry_safe(bo, n, &adev->gem.objects, list) {
|
||||
mutex_lock(&adev->ddev->struct_mutex);
|
||||
dev_err(adev->dev, "%p %p %lu %lu force free\n",
|
||||
&bo->gem_base, bo, (unsigned long)bo->gem_base.size,
|
||||
*((unsigned long *)&bo->gem_base.refcount));
|
||||
|
@ -486,8 +473,7 @@ void amdgpu_bo_force_delete(struct amdgpu_device *adev)
|
|||
list_del_init(&bo->list);
|
||||
mutex_unlock(&bo->adev->gem.mutex);
|
||||
/* this should unref the ttm bo */
|
||||
drm_gem_object_unreference(&bo->gem_base);
|
||||
mutex_unlock(&adev->ddev->struct_mutex);
|
||||
drm_gem_object_unreference_unlocked(&bo->gem_base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -658,13 +644,13 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
|
|||
* @shared: true if fence should be added shared
|
||||
*
|
||||
*/
|
||||
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct amdgpu_fence *fence,
|
||||
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence,
|
||||
bool shared)
|
||||
{
|
||||
struct reservation_object *resv = bo->tbo.resv;
|
||||
|
||||
if (shared)
|
||||
reservation_object_add_shared_fence(resv, &fence->base);
|
||||
reservation_object_add_shared_fence(resv, fence);
|
||||
else
|
||||
reservation_object_add_excl_fence(resv, &fence->base);
|
||||
reservation_object_add_excl_fence(resv, fence);
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
|
|||
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
|
||||
struct ttm_mem_reg *new_mem);
|
||||
int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
|
||||
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct amdgpu_fence *fence,
|
||||
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence,
|
||||
bool shared);
|
||||
|
||||
/*
|
||||
|
|
|
@ -82,7 +82,7 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,
|
|||
mutex_unlock(&adev->pm.mutex);
|
||||
|
||||
/* Can't set dpm state when the card is off */
|
||||
if (!(adev->flags & AMDGPU_IS_PX) ||
|
||||
if (!(adev->flags & AMD_IS_PX) ||
|
||||
(ddev->switch_power_state == DRM_SWITCH_POWER_ON))
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
fail:
|
||||
|
@ -538,7 +538,7 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
|
|||
/* vce just modifies an existing state so force a change */
|
||||
if (ps->vce_active != adev->pm.dpm.vce_active)
|
||||
goto force;
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
/* for APUs if the num crtcs changed but state is the same,
|
||||
* all we need to do is update the display configuration.
|
||||
*/
|
||||
|
@ -580,7 +580,6 @@ force:
|
|||
amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
|
||||
}
|
||||
|
||||
mutex_lock(&adev->ddev->struct_mutex);
|
||||
mutex_lock(&adev->ring_lock);
|
||||
|
||||
/* update whether vce is active */
|
||||
|
@ -628,7 +627,6 @@ force:
|
|||
|
||||
done:
|
||||
mutex_unlock(&adev->ring_lock);
|
||||
mutex_unlock(&adev->ddev->struct_mutex);
|
||||
}
|
||||
|
||||
void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
|
||||
|
|
|
@ -342,6 +342,8 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
|||
amdgpu_fence_driver_init_ring(ring);
|
||||
}
|
||||
|
||||
init_waitqueue_head(&ring->fence_drv.fence_queue);
|
||||
|
||||
r = amdgpu_wb_get(adev, &ring->rptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
|
||||
|
@ -367,7 +369,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
|||
}
|
||||
ring->next_rptr_gpu_addr = adev->wb.gpu_addr + (ring->next_rptr_offs * 4);
|
||||
ring->next_rptr_cpu_addr = &adev->wb.wb[ring->next_rptr_offs];
|
||||
|
||||
spin_lock_init(&ring->fence_lock);
|
||||
r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "failed initializing fences (%d).\n", r);
|
||||
|
|
|
@ -160,7 +160,8 @@ static void amdgpu_sa_bo_try_free(struct amdgpu_sa_manager *sa_manager)
|
|||
|
||||
sa_bo = list_entry(sa_manager->hole->next, struct amdgpu_sa_bo, olist);
|
||||
list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) {
|
||||
if (sa_bo->fence == NULL || !amdgpu_fence_signaled(sa_bo->fence)) {
|
||||
if (sa_bo->fence == NULL ||
|
||||
!fence_is_signaled(&sa_bo->fence->base)) {
|
||||
return;
|
||||
}
|
||||
amdgpu_sa_bo_remove_locked(sa_bo);
|
||||
|
@ -274,7 +275,7 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager,
|
|||
sa_bo = list_first_entry(&sa_manager->flist[i],
|
||||
struct amdgpu_sa_bo, flist);
|
||||
|
||||
if (!amdgpu_fence_signaled(sa_bo->fence)) {
|
||||
if (!fence_is_signaled(&sa_bo->fence->base)) {
|
||||
fences[i] = sa_bo->fence;
|
||||
continue;
|
||||
}
|
||||
|
@ -317,6 +318,7 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev,
|
|||
struct amdgpu_fence *fences[AMDGPU_MAX_RINGS];
|
||||
unsigned tries[AMDGPU_MAX_RINGS];
|
||||
int i, r;
|
||||
signed long t;
|
||||
|
||||
BUG_ON(align > sa_manager->align);
|
||||
BUG_ON(size > sa_manager->size);
|
||||
|
@ -350,7 +352,8 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev,
|
|||
} while (amdgpu_sa_bo_next_hole(sa_manager, fences, tries));
|
||||
|
||||
spin_unlock(&sa_manager->wq.lock);
|
||||
r = amdgpu_fence_wait_any(adev, fences, false);
|
||||
t = amdgpu_fence_wait_any(adev, fences, false, MAX_SCHEDULE_TIMEOUT);
|
||||
r = (t > 0) ? 0 : t;
|
||||
spin_lock(&sa_manager->wq.lock);
|
||||
/* if we have nothing to wait for block */
|
||||
if (r == -ENOENT) {
|
||||
|
@ -379,7 +382,7 @@ void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo,
|
|||
|
||||
sa_manager = (*sa_bo)->manager;
|
||||
spin_lock(&sa_manager->wq.lock);
|
||||
if (fence && !amdgpu_fence_signaled(fence)) {
|
||||
if (fence && !fence_is_signaled(&fence->base)) {
|
||||
(*sa_bo)->fence = amdgpu_fence_ref(fence);
|
||||
list_add_tail(&(*sa_bo)->flist,
|
||||
&sa_manager->flist[fence->ring->idx]);
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "amdgpu.h"
|
||||
|
||||
static int amdgpu_sched_prepare_job(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity,
|
||||
struct amd_sched_job *job)
|
||||
{
|
||||
int r = 0;
|
||||
struct amdgpu_cs_parser *sched_job;
|
||||
if (!job || !job->data) {
|
||||
DRM_ERROR("job is null\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sched_job = (struct amdgpu_cs_parser *)job->data;
|
||||
if (sched_job->prepare_job) {
|
||||
r = sched_job->prepare_job(sched_job);
|
||||
if (r) {
|
||||
DRM_ERROR("Prepare job error\n");
|
||||
schedule_work(&sched_job->job_work);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct fence *amdgpu_sched_run_job(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity,
|
||||
struct amd_sched_job *job)
|
||||
{
|
||||
int r = 0;
|
||||
struct amdgpu_cs_parser *sched_job;
|
||||
struct amdgpu_fence *fence;
|
||||
|
||||
if (!job || !job->data) {
|
||||
DRM_ERROR("job is null\n");
|
||||
return NULL;
|
||||
}
|
||||
sched_job = (struct amdgpu_cs_parser *)job->data;
|
||||
mutex_lock(&sched_job->job_lock);
|
||||
r = amdgpu_ib_schedule(sched_job->adev,
|
||||
sched_job->num_ibs,
|
||||
sched_job->ibs,
|
||||
sched_job->filp);
|
||||
if (r)
|
||||
goto err;
|
||||
fence = amdgpu_fence_ref(sched_job->ibs[sched_job->num_ibs - 1].fence);
|
||||
|
||||
if (sched_job->run_job) {
|
||||
r = sched_job->run_job(sched_job);
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_unlock(&sched_job->job_lock);
|
||||
return &fence->base;
|
||||
|
||||
err:
|
||||
DRM_ERROR("Run job error\n");
|
||||
mutex_unlock(&sched_job->job_lock);
|
||||
schedule_work(&sched_job->job_work);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void amdgpu_sched_process_job(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_job *job)
|
||||
{
|
||||
struct amdgpu_cs_parser *sched_job;
|
||||
|
||||
if (!job || !job->data) {
|
||||
DRM_ERROR("job is null\n");
|
||||
return;
|
||||
}
|
||||
sched_job = (struct amdgpu_cs_parser *)job->data;
|
||||
schedule_work(&sched_job->job_work);
|
||||
}
|
||||
|
||||
struct amd_sched_backend_ops amdgpu_sched_ops = {
|
||||
.prepare_job = amdgpu_sched_prepare_job,
|
||||
.run_job = amdgpu_sched_run_job,
|
||||
.process_job = amdgpu_sched_process_job
|
||||
};
|
||||
|
||||
int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring,
|
||||
struct amdgpu_ib *ibs,
|
||||
unsigned num_ibs,
|
||||
int (*free_job)(struct amdgpu_cs_parser *),
|
||||
void *owner,
|
||||
struct fence **f)
|
||||
{
|
||||
int r = 0;
|
||||
if (amdgpu_enable_scheduler) {
|
||||
struct amdgpu_cs_parser *sched_job =
|
||||
amdgpu_cs_parser_create(adev, owner, &adev->kernel_ctx,
|
||||
ibs, num_ibs);
|
||||
if(!sched_job) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
sched_job->free_job = free_job;
|
||||
mutex_lock(&sched_job->job_lock);
|
||||
r = amd_sched_push_job(ring->scheduler,
|
||||
&adev->kernel_ctx.rings[ring->idx].entity,
|
||||
sched_job, &sched_job->s_fence);
|
||||
if (r) {
|
||||
mutex_unlock(&sched_job->job_lock);
|
||||
kfree(sched_job);
|
||||
return r;
|
||||
}
|
||||
ibs[num_ibs - 1].sequence = sched_job->s_fence->v_seq;
|
||||
*f = fence_get(&sched_job->s_fence->base);
|
||||
mutex_unlock(&sched_job->job_lock);
|
||||
} else {
|
||||
r = amdgpu_ib_schedule(adev, num_ibs, ibs, owner);
|
||||
if (r)
|
||||
return r;
|
||||
*f = fence_get(&ibs[num_ibs - 1].fence->base);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -53,20 +53,24 @@ void amdgpu_sync_create(struct amdgpu_sync *sync)
|
|||
}
|
||||
|
||||
/**
|
||||
* amdgpu_sync_fence - use the semaphore to sync to a fence
|
||||
* amdgpu_sync_fence - remember to sync to this fence
|
||||
*
|
||||
* @sync: sync object to add fence to
|
||||
* @fence: fence to sync to
|
||||
*
|
||||
* Sync to the fence using the semaphore objects
|
||||
*/
|
||||
void amdgpu_sync_fence(struct amdgpu_sync *sync,
|
||||
struct amdgpu_fence *fence)
|
||||
int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync,
|
||||
struct fence *f)
|
||||
{
|
||||
struct amdgpu_fence *fence;
|
||||
struct amdgpu_fence *other;
|
||||
|
||||
if (!fence)
|
||||
return;
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
fence = to_amdgpu_fence(f);
|
||||
if (!fence || fence->ring->adev != adev)
|
||||
return fence_wait(f, true);
|
||||
|
||||
other = sync->sync_to[fence->ring->idx];
|
||||
sync->sync_to[fence->ring->idx] = amdgpu_fence_ref(
|
||||
|
@ -79,6 +83,8 @@ void amdgpu_sync_fence(struct amdgpu_sync *sync,
|
|||
amdgpu_fence_later(fence, other));
|
||||
amdgpu_fence_unref(&other);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,11 +112,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,
|
|||
|
||||
/* always sync to the exclusive fence */
|
||||
f = reservation_object_get_excl(resv);
|
||||
fence = f ? to_amdgpu_fence(f) : NULL;
|
||||
if (fence && fence->ring->adev == adev)
|
||||
amdgpu_sync_fence(sync, fence);
|
||||
else if (f)
|
||||
r = fence_wait(f, true);
|
||||
r = amdgpu_sync_fence(adev, sync, f);
|
||||
|
||||
flist = reservation_object_get_list(resv);
|
||||
if (!flist || r)
|
||||
|
@ -121,14 +123,26 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,
|
|||
reservation_object_held(resv));
|
||||
fence = f ? to_amdgpu_fence(f) : NULL;
|
||||
if (fence && fence->ring->adev == adev) {
|
||||
if (fence->owner != owner ||
|
||||
fence->owner == AMDGPU_FENCE_OWNER_UNDEFINED)
|
||||
amdgpu_sync_fence(sync, fence);
|
||||
} else if (f) {
|
||||
r = fence_wait(f, true);
|
||||
if (r)
|
||||
break;
|
||||
/* VM updates are only interesting
|
||||
* for other VM updates and moves.
|
||||
*/
|
||||
if ((owner != AMDGPU_FENCE_OWNER_MOVE) &&
|
||||
(fence->owner != AMDGPU_FENCE_OWNER_MOVE) &&
|
||||
((owner == AMDGPU_FENCE_OWNER_VM) !=
|
||||
(fence->owner == AMDGPU_FENCE_OWNER_VM)))
|
||||
continue;
|
||||
|
||||
/* Ignore fence from the same owner as
|
||||
* long as it isn't undefined.
|
||||
*/
|
||||
if (owner != AMDGPU_FENCE_OWNER_UNDEFINED &&
|
||||
fence->owner == owner)
|
||||
continue;
|
||||
}
|
||||
|
||||
r = amdgpu_sync_fence(adev, sync, f);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -164,9 +178,9 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (count >= AMDGPU_NUM_SYNCS) {
|
||||
if (amdgpu_enable_scheduler || (count >= AMDGPU_NUM_SYNCS)) {
|
||||
/* not enough room, wait manually */
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r)
|
||||
return r;
|
||||
continue;
|
||||
|
@ -186,7 +200,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
|
|||
if (!amdgpu_semaphore_emit_signal(other, semaphore)) {
|
||||
/* signaling wasn't successful wait manually */
|
||||
amdgpu_ring_undo(other);
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r)
|
||||
return r;
|
||||
continue;
|
||||
|
@ -196,7 +210,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
|
|||
if (!amdgpu_semaphore_emit_wait(ring, semaphore)) {
|
||||
/* waiting wasn't successful wait manually */
|
||||
amdgpu_ring_undo(other);
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r)
|
||||
return r;
|
||||
continue;
|
||||
|
|
|
@ -116,7 +116,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
|
|||
goto out_lclean_unpin;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i);
|
||||
goto out_lclean_unpin;
|
||||
|
@ -161,7 +161,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
|
|||
goto out_lclean_unpin;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(&fence->base, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i);
|
||||
goto out_lclean_unpin;
|
||||
|
@ -238,7 +238,7 @@ void amdgpu_test_moves(struct amdgpu_device *adev)
|
|||
|
||||
static int amdgpu_test_create_and_emit_fence(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
uint32_t handle = ring->idx ^ 0xdeafbeef;
|
||||
int r;
|
||||
|
@ -269,15 +269,16 @@ static int amdgpu_test_create_and_emit_fence(struct amdgpu_device *adev,
|
|||
DRM_ERROR("Failed to get dummy destroy msg\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct amdgpu_fence *a_fence = NULL;
|
||||
r = amdgpu_ring_lock(ring, 64);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to lock ring A %d\n", ring->idx);
|
||||
return r;
|
||||
}
|
||||
amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_UNDEFINED, fence);
|
||||
amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_UNDEFINED, &a_fence);
|
||||
amdgpu_ring_unlock_commit(ring);
|
||||
*fence = &a_fence->base;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
|||
struct amdgpu_ring *ringA,
|
||||
struct amdgpu_ring *ringB)
|
||||
{
|
||||
struct amdgpu_fence *fence1 = NULL, *fence2 = NULL;
|
||||
struct fence *fence1 = NULL, *fence2 = NULL;
|
||||
struct amdgpu_semaphore *semaphore = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -322,7 +323,7 @@ void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
|||
|
||||
mdelay(1000);
|
||||
|
||||
if (amdgpu_fence_signaled(fence1)) {
|
||||
if (fence_is_signaled(fence1)) {
|
||||
DRM_ERROR("Fence 1 signaled without waiting for semaphore.\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
@ -335,7 +336,7 @@ void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
|||
amdgpu_semaphore_emit_signal(ringB, semaphore);
|
||||
amdgpu_ring_unlock_commit(ringB);
|
||||
|
||||
r = amdgpu_fence_wait(fence1, false);
|
||||
r = fence_wait(fence1, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for sync fence 1\n");
|
||||
goto out_cleanup;
|
||||
|
@ -343,7 +344,7 @@ void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
|||
|
||||
mdelay(1000);
|
||||
|
||||
if (amdgpu_fence_signaled(fence2)) {
|
||||
if (fence_is_signaled(fence2)) {
|
||||
DRM_ERROR("Fence 2 signaled without waiting for semaphore.\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
@ -356,7 +357,7 @@ void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
|||
amdgpu_semaphore_emit_signal(ringB, semaphore);
|
||||
amdgpu_ring_unlock_commit(ringB);
|
||||
|
||||
r = amdgpu_fence_wait(fence2, false);
|
||||
r = fence_wait(fence2, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for sync fence 1\n");
|
||||
goto out_cleanup;
|
||||
|
@ -366,10 +367,10 @@ out_cleanup:
|
|||
amdgpu_semaphore_free(adev, &semaphore, NULL);
|
||||
|
||||
if (fence1)
|
||||
amdgpu_fence_unref(&fence1);
|
||||
fence_put(fence1);
|
||||
|
||||
if (fence2)
|
||||
amdgpu_fence_unref(&fence2);
|
||||
fence_put(fence2);
|
||||
|
||||
if (r)
|
||||
printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);
|
||||
|
@ -380,7 +381,7 @@ static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
|
|||
struct amdgpu_ring *ringB,
|
||||
struct amdgpu_ring *ringC)
|
||||
{
|
||||
struct amdgpu_fence *fenceA = NULL, *fenceB = NULL;
|
||||
struct fence *fenceA = NULL, *fenceB = NULL;
|
||||
struct amdgpu_semaphore *semaphore = NULL;
|
||||
bool sigA, sigB;
|
||||
int i, r;
|
||||
|
@ -416,11 +417,11 @@ static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
|
|||
|
||||
mdelay(1000);
|
||||
|
||||
if (amdgpu_fence_signaled(fenceA)) {
|
||||
if (fence_is_signaled(fenceA)) {
|
||||
DRM_ERROR("Fence A signaled without waiting for semaphore.\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
if (amdgpu_fence_signaled(fenceB)) {
|
||||
if (fence_is_signaled(fenceB)) {
|
||||
DRM_ERROR("Fence B signaled without waiting for semaphore.\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
@ -435,8 +436,8 @@ static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
|
|||
|
||||
for (i = 0; i < 30; ++i) {
|
||||
mdelay(100);
|
||||
sigA = amdgpu_fence_signaled(fenceA);
|
||||
sigB = amdgpu_fence_signaled(fenceB);
|
||||
sigA = fence_is_signaled(fenceA);
|
||||
sigB = fence_is_signaled(fenceB);
|
||||
if (sigA || sigB)
|
||||
break;
|
||||
}
|
||||
|
@ -461,12 +462,12 @@ static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
|
|||
|
||||
mdelay(1000);
|
||||
|
||||
r = amdgpu_fence_wait(fenceA, false);
|
||||
r = fence_wait(fenceA, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for sync fence A\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
r = amdgpu_fence_wait(fenceB, false);
|
||||
r = fence_wait(fenceB, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to wait for sync fence B\n");
|
||||
goto out_cleanup;
|
||||
|
@ -476,10 +477,10 @@ out_cleanup:
|
|||
amdgpu_semaphore_free(adev, &semaphore, NULL);
|
||||
|
||||
if (fenceA)
|
||||
amdgpu_fence_unref(&fenceA);
|
||||
fence_put(fenceA);
|
||||
|
||||
if (fenceB)
|
||||
amdgpu_fence_unref(&fenceB);
|
||||
fence_put(fenceB);
|
||||
|
||||
if (r)
|
||||
printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#endif
|
||||
#define FIRMWARE_TONGA "amdgpu/tonga_uvd.bin"
|
||||
#define FIRMWARE_CARRIZO "amdgpu/carrizo_uvd.bin"
|
||||
#define FIRMWARE_FIJI "amdgpu/fiji_uvd.bin"
|
||||
|
||||
/**
|
||||
* amdgpu_uvd_cs_ctx - Command submission parser context
|
||||
|
@ -81,6 +82,7 @@ MODULE_FIRMWARE(FIRMWARE_MULLINS);
|
|||
#endif
|
||||
MODULE_FIRMWARE(FIRMWARE_TONGA);
|
||||
MODULE_FIRMWARE(FIRMWARE_CARRIZO);
|
||||
MODULE_FIRMWARE(FIRMWARE_FIJI);
|
||||
|
||||
static void amdgpu_uvd_note_usage(struct amdgpu_device *adev);
|
||||
static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
|
||||
|
@ -116,6 +118,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
|
|||
case CHIP_TONGA:
|
||||
fw_name = FIRMWARE_TONGA;
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
fw_name = FIRMWARE_FIJI;
|
||||
break;
|
||||
case CHIP_CARRIZO:
|
||||
fw_name = FIRMWARE_CARRIZO;
|
||||
break;
|
||||
|
@ -283,7 +288,7 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
|
|||
for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
|
||||
uint32_t handle = atomic_read(&adev->uvd.handles[i]);
|
||||
if (handle != 0 && adev->uvd.filp[i] == filp) {
|
||||
struct amdgpu_fence *fence;
|
||||
struct fence *fence;
|
||||
|
||||
amdgpu_uvd_note_usage(adev);
|
||||
|
||||
|
@ -293,8 +298,8 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
|
|||
continue;
|
||||
}
|
||||
|
||||
amdgpu_fence_wait(fence, false);
|
||||
amdgpu_fence_unref(&fence);
|
||||
fence_wait(fence, false);
|
||||
fence_put(fence);
|
||||
|
||||
adev->uvd.filp[i] = NULL;
|
||||
atomic_set(&adev->uvd.handles[i], 0);
|
||||
|
@ -374,7 +379,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
|
|||
unsigned height_in_mb = ALIGN(height / 16, 2);
|
||||
unsigned fs_in_mb = width_in_mb * height_in_mb;
|
||||
|
||||
unsigned image_size, tmp, min_dpb_size, num_dpb_buffer, min_ctx_size;
|
||||
unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
|
||||
unsigned min_ctx_size = 0;
|
||||
|
||||
image_size = width * height;
|
||||
image_size += image_size / 2;
|
||||
|
@ -507,28 +513,25 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx,
|
|||
{
|
||||
struct amdgpu_device *adev = ctx->parser->adev;
|
||||
int32_t *msg, msg_type, handle;
|
||||
struct fence *f;
|
||||
void *ptr;
|
||||
|
||||
int i, r;
|
||||
long r;
|
||||
int i;
|
||||
|
||||
if (offset & 0x3F) {
|
||||
DRM_ERROR("UVD messages must be 64 byte aligned!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f = reservation_object_get_excl(bo->tbo.resv);
|
||||
if (f) {
|
||||
r = amdgpu_fence_wait((struct amdgpu_fence *)f, false);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
|
||||
return r;
|
||||
}
|
||||
r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0) {
|
||||
DRM_ERROR("Failed waiting for UVD message (%ld)!\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_kmap(bo, &ptr);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
|
||||
DRM_ERROR("Failed mapping the UVD message (%ld)!\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -803,14 +806,24 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_uvd_free_job(
|
||||
struct amdgpu_cs_parser *sched_job)
|
||||
{
|
||||
amdgpu_ib_free(sched_job->adev, sched_job->ibs);
|
||||
kfree(sched_job->ibs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring,
|
||||
struct amdgpu_bo *bo,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
struct ttm_validate_buffer tv;
|
||||
struct ww_acquire_ctx ticket;
|
||||
struct list_head head;
|
||||
struct amdgpu_ib ib;
|
||||
struct amdgpu_ib *ib = NULL;
|
||||
struct fence *f = NULL;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint64_t addr;
|
||||
int i, r;
|
||||
|
||||
|
@ -832,34 +845,49 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring,
|
|||
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, 64, &ib);
|
||||
if (r)
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
r = amdgpu_ib_get(ring, NULL, 64, ib);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
addr = amdgpu_bo_gpu_offset(bo);
|
||||
ib.ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0);
|
||||
ib.ptr[1] = addr;
|
||||
ib.ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0);
|
||||
ib.ptr[3] = addr >> 32;
|
||||
ib.ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
|
||||
ib.ptr[5] = 0;
|
||||
ib->ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0);
|
||||
ib->ptr[1] = addr;
|
||||
ib->ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0);
|
||||
ib->ptr[3] = addr >> 32;
|
||||
ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
|
||||
ib->ptr[5] = 0;
|
||||
for (i = 6; i < 16; ++i)
|
||||
ib.ptr[i] = PACKET2(0);
|
||||
ib.length_dw = 16;
|
||||
ib->ptr[i] = PACKET2(0);
|
||||
ib->length_dw = 16;
|
||||
|
||||
r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_uvd_free_job,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err;
|
||||
ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base);
|
||||
goto err2;
|
||||
|
||||
ttm_eu_fence_buffer_objects(&ticket, &head, f);
|
||||
|
||||
if (fence)
|
||||
*fence = amdgpu_fence_ref(ib.fence);
|
||||
|
||||
amdgpu_ib_free(ring->adev, &ib);
|
||||
*fence = fence_get(f);
|
||||
amdgpu_bo_unref(&bo);
|
||||
return 0;
|
||||
fence_put(f);
|
||||
if (amdgpu_enable_scheduler)
|
||||
return 0;
|
||||
|
||||
amdgpu_ib_free(ring->adev, ib);
|
||||
kfree(ib);
|
||||
return 0;
|
||||
err2:
|
||||
amdgpu_ib_free(ring->adev, ib);
|
||||
err1:
|
||||
kfree(ib);
|
||||
err:
|
||||
ttm_eu_backoff_reservation(&ticket, &head);
|
||||
return r;
|
||||
|
@ -869,7 +897,7 @@ err:
|
|||
crash the vcpu so just try to emmit a dummy create/destroy msg to
|
||||
avoid this */
|
||||
int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_bo *bo;
|
||||
|
@ -916,7 +944,7 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
|||
}
|
||||
|
||||
int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_bo *bo;
|
||||
|
|
|
@ -29,9 +29,9 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev);
|
|||
int amdgpu_uvd_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_uvd_resume(struct amdgpu_device *adev);
|
||||
int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence);
|
||||
struct fence **fence);
|
||||
int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence);
|
||||
struct fence **fence);
|
||||
void amdgpu_uvd_free_handles(struct amdgpu_device *adev,
|
||||
struct drm_file *filp);
|
||||
int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#endif
|
||||
#define FIRMWARE_TONGA "amdgpu/tonga_vce.bin"
|
||||
#define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin"
|
||||
#define FIRMWARE_FIJI "amdgpu/fiji_vce.bin"
|
||||
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
MODULE_FIRMWARE(FIRMWARE_BONAIRE);
|
||||
|
@ -58,6 +59,7 @@ MODULE_FIRMWARE(FIRMWARE_MULLINS);
|
|||
#endif
|
||||
MODULE_FIRMWARE(FIRMWARE_TONGA);
|
||||
MODULE_FIRMWARE(FIRMWARE_CARRIZO);
|
||||
MODULE_FIRMWARE(FIRMWARE_FIJI);
|
||||
|
||||
static void amdgpu_vce_idle_work_handler(struct work_struct *work);
|
||||
|
||||
|
@ -101,6 +103,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
|
|||
case CHIP_CARRIZO:
|
||||
fw_name = FIRMWARE_CARRIZO;
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
fw_name = FIRMWARE_FIJI;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -334,6 +339,14 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
|
|||
}
|
||||
}
|
||||
|
||||
static int amdgpu_vce_free_job(
|
||||
struct amdgpu_cs_parser *sched_job)
|
||||
{
|
||||
amdgpu_ib_free(sched_job->adev, sched_job->ibs);
|
||||
kfree(sched_job->ibs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vce_get_create_msg - generate a VCE create msg
|
||||
*
|
||||
|
@ -345,59 +358,69 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
|
|||
* Open up a stream for HW test
|
||||
*/
|
||||
int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
const unsigned ib_size_dw = 1024;
|
||||
struct amdgpu_ib ib;
|
||||
struct amdgpu_ib *ib = NULL;
|
||||
struct fence *f = NULL;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint64_t dummy;
|
||||
int i, r;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib)
|
||||
return -ENOMEM;
|
||||
r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, ib);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
dummy = ib.gpu_addr + 1024;
|
||||
dummy = ib->gpu_addr + 1024;
|
||||
|
||||
/* stitch together an VCE create msg */
|
||||
ib.length_dw = 0;
|
||||
ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
|
||||
ib.ptr[ib.length_dw++] = handle;
|
||||
ib->length_dw = 0;
|
||||
ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
|
||||
ib->ptr[ib->length_dw++] = handle;
|
||||
|
||||
ib.ptr[ib.length_dw++] = 0x00000030; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
|
||||
ib.ptr[ib.length_dw++] = 0x00000000;
|
||||
ib.ptr[ib.length_dw++] = 0x00000042;
|
||||
ib.ptr[ib.length_dw++] = 0x0000000a;
|
||||
ib.ptr[ib.length_dw++] = 0x00000001;
|
||||
ib.ptr[ib.length_dw++] = 0x00000080;
|
||||
ib.ptr[ib.length_dw++] = 0x00000060;
|
||||
ib.ptr[ib.length_dw++] = 0x00000100;
|
||||
ib.ptr[ib.length_dw++] = 0x00000100;
|
||||
ib.ptr[ib.length_dw++] = 0x0000000c;
|
||||
ib.ptr[ib.length_dw++] = 0x00000000;
|
||||
ib->ptr[ib->length_dw++] = 0x00000030; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
|
||||
ib->ptr[ib->length_dw++] = 0x00000000;
|
||||
ib->ptr[ib->length_dw++] = 0x00000042;
|
||||
ib->ptr[ib->length_dw++] = 0x0000000a;
|
||||
ib->ptr[ib->length_dw++] = 0x00000001;
|
||||
ib->ptr[ib->length_dw++] = 0x00000080;
|
||||
ib->ptr[ib->length_dw++] = 0x00000060;
|
||||
ib->ptr[ib->length_dw++] = 0x00000100;
|
||||
ib->ptr[ib->length_dw++] = 0x00000100;
|
||||
ib->ptr[ib->length_dw++] = 0x0000000c;
|
||||
ib->ptr[ib->length_dw++] = 0x00000000;
|
||||
|
||||
ib.ptr[ib.length_dw++] = 0x00000014; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
|
||||
ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
|
||||
ib.ptr[ib.length_dw++] = dummy;
|
||||
ib.ptr[ib.length_dw++] = 0x00000001;
|
||||
ib->ptr[ib->length_dw++] = 0x00000014; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(dummy);
|
||||
ib->ptr[ib->length_dw++] = dummy;
|
||||
ib->ptr[ib->length_dw++] = 0x00000001;
|
||||
|
||||
for (i = ib.length_dw; i < ib_size_dw; ++i)
|
||||
ib.ptr[i] = 0x0;
|
||||
|
||||
r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
}
|
||||
for (i = ib->length_dw; i < ib_size_dw; ++i)
|
||||
ib->ptr[i] = 0x0;
|
||||
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_vce_free_job,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err;
|
||||
if (fence)
|
||||
*fence = amdgpu_fence_ref(ib.fence);
|
||||
|
||||
amdgpu_ib_free(ring->adev, &ib);
|
||||
|
||||
*fence = fence_get(f);
|
||||
fence_put(f);
|
||||
if (amdgpu_enable_scheduler)
|
||||
return 0;
|
||||
err:
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -412,49 +435,59 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
|||
* Close up a stream for HW test or if userspace failed to do so
|
||||
*/
|
||||
int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
const unsigned ib_size_dw = 1024;
|
||||
struct amdgpu_ib ib;
|
||||
struct amdgpu_ib *ib = NULL;
|
||||
struct fence *f = NULL;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint64_t dummy;
|
||||
int i, r;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib)
|
||||
return -ENOMEM;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, ib);
|
||||
if (r) {
|
||||
kfree(ib);
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
dummy = ib.gpu_addr + 1024;
|
||||
dummy = ib->gpu_addr + 1024;
|
||||
|
||||
/* stitch together an VCE destroy msg */
|
||||
ib.length_dw = 0;
|
||||
ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
|
||||
ib.ptr[ib.length_dw++] = handle;
|
||||
ib->length_dw = 0;
|
||||
ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
|
||||
ib->ptr[ib->length_dw++] = handle;
|
||||
|
||||
ib.ptr[ib.length_dw++] = 0x00000014; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
|
||||
ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
|
||||
ib.ptr[ib.length_dw++] = dummy;
|
||||
ib.ptr[ib.length_dw++] = 0x00000001;
|
||||
ib->ptr[ib->length_dw++] = 0x00000014; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(dummy);
|
||||
ib->ptr[ib->length_dw++] = dummy;
|
||||
ib->ptr[ib->length_dw++] = 0x00000001;
|
||||
|
||||
ib.ptr[ib.length_dw++] = 0x00000008; /* len */
|
||||
ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
|
||||
|
||||
for (i = ib.length_dw; i < ib_size_dw; ++i)
|
||||
ib.ptr[i] = 0x0;
|
||||
|
||||
r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
}
|
||||
ib->ptr[ib->length_dw++] = 0x00000008; /* len */
|
||||
ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */
|
||||
|
||||
for (i = ib->length_dw; i < ib_size_dw; ++i)
|
||||
ib->ptr[i] = 0x0;
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_vce_free_job,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err;
|
||||
if (fence)
|
||||
*fence = amdgpu_fence_ref(ib.fence);
|
||||
|
||||
amdgpu_ib_free(ring->adev, &ib);
|
||||
|
||||
*fence = fence_get(f);
|
||||
fence_put(f);
|
||||
if (amdgpu_enable_scheduler)
|
||||
return 0;
|
||||
err:
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -800,7 +833,7 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
|
|||
*/
|
||||
int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_fence *fence = NULL;
|
||||
struct fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
r = amdgpu_vce_get_create_msg(ring, 1, NULL);
|
||||
|
@ -815,13 +848,13 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)
|
|||
goto error;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(fence, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
} else {
|
||||
DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
|
||||
}
|
||||
error:
|
||||
amdgpu_fence_unref(&fence);
|
||||
fence_put(fence);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev);
|
|||
int amdgpu_vce_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_vce_resume(struct amdgpu_device *adev);
|
||||
int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence);
|
||||
struct fence **fence);
|
||||
int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
|
||||
struct amdgpu_fence **fence);
|
||||
struct fence **fence);
|
||||
void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
|
||||
int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
|
||||
bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring,
|
||||
|
|
|
@ -127,16 +127,16 @@ struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
|
|||
/**
|
||||
* amdgpu_vm_grab_id - allocate the next free VMID
|
||||
*
|
||||
* @ring: ring we want to submit job to
|
||||
* @vm: vm to allocate id for
|
||||
* @ring: ring we want to submit job to
|
||||
* @sync: sync object where we add dependencies
|
||||
*
|
||||
* Allocate an id for the vm (cayman+).
|
||||
* Returns the fence we need to sync to (if any).
|
||||
* Allocate an id for the vm, adding fences to the sync obj as necessary.
|
||||
*
|
||||
* Global and local mutex must be locked!
|
||||
* Global mutex must be locked!
|
||||
*/
|
||||
struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
|
||||
struct amdgpu_vm *vm)
|
||||
int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
||||
struct amdgpu_sync *sync)
|
||||
{
|
||||
struct amdgpu_fence *best[AMDGPU_MAX_RINGS] = {};
|
||||
struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
|
||||
|
@ -148,7 +148,7 @@ struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
|
|||
/* check if the id is still valid */
|
||||
if (vm_id->id && vm_id->last_id_use &&
|
||||
vm_id->last_id_use == adev->vm_manager.active[vm_id->id])
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
/* we definately need to flush */
|
||||
vm_id->pd_gpu_addr = ~0ll;
|
||||
|
@ -161,7 +161,7 @@ struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
|
|||
/* found a free one */
|
||||
vm_id->id = i;
|
||||
trace_amdgpu_vm_grab_id(i, ring->idx);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (amdgpu_fence_is_earlier(fence, best[fence->ring->idx])) {
|
||||
|
@ -172,15 +172,19 @@ struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
|
|||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (choices[i]) {
|
||||
struct amdgpu_fence *fence;
|
||||
|
||||
fence = adev->vm_manager.active[choices[i]];
|
||||
vm_id->id = choices[i];
|
||||
|
||||
trace_amdgpu_vm_grab_id(choices[i], ring->idx);
|
||||
return adev->vm_manager.active[choices[i]];
|
||||
return amdgpu_sync_fence(ring->adev, sync, &fence->base);
|
||||
}
|
||||
}
|
||||
|
||||
/* should never happen */
|
||||
BUG();
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,13 +204,15 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring,
|
|||
{
|
||||
uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory);
|
||||
struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
|
||||
struct amdgpu_fence *flushed_updates = vm_id->flushed_updates;
|
||||
|
||||
if (pd_addr != vm_id->pd_gpu_addr || !vm_id->flushed_updates ||
|
||||
amdgpu_fence_is_earlier(vm_id->flushed_updates, updates)) {
|
||||
if (pd_addr != vm_id->pd_gpu_addr || !flushed_updates ||
|
||||
(updates && amdgpu_fence_is_earlier(flushed_updates, updates))) {
|
||||
|
||||
trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id);
|
||||
amdgpu_fence_unref(&vm_id->flushed_updates);
|
||||
vm_id->flushed_updates = amdgpu_fence_ref(updates);
|
||||
vm_id->flushed_updates = amdgpu_fence_ref(
|
||||
amdgpu_fence_later(flushed_updates, updates));
|
||||
amdgpu_fence_unref(&flushed_updates);
|
||||
vm_id->pd_gpu_addr = pd_addr;
|
||||
amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr);
|
||||
}
|
||||
|
@ -300,6 +306,16 @@ static void amdgpu_vm_update_pages(struct amdgpu_device *adev,
|
|||
}
|
||||
}
|
||||
|
||||
static int amdgpu_vm_free_job(
|
||||
struct amdgpu_cs_parser *sched_job)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sched_job->num_ibs; i++)
|
||||
amdgpu_ib_free(sched_job->adev, &sched_job->ibs[i]);
|
||||
kfree(sched_job->ibs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_clear_bo - initially clear the page dir/table
|
||||
*
|
||||
|
@ -310,7 +326,8 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
|
|||
struct amdgpu_bo *bo)
|
||||
{
|
||||
struct amdgpu_ring *ring = adev->vm_manager.vm_pte_funcs_ring;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *fence = NULL;
|
||||
struct amdgpu_ib *ib;
|
||||
unsigned entries;
|
||||
uint64_t addr;
|
||||
int r;
|
||||
|
@ -330,24 +347,33 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
|
|||
addr = amdgpu_bo_gpu_offset(bo);
|
||||
entries = amdgpu_bo_size(bo) / 8;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, &ib);
|
||||
if (r)
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib)
|
||||
goto error_unreserve;
|
||||
|
||||
ib.length_dw = 0;
|
||||
|
||||
amdgpu_vm_update_pages(adev, &ib, addr, 0, entries, 0, 0, 0);
|
||||
amdgpu_vm_pad_ib(adev, &ib);
|
||||
WARN_ON(ib.length_dw > 64);
|
||||
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
|
||||
r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, ib);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
amdgpu_bo_fence(bo, ib.fence, true);
|
||||
ib->length_dw = 0;
|
||||
|
||||
amdgpu_vm_update_pages(adev, ib, addr, 0, entries, 0, 0, 0);
|
||||
amdgpu_vm_pad_ib(adev, ib);
|
||||
WARN_ON(ib->length_dw > 64);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_vm_free_job,
|
||||
AMDGPU_FENCE_OWNER_VM,
|
||||
&fence);
|
||||
if (!r)
|
||||
amdgpu_bo_fence(bo, fence, true);
|
||||
fence_put(fence);
|
||||
if (amdgpu_enable_scheduler) {
|
||||
amdgpu_bo_unreserve(bo);
|
||||
return 0;
|
||||
}
|
||||
error_free:
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
|
||||
error_unreserve:
|
||||
amdgpu_bo_unreserve(bo);
|
||||
|
@ -400,7 +426,9 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
|||
uint32_t incr = AMDGPU_VM_PTE_COUNT * 8;
|
||||
uint64_t last_pde = ~0, last_pt = ~0;
|
||||
unsigned count = 0, pt_idx, ndw;
|
||||
struct amdgpu_ib ib;
|
||||
struct amdgpu_ib *ib;
|
||||
struct fence *fence = NULL;
|
||||
|
||||
int r;
|
||||
|
||||
/* padding, etc. */
|
||||
|
@ -413,10 +441,14 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
|||
if (ndw > 0xfffff)
|
||||
return -ENOMEM;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ndw * 4, &ib);
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib)
|
||||
return -ENOMEM;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ndw * 4, ib);
|
||||
if (r)
|
||||
return r;
|
||||
ib.length_dw = 0;
|
||||
ib->length_dw = 0;
|
||||
|
||||
/* walk over the address space and update the page directory */
|
||||
for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
|
||||
|
@ -436,7 +468,7 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
|||
((last_pt + incr * count) != pt)) {
|
||||
|
||||
if (count) {
|
||||
amdgpu_vm_update_pages(adev, &ib, last_pde,
|
||||
amdgpu_vm_update_pages(adev, ib, last_pde,
|
||||
last_pt, count, incr,
|
||||
AMDGPU_PTE_VALID, 0);
|
||||
}
|
||||
|
@ -450,23 +482,37 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
if (count)
|
||||
amdgpu_vm_update_pages(adev, &ib, last_pde, last_pt, count,
|
||||
amdgpu_vm_update_pages(adev, ib, last_pde, last_pt, count,
|
||||
incr, AMDGPU_PTE_VALID, 0);
|
||||
|
||||
if (ib.length_dw != 0) {
|
||||
amdgpu_vm_pad_ib(adev, &ib);
|
||||
amdgpu_sync_resv(adev, &ib.sync, pd->tbo.resv, AMDGPU_FENCE_OWNER_VM);
|
||||
WARN_ON(ib.length_dw > ndw);
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
return r;
|
||||
}
|
||||
amdgpu_bo_fence(pd, ib.fence, true);
|
||||
if (ib->length_dw != 0) {
|
||||
amdgpu_vm_pad_ib(adev, ib);
|
||||
amdgpu_sync_resv(adev, &ib->sync, pd->tbo.resv, AMDGPU_FENCE_OWNER_VM);
|
||||
WARN_ON(ib->length_dw > ndw);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_vm_free_job,
|
||||
AMDGPU_FENCE_OWNER_VM,
|
||||
&fence);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
amdgpu_bo_fence(pd, fence, true);
|
||||
fence_put(vm->page_directory_fence);
|
||||
vm->page_directory_fence = fence_get(fence);
|
||||
fence_put(fence);
|
||||
}
|
||||
|
||||
if (!amdgpu_enable_scheduler || ib->length_dw == 0) {
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
}
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -640,7 +686,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,
|
|||
*/
|
||||
static void amdgpu_vm_fence_pts(struct amdgpu_vm *vm,
|
||||
uint64_t start, uint64_t end,
|
||||
struct amdgpu_fence *fence)
|
||||
struct fence *fence)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
|
@ -670,12 +716,13 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
|
|||
struct amdgpu_vm *vm,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t addr, uint32_t gtt_flags,
|
||||
struct amdgpu_fence **fence)
|
||||
struct fence **fence)
|
||||
{
|
||||
struct amdgpu_ring *ring = adev->vm_manager.vm_pte_funcs_ring;
|
||||
unsigned nptes, ncmds, ndw;
|
||||
uint32_t flags = gtt_flags;
|
||||
struct amdgpu_ib ib;
|
||||
struct amdgpu_ib *ib;
|
||||
struct fence *f = NULL;
|
||||
int r;
|
||||
|
||||
/* normally,bo_va->flags only contians READABLE and WIRTEABLE bit go here
|
||||
|
@ -722,46 +769,65 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
|
|||
if (ndw > 0xfffff)
|
||||
return -ENOMEM;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ndw * 4, &ib);
|
||||
if (r)
|
||||
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
|
||||
if (!ib)
|
||||
return -ENOMEM;
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, ndw * 4, ib);
|
||||
if (r) {
|
||||
kfree(ib);
|
||||
return r;
|
||||
ib.length_dw = 0;
|
||||
}
|
||||
|
||||
ib->length_dw = 0;
|
||||
|
||||
if (!(flags & AMDGPU_PTE_VALID)) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_fence *f = vm->ids[i].last_id_use;
|
||||
amdgpu_sync_fence(&ib.sync, f);
|
||||
r = amdgpu_sync_fence(adev, &ib->sync, &f->base);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_vm_update_ptes(adev, vm, &ib, mapping->it.start,
|
||||
r = amdgpu_vm_update_ptes(adev, vm, ib, mapping->it.start,
|
||||
mapping->it.last + 1, addr + mapping->offset,
|
||||
flags, gtt_flags);
|
||||
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
amdgpu_vm_pad_ib(adev, &ib);
|
||||
WARN_ON(ib.length_dw > ndw);
|
||||
amdgpu_vm_pad_ib(adev, ib);
|
||||
WARN_ON(ib->length_dw > ndw);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1,
|
||||
&amdgpu_vm_free_job,
|
||||
AMDGPU_FENCE_OWNER_VM,
|
||||
&f);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
return r;
|
||||
}
|
||||
amdgpu_vm_fence_pts(vm, mapping->it.start,
|
||||
mapping->it.last + 1, ib.fence);
|
||||
mapping->it.last + 1, f);
|
||||
if (fence) {
|
||||
amdgpu_fence_unref(fence);
|
||||
*fence = amdgpu_fence_ref(ib.fence);
|
||||
fence_put(*fence);
|
||||
*fence = fence_get(f);
|
||||
}
|
||||
fence_put(f);
|
||||
if (!amdgpu_enable_scheduler) {
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
}
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
amdgpu_ib_free(adev, ib);
|
||||
kfree(ib);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -794,21 +860,25 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev,
|
|||
addr = 0;
|
||||
}
|
||||
|
||||
if (addr == bo_va->addr)
|
||||
return 0;
|
||||
|
||||
flags = amdgpu_ttm_tt_pte_flags(adev, bo_va->bo->tbo.ttm, mem);
|
||||
|
||||
list_for_each_entry(mapping, &bo_va->mappings, list) {
|
||||
spin_lock(&vm->status_lock);
|
||||
if (!list_empty(&bo_va->vm_status))
|
||||
list_splice_init(&bo_va->valids, &bo_va->invalids);
|
||||
spin_unlock(&vm->status_lock);
|
||||
|
||||
list_for_each_entry(mapping, &bo_va->invalids, list) {
|
||||
r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, addr,
|
||||
flags, &bo_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
bo_va->addr = addr;
|
||||
spin_lock(&vm->status_lock);
|
||||
list_splice_init(&bo_va->invalids, &bo_va->valids);
|
||||
list_del_init(&bo_va->vm_status);
|
||||
if (!mem)
|
||||
list_add(&bo_va->vm_status, &vm->cleared);
|
||||
spin_unlock(&vm->status_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -861,7 +931,7 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
|
|||
struct amdgpu_vm *vm, struct amdgpu_sync *sync)
|
||||
{
|
||||
struct amdgpu_bo_va *bo_va = NULL;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
spin_lock(&vm->status_lock);
|
||||
while (!list_empty(&vm->invalidated)) {
|
||||
|
@ -878,8 +948,9 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
|
|||
spin_unlock(&vm->status_lock);
|
||||
|
||||
if (bo_va)
|
||||
amdgpu_sync_fence(sync, bo_va->last_pt_update);
|
||||
return 0;
|
||||
r = amdgpu_sync_fence(adev, sync, bo_va->last_pt_update);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -907,10 +978,10 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
|
|||
}
|
||||
bo_va->vm = vm;
|
||||
bo_va->bo = bo;
|
||||
bo_va->addr = 0;
|
||||
bo_va->ref_count = 1;
|
||||
INIT_LIST_HEAD(&bo_va->bo_list);
|
||||
INIT_LIST_HEAD(&bo_va->mappings);
|
||||
INIT_LIST_HEAD(&bo_va->valids);
|
||||
INIT_LIST_HEAD(&bo_va->invalids);
|
||||
INIT_LIST_HEAD(&bo_va->vm_status);
|
||||
|
||||
mutex_lock(&vm->mutex);
|
||||
|
@ -999,12 +1070,10 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|||
mapping->offset = offset;
|
||||
mapping->flags = flags;
|
||||
|
||||
list_add(&mapping->list, &bo_va->mappings);
|
||||
list_add(&mapping->list, &bo_va->invalids);
|
||||
interval_tree_insert(&mapping->it, &vm->va);
|
||||
trace_amdgpu_vm_bo_map(bo_va, mapping);
|
||||
|
||||
bo_va->addr = 0;
|
||||
|
||||
/* Make sure the page tables are allocated */
|
||||
saddr >>= amdgpu_vm_block_size;
|
||||
eaddr >>= amdgpu_vm_block_size;
|
||||
|
@ -1085,17 +1154,27 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
|||
{
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
struct amdgpu_vm *vm = bo_va->vm;
|
||||
bool valid = true;
|
||||
|
||||
saddr /= AMDGPU_GPU_PAGE_SIZE;
|
||||
|
||||
list_for_each_entry(mapping, &bo_va->mappings, list) {
|
||||
list_for_each_entry(mapping, &bo_va->valids, list) {
|
||||
if (mapping->it.start == saddr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (&mapping->list == &bo_va->mappings) {
|
||||
amdgpu_bo_unreserve(bo_va->bo);
|
||||
return -ENOENT;
|
||||
if (&mapping->list == &bo_va->valids) {
|
||||
valid = false;
|
||||
|
||||
list_for_each_entry(mapping, &bo_va->invalids, list) {
|
||||
if (mapping->it.start == saddr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (&mapping->list == &bo_va->invalids) {
|
||||
amdgpu_bo_unreserve(bo_va->bo);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&vm->mutex);
|
||||
|
@ -1103,12 +1182,10 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
|||
interval_tree_remove(&mapping->it, &vm->va);
|
||||
trace_amdgpu_vm_bo_unmap(bo_va, mapping);
|
||||
|
||||
if (bo_va->addr) {
|
||||
/* clear the old address */
|
||||
if (valid)
|
||||
list_add(&mapping->list, &vm->freed);
|
||||
} else {
|
||||
else
|
||||
kfree(mapping);
|
||||
}
|
||||
mutex_unlock(&vm->mutex);
|
||||
amdgpu_bo_unreserve(bo_va->bo);
|
||||
|
||||
|
@ -1139,16 +1216,19 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
|
|||
list_del(&bo_va->vm_status);
|
||||
spin_unlock(&vm->status_lock);
|
||||
|
||||
list_for_each_entry_safe(mapping, next, &bo_va->mappings, list) {
|
||||
list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
|
||||
list_del(&mapping->list);
|
||||
interval_tree_remove(&mapping->it, &vm->va);
|
||||
trace_amdgpu_vm_bo_unmap(bo_va, mapping);
|
||||
if (bo_va->addr)
|
||||
list_add(&mapping->list, &vm->freed);
|
||||
else
|
||||
kfree(mapping);
|
||||
list_add(&mapping->list, &vm->freed);
|
||||
}
|
||||
amdgpu_fence_unref(&bo_va->last_pt_update);
|
||||
list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
|
||||
list_del(&mapping->list);
|
||||
interval_tree_remove(&mapping->it, &vm->va);
|
||||
kfree(mapping);
|
||||
}
|
||||
|
||||
fence_put(bo_va->last_pt_update);
|
||||
kfree(bo_va);
|
||||
|
||||
mutex_unlock(&vm->mutex);
|
||||
|
@ -1169,12 +1249,10 @@ void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
|
|||
struct amdgpu_bo_va *bo_va;
|
||||
|
||||
list_for_each_entry(bo_va, &bo->va, bo_list) {
|
||||
if (bo_va->addr) {
|
||||
spin_lock(&bo_va->vm->status_lock);
|
||||
list_del(&bo_va->vm_status);
|
||||
spin_lock(&bo_va->vm->status_lock);
|
||||
if (list_empty(&bo_va->vm_status))
|
||||
list_add(&bo_va->vm_status, &bo_va->vm->invalidated);
|
||||
spin_unlock(&bo_va->vm->status_lock);
|
||||
}
|
||||
spin_unlock(&bo_va->vm->status_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1202,6 +1280,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|||
vm->va = RB_ROOT;
|
||||
spin_lock_init(&vm->status_lock);
|
||||
INIT_LIST_HEAD(&vm->invalidated);
|
||||
INIT_LIST_HEAD(&vm->cleared);
|
||||
INIT_LIST_HEAD(&vm->freed);
|
||||
|
||||
pd_size = amdgpu_vm_directory_size(adev);
|
||||
|
@ -1215,6 +1294,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vm->page_directory_fence = NULL;
|
||||
|
||||
r = amdgpu_bo_create(adev, pd_size, align, true,
|
||||
AMDGPU_GEM_DOMAIN_VRAM, 0,
|
||||
NULL, &vm->page_directory);
|
||||
|
@ -1263,6 +1344,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|||
kfree(vm->page_tables);
|
||||
|
||||
amdgpu_bo_unref(&vm->page_directory);
|
||||
fence_put(vm->page_directory_fence);
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
amdgpu_fence_unref(&vm->ids[i].flushed_updates);
|
||||
|
|
|
@ -812,7 +812,7 @@ amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int a
|
|||
else
|
||||
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
|
||||
|
||||
if ((adev->flags & AMDGPU_IS_APU) &&
|
||||
if ((adev->flags & AMD_IS_APU) &&
|
||||
(amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
|
||||
if (is_dp ||
|
||||
!amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock)) {
|
||||
|
|
|
@ -838,7 +838,7 @@ static u32 cik_get_xclk(struct amdgpu_device *adev)
|
|||
{
|
||||
u32 reference_clock = adev->clock.spll.reference_freq;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
if (RREG32_SMC(ixGENERAL_PWRMGT) & GENERAL_PWRMGT__GPU_COUNTER_CLK_MASK)
|
||||
return reference_clock / 2;
|
||||
} else {
|
||||
|
@ -1235,7 +1235,7 @@ static void cik_gpu_soft_reset(struct amdgpu_device *adev, u32 reset_mask)
|
|||
if (reset_mask & AMDGPU_RESET_VMC)
|
||||
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_VMC_MASK;
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU)) {
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
if (reset_mask & AMDGPU_RESET_MC)
|
||||
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_MC_MASK;
|
||||
}
|
||||
|
@ -1411,7 +1411,7 @@ static void cik_gpu_pci_config_reset(struct amdgpu_device *adev)
|
|||
dev_warn(adev->dev, "Wait for MC idle timed out !\n");
|
||||
}
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
kv_save_regs_for_reset(adev, &kv_save);
|
||||
|
||||
/* disable BM */
|
||||
|
@ -1429,7 +1429,7 @@ static void cik_gpu_pci_config_reset(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
/* does asic init need to be run first??? */
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
kv_restore_regs_for_reset(adev, &kv_save);
|
||||
}
|
||||
|
||||
|
@ -1570,7 +1570,7 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
if (amdgpu_pcie_gen2 == 0)
|
||||
return;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
|
||||
|
@ -1730,7 +1730,7 @@ static void cik_program_aspm(struct amdgpu_device *adev)
|
|||
return;
|
||||
|
||||
/* XXX double check APUs */
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
orig = data = RREG32_PCIE(ixPCIE_LC_N_FTS_CNTL);
|
||||
|
|
|
@ -614,6 +614,7 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring)
|
|||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *f = NULL;
|
||||
unsigned i;
|
||||
unsigned index;
|
||||
int r;
|
||||
|
@ -629,12 +630,10 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring)
|
|||
gpu_addr = adev->wb.gpu_addr + (index * 4);
|
||||
tmp = 0xCAFEDEAD;
|
||||
adev->wb.wb[index] = cpu_to_le32(tmp);
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, 256, &ib);
|
||||
if (r) {
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
return r;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
|
||||
|
@ -643,20 +642,16 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring)
|
|||
ib.ptr[3] = 1;
|
||||
ib.ptr[4] = 0xDEADBEEF;
|
||||
ib.length_dw = 5;
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
r = fence_wait(f, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_fence_wait(ib.fence, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
return r;
|
||||
goto err1;
|
||||
}
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
tmp = le32_to_cpu(adev->wb.wb[index]);
|
||||
|
@ -666,12 +661,17 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring)
|
|||
}
|
||||
if (i < adev->usec_timeout) {
|
||||
DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
|
||||
ib.fence->ring->idx, i);
|
||||
ring->idx, i);
|
||||
goto err1;
|
||||
} else {
|
||||
DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
err1:
|
||||
fence_put(f);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
err0:
|
||||
amdgpu_wb_free(adev, index);
|
||||
return r;
|
||||
}
|
||||
|
@ -1404,5 +1404,6 @@ static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev)
|
|||
if (adev->vm_manager.vm_pte_funcs == NULL) {
|
||||
adev->vm_manager.vm_pte_funcs = &cik_sdma_vm_pte_funcs;
|
||||
adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring;
|
||||
adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,9 +126,31 @@ static const u32 tonga_mgcg_cgcg_init[] =
|
|||
mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
|
||||
};
|
||||
|
||||
static const u32 golden_settings_fiji_a10[] =
|
||||
{
|
||||
mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
|
||||
mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
|
||||
mmFBC_MISC, 0x1f311fff, 0x12300000,
|
||||
mmHDMI_CONTROL, 0x31000111, 0x00000011,
|
||||
};
|
||||
|
||||
static const u32 fiji_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
|
||||
mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
|
||||
};
|
||||
|
||||
static void dce_v10_0_init_golden_registers(struct amdgpu_device *adev)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(fiji_mgcg_cgcg_init));
|
||||
amdgpu_program_register_sequence(adev,
|
||||
golden_settings_fiji_a10,
|
||||
(const u32)ARRAY_SIZE(golden_settings_fiji_a10));
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
tonga_mgcg_cgcg_init,
|
||||
|
@ -803,11 +825,11 @@ static u32 dce_v10_0_line_buffer_adjust(struct amdgpu_device *adev,
|
|||
buffer_alloc = 2;
|
||||
} else if (mode->crtc_hdisplay < 4096) {
|
||||
mem_cfg = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Mode too big for LB!\n");
|
||||
mem_cfg = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
}
|
||||
} else {
|
||||
mem_cfg = 1;
|
||||
|
@ -2888,6 +2910,7 @@ static int dce_v10_0_early_init(void *handle)
|
|||
dce_v10_0_set_irq_funcs(adev);
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
case CHIP_TONGA:
|
||||
adev->mode_info.num_crtc = 6; /* XXX 7??? */
|
||||
adev->mode_info.num_hpd = 6;
|
||||
|
|
|
@ -801,11 +801,11 @@ static u32 dce_v11_0_line_buffer_adjust(struct amdgpu_device *adev,
|
|||
buffer_alloc = 2;
|
||||
} else if (mode->crtc_hdisplay < 4096) {
|
||||
mem_cfg = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Mode too big for LB!\n");
|
||||
mem_cfg = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
}
|
||||
} else {
|
||||
mem_cfg = 1;
|
||||
|
|
|
@ -770,11 +770,11 @@ static u32 dce_v8_0_line_buffer_adjust(struct amdgpu_device *adev,
|
|||
buffer_alloc = 2;
|
||||
} else if (mode->crtc_hdisplay < 4096) {
|
||||
tmp = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Mode too big for LB!\n");
|
||||
tmp = 0;
|
||||
buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
|
||||
buffer_alloc = (adev->flags & AMD_IS_APU) ? 2 : 4;
|
||||
}
|
||||
} else {
|
||||
tmp = 1;
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_smumgr.h"
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
|
||||
|
||||
static void fiji_dpm_set_funcs(struct amdgpu_device *adev);
|
||||
|
||||
static int fiji_dpm_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_set_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_init_microcode(struct amdgpu_device *adev)
|
||||
{
|
||||
char fw_name[30] = "amdgpu/fiji_smc.bin";
|
||||
int err;
|
||||
|
||||
err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = amdgpu_ucode_validate(adev->pm.fw);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fiji_dpm_sw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
ret = fiji_dpm_init_microcode(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_sw_fini(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_hw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
ret = fiji_smu_init(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = fiji_smu_start(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("SMU start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
adev->firmware.smu_load = false;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int fiji_dpm_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
fiji_smu_fini(adev);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_suspend(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_resume(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
fiji_dpm_hw_init(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_dpm_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs fiji_dpm_ip_funcs = {
|
||||
.early_init = fiji_dpm_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = fiji_dpm_sw_init,
|
||||
.sw_fini = fiji_dpm_sw_fini,
|
||||
.hw_init = fiji_dpm_hw_init,
|
||||
.hw_fini = fiji_dpm_hw_fini,
|
||||
.suspend = fiji_dpm_suspend,
|
||||
.resume = fiji_dpm_resume,
|
||||
.is_idle = NULL,
|
||||
.wait_for_idle = NULL,
|
||||
.soft_reset = NULL,
|
||||
.print_status = NULL,
|
||||
.set_clockgating_state = fiji_dpm_set_clockgating_state,
|
||||
.set_powergating_state = fiji_dpm_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_dpm_funcs fiji_dpm_funcs = {
|
||||
.get_temperature = NULL,
|
||||
.pre_set_power_state = NULL,
|
||||
.set_power_state = NULL,
|
||||
.post_set_power_state = NULL,
|
||||
.display_configuration_changed = NULL,
|
||||
.get_sclk = NULL,
|
||||
.get_mclk = NULL,
|
||||
.print_power_state = NULL,
|
||||
.debugfs_print_current_performance_level = NULL,
|
||||
.force_performance_level = NULL,
|
||||
.vblank_too_short = NULL,
|
||||
.powergate_uvd = NULL,
|
||||
};
|
||||
|
||||
static void fiji_dpm_set_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
if (NULL == adev->pm.funcs)
|
||||
adev->pm.funcs = &fiji_dpm_funcs;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FIJI_PP_SMC_H
|
||||
#define FIJI_PP_SMC_H
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define PPSMC_SWSTATE_FLAG_DC 0x01
|
||||
#define PPSMC_SWSTATE_FLAG_UVD 0x02
|
||||
#define PPSMC_SWSTATE_FLAG_VCE 0x04
|
||||
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
|
||||
#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
|
||||
#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
|
||||
#define PPSMC_SYSTEMFLAG_GDDR5 0x04
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
|
||||
|
||||
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
|
||||
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
|
||||
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
|
||||
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
|
||||
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
|
||||
|
||||
#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
|
||||
#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
|
||||
#define PPSMC_DPM2FLAGS_OCP 0x04
|
||||
|
||||
#define PPSMC_DISPLAY_WATERMARK_LOW 0
|
||||
#define PPSMC_DISPLAY_WATERMARK_HIGH 1
|
||||
|
||||
#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
|
||||
#define PPSMC_STATEFLAG_POWERBOOST 0x02
|
||||
#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
|
||||
#define PPSMC_STATEFLAG_POWERSHIFT 0x08
|
||||
#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
|
||||
#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
|
||||
#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
|
||||
|
||||
#define FDO_MODE_HARDWARE 0
|
||||
#define FDO_MODE_PIECE_WISE_LINEAR 1
|
||||
|
||||
enum FAN_CONTROL {
|
||||
FAN_CONTROL_FUZZY,
|
||||
FAN_CONTROL_TABLE
|
||||
};
|
||||
|
||||
//Gemini Modes
|
||||
#define PPSMC_GeminiModeNone 0 //Single GPU board
|
||||
#define PPSMC_GeminiModeMaster 1 //Master GPU on a Gemini board
|
||||
#define PPSMC_GeminiModeSlave 2 //Slave GPU on a Gemini board
|
||||
|
||||
#define PPSMC_Result_OK ((uint16_t)0x01)
|
||||
#define PPSMC_Result_NoMore ((uint16_t)0x02)
|
||||
#define PPSMC_Result_NotNow ((uint16_t)0x03)
|
||||
#define PPSMC_Result_Failed ((uint16_t)0xFF)
|
||||
#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
|
||||
#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
|
||||
|
||||
typedef uint16_t PPSMC_Result;
|
||||
|
||||
#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
|
||||
|
||||
#define PPSMC_MSG_Halt ((uint16_t)0x10)
|
||||
#define PPSMC_MSG_Resume ((uint16_t)0x11)
|
||||
#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
|
||||
#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
|
||||
#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
|
||||
#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
|
||||
#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
|
||||
#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
|
||||
#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
|
||||
#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
|
||||
#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
|
||||
#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
|
||||
#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
|
||||
#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
|
||||
#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
|
||||
#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
|
||||
#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
|
||||
#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
|
||||
#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
|
||||
#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
|
||||
#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
|
||||
#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
|
||||
#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
|
||||
#define PPSMC_CACHistoryStart ((uint16_t)0x57)
|
||||
#define PPSMC_CACHistoryStop ((uint16_t)0x58)
|
||||
#define PPSMC_TDPClampingActive ((uint16_t)0x59)
|
||||
#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
|
||||
#define PPSMC_StartFanControl ((uint16_t)0x5B)
|
||||
#define PPSMC_StopFanControl ((uint16_t)0x5C)
|
||||
#define PPSMC_NoDisplay ((uint16_t)0x5D)
|
||||
#define PPSMC_HasDisplay ((uint16_t)0x5E)
|
||||
#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
|
||||
#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
|
||||
#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
|
||||
#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
|
||||
#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
|
||||
#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
|
||||
#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
|
||||
#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
|
||||
#define PPSMC_OCPActive ((uint16_t)0x6C)
|
||||
#define PPSMC_OCPInactive ((uint16_t)0x6D)
|
||||
#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
|
||||
#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
|
||||
#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
|
||||
#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
|
||||
#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
|
||||
#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
|
||||
#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
|
||||
#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
|
||||
#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
|
||||
#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
|
||||
#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
|
||||
#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
|
||||
#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
|
||||
#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
|
||||
#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
|
||||
#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
|
||||
#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
|
||||
#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
|
||||
#define PPSMC_FlushDataCache ((uint16_t)0x80)
|
||||
#define PPSMC_FlushInstrCache ((uint16_t)0x81)
|
||||
#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
|
||||
#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
|
||||
#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
|
||||
#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
|
||||
#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
|
||||
#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
|
||||
#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
|
||||
#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
|
||||
#define PPSMC_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
|
||||
#define PPSMC_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
|
||||
#define PPSMC_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
|
||||
|
||||
#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
|
||||
|
||||
#define PPSMC_MSG_Test ((uint16_t)0x100)
|
||||
#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t)0x250)
|
||||
#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t)0x251)
|
||||
#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t)0x252)
|
||||
#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t)0x253)
|
||||
#define PPSMC_MSG_LoadUcodes ((uint16_t)0x254)
|
||||
|
||||
typedef uint16_t PPSMC_Msg;
|
||||
|
||||
#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
|
||||
#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
|
||||
#define PPSMC_EVENT_STATUS_DC 0x00000004
|
||||
#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,853 @@
|
|||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "fiji_ppsmc.h"
|
||||
#include "fiji_smumgr.h"
|
||||
#include "smu_ucode_xfer_vi.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
|
||||
#include "smu/smu_7_1_3_d.h"
|
||||
#include "smu/smu_7_1_3_sh_mask.h"
|
||||
|
||||
#define FIJI_SMC_SIZE 0x20000
|
||||
|
||||
static int fiji_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (smc_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_address + 3) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
WREG32(mmSMC_IND_INDEX_0, smc_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t data, orig_data;
|
||||
int result = 0;
|
||||
uint32_t extra_shift;
|
||||
unsigned long flags;
|
||||
|
||||
if (smc_start_address & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((smc_start_address + byte_count) > limit)
|
||||
return -EINVAL;
|
||||
|
||||
addr = smc_start_address;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
while (byte_count >= 4) {
|
||||
/* Bytes are written into the SMC addres space with the MSB first */
|
||||
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
|
||||
src += 4;
|
||||
byte_count -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
if (0 != byte_count) {
|
||||
/* Now write odd bytes left, do a read modify write cycle */
|
||||
data = 0;
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
orig_data = RREG32(mmSMC_IND_DATA_0);
|
||||
extra_shift = 8 * (4 - byte_count);
|
||||
|
||||
while (byte_count > 0) {
|
||||
data = (data << 8) + *src++;
|
||||
byte_count--;
|
||||
}
|
||||
|
||||
data <<= extra_shift;
|
||||
data |= (orig_data & ~((~0UL) << extra_shift));
|
||||
|
||||
result = fiji_set_smc_sram_address(adev, addr, limit);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
WREG32(mmSMC_IND_DATA_0, data);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_program_jump_on_start(struct amdgpu_device *adev)
|
||||
{
|
||||
static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
|
||||
fiji_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool fiji_is_smc_ram_running(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
|
||||
|
||||
return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
|
||||
}
|
||||
|
||||
static int wait_smu_response(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32(mmSMC_RESP_0);
|
||||
if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_offset(struct amdgpu_device *adev)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, 0x20000);
|
||||
WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
{
|
||||
return -EINVAL;;
|
||||
}
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MESSAGE_0, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg,
|
||||
uint32_t parameter)
|
||||
{
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return fiji_send_msg_to_smc(adev, msg);
|
||||
}
|
||||
|
||||
static int fiji_send_msg_to_smc_with_parameter_without_waiting(
|
||||
struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg, uint32_t parameter)
|
||||
{
|
||||
if (wait_smu_response(adev)) {
|
||||
DRM_ERROR("Failed to send previous message\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmSMC_MSG_ARG_0, parameter);
|
||||
|
||||
return fiji_send_msg_to_smc_without_waiting(adev, msg);
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int fiji_wait_for_smc_inactive(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
if (!fiji_is_smc_ram_running(adev))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fiji_smu_upload_firmware_image(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
uint32_t ucode_size;
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
uint32_t val;
|
||||
uint32_t byte_count;
|
||||
uint32_t *data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!adev->pm.fw)
|
||||
return -EINVAL;
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
|
||||
amdgpu_ucode_print_smc_hdr(&hdr->header);
|
||||
|
||||
adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
|
||||
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
|
||||
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
|
||||
src = (const uint8_t *)
|
||||
(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
|
||||
if (ucode_size & 3) {
|
||||
DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ucode_size > FIJI_SMC_SIZE) {
|
||||
DRM_ERROR("SMC address is beyond the SMC RAM area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
|
||||
byte_count = ucode_size;
|
||||
data = (uint32_t *)src;
|
||||
for (; byte_count >= 4; data++, byte_count -= 4)
|
||||
WREG32(mmSMC_IND_DATA_0, data[0]);
|
||||
|
||||
val = RREG32(mmSMC_IND_ACCESS_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
|
||||
WREG32(mmSMC_IND_ACCESS_CNTL, val);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static int fiji_read_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t *value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = fiji_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
*value = RREG32(mmSMC_IND_DATA_0);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_write_smc_sram_dword(struct amdgpu_device *adev,
|
||||
uint32_t smc_address,
|
||||
uint32_t value,
|
||||
uint32_t limit)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adev->smc_idx_lock, flags);
|
||||
result = fiji_set_smc_sram_address(adev, smc_address, limit);
|
||||
if (result == 0)
|
||||
WREG32(mmSMC_IND_DATA_0, value);
|
||||
spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fiji_smu_stop_smc(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum AMDGPU_UCODE_ID fiji_convert_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case UCODE_ID_SDMA0:
|
||||
return AMDGPU_UCODE_ID_SDMA0;
|
||||
case UCODE_ID_SDMA1:
|
||||
return AMDGPU_UCODE_ID_SDMA1;
|
||||
case UCODE_ID_CP_CE:
|
||||
return AMDGPU_UCODE_ID_CP_CE;
|
||||
case UCODE_ID_CP_PFP:
|
||||
return AMDGPU_UCODE_ID_CP_PFP;
|
||||
case UCODE_ID_CP_ME:
|
||||
return AMDGPU_UCODE_ID_CP_ME;
|
||||
case UCODE_ID_CP_MEC:
|
||||
case UCODE_ID_CP_MEC_JT1:
|
||||
case UCODE_ID_CP_MEC_JT2:
|
||||
return AMDGPU_UCODE_ID_CP_MEC1;
|
||||
case UCODE_ID_RLC_G:
|
||||
return AMDGPU_UCODE_ID_RLC_G;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return AMDGPU_UCODE_ID_MAXIMUM;
|
||||
}
|
||||
}
|
||||
|
||||
static int fiji_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
|
||||
uint32_t fw_type,
|
||||
struct SMU_Entry *entry)
|
||||
{
|
||||
enum AMDGPU_UCODE_ID id = fiji_convert_fw_type(fw_type);
|
||||
struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
|
||||
const struct gfx_firmware_header_v1_0 *header = NULL;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t data_size;
|
||||
|
||||
if (ucode->fw == NULL)
|
||||
return -EINVAL;
|
||||
gpu_addr = ucode->mc_addr;
|
||||
header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
data_size = le32_to_cpu(header->header.ucode_size_bytes);
|
||||
|
||||
if ((fw_type == UCODE_ID_CP_MEC_JT1) ||
|
||||
(fw_type == UCODE_ID_CP_MEC_JT2)) {
|
||||
gpu_addr += le32_to_cpu(header->jt_offset) << 2;
|
||||
data_size = le32_to_cpu(header->jt_size) << 2;
|
||||
}
|
||||
|
||||
entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
|
||||
entry->id = (uint16_t)fw_type;
|
||||
entry->image_addr_high = upper_32_bits(gpu_addr);
|
||||
entry->image_addr_low = lower_32_bits(gpu_addr);
|
||||
entry->meta_data_addr_high = 0;
|
||||
entry->meta_data_addr_low = 0;
|
||||
entry->data_size_byte = data_size;
|
||||
entry->num_register_entries = 0;
|
||||
|
||||
if (fw_type == UCODE_ID_RLC_G)
|
||||
entry->flags = 1;
|
||||
else
|
||||
entry->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_request_load_fw(struct amdgpu_device *adev)
|
||||
{
|
||||
struct fiji_smu_private_data *private = (struct fiji_smu_private_data *)adev->smu.priv;
|
||||
struct SMU_DRAMData_TOC *toc;
|
||||
uint32_t fw_to_load;
|
||||
|
||||
WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0);
|
||||
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high);
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low);
|
||||
|
||||
toc = (struct SMU_DRAMData_TOC *)private->header;
|
||||
toc->num_entries = 0;
|
||||
toc->structure_version = 1;
|
||||
|
||||
if (!adev->firmware.smu_load)
|
||||
return 0;
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for RLC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for CE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for PFP\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for ME\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
|
||||
&toc->entry[toc->num_entries++])) {
|
||||
DRM_ERROR("Failed to get firmware entry for SDMA1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
|
||||
fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
|
||||
|
||||
fw_to_load = UCODE_ID_RLC_G_MASK |
|
||||
UCODE_ID_SDMA0_MASK |
|
||||
UCODE_ID_SDMA1_MASK |
|
||||
UCODE_ID_CP_CE_MASK |
|
||||
UCODE_ID_CP_ME_MASK |
|
||||
UCODE_ID_CP_PFP_MASK |
|
||||
UCODE_ID_CP_MEC_MASK;
|
||||
|
||||
if (fiji_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
|
||||
DRM_ERROR("Fail to request SMU load ucode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t fiji_smu_get_mask_for_fw_type(uint32_t fw_type)
|
||||
{
|
||||
switch (fw_type) {
|
||||
case AMDGPU_UCODE_ID_SDMA0:
|
||||
return UCODE_ID_SDMA0_MASK;
|
||||
case AMDGPU_UCODE_ID_SDMA1:
|
||||
return UCODE_ID_SDMA1_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_CE:
|
||||
return UCODE_ID_CP_CE_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_PFP:
|
||||
return UCODE_ID_CP_PFP_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_ME:
|
||||
return UCODE_ID_CP_ME_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC1:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_CP_MEC2:
|
||||
return UCODE_ID_CP_MEC_MASK;
|
||||
case AMDGPU_UCODE_ID_RLC_G:
|
||||
return UCODE_ID_RLC_G_MASK;
|
||||
default:
|
||||
DRM_ERROR("ucode type is out of range!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int fiji_smu_check_fw_load_finish(struct amdgpu_device *adev,
|
||||
uint32_t fw_type)
|
||||
{
|
||||
uint32_t fw_mask = fiji_smu_get_mask_for_fw_type(fw_type);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("check firmware loading failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_start_in_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = fiji_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Clear status */
|
||||
WREG32_SMC(ixSMU_STATUS, 0);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Set SMU Auto Start */
|
||||
val = RREG32_SMC(ixSMU_INPUT_DATA);
|
||||
val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1);
|
||||
WREG32_SMC(ixSMU_INPUT_DATA, val);
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Interrupt is not enabled by firmware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Call Test SMU message with 0x20000 offset
|
||||
* to trigger SMU start
|
||||
*/
|
||||
fiji_send_msg_to_smc_offset(adev);
|
||||
DRM_INFO("[FM]try triger smu start\n");
|
||||
/* Wait for done bit to be set */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMU start\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check pass/failed indicator */
|
||||
val = RREG32_SMC(ixSMU_STATUS);
|
||||
if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) {
|
||||
DRM_ERROR("SMU Firmware start failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
DRM_INFO("[FM]smu started\n");
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMU firmware initialization failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
DRM_INFO("[FM]smu initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiji_smu_start_in_non_protection_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, result;
|
||||
uint32_t val;
|
||||
|
||||
/* wait for smc boot up */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixRCU_UC_EVENTS);
|
||||
val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done);
|
||||
if (val)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("SMC boot sequence is not completed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear firmware interrupt enable flag */
|
||||
WREG32_SMC(ixFIRMWARE_FLAGS, 0);
|
||||
|
||||
/* Assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
result = fiji_smu_upload_firmware_image(adev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Set smc instruct start point at 0x0 */
|
||||
fiji_program_jump_on_start(adev);
|
||||
|
||||
/* Enable clock */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
|
||||
|
||||
/* De-assert reset */
|
||||
val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
|
||||
val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
|
||||
WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
|
||||
|
||||
/* Wait for firmware to initialize */
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32_SMC(ixFIRMWARE_FLAGS);
|
||||
if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i == adev->usec_timeout) {
|
||||
DRM_ERROR("Timeout for SMC firmware initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_smu_start(struct amdgpu_device *adev)
|
||||
{
|
||||
int result;
|
||||
uint32_t val;
|
||||
|
||||
if (!fiji_is_smc_ram_running(adev)) {
|
||||
val = RREG32_SMC(ixSMU_FIRMWARE);
|
||||
if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) {
|
||||
DRM_INFO("[FM]start smu in nonprotection mode\n");
|
||||
result = fiji_smu_start_in_non_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
DRM_INFO("[FM]start smu in protection mode\n");
|
||||
result = fiji_smu_start_in_protection_mode(adev);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return fiji_smu_request_load_fw(adev);
|
||||
}
|
||||
|
||||
static const struct amdgpu_smumgr_funcs fiji_smumgr_funcs = {
|
||||
.check_fw_load_finish = fiji_smu_check_fw_load_finish,
|
||||
.request_smu_load_fw = NULL,
|
||||
.request_smu_specific_fw = NULL,
|
||||
};
|
||||
|
||||
int fiji_smu_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct fiji_smu_private_data *private;
|
||||
uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
|
||||
uint32_t smu_internal_buffer_size = 200*4096;
|
||||
struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
|
||||
struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
|
||||
uint64_t mc_addr;
|
||||
void *toc_buf_ptr;
|
||||
void *smu_buf_ptr;
|
||||
int ret;
|
||||
|
||||
private = kzalloc(sizeof(struct fiji_smu_private_data), GFP_KERNEL);
|
||||
if (NULL == private)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate firmware buffers */
|
||||
if (adev->firmware.smu_load)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
adev->smu.priv = private;
|
||||
adev->smu.fw_flags = 0;
|
||||
|
||||
/* Allocate FW image data structure and header buffer */
|
||||
ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for TOC buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate buffer for SMU internal buffer */
|
||||
ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE,
|
||||
true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Retrieve GPU address for header buffer and internal buffer */
|
||||
ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the TOC buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.toc_buf);
|
||||
private->header_addr_low = lower_32_bits(mc_addr);
|
||||
private->header_addr_high = upper_32_bits(mc_addr);
|
||||
private->header = toc_buf_ptr;
|
||||
|
||||
ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
|
||||
if (ret) {
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to reserve the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to pin the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
|
||||
if (ret) {
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
DRM_ERROR("Failed to map the SMU internal buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->smu.smu_buf);
|
||||
private->smu_buffer_addr_low = lower_32_bits(mc_addr);
|
||||
private->smu_buffer_addr_high = upper_32_bits(mc_addr);
|
||||
|
||||
adev->smu.smumgr_funcs = &fiji_smumgr_funcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fiji_smu_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_bo_unref(&adev->smu.toc_buf);
|
||||
amdgpu_bo_unref(&adev->smu.smu_buf);
|
||||
kfree(adev->smu.priv);
|
||||
adev->smu.priv = NULL;
|
||||
if (adev->firmware.fw_buf)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* Copyright 2008 Advanced Micro Devices, Inc.
|
||||
* Copyright 2008 Red Hat Inc.
|
||||
* Copyright 2009 Jerome Glisse.
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -21,42 +19,24 @@
|
|||
* 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
|
||||
*/
|
||||
|
||||
/* this file defines the CHIP_ and family flags used in the pciids,
|
||||
* its is common between kms and non-kms because duplicating it and
|
||||
* changing one place is fail.
|
||||
*/
|
||||
#ifndef AMDGPU_FAMILY_H
|
||||
#define AMDGPU_FAMILY_H
|
||||
/*
|
||||
* Supported ASIC types
|
||||
*/
|
||||
enum amdgpu_asic_type {
|
||||
CHIP_BONAIRE = 0,
|
||||
CHIP_KAVERI,
|
||||
CHIP_KABINI,
|
||||
CHIP_HAWAII,
|
||||
CHIP_MULLINS,
|
||||
CHIP_TOPAZ,
|
||||
CHIP_TONGA,
|
||||
CHIP_CARRIZO,
|
||||
CHIP_LAST,
|
||||
};
|
||||
#ifndef FIJI_SMUMGR_H
|
||||
#define FIJI_SMUMGR_H
|
||||
|
||||
/*
|
||||
* Chip flags
|
||||
*/
|
||||
enum amdgpu_chip_flags {
|
||||
AMDGPU_ASIC_MASK = 0x0000ffffUL,
|
||||
AMDGPU_FLAGS_MASK = 0xffff0000UL,
|
||||
AMDGPU_IS_MOBILITY = 0x00010000UL,
|
||||
AMDGPU_IS_APU = 0x00020000UL,
|
||||
AMDGPU_IS_PX = 0x00040000UL,
|
||||
AMDGPU_EXP_HW_SUPPORT = 0x00080000UL,
|
||||
#include "fiji_ppsmc.h"
|
||||
|
||||
int fiji_smu_init(struct amdgpu_device *adev);
|
||||
int fiji_smu_fini(struct amdgpu_device *adev);
|
||||
int fiji_smu_start(struct amdgpu_device *adev);
|
||||
|
||||
struct fiji_smu_private_data
|
||||
{
|
||||
uint8_t *header;
|
||||
uint32_t smu_buffer_addr_high;
|
||||
uint32_t smu_buffer_addr_low;
|
||||
uint32_t header_addr_high;
|
||||
uint32_t header_addr_low;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2173,7 +2173,7 @@ static void gfx_v7_0_gpu_init(struct amdgpu_device *adev)
|
|||
|
||||
adev->gfx.config.num_tile_pipes = adev->gfx.config.max_tile_pipes;
|
||||
adev->gfx.config.mem_max_burst_length_bytes = 256;
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
/* Get memory bank mapping mode. */
|
||||
tmp = RREG32(mmMC_FUS_DRAM0_BANK_ADDR_MAPPING);
|
||||
dimm00_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM0ADDRMAP);
|
||||
|
@ -2648,6 +2648,7 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *f = NULL;
|
||||
uint32_t scratch;
|
||||
uint32_t tmp = 0;
|
||||
unsigned i;
|
||||
|
@ -2662,26 +2663,23 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
r = amdgpu_ib_get(ring, NULL, 256, &ib);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
return r;
|
||||
goto err1;
|
||||
}
|
||||
ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
|
||||
ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START));
|
||||
ib.ptr[2] = 0xDEADBEEF;
|
||||
ib.length_dw = 3;
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
if (r) {
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_fence_wait(ib.fence, false);
|
||||
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
r = fence_wait(f, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
return r;
|
||||
goto err2;
|
||||
}
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
tmp = RREG32(scratch);
|
||||
|
@ -2691,14 +2689,19 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
}
|
||||
if (i < adev->usec_timeout) {
|
||||
DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
|
||||
ib.fence->ring->idx, i);
|
||||
ring->idx, i);
|
||||
goto err2;
|
||||
} else {
|
||||
DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
|
||||
scratch, tmp);
|
||||
r = -EINVAL;
|
||||
}
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
|
||||
err2:
|
||||
fence_put(f);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
err1:
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -3758,7 +3761,7 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)
|
|||
int r;
|
||||
|
||||
/* allocate rlc buffers */
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
if (adev->asic_type == CHIP_KAVERI) {
|
||||
adev->gfx.rlc.reg_list = spectre_rlc_save_restore_register_list;
|
||||
adev->gfx.rlc.reg_list_size =
|
||||
|
|
|
@ -87,6 +87,13 @@ MODULE_FIRMWARE("amdgpu/topaz_mec.bin");
|
|||
MODULE_FIRMWARE("amdgpu/topaz_mec2.bin");
|
||||
MODULE_FIRMWARE("amdgpu/topaz_rlc.bin");
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/fiji_ce.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_pfp.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_me.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_mec.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_mec2.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_rlc.bin");
|
||||
|
||||
static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] =
|
||||
{
|
||||
{mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0},
|
||||
|
@ -217,6 +224,71 @@ static const u32 tonga_mgcg_cgcg_init[] =
|
|||
mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
|
||||
};
|
||||
|
||||
static const u32 fiji_golden_common_all[] =
|
||||
{
|
||||
mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
|
||||
mmPA_SC_RASTER_CONFIG, 0xffffffff, 0x3a00161a,
|
||||
mmPA_SC_RASTER_CONFIG_1, 0xffffffff, 0x0000002e,
|
||||
mmGB_ADDR_CONFIG, 0xffffffff, 0x12011003,
|
||||
mmSPI_RESOURCE_RESERVE_CU_0, 0xffffffff, 0x00000800,
|
||||
mmSPI_RESOURCE_RESERVE_CU_1, 0xffffffff, 0x00000800,
|
||||
mmSPI_RESOURCE_RESERVE_EN_CU_0, 0xffffffff, 0x00007FBF,
|
||||
mmSPI_RESOURCE_RESERVE_EN_CU_1, 0xffffffff, 0x00007FAF
|
||||
};
|
||||
|
||||
static const u32 golden_settings_fiji_a10[] =
|
||||
{
|
||||
mmCB_HW_CONTROL_3, 0x000001ff, 0x00000040,
|
||||
mmDB_DEBUG2, 0xf00fffff, 0x00000400,
|
||||
mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
|
||||
mmPA_SC_FIFO_DEPTH_CNTL, 0x000003ff, 0x00000100,
|
||||
mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
|
||||
mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
|
||||
mmTCC_CTRL, 0x00100000, 0xf30fff7f,
|
||||
mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000ff,
|
||||
mmTCP_CHAN_STEER_HI, 0xffffffff, 0x7d6cf5e4,
|
||||
mmTCP_CHAN_STEER_LO, 0xffffffff, 0x3928b1a0,
|
||||
};
|
||||
|
||||
static const u32 fiji_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmRLC_CGTT_MGCG_OVERRIDE, 0xffffffff, 0xffffffc0,
|
||||
mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
|
||||
mmCB_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_BCI_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100,
|
||||
mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
|
||||
mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_WD_CLK_CTRL, 0xffffffff, 0x06000100,
|
||||
mmCGTT_PC_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_RLC_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SC_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SPI_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SQ_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SQG_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SX_CLK_CTRL0, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SX_CLK_CTRL1, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SX_CLK_CTRL2, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SX_CLK_CTRL3, 0xffffffff, 0x00000100,
|
||||
mmCGTT_SX_CLK_CTRL4, 0xffffffff, 0x00000100,
|
||||
mmCGTT_TCI_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_TCP_CLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmCGTT_VGT_CLK_CTRL, 0xffffffff, 0x06000100,
|
||||
mmDB_CGTT_CLK_CTRL_0, 0xffffffff, 0x00000100,
|
||||
mmTA_CGTT_CTRL, 0xffffffff, 0x00000100,
|
||||
mmTCA_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmTCC_CGTT_SCLK_CTRL, 0xffffffff, 0x00000100,
|
||||
mmTD_CGTT_CTRL, 0xffffffff, 0x00000100,
|
||||
mmGRBM_GFX_INDEX, 0xffffffff, 0xe0000000,
|
||||
mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200,
|
||||
mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
|
||||
mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c,
|
||||
mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
|
||||
};
|
||||
|
||||
static const u32 golden_settings_iceland_a11[] =
|
||||
{
|
||||
mmCB_HW_CONTROL_3, 0x00000040, 0x00000040,
|
||||
|
@ -439,6 +511,18 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
|
|||
iceland_golden_common_all,
|
||||
(const u32)ARRAY_SIZE(iceland_golden_common_all));
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(fiji_mgcg_cgcg_init));
|
||||
amdgpu_program_register_sequence(adev,
|
||||
golden_settings_fiji_a10,
|
||||
(const u32)ARRAY_SIZE(golden_settings_fiji_a10));
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_golden_common_all,
|
||||
(const u32)ARRAY_SIZE(fiji_golden_common_all));
|
||||
break;
|
||||
|
||||
case CHIP_TONGA:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
tonga_mgcg_cgcg_init,
|
||||
|
@ -526,6 +610,7 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *f = NULL;
|
||||
uint32_t scratch;
|
||||
uint32_t tmp = 0;
|
||||
unsigned i;
|
||||
|
@ -540,26 +625,23 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
r = amdgpu_ib_get(ring, NULL, 256, &ib);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
return r;
|
||||
goto err1;
|
||||
}
|
||||
ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
|
||||
ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START));
|
||||
ib.ptr[2] = 0xDEADBEEF;
|
||||
ib.length_dw = 3;
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
if (r) {
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_fence_wait(ib.fence, false);
|
||||
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
r = fence_wait(f, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
return r;
|
||||
goto err2;
|
||||
}
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
tmp = RREG32(scratch);
|
||||
|
@ -569,14 +651,18 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
}
|
||||
if (i < adev->usec_timeout) {
|
||||
DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
|
||||
ib.fence->ring->idx, i);
|
||||
ring->idx, i);
|
||||
goto err2;
|
||||
} else {
|
||||
DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
|
||||
scratch, tmp);
|
||||
r = -EINVAL;
|
||||
}
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
err2:
|
||||
fence_put(f);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
err1:
|
||||
amdgpu_gfx_scratch_free(adev, scratch);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -601,6 +687,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
|
|||
case CHIP_CARRIZO:
|
||||
chip_name = "carrizo";
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
chip_name = "fiji";
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -1236,6 +1325,7 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
|
|||
adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
|
||||
WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
|
||||
}
|
||||
case CHIP_FIJI:
|
||||
case CHIP_TONGA:
|
||||
for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
|
||||
switch (reg_offset) {
|
||||
|
@ -1984,6 +2074,23 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
|
|||
adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
|
||||
gb_addr_config = TOPAZ_GB_ADDR_CONFIG_GOLDEN;
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
adev->gfx.config.max_shader_engines = 4;
|
||||
adev->gfx.config.max_tile_pipes = 16;
|
||||
adev->gfx.config.max_cu_per_sh = 16;
|
||||
adev->gfx.config.max_sh_per_se = 1;
|
||||
adev->gfx.config.max_backends_per_se = 4;
|
||||
adev->gfx.config.max_texture_channel_caches = 8;
|
||||
adev->gfx.config.max_gprs = 256;
|
||||
adev->gfx.config.max_gs_threads = 32;
|
||||
adev->gfx.config.max_hw_contexts = 8;
|
||||
|
||||
adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
|
||||
adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
|
||||
adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
|
||||
adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
|
||||
gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN;
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
adev->gfx.config.max_shader_engines = 4;
|
||||
adev->gfx.config.max_tile_pipes = 8;
|
||||
|
@ -2078,7 +2185,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
|
|||
|
||||
adev->gfx.config.num_tile_pipes = adev->gfx.config.max_tile_pipes;
|
||||
adev->gfx.config.mem_max_burst_length_bytes = 256;
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
/* Get memory bank mapping mode. */
|
||||
tmp = RREG32(mmMC_FUS_DRAM0_BANK_ADDR_MAPPING);
|
||||
dimm00_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM0ADDRMAP);
|
||||
|
@ -2490,6 +2597,7 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev)
|
|||
amdgpu_ring_write(ring, mmPA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_TONGA:
|
||||
case CHIP_FIJI:
|
||||
amdgpu_ring_write(ring, 0x16000012);
|
||||
amdgpu_ring_write(ring, 0x0000002A);
|
||||
break;
|
||||
|
@ -3875,7 +3983,8 @@ static bool gfx_v8_0_ring_emit_semaphore(struct amdgpu_ring *ring,
|
|||
unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
|
||||
|
||||
if (ring->adev->asic_type == CHIP_TOPAZ ||
|
||||
ring->adev->asic_type == CHIP_TONGA)
|
||||
ring->adev->asic_type == CHIP_TONGA ||
|
||||
ring->adev->asic_type == CHIP_FIJI)
|
||||
/* we got a hw semaphore bug in VI TONGA, return false to switch back to sw fence wait */
|
||||
return false;
|
||||
else {
|
||||
|
|
|
@ -636,7 +636,7 @@ static int gmc_v7_0_vm_init(struct amdgpu_device *adev)
|
|||
adev->vm_manager.nvm = AMDGPU_NUM_OF_VMIDS;
|
||||
|
||||
/* base offset of vram pages */
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
u64 tmp = RREG32(mmMC_VM_FB_OFFSET);
|
||||
tmp <<= 22;
|
||||
adev->vm_manager.vram_base_offset = tmp;
|
||||
|
@ -841,7 +841,7 @@ static int gmc_v7_0_early_init(void *handle)
|
|||
gmc_v7_0_set_gart_funcs(adev);
|
||||
gmc_v7_0_set_irq_funcs(adev);
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
|
||||
} else {
|
||||
u32 tmp = RREG32(mmMC_SEQ_MISC0);
|
||||
|
@ -957,7 +957,7 @@ static int gmc_v7_0_hw_init(void *handle)
|
|||
|
||||
gmc_v7_0_mc_program(adev);
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU)) {
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
r = gmc_v7_0_mc_load_microcode(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to load MC firmware!\n");
|
||||
|
@ -1172,7 +1172,7 @@ static int gmc_v7_0_soft_reset(void *handle)
|
|||
|
||||
if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
|
||||
SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK)) {
|
||||
if (!(adev->flags & AMDGPU_IS_APU))
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
|
||||
SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
|
||||
}
|
||||
|
@ -1282,7 +1282,7 @@ static int gmc_v7_0_set_clockgating_state(void *handle,
|
|||
if (state == AMD_CG_STATE_GATE)
|
||||
gate = true;
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU)) {
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
gmc_v7_0_enable_mc_mgcg(adev, gate);
|
||||
gmc_v7_0_enable_mc_ls(adev, gate);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev);
|
|||
|
||||
MODULE_FIRMWARE("amdgpu/topaz_mc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_mc.bin");
|
||||
|
||||
static const u32 golden_settings_tonga_a11[] =
|
||||
{
|
||||
|
@ -61,6 +62,19 @@ static const u32 tonga_mgcg_cgcg_init[] =
|
|||
mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
|
||||
};
|
||||
|
||||
static const u32 golden_settings_fiji_a10[] =
|
||||
{
|
||||
mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
|
||||
mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
|
||||
mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
|
||||
mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff,
|
||||
};
|
||||
|
||||
static const u32 fiji_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
|
||||
};
|
||||
|
||||
static const u32 golden_settings_iceland_a11[] =
|
||||
{
|
||||
mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
|
||||
|
@ -90,6 +104,14 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
|
|||
golden_settings_iceland_a11,
|
||||
(const u32)ARRAY_SIZE(golden_settings_iceland_a11));
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(fiji_mgcg_cgcg_init));
|
||||
amdgpu_program_register_sequence(adev,
|
||||
golden_settings_fiji_a10,
|
||||
(const u32)ARRAY_SIZE(golden_settings_fiji_a10));
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
tonga_mgcg_cgcg_init,
|
||||
|
@ -202,6 +224,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev)
|
|||
case CHIP_TONGA:
|
||||
chip_name = "tonga";
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
chip_name = "fiji";
|
||||
break;
|
||||
case CHIP_CARRIZO:
|
||||
return 0;
|
||||
default: BUG();
|
||||
|
@ -737,7 +762,7 @@ static int gmc_v8_0_vm_init(struct amdgpu_device *adev)
|
|||
adev->vm_manager.nvm = AMDGPU_NUM_OF_VMIDS;
|
||||
|
||||
/* base offset of vram pages */
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
u64 tmp = RREG32(mmMC_VM_FB_OFFSET);
|
||||
tmp <<= 22;
|
||||
adev->vm_manager.vram_base_offset = tmp;
|
||||
|
@ -816,7 +841,7 @@ static int gmc_v8_0_early_init(void *handle)
|
|||
gmc_v8_0_set_gart_funcs(adev);
|
||||
gmc_v8_0_set_irq_funcs(adev);
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
|
||||
} else {
|
||||
u32 tmp = RREG32(mmMC_SEQ_MISC0);
|
||||
|
@ -934,7 +959,7 @@ static int gmc_v8_0_hw_init(void *handle)
|
|||
|
||||
gmc_v8_0_mc_program(adev);
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU)) {
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
r = gmc_v8_0_mc_load_microcode(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to load MC firmware!\n");
|
||||
|
@ -1147,7 +1172,7 @@ static int gmc_v8_0_soft_reset(void *handle)
|
|||
|
||||
if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
|
||||
SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK)) {
|
||||
if (!(adev->flags & AMDGPU_IS_APU))
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
|
||||
SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
|
||||
}
|
||||
|
|
|
@ -673,6 +673,7 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring)
|
|||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *f = NULL;
|
||||
unsigned i;
|
||||
unsigned index;
|
||||
int r;
|
||||
|
@ -688,12 +689,10 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring)
|
|||
gpu_addr = adev->wb.gpu_addr + (index * 4);
|
||||
tmp = 0xCAFEDEAD;
|
||||
adev->wb.wb[index] = cpu_to_le32(tmp);
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, 256, &ib);
|
||||
if (r) {
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
return r;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
|
||||
|
@ -707,19 +706,16 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring)
|
|||
ib.ptr[7] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP);
|
||||
ib.length_dw = 8;
|
||||
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
r = fence_wait(f, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_fence_wait(ib.fence, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
return r;
|
||||
goto err1;
|
||||
}
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
tmp = le32_to_cpu(adev->wb.wb[index]);
|
||||
|
@ -729,12 +725,17 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring)
|
|||
}
|
||||
if (i < adev->usec_timeout) {
|
||||
DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
|
||||
ib.fence->ring->idx, i);
|
||||
ring->idx, i);
|
||||
goto err1;
|
||||
} else {
|
||||
DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
err1:
|
||||
fence_put(f);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
err0:
|
||||
amdgpu_wb_free(adev, index);
|
||||
return r;
|
||||
}
|
||||
|
@ -1415,5 +1416,6 @@ static void sdma_v2_4_set_vm_pte_funcs(struct amdgpu_device *adev)
|
|||
if (adev->vm_manager.vm_pte_funcs == NULL) {
|
||||
adev->vm_manager.vm_pte_funcs = &sdma_v2_4_vm_pte_funcs;
|
||||
adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring;
|
||||
adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ MODULE_FIRMWARE("amdgpu/tonga_sdma.bin");
|
|||
MODULE_FIRMWARE("amdgpu/tonga_sdma1.bin");
|
||||
MODULE_FIRMWARE("amdgpu/carrizo_sdma.bin");
|
||||
MODULE_FIRMWARE("amdgpu/carrizo_sdma1.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_sdma.bin");
|
||||
MODULE_FIRMWARE("amdgpu/fiji_sdma1.bin");
|
||||
|
||||
static const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
|
||||
{
|
||||
|
@ -80,6 +82,24 @@ static const u32 tonga_mgcg_cgcg_init[] =
|
|||
mmSDMA1_CLK_CTRL, 0xff000ff0, 0x00000100
|
||||
};
|
||||
|
||||
static const u32 golden_settings_fiji_a10[] =
|
||||
{
|
||||
mmSDMA0_CHICKEN_BITS, 0xfc910007, 0x00810007,
|
||||
mmSDMA0_GFX_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
mmSDMA0_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
mmSDMA0_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
mmSDMA1_CHICKEN_BITS, 0xfc910007, 0x00810007,
|
||||
mmSDMA1_GFX_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
mmSDMA1_RLC0_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
mmSDMA1_RLC1_IB_CNTL, 0x800f0111, 0x00000100,
|
||||
};
|
||||
|
||||
static const u32 fiji_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmSDMA0_CLK_CTRL, 0xff000ff0, 0x00000100,
|
||||
mmSDMA1_CLK_CTRL, 0xff000ff0, 0x00000100
|
||||
};
|
||||
|
||||
static const u32 cz_golden_settings_a11[] =
|
||||
{
|
||||
mmSDMA0_CHICKEN_BITS, 0xfc910007, 0x00810007,
|
||||
|
@ -122,6 +142,14 @@ static const u32 cz_mgcg_cgcg_init[] =
|
|||
static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_FIJI:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(fiji_mgcg_cgcg_init));
|
||||
amdgpu_program_register_sequence(adev,
|
||||
golden_settings_fiji_a10,
|
||||
(const u32)ARRAY_SIZE(golden_settings_fiji_a10));
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
tonga_mgcg_cgcg_init,
|
||||
|
@ -167,6 +195,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
|
|||
case CHIP_TONGA:
|
||||
chip_name = "tonga";
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
chip_name = "fiji";
|
||||
break;
|
||||
case CHIP_CARRIZO:
|
||||
chip_name = "carrizo";
|
||||
break;
|
||||
|
@ -763,6 +794,7 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib ib;
|
||||
struct fence *f = NULL;
|
||||
unsigned i;
|
||||
unsigned index;
|
||||
int r;
|
||||
|
@ -778,12 +810,10 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
gpu_addr = adev->wb.gpu_addr + (index * 4);
|
||||
tmp = 0xCAFEDEAD;
|
||||
adev->wb.wb[index] = cpu_to_le32(tmp);
|
||||
|
||||
r = amdgpu_ib_get(ring, NULL, 256, &ib);
|
||||
if (r) {
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
|
||||
return r;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
|
||||
|
@ -797,19 +827,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
ib.ptr[7] = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP);
|
||||
ib.length_dw = 8;
|
||||
|
||||
r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
|
||||
r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
|
||||
AMDGPU_FENCE_OWNER_UNDEFINED,
|
||||
&f);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
r = fence_wait(f, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_fence_wait(ib.fence, false);
|
||||
if (r) {
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
amdgpu_wb_free(adev, index);
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
return r;
|
||||
goto err1;
|
||||
}
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
tmp = le32_to_cpu(adev->wb.wb[index]);
|
||||
|
@ -819,12 +846,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
}
|
||||
if (i < adev->usec_timeout) {
|
||||
DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
|
||||
ib.fence->ring->idx, i);
|
||||
ring->idx, i);
|
||||
goto err1;
|
||||
} else {
|
||||
DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
|
||||
r = -EINVAL;
|
||||
}
|
||||
err1:
|
||||
fence_put(f);
|
||||
amdgpu_ib_free(adev, &ib);
|
||||
err0:
|
||||
amdgpu_wb_free(adev, index);
|
||||
return r;
|
||||
}
|
||||
|
@ -1509,5 +1540,6 @@ static void sdma_v3_0_set_vm_pte_funcs(struct amdgpu_device *adev)
|
|||
if (adev->vm_manager.vm_pte_funcs == NULL) {
|
||||
adev->vm_manager.vm_pte_funcs = &sdma_v3_0_vm_pte_funcs;
|
||||
adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring;
|
||||
adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -534,7 +534,7 @@ static void uvd_v4_2_ring_emit_ib(struct amdgpu_ring *ring,
|
|||
static int uvd_v4_2_ring_test_ib(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_fence *fence = NULL;
|
||||
struct fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
r = amdgpu_asic_set_uvd_clocks(adev, 53300, 40000);
|
||||
|
@ -555,14 +555,14 @@ static int uvd_v4_2_ring_test_ib(struct amdgpu_ring *ring)
|
|||
goto error;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(fence, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
goto error;
|
||||
}
|
||||
DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
|
||||
error:
|
||||
amdgpu_fence_unref(&fence);
|
||||
fence_put(fence);
|
||||
amdgpu_asic_set_uvd_clocks(adev, 0, 0);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -580,7 +580,7 @@ static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
|
|||
static int uvd_v5_0_ring_test_ib(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_fence *fence = NULL;
|
||||
struct fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
r = amdgpu_asic_set_uvd_clocks(adev, 53300, 40000);
|
||||
|
@ -601,14 +601,14 @@ static int uvd_v5_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
goto error;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(fence, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
goto error;
|
||||
}
|
||||
DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
|
||||
error:
|
||||
amdgpu_fence_unref(&fence);
|
||||
fence_put(fence);
|
||||
amdgpu_asic_set_uvd_clocks(adev, 0, 0);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -575,7 +575,7 @@ static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
|
|||
*/
|
||||
static int uvd_v6_0_ring_test_ib(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_fence *fence = NULL;
|
||||
struct fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
r = amdgpu_uvd_get_create_msg(ring, 1, NULL);
|
||||
|
@ -590,14 +590,14 @@ static int uvd_v6_0_ring_test_ib(struct amdgpu_ring *ring)
|
|||
goto error;
|
||||
}
|
||||
|
||||
r = amdgpu_fence_wait(fence, false);
|
||||
r = fence_wait(fence, false);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
|
||||
goto error;
|
||||
}
|
||||
DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
|
||||
error:
|
||||
amdgpu_fence_unref(&fence);
|
||||
fence_put(fence);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,14 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
|
|||
u32 tmp;
|
||||
unsigned ret;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
/* Fiji is single pipe */
|
||||
if (adev->asic_type == CHIP_FIJI) {
|
||||
ret = AMDGPU_VCE_HARVEST_VCE1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Tonga and CZ are dual or single pipe */
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
|
||||
VCE_HARVEST_FUSE_MACRO__MASK) >>
|
||||
VCE_HARVEST_FUSE_MACRO__SHIFT;
|
||||
|
|
|
@ -203,6 +203,17 @@ static const u32 tonga_mgcg_cgcg_init[] =
|
|||
mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
|
||||
};
|
||||
|
||||
static const u32 fiji_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100,
|
||||
mmPCIE_INDEX, 0xffffffff, 0x0140001c,
|
||||
mmPCIE_DATA, 0x000f0000, 0x00000000,
|
||||
mmSMC_IND_INDEX_4, 0xffffffff, 0xC060000C,
|
||||
mmSMC_IND_DATA_4, 0xc0000fff, 0x00000100,
|
||||
mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
|
||||
mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
|
||||
};
|
||||
|
||||
static const u32 iceland_mgcg_cgcg_init[] =
|
||||
{
|
||||
mmPCIE_INDEX, 0xffffffff, ixPCIE_CNTL2,
|
||||
|
@ -232,6 +243,11 @@ static void vi_init_golden_registers(struct amdgpu_device *adev)
|
|||
iceland_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init));
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
fiji_mgcg_cgcg_init,
|
||||
(const u32)ARRAY_SIZE(fiji_mgcg_cgcg_init));
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
amdgpu_program_register_sequence(adev,
|
||||
tonga_mgcg_cgcg_init,
|
||||
|
@ -261,7 +277,7 @@ static u32 vi_get_xclk(struct amdgpu_device *adev)
|
|||
u32 reference_clock = adev->clock.spll.reference_freq;
|
||||
u32 tmp;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return reference_clock;
|
||||
|
||||
tmp = RREG32_SMC(ixCG_CLKPIN_CNTL_2);
|
||||
|
@ -362,6 +378,26 @@ static struct amdgpu_allowed_register_entry cz_allowed_read_registers[] = {
|
|||
|
||||
static struct amdgpu_allowed_register_entry vi_allowed_read_registers[] = {
|
||||
{mmGRBM_STATUS, false},
|
||||
{mmGRBM_STATUS2, false},
|
||||
{mmGRBM_STATUS_SE0, false},
|
||||
{mmGRBM_STATUS_SE1, false},
|
||||
{mmGRBM_STATUS_SE2, false},
|
||||
{mmGRBM_STATUS_SE3, false},
|
||||
{mmSRBM_STATUS, false},
|
||||
{mmSRBM_STATUS2, false},
|
||||
{mmSRBM_STATUS3, false},
|
||||
{mmSDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET, false},
|
||||
{mmSDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET, false},
|
||||
{mmCP_STAT, false},
|
||||
{mmCP_STALLED_STAT1, false},
|
||||
{mmCP_STALLED_STAT2, false},
|
||||
{mmCP_STALLED_STAT3, false},
|
||||
{mmCP_CPF_BUSY_STAT, false},
|
||||
{mmCP_CPF_STALLED_STAT1, false},
|
||||
{mmCP_CPF_STATUS, false},
|
||||
{mmCP_CPC_BUSY_STAT, false},
|
||||
{mmCP_CPC_STALLED_STAT1, false},
|
||||
{mmCP_CPC_STATUS, false},
|
||||
{mmGB_ADDR_CONFIG, false},
|
||||
{mmMC_ARB_RAMCFG, false},
|
||||
{mmGB_TILE_MODE0, false},
|
||||
|
@ -449,6 +485,7 @@ static int vi_read_register(struct amdgpu_device *adev, u32 se_num,
|
|||
asic_register_table = tonga_allowed_read_registers;
|
||||
size = ARRAY_SIZE(tonga_allowed_read_registers);
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
case CHIP_TONGA:
|
||||
case CHIP_CARRIZO:
|
||||
asic_register_table = cz_allowed_read_registers;
|
||||
|
@ -751,7 +788,7 @@ static void vi_gpu_soft_reset(struct amdgpu_device *adev, u32 reset_mask)
|
|||
srbm_soft_reset =
|
||||
REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
|
||||
|
||||
if (!(adev->flags & AMDGPU_IS_APU)) {
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
if (reset_mask & AMDGPU_RESET_MC)
|
||||
srbm_soft_reset =
|
||||
REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
|
||||
|
@ -971,7 +1008,7 @@ static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
if (amdgpu_pcie_gen2 == 0)
|
||||
return;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
|
||||
|
@ -999,7 +1036,7 @@ static void vi_enable_doorbell_aperture(struct amdgpu_device *adev,
|
|||
u32 tmp;
|
||||
|
||||
/* not necessary on CZ */
|
||||
if (adev->flags & AMDGPU_IS_APU)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
tmp = RREG32(mmBIF_DOORBELL_APER_EN);
|
||||
|
@ -1127,6 +1164,74 @@ static const struct amdgpu_ip_block_version tonga_ip_blocks[] =
|
|||
},
|
||||
};
|
||||
|
||||
static const struct amdgpu_ip_block_version fiji_ip_blocks[] =
|
||||
{
|
||||
/* ORDER MATTERS! */
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_COMMON,
|
||||
.major = 2,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &vi_common_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_GMC,
|
||||
.major = 8,
|
||||
.minor = 5,
|
||||
.rev = 0,
|
||||
.funcs = &gmc_v8_0_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_IH,
|
||||
.major = 3,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &tonga_ih_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_SMC,
|
||||
.major = 7,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &fiji_dpm_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_DCE,
|
||||
.major = 10,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &dce_v10_0_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_GFX,
|
||||
.major = 8,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &gfx_v8_0_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_SDMA,
|
||||
.major = 3,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &sdma_v3_0_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_UVD,
|
||||
.major = 6,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &uvd_v6_0_ip_funcs,
|
||||
},
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_VCE,
|
||||
.major = 3,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &vce_v3_0_ip_funcs,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct amdgpu_ip_block_version cz_ip_blocks[] =
|
||||
{
|
||||
/* ORDER MATTERS! */
|
||||
|
@ -1202,6 +1307,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
|
|||
adev->ip_blocks = topaz_ip_blocks;
|
||||
adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks);
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
adev->ip_blocks = fiji_ip_blocks;
|
||||
adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks);
|
||||
break;
|
||||
case CHIP_TONGA:
|
||||
adev->ip_blocks = tonga_ip_blocks;
|
||||
adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks);
|
||||
|
@ -1248,7 +1357,7 @@ static int vi_common_early_init(void *handle)
|
|||
bool smc_enabled = false;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->flags & AMDGPU_IS_APU) {
|
||||
if (adev->flags & AMD_IS_APU) {
|
||||
adev->smc_rreg = &cz_smc_rreg;
|
||||
adev->smc_wreg = &cz_smc_wreg;
|
||||
} else {
|
||||
|
@ -1279,6 +1388,7 @@ static int vi_common_early_init(void *handle)
|
|||
if (amdgpu_smc_load_fw && smc_enabled)
|
||||
adev->firmware.smu_load = true;
|
||||
break;
|
||||
case CHIP_FIJI:
|
||||
case CHIP_TONGA:
|
||||
adev->has_uvd = true;
|
||||
adev->cg_flags = 0;
|
||||
|
|
|
@ -30,7 +30,7 @@ int cz_smu_start(struct amdgpu_device *adev);
|
|||
int cz_smu_fini(struct amdgpu_device *adev);
|
||||
|
||||
extern const struct amd_ip_funcs tonga_dpm_ip_funcs;
|
||||
|
||||
extern const struct amd_ip_funcs fiji_dpm_ip_funcs;
|
||||
extern const struct amd_ip_funcs iceland_dpm_ip_funcs;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,45 @@
|
|||
#ifndef __AMD_SHARED_H__
|
||||
#define __AMD_SHARED_H__
|
||||
|
||||
#define AMD_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||
|
||||
/*
|
||||
* Supported GPU families (aligned with amdgpu_drm.h)
|
||||
*/
|
||||
#define AMD_FAMILY_UNKNOWN 0
|
||||
#define AMD_FAMILY_CI 120 /* Bonaire, Hawaii */
|
||||
#define AMD_FAMILY_KV 125 /* Kaveri, Kabini, Mullins */
|
||||
#define AMD_FAMILY_VI 130 /* Iceland, Tonga */
|
||||
#define AMD_FAMILY_CZ 135 /* Carrizo */
|
||||
|
||||
/*
|
||||
* Supported ASIC types
|
||||
*/
|
||||
enum amd_asic_type {
|
||||
CHIP_BONAIRE = 0,
|
||||
CHIP_KAVERI,
|
||||
CHIP_KABINI,
|
||||
CHIP_HAWAII,
|
||||
CHIP_MULLINS,
|
||||
CHIP_TOPAZ,
|
||||
CHIP_TONGA,
|
||||
CHIP_FIJI,
|
||||
CHIP_CARRIZO,
|
||||
CHIP_LAST,
|
||||
};
|
||||
|
||||
/*
|
||||
* Chip flags
|
||||
*/
|
||||
enum amd_chip_flags {
|
||||
AMD_ASIC_MASK = 0x0000ffffUL,
|
||||
AMD_FLAGS_MASK = 0xffff0000UL,
|
||||
AMD_IS_MOBILITY = 0x00010000UL,
|
||||
AMD_IS_APU = 0x00020000UL,
|
||||
AMD_IS_PX = 0x00040000UL,
|
||||
AMD_EXP_HW_SUPPORT = 0x00080000UL,
|
||||
};
|
||||
|
||||
enum amd_ip_block_type {
|
||||
AMD_IP_BLOCK_TYPE_COMMON,
|
||||
AMD_IP_BLOCK_TYPE_GMC,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,624 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef _CGS_COMMON_H
|
||||
#define _CGS_COMMON_H
|
||||
|
||||
#include "amd_shared.h"
|
||||
|
||||
/**
|
||||
* enum cgs_gpu_mem_type - GPU memory types
|
||||
*/
|
||||
enum cgs_gpu_mem_type {
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_FB,
|
||||
CGS_GPU_MEM_TYPE__INVISIBLE_FB,
|
||||
CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
|
||||
CGS_GPU_MEM_TYPE__INVISIBLE_CONTIG_FB,
|
||||
CGS_GPU_MEM_TYPE__GART_CACHEABLE,
|
||||
CGS_GPU_MEM_TYPE__GART_WRITECOMBINE
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cgs_ind_reg - Indirect register spaces
|
||||
*/
|
||||
enum cgs_ind_reg {
|
||||
CGS_IND_REG__MMIO,
|
||||
CGS_IND_REG__PCIE,
|
||||
CGS_IND_REG__SMC,
|
||||
CGS_IND_REG__UVD_CTX,
|
||||
CGS_IND_REG__DIDT,
|
||||
CGS_IND_REG__AUDIO_ENDPT
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cgs_clock - Clocks controlled by the SMU
|
||||
*/
|
||||
enum cgs_clock {
|
||||
CGS_CLOCK__SCLK,
|
||||
CGS_CLOCK__MCLK,
|
||||
CGS_CLOCK__VCLK,
|
||||
CGS_CLOCK__DCLK,
|
||||
CGS_CLOCK__ECLK,
|
||||
CGS_CLOCK__ACLK,
|
||||
CGS_CLOCK__ICLK,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cgs_engine - Engines that can be statically power-gated
|
||||
*/
|
||||
enum cgs_engine {
|
||||
CGS_ENGINE__UVD,
|
||||
CGS_ENGINE__VCE,
|
||||
CGS_ENGINE__VP8,
|
||||
CGS_ENGINE__ACP_DMA,
|
||||
CGS_ENGINE__ACP_DSP0,
|
||||
CGS_ENGINE__ACP_DSP1,
|
||||
CGS_ENGINE__ISP,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cgs_voltage_planes - Voltage planes for external camera HW
|
||||
*/
|
||||
enum cgs_voltage_planes {
|
||||
CGS_VOLTAGE_PLANE__SENSOR0,
|
||||
CGS_VOLTAGE_PLANE__SENSOR1,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
/*
|
||||
* enum cgs_ucode_id - Firmware types for different IPs
|
||||
*/
|
||||
enum cgs_ucode_id {
|
||||
CGS_UCODE_ID_SMU = 0,
|
||||
CGS_UCODE_ID_SDMA0,
|
||||
CGS_UCODE_ID_SDMA1,
|
||||
CGS_UCODE_ID_CP_CE,
|
||||
CGS_UCODE_ID_CP_PFP,
|
||||
CGS_UCODE_ID_CP_ME,
|
||||
CGS_UCODE_ID_CP_MEC,
|
||||
CGS_UCODE_ID_CP_MEC_JT1,
|
||||
CGS_UCODE_ID_CP_MEC_JT2,
|
||||
CGS_UCODE_ID_GMCON_RENG,
|
||||
CGS_UCODE_ID_RLC_G,
|
||||
CGS_UCODE_ID_MAXIMUM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cgs_clock_limits - Clock limits
|
||||
*
|
||||
* Clocks are specified in 10KHz units.
|
||||
*/
|
||||
struct cgs_clock_limits {
|
||||
unsigned min; /**< Minimum supported frequency */
|
||||
unsigned max; /**< Maxumim supported frequency */
|
||||
unsigned sustainable; /**< Thermally sustainable frequency */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cgs_firmware_info - Firmware information
|
||||
*/
|
||||
struct cgs_firmware_info {
|
||||
uint16_t version;
|
||||
uint16_t feature_version;
|
||||
uint32_t image_size;
|
||||
uint64_t mc_addr;
|
||||
void *kptr;
|
||||
};
|
||||
|
||||
typedef unsigned long cgs_handle_t;
|
||||
|
||||
/**
|
||||
* cgs_gpu_mem_info() - Return information about memory heaps
|
||||
* @cgs_device: opaque device handle
|
||||
* @type: memory type
|
||||
* @mc_start: Start MC address of the heap (output)
|
||||
* @mc_size: MC address space size (output)
|
||||
* @mem_size: maximum amount of memory available for allocation (output)
|
||||
*
|
||||
* This function returns information about memory heaps. The type
|
||||
* parameter is used to select the memory heap. The mc_start and
|
||||
* mc_size for GART heaps may be bigger than the memory available for
|
||||
* allocation.
|
||||
*
|
||||
* mc_start and mc_size are undefined for non-contiguous FB memory
|
||||
* types, since buffers allocated with these types may or may not be
|
||||
* GART mapped.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_gpu_mem_info_t)(void *cgs_device, enum cgs_gpu_mem_type type,
|
||||
uint64_t *mc_start, uint64_t *mc_size,
|
||||
uint64_t *mem_size);
|
||||
|
||||
/**
|
||||
* cgs_gmap_kmem() - map kernel memory to GART aperture
|
||||
* @cgs_device: opaque device handle
|
||||
* @kmem: pointer to kernel memory
|
||||
* @size: size to map
|
||||
* @min_offset: minimum offset from start of GART aperture
|
||||
* @max_offset: maximum offset from start of GART aperture
|
||||
* @kmem_handle: kernel memory handle (output)
|
||||
* @mcaddr: MC address (output)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_gmap_kmem_t)(void *cgs_device, void *kmem, uint64_t size,
|
||||
uint64_t min_offset, uint64_t max_offset,
|
||||
cgs_handle_t *kmem_handle, uint64_t *mcaddr);
|
||||
|
||||
/**
|
||||
* cgs_gunmap_kmem() - unmap kernel memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @kmem_handle: kernel memory handle returned by gmap_kmem
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_gunmap_kmem_t)(void *cgs_device, cgs_handle_t kmem_handle);
|
||||
|
||||
/**
|
||||
* cgs_alloc_gpu_mem() - Allocate GPU memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @type: memory type
|
||||
* @size: size in bytes
|
||||
* @align: alignment in bytes
|
||||
* @min_offset: minimum offset from start of heap
|
||||
* @max_offset: maximum offset from start of heap
|
||||
* @handle: memory handle (output)
|
||||
*
|
||||
* The memory types CGS_GPU_MEM_TYPE_*_CONTIG_FB force contiguous
|
||||
* memory allocation. This guarantees that the MC address returned by
|
||||
* cgs_gmap_gpu_mem is not mapped through the GART. The non-contiguous
|
||||
* FB memory types may be GART mapped depending on memory
|
||||
* fragmentation and memory allocator policies.
|
||||
*
|
||||
* If min/max_offset are non-0, the allocation will be forced to
|
||||
* reside between these offsets in its respective memory heap. The
|
||||
* base address that the offset relates to, depends on the memory
|
||||
* type.
|
||||
*
|
||||
* - CGS_GPU_MEM_TYPE__*_CONTIG_FB: FB MC base address
|
||||
* - CGS_GPU_MEM_TYPE__GART_*: GART aperture base address
|
||||
* - others: undefined, don't use with max_offset
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_alloc_gpu_mem_t)(void *cgs_device, enum cgs_gpu_mem_type type,
|
||||
uint64_t size, uint64_t align,
|
||||
uint64_t min_offset, uint64_t max_offset,
|
||||
cgs_handle_t *handle);
|
||||
|
||||
/**
|
||||
* cgs_free_gpu_mem() - Free GPU memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @handle: memory handle returned by alloc or import
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_free_gpu_mem_t)(void *cgs_device, cgs_handle_t handle);
|
||||
|
||||
/**
|
||||
* cgs_gmap_gpu_mem() - GPU-map GPU memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @handle: memory handle returned by alloc or import
|
||||
* @mcaddr: MC address (output)
|
||||
*
|
||||
* Ensures that a buffer is GPU accessible and returns its MC address.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_gmap_gpu_mem_t)(void *cgs_device, cgs_handle_t handle,
|
||||
uint64_t *mcaddr);
|
||||
|
||||
/**
|
||||
* cgs_gunmap_gpu_mem() - GPU-unmap GPU memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @handle: memory handle returned by alloc or import
|
||||
*
|
||||
* Allows the buffer to be migrated while it's not used by the GPU.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_gunmap_gpu_mem_t)(void *cgs_device, cgs_handle_t handle);
|
||||
|
||||
/**
|
||||
* cgs_kmap_gpu_mem() - Kernel-map GPU memory
|
||||
*
|
||||
* @cgs_device: opaque device handle
|
||||
* @handle: memory handle returned by alloc or import
|
||||
* @map: Kernel virtual address the memory was mapped to (output)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_kmap_gpu_mem_t)(void *cgs_device, cgs_handle_t handle,
|
||||
void **map);
|
||||
|
||||
/**
|
||||
* cgs_kunmap_gpu_mem() - Kernel-unmap GPU memory
|
||||
* @cgs_device: opaque device handle
|
||||
* @handle: memory handle returned by alloc or import
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_kunmap_gpu_mem_t)(void *cgs_device, cgs_handle_t handle);
|
||||
|
||||
/**
|
||||
* cgs_read_register() - Read an MMIO register
|
||||
* @cgs_device: opaque device handle
|
||||
* @offset: register offset
|
||||
*
|
||||
* Return: register value
|
||||
*/
|
||||
typedef uint32_t (*cgs_read_register_t)(void *cgs_device, unsigned offset);
|
||||
|
||||
/**
|
||||
* cgs_write_register() - Write an MMIO register
|
||||
* @cgs_device: opaque device handle
|
||||
* @offset: register offset
|
||||
* @value: register value
|
||||
*/
|
||||
typedef void (*cgs_write_register_t)(void *cgs_device, unsigned offset,
|
||||
uint32_t value);
|
||||
|
||||
/**
|
||||
* cgs_read_ind_register() - Read an indirect register
|
||||
* @cgs_device: opaque device handle
|
||||
* @offset: register offset
|
||||
*
|
||||
* Return: register value
|
||||
*/
|
||||
typedef uint32_t (*cgs_read_ind_register_t)(void *cgs_device, enum cgs_ind_reg space,
|
||||
unsigned index);
|
||||
|
||||
/**
|
||||
* cgs_write_ind_register() - Write an indirect register
|
||||
* @cgs_device: opaque device handle
|
||||
* @offset: register offset
|
||||
* @value: register value
|
||||
*/
|
||||
typedef void (*cgs_write_ind_register_t)(void *cgs_device, enum cgs_ind_reg space,
|
||||
unsigned index, uint32_t value);
|
||||
|
||||
/**
|
||||
* cgs_read_pci_config_byte() - Read byte from PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address
|
||||
*
|
||||
* Return: Value read
|
||||
*/
|
||||
typedef uint8_t (*cgs_read_pci_config_byte_t)(void *cgs_device, unsigned addr);
|
||||
|
||||
/**
|
||||
* cgs_read_pci_config_word() - Read word from PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address, must be word-aligned
|
||||
*
|
||||
* Return: Value read
|
||||
*/
|
||||
typedef uint16_t (*cgs_read_pci_config_word_t)(void *cgs_device, unsigned addr);
|
||||
|
||||
/**
|
||||
* cgs_read_pci_config_dword() - Read dword from PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address, must be dword-aligned
|
||||
*
|
||||
* Return: Value read
|
||||
*/
|
||||
typedef uint32_t (*cgs_read_pci_config_dword_t)(void *cgs_device,
|
||||
unsigned addr);
|
||||
|
||||
/**
|
||||
* cgs_write_pci_config_byte() - Write byte to PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address
|
||||
* @value: value to write
|
||||
*/
|
||||
typedef void (*cgs_write_pci_config_byte_t)(void *cgs_device, unsigned addr,
|
||||
uint8_t value);
|
||||
|
||||
/**
|
||||
* cgs_write_pci_config_word() - Write byte to PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address, must be word-aligned
|
||||
* @value: value to write
|
||||
*/
|
||||
typedef void (*cgs_write_pci_config_word_t)(void *cgs_device, unsigned addr,
|
||||
uint16_t value);
|
||||
|
||||
/**
|
||||
* cgs_write_pci_config_dword() - Write byte to PCI configuration space
|
||||
* @cgs_device: opaque device handle
|
||||
* @addr: address, must be dword-aligned
|
||||
* @value: value to write
|
||||
*/
|
||||
typedef void (*cgs_write_pci_config_dword_t)(void *cgs_device, unsigned addr,
|
||||
uint32_t value);
|
||||
|
||||
/**
|
||||
* cgs_atom_get_data_table() - Get a pointer to an ATOM BIOS data table
|
||||
* @cgs_device: opaque device handle
|
||||
* @table: data table index
|
||||
* @size: size of the table (output, may be NULL)
|
||||
* @frev: table format revision (output, may be NULL)
|
||||
* @crev: table content revision (output, may be NULL)
|
||||
*
|
||||
* Return: Pointer to start of the table, or NULL on failure
|
||||
*/
|
||||
typedef const void *(*cgs_atom_get_data_table_t)(
|
||||
void *cgs_device, unsigned table,
|
||||
uint16_t *size, uint8_t *frev, uint8_t *crev);
|
||||
|
||||
/**
|
||||
* cgs_atom_get_cmd_table_revs() - Get ATOM BIOS command table revisions
|
||||
* @cgs_device: opaque device handle
|
||||
* @table: data table index
|
||||
* @frev: table format revision (output, may be NULL)
|
||||
* @crev: table content revision (output, may be NULL)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_atom_get_cmd_table_revs_t)(void *cgs_device, unsigned table,
|
||||
uint8_t *frev, uint8_t *crev);
|
||||
|
||||
/**
|
||||
* cgs_atom_exec_cmd_table() - Execute an ATOM BIOS command table
|
||||
* @cgs_device: opaque device handle
|
||||
* @table: command table index
|
||||
* @args: arguments
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_atom_exec_cmd_table_t)(void *cgs_device,
|
||||
unsigned table, void *args);
|
||||
|
||||
/**
|
||||
* cgs_create_pm_request() - Create a power management request
|
||||
* @cgs_device: opaque device handle
|
||||
* @request: handle of created PM request (output)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_create_pm_request_t)(void *cgs_device, cgs_handle_t *request);
|
||||
|
||||
/**
|
||||
* cgs_destroy_pm_request() - Destroy a power management request
|
||||
* @cgs_device: opaque device handle
|
||||
* @request: handle of created PM request
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_destroy_pm_request_t)(void *cgs_device, cgs_handle_t request);
|
||||
|
||||
/**
|
||||
* cgs_set_pm_request() - Activate or deactiveate a PM request
|
||||
* @cgs_device: opaque device handle
|
||||
* @request: PM request handle
|
||||
* @active: 0 = deactivate, non-0 = activate
|
||||
*
|
||||
* While a PM request is active, its minimum clock requests are taken
|
||||
* into account as the requested engines are powered up. When the
|
||||
* request is inactive, the engines may be powered down and clocks may
|
||||
* be lower, depending on other PM requests by other driver
|
||||
* components.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_set_pm_request_t)(void *cgs_device, cgs_handle_t request,
|
||||
int active);
|
||||
|
||||
/**
|
||||
* cgs_pm_request_clock() - Request a minimum frequency for a specific clock
|
||||
* @cgs_device: opaque device handle
|
||||
* @request: PM request handle
|
||||
* @clock: which clock?
|
||||
* @freq: requested min. frequency in 10KHz units (0 to clear request)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_pm_request_clock_t)(void *cgs_device, cgs_handle_t request,
|
||||
enum cgs_clock clock, unsigned freq);
|
||||
|
||||
/**
|
||||
* cgs_pm_request_engine() - Request an engine to be powered up
|
||||
* @cgs_device: opaque device handle
|
||||
* @request: PM request handle
|
||||
* @engine: which engine?
|
||||
* @powered: 0 = powered down, non-0 = powered up
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_pm_request_engine_t)(void *cgs_device, cgs_handle_t request,
|
||||
enum cgs_engine engine, int powered);
|
||||
|
||||
/**
|
||||
* cgs_pm_query_clock_limits() - Query clock frequency limits
|
||||
* @cgs_device: opaque device handle
|
||||
* @clock: which clock?
|
||||
* @limits: clock limits
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_pm_query_clock_limits_t)(void *cgs_device,
|
||||
enum cgs_clock clock,
|
||||
struct cgs_clock_limits *limits);
|
||||
|
||||
/**
|
||||
* cgs_set_camera_voltages() - Apply specific voltages to PMIC voltage planes
|
||||
* @cgs_device: opaque device handle
|
||||
* @mask: bitmask of voltages to change (1<<CGS_VOLTAGE_PLANE__xyz|...)
|
||||
* @voltages: pointer to array of voltage values in 1mV units
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_set_camera_voltages_t)(void *cgs_device, uint32_t mask,
|
||||
const uint32_t *voltages);
|
||||
/**
|
||||
* cgs_get_firmware_info - Get the firmware information from core driver
|
||||
* @cgs_device: opaque device handle
|
||||
* @type: the firmware type
|
||||
* @info: returend firmware information
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_get_firmware_info)(void *cgs_device,
|
||||
enum cgs_ucode_id type,
|
||||
struct cgs_firmware_info *info);
|
||||
|
||||
typedef int(*cgs_set_powergating_state)(void *cgs_device,
|
||||
enum amd_ip_block_type block_type,
|
||||
enum amd_powergating_state state);
|
||||
|
||||
typedef int(*cgs_set_clockgating_state)(void *cgs_device,
|
||||
enum amd_ip_block_type block_type,
|
||||
enum amd_clockgating_state state);
|
||||
|
||||
struct cgs_ops {
|
||||
/* memory management calls (similar to KFD interface) */
|
||||
cgs_gpu_mem_info_t gpu_mem_info;
|
||||
cgs_gmap_kmem_t gmap_kmem;
|
||||
cgs_gunmap_kmem_t gunmap_kmem;
|
||||
cgs_alloc_gpu_mem_t alloc_gpu_mem;
|
||||
cgs_free_gpu_mem_t free_gpu_mem;
|
||||
cgs_gmap_gpu_mem_t gmap_gpu_mem;
|
||||
cgs_gunmap_gpu_mem_t gunmap_gpu_mem;
|
||||
cgs_kmap_gpu_mem_t kmap_gpu_mem;
|
||||
cgs_kunmap_gpu_mem_t kunmap_gpu_mem;
|
||||
/* MMIO access */
|
||||
cgs_read_register_t read_register;
|
||||
cgs_write_register_t write_register;
|
||||
cgs_read_ind_register_t read_ind_register;
|
||||
cgs_write_ind_register_t write_ind_register;
|
||||
/* PCI configuration space access */
|
||||
cgs_read_pci_config_byte_t read_pci_config_byte;
|
||||
cgs_read_pci_config_word_t read_pci_config_word;
|
||||
cgs_read_pci_config_dword_t read_pci_config_dword;
|
||||
cgs_write_pci_config_byte_t write_pci_config_byte;
|
||||
cgs_write_pci_config_word_t write_pci_config_word;
|
||||
cgs_write_pci_config_dword_t write_pci_config_dword;
|
||||
/* ATOM BIOS */
|
||||
cgs_atom_get_data_table_t atom_get_data_table;
|
||||
cgs_atom_get_cmd_table_revs_t atom_get_cmd_table_revs;
|
||||
cgs_atom_exec_cmd_table_t atom_exec_cmd_table;
|
||||
/* Power management */
|
||||
cgs_create_pm_request_t create_pm_request;
|
||||
cgs_destroy_pm_request_t destroy_pm_request;
|
||||
cgs_set_pm_request_t set_pm_request;
|
||||
cgs_pm_request_clock_t pm_request_clock;
|
||||
cgs_pm_request_engine_t pm_request_engine;
|
||||
cgs_pm_query_clock_limits_t pm_query_clock_limits;
|
||||
cgs_set_camera_voltages_t set_camera_voltages;
|
||||
/* Firmware Info */
|
||||
cgs_get_firmware_info get_firmware_info;
|
||||
/* cg pg interface*/
|
||||
cgs_set_powergating_state set_powergating_state;
|
||||
cgs_set_clockgating_state set_clockgating_state;
|
||||
/* ACPI (TODO) */
|
||||
};
|
||||
|
||||
struct cgs_os_ops; /* To be define in OS-specific CGS header */
|
||||
|
||||
struct cgs_device
|
||||
{
|
||||
const struct cgs_ops *ops;
|
||||
const struct cgs_os_ops *os_ops;
|
||||
/* to be embedded at the start of driver private structure */
|
||||
};
|
||||
|
||||
/* Convenience macros that make CGS indirect function calls look like
|
||||
* normal function calls */
|
||||
#define CGS_CALL(func,dev,...) \
|
||||
(((struct cgs_device *)dev)->ops->func(dev, ##__VA_ARGS__))
|
||||
#define CGS_OS_CALL(func,dev,...) \
|
||||
(((struct cgs_device *)dev)->os_ops->func(dev, ##__VA_ARGS__))
|
||||
|
||||
#define cgs_gpu_mem_info(dev,type,mc_start,mc_size,mem_size) \
|
||||
CGS_CALL(gpu_mem_info,dev,type,mc_start,mc_size,mem_size)
|
||||
#define cgs_gmap_kmem(dev,kmem,size,min_off,max_off,kmem_handle,mcaddr) \
|
||||
CGS_CALL(gmap_kmem,dev,kmem,size,min_off,max_off,kmem_handle,mcaddr)
|
||||
#define cgs_gunmap_kmem(dev,kmem_handle) \
|
||||
CGS_CALL(gunmap_kmem,dev,keme_handle)
|
||||
#define cgs_alloc_gpu_mem(dev,type,size,align,min_off,max_off,handle) \
|
||||
CGS_CALL(alloc_gpu_mem,dev,type,size,align,min_off,max_off,handle)
|
||||
#define cgs_free_gpu_mem(dev,handle) \
|
||||
CGS_CALL(free_gpu_mem,dev,handle)
|
||||
#define cgs_gmap_gpu_mem(dev,handle,mcaddr) \
|
||||
CGS_CALL(gmap_gpu_mem,dev,handle,mcaddr)
|
||||
#define cgs_gunmap_gpu_mem(dev,handle) \
|
||||
CGS_CALL(gunmap_gpu_mem,dev,handle)
|
||||
#define cgs_kmap_gpu_mem(dev,handle,map) \
|
||||
CGS_CALL(kmap_gpu_mem,dev,handle,map)
|
||||
#define cgs_kunmap_gpu_mem(dev,handle) \
|
||||
CGS_CALL(kunmap_gpu_mem,dev,handle)
|
||||
|
||||
#define cgs_read_register(dev,offset) \
|
||||
CGS_CALL(read_register,dev,offset)
|
||||
#define cgs_write_register(dev,offset,value) \
|
||||
CGS_CALL(write_register,dev,offset,value)
|
||||
#define cgs_read_ind_register(dev,space,index) \
|
||||
CGS_CALL(read_ind_register,dev,space,index)
|
||||
#define cgs_write_ind_register(dev,space,index,value) \
|
||||
CGS_CALL(write_ind_register,dev,space,index,value)
|
||||
|
||||
#define cgs_read_pci_config_byte(dev,addr) \
|
||||
CGS_CALL(read_pci_config_byte,dev,addr)
|
||||
#define cgs_read_pci_config_word(dev,addr) \
|
||||
CGS_CALL(read_pci_config_word,dev,addr)
|
||||
#define cgs_read_pci_config_dword(dev,addr) \
|
||||
CGS_CALL(read_pci_config_dword,dev,addr)
|
||||
#define cgs_write_pci_config_byte(dev,addr,value) \
|
||||
CGS_CALL(write_pci_config_byte,dev,addr,value)
|
||||
#define cgs_write_pci_config_word(dev,addr,value) \
|
||||
CGS_CALL(write_pci_config_word,dev,addr,value)
|
||||
#define cgs_write_pci_config_dword(dev,addr,value) \
|
||||
CGS_CALL(write_pci_config_dword,dev,addr,value)
|
||||
|
||||
#define cgs_atom_get_data_table(dev,table,size,frev,crev) \
|
||||
CGS_CALL(atom_get_data_table,dev,table,size,frev,crev)
|
||||
#define cgs_atom_get_cmd_table_revs(dev,table,frev,crev) \
|
||||
CGS_CALL(atom_get_cmd_table_revs,dev,table,frev,crev)
|
||||
#define cgs_atom_exec_cmd_table(dev,table,args) \
|
||||
CGS_CALL(atom_exec_cmd_table,dev,table,args)
|
||||
|
||||
#define cgs_create_pm_request(dev,request) \
|
||||
CGS_CALL(create_pm_request,dev,request)
|
||||
#define cgs_destroy_pm_request(dev,request) \
|
||||
CGS_CALL(destroy_pm_request,dev,request)
|
||||
#define cgs_set_pm_request(dev,request,active) \
|
||||
CGS_CALL(set_pm_request,dev,request,active)
|
||||
#define cgs_pm_request_clock(dev,request,clock,freq) \
|
||||
CGS_CALL(pm_request_clock,dev,request,clock,freq)
|
||||
#define cgs_pm_request_engine(dev,request,engine,powered) \
|
||||
CGS_CALL(pm_request_engine,dev,request,engine,powered)
|
||||
#define cgs_pm_query_clock_limits(dev,clock,limits) \
|
||||
CGS_CALL(pm_query_clock_limits,dev,clock,limits)
|
||||
#define cgs_set_camera_voltages(dev,mask,voltages) \
|
||||
CGS_CALL(set_camera_voltages,dev,mask,voltages)
|
||||
#define cgs_get_firmware_info(dev, type, info) \
|
||||
CGS_CALL(get_firmware_info, dev, type, info)
|
||||
#define cgs_set_powergating_state(dev, block_type, state) \
|
||||
CGS_CALL(set_powergating_state, dev, block_type, state)
|
||||
#define cgs_set_clockgating_state(dev, block_type, state) \
|
||||
CGS_CALL(set_clockgating_state, dev, block_type, state)
|
||||
|
||||
#endif /* _CGS_COMMON_H */
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef _CGS_LINUX_H
|
||||
#define _CGS_LINUX_H
|
||||
|
||||
#include "cgs_common.h"
|
||||
|
||||
/**
|
||||
* cgs_import_gpu_mem() - Import dmabuf handle
|
||||
* @cgs_device: opaque device handle
|
||||
* @dmabuf_fd: DMABuf file descriptor
|
||||
* @handle: memory handle (output)
|
||||
*
|
||||
* Must be called in the process context that dmabuf_fd belongs to.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_import_gpu_mem_t)(void *cgs_device, int dmabuf_fd,
|
||||
cgs_handle_t *handle);
|
||||
|
||||
/**
|
||||
* cgs_irq_source_set_func() - Callback for enabling/disabling interrupt sources
|
||||
* @private_data: private data provided to cgs_add_irq_source
|
||||
* @src_id: interrupt source ID
|
||||
* @type: interrupt type
|
||||
* @enabled: 0 = disable source, non-0 = enable source
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_irq_source_set_func_t)(void *private_data,
|
||||
unsigned src_id, unsigned type,
|
||||
int enabled);
|
||||
|
||||
/**
|
||||
* cgs_irq_handler_func() - Interrupt handler callback
|
||||
* @private_data: private data provided to cgs_add_irq_source
|
||||
* @src_id: interrupt source ID
|
||||
* @iv_entry: pointer to raw ih ring entry
|
||||
*
|
||||
* This callback runs in interrupt context.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_irq_handler_func_t)(void *private_data,
|
||||
unsigned src_id, const uint32_t *iv_entry);
|
||||
|
||||
/**
|
||||
* cgs_add_irq_source() - Add an IRQ source
|
||||
* @cgs_device: opaque device handle
|
||||
* @src_id: interrupt source ID
|
||||
* @num_types: number of interrupt types that can be independently enabled
|
||||
* @set: callback function to enable/disable an interrupt type
|
||||
* @handler: interrupt handler callback
|
||||
* @private_data: private data to pass to callback functions
|
||||
*
|
||||
* The same IRQ source can be added only once. Adding an IRQ source
|
||||
* indicates ownership of that IRQ source and all its IRQ types.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_add_irq_source_t)(void *cgs_device, unsigned src_id,
|
||||
unsigned num_types,
|
||||
cgs_irq_source_set_func_t set,
|
||||
cgs_irq_handler_func_t handler,
|
||||
void *private_data);
|
||||
|
||||
/**
|
||||
* cgs_irq_get() - Request enabling an IRQ source and type
|
||||
* @cgs_device: opaque device handle
|
||||
* @src_id: interrupt source ID
|
||||
* @type: interrupt type
|
||||
*
|
||||
* cgs_irq_get and cgs_irq_put calls must be balanced. They count
|
||||
* "references" to IRQ sources.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_irq_get_t)(void *cgs_device, unsigned src_id, unsigned type);
|
||||
|
||||
/**
|
||||
* cgs_irq_put() - Indicate IRQ source is no longer needed
|
||||
* @cgs_device: opaque device handle
|
||||
* @src_id: interrupt source ID
|
||||
* @type: interrupt type
|
||||
*
|
||||
* cgs_irq_get and cgs_irq_put calls must be balanced. They count
|
||||
* "references" to IRQ sources. Even after cgs_irq_put is called, the
|
||||
* IRQ handler may still be called if there are more refecences to
|
||||
* the IRQ source.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise
|
||||
*/
|
||||
typedef int (*cgs_irq_put_t)(void *cgs_device, unsigned src_id, unsigned type);
|
||||
|
||||
struct cgs_os_ops {
|
||||
cgs_import_gpu_mem_t import_gpu_mem;
|
||||
|
||||
/* IRQ handling */
|
||||
cgs_add_irq_source_t add_irq_source;
|
||||
cgs_irq_get_t irq_get;
|
||||
cgs_irq_put_t irq_put;
|
||||
};
|
||||
|
||||
#define cgs_import_gpu_mem(dev,dmabuf_fd,handle) \
|
||||
CGS_OS_CALL(import_gpu_mem,dev,dmabuf_fd,handle)
|
||||
#define cgs_add_irq_source(dev,src_id,num_types,set,handler,private_data) \
|
||||
CGS_OS_CALL(add_irq_source,dev,src_id,num_types,set,handler, \
|
||||
private_data)
|
||||
#define cgs_irq_get(dev,src_id,type) \
|
||||
CGS_OS_CALL(irq_get,dev,src_id,type)
|
||||
#define cgs_irq_put(dev,src_id,type) \
|
||||
CGS_OS_CALL(irq_put,dev,src_id,type)
|
||||
|
||||
#endif /* _CGS_LINUX_H */
|
|
@ -146,6 +146,9 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
|
|||
#define ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE 0x00200000 // Does the driver supports VR HOT GPIO Configurable.
|
||||
#define ATOM_PP_PLATFORM_CAP_TEMP_INVERSION 0x00400000 // Does the driver supports Temp Inversion feature.
|
||||
#define ATOM_PP_PLATFORM_CAP_EVV 0x00800000
|
||||
#define ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL 0x01000000
|
||||
#define ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE 0x02000000
|
||||
#define ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC 0x04000000
|
||||
|
||||
typedef struct _ATOM_PPLIB_POWERPLAYTABLE
|
||||
{
|
||||
|
@ -673,7 +676,8 @@ typedef struct _ATOM_PPLIB_POWERTUNE_Table_V1
|
|||
UCHAR revid;
|
||||
ATOM_PowerTune_Table power_tune_table;
|
||||
USHORT usMaximumPowerDeliveryLimit;
|
||||
USHORT usReserve[7];
|
||||
USHORT usTjMax;
|
||||
USHORT usReserve[6];
|
||||
} ATOM_PPLIB_POWERTUNE_Table_V1;
|
||||
|
||||
#define ATOM_PPM_A_A 1
|
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "gpu_scheduler.h"
|
||||
|
||||
/* Initialize a given run queue struct */
|
||||
static void amd_sched_rq_init(struct amd_sched_rq *rq)
|
||||
{
|
||||
INIT_LIST_HEAD(&rq->entities);
|
||||
mutex_init(&rq->lock);
|
||||
rq->current_entity = NULL;
|
||||
}
|
||||
|
||||
static void amd_sched_rq_add_entity(struct amd_sched_rq *rq,
|
||||
struct amd_sched_entity *entity)
|
||||
{
|
||||
mutex_lock(&rq->lock);
|
||||
list_add_tail(&entity->list, &rq->entities);
|
||||
mutex_unlock(&rq->lock);
|
||||
}
|
||||
|
||||
static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
|
||||
struct amd_sched_entity *entity)
|
||||
{
|
||||
mutex_lock(&rq->lock);
|
||||
list_del_init(&entity->list);
|
||||
if (rq->current_entity == entity)
|
||||
rq->current_entity = NULL;
|
||||
mutex_unlock(&rq->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select next entity from a specified run queue with round robin policy.
|
||||
* It could return the same entity as current one if current is the only
|
||||
* available one in the queue. Return NULL if nothing available.
|
||||
*/
|
||||
static struct amd_sched_entity *
|
||||
amd_sched_rq_select_entity(struct amd_sched_rq *rq)
|
||||
{
|
||||
struct amd_sched_entity *entity = rq->current_entity;
|
||||
|
||||
if (entity) {
|
||||
list_for_each_entry_continue(entity, &rq->entities, list) {
|
||||
if (!kfifo_is_empty(&entity->job_queue)) {
|
||||
rq->current_entity = entity;
|
||||
return rq->current_entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(entity, &rq->entities, list) {
|
||||
|
||||
if (!kfifo_is_empty(&entity->job_queue)) {
|
||||
rq->current_entity = entity;
|
||||
return rq->current_entity;
|
||||
}
|
||||
|
||||
if (entity == rq->current_entity)
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function should only been called inside scheduler main
|
||||
* function for thread safety, there is no other protection here.
|
||||
* return ture if scheduler has something ready to run.
|
||||
*
|
||||
* For active_hw_rq, there is only one producer(scheduler thread) and
|
||||
* one consumer(ISR). It should be safe to use this function in scheduler
|
||||
* main thread to decide whether to continue emit more IBs.
|
||||
*/
|
||||
static bool is_scheduler_ready(struct amd_gpu_scheduler *sched)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool full;
|
||||
|
||||
spin_lock_irqsave(&sched->queue_lock, flags);
|
||||
full = atomic64_read(&sched->hw_rq_count) <
|
||||
sched->hw_submission_limit ? true : false;
|
||||
spin_unlock_irqrestore(&sched->queue_lock, flags);
|
||||
|
||||
return full;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select next entity from the kernel run queue, if not available,
|
||||
* return null.
|
||||
*/
|
||||
static struct amd_sched_entity *
|
||||
kernel_rq_select_context(struct amd_gpu_scheduler *sched)
|
||||
{
|
||||
struct amd_sched_entity *sched_entity;
|
||||
struct amd_sched_rq *rq = &sched->kernel_rq;
|
||||
|
||||
mutex_lock(&rq->lock);
|
||||
sched_entity = amd_sched_rq_select_entity(rq);
|
||||
mutex_unlock(&rq->lock);
|
||||
return sched_entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select next entity containing real IB submissions
|
||||
*/
|
||||
static struct amd_sched_entity *
|
||||
select_context(struct amd_gpu_scheduler *sched)
|
||||
{
|
||||
struct amd_sched_entity *wake_entity = NULL;
|
||||
struct amd_sched_entity *tmp;
|
||||
struct amd_sched_rq *rq;
|
||||
|
||||
if (!is_scheduler_ready(sched))
|
||||
return NULL;
|
||||
|
||||
/* Kernel run queue has higher priority than normal run queue*/
|
||||
tmp = kernel_rq_select_context(sched);
|
||||
if (tmp != NULL)
|
||||
goto exit;
|
||||
|
||||
rq = &sched->sched_rq;
|
||||
mutex_lock(&rq->lock);
|
||||
tmp = amd_sched_rq_select_entity(rq);
|
||||
mutex_unlock(&rq->lock);
|
||||
exit:
|
||||
if (sched->current_entity && (sched->current_entity != tmp))
|
||||
wake_entity = sched->current_entity;
|
||||
sched->current_entity = tmp;
|
||||
if (wake_entity && wake_entity->need_wakeup)
|
||||
wake_up(&wake_entity->wait_queue);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init a context entity used by scheduler when submit to HW ring.
|
||||
*
|
||||
* @sched The pointer to the scheduler
|
||||
* @entity The pointer to a valid amd_sched_entity
|
||||
* @rq The run queue this entity belongs
|
||||
* @kernel If this is an entity for the kernel
|
||||
* @jobs The max number of jobs in the job queue
|
||||
*
|
||||
* return 0 if succeed. negative error code on failure
|
||||
*/
|
||||
int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity,
|
||||
struct amd_sched_rq *rq,
|
||||
uint32_t jobs)
|
||||
{
|
||||
uint64_t seq_ring = 0;
|
||||
char name[20];
|
||||
|
||||
if (!(sched && entity && rq))
|
||||
return -EINVAL;
|
||||
|
||||
memset(entity, 0, sizeof(struct amd_sched_entity));
|
||||
seq_ring = ((uint64_t)sched->ring_id) << 60;
|
||||
spin_lock_init(&entity->lock);
|
||||
entity->belongto_rq = rq;
|
||||
entity->scheduler = sched;
|
||||
init_waitqueue_head(&entity->wait_queue);
|
||||
init_waitqueue_head(&entity->wait_emit);
|
||||
entity->fence_context = fence_context_alloc(1);
|
||||
snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context);
|
||||
memcpy(entity->name, name, 20);
|
||||
entity->need_wakeup = false;
|
||||
if(kfifo_alloc(&entity->job_queue,
|
||||
jobs * sizeof(void *),
|
||||
GFP_KERNEL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_init(&entity->queue_lock);
|
||||
atomic64_set(&entity->last_queued_v_seq, seq_ring);
|
||||
atomic64_set(&entity->last_signaled_v_seq, seq_ring);
|
||||
|
||||
/* Add the entity to the run queue */
|
||||
amd_sched_rq_add_entity(rq, entity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query if entity is initialized
|
||||
*
|
||||
* @sched Pointer to scheduler instance
|
||||
* @entity The pointer to a valid scheduler entity
|
||||
*
|
||||
* return true if entity is initialized, false otherwise
|
||||
*/
|
||||
static bool is_context_entity_initialized(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity)
|
||||
{
|
||||
return entity->scheduler == sched &&
|
||||
entity->belongto_rq != NULL;
|
||||
}
|
||||
|
||||
static bool is_context_entity_idle(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity)
|
||||
{
|
||||
/**
|
||||
* Idle means no pending IBs, and the entity is not
|
||||
* currently being used.
|
||||
*/
|
||||
barrier();
|
||||
if ((sched->current_entity != entity) &&
|
||||
kfifo_is_empty(&entity->job_queue))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a context entity
|
||||
*
|
||||
* @sched Pointer to scheduler instance
|
||||
* @entity The pointer to a valid scheduler entity
|
||||
*
|
||||
* return 0 if succeed. negative error code on failure
|
||||
*/
|
||||
int amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity)
|
||||
{
|
||||
int r = 0;
|
||||
struct amd_sched_rq *rq = entity->belongto_rq;
|
||||
|
||||
if (!is_context_entity_initialized(sched, entity))
|
||||
return 0;
|
||||
entity->need_wakeup = true;
|
||||
/**
|
||||
* The client will not queue more IBs during this fini, consume existing
|
||||
* queued IBs
|
||||
*/
|
||||
r = wait_event_timeout(
|
||||
entity->wait_queue,
|
||||
is_context_entity_idle(sched, entity),
|
||||
msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS)
|
||||
) ? 0 : -1;
|
||||
|
||||
if (r) {
|
||||
if (entity->is_pending)
|
||||
DRM_INFO("Entity %p is in waiting state during fini,\
|
||||
all pending ibs will be canceled.\n",
|
||||
entity);
|
||||
}
|
||||
|
||||
amd_sched_rq_remove_entity(rq, entity);
|
||||
kfifo_free(&entity->job_queue);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a normal job to the job queue
|
||||
*
|
||||
* @sched The pointer to the scheduler
|
||||
* @c_entity The pointer to amd_sched_entity
|
||||
* @job The pointer to job required to submit
|
||||
* return 0 if succeed. -1 if failed.
|
||||
* -2 indicate queue is full for this client, client should wait untill
|
||||
* scheduler consum some queued command.
|
||||
* -1 other fail.
|
||||
*/
|
||||
int amd_sched_push_job(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *c_entity,
|
||||
void *data,
|
||||
struct amd_sched_fence **fence)
|
||||
{
|
||||
struct amd_sched_job *job;
|
||||
|
||||
if (!fence)
|
||||
return -EINVAL;
|
||||
job = kzalloc(sizeof(struct amd_sched_job), GFP_KERNEL);
|
||||
if (!job)
|
||||
return -ENOMEM;
|
||||
job->sched = sched;
|
||||
job->s_entity = c_entity;
|
||||
job->data = data;
|
||||
*fence = amd_sched_fence_create(c_entity);
|
||||
if ((*fence) == NULL) {
|
||||
kfree(job);
|
||||
return -EINVAL;
|
||||
}
|
||||
fence_get(&(*fence)->base);
|
||||
job->s_fence = *fence;
|
||||
while (kfifo_in_spinlocked(&c_entity->job_queue, &job, sizeof(void *),
|
||||
&c_entity->queue_lock) != sizeof(void *)) {
|
||||
/**
|
||||
* Current context used up all its IB slots
|
||||
* wait here, or need to check whether GPU is hung
|
||||
*/
|
||||
schedule();
|
||||
}
|
||||
/* first job wake up scheduler */
|
||||
if ((kfifo_len(&c_entity->job_queue) / sizeof(void *)) == 1)
|
||||
wake_up_interruptible(&sched->wait_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
|
||||
{
|
||||
struct amd_sched_job *sched_job =
|
||||
container_of(cb, struct amd_sched_job, cb);
|
||||
struct amd_gpu_scheduler *sched;
|
||||
unsigned long flags;
|
||||
|
||||
sched = sched_job->sched;
|
||||
atomic64_set(&sched_job->s_entity->last_signaled_v_seq,
|
||||
sched_job->s_fence->v_seq);
|
||||
amd_sched_fence_signal(sched_job->s_fence);
|
||||
spin_lock_irqsave(&sched->queue_lock, flags);
|
||||
list_del(&sched_job->list);
|
||||
atomic64_dec(&sched->hw_rq_count);
|
||||
spin_unlock_irqrestore(&sched->queue_lock, flags);
|
||||
|
||||
sched->ops->process_job(sched, sched_job);
|
||||
fence_put(&sched_job->s_fence->base);
|
||||
kfree(sched_job);
|
||||
wake_up_interruptible(&sched->wait_queue);
|
||||
}
|
||||
|
||||
static int amd_sched_main(void *param)
|
||||
{
|
||||
int r;
|
||||
struct amd_sched_job *job;
|
||||
struct sched_param sparam = {.sched_priority = 1};
|
||||
struct amd_sched_entity *c_entity = NULL;
|
||||
struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param;
|
||||
|
||||
sched_setscheduler(current, SCHED_FIFO, &sparam);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
struct fence *fence;
|
||||
|
||||
wait_event_interruptible(sched->wait_queue,
|
||||
is_scheduler_ready(sched) &&
|
||||
(c_entity = select_context(sched)));
|
||||
r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *));
|
||||
if (r != sizeof(void *))
|
||||
continue;
|
||||
r = sched->ops->prepare_job(sched, c_entity, job);
|
||||
if (!r) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&sched->queue_lock, flags);
|
||||
list_add_tail(&job->list, &sched->active_hw_rq);
|
||||
atomic64_inc(&sched->hw_rq_count);
|
||||
spin_unlock_irqrestore(&sched->queue_lock, flags);
|
||||
}
|
||||
mutex_lock(&sched->sched_lock);
|
||||
fence = sched->ops->run_job(sched, c_entity, job);
|
||||
if (fence) {
|
||||
r = fence_add_callback(fence, &job->cb,
|
||||
amd_sched_process_job);
|
||||
if (r == -ENOENT)
|
||||
amd_sched_process_job(fence, &job->cb);
|
||||
else if (r)
|
||||
DRM_ERROR("fence add callback failed (%d)\n", r);
|
||||
fence_put(fence);
|
||||
}
|
||||
mutex_unlock(&sched->sched_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gpu scheduler
|
||||
*
|
||||
* @device The device context for this scheduler
|
||||
* @ops The backend operations for this scheduler.
|
||||
* @id The scheduler is per ring, here is ring id.
|
||||
* @granularity The minumum ms unit the scheduler will scheduled.
|
||||
* @preemption Indicate whether this ring support preemption, 0 is no.
|
||||
*
|
||||
* return the pointer to scheduler for success, otherwise return NULL
|
||||
*/
|
||||
struct amd_gpu_scheduler *amd_sched_create(void *device,
|
||||
struct amd_sched_backend_ops *ops,
|
||||
unsigned ring,
|
||||
unsigned granularity,
|
||||
unsigned preemption,
|
||||
unsigned hw_submission)
|
||||
{
|
||||
struct amd_gpu_scheduler *sched;
|
||||
char name[20];
|
||||
|
||||
sched = kzalloc(sizeof(struct amd_gpu_scheduler), GFP_KERNEL);
|
||||
if (!sched)
|
||||
return NULL;
|
||||
|
||||
sched->device = device;
|
||||
sched->ops = ops;
|
||||
sched->granularity = granularity;
|
||||
sched->ring_id = ring;
|
||||
sched->preemption = preemption;
|
||||
sched->hw_submission_limit = hw_submission;
|
||||
snprintf(name, sizeof(name), "gpu_sched[%d]", ring);
|
||||
mutex_init(&sched->sched_lock);
|
||||
spin_lock_init(&sched->queue_lock);
|
||||
amd_sched_rq_init(&sched->sched_rq);
|
||||
amd_sched_rq_init(&sched->kernel_rq);
|
||||
|
||||
init_waitqueue_head(&sched->wait_queue);
|
||||
INIT_LIST_HEAD(&sched->active_hw_rq);
|
||||
atomic64_set(&sched->hw_rq_count, 0);
|
||||
/* Each scheduler will run on a seperate kernel thread */
|
||||
sched->thread = kthread_create(amd_sched_main, sched, name);
|
||||
if (sched->thread) {
|
||||
wake_up_process(sched->thread);
|
||||
return sched;
|
||||
}
|
||||
|
||||
DRM_ERROR("Failed to create scheduler for id %d.\n", ring);
|
||||
kfree(sched);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a gpu scheduler
|
||||
*
|
||||
* @sched The pointer to the scheduler
|
||||
*
|
||||
* return 0 if succeed. -1 if failed.
|
||||
*/
|
||||
int amd_sched_destroy(struct amd_gpu_scheduler *sched)
|
||||
{
|
||||
kthread_stop(sched->thread);
|
||||
kfree(sched);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next queued sequence number
|
||||
*
|
||||
* @entity The context entity
|
||||
*
|
||||
* return the next queued sequence number
|
||||
*/
|
||||
uint64_t amd_sched_next_queued_seq(struct amd_sched_entity *c_entity)
|
||||
{
|
||||
return atomic64_read(&c_entity->last_queued_v_seq) + 1;
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GPU_SCHEDULER_H_
|
||||
#define _GPU_SCHEDULER_H_
|
||||
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/fence.h>
|
||||
|
||||
#define AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
|
||||
|
||||
struct amd_gpu_scheduler;
|
||||
struct amd_sched_rq;
|
||||
|
||||
/**
|
||||
* A scheduler entity is a wrapper around a job queue or a group
|
||||
* of other entities. Entities take turns emitting jobs from their
|
||||
* job queues to corresponding hardware ring based on scheduling
|
||||
* policy.
|
||||
*/
|
||||
struct amd_sched_entity {
|
||||
struct list_head list;
|
||||
struct amd_sched_rq *belongto_rq;
|
||||
spinlock_t lock;
|
||||
/* the virtual_seq is unique per context per ring */
|
||||
atomic64_t last_queued_v_seq;
|
||||
atomic64_t last_signaled_v_seq;
|
||||
/* the job_queue maintains the jobs submitted by clients */
|
||||
struct kfifo job_queue;
|
||||
spinlock_t queue_lock;
|
||||
struct amd_gpu_scheduler *scheduler;
|
||||
wait_queue_head_t wait_queue;
|
||||
wait_queue_head_t wait_emit;
|
||||
bool is_pending;
|
||||
uint64_t fence_context;
|
||||
char name[20];
|
||||
bool need_wakeup;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run queue is a set of entities scheduling command submissions for
|
||||
* one specific ring. It implements the scheduling policy that selects
|
||||
* the next entity to emit commands from.
|
||||
*/
|
||||
struct amd_sched_rq {
|
||||
struct mutex lock;
|
||||
struct list_head entities;
|
||||
struct amd_sched_entity *current_entity;
|
||||
};
|
||||
|
||||
struct amd_sched_fence {
|
||||
struct fence base;
|
||||
struct fence_cb cb;
|
||||
struct amd_sched_entity *entity;
|
||||
uint64_t v_seq;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct amd_sched_job {
|
||||
struct list_head list;
|
||||
struct fence_cb cb;
|
||||
struct amd_gpu_scheduler *sched;
|
||||
struct amd_sched_entity *s_entity;
|
||||
void *data;
|
||||
struct amd_sched_fence *s_fence;
|
||||
};
|
||||
|
||||
extern const struct fence_ops amd_sched_fence_ops;
|
||||
static inline struct amd_sched_fence *to_amd_sched_fence(struct fence *f)
|
||||
{
|
||||
struct amd_sched_fence *__f = container_of(f, struct amd_sched_fence, base);
|
||||
|
||||
if (__f->base.ops == &amd_sched_fence_ops)
|
||||
return __f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the backend operations called by the scheduler,
|
||||
* these functions should be implemented in driver side
|
||||
*/
|
||||
struct amd_sched_backend_ops {
|
||||
int (*prepare_job)(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *c_entity,
|
||||
struct amd_sched_job *job);
|
||||
struct fence *(*run_job)(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *c_entity,
|
||||
struct amd_sched_job *job);
|
||||
void (*process_job)(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_job *job);
|
||||
};
|
||||
|
||||
/**
|
||||
* One scheduler is implemented for each hardware ring
|
||||
*/
|
||||
struct amd_gpu_scheduler {
|
||||
void *device;
|
||||
struct task_struct *thread;
|
||||
struct amd_sched_rq sched_rq;
|
||||
struct amd_sched_rq kernel_rq;
|
||||
struct list_head active_hw_rq;
|
||||
atomic64_t hw_rq_count;
|
||||
struct amd_sched_backend_ops *ops;
|
||||
uint32_t ring_id;
|
||||
uint32_t granularity; /* in ms unit */
|
||||
uint32_t preemption;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct amd_sched_entity *current_entity;
|
||||
struct mutex sched_lock;
|
||||
spinlock_t queue_lock;
|
||||
uint32_t hw_submission_limit;
|
||||
};
|
||||
|
||||
struct amd_gpu_scheduler *amd_sched_create(void *device,
|
||||
struct amd_sched_backend_ops *ops,
|
||||
uint32_t ring,
|
||||
uint32_t granularity,
|
||||
uint32_t preemption,
|
||||
uint32_t hw_submission);
|
||||
int amd_sched_destroy(struct amd_gpu_scheduler *sched);
|
||||
|
||||
int amd_sched_push_job(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *c_entity,
|
||||
void *data,
|
||||
struct amd_sched_fence **fence);
|
||||
|
||||
int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity,
|
||||
struct amd_sched_rq *rq,
|
||||
uint32_t jobs);
|
||||
int amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
|
||||
struct amd_sched_entity *entity);
|
||||
|
||||
uint64_t amd_sched_next_queued_seq(struct amd_sched_entity *c_entity);
|
||||
|
||||
struct amd_sched_fence *amd_sched_fence_create(
|
||||
struct amd_sched_entity *s_entity);
|
||||
void amd_sched_fence_signal(struct amd_sched_fence *fence);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2015 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "gpu_scheduler.h"
|
||||
|
||||
struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity)
|
||||
{
|
||||
struct amd_sched_fence *fence = NULL;
|
||||
fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL);
|
||||
if (fence == NULL)
|
||||
return NULL;
|
||||
fence->v_seq = atomic64_inc_return(&s_entity->last_queued_v_seq);
|
||||
fence->entity = s_entity;
|
||||
spin_lock_init(&fence->lock);
|
||||
fence_init(&fence->base, &amd_sched_fence_ops,
|
||||
&fence->lock,
|
||||
s_entity->fence_context,
|
||||
fence->v_seq);
|
||||
return fence;
|
||||
}
|
||||
|
||||
void amd_sched_fence_signal(struct amd_sched_fence *fence)
|
||||
{
|
||||
int ret = fence_signal(&fence->base);
|
||||
if (!ret)
|
||||
FENCE_TRACE(&fence->base, "signaled from irq context\n");
|
||||
else
|
||||
FENCE_TRACE(&fence->base, "was already signaled\n");
|
||||
}
|
||||
|
||||
static const char *amd_sched_fence_get_driver_name(struct fence *fence)
|
||||
{
|
||||
return "amd_sched";
|
||||
}
|
||||
|
||||
static const char *amd_sched_fence_get_timeline_name(struct fence *f)
|
||||
{
|
||||
struct amd_sched_fence *fence = to_amd_sched_fence(f);
|
||||
return (const char *)fence->entity->name;
|
||||
}
|
||||
|
||||
static bool amd_sched_fence_enable_signaling(struct fence *f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct fence_ops amd_sched_fence_ops = {
|
||||
.get_driver_name = amd_sched_fence_get_driver_name,
|
||||
.get_timeline_name = amd_sched_fence_get_timeline_name,
|
||||
.enable_signaling = amd_sched_fence_enable_signaling,
|
||||
.signaled = NULL,
|
||||
.wait = fence_default_wait,
|
||||
.release = NULL,
|
||||
};
|
|
@ -76,16 +76,35 @@ static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
|
|||
|
||||
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev)
|
||||
{
|
||||
int i;
|
||||
struct drm_encoder *encoder;
|
||||
struct radeon_encoder *radeon_encoder;
|
||||
struct radeon_encoder_atom_dig *dig;
|
||||
struct r600_audio_pin *pin = NULL;
|
||||
int i, pin_count;
|
||||
|
||||
dce6_afmt_get_connected_pins(rdev);
|
||||
|
||||
for (i = 0; i < rdev->audio.num_pins; i++) {
|
||||
if (rdev->audio.pin[i].connected)
|
||||
return &rdev->audio.pin[i];
|
||||
if (rdev->audio.pin[i].connected) {
|
||||
pin = &rdev->audio.pin[i];
|
||||
pin_count = 0;
|
||||
|
||||
list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
|
||||
if (radeon_encoder_is_digital(encoder)) {
|
||||
radeon_encoder = to_radeon_encoder(encoder);
|
||||
dig = radeon_encoder->enc_priv;
|
||||
if (dig->pin == pin)
|
||||
pin_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pin_count == 0)
|
||||
return pin;
|
||||
}
|
||||
}
|
||||
DRM_ERROR("No connected audio pins found!\n");
|
||||
return NULL;
|
||||
if (!pin)
|
||||
DRM_ERROR("No connected audio pins found!\n");
|
||||
return pin;
|
||||
}
|
||||
|
||||
void dce6_afmt_select_pin(struct drm_encoder *encoder)
|
||||
|
|
|
@ -419,7 +419,6 @@ void radeon_bo_force_delete(struct radeon_device *rdev)
|
|||
}
|
||||
dev_err(rdev->dev, "Userspace still has active objects !\n");
|
||||
list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
|
||||
mutex_lock(&rdev->ddev->struct_mutex);
|
||||
dev_err(rdev->dev, "%p %p %lu %lu force free\n",
|
||||
&bo->gem_base, bo, (unsigned long)bo->gem_base.size,
|
||||
*((unsigned long *)&bo->gem_base.refcount));
|
||||
|
@ -427,8 +426,7 @@ void radeon_bo_force_delete(struct radeon_device *rdev)
|
|||
list_del_init(&bo->list);
|
||||
mutex_unlock(&bo->rdev->gem.mutex);
|
||||
/* this should unref the ttm bo */
|
||||
drm_gem_object_unreference(&bo->gem_base);
|
||||
mutex_unlock(&rdev->ddev->struct_mutex);
|
||||
drm_gem_object_unreference_unlocked(&bo->gem_base);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -253,7 +253,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
|
|||
(rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
|
||||
return;
|
||||
|
||||
mutex_lock(&rdev->ddev->struct_mutex);
|
||||
down_write(&rdev->pm.mclk_lock);
|
||||
mutex_lock(&rdev->ring_lock);
|
||||
|
||||
|
@ -268,7 +267,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
|
|||
/* needs a GPU reset dont reset here */
|
||||
mutex_unlock(&rdev->ring_lock);
|
||||
up_write(&rdev->pm.mclk_lock);
|
||||
mutex_unlock(&rdev->ddev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +302,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
|
|||
|
||||
mutex_unlock(&rdev->ring_lock);
|
||||
up_write(&rdev->pm.mclk_lock);
|
||||
mutex_unlock(&rdev->ddev->struct_mutex);
|
||||
}
|
||||
|
||||
static void radeon_pm_print_states(struct radeon_device *rdev)
|
||||
|
@ -1062,7 +1059,6 @@ force:
|
|||
radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
|
||||
}
|
||||
|
||||
mutex_lock(&rdev->ddev->struct_mutex);
|
||||
down_write(&rdev->pm.mclk_lock);
|
||||
mutex_lock(&rdev->ring_lock);
|
||||
|
||||
|
@ -1113,7 +1109,6 @@ force:
|
|||
done:
|
||||
mutex_unlock(&rdev->ring_lock);
|
||||
up_write(&rdev->pm.mclk_lock);
|
||||
mutex_unlock(&rdev->ddev->struct_mutex);
|
||||
}
|
||||
|
||||
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
|
||||
|
|
Loading…
Reference in New Issue