提交 565c17b5 编写于 作者: D Dave Airlie

Merge branch 'drm-next-4.19' of git://people.freedesktop.org/~agd5f/linux into drm-next

First feature request for 4.19.  Highlights:
- Add initial amdgpu documentation
- Add initial GPU scheduler documention
- GPU scheduler fixes for dying processes
- Add support for the JPEG engine on VCN
- Switch CI to use powerplay by default
- EDC support for CZ
- More powerplay cleanups
- Misc DC fixes
Signed-off-by: NDave Airlie <airlied@redhat.com>

Link: https://patchwork.freedesktop.org/patch/msgid/20180621161138.3008-1-alexander.deucher@amd.com
=========================
drm/amdgpu AMDgpu driver
=========================
The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core
Next (GCN) architecture.
Core Driver Infrastructure
==========================
This section covers core driver infrastructure.
.. _amdgpu_memory_domains:
Memory Domains
--------------
.. kernel-doc:: include/uapi/drm/amdgpu_drm.h
:doc: memory domains
Buffer Objects
--------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:doc: amdgpu_object
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:internal:
PRIME Buffer Sharing
--------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
:doc: PRIME Buffer Sharing
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
:internal:
MMU Notifier
------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:doc: MMU Notifier
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:internal:
AMDGPU Virtual Memory
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:doc: GPUVM
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:internal:
Interrupt Handling
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:doc: Interrupt Handling
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:internal:
GPU Power/Thermal Controls and Monitoring
=========================================
This section covers hwmon and power/thermal controls.
HWMON Interfaces
----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: hwmon
GPU sysfs Power State Interfaces
--------------------------------
GPU power controls are exposed via sysfs files.
power_dpm_state
~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: power_dpm_state
power_dpm_force_performance_level
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: power_dpm_force_performance_level
pp_table
~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_table
pp_od_clk_voltage
~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_od_clk_voltage
pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
pp_power_profile_mode
~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_power_profile_mode
......@@ -4,6 +4,7 @@ GPU Driver Documentation
.. toctree::
amdgpu
i915
meson
pl111
......
......@@ -395,6 +395,8 @@ VMA Offset Manager
.. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
:export:
.. _prime_buffer_sharing:
PRIME Buffer Sharing
====================
......@@ -496,3 +498,21 @@ DRM Sync Objects
.. kernel-doc:: drivers/gpu/drm/drm_syncobj.c
:export:
GPU Scheduler
=============
Overview
--------
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c
:doc: Overview
Scheduler Function References
-----------------------------
.. kernel-doc:: include/drm/gpu_scheduler.h
:internal:
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c
:export:
......@@ -136,6 +136,7 @@
#define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02
#define GENERIC_OBJECT_ID_MXM_OPM 0x03
#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin
#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05
/****************************************************/
/* Graphics Object ENUM ID Definition */
......@@ -714,6 +715,13 @@
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT)
#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
/****************************************************/
/* Object Cap definition - Shared with BIOS */
/****************************************************/
......
......@@ -968,6 +968,8 @@ struct amdgpu_gfx {
struct amdgpu_irq_src eop_irq;
struct amdgpu_irq_src priv_reg_irq;
struct amdgpu_irq_src priv_inst_irq;
struct amdgpu_irq_src cp_ecc_error_irq;
struct amdgpu_irq_src sq_irq;
/* gfx status */
uint32_t gfx_current_status;
/* ce ram size*/
......
......@@ -31,6 +31,7 @@
#include <drm/drm_syncobj.h>
#include "amdgpu.h"
#include "amdgpu_trace.h"
#include "amdgpu_gmc.h"
static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
struct drm_amdgpu_cs_chunk_fence *data,
......@@ -302,7 +303,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
*max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us);
/* Do the same for visible VRAM if half of it is free */
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size) {
if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) {
u64 total_vis_vram = adev->gmc.visible_vram_size;
u64 used_vis_vram =
amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
......@@ -359,7 +360,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
* to move it. Don't move anything if the threshold is zero.
*/
if (p->bytes_moved < p->bytes_moved_threshold) {
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size &&
if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
(bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) {
/* And don't move a CPU_ACCESS_REQUIRED BO to limited
* visible VRAM if we've depleted our allowance to do
......@@ -381,7 +382,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
p->bytes_moved += ctx.bytes_moved;
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size &&
if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
amdgpu_bo_in_cpu_visible_vram(bo))
p->bytes_moved_vis += ctx.bytes_moved;
......@@ -434,8 +435,8 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,
/* Good we can try to move this BO somewhere else */
update_bytes_moved_vis =
adev->gmc.visible_vram_size < adev->gmc.real_vram_size &&
amdgpu_bo_in_cpu_visible_vram(bo);
!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
amdgpu_bo_in_cpu_visible_vram(bo);
amdgpu_ttm_placement_from_domain(bo, other);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
p->bytes_moved += ctx.bytes_moved;
......
......@@ -449,26 +449,28 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
struct amdgpu_ctx *ctx;
struct idr *idp;
uint32_t id, i;
long max_wait = MAX_WAIT_SCHED_ENTITY_Q_EMPTY;
idp = &mgr->ctx_handles;
mutex_lock(&mgr->lock);
idr_for_each_entry(idp, ctx, id) {
if (!ctx->adev)
if (!ctx->adev) {
mutex_unlock(&mgr->lock);
return;
}
for (i = 0; i < ctx->adev->num_rings; i++) {
if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring)
continue;
if (kref_read(&ctx->refcount) == 1)
drm_sched_entity_do_release(&ctx->adev->rings[i]->sched,
&ctx->rings[i].entity);
else
DRM_ERROR("ctx %p is still alive\n", ctx);
max_wait = drm_sched_entity_do_release(&ctx->adev->rings[i]->sched,
&ctx->rings[i].entity, max_wait);
}
}
mutex_unlock(&mgr->lock);
}
void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr)
......
......@@ -25,6 +25,7 @@
* Alex Deucher
* Jerome Glisse
*/
#include <linux/power_supply.h>
#include <linux/kthread.h>
#include <linux/console.h>
#include <linux/slab.h>
......@@ -675,17 +676,15 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev,
}
/**
* amdgpu_device_gart_location - try to find GTT location
* amdgpu_device_gart_location - try to find GART location
*
* @adev: amdgpu device structure holding all necessary informations
* @mc: memory controller structure holding memory informations
*
* Function will place try to place GTT before or after VRAM.
* Function will place try to place GART before or after VRAM.
*
* If GTT size is bigger than space left then we ajust GTT size.
* If GART size is bigger than space left then we ajust GART size.
* Thus function will never fails.
*
* FIXME: when reducing GTT size align new size on power of 2.
*/
void amdgpu_device_gart_location(struct amdgpu_device *adev,
struct amdgpu_gmc *mc)
......@@ -698,13 +697,13 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev,
size_bf = mc->vram_start;
if (size_bf > size_af) {
if (mc->gart_size > size_bf) {
dev_warn(adev->dev, "limiting GTT\n");
dev_warn(adev->dev, "limiting GART\n");
mc->gart_size = size_bf;
}
mc->gart_start = 0;
} else {
if (mc->gart_size > size_af) {
dev_warn(adev->dev, "limiting GTT\n");
dev_warn(adev->dev, "limiting GART\n");
mc->gart_size = size_af;
}
/* VCE doesn't like it when BOs cross a 4GB segment, so align
......@@ -713,7 +712,7 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev,
mc->gart_start = ALIGN(mc->vram_end + 1, 0x100000000ULL);
}
mc->gart_end = mc->gart_start + mc->gart_size - 1;
dev_info(adev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n",
mc->gart_size >> 20, mc->gart_start, mc->gart_end);
}
......@@ -1926,7 +1925,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev)
if (adev->powerplay.pp_feature & PP_GFXOFF_MASK)
amdgpu_device_ip_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_SMC,
AMD_CG_STATE_UNGATE);
AMD_PG_STATE_UNGATE);
/* ungate SMC block first */
r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC,
......@@ -2293,6 +2292,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
INIT_DELAYED_WORK(&adev->late_init_work,
amdgpu_device_ip_late_init_func_handler);
adev->pm.ac_power = power_supply_is_system_supplied() > 0 ? true : false;
/* Registers mapping */
/* TODO: block userspace mapping of io register */
if (adev->asic_type >= CHIP_BONAIRE) {
......
......@@ -402,7 +402,6 @@ struct amdgpu_dpm {
u32 tdp_adjustment;
u16 load_line_slope;
bool power_control;
bool ac_power;
/* special states active */
bool thermal_active;
bool uvd_active;
......@@ -439,6 +438,7 @@ struct amdgpu_pm {
struct amd_pp_display_configuration pm_display_cfg;/* set by dc */
uint32_t smu_prv_buffer_size;
struct amdgpu_bo *smu_prv_buffer;
bool ac_power;
};
#define R600_SSTU_DFLT 0
......
......@@ -855,9 +855,21 @@ static const struct dev_pm_ops amdgpu_pm_ops = {
.runtime_idle = amdgpu_pmops_runtime_idle,
};
static int amdgpu_flush(struct file *f, fl_owner_t id)
{
struct drm_file *file_priv = f->private_data;
struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr);
return 0;
}
static const struct file_operations amdgpu_driver_kms_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.flush = amdgpu_flush,
.release = drm_release,
.unlocked_ioctl = amdgpu_drm_ioctl,
.mmap = amdgpu_mmap,
......
......@@ -510,7 +510,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
* @adev: amdgpu_device pointer
* @vm: vm to update
* @bo_va: bo_va to update
* @list: validation list
* @operation: map, unmap or clear
*
* Update the bo_va directly after setting its address. Errors are not
......@@ -519,7 +518,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
struct amdgpu_bo_va *bo_va,
struct list_head *list,
uint32_t operation)
{
int r;
......@@ -612,7 +610,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
abo = gem_to_amdgpu_bo(gobj);
tv.bo = &abo->tbo;
tv.shared = false;
tv.shared = !!(abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID);
list_add(&tv.head, &list);
} else {
gobj = NULL;
......@@ -673,7 +671,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
break;
}
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug)
amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, &list,
amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va,
args->operation);
error_backoff:
......
......@@ -109,4 +109,19 @@ struct amdgpu_gmc {
const struct amdgpu_gmc_funcs *gmc_funcs;
};
/**
* amdgpu_gmc_vram_full_visible - Check if full VRAM is visible through the BAR
*
* @adev: amdgpu_device pointer
*
* Returns:
* True if full VRAM is visible through the BAR
*/
static inline bool amdgpu_gmc_vram_full_visible(struct amdgpu_gmc *gmc)
{
WARN_ON(gmc->real_vram_size < gmc->visible_vram_size);
return (gmc->real_vram_size == gmc->visible_vram_size);
}
#endif
......@@ -353,7 +353,8 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
ring->funcs->type == AMDGPU_RING_TYPE_VCE ||
ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC)
ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
tmo = tmo_mm;
else
tmo = tmo_gfx;
......
......@@ -25,6 +25,23 @@
* Alex Deucher
* Jerome Glisse
*/
/**
* DOC: Interrupt Handling
*
* Interrupts generated within GPU hardware raise interrupt requests that are
* passed to amdgpu IRQ handler which is responsible for detecting source and
* type of the interrupt and dispatching matching handlers. If handling an
* interrupt requires calling kernel functions that may sleep processing is
* dispatched to work handlers.
*
* If MSI functionality is not disabled by module parameter then MSI
* support will be enabled.
*
* For GPU interrupt sources that may be driven by another driver, IRQ domain
* support is used (with mapping between virtual and hardware IRQs).
*/
#include <linux/irq.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
......@@ -43,19 +60,21 @@
#define AMDGPU_WAIT_IDLE_TIMEOUT 200
/*
* Handle hotplug events outside the interrupt handler proper.
*/
/**
* amdgpu_hotplug_work_func - display hotplug work handler
* amdgpu_hotplug_work_func - work handler for display hotplug event
*
* @work: work struct
* @work: work struct pointer
*
* This is the hot plug event work handler (all asics).
* The work gets scheduled from the irq handler if there
* was a hot plug interrupt. It walks the connector table
* and calls the hotplug handler for each one, then sends
* a drm hotplug event to alert userspace.
* This is the hotplug event work handler (all ASICs).
* The work gets scheduled from the IRQ handler if there
* was a hotplug interrupt. It walks through the connector table
* and calls hotplug handler for each connector. After this, it sends
* a DRM hotplug event to alert userspace.
*
* This design approach is required in order to defer hotplug event handling
* from the IRQ handler to a work handler because hotplug handler has to use
* mutexes which cannot be locked in an IRQ handler (since &mutex_lock may
* sleep).
*/
static void amdgpu_hotplug_work_func(struct work_struct *work)
{
......@@ -74,13 +93,12 @@ static void amdgpu_hotplug_work_func(struct work_struct *work)
}
/**
* amdgpu_irq_reset_work_func - execute gpu reset
* amdgpu_irq_reset_work_func - execute GPU reset
*
* @work: work struct
* @work: work struct pointer
*
* Execute scheduled gpu reset (cayman+).
* This function is called when the irq handler
* thinks we need a gpu reset.
* Execute scheduled GPU reset (Cayman+).
* This function is called when the IRQ handler thinks we need a GPU reset.
*/
static void amdgpu_irq_reset_work_func(struct work_struct *work)
{
......@@ -91,7 +109,13 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work)
amdgpu_device_gpu_recover(adev, NULL, false);
}
/* Disable *all* interrupts */
/**
* amdgpu_irq_disable_all - disable *all* interrupts
*
* @adev: amdgpu device pointer
*
* Disable all types of interrupts from all sources.
*/
void amdgpu_irq_disable_all(struct amdgpu_device *adev)
{
unsigned long irqflags;
......@@ -123,11 +147,15 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_handler - irq handler
* amdgpu_irq_handler - IRQ handler
*
* @irq: IRQ number (unused)
* @arg: pointer to DRM device
*
* @int irq, void *arg: args
* IRQ handler for amdgpu driver (all ASICs).
*
* This is the irq handler for the amdgpu driver (all asics).
* Returns:
* result of handling the IRQ, as defined by &irqreturn_t
*/
irqreturn_t amdgpu_irq_handler(int irq, void *arg)
{
......@@ -142,18 +170,18 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg)
}
/**
* amdgpu_msi_ok - asic specific msi checks
* amdgpu_msi_ok - check whether MSI functionality is enabled
*
* @adev: amdgpu device pointer
* @adev: amdgpu device pointer (unused)
*
* Checks whether MSI functionality has been disabled via module parameter
* (all ASICs).
*
* Handles asic specific MSI checks to determine if
* MSIs should be enabled on a particular chip (all asics).
* Returns true if MSIs should be enabled, false if MSIs
* should not be enabled.
* Returns:
* *true* if MSIs are allowed to be enabled or *false* otherwise
*/
static bool amdgpu_msi_ok(struct amdgpu_device *adev)
{
/* force MSI on */
if (amdgpu_msi == 1)
return true;
else if (amdgpu_msi == 0)
......@@ -163,12 +191,15 @@ static bool amdgpu_msi_ok(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_init - init driver interrupt info
* amdgpu_irq_init - initialize interrupt handling
*
* @adev: amdgpu device pointer
*
* Sets up the work irq handlers, vblank init, MSIs, etc. (all asics).
* Returns 0 for success, error for failure.
* Sets up work functions for hotplug and reset interrupts, enables MSI
* functionality, initializes vblank, hotplug and reset interrupt handling.
*
* Returns:
* 0 on success or error code on failure
*/
int amdgpu_irq_init(struct amdgpu_device *adev)
{
......@@ -176,7 +207,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
spin_lock_init(&adev->irq.lock);
/* enable msi */
/* Enable MSI if not disabled by module parameter */
adev->irq.msi_enabled = false;
if (amdgpu_msi_ok(adev)) {
......@@ -189,7 +220,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
if (!amdgpu_device_has_dc_support(adev)) {
if (!adev->enable_virtual_display)
/* Disable vblank irqs aggressively for power-saving */
/* Disable vblank IRQs aggressively for power-saving */
/* XXX: can this be enabled for DC? */
adev->ddev->vblank_disable_immediate = true;
......@@ -197,7 +228,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
if (r)
return r;
/* pre DCE11 */
/* Pre-DCE11 */
INIT_WORK(&adev->hotplug_work,
amdgpu_hotplug_work_func);
}
......@@ -220,11 +251,13 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_fini - tear down driver interrupt info
* amdgpu_irq_fini - shut down interrupt handling
*
* @adev: amdgpu device pointer
*
* Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics).
* Tears down work functions for hotplug and reset interrupts, disables MSI
* functionality, shuts down vblank, hotplug and reset interrupt handling,
* turns off interrupts from all sources (all ASICs).
*/
void amdgpu_irq_fini(struct amdgpu_device *adev)
{
......@@ -264,12 +297,17 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_add_id - register irq source
* amdgpu_irq_add_id - register IRQ source
*
* @adev: amdgpu device pointer
* @src_id: source id for this source
* @source: irq source
* @client_id: client id
* @src_id: source id
* @source: IRQ source pointer
*
* Registers IRQ source on a client.
*
* Returns:
* 0 on success or error code otherwise
*/
int amdgpu_irq_add_id(struct amdgpu_device *adev,
unsigned client_id, unsigned src_id,
......@@ -312,12 +350,12 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev,
}
/**
* amdgpu_irq_dispatch - dispatch irq to IP blocks
* amdgpu_irq_dispatch - dispatch IRQ to IP blocks
*
* @adev: amdgpu device pointer
* @entry: interrupt vector
* @entry: interrupt vector pointer
*
* Dispatches the irq to the different IP blocks
* Dispatches IRQ to IP blocks.
*/
void amdgpu_irq_dispatch(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
......@@ -361,13 +399,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
}
/**
* amdgpu_irq_update - update hw interrupt state
* amdgpu_irq_update - update hardware interrupt state
*
* @adev: amdgpu device pointer
* @src: interrupt src you want to enable
* @type: type of interrupt you want to update
* @src: interrupt source pointer
* @type: type of interrupt
*
* Updates the interrupt state for a specific src (all asics).
* Updates interrupt state for the specific source (all ASICs).
*/
int amdgpu_irq_update(struct amdgpu_device *adev,
struct amdgpu_irq_src *src, unsigned type)
......@@ -378,7 +416,7 @@ int amdgpu_irq_update(struct amdgpu_device *adev,
spin_lock_irqsave(&adev->irq.lock, irqflags);
/* we need to determine after taking the lock, otherwise
/* We need to determine after taking the lock, otherwise
we might disable just enabled interrupts again */
if (amdgpu_irq_enabled(adev, src, type))
state = AMDGPU_IRQ_STATE_ENABLE;
......@@ -390,6 +428,14 @@ int amdgpu_irq_update(struct amdgpu_device *adev,
return r;
}
/**
* amdgpu_irq_gpu_reset_resume_helper - update interrupt states on all sources
*
* @adev: amdgpu device pointer
*
* Updates state of all types of interrupts on all sources on resume after
* reset.
*/
void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
{
int i, j, k;
......@@ -413,10 +459,13 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
* amdgpu_irq_get - enable interrupt
*
* @adev: amdgpu device pointer
* @src: interrupt src you want to enable
* @type: type of interrupt you want to enable
* @src: interrupt source pointer
* @type: type of interrupt
*
* Enables the interrupt type for a specific src (all asics).
* Enables specified type of interrupt on the specified source (all ASICs).
*
* Returns:
* 0 on success or error code otherwise
*/
int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type)
......@@ -440,10 +489,13 @@ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
* amdgpu_irq_put - disable interrupt
*
* @adev: amdgpu device pointer
* @src: interrupt src you want to disable
* @type: type of interrupt you want to disable
* @src: interrupt source pointer
* @type: type of interrupt
*
* Enables specified type of interrupt on the specified source (all ASICs).
*
* Disables the interrupt type for a specific src (all asics).
* Returns:
* 0 on success or error code otherwise
*/
int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type)
......@@ -464,12 +516,17 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
}
/**
* amdgpu_irq_enabled - test if irq is enabled or not
* amdgpu_irq_enabled - check whether interrupt is enabled or not
*
* @adev: amdgpu device pointer
* @idx: interrupt src you want to test
* @src: interrupt source pointer
* @type: type of interrupt
*
* Tests if the given interrupt source is enabled or not
* Checks whether the given type of interrupt is enabled on the given source.
*
* Returns:
* *true* if interrupt is enabled, *false* if interrupt is disabled or on
* invalid parameters
*/
bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type)
......@@ -486,7 +543,7 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
return !!atomic_read(&src->enabled_types[type]);
}
/* gen irq */
/* XXX: Generic IRQ handling */
static void amdgpu_irq_mask(struct irq_data *irqd)
{
/* XXX */
......@@ -497,12 +554,26 @@ static void amdgpu_irq_unmask(struct irq_data *irqd)
/* XXX */
}
/* amdgpu hardware interrupt chip descriptor */
static struct irq_chip amdgpu_irq_chip = {
.name = "amdgpu-ih",
.irq_mask = amdgpu_irq_mask,
.irq_unmask = amdgpu_irq_unmask,
};
/**
* amdgpu_irqdomain_map - create mapping between virtual and hardware IRQ numbers
*
* @d: amdgpu IRQ domain pointer (unused)
* @irq: virtual IRQ number
* @hwirq: hardware irq number
*
* Current implementation assigns simple interrupt handler to the given virtual
* IRQ.
*
* Returns:
* 0 on success or error code otherwise
*/
static int amdgpu_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq)
{
......@@ -514,17 +585,21 @@ static int amdgpu_irqdomain_map(struct irq_domain *d,
return 0;
}
/* Implementation of methods for amdgpu IRQ domain */
static const struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
.map = amdgpu_irqdomain_map,
};
/**
* amdgpu_irq_add_domain - create a linear irq domain
* amdgpu_irq_add_domain - create a linear IRQ domain
*
* @adev: amdgpu device pointer
*
* Create an irq domain for GPU interrupt sources
* Creates an IRQ domain for GPU interrupt sources
* that may be driven by another driver (e.g., ACP).
*
* Returns:
* 0 on success or error code otherwise
*/
int amdgpu_irq_add_domain(struct amdgpu_device *adev)
{
......@@ -539,11 +614,11 @@ int amdgpu_irq_add_domain(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_remove_domain - remove the irq domain
* amdgpu_irq_remove_domain - remove the IRQ domain
*
* @adev: amdgpu device pointer
*
* Remove the irq domain for GPU interrupt sources
* Removes the IRQ domain for GPU interrupt sources
* that may be driven by another driver (e.g., ACP).
*/
void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
......@@ -555,16 +630,17 @@ void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_create_mapping - create a mapping between a domain irq and a
* Linux irq
* amdgpu_irq_create_mapping - create mapping between domain Linux IRQs
*
* @adev: amdgpu device pointer
* @src_id: IH source id
*
* Create a mapping between a domain irq (GPU IH src id) and a Linux irq
* Creates mapping between a domain IRQ (GPU IH src id) and a Linux IRQ
* Use this for components that generate a GPU interrupt, but are driven
* by a different driver (e.g., ACP).
* Returns the Linux irq.
*
* Returns:
* Linux IRQ
*/
unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
{
......
......@@ -329,35 +329,35 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_size_alignment = 8;
ib_start_alignment = 32;
ib_size_alignment = 32;
break;
case AMDGPU_HW_IP_COMPUTE:
type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_compute_rings; i++)
ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_size_alignment = 8;
ib_start_alignment = 32;
ib_size_alignment = 32;
break;
case AMDGPU_HW_IP_DMA:
type = AMD_IP_BLOCK_TYPE_SDMA;
for (i = 0; i < adev->sdma.num_instances; i++)
ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_size_alignment = 1;
ib_start_alignment = 256;
ib_size_alignment = 4;
break;
case AMDGPU_HW_IP_UVD:
type = AMD_IP_BLOCK_TYPE_UVD;
for (i = 0; i < adev->uvd.num_uvd_inst; i++)
ring_mask |= ((adev->uvd.inst[i].ring.ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_size_alignment = 16;
ib_start_alignment = 64;
ib_size_alignment = 64;
break;
case AMDGPU_HW_IP_VCE:
type = AMD_IP_BLOCK_TYPE_VCE;
for (i = 0; i < adev->vce.num_rings; i++)
ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_start_alignment = 4;
ib_size_alignment = 1;
break;
case AMDGPU_HW_IP_UVD_ENC:
......@@ -367,22 +367,28 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
ring_mask |=
((adev->uvd.inst[i].ring_enc[j].ready ? 1 : 0) <<
(j + i * adev->uvd.num_enc_rings));
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_size_alignment = 1;
ib_start_alignment = 64;
ib_size_alignment = 64;
break;
case AMDGPU_HW_IP_VCN_DEC:
type = AMD_IP_BLOCK_TYPE_VCN;
ring_mask = adev->vcn.ring_dec.ready ? 1 : 0;
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_start_alignment = 16;
ib_size_alignment = 16;
break;
case AMDGPU_HW_IP_VCN_ENC:
type = AMD_IP_BLOCK_TYPE_VCN;
for (i = 0; i < adev->vcn.num_enc_rings; i++)
ring_mask |= ((adev->vcn.ring_enc[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
ib_start_alignment = 64;
ib_size_alignment = 1;
break;
case AMDGPU_HW_IP_VCN_JPEG:
type = AMD_IP_BLOCK_TYPE_VCN;
ring_mask = adev->vcn.ring_jpeg.ready ? 1 : 0;
ib_start_alignment = 16;
ib_size_alignment = 16;
break;
default:
return -EINVAL;
}
......@@ -427,6 +433,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
break;
case AMDGPU_HW_IP_VCN_DEC:
case AMDGPU_HW_IP_VCN_ENC:
case AMDGPU_HW_IP_VCN_JPEG:
type = AMD_IP_BLOCK_TYPE_VCN;
break;
default:
......@@ -930,7 +937,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
return;
pm_runtime_get_sync(dev->dev);
amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr);
if (adev->asic_type != CHIP_RAVEN) {
amdgpu_uvd_free_handles(adev, file_priv);
......
......@@ -28,6 +28,21 @@
* Christian König <christian.koenig@amd.com>
*/
/**
* DOC: MMU Notifier
*
* For coherent userptr handling registers an MMU notifier to inform the driver
* about updates on the page tables of a process.
*
* When somebody tries to invalidate the page tables we block the update until
* all operations on the pages in question are completed, then those pages are
* marked as accessed and also dirty if it wasn't a read only access.
*
* New command submissions using the userptrs in question are delayed until all
* page table invalidation are completed and we once more see a coherent process
* address space.
*/
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/mmu_notifier.h>
......@@ -38,6 +53,21 @@
#include "amdgpu.h"
#include "amdgpu_amdkfd.h"
/**
* struct amdgpu_mn
*
* @adev: amdgpu device pointer
* @mm: process address space
* @mn: MMU notifier structur
* @work: destruction work item
* @node: hash table node to find structure by adev and mn
* @lock: rw semaphore protecting the notifier nodes
* @objects: interval tree containing amdgpu_mn_nodes
* @read_lock: mutex for recursive locking of @lock
* @recursion: depth of recursion
*
* Data for each amdgpu device and process address space.
*/
struct amdgpu_mn {
/* constant after initialisation */
struct amdgpu_device *adev;
......@@ -58,13 +88,21 @@ struct amdgpu_mn {
atomic_t recursion;
};
/**
* struct amdgpu_mn_node
*
* @it: interval node defining start-last of the affected address range
* @bos: list of all BOs in the affected address range
*
* Manages all BOs which are affected of a certain range of address space.
*/
struct amdgpu_mn_node {
struct interval_tree_node it;
struct list_head bos;
};
/**
* amdgpu_mn_destroy - destroy the rmn
* amdgpu_mn_destroy - destroy the MMU notifier
*
* @work: previously sheduled work item
*
......@@ -72,47 +110,50 @@ struct amdgpu_mn_node {
*/
static void amdgpu_mn_destroy(struct work_struct *work)
{
struct amdgpu_mn *rmn = container_of(work, struct amdgpu_mn, work);
struct amdgpu_device *adev = rmn->adev;
struct amdgpu_mn *amn = container_of(work, struct amdgpu_mn, work);
struct amdgpu_device *adev = amn->adev;
struct amdgpu_mn_node *node, *next_node;
struct amdgpu_bo *bo, *next_bo;
mutex_lock(&adev->mn_lock);
down_write(&rmn->lock);
hash_del(&rmn->node);
down_write(&amn->lock);
hash_del(&amn->node);
rbtree_postorder_for_each_entry_safe(node, next_node,
&rmn->objects.rb_root, it.rb) {
&amn->objects.rb_root, it.rb) {
list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
bo->mn = NULL;
list_del_init(&bo->mn_list);
}
kfree(node);
}
up_write(&rmn->lock);
up_write(&amn->lock);
mutex_unlock(&adev->mn_lock);
mmu_notifier_unregister_no_release(&rmn->mn, rmn->mm);
kfree(rmn);
mmu_notifier_unregister_no_release(&amn->mn, amn->mm);
kfree(amn);
}
/**
* amdgpu_mn_release - callback to notify about mm destruction
*
* @mn: our notifier
* @mn: the mm this callback is about
* @mm: the mm this callback is about
*
* Shedule a work item to lazy destroy our notifier.
*/
static void amdgpu_mn_release(struct mmu_notifier *mn,
struct mm_struct *mm)
{
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
INIT_WORK(&rmn->work, amdgpu_mn_destroy);
schedule_work(&rmn->work);
struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
INIT_WORK(&amn->work, amdgpu_mn_destroy);
schedule_work(&amn->work);
}
/**
* amdgpu_mn_lock - take the write side lock for this mn
* amdgpu_mn_lock - take the write side lock for this notifier
*
* @mn: our notifier
*/
void amdgpu_mn_lock(struct amdgpu_mn *mn)
{
......@@ -121,7 +162,9 @@ void amdgpu_mn_lock(struct amdgpu_mn *mn)
}
/**
* amdgpu_mn_unlock - drop the write side lock for this mn
* amdgpu_mn_unlock - drop the write side lock for this notifier
*
* @mn: our notifier
*/
void amdgpu_mn_unlock(struct amdgpu_mn *mn)
{
......@@ -130,40 +173,38 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn)
}
/**
* amdgpu_mn_read_lock - take the rmn read lock
*
* @rmn: our notifier
* amdgpu_mn_read_lock - take the read side lock for this notifier
*
* Take the rmn read side lock.
* @amn: our notifier
*/
static void amdgpu_mn_read_lock(struct amdgpu_mn *rmn)
static void amdgpu_mn_read_lock(struct amdgpu_mn *amn)
{
mutex_lock(&rmn->read_lock);
if (atomic_inc_return(&rmn->recursion) == 1)
down_read_non_owner(&rmn->lock);
mutex_unlock(&rmn->read_lock);
mutex_lock(&amn->read_lock);
if (atomic_inc_return(&amn->recursion) == 1)
down_read_non_owner(&amn->lock);
mutex_unlock(&amn->read_lock);
}
/**
* amdgpu_mn_read_unlock - drop the rmn read lock
*
* @rmn: our notifier
* amdgpu_mn_read_unlock - drop the read side lock for this notifier
*
* Drop the rmn read side lock.
* @amn: our notifier
*/
static void amdgpu_mn_read_unlock(struct amdgpu_mn *rmn)
static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn)
{
if (atomic_dec_return(&rmn->recursion) == 0)
up_read_non_owner(&rmn->lock);
if (atomic_dec_return(&amn->recursion) == 0)
up_read_non_owner(&amn->lock);
}
/**
* amdgpu_mn_invalidate_node - unmap all BOs of a node
*
* @node: the node with the BOs to unmap
* @start: start of address range affected
* @end: end of address range affected
*
* We block for all BOs and unmap them by move them
* into system domain again.
* Block for operations on BOs to finish and mark pages as accessed and
* potentially dirty.
*/
static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
unsigned long start,
......@@ -190,27 +231,27 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
* amdgpu_mn_invalidate_range_start_gfx - callback to notify about mm change
*
* @mn: our notifier
* @mn: the mm this callback is about
* @mm: the mm this callback is about
* @start: start of updated range
* @end: end of updated range
*
* We block for all BOs between start and end to be idle and
* unmap them by move them into system domain again.
* Block for operations on BOs to finish and mark pages as accessed and
* potentially dirty.
*/
static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long start,
unsigned long end)
{
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
struct interval_tree_node *it;
/* notification is exclusive, but interval is inclusive */
end -= 1;
amdgpu_mn_read_lock(rmn);
amdgpu_mn_read_lock(amn);
it = interval_tree_iter_first(&rmn->objects, start, end);
it = interval_tree_iter_first(&amn->objects, start, end);
while (it) {
struct amdgpu_mn_node *node;
......@@ -238,15 +279,15 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
unsigned long start,
unsigned long end)
{
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
struct interval_tree_node *it;
/* notification is exclusive, but interval is inclusive */
end -= 1;
amdgpu_mn_read_lock(rmn);
amdgpu_mn_read_lock(amn);
it = interval_tree_iter_first(&rmn->objects, start, end);
it = interval_tree_iter_first(&amn->objects, start, end);
while (it) {
struct amdgpu_mn_node *node;
struct amdgpu_bo *bo;
......@@ -268,7 +309,7 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
* amdgpu_mn_invalidate_range_end - callback to notify about mm change
*
* @mn: our notifier
* @mn: the mm this callback is about
* @mm: the mm this callback is about
* @start: start of updated range
* @end: end of updated range
*
......@@ -279,9 +320,9 @@ static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn,
unsigned long start,
unsigned long end)
{
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
amdgpu_mn_read_unlock(rmn);
amdgpu_mn_read_unlock(amn);
}
static const struct mmu_notifier_ops amdgpu_mn_ops[] = {
......@@ -315,7 +356,7 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev,
enum amdgpu_mn_type type)
{
struct mm_struct *mm = current->mm;
struct amdgpu_mn *rmn;
struct amdgpu_mn *amn;
unsigned long key = AMDGPU_MN_KEY(mm, type);
int r;
......@@ -325,41 +366,41 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev,
return ERR_PTR(-EINTR);
}
hash_for_each_possible(adev->mn_hash, rmn, node, key)
if (AMDGPU_MN_KEY(rmn->mm, rmn->type) == key)
hash_for_each_possible(adev->mn_hash, amn, node, key)
if (AMDGPU_MN_KEY(amn->mm, amn->type) == key)
goto release_locks;
rmn = kzalloc(sizeof(*rmn), GFP_KERNEL);
if (!rmn) {
rmn = ERR_PTR(-ENOMEM);
amn = kzalloc(sizeof(*amn), GFP_KERNEL);
if (!amn) {
amn = ERR_PTR(-ENOMEM);
goto release_locks;
}
rmn->adev = adev;
rmn->mm = mm;
init_rwsem(&rmn->lock);
rmn->type = type;
rmn->mn.ops = &amdgpu_mn_ops[type];
rmn->objects = RB_ROOT_CACHED;
mutex_init(&rmn->read_lock);
atomic_set(&rmn->recursion, 0);
amn->adev = adev;
amn->mm = mm;
init_rwsem(&amn->lock);
amn->type = type;
amn->mn.ops = &amdgpu_mn_ops[type];
amn->objects = RB_ROOT_CACHED;
mutex_init(&amn->read_lock);
atomic_set(&amn->recursion, 0);
r = __mmu_notifier_register(&rmn->mn, mm);
r = __mmu_notifier_register(&amn->mn, mm);
if (r)
goto free_rmn;
goto free_amn;
hash_add(adev->mn_hash, &rmn->node, AMDGPU_MN_KEY(mm, type));
hash_add(adev->mn_hash, &amn->node, AMDGPU_MN_KEY(mm, type));
release_locks:
up_write(&mm->mmap_sem);
mutex_unlock(&adev->mn_lock);
return rmn;
return amn;
free_rmn:
free_amn:
up_write(&mm->mmap_sem);
mutex_unlock(&adev->mn_lock);
kfree(rmn);
kfree(amn);
return ERR_PTR(r);
}
......@@ -379,14 +420,14 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
enum amdgpu_mn_type type =
bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX;
struct amdgpu_mn *rmn;
struct amdgpu_mn *amn;
struct amdgpu_mn_node *node = NULL, *new_node;
struct list_head bos;
struct interval_tree_node *it;
rmn = amdgpu_mn_get(adev, type);
if (IS_ERR(rmn))
return PTR_ERR(rmn);
amn = amdgpu_mn_get(adev, type);
if (IS_ERR(amn))
return PTR_ERR(amn);
new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
if (!new_node)
......@@ -394,12 +435,12 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
INIT_LIST_HEAD(&bos);
down_write(&rmn->lock);
down_write(&amn->lock);
while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) {
while ((it = interval_tree_iter_first(&amn->objects, addr, end))) {
kfree(node);
node = container_of(it, struct amdgpu_mn_node, it);
interval_tree_remove(&node->it, &rmn->objects);
interval_tree_remove(&node->it, &amn->objects);
addr = min(it->start, addr);
end = max(it->last, end);
list_splice(&node->bos, &bos);
......@@ -410,7 +451,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
else
kfree(new_node);
bo->mn = rmn;
bo->mn = amn;
node->it.start = addr;
node->it.last = end;
......@@ -418,9 +459,9 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
list_splice(&bos, &node->bos);
list_add(&bo->mn_list, &node->bos);
interval_tree_insert(&node->it, &rmn->objects);
interval_tree_insert(&node->it, &amn->objects);
up_write(&rmn->lock);
up_write(&amn->lock);
return 0;
}
......@@ -435,18 +476,18 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
void amdgpu_mn_unregister(struct amdgpu_bo *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct amdgpu_mn *rmn;
struct amdgpu_mn *amn;
struct list_head *head;
mutex_lock(&adev->mn_lock);
rmn = bo->mn;
if (rmn == NULL) {
amn = bo->mn;
if (amn == NULL) {
mutex_unlock(&adev->mn_lock);
return;
}
down_write(&rmn->lock);
down_write(&amn->lock);
/* save the next list entry for later */
head = bo->mn_list.next;
......@@ -456,12 +497,13 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
if (list_empty(head)) {
struct amdgpu_mn_node *node;
node = container_of(head, struct amdgpu_mn_node, bos);
interval_tree_remove(&node->it, &rmn->objects);
interval_tree_remove(&node->it, &amn->objects);
kfree(node);
}
up_write(&rmn->lock);
up_write(&amn->lock);
mutex_unlock(&adev->mn_lock);
}
......@@ -38,6 +38,19 @@
#include "amdgpu_trace.h"
#include "amdgpu_amdkfd.h"
/**
* DOC: amdgpu_object
*
* This defines the interfaces to operate on an &amdgpu_bo buffer object which
* represents memory used by driver (VRAM, system memory, etc.). The driver
* provides DRM/GEM APIs to userspace. DRM/GEM APIs then use these interfaces
* to create/destroy/set buffer object which are then managed by the kernel TTM
* memory manager.
* The interfaces are also used internally by kernel clients, including gfx,
* uvd, etc. for kernel managed allocations used by the GPU.
*
*/
static bool amdgpu_need_backup(struct amdgpu_device *adev)
{
if (adev->flags & AMD_IS_APU)
......@@ -73,6 +86,16 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
kfree(bo);
}
/**
* amdgpu_ttm_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo
* @bo: buffer object to be checked
*
* Uses destroy function associated with the object to determine if this is
* an &amdgpu_bo.
*
* Returns:
* true if the object belongs to &amdgpu_bo, false if not.
*/
bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
{
if (bo->destroy == &amdgpu_ttm_bo_destroy)
......@@ -80,6 +103,14 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
return false;
}
/**
* amdgpu_ttm_placement_from_domain - set buffer's placement
* @abo: &amdgpu_bo buffer object whose placement is to be set
* @domain: requested domain
*
* Sets buffer's placement according to requested domain and the buffer's
* flags.
*/
void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
......@@ -184,7 +215,8 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
*
* Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
*
* Returns 0 on success, negative error code otherwise.
* Returns:
* 0 on success, negative error code otherwise.
*/
int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
unsigned long size, int align,
......@@ -261,7 +293,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
*
* Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
*
* Returns 0 on success, negative error code otherwise.
* Returns:
* 0 on success, negative error code otherwise.
*/
int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
unsigned long size, int align,
......@@ -285,6 +318,8 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
* amdgpu_bo_free_kernel - free BO for kernel use
*
* @bo: amdgpu BO to free
* @gpu_addr: pointer to where the BO's GPU memory space address was stored
* @cpu_addr: pointer to where the BO's CPU memory space address was stored
*
* unmaps and unpin a BO for kernel internal use.
*/
......@@ -428,7 +463,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
if (unlikely(r != 0))
return r;
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size &&
if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
bo->tbo.mem.mem_type == TTM_PL_VRAM &&
bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved,
......@@ -498,6 +533,20 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev,
return r;
}
/**
* amdgpu_bo_create - create an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @bp: parameters to be used for the buffer object
* @bo_ptr: pointer to the buffer object pointer
*
* Creates an &amdgpu_bo buffer object; and if requested, also creates a
* shadow object.
* Shadow object is used to backup the original buffer object, and is always
* in GTT.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_create(struct amdgpu_device *adev,
struct amdgpu_bo_param *bp,
struct amdgpu_bo **bo_ptr)
......@@ -527,6 +576,21 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
return r;
}
/**
* amdgpu_bo_backup_to_shadow - Backs up an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @ring: amdgpu_ring for the engine handling the buffer operations
* @bo: &amdgpu_bo buffer to be backed up
* @resv: reservation object with embedded fence
* @fence: dma_fence associated with the operation
* @direct: whether to submit the job directly
*
* Copies an &amdgpu_bo buffer object to its shadow object.
* Not used for now.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
struct amdgpu_ring *ring,
struct amdgpu_bo *bo,
......@@ -559,6 +623,18 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
return r;
}
/**
* amdgpu_bo_validate - validate an &amdgpu_bo buffer object
* @bo: pointer to the buffer object
*
* Sets placement according to domain; and changes placement and caching
* policy of the buffer object according to the placement.
* This is used for validating shadow bos. It calls ttm_bo_validate() to
* make sure the buffer is resident where it needs to be.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_validate(struct amdgpu_bo *bo)
{
struct ttm_operation_ctx ctx = { false, false };
......@@ -581,6 +657,22 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo)
return r;
}
/**
* amdgpu_bo_restore_from_shadow - restore an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @ring: amdgpu_ring for the engine handling the buffer operations
* @bo: &amdgpu_bo buffer to be restored
* @resv: reservation object with embedded fence
* @fence: dma_fence associated with the operation
* @direct: whether to submit the job directly
*
* Copies a buffer object's shadow content back to the object.
* This is used for recovering a buffer from its shadow in case of a gpu
* reset where vram context may be lost.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
struct amdgpu_ring *ring,
struct amdgpu_bo *bo,
......@@ -613,6 +705,17 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
return r;
}
/**
* amdgpu_bo_kmap - map an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be mapped
* @ptr: kernel virtual address to be returned
*
* Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls
* amdgpu_bo_kptr() to get the kernel virtual address.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
{
void *kptr;
......@@ -643,6 +746,15 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
return 0;
}
/**
* amdgpu_bo_kptr - returns a kernel virtual address of the buffer object
* @bo: &amdgpu_bo buffer object
*
* Calls ttm_kmap_obj_virtual() to get the kernel virtual address
*
* Returns:
* the virtual address of a buffer object area.
*/
void *amdgpu_bo_kptr(struct amdgpu_bo *bo)
{
bool is_iomem;
......@@ -650,12 +762,27 @@ void *amdgpu_bo_kptr(struct amdgpu_bo *bo)
return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
}
/**
* amdgpu_bo_kunmap - unmap an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be unmapped
*
* Unmaps a kernel map set up by amdgpu_bo_kmap().
*/
void amdgpu_bo_kunmap(struct amdgpu_bo *bo)
{
if (bo->kmap.bo)
ttm_bo_kunmap(&bo->kmap);
}
/**
* amdgpu_bo_ref - reference an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object
*
* References the contained &ttm_buffer_object.
*
* Returns:
* a refcounted pointer to the &amdgpu_bo buffer object.
*/
struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
{
if (bo == NULL)
......@@ -665,6 +792,12 @@ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
return bo;
}
/**
* amdgpu_bo_unref - unreference an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object
*
* Unreferences the contained &ttm_buffer_object and clear the pointer
*/
void amdgpu_bo_unref(struct amdgpu_bo **bo)
{
struct ttm_buffer_object *tbo;
......@@ -678,6 +811,29 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo)
*bo = NULL;
}
/**
* amdgpu_bo_pin_restricted - pin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be pinned
* @domain: domain to be pinned to
* @min_offset: the start of requested address range
* @max_offset: the end of requested address range
* @gpu_addr: GPU offset of the &amdgpu_bo buffer object
*
* Pins the buffer object according to requested domain and address range. If
* the memory is unbound gart memory, binds the pages into gart table. Adjusts
* pin_count and pin_size accordingly.
*
* Pinning means to lock pages in memory along with keeping them at a fixed
* offset. It is required when a buffer can not be moved, for example, when
* a display buffer is being scanned out.
*
* Compared with amdgpu_bo_pin(), this function gives more flexibility on
* where to pin a buffer if there are specific restrictions on where a buffer
* must be located.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
u64 min_offset, u64 max_offset,
u64 *gpu_addr)
......@@ -772,11 +928,34 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
return r;
}
/**
* amdgpu_bo_pin - pin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be pinned
* @domain: domain to be pinned to
* @gpu_addr: GPU offset of the &amdgpu_bo buffer object
*
* A simple wrapper to amdgpu_bo_pin_restricted().
* Provides a simpler API for buffers that do not have any strict restrictions
* on where a buffer must be located.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr)
{
return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr);
}
/**
* amdgpu_bo_unpin - unpin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be unpinned
*
* Decreases the pin_count, and clears the flags if pin_count reaches 0.
* Changes placement and pin size accordingly.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_unpin(struct amdgpu_bo *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
......@@ -812,6 +991,16 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo)
return r;
}
/**
* amdgpu_bo_evict_vram - evict VRAM buffers
* @adev: amdgpu device object
*
* Evicts all VRAM buffers on the lru list of the memory type.
* Mainly used for evicting vram at suspend time.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_evict_vram(struct amdgpu_device *adev)
{
/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
......@@ -834,6 +1023,15 @@ static const char *amdgpu_vram_names[] = {
"DDR4",
};
/**
* amdgpu_bo_init - initialize memory manager
* @adev: amdgpu device object
*
* Calls amdgpu_ttm_init() to initialize amdgpu memory manager.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_init(struct amdgpu_device *adev)
{
/* reserve PAT memory space to WC for VRAM */
......@@ -851,6 +1049,16 @@ int amdgpu_bo_init(struct amdgpu_device *adev)
return amdgpu_ttm_init(adev);
}
/**
* amdgpu_bo_late_init - late init
* @adev: amdgpu device object
*
* Calls amdgpu_ttm_late_init() to free resources used earlier during
* initialization.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_late_init(struct amdgpu_device *adev)
{
amdgpu_ttm_late_init(adev);
......@@ -858,6 +1066,12 @@ int amdgpu_bo_late_init(struct amdgpu_device *adev)
return 0;
}
/**
* amdgpu_bo_fini - tear down memory manager
* @adev: amdgpu device object
*
* Reverses amdgpu_bo_init() to tear down memory manager.
*/
void amdgpu_bo_fini(struct amdgpu_device *adev)
{
amdgpu_ttm_fini(adev);
......@@ -865,12 +1079,33 @@ void amdgpu_bo_fini(struct amdgpu_device *adev)
arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
}
/**
* amdgpu_bo_fbdev_mmap - mmap fbdev memory
* @bo: &amdgpu_bo buffer object
* @vma: vma as input from the fbdev mmap method
*
* Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
struct vm_area_struct *vma)
{
return ttm_fbdev_mmap(vma, &bo->tbo);
}
/**
* amdgpu_bo_set_tiling_flags - set tiling flags
* @bo: &amdgpu_bo buffer object
* @tiling_flags: new flags
*
* Sets buffer object's tiling flags with the new one. Used by GEM ioctl or
* kernel driver to set the tiling flags on a buffer.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
......@@ -883,6 +1118,14 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
return 0;
}
/**
* amdgpu_bo_get_tiling_flags - get tiling flags
* @bo: &amdgpu_bo buffer object
* @tiling_flags: returned flags
*
* Gets buffer object's tiling flags. Used by GEM ioctl or kernel driver to
* set the tiling flags on a buffer.
*/
void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
{
lockdep_assert_held(&bo->tbo.resv->lock.base);
......@@ -891,6 +1134,19 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
*tiling_flags = bo->tiling_flags;
}
/**
* amdgpu_bo_set_metadata - set metadata
* @bo: &amdgpu_bo buffer object
* @metadata: new metadata
* @metadata_size: size of the new metadata
* @flags: flags of the new metadata
*
* Sets buffer object's metadata, its size and flags.
* Used via GEM ioctl.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
uint32_t metadata_size, uint64_t flags)
{
......@@ -920,6 +1176,21 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
return 0;
}
/**
* amdgpu_bo_get_metadata - get metadata
* @bo: &amdgpu_bo buffer object
* @buffer: returned metadata
* @buffer_size: size of the buffer
* @metadata_size: size of the returned metadata
* @flags: flags of the returned metadata
*
* Gets buffer object's metadata, its size and flags. buffer_size shall not be
* less than metadata_size.
* Used via GEM ioctl.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
size_t buffer_size, uint32_t *metadata_size,
uint64_t *flags)
......@@ -943,6 +1214,16 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
return 0;
}
/**
* amdgpu_bo_move_notify - notification about a memory move
* @bo: pointer to a buffer object
* @evict: if this move is evicting the buffer from the graphics address space
* @new_mem: new information of the bufer object
*
* Marks the corresponding &amdgpu_bo buffer object as invalid, also performs
* bookkeeping.
* TTM driver callback which is called when ttm moves a buffer.
*/
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
struct ttm_mem_reg *new_mem)
......@@ -971,6 +1252,17 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type);
}
/**
* amdgpu_bo_fault_reserve_notify - notification about a memory fault
* @bo: pointer to a buffer object
*
* Notifies the driver we are taking a fault on this BO and have reserved it,
* also performs bookkeeping.
* TTM driver callback for dealing with vm faults.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
......@@ -1044,10 +1336,11 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
* amdgpu_bo_gpu_offset - return GPU offset of bo
* @bo: amdgpu object for which we query the offset
*
* Returns current GPU offset of the object.
*
* Note: object should either be pinned or reserved when calling this
* function, it might be useful to add check for this for debugging.
*
* Returns:
* current GPU offset of the object.
*/
u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
{
......@@ -1063,6 +1356,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
return bo->tbo.offset;
}
/**
* amdgpu_bo_get_preferred_pin_domain - get preferred domain for scanout
* @adev: amdgpu device object
* @domain: allowed :ref:`memory domains <amdgpu_memory_domains>`
*
* Returns:
* Which of the allowed domains is preferred for pinning the BO for scanout.
*/
uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev,
uint32_t domain)
{
......
......@@ -68,11 +68,11 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
if (adev->pm.dpm_enabled) {
mutex_lock(&adev->pm.mutex);
if (power_supply_is_system_supplied() > 0)
adev->pm.dpm.ac_power = true;
adev->pm.ac_power = true;
else
adev->pm.dpm.ac_power = false;
adev->pm.ac_power = false;
if (adev->powerplay.pp_funcs->enable_bapm)
amdgpu_dpm_enable_bapm(adev, adev->pm.dpm.ac_power);
amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
mutex_unlock(&adev->pm.mutex);
}
}
......@@ -80,12 +80,15 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
/**
* DOC: power_dpm_state
*
* This is a legacy interface and is only provided for backwards compatibility.
* The amdgpu driver provides a sysfs API for adjusting certain power
* related parameters. The file power_dpm_state is used for this.
* The power_dpm_state file is a legacy interface and is only provided for
* backwards compatibility. The amdgpu driver provides a sysfs API for adjusting
* certain power related parameters. The file power_dpm_state is used for this.
* It accepts the following arguments:
*
* - battery
*
* - balanced
*
* - performance
*
* battery
......@@ -169,14 +172,21 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,
* The amdgpu driver provides a sysfs API for adjusting certain power
* related parameters. The file power_dpm_force_performance_level is
* used for this. It accepts the following arguments:
*
* - auto
*
* - low
*
* - high
*
* - manual
* - GPU fan
*
* - profile_standard
*
* - profile_min_sclk
*
* - profile_min_mclk
*
* - profile_peak
*
* auto
......@@ -463,8 +473,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
* this.
*
* Reading the file will display:
*
* - a list of engine clock levels and voltages labeled OD_SCLK
*
* - a list of memory clock levels and voltages labeled OD_MCLK
*
* - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE
*
* To manually adjust these settings, first select manual using
......@@ -1285,35 +1298,51 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
* DOC: hwmon
*
* The amdgpu driver exposes the following sensor interfaces:
*
* - GPU temperature (via the on-die sensor)
*
* - GPU voltage
*
* - Northbridge voltage (APUs only)
*
* - GPU power
*
* - GPU fan
*
* hwmon interfaces for GPU temperature:
*
* - temp1_input: the on die GPU temperature in millidegrees Celsius
*
* - temp1_crit: temperature critical max value in millidegrees Celsius
*
* - temp1_crit_hyst: temperature hysteresis for critical limit in millidegrees Celsius
*
* hwmon interfaces for GPU voltage:
*
* - in0_input: the voltage on the GPU in millivolts
*
* - in1_input: the voltage on the Northbridge in millivolts
*
* hwmon interfaces for GPU power:
*
* - power1_average: average power used by the GPU in microWatts
*
* - power1_cap_min: minimum cap supported in microWatts
*
* - power1_cap_max: maximum cap supported in microWatts
*
* - power1_cap: selected power cap in microWatts
*
* hwmon interfaces for GPU fan:
*
* - pwm1: pulse width modulation fan level (0-255)
* - pwm1_enable: pulse width modulation fan control method
* 0: no fan speed control
* 1: manual fan speed control using pwm interface
* 2: automatic fan speed control
*
* - pwm1_enable: pulse width modulation fan control method (0: no fan speed control, 1: manual fan speed control using pwm interface, 2: automatic fan speed control)
*
* - pwm1_min: pulse width modulation fan control minimum level (0)
*
* - pwm1_max: pulse width modulation fan control maximum level (255)
*
* - fan1_input: fan speed in RPM
*
* You can use hwmon tools like sensors to view this information on your system.
......@@ -1878,6 +1907,14 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
amdgpu_fence_wait_empty(ring);
}
mutex_lock(&adev->pm.mutex);
/* update battery/ac status */
if (power_supply_is_system_supplied() > 0)
adev->pm.ac_power = true;
else
adev->pm.ac_power = false;
mutex_unlock(&adev->pm.mutex);
if (adev->powerplay.pp_funcs->dispatch_tasks) {
if (!amdgpu_device_has_dc_support(adev)) {
mutex_lock(&adev->pm.mutex);
......@@ -1898,14 +1935,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
} else {
mutex_lock(&adev->pm.mutex);
amdgpu_dpm_get_active_displays(adev);
/* update battery/ac status */
if (power_supply_is_system_supplied() > 0)
adev->pm.dpm.ac_power = true;
else
adev->pm.dpm.ac_power = false;
amdgpu_dpm_change_power_state_locked(adev);
mutex_unlock(&adev->pm.mutex);
}
}
......
......@@ -23,6 +23,14 @@
*
* Authors: Alex Deucher
*/
/**
* DOC: PRIME Buffer Sharing
*
* The following callback implementations are used for :ref:`sharing GEM buffer
* objects between different devices via PRIME <prime_buffer_sharing>`.
*/
#include <drm/drmP.h>
#include "amdgpu.h"
......@@ -32,6 +40,14 @@
static const struct dma_buf_ops amdgpu_dmabuf_ops;
/**
* amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table
* implementation
* @obj: GEM buffer object
*
* Returns:
* A scatter/gather table for the pinned pages of the buffer object's memory.
*/
struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
......@@ -40,6 +56,15 @@ struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
}
/**
* amdgpu_gem_prime_vmap - &dma_buf_ops.vmap implementation
* @obj: GEM buffer object
*
* Sets up an in-kernel virtual mapping of the buffer object's memory.
*
* Returns:
* The virtual address of the mapping or an error pointer.
*/
void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
......@@ -53,6 +78,13 @@ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj)
return bo->dma_buf_vmap.virtual;
}
/**
* amdgpu_gem_prime_vunmap - &dma_buf_ops.vunmap implementation
* @obj: GEM buffer object
* @vaddr: virtual address (unused)
*
* Tears down the in-kernel virtual mapping of the buffer object's memory.
*/
void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
......@@ -60,6 +92,17 @@ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
ttm_bo_kunmap(&bo->dma_buf_vmap);
}
/**
* amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation
* @obj: GEM buffer object
* @vma: virtual memory area
*
* Sets up a userspace mapping of the buffer object's memory in the given
* virtual memory area.
*
* Returns:
* 0 on success or negative error code.
*/
int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
......@@ -94,6 +137,19 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma
return ret;
}
/**
* amdgpu_gem_prime_import_sg_table - &drm_driver.gem_prime_import_sg_table
* implementation
* @dev: DRM device
* @attach: DMA-buf attachment
* @sg: Scatter/gather table
*
* Import shared DMA buffer memory exported by another device.
*
* Returns:
* A new GEM buffer object of the given DRM device, representing the memory
* described by the given DMA-buf attachment and scatter/gather table.
*/
struct drm_gem_object *
amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
......@@ -132,6 +188,19 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
return ERR_PTR(ret);
}
/**
* amdgpu_gem_map_attach - &dma_buf_ops.attach implementation
* @dma_buf: shared DMA buffer
* @target_dev: target device
* @attach: DMA-buf attachment
*
* Makes sure that the shared DMA buffer can be accessed by the target device.
* For now, simply pins it to the GTT domain, where it should be accessible by
* all DMA devices.
*
* Returns:
* 0 on success or negative error code.
*/
static int amdgpu_gem_map_attach(struct dma_buf *dma_buf,
struct dma_buf_attachment *attach)
{
......@@ -180,6 +249,14 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf,
return r;
}
/**
* amdgpu_gem_map_detach - &dma_buf_ops.detach implementation
* @dma_buf: shared DMA buffer
* @attach: DMA-buf attachment
*
* This is called when a shared DMA buffer no longer needs to be accessible by
* the other device. For now, simply unpins the buffer from GTT.
*/
static void amdgpu_gem_map_detach(struct dma_buf *dma_buf,
struct dma_buf_attachment *attach)
{
......@@ -201,6 +278,13 @@ static void amdgpu_gem_map_detach(struct dma_buf *dma_buf,
drm_gem_map_detach(dma_buf, attach);
}
/**
* amdgpu_gem_prime_res_obj - &drm_driver.gem_prime_res_obj implementation
* @obj: GEM buffer object
*
* Returns:
* The buffer object's reservation object.
*/
struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
......@@ -208,6 +292,18 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
return bo->tbo.resv;
}
/**
* amdgpu_gem_begin_cpu_access - &dma_buf_ops.begin_cpu_access implementation
* @dma_buf: shared DMA buffer
* @direction: direction of DMA transfer
*
* This is called before CPU access to the shared DMA buffer's memory. If it's
* a read access, the buffer is moved to the GTT domain if possible, for optimal
* CPU read performance.
*
* Returns:
* 0 on success or negative error code.
*/
static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction direction)
{
......@@ -250,6 +346,18 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = {
.vunmap = drm_gem_dmabuf_vunmap,
};
/**
* amdgpu_gem_prime_export - &drm_driver.gem_prime_export implementation
* @dev: DRM device
* @gobj: GEM buffer object
* @flags: flags like DRM_CLOEXEC and DRM_RDWR
*
* The main work is done by the &drm_gem_prime_export helper, which in turn
* uses &amdgpu_gem_prime_res_obj.
*
* Returns:
* Shared DMA buffer representing the GEM buffer object from the given device.
*/
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *gobj,
int flags)
......@@ -270,6 +378,17 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
return buf;
}
/**
* amdgpu_gem_prime_import - &drm_driver.gem_prime_import implementation
* @dev: DRM device
* @dma_buf: Shared DMA buffer
*
* The main work is done by the &drm_gem_prime_import helper, which in turn
* uses &amdgpu_gem_prime_import_sg_table.
*
* Returns:
* GEM buffer object representing the shared DMA buffer for the given device.
*/
struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf)
{
......
......@@ -96,6 +96,9 @@ static int amdgpu_identity_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC:
*out_ring = &adev->vcn.ring_enc[ring];
break;
case AMDGPU_HW_IP_VCN_JPEG:
*out_ring = &adev->vcn.ring_jpeg;
break;
default:
*out_ring = NULL;
DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip);
......@@ -260,6 +263,9 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC:
ip_num_rings = adev->vcn.num_enc_rings;
break;
case AMDGPU_HW_IP_VCN_JPEG:
ip_num_rings = 1;
break;
default:
DRM_DEBUG("unknown ip type: %d\n", hw_ip);
return -EINVAL;
......@@ -287,6 +293,7 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_UVD_ENC:
case AMDGPU_HW_IP_VCN_DEC:
case AMDGPU_HW_IP_VCN_ENC:
case AMDGPU_HW_IP_VCN_JPEG:
r = amdgpu_identity_map(adev, mapper, ring, out_ring);
break;
case AMDGPU_HW_IP_DMA:
......
......@@ -304,7 +304,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
0xffffffffffffffff : ring->buf_mask;
/* Allocate ring buffer */
if (ring->ring_obj == NULL) {
r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_GTT,
&ring->ring_obj,
&ring->gpu_addr,
......
......@@ -53,7 +53,8 @@ enum amdgpu_ring_type {
AMDGPU_RING_TYPE_KIQ,
AMDGPU_RING_TYPE_UVD_ENC,
AMDGPU_RING_TYPE_VCN_DEC,
AMDGPU_RING_TYPE_VCN_ENC
AMDGPU_RING_TYPE_VCN_ENC,
AMDGPU_RING_TYPE_VCN_JPEG
};
struct amdgpu_device;
......@@ -112,6 +113,7 @@ struct amdgpu_ring_funcs {
u32 nop;
bool support_64bit_ptrs;
unsigned vmhub;
unsigned extra_dw;
/* ring read/write ptr handling */
u64 (*get_rptr)(struct amdgpu_ring *ring);
......
......@@ -277,7 +277,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
if (!adev->mman.buffer_funcs_enabled) {
/* Move to system memory */
amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
} else if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size &&
} else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
!(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
amdgpu_bo_in_cpu_visible_vram(abo)) {
......
......@@ -127,7 +127,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
unsigned long bo_size;
const char *fw_name;
const struct common_firmware_header *hdr;
unsigned version_major, version_minor, family_id;
unsigned family_id;
int i, j, r;
INIT_DELAYED_WORK(&adev->uvd.inst->idle_work, amdgpu_uvd_idle_work_handler);
......@@ -208,29 +208,46 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
version_major, version_minor, family_id);
/*
* Limit the number of UVD handles depending on microcode major
* and minor versions. The firmware version which has 40 UVD
* instances support is 1.80. So all subsequent versions should
* also have the same support.
*/
if ((version_major > 0x01) ||
((version_major == 0x01) && (version_minor >= 0x50)))
adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) |
(family_id << 8));
if (adev->asic_type < CHIP_VEGA20) {
unsigned version_major, version_minor;
version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
version_major, version_minor, family_id);
/*
* Limit the number of UVD handles depending on microcode major
* and minor versions. The firmware version which has 40 UVD
* instances support is 1.80. So all subsequent versions should
* also have the same support.
*/
if ((version_major > 0x01) ||
((version_major == 0x01) && (version_minor >= 0x50)))
adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) |
(family_id << 8));
if ((adev->asic_type == CHIP_POLARIS10 ||
adev->asic_type == CHIP_POLARIS11) &&
(adev->uvd.fw_version < FW_1_66_16))
DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n",
version_major, version_minor);
} else {
unsigned int enc_major, enc_minor, dec_minor;
dec_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
enc_minor = (le32_to_cpu(hdr->ucode_version) >> 24) & 0x3f;
enc_major = (le32_to_cpu(hdr->ucode_version) >> 30) & 0x3;
DRM_INFO("Found UVD firmware ENC: %hu.%hu DEC: .%hu Family ID: %hu\n",
enc_major, enc_minor, dec_minor, family_id);
if ((adev->asic_type == CHIP_POLARIS10 ||
adev->asic_type == CHIP_POLARIS11) &&
(adev->uvd.fw_version < FW_1_66_16))
DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n",
version_major, version_minor);
adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
adev->uvd.fw_version = le32_to_cpu(hdr->ucode_version);
}
bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
+ AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles;
......
......@@ -119,6 +119,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
for (i = 0; i < adev->vcn.num_enc_rings; ++i)
amdgpu_ring_fini(&adev->vcn.ring_enc[i]);
amdgpu_ring_fini(&adev->vcn.ring_jpeg);
release_firmware(adev->vcn.fw);
return 0;
......@@ -576,3 +578,129 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
dma_fence_put(fence);
return r;
}
int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t tmp = 0;
unsigned i;
int r;
WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
if (r) {
DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
ring->idx, r);
return r;
}
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0, 0, 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID));
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < adev->usec_timeout) {
DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
ring->idx, i);
} else {
DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
ring->idx, tmp);
r = -EINVAL;
}
return r;
}
static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle,
struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_job *job;
struct amdgpu_ib *ib;
struct dma_fence *f = NULL;
const unsigned ib_size_dw = 16;
int i, r;
r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
if (r)
return r;
ib = &job->ibs[0];
ib->ptr[0] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH), 0, 0, PACKETJ_TYPE0);
ib->ptr[1] = 0xDEADBEEF;
for (i = 2; i < 16; i += 2) {
ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
ib->ptr[i+1] = 0;
}
ib->length_dw = 16;
r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
job->fence = dma_fence_get(f);
if (r)
goto err;
amdgpu_job_free(job);
if (fence)
*fence = dma_fence_get(f);
dma_fence_put(f);
return 0;
err:
amdgpu_job_free(job);
return r;
}
int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
{
struct amdgpu_device *adev = ring->adev;
uint32_t tmp = 0;
unsigned i;
struct dma_fence *fence = NULL;
long r = 0;
r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence);
if (r) {
DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r);
goto error;
}
r = dma_fence_wait_timeout(fence, false, timeout);
if (r == 0) {
DRM_ERROR("amdgpu: IB test timed out.\n");
r = -ETIMEDOUT;
goto error;
} else if (r < 0) {
DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto error;
} else
r = 0;
for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH));
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < adev->usec_timeout)
DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
else {
DRM_ERROR("ib test failed (0x%08X)\n", tmp);
r = -EINVAL;
}
dma_fence_put(fence);
error:
return r;
}
......@@ -66,6 +66,7 @@ struct amdgpu_vcn {
const struct firmware *fw; /* VCN firmware */
struct amdgpu_ring ring_dec;
struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS];
struct amdgpu_ring ring_jpeg;
struct amdgpu_irq_src irq;
unsigned num_enc_rings;
};
......@@ -83,4 +84,7 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout);
int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring);
int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout);
int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring);
int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout);
#endif
......@@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index,
ectx.abort = false;
ectx.last_jump = 0;
if (ws)
ectx.ws = kcalloc(4, ws, GFP_KERNEL);
ectx.ws = kcalloc(4, ws, GFP_ATOMIC);
else
ectx.ws = NULL;
......
......@@ -951,12 +951,12 @@ static void ci_apply_state_adjust_rules(struct amdgpu_device *adev,
else
pi->battery_state = false;
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
if (adev->pm.dpm.ac_power == false) {
if (adev->pm.ac_power == false) {
for (i = 0; i < ps->performance_level_count; i++) {
if (ps->performance_levels[i].mclk > max_limits->mclk)
ps->performance_levels[i].mclk = max_limits->mclk;
......@@ -4078,7 +4078,7 @@ static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits;
int i;
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......@@ -4127,7 +4127,7 @@ static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits;
int i;
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......@@ -4160,7 +4160,7 @@ static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits;
int i;
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......@@ -4191,7 +4191,7 @@ static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits;
int i;
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......
......@@ -2003,9 +2003,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block);
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
if (amdgpu_dpm == -1)
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
......@@ -2024,9 +2024,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block);
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
if (amdgpu_dpm == -1)
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC)
......
......@@ -866,26 +866,32 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
struct amdgpu_device *adev = ring->adev;
struct amdgpu_ib ib;
struct dma_fence *f = NULL;
uint32_t scratch;
uint32_t tmp = 0;
unsigned int index;
uint64_t gpu_addr;
uint32_t tmp;
long r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
r = amdgpu_device_wb_get(adev, &index);
if (r) {
DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
return r;
}
WREG32(scratch, 0xCAFEDEAD);
gpu_addr = adev->wb.gpu_addr + (index * 4);
adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
r = amdgpu_ib_get(adev, NULL, 16, &ib);
if (r) {
DRM_ERROR("amdgpu: failed to get ib (%ld).\n", 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;
ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
ib.ptr[2] = lower_32_bits(gpu_addr);
ib.ptr[3] = upper_32_bits(gpu_addr);
ib.ptr[4] = 0xDEADBEEF;
ib.length_dw = 5;
r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r)
......@@ -900,20 +906,21 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err2;
}
tmp = RREG32(scratch);
tmp = adev->wb.wb[index];
if (tmp == 0xDEADBEEF) {
DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
r = 0;
} else {
DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
scratch, tmp);
DRM_ERROR("ib test on ring %d failed\n", ring->idx);
r = -EINVAL;
}
err2:
amdgpu_ib_free(adev, &ib, NULL);
dma_fence_put(f);
err1:
amdgpu_gfx_scratch_free(adev, scratch);
amdgpu_device_wb_free(adev, index);
return r;
}
......@@ -2048,6 +2055,20 @@ static int gfx_v8_0_sw_init(void *handle)
if (r)
return r;
/* Add CP EDC/ECC irq */
r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 197,
&adev->gfx.cp_ecc_error_irq);
if (r)
return r;
/* SQ interrupts. */
r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 239,
&adev->gfx.sq_irq);
if (r) {
DRM_ERROR("amdgpu_irq_add() for SQ failed: %d\n", r);
return r;
}
adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
gfx_v8_0_scratch_init(adev);
......@@ -5111,6 +5132,10 @@ static int gfx_v8_0_hw_fini(void *handle)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.sq_irq, 0);
/* disable KCQ to avoid CPC touch memory not valid anymore */
for (i = 0; i < adev->gfx.num_compute_rings; i++)
gfx_v8_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]);
......@@ -5542,6 +5567,20 @@ static int gfx_v8_0_late_init(void *handle)
if (r)
return r;
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
if (r) {
DRM_ERROR("amdgpu_irq_get() failed to get IRQ for EDC, r: %d.\n", r);
return r;
}
r = amdgpu_irq_get(adev, &adev->gfx.sq_irq, 0);
if (r) {
DRM_ERROR(
"amdgpu_irq_get() failed to get IRQ for SQ, r: %d.\n",
r);
return r;
}
amdgpu_device_ip_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_GFX,
AMD_PG_STATE_GATE);
......@@ -6787,6 +6826,77 @@ static int gfx_v8_0_set_eop_interrupt_state(struct amdgpu_device *adev,
return 0;
}
static int gfx_v8_0_set_cp_ecc_int_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned int type,
enum amdgpu_interrupt_state state)
{
int enable_flag;
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
enable_flag = 0;
break;
case AMDGPU_IRQ_STATE_ENABLE:
enable_flag = 1;
break;
default:
return -EINVAL;
}
WREG32_FIELD(CP_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING1, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING2, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CPC_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
return 0;
}
static int gfx_v8_0_set_sq_int_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned int type,
enum amdgpu_interrupt_state state)
{
int enable_flag;
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
enable_flag = 1;
break;
case AMDGPU_IRQ_STATE_ENABLE:
enable_flag = 0;
break;
default:
return -EINVAL;
}
WREG32_FIELD(SQ_INTERRUPT_MSG_CTRL, STALL,
enable_flag);
return 0;
}
static int gfx_v8_0_eop_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
......@@ -6837,6 +6947,69 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
return 0;
}
static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("CP EDC/ECC error detected.");
return 0;
}
static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
u8 enc, se_id;
char type[20];
/* Parse all fields according to SQ_INTERRUPT* registers */
enc = (entry->src_data[0] >> 26) & 0x3;
se_id = (entry->src_data[0] >> 24) & 0x3;
switch (enc) {
case 0:
DRM_INFO("SQ general purpose intr detected:"
"se_id %d, immed_overflow %d, host_reg_overflow %d,"
"host_cmd_overflow %d, cmd_timestamp %d,"
"reg_timestamp %d, thread_trace_buff_full %d,"
"wlt %d, thread_trace %d.\n",
se_id,
(entry->src_data[0] >> 7) & 0x1,
(entry->src_data[0] >> 6) & 0x1,
(entry->src_data[0] >> 5) & 0x1,
(entry->src_data[0] >> 4) & 0x1,
(entry->src_data[0] >> 3) & 0x1,
(entry->src_data[0] >> 2) & 0x1,
(entry->src_data[0] >> 1) & 0x1,
entry->src_data[0] & 0x1
);
break;
case 1:
case 2:
if (enc == 1)
sprintf(type, "instruction intr");
else
sprintf(type, "EDC/ECC error");
DRM_INFO(
"SQ %s detected: "
"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n",
type, se_id,
(entry->src_data[0] >> 20) & 0xf,
(entry->src_data[0] >> 18) & 0x3,
(entry->src_data[0] >> 14) & 0xf,
(entry->src_data[0] >> 10) & 0xf
);
break;
default:
DRM_ERROR("SQ invalid encoding type\n.");
return -EINVAL;
}
return 0;
}
static int gfx_v8_0_kiq_set_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src,
unsigned int type,
......@@ -7037,6 +7210,16 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_kiq_irq_funcs = {
.process = gfx_v8_0_kiq_irq,
};
static const struct amdgpu_irq_src_funcs gfx_v8_0_cp_ecc_error_irq_funcs = {
.set = gfx_v8_0_set_cp_ecc_int_state,
.process = gfx_v8_0_cp_ecc_error_irq,
};
static const struct amdgpu_irq_src_funcs gfx_v8_0_sq_irq_funcs = {
.set = gfx_v8_0_set_sq_int_state,
.process = gfx_v8_0_sq_irq,
};
static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
{
adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST;
......@@ -7050,6 +7233,12 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
adev->gfx.kiq.irq.num_types = AMDGPU_CP_KIQ_IRQ_LAST;
adev->gfx.kiq.irq.funcs = &gfx_v8_0_kiq_irq_funcs;
adev->gfx.cp_ecc_error_irq.num_types = 1;
adev->gfx.cp_ecc_error_irq.funcs = &gfx_v8_0_cp_ecc_error_irq_funcs;
adev->gfx.sq_irq.num_types = 1;
adev->gfx.sq_irq.funcs = &gfx_v8_0_sq_irq_funcs;
}
static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev)
......
......@@ -1921,7 +1921,7 @@ static int kv_dpm_set_power_state(void *handle)
int ret;
if (pi->bapm_enable) {
ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.dpm.ac_power);
ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power);
if (ret) {
DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
return ret;
......
......@@ -3480,7 +3480,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
disable_sclk_switching = true;
}
if (adev->pm.dpm.ac_power)
if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......@@ -3489,7 +3489,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc)
ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc;
}
if (adev->pm.dpm.ac_power == false) {
if (adev->pm.ac_power == false) {
for (i = 0; i < ps->performance_level_count; i++) {
if (ps->performance_levels[i].mclk > max_limits->mclk)
ps->performance_levels[i].mclk = max_limits->mclk;
......
......@@ -53,6 +53,29 @@
#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
#define PACKETJ_CONDITION_CHECK0 0
#define PACKETJ_CONDITION_CHECK1 1
#define PACKETJ_CONDITION_CHECK2 2
#define PACKETJ_CONDITION_CHECK3 3
#define PACKETJ_CONDITION_CHECK4 4
#define PACKETJ_CONDITION_CHECK5 5
#define PACKETJ_CONDITION_CHECK6 6
#define PACKETJ_CONDITION_CHECK7 7
#define PACKETJ_TYPE0 0
#define PACKETJ_TYPE1 1
#define PACKETJ_TYPE2 2
#define PACKETJ_TYPE3 3
#define PACKETJ_TYPE4 4
#define PACKETJ_TYPE5 5
#define PACKETJ_TYPE6 6
#define PACKETJ_TYPE7 7
#define PACKETJ(reg, r, cond, type) ((reg & 0x3FFFF) | \
((r & 0x3F) << 18) | \
((cond & 0xF) << 24) | \
((type & 0xF) << 28))
/* Packet 3 types */
#define PACKET3_NOP 0x10
#define PACKET3_SET_BASE 0x11
......
......@@ -38,7 +38,9 @@
static int vcn_v1_0_stop(struct amdgpu_device *adev);
static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr);
/**
* vcn_v1_0_early_init - set function pointers
......@@ -55,6 +57,7 @@ static int vcn_v1_0_early_init(void *handle)
vcn_v1_0_set_dec_ring_funcs(adev);
vcn_v1_0_set_enc_ring_funcs(adev);
vcn_v1_0_set_jpeg_ring_funcs(adev);
vcn_v1_0_set_irq_funcs(adev);
return 0;
......@@ -86,6 +89,11 @@ static int vcn_v1_0_sw_init(void *handle)
return r;
}
/* VCN JPEG TRAP */
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 126, &adev->vcn.irq);
if (r)
return r;
r = amdgpu_vcn_sw_init(adev);
if (r)
return r;
......@@ -108,6 +116,12 @@ static int vcn_v1_0_sw_init(void *handle)
return r;
}
ring = &adev->vcn.ring_jpeg;
sprintf(ring->name, "vcn_jpeg");
r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.irq, 0);
if (r)
return r;
return r;
}
......@@ -162,6 +176,14 @@ static int vcn_v1_0_hw_init(void *handle)
}
}
ring = &adev->vcn.ring_jpeg;
ring->ready = true;
r = amdgpu_ring_test_ring(ring);
if (r) {
ring->ready = false;
goto done;
}
done:
if (!r)
DRM_INFO("VCN decode and encode initialized successfully.\n");
......@@ -729,6 +751,22 @@ static int vcn_v1_0_start(struct amdgpu_device *adev)
WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4);
ring = &adev->vcn.ring_jpeg;
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L));
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L);
/* initialize wptr */
ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
/* copy patch commands to the jpeg ring */
vcn_v1_0_jpeg_ring_set_patch_ring(ring,
(ring->wptr + ring->max_dw * amdgpu_sched_hw_submission));
return 0;
}
......@@ -1126,6 +1164,383 @@ static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, val);
}
/**
* vcn_v1_0_jpeg_ring_get_rptr - get read pointer
*
* @ring: amdgpu_ring pointer
*
* Returns the current hardware read pointer
*/
static uint64_t vcn_v1_0_jpeg_ring_get_rptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR);
}
/**
* vcn_v1_0_jpeg_ring_get_wptr - get write pointer
*
* @ring: amdgpu_ring pointer
*
* Returns the current hardware write pointer
*/
static uint64_t vcn_v1_0_jpeg_ring_get_wptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
}
/**
* vcn_v1_0_jpeg_ring_set_wptr - set write pointer
*
* @ring: amdgpu_ring pointer
*
* Commits the write pointer to the hardware
*/
static void vcn_v1_0_jpeg_ring_set_wptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr));
}
/**
* vcn_v1_0_jpeg_ring_insert_start - insert a start command
*
* @ring: amdgpu_ring pointer
*
* Write a start command to the ring.
*/
static void vcn_v1_0_jpeg_ring_insert_start(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x68e04);
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x80010000);
}
/**
* vcn_v1_0_jpeg_ring_insert_end - insert a end command
*
* @ring: amdgpu_ring pointer
*
* Write a end command to the ring.
*/
static void vcn_v1_0_jpeg_ring_insert_end(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x68e04);
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x00010000);
}
/**
* vcn_v1_0_jpeg_ring_emit_fence - emit an fence & trap command
*
* @ring: amdgpu_ring pointer
* @fence: fence to emit
*
* Write a fence and a trap command to the ring.
*/
static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
unsigned flags)
{
struct amdgpu_device *adev = ring->adev;
WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA0), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA1), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x8);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(0, 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE2));
amdgpu_ring_write(ring, 0xffffffff);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x3fbc);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x1);
}
/**
* vcn_v1_0_jpeg_ring_emit_ib - execute indirect buffer
*
* @ring: amdgpu_ring pointer
* @ib: indirect buffer to execute
*
* Write ring commands to execute the indirect buffer.
*/
static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_ib *ib,
unsigned vmid, bool ctx_switch)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, (vmid | (vmid << 4)));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, (vmid | (vmid << 4)));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_IB_SIZE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, ib->length_dw);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_STATUS), 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3));
amdgpu_ring_write(ring, 0x2);
}
static void vcn_v1_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val,
uint32_t mask)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg_offset = (reg << 2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, val);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3));
} else {
amdgpu_ring_write(ring, reg_offset);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE3));
}
amdgpu_ring_write(ring, mask);
}
static void vcn_v1_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring,
unsigned vmid, uint64_t pd_addr)
{
struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub];
uint32_t data0, data1, mask;
pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr);
/* wait for register write */
data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2;
data1 = lower_32_bits(pd_addr);
mask = 0xffffffff;
vcn_v1_0_jpeg_ring_emit_reg_wait(ring, data0, data1, mask);
}
static void vcn_v1_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg_offset = (reg << 2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0));
} else {
amdgpu_ring_write(ring, reg_offset);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE0));
}
amdgpu_ring_write(ring, val);
}
static void vcn_v1_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count)
{
int i;
WARN_ON(ring->wptr % 2 || count % 2);
for (i = 0; i < count / 2; i++) {
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6));
amdgpu_ring_write(ring, 0);
}
}
static void vcn_v1_0_jpeg_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val)
{
struct amdgpu_device *adev = ring->adev;
ring->ring[(*ptr)++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0);
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
ring->ring[(*ptr)++] = 0;
ring->ring[(*ptr)++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0);
} else {
ring->ring[(*ptr)++] = reg_offset;
ring->ring[(*ptr)++] = PACKETJ(0, 0, 0, PACKETJ_TYPE0);
}
ring->ring[(*ptr)++] = val;
}
static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg, reg_offset, val, mask, i;
// 1st: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW);
reg_offset = (reg << 2);
val = lower_32_bits(ring->gpu_addr);
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 2nd: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH);
reg_offset = (reg << 2);
val = upper_32_bits(ring->gpu_addr);
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 3rd to 5th: issue MEM_READ commands
for (i = 0; i <= 2; i++) {
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE2);
ring->ring[ptr++] = 0;
}
// 6th: program mmUVD_JRBC_RB_CNTL register to enable NO_FETCH and RPTR write ability
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x13;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 7th: program mmUVD_JRBC_RB_REF_DATA
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA);
reg_offset = (reg << 2);
val = 0x1;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 8th: issue conditional register read mmUVD_JRBC_RB_CNTL
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x1;
mask = 0x1;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0);
ring->ring[ptr++] = 0x01400200;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0);
ring->ring[ptr++] = val;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0);
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
ring->ring[ptr++] = 0;
ring->ring[ptr++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3);
} else {
ring->ring[ptr++] = reg_offset;
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE3);
}
ring->ring[ptr++] = mask;
//9th to 21st: insert no-op
for (i = 0; i <= 12; i++) {
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
ring->ring[ptr++] = 0;
}
//22nd: reset mmUVD_JRBC_RB_RPTR
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_RPTR);
reg_offset = (reg << 2);
val = 0;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
//23rd: program mmUVD_JRBC_RB_CNTL to disable no_fetch
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x12;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
}
static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned type,
......@@ -1150,6 +1565,9 @@ static int vcn_v1_0_process_interrupt(struct amdgpu_device *adev,
case 120:
amdgpu_fence_process(&adev->vcn.ring_enc[1]);
break;
case 126:
amdgpu_fence_process(&adev->vcn.ring_jpeg);
break;
default:
DRM_ERROR("Unhandled interrupt: %d %d\n",
entry->src_id, entry->src_data[0]);
......@@ -1273,6 +1691,39 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = {
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
};
static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.nop = PACKET0(0x81ff, 0),
.support_64bit_ptrs = false,
.vmhub = AMDGPU_MMHUB,
.extra_dw = 64,
.get_rptr = vcn_v1_0_jpeg_ring_get_rptr,
.get_wptr = vcn_v1_0_jpeg_ring_get_wptr,
.set_wptr = vcn_v1_0_jpeg_ring_set_wptr,
.emit_frame_size =
6 + 6 + /* hdp invalidate / flush */
SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 +
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 +
8 + /* vcn_v1_0_dec_ring_emit_vm_flush */
14 + 14 + /* vcn_v1_0_dec_ring_emit_fence x2 vm fence */
6,
.emit_ib_size = 22, /* vcn_v1_0_dec_ring_emit_ib */
.emit_ib = vcn_v1_0_jpeg_ring_emit_ib,
.emit_fence = vcn_v1_0_jpeg_ring_emit_fence,
.emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush,
.test_ring = amdgpu_vcn_jpeg_ring_test_ring,
.test_ib = amdgpu_vcn_jpeg_ring_test_ib,
.insert_nop = vcn_v1_0_jpeg_ring_nop,
.insert_start = vcn_v1_0_jpeg_ring_insert_start,
.insert_end = vcn_v1_0_jpeg_ring_insert_end,
.pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vcn_ring_begin_use,
.end_use = amdgpu_vcn_ring_end_use,
.emit_wreg = vcn_v1_0_jpeg_ring_emit_wreg,
.emit_reg_wait = vcn_v1_0_jpeg_ring_emit_reg_wait,
};
static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev)
{
adev->vcn.ring_dec.funcs = &vcn_v1_0_dec_ring_vm_funcs;
......@@ -1289,6 +1740,12 @@ static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev)
DRM_INFO("VCN encode is enabled in VM mode\n");
}
static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev)
{
adev->vcn.ring_jpeg.funcs = &vcn_v1_0_jpeg_ring_vm_funcs;
DRM_INFO("VCN jpeg decode is enabled in VM mode\n");
}
static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = {
.set = vcn_v1_0_set_interrupt_state,
.process = vcn_v1_0_process_interrupt,
......
......@@ -9,19 +9,10 @@ config DRM_AMD_DC
support for AMDGPU. This adds required support for Vega and
Raven ASICs.
config DRM_AMD_DC_FBC
bool "AMD FBC - Enable Frame Buffer Compression"
depends on DRM_AMD_DC
help
Choose this option if you want to use frame buffer compression
support.
This is a power optimisation feature, check its availability
on your hardware before enabling this option.
config DRM_AMD_DC_DCN1_0
bool "DCN 1.0 Raven family"
depends on DRM_AMD_DC && X86
default y
help
Choose this option if you want to have
RV family for display engine
......
......@@ -347,7 +347,6 @@ static void hotplug_notify_work_func(struct work_struct *work)
drm_kms_helper_hotplug_event(dev);
}
#if defined(CONFIG_DRM_AMD_DC_FBC)
/* Allocate memory for FBC compressed data */
static void amdgpu_dm_fbc_init(struct drm_connector *connector)
{
......@@ -388,7 +387,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
}
}
#endif
/* Init display KMS
......@@ -3426,12 +3424,15 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
struct edid *edid = amdgpu_dm_connector->edid;
encoder = helper->best_encoder(connector);
amdgpu_dm_connector_ddc_get_modes(connector, edid);
amdgpu_dm_connector_add_common_modes(encoder, connector);
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (!edid || !drm_edid_is_valid(edid)) {
drm_add_modes_noedid(connector, 640, 480);
} else {
amdgpu_dm_connector_ddc_get_modes(connector, edid);
amdgpu_dm_connector_add_common_modes(encoder, connector);
}
amdgpu_dm_fbc_init(connector);
#endif
return amdgpu_dm_connector->num_modes;
}
......
......@@ -72,13 +72,11 @@ struct irq_list_head {
struct work_struct work;
};
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info {
void *cpu_addr;
struct amdgpu_bo *bo_ptr;
uint64_t gpu_addr;
};
#endif
struct amdgpu_display_manager {
......@@ -129,9 +127,8 @@ struct amdgpu_display_manager {
* Caches device atomic state for suspend/resume
*/
struct drm_atomic_state *cached_state;
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info compressor;
#endif
};
struct amdgpu_dm_connector {
......
......@@ -497,6 +497,34 @@ enum dc_edid_status dm_helpers_read_local_edid(
DRM_ERROR("EDID err: %d, on connector: %s",
edid_status,
aconnector->base.name);
if (link->aux_mode) {
union test_request test_request = {0};
union test_response test_response = {0};
dm_helpers_dp_read_dpcd(ctx,
link,
DP_TEST_REQUEST,
&test_request.raw,
sizeof(union test_request));
if (!test_request.bits.EDID_READ)
return edid_status;
test_response.bits.EDID_CHECKSUM_WRITE = 1;
dm_helpers_dp_write_dpcd(ctx,
link,
DP_TEST_EDID_CHECKSUM,
&sink->dc_edid.raw_edid[sink->dc_edid.length-1],
1);
dm_helpers_dp_write_dpcd(ctx,
link,
DP_TEST_RESPONSE,
&test_response.raw,
sizeof(test_response));
}
return edid_status;
}
......
......@@ -35,14 +35,6 @@
#include "amdgpu_dm_irq.h"
#include "amdgpu_pm.h"
unsigned long long dm_get_timestamp(struct dc_context *ctx)
{
struct timespec64 time;
getrawmonotonic64(&time);
return timespec64_to_ns(&time);
}
unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx,
unsigned long long current_time_stamp,
unsigned long long last_time_stamp)
......
......@@ -78,6 +78,8 @@ void dc_conn_log(struct dc_context *ctx,
if (i == NUM_ELEMENTS(signal_type_info_tbl))
goto fail;
dm_logger_append_heading(&entry);
dm_logger_append(&entry, "[%s][ConnIdx:%d] ",
signal_type_info_tbl[i].name,
link->link_index);
......
......@@ -32,8 +32,9 @@
static const struct dc_log_type_info log_type_info_tbl[] = {
{LOG_ERROR, "Error"},
{LOG_WARNING, "Warning"},
{LOG_DEBUG, "Debug"},
{LOG_DEBUG, "Debug"},
{LOG_DC, "DC_Interface"},
{LOG_DTN, "DTN"},
{LOG_SURFACE, "Surface"},
{LOG_HW_HOTPLUG, "HW_Hotplug"},
{LOG_HW_LINK_TRAINING, "HW_LKTN"},
......@@ -60,7 +61,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = {
{LOG_EVENT_LINK_LOSS, "LinkLoss"},
{LOG_EVENT_UNDERFLOW, "Underflow"},
{LOG_IF_TRACE, "InterfaceTrace"},
{LOG_DTN, "DTN"},
{LOG_PERF_TRACE, "PerfTrace"},
{LOG_DISPLAYSTATS, "DisplayStats"}
};
......@@ -128,8 +129,45 @@ uint32_t dal_logger_destroy(struct dal_logger **logger)
}
/* ------------------------------------------------------------------------ */
void dm_logger_append_heading(struct log_entry *entry)
{
int j;
for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) {
const struct dc_log_type_info *info = &log_type_info_tbl[j];
if (info->type == entry->type)
dm_logger_append(entry, "[%s]\t", info->name);
}
}
/* Print everything unread existing in log_buffer to debug console*/
void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn)
{
char *string_start = &logger->log_buffer[logger->buffer_read_offset];
if (should_warn)
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (logger->buffer_read_offset < logger->buffer_write_offset) {
if (logger->log_buffer[logger->buffer_read_offset] == '\0') {
dm_output_to_console("%s", string_start);
string_start = logger->log_buffer + logger->buffer_read_offset + 1;
}
logger->buffer_read_offset++;
}
if (should_warn)
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
}
/* ------------------------------------------------------------------------ */
/* Warning: Be careful that 'msg' is null terminated and the total size is
* less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0'
*/
static bool dal_logger_should_log(
struct dal_logger *logger,
enum dc_log_type log_type)
......@@ -159,26 +197,6 @@ static void log_to_debug_console(struct log_entry *entry)
}
}
/* Print everything unread existing in log_buffer to debug console*/
void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn)
{
char *string_start = &logger->log_buffer[logger->buffer_read_offset];
if (should_warn)
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (logger->buffer_read_offset < logger->buffer_write_offset) {
if (logger->log_buffer[logger->buffer_read_offset] == '\0') {
dm_output_to_console("%s", string_start);
string_start = logger->log_buffer + logger->buffer_read_offset + 1;
}
logger->buffer_read_offset++;
}
if (should_warn)
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
}
static void log_to_internal_buffer(struct log_entry *entry)
{
......@@ -229,19 +247,6 @@ static void log_to_internal_buffer(struct log_entry *entry)
}
}
static void log_heading(struct log_entry *entry)
{
int j;
for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) {
const struct dc_log_type_info *info = &log_type_info_tbl[j];
if (info->type == entry->type)
dm_logger_append(entry, "[%s]\t", info->name);
}
}
static void append_entry(
struct log_entry *entry,
char *buffer,
......@@ -259,11 +264,7 @@ static void append_entry(
entry->buf_offset += buf_size;
}
/* ------------------------------------------------------------------------ */
/* Warning: Be careful that 'msg' is null terminated and the total size is
* less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0'
*/
void dm_logger_write(
struct dal_logger *logger,
enum dc_log_type log_type,
......@@ -287,7 +288,7 @@ void dm_logger_write(
entry.type = log_type;
log_heading(&entry);
dm_logger_append_heading(&entry);
size = dm_log_to_buffer(
buffer, LOG_MAX_LINE_SIZE - 1, msg, args);
......@@ -372,7 +373,7 @@ void dm_logger_open(
logger->open_count++;
log_heading(entry);
dm_logger_append_heading(entry);
}
void dm_logger_close(struct log_entry *entry)
......
......@@ -169,6 +169,22 @@ static bool create_links(
return false;
}
/**
*****************************************************************************
* Function: dc_stream_adjust_vmin_vmax
*
* @brief
* Looks up the pipe context of dc_stream_state and updates the
* vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
* Rate, which is a power-saving feature that targets reducing panel
* refresh rate while the screen is static
*
* @param [in] dc: dc reference
* @param [in] stream: Initial dc stream state
* @param [in] adjust: Updated parameters for vertical_total_min and
* vertical_total_max
*****************************************************************************
*/
bool dc_stream_adjust_vmin_vmax(struct dc *dc,
struct dc_stream_state **streams, int num_streams,
int vmin, int vmax)
......@@ -465,6 +481,7 @@ static bool construct(struct dc *dc,
dc_ctx->driver_context = init_params->driver;
dc_ctx->dc = dc;
dc_ctx->asic_id = init_params->asic_id;
dc_ctx->dc_sink_id_count = 0;
dc->ctx = dc_ctx;
dc->current_state = dc_create_state();
......@@ -1548,7 +1565,7 @@ struct dc_sink *dc_link_add_remote_sink(
struct dc_sink *dc_sink;
enum dc_edid_status edid_status;
if (len > MAX_EDID_BUFFER_SIZE) {
if (len > DC_MAX_EDID_BUFFER_SIZE) {
dm_error("Max EDID buffer size breached!\n");
return NULL;
}
......
......@@ -1861,28 +1861,6 @@ static enum dc_status enable_link(
break;
}
if (pipe_ctx->stream_res.audio && status == DC_OK) {
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
/* notify audio driver for audio modes of monitor */
struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu;
unsigned int i, num_audio = 1;
for (i = 0; i < MAX_PIPES; i++) {
/*current_state not updated yet*/
if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
num_audio++;
}
pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL)
/*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
pp_smu->set_pme_wa_enable(&pp_smu->pp_smu);
/* un-mute audio */
/* TODO: audio should be per stream rather than per link */
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, false);
}
return status;
}
......@@ -2415,6 +2393,8 @@ void core_link_enable_stream(
}
}
core_dc->hwss.enable_audio_stream(pipe_ctx);
/* turn off otg test pattern if enable */
pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
......@@ -2453,6 +2433,22 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
core_dc->hwss.set_avmute(pipe_ctx, enable);
}
/**
*****************************************************************************
* Function: dc_link_enable_hpd_filter
*
* @brief
* If enable is true, programs HPD filter on associated HPD line using
* delay_on_disconnect/delay_on_connect values dependent on
* link->connector_signal
*
* If enable is false, programs HPD filter on associated HPD line with no
* delays on connect or disconnect
*
* @param [in] link: pointer to the dc link
* @param [in] enable: boolean specifying whether to enable hbd
*****************************************************************************
*/
void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
{
struct gpio *hpd;
......
......@@ -1647,22 +1647,26 @@ static enum dc_status read_hpd_rx_irq_data(
irq_data->raw,
sizeof(union hpd_irq_data));
else {
/* Read 2 bytes at this location,... */
/* Read 14 bytes in a single read and then copy only the required fields.
* This is more efficient than doing it in two separate AUX reads. */
uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
retval = core_link_read_dpcd(
link,
DP_SINK_COUNT_ESI,
irq_data->raw,
2);
tmp,
sizeof(tmp));
if (retval != DC_OK)
return retval;
/* ... then read remaining 4 at the other location */
retval = core_link_read_dpcd(
link,
DP_LANE0_1_STATUS_ESI,
&irq_data->raw[2],
4);
irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
}
return retval;
......@@ -2305,6 +2309,7 @@ static bool retrieve_link_cap(struct dc_link *link)
{
uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1];
struct dp_device_vendor_id sink_id;
union down_stream_port_count down_strm_port_count;
union edp_configuration_cap edp_config_cap;
union dp_downstream_port_present ds_port = { 0 };
......@@ -2391,6 +2396,17 @@ static bool retrieve_link_cap(struct dc_link *link)
&link->dpcd_caps.sink_count.raw,
sizeof(link->dpcd_caps.sink_count.raw));
/* read sink ieee oui */
core_link_read_dpcd(link,
DP_SINK_OUI,
(uint8_t *)(&sink_id),
sizeof(sink_id));
link->dpcd_caps.sink_dev_id =
(sink_id.ieee_oui[0] << 16) +
(sink_id.ieee_oui[1] << 8) +
(sink_id.ieee_oui[2]);
/* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
......
......@@ -53,6 +53,10 @@ static bool construct(struct dc_sink *sink, const struct dc_sink_init_data *init
sink->dongle_max_pix_clk = init_params->dongle_max_pix_clk;
sink->converter_disable_audio = init_params->converter_disable_audio;
sink->dc_container_id = NULL;
sink->sink_id = init_params->link->ctx->dc_sink_id_count;
// increment dc_sink_id_count because we don't want two sinks with same ID
// unless they are actually the same
init_params->link->ctx->dc_sink_id_count++;
return true;
}
......
......@@ -84,6 +84,17 @@ struct dc_plane_state *dc_create_plane_state(struct dc *dc)
return plane_state;
}
/**
*****************************************************************************
* Function: dc_plane_get_status
*
* @brief
* Looks up the pipe context of plane_state and updates the pending status
* of the pipe context. Then returns plane_state->status
*
* @param [in] plane_state: pointer to the plane_state to get the status of
*****************************************************************************
*/
const struct dc_plane_status *dc_plane_get_status(
const struct dc_plane_state *plane_state)
{
......
此差异已折叠。
......@@ -430,7 +430,7 @@ union test_request {
struct {
uint8_t LINK_TRAINING :1;
uint8_t LINK_TEST_PATTRN :1;
uint8_t EDID_REAT :1;
uint8_t EDID_READ :1;
uint8_t PHY_TEST_PATTERN :1;
uint8_t AUDIO_TEST_PATTERN :1;
uint8_t RESERVED :1;
......@@ -443,7 +443,8 @@ union test_response {
struct {
uint8_t ACK :1;
uint8_t NO_ACK :1;
uint8_t RESERVED :6;
uint8_t EDID_CHECKSUM_WRITE:1;
uint8_t RESERVED :5;
} bits;
uint8_t raw;
};
......
......@@ -59,6 +59,9 @@ struct dc_stream_state {
struct freesync_context freesync_ctx;
struct dc_info_packet hdr_static_metadata;
PHYSICAL_ADDRESS_LOC dmdata_address;
bool use_dynamic_meta;
struct dc_transfer_func *out_transfer_func;
struct colorspace_transform gamut_remap_matrix;
struct dc_csc_transform csc_color_matrix;
......@@ -299,9 +302,4 @@ bool dc_stream_get_crtc_position(struct dc *dc,
unsigned int *v_pos,
unsigned int *nom_v_pos);
void dc_stream_set_static_screen_events(struct dc *dc,
struct dc_stream_state **stream,
int num_streams,
const struct dc_static_screen_events *events);
#endif /* DC_STREAM_H_ */
......@@ -507,4 +507,8 @@ bool optc1_is_optc_underflow_occurred(struct timing_generator *optc);
void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable);
bool optc1_get_otg_active_size(struct timing_generator *optc,
uint32_t *otg_active_width,
uint32_t *otg_active_height);
#endif /* __DC_TIMING_GENERATOR_DCN10_H__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册