Add doorbell layout and field descriptions together with common helpers to build and program nbio doorbell entries.
Signed-off-by: Hawking Zhang <[email protected]> Reviewed-by: Likun Gao <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.c | 142 +++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h | 79 +++++++++++++ 2 files changed, 221 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.c index e4c8e98725f0..70b63fd3656f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.c @@ -21,6 +21,7 @@ #include "amdgpu.h" #include "amdgpu_ras.h" +#include "soc15_common.h" int amdgpu_nbio_ras_sw_init(struct amdgpu_device *adev) { @@ -94,3 +95,144 @@ void amdgpu_nbio_program_aspm(struct amdgpu_device *adev) if (adev->nbio.funcs->program_aspm) adev->nbio.funcs->program_aspm(adev); } + +static int amdgpu_nbio_set_doorbell_field(u32 *reg, u32 mask, u32 value) +{ + u32 shift; + + if (!mask) + return value ? -EOPNOTSUPP : 0; + + shift = __ffs(mask); + if (value > (mask >> shift)) + return -ERANGE; + + *reg |= (value << shift) & mask; + return 0; +} + +int amdgpu_nbio_build_doorbell_entry( + struct amdgpu_device *adev, + const struct amdgpu_nbio_doorbell_fields *fields, + u32 *ctrl, u32 *ctrl1) +{ + const struct amdgpu_nbio_doorbell_layout *layout; + int r; + + if (!fields || !ctrl) + return -EINVAL; + + layout = adev->nbio.doorbell_layout; + if (!layout) + return -EINVAL; + + *ctrl = 0; + if (ctrl1) + *ctrl1 = 0; + + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.enable, + fields->enable); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.awid, + fields->awid); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.fence_enable, + fields->fence_enable); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.range_offset, + fields->range_offset); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.range_size, + fields->range_size); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.disable_64bit, + fields->disable_64bit); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, + layout->ctrl.deduct_range_offset, + fields->deduct_range_offset); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.drop, + fields->drop); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl, layout->ctrl.awaddr_31_28, + fields->awaddr_31_28); + if (r) + return r; + + if (!ctrl1) + return 0; + if (!layout->has_ctrl1) + return -EOPNOTSUPP; + + r = amdgpu_nbio_set_doorbell_field(ctrl1, + layout->ctrl1.target_port_type, + fields->target_port_type); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl1, + layout->ctrl1.target_die_id, + fields->target_die_id); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl1, + layout->ctrl1.target_port_id, + fields->target_port_id); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl1, + layout->ctrl1.override_poison_data, + fields->override_poison_data); + if (r) + return r; + r = amdgpu_nbio_set_doorbell_field(ctrl1, + layout->ctrl1.disable_4k_page_decode, + fields->disable_4k_page_decode); + if (r) + return r; + + return 0; +} + +void amdgpu_nbio_program_doorbell_entry( + struct amdgpu_device *adev, + enum amdgpu_nbio_doorbell_client client, + u32 instance, const u32 *ctrl, const u32 *ctrl1) +{ + struct amdgpu_nbio_doorbell_entries *entries; + struct amdgpu_nbio_doorbell_entry *entry; + + if (WARN_ON_ONCE(client >= AMDGPU_NBIO_DOORBELL_CLIENT_COUNT)) + return; + + entries = &adev->nbio.doorbell_entries[client]; + if (WARN_ON_ONCE(instance >= entries->num_entries)) + return; + + entry = &entries->entry[instance]; + if (WARN_ON_ONCE(!entry->ctrl_reg)) + return; + + /* A NULL CTRL disables and clears the entry. */ + if (!ctrl) { + WREG32_SOC15_IP(NBIO, entry->ctrl_reg, 0); + if (entry->ctrl1_reg) + WREG32_SOC15_IP(NBIO, entry->ctrl1_reg, 0); + return; + } + + if (WARN_ON_ONCE(ctrl1 && !entry->ctrl1_reg)) + return; + + WREG32_SOC15_IP(NBIO, entry->ctrl_reg, *ctrl); + if (ctrl1) + WREG32_SOC15_IP(NBIO, entry->ctrl1_reg, *ctrl1); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h index a61f3a6e8ec7..2ac392934169 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h @@ -55,6 +55,73 @@ struct amdgpu_nbio_ras { int (*init_ras_err_event_athub_interrupt)(struct amdgpu_device *adev); }; +enum amdgpu_nbio_doorbell_client { + AMDGPU_NBIO_DOORBELL_CLIENT_CP, + AMDGPU_NBIO_DOORBELL_CLIENT_IH, + AMDGPU_NBIO_DOORBELL_CLIENT_SDMA, + AMDGPU_NBIO_DOORBELL_CLIENT_RLC, + AMDGPU_NBIO_DOORBELL_CLIENT_VCN, + AMDGPU_NBIO_DOORBELL_CLIENT_VPE, + AMDGPU_NBIO_DOORBELL_CLIENT_COUNT, +}; + +struct amdgpu_nbio_doorbell_ctrl_layout { + u32 enable; + u32 awid; + u32 fence_enable; + u32 range_offset; + u32 range_size; + u32 disable_64bit; + u32 deduct_range_offset; + u32 drop; + u32 awaddr_31_28; +}; + +struct amdgpu_nbio_doorbell_ctrl1_layout { + u32 target_port_type; + u32 target_die_id; + u32 target_port_id; + u32 override_poison_data; + u32 disable_4k_page_decode; +}; + +struct amdgpu_nbio_doorbell_layout { + struct amdgpu_nbio_doorbell_ctrl_layout ctrl; + struct amdgpu_nbio_doorbell_ctrl1_layout ctrl1; + bool has_ctrl1; +}; + +struct amdgpu_nbio_doorbell_fields { + bool enable; + u32 awid; + u32 range_offset; + u32 range_size; + u32 awaddr_31_28; + u32 target_port_type; + u32 target_die_id; + u32 target_port_id; + bool fence_enable; + bool disable_64bit; + bool deduct_range_offset; + bool drop; + bool override_poison_data; + bool disable_4k_page_decode; +}; + +#define AMDGPU_NBIO_MAX_DOORBELL_INSTANCES 16 + +struct amdgpu_nbio_doorbell_entry { + u32 port; + u32 ctrl_reg; + u32 ctrl1_reg; +}; + +struct amdgpu_nbio_doorbell_entries { + u32 num_entries; + struct amdgpu_nbio_doorbell_entry + entry[AMDGPU_NBIO_MAX_DOORBELL_INSTANCES]; +}; + struct amdgpu_nbio_funcs { const struct nbio_hdp_flush_reg *hdp_flush_reg; u32 (*get_hdp_flush_req_offset)(struct amdgpu_device *adev); @@ -113,6 +180,9 @@ struct amdgpu_nbio { struct ras_common_if *ras_if; const struct amdgpu_nbio_funcs *funcs; struct amdgpu_nbio_ras *ras; + const struct amdgpu_nbio_doorbell_layout *doorbell_layout; + struct amdgpu_nbio_doorbell_entries + doorbell_entries[AMDGPU_NBIO_DOORBELL_CLIENT_COUNT]; }; int amdgpu_nbio_ras_sw_init(struct amdgpu_device *adev); @@ -123,4 +193,13 @@ bool amdgpu_nbio_is_replay_cnt_supported(struct amdgpu_device *adev); void amdgpu_nbio_program_aspm(struct amdgpu_device *adev); +int amdgpu_nbio_build_doorbell_entry( + struct amdgpu_device *adev, + const struct amdgpu_nbio_doorbell_fields *fields, + u32 *ctrl, u32 *ctrl1); +void amdgpu_nbio_program_doorbell_entry( + struct amdgpu_device *adev, + enum amdgpu_nbio_doorbell_client client, + u32 instance, const u32 *ctrl, const u32 *ctrl1); + #endif -- 2.17.1
