Re: [PATCH] drm/amd/display: Enabling eDP no power sequencing with DAL feature mask
[Public] >From: Liu, Zhan >Sent: Monday, June 21, 2021 9:13 PM >To: amd-gfx@lists.freedesktop.org ; Cornij, >Nikola >Cc: Liu, Charlene >Subject: [PATCH] drm/amd/display: Enabling eDP no power sequencing with DAL >feature mask > >[Public] > >[Why] >Sometimes, DP receiver chip power-controlled externally by an >Embedded Controller could be treated and used as eDP, >if it drives mobile display. In this case, >we shouldn't be doing power-sequencing, hence we can skip >waiting for T7-ready and T9-ready." > >[How] >Added a feature mask to enable eDP no power sequencing feature. > >To enable this, set 0x10 flag in amdgpu.dcfeaturemask on >Linux command line. > >Signed-off-by: Zhan Liu Reviewed-by: Nikola Cornij >Change-Id: I15e8fb2979fe3ff5491ccf1ee384693d4dce787c >--- > drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 + > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++ > drivers/gpu/drm/amd/display/dc/dc.h | 1 + > .../display/dc/dce110/dce110_hw_sequencer.c | 31 --- > drivers/gpu/drm/amd/include/amd_shared.h | 10 +++--- > 5 files changed, 38 insertions(+), 8 deletions(-) > >diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >index 3de1accb060e..b588cf4398db 100644 >--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >@@ -159,6 +159,7 @@ int amdgpu_smu_pptable_id = -1; > * highest. That helps saving some idle power. > * DISABLE_FRACTIONAL_PWM (bit 2) disabled by default > * PSR (bit 3) disabled by default >+ * EDP NO POWER SEQUENCING (bit 4) disabled by default > */ > uint amdgpu_dc_feature_mask = 2; > uint amdgpu_dc_debug_mask; >diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >index c0a3119982b0..abba26c8f20a 100644 >--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >@@ -1174,6 +1174,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) >if (amdgpu_dc_feature_mask & DC_DISABLE_FRACTIONAL_PWM_MASK) >init_data.flags.disable_fractional_pwm = true; > >+ if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING) >+ init_data.flags.edp_no_power_sequencing = true; >+ >init_data.flags.power_down_display_on_boot = true; > >INIT_LIST_HEAD(>dm.da_list); >diff --git a/drivers/gpu/drm/amd/display/dc/dc.h >b/drivers/gpu/drm/amd/display/dc/dc.h >index a70697898025..7f1d2d6f9de8 100644 >--- a/drivers/gpu/drm/amd/display/dc/dc.h >+++ b/drivers/gpu/drm/amd/display/dc/dc.h >@@ -297,6 +297,7 @@ struct dc_config { >bool allow_seamless_boot_optimization; >bool power_down_display_on_boot; >bool edp_not_connected; >+ bool edp_no_power_sequencing; >bool force_enum_edp; >bool forced_clocks; >bool allow_lttpr_non_transparent_mode; >diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c >b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c >index 53dd305fa6b0..013d94c9506a 100644 >--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c >+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c >@@ -1023,8 +1023,20 @@ void dce110_edp_backlight_control( >/* dc_service_sleep_in_milliseconds(50); */ >/*edp 1.2*/ >panel_instance = link->panel_cntl->inst; >- if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) >- edp_receiver_ready_T7(link); >+ >+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { >+ if (!link->dc->config.edp_no_power_sequencing) >+ /* >+* Sometimes, DP receiver chip power-controlled externally by >an >+* Embedded Controller could be treated and used as eDP, >+* if it drives mobile display. In this case, >+* we shouldn't be doing power-sequencing, hence we can skip >+* waiting for T7-ready. >+*/ >+ edp_receiver_ready_T7(link); >+ else >+ DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); >+ } > >if (ctx->dc->ctx->dmub_srv && >ctx->dc->debug.dmub_command_table) { >@@ -1049,8 +1061,19 @@ void dce110_edp_backlight_control( >dc_link_backlight_enable_aux(link, enable); > >/*edp 1.2*/ >- if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) >- edp_add_delay_for_T9(link); >+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { >+ if (!link->dc->config.edp_no_power_sequencing) >+ /* >+* Sometimes, DP receiver chip power-controlled externally by >an >+* Embedded Controller could be treated and used as eDP, >+* if it drives mobile display. In this case, >+* we shouldn't be doing
[PATCH] drm/amd/display: Enabling eDP no power sequencing with DAL feature mask
[Public] [Why] Sometimes, DP receiver chip power-controlled externally by an Embedded Controller could be treated and used as eDP, if it drives mobile display. In this case, we shouldn't be doing power-sequencing, hence we can skip waiting for T7-ready and T9-ready." [How] Added a feature mask to enable eDP no power sequencing feature. To enable this, set 0x10 flag in amdgpu.dcfeaturemask on Linux command line. Signed-off-by: Zhan Liu Change-Id: I15e8fb2979fe3ff5491ccf1ee384693d4dce787c --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++ drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../display/dc/dce110/dce110_hw_sequencer.c | 31 --- drivers/gpu/drm/amd/include/amd_shared.h | 10 +++--- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 3de1accb060e..b588cf4398db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -159,6 +159,7 @@ int amdgpu_smu_pptable_id = -1; * highest. That helps saving some idle power. * DISABLE_FRACTIONAL_PWM (bit 2) disabled by default * PSR (bit 3) disabled by default + * EDP NO POWER SEQUENCING (bit 4) disabled by default */ uint amdgpu_dc_feature_mask = 2; uint amdgpu_dc_debug_mask; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c0a3119982b0..abba26c8f20a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1174,6 +1174,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_feature_mask & DC_DISABLE_FRACTIONAL_PWM_MASK) init_data.flags.disable_fractional_pwm = true; + if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING) + init_data.flags.edp_no_power_sequencing = true; + init_data.flags.power_down_display_on_boot = true; INIT_LIST_HEAD(>dm.da_list); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index a70697898025..7f1d2d6f9de8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -297,6 +297,7 @@ struct dc_config { bool allow_seamless_boot_optimization; bool power_down_display_on_boot; bool edp_not_connected; + bool edp_no_power_sequencing; bool force_enum_edp; bool forced_clocks; bool allow_lttpr_non_transparent_mode; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 53dd305fa6b0..013d94c9506a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1023,8 +1023,20 @@ void dce110_edp_backlight_control( /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ panel_instance = link->panel_cntl->inst; - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) - edp_receiver_ready_T7(link); + + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { + if (!link->dc->config.edp_no_power_sequencing) + /* +* Sometimes, DP receiver chip power-controlled externally by an +* Embedded Controller could be treated and used as eDP, +* if it drives mobile display. In this case, +* we shouldn't be doing power-sequencing, hence we can skip +* waiting for T7-ready. +*/ + edp_receiver_ready_T7(link); + else + DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); + } if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { @@ -1049,8 +1061,19 @@ void dce110_edp_backlight_control( dc_link_backlight_enable_aux(link, enable); /*edp 1.2*/ - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) - edp_add_delay_for_T9(link); + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { + if (!link->dc->config.edp_no_power_sequencing) + /* +* Sometimes, DP receiver chip power-controlled externally by an +* Embedded Controller could be treated and used as eDP, +* if it drives mobile display. In this case, +* we shouldn't be doing power-sequencing, hence we can skip +* waiting for T9-ready. +*/ + edp_add_delay_for_T9(link); + else + DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); + } if (!enable && link->dpcd_sink_ext_caps.bits.oled) msleep(OLED_PRE_T11_DELAY); diff --git
Re: [PATCH 10/10] drm/amdkfd: protect svm_bo ref in case prange has forked
On 2021-06-21 12:04 p.m., Alex Sierra wrote: Keep track of all the pages inside of pranges referenced to the same svm_bo. This description is a bit confusing because you're not tracking page references but BO references. This is done, by using the ref count inside this object. This makes sure the object has freed after the last prange is not longer at any GPU. Including references shared between a parent and child during a fork. References to the BO are not really shared between parent and child processes. They share page references. What we're doing here is, we're removing assumptions about the lifetime of the svm_bo by tying it to the lifetime of any pages referencing it. I'd suggest this description: drm/amdkfd: Maintain svm_bo reference in page->zone_device_data Each zone-device page holds a reference to the SVM BO that manages its backing storage. This is necessary to correctly hold on to the BO in case zone_device pages are shared with a child-process. Signed-off-by: Alex Sierra Change-Id: Ibfe5efbfed28c2d7681fe091264a5d0d5f3657b2 Please remove the Change-Id. --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 10 -- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 10 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 10 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index acb9f64577a0..c8ca3252cbc2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -245,7 +245,7 @@ svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn) struct page *page; page = pfn_to_page(pfn); - page->zone_device_data = prange; + page->zone_device_data = prange->svm_bo; get_page(page); lock_page(page); } @@ -336,6 +336,7 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, svm_migrate_get_vram_page(prange, migrate->dst[i]); migrate->dst[i] = migrate_pfn(migrate->dst[i]); migrate->dst[i] |= MIGRATE_PFN_LOCKED; + svm_range_bo_ref(prange->svm_bo); It would be cleaner to move this into svm_migrate_get_vram_page, where you assign the prange->svm_bo reference to page->zonde_device_data. Regards, Felix } if (migrate->dst[i] & MIGRATE_PFN_VALID) { spage = migrate_pfn_to_page(migrate->src[i]); @@ -540,7 +541,12 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, static void svm_migrate_page_free(struct page *page) { - /* Keep this function to avoid warning */ + struct svm_range_bo *svm_bo = page->zone_device_data; + + if (svm_bo) { + pr_debug("svm_bo ref left: %d\n", kref_read(_bo->kref)); + svm_range_bo_unref(svm_bo); + } } static int diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index ebc1ae7e5193..4b5fc2375641 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -309,14 +309,6 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo) return true; } -static struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) -{ - if (svm_bo) - kref_get(_bo->kref); - - return svm_bo; -} - static void svm_range_bo_release(struct kref *kref) { struct svm_range_bo *svm_bo; @@ -355,7 +347,7 @@ static void svm_range_bo_release(struct kref *kref) kfree(svm_bo); } -static void svm_range_bo_unref(struct svm_range_bo *svm_bo) +void svm_range_bo_unref(struct svm_range_bo *svm_bo) { if (!svm_bo) return; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 27fbe1936493..21f693767a0d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -150,6 +150,14 @@ static inline void svm_range_unlock(struct svm_range *prange) mutex_unlock(>lock); } +static inline struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) +{ + if (svm_bo) + kref_get(_bo->kref); + + return svm_bo; +} + int svm_range_list_init(struct kfd_process *p); void svm_range_list_fini(struct kfd_process *p); int svm_ioctl(struct kfd_process *p, enum kfd_ioctl_svm_op op, uint64_t start, @@ -178,7 +186,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, void svm_range_free_dma_mappings(struct svm_range *prange); void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, void *owner); - +void svm_range_bo_unref(struct svm_range_bo *svm_bo); #else struct kfd_process; ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org
[pull] amdgpu drm-fixes-5.13
Hi Dave, Daniel, Last minute fixes for 5.13. The following changes since commit 13311e74253fe64329390df80bed3f07314ddd61: Linux 5.13-rc7 (2021-06-20 15:03:15 -0700) are available in the Git repository at: https://gitlab.freedesktop.org/agd5f/linux.git tags/amd-drm-fixes-5.13-2021-06-21 for you to fetch changes up to ee5468b9f1d3bf48082eed351dace14598e8ca39: Revert "drm/amdgpu/gfx9: fix the doorbell missing when in CGPG issue." (2021-06-21 17:22:52 -0400) amd-drm-fixes-5.13-2021-06-21: amdgpu: - Revert GFX9, 10 doorbell fixes, we just end up trading one bug for another - Potential memory corruption fix in framebuffer handling Michel Dänzer (1): drm/amdgpu: Call drm_framebuffer_init last for framebuffer init Yifan Zhang (2): Revert "drm/amdgpu/gfx10: enlarge CP_MEC_DOORBELL_RANGE_UPPER to cover full doorbell." Revert "drm/amdgpu/gfx9: fix the doorbell missing when in CGPG issue." drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 12 +++- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 6 +- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 6 +- 3 files changed, 9 insertions(+), 15 deletions(-) ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 10:24:16PM +0300, Oded Gabbay wrote: > Another thing I want to emphasize is that we are doing p2p only > through the export/import of the FD. We do *not* allow the user to > mmap the dma-buf as we do not support direct IO. So there is no access > to these pages through the userspace. Arguably mmaping the memory is a better choice, and is the direction that Logan's series goes in. Here the use of DMABUF was specifically designed to allow hitless revokation of the memory, which this isn't even using. So you are taking the hit of very limited hardware support and reduced performance just to squeeze into DMABUF.. Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH] drm/amdgpu/display: fold DRM_AMD_DC_DCN3_1 into DRM_AMD_DC_DCN
On 2021-06-21 4:58 p.m., Alex Deucher wrote: No need for a separate flag now that DCN3.1 is not in bring up. Fold into DRM_AMD_DC_DCN like previous DCN IPs. Signed-off-by: Alex Deucher Reviewed-by: Nicholas Kazlauskas Regards, Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/Kconfig | 7 -- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 22 +-- .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c| 4 drivers/gpu/drm/amd/display/dc/Makefile | 2 -- .../drm/amd/display/dc/bios/bios_parser2.c| 7 +- .../display/dc/bios/command_table_helper2.c | 6 + .../gpu/drm/amd/display/dc/clk_mgr/Makefile | 2 -- .../gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c | 7 -- .../display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c | 2 -- drivers/gpu/drm/amd/display/dc/core/dc.c | 8 +++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 6 ++--- .../gpu/drm/amd/display/dc/core/dc_resource.c | 10 ++--- .../gpu/drm/amd/display/dc/core/dc_stream.c | 4 drivers/gpu/drm/amd/display/dc/dc.h | 14 +--- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 3 +-- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 3 +-- .../gpu/drm/amd/display/dc/dce/dce_hwseq.h| 6 - .../display/dc/dce110/dce110_hw_sequencer.c | 4 ++-- .../drm/amd/display/dc/dcn10/dcn10_hubbub.h | 9 +--- .../amd/display/dc/dcn10/dcn10_link_encoder.h | 9 +--- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 8 --- .../drm/amd/display/dc/dcn20/dcn20_hubbub.h | 2 -- .../gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h | 10 - .../drm/amd/display/dc/dcn20/dcn20_hwseq.c| 19 +++- .../drm/amd/display/dc/dcn20/dcn20_resource.c | 16 -- .../drm/amd/display/dc/dcn30/dcn30_hwseq.c| 2 -- .../drm/amd/display/dc/dcn31/dcn31_hwseq.c| 2 -- drivers/gpu/drm/amd/display/dc/dm_cp_psp.h| 2 -- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 - .../dc/dml/dcn31/display_mode_vba_31.c| 2 -- .../dc/dml/dcn31/display_rq_dlg_calc_31.c | 3 --- .../drm/amd/display/dc/dml/display_mode_lib.c | 9 ++-- .../drm/amd/display/dc/dml/display_mode_lib.h | 2 -- .../amd/display/dc/dml/display_mode_structs.h | 4 .../drm/amd/display/dc/dml/display_mode_vba.c | 12 -- .../drm/amd/display/dc/dml/display_mode_vba.h | 6 - .../gpu/drm/amd/display/dc/gpio/hw_factory.c | 2 -- .../drm/amd/display/dc/gpio/hw_translate.c| 2 -- .../gpu/drm/amd/display/dc/inc/core_types.h | 6 - .../gpu/drm/amd/display/dc/inc/hw/clk_mgr.h | 2 -- drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 6 - .../gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 2 -- .../drm/amd/display/dc/inc/hw/link_encoder.h | 14 +--- .../gpu/drm/amd/display/dc/inc/hw/mem_input.h | 2 -- .../amd/display/dc/inc/hw/timing_generator.h | 2 -- .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 -- drivers/gpu/drm/amd/display/dc/irq/Makefile | 2 -- .../display/dc/irq/dcn31/irq_service_dcn31.h | 3 --- drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 8 --- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 14 +--- drivers/gpu/drm/amd/display/dmub/src/Makefile | 6 + .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 4 .../gpu/drm/amd/display/include/dal_asic_id.h | 2 -- .../gpu/drm/amd/display/include/dal_types.h | 2 -- .../drm/amd/display/modules/hdcp/hdcp_log.c | 2 -- .../drm/amd/display/modules/hdcp/hdcp_psp.c | 18 --- .../drm/amd/display/modules/hdcp/hdcp_psp.h | 13 ++- .../drm/amd/display/modules/inc/mod_hdcp.h| 10 - 58 files changed, 45 insertions(+), 319 deletions(-) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 5b5f36c80efb..7dffc04a557e 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -31,13 +31,6 @@ config DRM_AMD_DC_SI by default. This includes Tahiti, Pitcairn, Cape Verde, Oland. Hainan is not supported by AMD DC and it has no physical DCE6. -config DRM_AMD_DC_DCN3_1 -bool "DCN 3.1 family" -depends on DRM_AMD_DC_DCN -help -Choose this option if you want to have -DCN3.1 family support for display engine - config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d069661abe45..b5b5ccf0ed71 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -110,10 +110,8 @@ MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); #define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB); -#if
Re: [PATCH 08/10] drm/amdkfd: add invalid pages debug at vram migration
On 2021-06-21 12:04 p.m., Alex Sierra wrote: This is for debug purposes only. It conditionally generates partial migrations to test mixed CPU/GPU memory domain pages in a prange easily. Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 8a3f21d76915..f71f8d7e2b72 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -404,6 +404,20 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, } } +#ifdef DEBUG_FORCE_MIXED_DOMAINS + for (i = 0, j = 0; i < npages; i += 4, j++) { + if (j & 1) + continue; + svm_migrate_put_vram_page(adev, dst[i]); + migrate->dst[i] = 0; + svm_migrate_put_vram_page(adev, dst[i + 1]); + migrate->dst[i + 1] = 0; + svm_migrate_put_vram_page(adev, dst[i + 2]); + migrate->dst[i + 2] = 0; + svm_migrate_put_vram_page(adev, dst[i + 3]); + migrate->dst[i + 3] = 0; + } +#endif out: return r; } ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 07/10] drm/amdkfd: skip migration for pages already in VRAM
On 2021-06-21 12:04 p.m., Alex Sierra wrote: Migration skipped for pages that are already in VRAM domain. These could be the result of previous partial migrations to SYS RAM, and prefetch back to VRAM. Ex. Coherent pages in VRAM that were not written/invalidated after a copy-on-write. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 17 + 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 6fd68528c425..8a3f21d76915 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -329,14 +329,15 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, for (i = j = 0; i < npages; i++) { struct page *spage; - dst[i] = vram_addr + (j << PAGE_SHIFT); - migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); - svm_migrate_get_vram_page(prange, migrate->dst[i]); - - migrate->dst[i] = migrate_pfn(migrate->dst[i]); - migrate->dst[i] |= MIGRATE_PFN_LOCKED; - - if (migrate->src[i] & MIGRATE_PFN_VALID) { + spage = migrate_pfn_to_page(migrate->src[i]); + if (spage && !is_zone_device_page(spage)) { + dst[i] = vram_addr + (j << PAGE_SHIFT); + migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); + svm_migrate_get_vram_page(prange, migrate->dst[i]); + migrate->dst[i] = migrate_pfn(migrate->dst[i]); + migrate->dst[i] |= MIGRATE_PFN_LOCKED; + } + if (migrate->dst[i] & MIGRATE_PFN_VALID) { spage = migrate_pfn_to_page(migrate->src[i]); I think spage is already set correctly here. You shouldn't need to assign it again. Also, is this condition (migrate->dst[i] & MIGRATE_PFN_VALID) really needed? It seems to me, migrate_pfn sets that flag unconditionally. So you can just continue the previous if-block. Regards, Felix src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE, DMA_TO_DEVICE); ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amdgpu/display: fold DRM_AMD_DC_DCN3_1 into DRM_AMD_DC_DCN
No need for a separate flag now that DCN3.1 is not in bring up. Fold into DRM_AMD_DC_DCN like previous DCN IPs. Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Kconfig | 7 -- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 22 +-- .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c| 4 drivers/gpu/drm/amd/display/dc/Makefile | 2 -- .../drm/amd/display/dc/bios/bios_parser2.c| 7 +- .../display/dc/bios/command_table_helper2.c | 6 + .../gpu/drm/amd/display/dc/clk_mgr/Makefile | 2 -- .../gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c | 7 -- .../display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c | 2 -- drivers/gpu/drm/amd/display/dc/core/dc.c | 8 +++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 6 ++--- .../gpu/drm/amd/display/dc/core/dc_resource.c | 10 ++--- .../gpu/drm/amd/display/dc/core/dc_stream.c | 4 drivers/gpu/drm/amd/display/dc/dc.h | 14 +--- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 3 +-- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 3 +-- .../gpu/drm/amd/display/dc/dce/dce_hwseq.h| 6 - .../display/dc/dce110/dce110_hw_sequencer.c | 4 ++-- .../drm/amd/display/dc/dcn10/dcn10_hubbub.h | 9 +--- .../amd/display/dc/dcn10/dcn10_link_encoder.h | 9 +--- .../gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h | 8 --- .../drm/amd/display/dc/dcn20/dcn20_hubbub.h | 2 -- .../gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h | 10 - .../drm/amd/display/dc/dcn20/dcn20_hwseq.c| 19 +++- .../drm/amd/display/dc/dcn20/dcn20_resource.c | 16 -- .../drm/amd/display/dc/dcn30/dcn30_hwseq.c| 2 -- .../drm/amd/display/dc/dcn31/dcn31_hwseq.c| 2 -- drivers/gpu/drm/amd/display/dc/dm_cp_psp.h| 2 -- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 - .../dc/dml/dcn31/display_mode_vba_31.c| 2 -- .../dc/dml/dcn31/display_rq_dlg_calc_31.c | 3 --- .../drm/amd/display/dc/dml/display_mode_lib.c | 9 ++-- .../drm/amd/display/dc/dml/display_mode_lib.h | 2 -- .../amd/display/dc/dml/display_mode_structs.h | 4 .../drm/amd/display/dc/dml/display_mode_vba.c | 12 -- .../drm/amd/display/dc/dml/display_mode_vba.h | 6 - .../gpu/drm/amd/display/dc/gpio/hw_factory.c | 2 -- .../drm/amd/display/dc/gpio/hw_translate.c| 2 -- .../gpu/drm/amd/display/dc/inc/core_types.h | 6 - .../gpu/drm/amd/display/dc/inc/hw/clk_mgr.h | 2 -- drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 6 - .../gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 2 -- .../drm/amd/display/dc/inc/hw/link_encoder.h | 14 +--- .../gpu/drm/amd/display/dc/inc/hw/mem_input.h | 2 -- .../amd/display/dc/inc/hw/timing_generator.h | 2 -- .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 -- drivers/gpu/drm/amd/display/dc/irq/Makefile | 2 -- .../display/dc/irq/dcn31/irq_service_dcn31.h | 3 --- drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 8 --- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 14 +--- drivers/gpu/drm/amd/display/dmub/src/Makefile | 6 + .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 4 .../gpu/drm/amd/display/include/dal_asic_id.h | 2 -- .../gpu/drm/amd/display/include/dal_types.h | 2 -- .../drm/amd/display/modules/hdcp/hdcp_log.c | 2 -- .../drm/amd/display/modules/hdcp/hdcp_psp.c | 18 --- .../drm/amd/display/modules/hdcp/hdcp_psp.h | 13 ++- .../drm/amd/display/modules/inc/mod_hdcp.h| 10 - 58 files changed, 45 insertions(+), 319 deletions(-) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 5b5f36c80efb..7dffc04a557e 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -31,13 +31,6 @@ config DRM_AMD_DC_SI by default. This includes Tahiti, Pitcairn, Cape Verde, Oland. Hainan is not supported by AMD DC and it has no physical DCE6. -config DRM_AMD_DC_DCN3_1 -bool "DCN 3.1 family" -depends on DRM_AMD_DC_DCN -help -Choose this option if you want to have -DCN3.1 family support for display engine - config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d069661abe45..b5b5ccf0ed71 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -110,10 +110,8 @@ MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); #define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB); -#if defined(CONFIG_DRM_AMD_DC_DCN3_1) #define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB); -#endif #define FIRMWARE_RAVEN_DMCU
Re: [PATCH 05/10] drm/amdkfd: classify and map mixed svm range pages in GPU
On 2021-06-21 12:04 p.m., Alex Sierra wrote: [Why] svm ranges can have mixed pages from device or system memory. A good example is, after a prange has been allocated in VRAM and a copy-on-write is triggered by a fork. This invalidates some pages inside the prange. Endding up in mixed pages. [How] By classifying each page inside a prange, based on its type. Device or system memory, during dma mapping call. If page corresponds to VRAM domain, a flag is set to its dma_addr entry for each GPU. Then, at the GPU page table mapping. All group of contiguous pages within the same type are mapped with their proper pte flags. v2: Instead of using ttm_res to calculate vram pfns in the svm_range. It is now done by setting the vram real physical address into drm_addr array. This makes more flexible VRAM management, plus removes the need to have a BO reference in the svm_range. v3: Remove mapping member from svm_range Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 73 ++-- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 2 +- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 2b4318646a75..3b05bc270732 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -119,11 +119,12 @@ static void svm_range_remove_notifier(struct svm_range *prange) } static int -svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr, +svm_range_dma_map_dev(struct amdgpu_device *adev, dma_addr_t **dma_addr, unsigned long *hmm_pfns, uint64_t npages) { enum dma_data_direction dir = DMA_BIDIRECTIONAL; dma_addr_t *addr = *dma_addr; + struct device *dev = adev->dev; struct page *page; int i, r; @@ -141,6 +142,14 @@ svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr, dma_unmap_page(dev, addr[i], PAGE_SIZE, dir); page = hmm_pfn_to_page(hmm_pfns[i]); + if (is_zone_device_page(page)) { + addr[i] = (hmm_pfns[i] << PAGE_SHIFT) + + adev->vm_manager.vram_base_offset - + adev->kfd.dev->pgmap.range.start; + addr[i] |= SVM_RANGE_VRAM_DOMAIN; + pr_debug("vram address detected: 0x%llx\n", addr[i]); + continue; + } addr[i] = dma_map_page(dev, page, 0, PAGE_SIZE, dir); r = dma_mapping_error(dev, addr[i]); if (r) { @@ -175,7 +184,7 @@ svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap, } adev = (struct amdgpu_device *)pdd->dev->kgd; - r = svm_range_dma_map_dev(adev->dev, >dma_addr[gpuidx], + r = svm_range_dma_map_dev(adev, >dma_addr[gpuidx], hmm_pfns, prange->npages); if (r) break; @@ -1003,21 +1012,22 @@ svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, } static uint64_t -svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) +svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange, + int domain) { struct amdgpu_device *bo_adev; uint32_t flags = prange->flags; uint32_t mapping_flags = 0; uint64_t pte_flags; - bool snoop = !prange->ttm_res; + bool snoop = (domain != SVM_RANGE_VRAM_DOMAIN); bool coherent = flags & KFD_IOCTL_SVM_FLAG_COHERENT; - if (prange->svm_bo && prange->ttm_res) + if (domain == SVM_RANGE_VRAM_DOMAIN) bo_adev = amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev); switch (adev->asic_type) { case CHIP_ARCTURUS: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1032,7 +1042,7 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) } break; case CHIP_ALDEBARAN: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1061,14 +1071,14 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE; pte_flags = AMDGPU_PTE_VALID; - pte_flags |= prange->ttm_res ? 0 : AMDGPU_PTE_SYSTEM; + pte_flags |=
Re: [PATCH 04/10] drm/amdgpu: get owner ref in validate and map
On 2021-06-21 12:04 p.m., Alex Sierra wrote: Get the proper owner reference for amdgpu_hmm_range_get_pages function. This is useful for partial migrations. To avoid migrating back to system memory, VRAM pages, that are accessible by all devices in the same memory domain. Ex. multiple devices in the same hive. Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 25 - 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 54f47b09b14a..2b4318646a75 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1313,6 +1313,17 @@ static void svm_range_unreserve_bos(struct svm_validate_context *ctx) ttm_eu_backoff_reservation(>ticket, >validate_list); } +static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx) +{ + struct kfd_process_device *pdd; + struct amdgpu_device *adev; + + pdd = kfd_process_device_from_gpuidx(p, gpuidx); + adev = (struct amdgpu_device *)pdd->dev->kgd; + + return SVM_ADEV_PGMAP_OWNER(adev); +} + /* * Validation+GPU mapping with concurrent invalidation (MMU notifiers) * @@ -1343,6 +1354,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm, { struct svm_validate_context ctx; struct hmm_range *hmm_range; + struct kfd_process *p; + void *owner; + int32_t idx; int r = 0; ctx.process = container_of(prange->svms, struct kfd_process, svms); @@ -1389,10 +1403,19 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_reserve_bos(); if (!prange->actual_loc) { + p = container_of(prange->svms, struct kfd_process, svms); + owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, + MAX_GPU_INSTANCE)); + for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { + if (kfd_svm_page_owner(p, idx) != owner) { + owner = NULL; + break; + } + } r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true, NULL); + false, true, owner); if (r) { pr_debug("failed %d to get svm range pages\n", r); goto unreserve_out; ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 02/10] drm/amdkfd: add owner ref param to get hmm pages
On 2021-06-21 12:04 p.m., Alex Sierra wrote: The parameter is used in the dev_private_owner to decide if device pages in the range require to be migrated back to system memory, based if they are or not in the same memory domain. In this case, this reference could come from the same memory domain with devices connected to the same hive. Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.c| 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 2741c28ff1b5..378c238c2099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -160,7 +160,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked) + bool mmap_locked, void *owner) { struct hmm_range *hmm_range; unsigned long timeout; @@ -185,6 +185,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, hmm_range->hmm_pfns = pfns; hmm_range->start = start; hmm_range->end = start + npages * PAGE_SIZE; + hmm_range->dev_private_owner = owner; /* Assuming 512MB takes maxmium 1 second to fault page address */ timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h index 7f7d37a457c3..14a3c1864085 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h @@ -34,7 +34,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked); + bool mmap_locked, void *owner); int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range); #if defined(CONFIG_HMM_MIRROR) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 7e7d8330d64b..c13f7fbfc070 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -709,7 +709,7 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages) readonly = amdgpu_ttm_tt_is_readonly(ttm); r = amdgpu_hmm_range_get_pages(>notifier, mm, pages, start, ttm->num_pages, >range, readonly, - false); + false, NULL); out_putmm: mmput(mm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index b665e9ff77e3..b939f353ac8c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1392,7 +1392,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true); + false, true, NULL); if (r) { pr_debug("failed %d to get svm range pages\n", r); goto unreserve_out; @@ -2657,7 +2657,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true); + false, true, NULL); if (!r) { amdgpu_hmm_range_get_pages_done(hmm_range); prange->validated_once = true; ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 01/10] drm/amdkfd: device pgmap owner at the svm migrate init
On 2021-06-21 12:04 p.m., Alex Sierra wrote: pgmap owner member at the svm migrate init could be referenced to either adev or hive, depending on device topology. The reasoning for this change is, that GPUs in the same XGMI hive have direct access to all members' VRAM. When mapping memory to a GPU, we don't need hmm_range_fault to fault device-private pages in the same hive back to the host. Identifying the page owner as the hive, rather than the individual GPU, accomplishes this. With this explanation in the commit description, the patch is Reviewed-by: Felix Kuehling Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 6 +++--- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index fd8f544f0de2..11f7f590c6ec 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -426,7 +426,7 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_SYSTEM; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -641,7 +641,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -907,7 +907,7 @@ int svm_migrate_init(struct amdgpu_device *adev) pgmap->range.start = res->start; pgmap->range.end = res->end; pgmap->ops = _migrate_pgmap_ops; - pgmap->owner = adev; + pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev); pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; r = devm_memremap_pages(adev->dev, pgmap); if (IS_ERR(r)) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 573f984b81fe..4297250f259d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -35,6 +35,9 @@ #include "amdgpu.h" #include "kfd_priv.h" +#define SVM_ADEV_PGMAP_OWNER(adev)\ + ((adev)->hive ? (void *)(adev)->hive : (void *)(adev)) + struct svm_range_bo { struct amdgpu_bo*bo; struct kref kref; ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 4/4] drm/amdkfd: add direct link flag to link properties
Flag peers as a direct link if over PCIe or over xGMI if they are adjacent in the hive. Signed-off-by: Jonathan Kim --- drivers/gpu/drm/amd/amdkfd/kfd_crat.h | 3 ++- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 11 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h index d1f6de5edfb9..0d661d60ece6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h @@ -232,8 +232,9 @@ struct crat_subtype_ccompute { #define CRAT_IOLINK_FLAGS_NO_ATOMICS_32_BIT(1 << 2) #define CRAT_IOLINK_FLAGS_NO_ATOMICS_64_BIT(1 << 3) #define CRAT_IOLINK_FLAGS_NO_PEER_TO_PEER_DMA (1 << 4) +#define CRAT_IOLINK_FLAGS_DIRECT_LINK (1 << 5) #define CRAT_IOLINK_FLAGS_BI_DIRECTIONAL (1 << 31) -#define CRAT_IOLINK_FLAGS_RESERVED_MASK0x7fe0 +#define CRAT_IOLINK_FLAGS_RESERVED_MASK0x7fc0 /* * IO interface types diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index b1ce072aa20b..037fa12ac1bc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1244,6 +1244,15 @@ static void kfd_set_iolink_non_coherent(struct kfd_topology_device *to_dev, } } +static void kfd_set_iolink_direct_link(struct kfd_topology_device *dev, + struct kfd_iolink_properties *link) +{ + if (link->iolink_type == CRAT_IOLINK_TYPE_PCIEXPRESS || + (link->iolink_type == CRAT_IOLINK_TYPE_XGMI && + link->max_bandwidth)) + link->flags |= CRAT_IOLINK_FLAGS_DIRECT_LINK; +} + static void kfd_fill_iolink_non_crat_info(struct kfd_topology_device *dev) { struct kfd_iolink_properties *link, *inbound_link; @@ -1256,6 +1265,7 @@ static void kfd_fill_iolink_non_crat_info(struct kfd_topology_device *dev) list_for_each_entry(link, >io_link_props, list) { link->flags = CRAT_IOLINK_FLAGS_ENABLED; kfd_set_iolink_no_atomics(dev, NULL, link); + kfd_set_iolink_direct_link(dev, link); peer_dev = kfd_topology_device_by_proximity_domain( link->node_to); @@ -1270,6 +1280,7 @@ static void kfd_fill_iolink_non_crat_info(struct kfd_topology_device *dev) inbound_link->flags = CRAT_IOLINK_FLAGS_ENABLED; kfd_set_iolink_no_atomics(peer_dev, dev, inbound_link); kfd_set_iolink_non_coherent(peer_dev, link, inbound_link); + kfd_set_iolink_direct_link(peer_dev, inbound_link); } } } -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 3/4] drm/amdkfd: report pcie bandwidth as number of lanes
Similar to xGMI reporting the min/max bandwidth as the number of links between peers, PCIe will report the min/max bandwidth as the number of supported lanes. Signed-off-by: Jonathan Kim --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 24 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 3 +++ drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 3 +++ 3 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index c84989eda8eb..99c662b70519 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -568,6 +568,30 @@ uint8_t amdgpu_amdkfd_get_xgmi_num_links(struct kgd_dev *dst, struct kgd_dev *sr return (uint8_t)ret; } +uint32_t amdgpu_amdkfd_get_pcie_min_lanes(struct kgd_dev *dev) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)dev; + int min_lane_shift = ffs(adev->pm.pcie_mlw_mask >> + CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT) - 1; + + if (min_lane_shift < 0) + return 0; + + return 1UL << min_lane_shift; +} + +uint32_t amdgpu_amdkfd_get_pcie_max_lanes(struct kgd_dev *dev) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)dev; + int max_lane_shift = fls(adev->pm.pcie_mlw_mask >> + CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT) - 1; + + if (max_lane_shift < 0) + return 0; + + return 1UL << max_lane_shift; +} + uint64_t amdgpu_amdkfd_get_mmio_remap_phys_addr(struct kgd_dev *kgd) { struct amdgpu_device *adev = (struct amdgpu_device *)kgd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 20e4bfce62be..88322c72a43d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -31,6 +31,7 @@ #include #include #include +#include "amd_pcie.h" #include "amdgpu_sync.h" #include "amdgpu_vm.h" @@ -227,6 +228,8 @@ uint32_t amdgpu_amdkfd_get_asic_rev_id(struct kgd_dev *kgd); int amdgpu_amdkfd_get_noretry(struct kgd_dev *kgd); uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *src); uint8_t amdgpu_amdkfd_get_xgmi_num_links(struct kgd_dev *dst, struct kgd_dev *src); +uint32_t amdgpu_amdkfd_get_pcie_min_lanes(struct kgd_dev *dev); +uint32_t amdgpu_amdkfd_get_pcie_max_lanes(struct kgd_dev *dev); /* Read user wptr from a specified user address space with page fault * disabled. The memory must be pinned and mapped to the hardware when diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 75047b77649b..f70d69035fe7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1036,6 +1036,7 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, props->max_latency = iolink->maximum_latency; props->min_bandwidth = iolink->minimum_bandwidth; props->max_bandwidth = iolink->maximum_bandwidth; + props->rec_transfer_size = iolink->recommended_transfer_size; @@ -1993,6 +1994,8 @@ static int kfd_fill_gpu_direct_io_link_to_cpu(int *avail_size, sub_type_hdr->maximum_bandwidth = 1; } else { sub_type_hdr->io_interface_type = CRAT_IOLINK_TYPE_PCIEXPRESS; + sub_type_hdr->minimum_bandwidth = amdgpu_amdkfd_get_pcie_min_lanes(kdev->kgd); + sub_type_hdr->maximum_bandwidth = amdgpu_amdkfd_get_pcie_max_lanes(kdev->kgd); } sub_type_hdr->proximity_domain_from = proximity_domain; -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/4] drm/amdgpu: add psp command to get num xgmi links between direct peers
The TA can now be invoked to provide the number of xgmi links connecting a direct source and destination peer. Non-direct peers will report zero links. Signed-off-by: Jonathan Kim --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 23 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 1 + drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h | 14 +- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 40da29d8ec1e..2af9a7a9b7de 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1037,6 +1037,12 @@ int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id) return 0; } +static bool psp_xgmi_peer_link_info_supported(struct psp_context *psp) +{ + return psp->adev->asic_type == CHIP_ALDEBARAN && + psp->ta_xgmi_ucode_version >= 0x200b; +} + int psp_xgmi_get_topology_info(struct psp_context *psp, int number_devices, struct psp_xgmi_topology_info *topology) @@ -1080,6 +1086,23 @@ int psp_xgmi_get_topology_info(struct psp_context *psp, topology->nodes[i].sdma_engine = topology_info_output->nodes[i].sdma_engine; } + /* Invoke xgmi ta again to get the link information */ + if (psp_xgmi_peer_link_info_supported(psp)) { + struct ta_xgmi_cmd_get_peer_link_info_output *link_info_output; + + xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_PEER_LINKS; + + ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_PEER_LINKS); + + if (ret) + return ret; + + link_info_output = _cmd->xgmi_out_message.get_link_info; + for (i = 0; i < topology->num_nodes; i++) + topology->nodes[i].num_links = + link_info_output->nodes[i].num_links; + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index e5dcc6713861..13f1b869f67e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -116,6 +116,7 @@ struct psp_xgmi_node_info { uint8_t num_hops; uint8_t is_sharing_enabled; enum ta_xgmi_assigned_sdma_engine sdma_engine; + uint8_t num_links; }; struct psp_xgmi_topology_info { diff --git a/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h b/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h index ac2c27b7630c..cce7127afeaa 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h @@ -33,7 +33,8 @@ enum ta_command_xgmi { TA_COMMAND_XGMI__GET_NODE_ID= 0x01, TA_COMMAND_XGMI__GET_HIVE_ID= 0x02, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO = 0x03, - TA_COMMAND_XGMI__SET_TOPOLOGY_INFO = 0x04 + TA_COMMAND_XGMI__SET_TOPOLOGY_INFO = 0x04, + TA_COMMAND_XGMI__GET_PEER_LINKS = 0x0B }; /* XGMI related enumerations */ @@ -75,6 +76,11 @@ struct ta_xgmi_node_info { enum ta_xgmi_assigned_sdma_engine sdma_engine; }; +struct ta_xgmi_peer_link_info { + uint64_tnode_id; + uint8_t num_links; +}; + struct ta_xgmi_cmd_initialize_output { uint32_tstatus; }; @@ -97,6 +103,11 @@ struct ta_xgmi_cmd_get_topology_info_output { struct ta_xgmi_node_infonodes[TA_XGMI__MAX_CONNECTED_NODES]; }; +struct ta_xgmi_cmd_get_peer_link_info_output { + uint32_tnum_nodes; + struct ta_xgmi_peer_link_info nodes[TA_XGMI__MAX_CONNECTED_NODES]; +}; + struct ta_xgmi_cmd_set_topology_info_input { uint32_tnum_nodes; struct ta_xgmi_node_infonodes[TA_XGMI__MAX_CONNECTED_NODES]; @@ -115,6 +126,7 @@ union ta_xgmi_cmd_output { struct ta_xgmi_cmd_get_node_id_output get_node_id; struct ta_xgmi_cmd_get_hive_id_output get_hive_id; struct ta_xgmi_cmd_get_topology_info_output get_topology_info; + struct ta_xgmi_cmd_get_peer_link_info_outputget_link_info; }; /**/ -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/4] drm/amdkfd: report num xgmi links between direct peers to the kfd
Since Min/Max bandwidth was never used, it will repurposed to report the number of xgmi links between direct peers to the KFD topology. Signed-off-by: Jonathan Kim --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 15 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 12 drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h | 2 ++ drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 11 +-- drivers/gpu/drm/amd/amdkfd/kfd_crat.h | 4 ++-- 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index bfab2f9fdd17..c84989eda8eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -553,6 +553,21 @@ uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *s return (uint8_t)ret; } +uint8_t amdgpu_amdkfd_get_xgmi_num_links(struct kgd_dev *dst, struct kgd_dev *src) +{ + struct amdgpu_device *peer_adev = (struct amdgpu_device *)src; + struct amdgpu_device *adev = (struct amdgpu_device *)dst; + int ret = amdgpu_xgmi_get_num_links(adev, peer_adev); + + if (ret < 0) { + DRM_ERROR("amdgpu: failed to get xgmi num links between node %d and %d. ret = %d\n", + adev->gmc.xgmi.physical_node_id, + peer_adev->gmc.xgmi.physical_node_id, ret); + ret = 0; + } + return (uint8_t)ret; +} + uint64_t amdgpu_amdkfd_get_mmio_remap_phys_addr(struct kgd_dev *kgd) { struct amdgpu_device *adev = (struct amdgpu_device *)kgd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index fabc68eec36a..20e4bfce62be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -226,6 +226,7 @@ uint32_t amdgpu_amdkfd_get_num_gws(struct kgd_dev *kgd); uint32_t amdgpu_amdkfd_get_asic_rev_id(struct kgd_dev *kgd); int amdgpu_amdkfd_get_noretry(struct kgd_dev *kgd); uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *src); +uint8_t amdgpu_amdkfd_get_xgmi_num_links(struct kgd_dev *dst, struct kgd_dev *src); /* Read user wptr from a specified user address space with page fault * disabled. The memory must be pinned and mapped to the hardware when diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 8567d5d77346..258cf86b32f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -486,6 +486,18 @@ int amdgpu_xgmi_get_hops_count(struct amdgpu_device *adev, return -EINVAL; } +int amdgpu_xgmi_get_num_links(struct amdgpu_device *adev, + struct amdgpu_device *peer_adev) +{ + struct psp_xgmi_topology_info *top = >psp.xgmi_context.top_info; + int i; + + for (i = 0 ; i < top->num_nodes; ++i) + if (top->nodes[i].node_id == peer_adev->gmc.xgmi.node_id) + return top->nodes[i].num_links; + return -EINVAL; +} + int amdgpu_xgmi_add_device(struct amdgpu_device *adev) { struct psp_xgmi_topology_info *top_info; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index 12969c0830d5..d2189bf7d428 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -59,6 +59,8 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev); int amdgpu_xgmi_set_pstate(struct amdgpu_device *adev, int pstate); int amdgpu_xgmi_get_hops_count(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); +int amdgpu_xgmi_get_num_links(struct amdgpu_device *adev, + struct amdgpu_device *peer_adev); uint64_t amdgpu_xgmi_get_relative_phy_addr(struct amdgpu_device *adev, uint64_t addr); static inline bool amdgpu_xgmi_same_hive(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index c6b02aee4993..75047b77649b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1034,8 +1034,8 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, props->min_latency = iolink->minimum_latency; props->max_latency = iolink->maximum_latency; - props->min_bandwidth = iolink->minimum_bandwidth_mbs; - props->max_bandwidth = iolink->maximum_bandwidth_mbs; + props->min_bandwidth = iolink->minimum_bandwidth; + props->max_bandwidth = iolink->maximum_bandwidth; props->rec_transfer_size = iolink->recommended_transfer_size; @@ -1989,6
Re: [PATCH 09/10] drm/amdkfd: partially actual_loc removed
On 2021-06-21 12:04 p.m., Alex Sierra wrote: actual_loc should not be used anymore, as pranges could have mixed locations (VRAM & SYSRAM) at the same time. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 12 +--- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 71 ++-- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index f71f8d7e2b72..acb9f64577a0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -501,12 +501,6 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, struct amdgpu_device *adev; int r = 0; - if (prange->actual_loc == best_loc) { - pr_debug("svms 0x%p [0x%lx 0x%lx] already on best_loc 0x%x\n", -prange->svms, prange->start, prange->last, best_loc); - return 0; - } - adev = svm_range_get_adev_by_id(prange, best_loc); if (!adev) { pr_debug("failed to get device by id 0x%x\n", best_loc); @@ -791,11 +785,7 @@ int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, struct mm_struct *mm) { - if (!prange->actual_loc) - return svm_migrate_ram_to_vram(prange, best_loc, mm); - else - return svm_migrate_vram_to_vram(prange, best_loc, mm); - + return svm_migrate_ram_to_vram(prange, best_loc, mm); Can you remove svm_migrate_vram_to_vram in this case? I guess we're relying on the svm_range_prefault call in svm_migrate_ram_to_vram now to migrate VRAM in a different XGMI hive to system memory now. But eventually we want to get rid of that pre-fault hack. } /** diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 3b05bc270732..ebc1ae7e5193 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1421,42 +1421,38 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_reserve_bos(); - if (!prange->actual_loc) { - p = container_of(prange->svms, struct kfd_process, svms); - owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, - MAX_GPU_INSTANCE)); - for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { - if (kfd_svm_page_owner(p, idx) != owner) { - owner = NULL; - break; - } - } - r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, - prange->start << PAGE_SHIFT, - prange->npages, _range, - false, true, owner); - if (r) { - pr_debug("failed %d to get svm range pages\n", r); - goto unreserve_out; - } - - r = svm_range_dma_map(prange, ctx.bitmap, - hmm_range->hmm_pfns); - if (r) { - pr_debug("failed %d to dma map range\n", r); - goto unreserve_out; + p = container_of(prange->svms, struct kfd_process, svms); + owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, + MAX_GPU_INSTANCE)); + for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { + if (kfd_svm_page_owner(p, idx) != owner) { + owner = NULL; + break; } + } + r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, + prange->start << PAGE_SHIFT, + prange->npages, _range, + false, true, owner); + if (r) { + pr_debug("failed %d to get svm range pages\n", r); + goto unreserve_out; + } - prange->validated_once = true; + r = svm_range_dma_map(prange, ctx.bitmap, + hmm_range->hmm_pfns); + if (r) { + pr_debug("failed %d to dma map range\n", r); + goto unreserve_out; } + prange->validated_once = true; + svm_range_lock(prange); - if (!prange->actual_loc) { - if (amdgpu_hmm_range_get_pages_done(hmm_range)) { - pr_debug("hmm update the range, need validate again\n"); - r = -EAGAIN; - goto unlock_out; - } + if (amdgpu_hmm_range_get_pages_done(hmm_range)) { + pr_debug("hmm update the range, need validate again\n"); + r = -EAGAIN; + goto unlock_out; IMO, this is the most
[PATCH 36/43] drm/amdgpu: Nerf buff
buff --> buf. Essentially buffer abbreviates to buf, remove 1/2 of it, or just the iron part, as opposed to just the Er, Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 98 +-- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 21e1e59e4857ff..8b60fba9f835e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -117,10 +117,10 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, return true; } -static void __encode_table_header_to_buff(struct amdgpu_ras_eeprom_table_header *hdr, - unsigned char *buff) +static void __encode_table_header_to_buf(struct amdgpu_ras_eeprom_table_header *hdr, +unsigned char *buf) { - uint32_t *pp = (uint32_t *) buff; + uint32_t *pp = (uint32_t *) buf; pp[0] = cpu_to_le32(hdr->header); pp[1] = cpu_to_le32(hdr->version); @@ -129,10 +129,10 @@ static void __encode_table_header_to_buff(struct amdgpu_ras_eeprom_table_header pp[4] = cpu_to_le32(hdr->checksum); } -static void __decode_table_header_from_buff(struct amdgpu_ras_eeprom_table_header *hdr, - unsigned char *buff) +static void __decode_table_header_from_buf(struct amdgpu_ras_eeprom_table_header *hdr, + unsigned char *buf) { - uint32_t *pp = (uint32_t *)buff; + u32 *pp = (uint32_t *) buf; hdr->header = le32_to_cpu(pp[0]); hdr->version = le32_to_cpu(pp[1]); @@ -142,18 +142,18 @@ static void __decode_table_header_from_buff(struct amdgpu_ras_eeprom_table_heade } static int __write_table_header(struct amdgpu_ras_eeprom_control *control, - unsigned char *buff) + unsigned char *buf) { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); - __encode_table_header_to_buff(>tbl_hdr, buff); + __encode_table_header_to_buf(>tbl_hdr, buf); /* i2c may be unstable in gpu reset */ down_read(>reset_sem); ret = amdgpu_eeprom_write(>pm.smu_i2c, control->i2c_address + RAS_HDR_START, - buff, RAS_TABLE_HEADER_SIZE); + buf, RAS_TABLE_HEADER_SIZE); up_read(>reset_sem); if (ret < 1) @@ -240,15 +240,15 @@ static int amdgpu_ras_eeprom_correct_header_tag( struct amdgpu_ras_eeprom_control *control, uint32_t header) { - unsigned char buff[RAS_TABLE_HEADER_SIZE]; + unsigned char buf[RAS_TABLE_HEADER_SIZE]; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; int ret = 0; - memset(buff, 0, RAS_TABLE_HEADER_SIZE); + memset(buf, 0, RAS_TABLE_HEADER_SIZE); mutex_lock(>tbl_mutex); hdr->header = header; - ret = __write_table_header(control, buff); + ret = __write_table_header(control, buf); mutex_unlock(>tbl_mutex); return ret; @@ -256,7 +256,7 @@ static int amdgpu_ras_eeprom_correct_header_tag( int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) { - unsigned char buff[RAS_TABLE_HEADER_SIZE] = { 0 }; + unsigned char buf[RAS_TABLE_HEADER_SIZE] = { 0 }; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; int ret = 0; @@ -269,7 +269,7 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) __update_tbl_checksum(control, NULL, 0); control->next_addr = RAS_RECORD_START; - ret = __write_table_header(control, buff); + ret = __write_table_header(control, buf); mutex_unlock(>tbl_mutex); @@ -282,7 +282,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); - unsigned char buff[RAS_TABLE_HEADER_SIZE] = { 0 }; + unsigned char buf[RAS_TABLE_HEADER_SIZE] = { 0 }; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); @@ -303,13 +303,13 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, /* Read/Create table header from EEPROM address 0 */ ret = amdgpu_eeprom_read(>pm.smu_i2c, control->i2c_address + RAS_HDR_START, -buff, RAS_TABLE_HEADER_SIZE); +buf, RAS_TABLE_HEADER_SIZE); if (ret < 1) { DRM_ERROR("Failed to read EEPROM table header, ret:%d", ret); return
[PATCH 37/43] drm/amdgpu: Some renames
Qualify with "ras_". Use kernel's own--don't redefine your own. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 16 +- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 30 +-- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 25 drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 2 +- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index c7ad90483f21d3..cd2fce8bbcab87 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1818,11 +1818,11 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) control = >eeprom_control; data = con->eh_data; - save_count = data->count - control->num_recs; + save_count = data->count - control->ras_num_recs; /* only new entries are saved */ if (save_count > 0) { if (amdgpu_ras_eeprom_write(control, - >bps[control->num_recs], + >bps[control->ras_num_recs], save_count)) { dev_err(adev->dev, "Failed to save EEPROM table data!"); return -EIO; @@ -1846,18 +1846,18 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) int ret; /* no bad page record, skip eeprom access */ - if (control->num_recs == 0 || amdgpu_bad_page_threshold == 0) + if (control->ras_num_recs == 0 || amdgpu_bad_page_threshold == 0) return 0; - bps = kcalloc(control->num_recs, sizeof(*bps), GFP_KERNEL); + bps = kcalloc(control->ras_num_recs, sizeof(*bps), GFP_KERNEL); if (!bps) return -ENOMEM; - ret = amdgpu_ras_eeprom_read(control, bps, control->num_recs); + ret = amdgpu_ras_eeprom_read(control, bps, control->ras_num_recs); if (ret) dev_err(adev->dev, "Failed to load EEPROM table records!"); else - ret = amdgpu_ras_add_bad_pages(adev, bps, control->num_recs); + ret = amdgpu_ras_add_bad_pages(adev, bps, control->ras_num_recs); kfree(bps); return ret; @@ -1974,13 +1974,13 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) if (exc_err_limit || ret) goto free; - if (con->eeprom_control.num_recs) { + if (con->eeprom_control.ras_num_recs) { ret = amdgpu_ras_load_bad_pages(adev); if (ret) goto free; if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->send_hbm_bad_pages_num) - adev->smu.ppt_funcs->send_hbm_bad_pages_num(>smu, con->eeprom_control.num_recs); + adev->smu.ppt_funcs->send_hbm_bad_pages_num(>smu, con->eeprom_control.ras_num_recs); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 8b60fba9f835e6..34da00ef8369bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -246,10 +246,10 @@ static int amdgpu_ras_eeprom_correct_header_tag( memset(buf, 0, RAS_TABLE_HEADER_SIZE); - mutex_lock(>tbl_mutex); + mutex_lock(>ras_tbl_mutex); hdr->header = header; ret = __write_table_header(control, buf); - mutex_unlock(>tbl_mutex); + mutex_unlock(>ras_tbl_mutex); return ret; } @@ -260,7 +260,7 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; int ret = 0; - mutex_lock(>tbl_mutex); + mutex_lock(>ras_tbl_mutex); hdr->header = RAS_TABLE_HDR_VAL; hdr->version = RAS_TABLE_VER; @@ -271,7 +271,7 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) control->next_addr = RAS_RECORD_START; ret = __write_table_header(control, buf); - mutex_unlock(>tbl_mutex); + mutex_unlock(>ras_tbl_mutex); return ret; @@ -298,7 +298,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, if (!__get_eeprom_i2c_addr(adev, control)) return -EINVAL; - mutex_init(>tbl_mutex); + mutex_init(>ras_tbl_mutex); /* Read/Create table header from EEPROM address 0 */ ret = amdgpu_eeprom_read(>pm.smu_i2c, @@ -312,17 +312,17 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, __decode_table_header_from_buf(hdr, buf); if (hdr->header == RAS_TABLE_HDR_VAL) { - control->num_recs = (hdr->tbl_size - RAS_TABLE_HEADER_SIZE) / +
[PATCH 38/43] drm/amdgpu: Get rid of test function
The code is now tested from userspace. Remove already macroed out test function. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 33 --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 2 -- 2 files changed, 35 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 34da00ef8369bb..7522d2ca5b03fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -572,36 +572,3 @@ inline uint32_t amdgpu_ras_eeprom_max_record_count(void) { return RAS_MAX_RECORD_COUNT; } - -/* Used for testing if bugs encountered */ -#if 0 -void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control) -{ - int i; - struct eeprom_table_record *recs = kcalloc(1, sizeof(*recs), GFP_KERNEL); - - if (!recs) - return; - - for (i = 0; i < 1 ; i++) { - recs[i].address = 0xdeadbeef; - recs[i].retired_page = i; - } - - if (!amdgpu_ras_eeprom_write(control, recs, 1)) { - - memset(recs, 0, sizeof(*recs) * 1); - - control->next_addr = RAS_RECORD_START; - - if (!amdgpu_ras_eeprom_read(control, recs)) { - for (i = 0; i < 1; i++) - DRM_INFO("rec.address :0x%llx, rec.retired_page :%llu", -recs[i].address, recs[i].retired_page); - } else - DRM_ERROR("Failed in reading from table"); - - } else - DRM_ERROR("Failed in writing to table"); -} -#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index 9e1e7656b7bc2a..67a7ec3e6c2296 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -103,6 +103,4 @@ int amdgpu_ras_eeprom_write(struct amdgpu_ras_eeprom_control *control, inline uint32_t amdgpu_ras_eeprom_max_record_count(void); -void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control); - #endif // _AMDGPU_RAS_EEPROM_H -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 42/43] drm/amdgpu: Use a single loop
In smu_v11_0_i2c_transmit() use a single loop to transmit bytes, instead of two nested loops. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 72 ++ 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 7f48ee020bc03e..751ea2517c4380 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -243,49 +243,45 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, /* Clear status bits */ smu_v11_0_i2c_clear_status(control); - timeout_counter = jiffies + msecs_to_jiffies(20); while (numbytes > 0) { reg = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_STATUS); - if (REG_GET_FIELD(reg, CKSVII2C_IC_STATUS, TFNF)) { - do { - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, DAT, data[bytes_sent]); - - /* Final message, final byte, must -* generate a STOP, to release the -* bus, i.e. don't hold SCL low. -*/ - if (numbytes == 1 && i2c_flag & I2C_M_STOP) - reg = REG_SET_FIELD(reg, - CKSVII2C_IC_DATA_CMD, - STOP, 1); - - if (bytes_sent == 0 && i2c_flag & I2C_X_RESTART) - reg = REG_SET_FIELD(reg, - CKSVII2C_IC_DATA_CMD, - RESTART, 1); - - /* Write */ - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, CMD, 0); - WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_DATA_CMD, reg); - - /* Record that the bytes were transmitted */ - bytes_sent++; - numbytes--; - - reg = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_STATUS); - - } while (numbytes && REG_GET_FIELD(reg, CKSVII2C_IC_STATUS, TFNF)); - } + if (!REG_GET_FIELD(reg, CKSVII2C_IC_STATUS, TFNF)) { + /* +* We waited for too long for the transmission +* FIFO to become not-full. Exit the loop +* with error. +*/ + if (time_after(jiffies, timeout_counter)) { + ret |= I2C_SW_TIMEOUT; + goto Err; + } + } else { + reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, DAT, + data[bytes_sent]); - /* -* We waited too long for the transmission FIFO to become not-full. -* Exit the loop with error. -*/ - if (time_after(jiffies, timeout_counter)) { - ret |= I2C_SW_TIMEOUT; - goto Err; + /* Final message, final byte, must generate a +* STOP to release the bus, i.e. don't hold +* SCL low. +*/ + if (numbytes == 1 && i2c_flag & I2C_M_STOP) + reg = REG_SET_FIELD(reg, + CKSVII2C_IC_DATA_CMD, + STOP, 1); + + if (bytes_sent == 0 && i2c_flag & I2C_X_RESTART) + reg = REG_SET_FIELD(reg, + CKSVII2C_IC_DATA_CMD, + RESTART, 1); + + /* Write */ + reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, CMD, 0); + WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_DATA_CMD, reg); + + /* Record that the bytes were transmitted */ + bytes_sent++; + numbytes--; } } -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 32/43] drm/amdgpu: Return result fix in RAS
The low level EEPROM write method, doesn't return 1, but the number of bytes written. Thus do not compare to 1, instead, compare to greater than 0 for success. Other cleanup: if the lower layers returned -errno, then return that, as opposed to overwriting the error code with one-fits-all -EINVAL. For instance, some return -EAGAIN. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c| 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 22 +++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 2 +- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c| 3 +-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index a5a87affedabf1..a4815af111ed12 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -105,8 +105,7 @@ static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, int r; u16 len; - r = 0; - for ( ; buf_size > 0; + for (r = 0; buf_size > 0; buf_size -= len, eeprom_addr += len, eeprom_buf += len) { /* Set the EEPROM address we want to write to/read from. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index a9af6d0a2ed6bc..64054a825b7421 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -355,8 +355,9 @@ static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f, * to see which blocks support RAS on a particular asic. * */ -static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user *buf, - size_t size, loff_t *pos) +static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, +const char __user *buf, +size_t size, loff_t *pos) { struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; struct ras_debug_if data; @@ -370,7 +371,7 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user * ret = amdgpu_ras_debugfs_ctrl_parse_data(f, buf, size, pos, ); if (ret) - return -EINVAL; + return ret; if (data.op == 3) { ret = amdgpu_reserve_page_direct(adev, data.inject.address); @@ -439,21 +440,24 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user * * will reset EEPROM table to 0 entries. * */ -static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f, const char __user *buf, - size_t size, loff_t *pos) +static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f, + const char __user *buf, + size_t size, loff_t *pos) { struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; int ret; ret = amdgpu_ras_eeprom_reset_table( - &(amdgpu_ras_get_context(adev)->eeprom_control)); + &(amdgpu_ras_get_context(adev)->eeprom_control)); - if (ret == 1) { + if (ret > 0) { + /* Something was written to EEPROM. +*/ amdgpu_ras_get_context(adev)->flags = RAS_DEFAULT_FLAGS; return size; } else { - return -EIO; + return ret; } } @@ -1994,7 +1998,7 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) kfree(*data); con->eh_data = NULL; out: - dev_warn(adev->dev, "Failed to initialize ras recovery!\n"); + dev_warn(adev->dev, "Failed to initialize ras recovery! (%d)\n", ret); /* * Except error threshold exceeding case, other failure cases in this diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 17cea35275e46c..dc48c556398039 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -335,7 +335,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, ret = amdgpu_ras_eeprom_reset_table(control); } - return ret == 1 ? 0 : -EIO; + return ret > 0 ? 0 : -EIO; } static void __encode_table_record_to_buff(struct amdgpu_ras_eeprom_control *control, diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 65035256756679..7f48ee020bc03e 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -222,7 +222,7 @@ static uint32_t
[PATCH 43/43] drm/amdgpu: Correctly disable the I2C IP block
On long transfers to the EEPROM device, i.e. write, it is observed that the driver aborts the transfer. The reason for this is that the driver isn't patient enough--the IC_STATUS register's contents is 0x27, which is MST_ACTIVITY | TFE | TFNF | ACTIVITY. That is, while the transmission FIFO is empty, we, the I2C master device, are still driving the bus. Implement the correct procedure to disable the block, as described in the DesignWare I2C Databook, section 3.8.3 Disabling DW_apb_i2c on page 56. Now there are no premature aborts on long data transfers. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 80 +- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 751ea2517c4380..7d74d6204d8d0a 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -54,12 +54,48 @@ static void smu_v11_0_i2c_set_clock_gating(struct i2c_adapter *control, bool en) WREG32_SOC15(SMUIO, 0, mmSMUIO_PWRMGT, reg); } +/* The T_I2C_POLL_US is defined as follows: + * + * "Define a timer interval (t_i2c_poll) equal to 10 times the + * signalling period for the highest I2C transfer speed used in the + * system and supported by DW_apb_i2c. For instance, if the highest + * I2C data transfer mode is 400 kb/s, then t_i2c_poll is 25 us." -- + * DesignWare DW_apb_i2c Databook, Version 1.21a, section 3.8.3.1, + * page 56, with grammar and syntax corrections. + * + * Vcc for our device is at 1.8V which puts it at 400 kHz, + * see Atmel AT24CM02 datasheet, section 8.3 DC Characteristics table, page 14. + * + * The procedure to disable the IP block is described in section + * 3.8.3 Disabling DW_apb_i2c on page 56. + */ +#define I2C_SPEED_MODE_FAST 2 +#define T_I2C_POLL_US 25 +#define I2C_MAX_T_POLL_COUNT1000 -static void smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable) +static int smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable) { struct amdgpu_device *adev = to_amdgpu_device(control); WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE, enable ? 1 : 0); + + if (!enable) { + int ii; + + for (ii = I2C_MAX_T_POLL_COUNT; ii > 0; ii--) { + u32 en_stat = RREG32_SOC15(SMUIO, + 0, + mmCKSVII2C_IC_ENABLE_STATUS); + if (REG_GET_FIELD(en_stat, CKSVII2C_IC_ENABLE_STATUS, IC_EN)) + udelay(T_I2C_POLL_US); + else + return I2C_OK; + } + + return I2C_ABORT; + } + + return I2C_OK; } static void smu_v11_0_i2c_clear_status(struct i2c_adapter *control) @@ -81,8 +117,13 @@ static void smu_v11_0_i2c_configure(struct i2c_adapter *control) reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_RESTART_EN, 1); reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_10BITADDR_MASTER, 0); reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_10BITADDR_SLAVE, 0); - /* Standard mode */ - reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MAX_SPEED_MODE, 2); + /* The values of IC_MAX_SPEED_MODE are, +* 1: standard mode, 0 - 100 Kb/s, +* 2: fast mode, <= 400 Kb/s, or fast mode plus, <= 1000 Kb/s, +* 3: high speed mode, <= 3.4 Mb/s. +*/ + reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MAX_SPEED_MODE, + I2C_SPEED_MODE_FAST); reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MASTER_MODE, 1); WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_CON, reg); @@ -404,7 +445,6 @@ static void smu_v11_0_i2c_abort(struct i2c_adapter *control) DRM_DEBUG_DRIVER("I2C_Abort() Done."); } - static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -416,7 +456,6 @@ static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control) reg_ic_enable_status = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE_STATUS); reg_ic_enable = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE); - if ((REG_GET_FIELD(reg_ic_enable, CKSVII2C_IC_ENABLE, ENABLE) == 0) && (REG_GET_FIELD(reg_ic_enable_status, CKSVII2C_IC_ENABLE_STATUS, IC_EN) == 1)) { /* @@ -446,6 +485,8 @@ static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control) static void smu_v11_0_i2c_init(struct i2c_adapter *control) { + int res; + /* Disable clock gating */ smu_v11_0_i2c_set_clock_gating(control, false); @@ -453,7 +494,9 @@ static void smu_v11_0_i2c_init(struct i2c_adapter *control) DRM_WARN("I2C busy !"); /* Disable I2C */ -
[PATCH 35/43] drm/amdgpu: Use explicit cardinality for clarity
RAS_MAX_RECORD_NUM may mean the maximum record number, as in the maximum house number on your street, or it may mean the maximum number of records, as in the count of records, which is also a number. To make this distinction whether the number is ordinal (index) or cardinal (count), rename this macro to RAS_MAX_RECORD_COUNT. This makes it easy to understand what it refers to, especially when we compute quantities such as, how many records do we have left in the table, especially when there are so many other numbers, quantities and numerical macros around. Also rename the long, amdgpu_ras_eeprom_get_record_max_length() to the more succinct and clear, amdgpu_ras_eeprom_max_record_count(). When computing the threshold, which also deals with counts, i.e. "how many", use cardinal "max_eeprom_records_count", than the quantitative "max_eeprom_records_len". Simplify the logic here and there, as well. Cc: Guchun Chen Cc: John Clements Cc: Hawking Zhang Cc: Alexander Deucher Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 9 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 50 --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 8 +-- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 2 +- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 80dab0c6e19ebb..406043c9906425 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -868,11 +868,10 @@ MODULE_PARM_DESC(reset_method, "GPU reset method (-1 = auto (default), 0 = legac module_param_named(reset_method, amdgpu_reset_method, int, 0444); /** - * DOC: bad_page_threshold (int) - * Bad page threshold is to specify the threshold value of faulty pages - * detected by RAS ECC, that may result in GPU entering bad status if total - * faulty pages by ECC exceed threshold value and leave it for user's further - * check. + * DOC: bad_page_threshold (int) Bad page threshold is specifies the + * threshold value of faulty pages detected by RAS ECC, which may + * result in the GPU entering bad status when the number of total + * faulty pages by ECC exceeds the threshold value. */ MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = auto(default value), 0 = disable bad page retirement)"); module_param_named(bad_page_threshold, amdgpu_bad_page_threshold, int, 0444); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 64054a825b7421..c7ad90483f21d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -71,8 +71,8 @@ const char *ras_block_string[] = { /* inject address is 52 bits */ #defineRAS_UMC_INJECT_ADDR_LIMIT (0x1ULL << 52) -/* typical ECC bad page rate(1 bad page per 100MB VRAM) */ -#define RAS_BAD_PAGE_RATE (100 * 1024 * 1024ULL) +/* typical ECC bad page rate is 1 bad page per 100MB VRAM */ +#define RAS_BAD_PAGE_COVER (100 * 1024 * 1024ULL) enum amdgpu_ras_retire_page_reservation { AMDGPU_RAS_RETIRE_PAGE_RESERVED, @@ -1841,27 +1841,24 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) { struct amdgpu_ras_eeprom_control *control = - >psp.ras.ras->eeprom_control; - struct eeprom_table_record *bps = NULL; - int ret = 0; + >psp.ras.ras->eeprom_control; + struct eeprom_table_record *bps; + int ret; /* no bad page record, skip eeprom access */ - if (!control->num_recs || (amdgpu_bad_page_threshold == 0)) - return ret; + if (control->num_recs == 0 || amdgpu_bad_page_threshold == 0) + return 0; bps = kcalloc(control->num_recs, sizeof(*bps), GFP_KERNEL); if (!bps) return -ENOMEM; - if (amdgpu_ras_eeprom_read(control, bps, control->num_recs)) { + ret = amdgpu_ras_eeprom_read(control, bps, control->num_recs); + if (ret) dev_err(adev->dev, "Failed to load EEPROM table records!"); - ret = -EIO; - goto out; - } - - ret = amdgpu_ras_add_bad_pages(adev, bps, control->num_recs); + else + ret = amdgpu_ras_add_bad_pages(adev, bps, control->num_recs); -out: kfree(bps); return ret; } @@ -1901,11 +1898,9 @@ static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev, } static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev, - uint32_t max_length) + uint32_t max_count) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - int tmp_threshold = amdgpu_bad_page_threshold; - u64 val; /* *
[PATCH 34/43] drm/amdgpu: Simplify RAS EEPROM checksum calculations
Rename update_table_header() to write_table_header() as this function is actually writing it to EEPROM. Use kernel types; use u8 to carry around the checksum, in order to take advantage of arithmetic modulo 8-bits (256). Tidy up to 80 columns. When updating the checksum, just recalculate the whole thing. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 98 +-- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 2 +- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 7d0f9e1e62dc4f..54ef31594accd9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -141,8 +141,8 @@ static void __decode_table_header_from_buff(struct amdgpu_ras_eeprom_table_heade hdr->checksum = le32_to_cpu(pp[4]); } -static int __update_table_header(struct amdgpu_ras_eeprom_control *control, -unsigned char *buff) +static int __write_table_header(struct amdgpu_ras_eeprom_control *control, + unsigned char *buff) { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); @@ -162,69 +162,74 @@ static int __update_table_header(struct amdgpu_ras_eeprom_control *control, return ret; } -static uint32_t __calc_hdr_byte_sum(struct amdgpu_ras_eeprom_control *control) +static u8 __calc_hdr_byte_sum(const struct amdgpu_ras_eeprom_control *control) { int i; - uint32_t tbl_sum = 0; + u8 hdr_sum = 0; + u8 *p; + size_t sz; /* Header checksum, skip checksum field in the calculation */ - for (i = 0; i < sizeof(control->tbl_hdr) - sizeof(control->tbl_hdr.checksum); i++) - tbl_sum += *(((unsigned char *)>tbl_hdr) + i); + sz = sizeof(control->tbl_hdr) - sizeof(control->tbl_hdr.checksum); + p = (u8 *) >tbl_hdr; + for (i = 0; i < sz; i++, p++) + hdr_sum += *p; - return tbl_sum; + return hdr_sum; } -static uint32_t __calc_recs_byte_sum(struct eeprom_table_record *records, - int num) +static u8 __calc_recs_byte_sum(const struct eeprom_table_record *record, + const int num) { int i, j; - uint32_t tbl_sum = 0; + u8 tbl_sum = 0; + + if (!record) + return 0; /* Records checksum */ for (i = 0; i < num; i++) { - struct eeprom_table_record *record = [i]; + u8 *p = (u8 *) [i]; - for (j = 0; j < sizeof(*record); j++) { - tbl_sum += *(((unsigned char *)record) + j); - } + for (j = 0; j < sizeof(*record); j++, p++) + tbl_sum += *p; } return tbl_sum; } -static inline uint32_t __calc_tbl_byte_sum(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, int num) +static inline u8 +__calc_tbl_byte_sum(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, int num) { - return __calc_hdr_byte_sum(control) + __calc_recs_byte_sum(records, num); + return __calc_hdr_byte_sum(control) + + __calc_recs_byte_sum(records, num); } -/* Checksum = 256 -((sum of all table entries) mod 256) */ static void __update_tbl_checksum(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, int num, - uint32_t old_hdr_byte_sum) + struct eeprom_table_record *records, int num) { - /* -* This will update the table sum with new records. -* -* TODO: What happens when the EEPROM table is to be wrapped around -* and old records from start will get overridden. -*/ - - /* need to recalculate updated header byte sum */ - control->tbl_byte_sum -= old_hdr_byte_sum; - control->tbl_byte_sum += __calc_tbl_byte_sum(control, records, num); + u8 v; - control->tbl_hdr.checksum = 256 - (control->tbl_byte_sum % 256); + control->tbl_byte_sum = __calc_tbl_byte_sum(control, records, num); + /* Avoid 32-bit sign extension. */ + v = -control->tbl_byte_sum; + control->tbl_hdr.checksum = v; } -/* table sum mod 256 + checksum must equals 256 */ -static bool __validate_tbl_checksum(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, int num) +static bool __verify_tbl_checksum(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, + int num)
[PATCH 40/43] drm/amdgpu: RAS EEPROM table is now in debugfs
Add "ras_eeprom_size" file in debugfs, which reports the maximum size allocated to the RAS table in EEROM, as the number of bytes and the number of records it could store. For instance, $cat /sys/kernel/debug/dri/0/ras/ras_eeprom_size 262144 bytes or 10921 records $_ Add "ras_eeprom_table" file in debugfs, which dumps the RAS table stored EEPROM, in a formatted way. For instance, $cat ras_eeprom_table SignatureVersion FirstOffs Size Checksum 0x414D4452 0x0001 0x0014 0x00EC 0x00DA Index Offset ErrType Bank/CU TimeStamp Offs/Addr MemChl MCUMCID RetiredPage 0 0x00014 ue0x00 0x607608DC 0x 0x000x00 0x 1 0x0002C ue0x00 0x607608DC 0x1000 0x000x00 0x0001 2 0x00044 ue0x00 0x607608DC 0x2000 0x000x00 0x0002 3 0x0005C ue0x00 0x607608DC 0x3000 0x000x00 0x0003 4 0x00074 ue0x00 0x607608DC 0x4000 0x000x00 0x0004 5 0x0008C ue0x00 0x607608DC 0x5000 0x000x00 0x0005 6 0x000A4 ue0x00 0x607608DC 0x6000 0x000x00 0x0006 7 0x000BC ue0x00 0x607608DC 0x7000 0x000x00 0x0007 8 0x000D4 ue0x00 0x607608DD 0x8000 0x000x00 0x0008 $_ Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: John Clements Cc: Hawking Zhang Cc: Xinhui Pan Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 12 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 1 + .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 241 +- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 10 +- 4 files changed, 252 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index f15f8ab5b9affb..edf4c02d075f48 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -404,9 +404,9 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, /* umc ce/ue error injection for a bad page is not allowed */ if ((data.head.block == AMDGPU_RAS_BLOCK__UMC) && amdgpu_ras_check_bad_page(adev, data.inject.address)) { - dev_warn(adev->dev, "RAS WARN: 0x%llx has been marked " - "as bad before error injection!\n", - data.inject.address); + dev_warn(adev->dev, "RAS WARN: inject: 0x%llx has " +"already been marked as bad!\n", +data.inject.address); break; } @@ -1301,6 +1301,12 @@ static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device * >bad_page_cnt_threshold); debugfs_create_x32("ras_hw_enabled", 0444, dir, >ras_hw_enabled); debugfs_create_x32("ras_enabled", 0444, dir, >ras_enabled); + debugfs_create_file("ras_eeprom_size", S_IRUGO, dir, adev, + _ras_debugfs_eeprom_size_ops); + con->de_ras_eeprom_table = debugfs_create_file("ras_eeprom_table", + S_IRUGO, dir, adev, + _ras_debugfs_eeprom_table_ops); + amdgpu_ras_debugfs_set_ret_size(>eeprom_control); /* * After one uncorrectable error happens, usually GPU recovery will diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 256cea5d34f2b6..283afd791db107 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -318,6 +318,7 @@ struct amdgpu_ras { /* sysfs */ struct device_attribute features_attr; struct bin_attribute badpages_attr; + struct dentry *de_ras_eeprom_table; /* block array */ struct ras_manager *objs; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index dc4a845a32404c..677e379f5fb5e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -27,6 +27,8 @@ #include #include "atom.h" #include "amdgpu_eeprom.h" +#include +#include #define EEPROM_I2C_MADDR_VEGA20 0x0 #define EEPROM_I2C_MADDR_ARCTURUS 0x4 @@ -70,6 +72,13 @@ #define RAS_OFFSET_TO_INDEX(_C, _O) (((_O) - \ (_C)->ras_record_offset) / RAS_TABLE_RECORD_SIZE) +/* Given a 0-based relative record index, 0, 1, 2, ..., etc., off + * of "fri", return the absolute record index off of the end of + * the table header. + */
[PATCH 39/43] drm/amdgpu: Optimize EEPROM RAS table I/O
Split functionality between read and write, which simplifies the code and exposes areas of optimization and more or less complexity, and take advantage of that. Read and write the table in one go; use a separate stage to decode or encode the data, as opposed to on the fly, which keeps the I2C bus busy. Use a single read/write to read/write the table or at most two if the number of records we're reading/writing wraps around. Check the check-sum of a table in EEPROM on init. Update the checksum at the same time as when updating the table header signature, when the threshold was increased on boot. Take advantage of arithmetic modulo 256, that is, use a byte!, to greatly simplify checksum arithmetic. Cc: Alexander Deucher Cc: Andrey Grodzovsky Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c| 20 +- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h| 23 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 8 +- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 844 -- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 32 +- 5 files changed, 620 insertions(+), 307 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index a4815af111ed12..4c3c65a5acae9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -176,8 +176,8 @@ static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, * * Returns the number of bytes read/written; -errno on error. */ -int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, - u8 *eeprom_buf, u16 buf_size, bool read) +static int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, + u8 *eeprom_buf, u16 buf_size, bool read) { const struct i2c_adapter_quirks *quirks = i2c_adap->quirks; u16 limit; @@ -221,3 +221,19 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, return res; } } + +int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, + u16 bytes) +{ + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + true); +} + +int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, + u16 bytes) +{ + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + false); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h index 966b434f0de2b7..6935adb2be1f1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h @@ -26,23 +26,12 @@ #include -int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, - u8 *eeprom_buf, u16 bytes, bool read); +int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, + u16 bytes); -static inline int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, -u32 eeprom_addr, u8 *eeprom_buf, -u16 bytes) -{ - return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, - true); -} - -static inline int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, - u32 eeprom_addr, u8 *eeprom_buf, - u16 bytes) -{ - return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, - false); -} +int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, + u16 bytes); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index cd2fce8bbcab87..f15f8ab5b9affb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -451,7 +451,7 @@ static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f, ret = amdgpu_ras_eeprom_reset_table( &(amdgpu_ras_get_context(adev)->eeprom_control)); - if (ret > 0) { + if (!ret) { /* Something was written to EEPROM. */ amdgpu_ras_get_context(adev)->flags = RAS_DEFAULT_FLAGS; @@ -1821,9 +1821,9 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) save_count = data->count - control->ras_num_recs; /* only new entries are saved */ if (save_count > 0) { - if (amdgpu_ras_eeprom_write(control, - >bps[control->ras_num_recs], - save_count)) { +
[PATCH 30/43] drm/amd/pm: Simplify managed I2C transfer functions
Now that we have an I2C quirk table for SMU-managed I2C controllers, the I2C core does the checks for us, so we don't need to do them, and so simplify the managed I2C transfer functions. Also, for Arcturus and Navi10, fix setting the command type from "cmd->CmdConfig" to "cmd->Cmd". The latter is what appears to be taking in the enumeration I2C_CMD_... as an integer, not a bit-flag. For Sienna, the "Cmd" field seems to have been eliminated, and command type and flags all live in the "CmdConfig" field--this is left untouched. Fix: Detect and add changing of direction bit-flag, as this is necessary for the SMU to detect the direction change in the 1-d array of data it gets. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 78 --- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 78 --- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 76 -- 3 files changed, 95 insertions(+), 137 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 3286c704bd08df..dc884b719717ad 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1937,31 +1937,14 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable) } static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, -struct i2c_msg *msgs, int num) +struct i2c_msg *msg, int num_msgs) { struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct smu_table_context *smu_table = >smu.smu_table; struct smu_table *table = _table->driver_table; SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; - short available_bytes = MAX_SW_I2C_COMMANDS; - int i, j, r, c, num_done = 0; - u8 slave; - - /* only support a single slave addr per transaction */ - slave = msgs[0].addr; - for (i = 0; i < num; i++) { - if (slave != msgs[i].addr) - return -EINVAL; - - available_bytes -= msgs[i].len; - if (available_bytes >= 0) { - num_done++; - } else { - /* This message and all the follwing won't be processed */ - available_bytes += msgs[i].len; - break; - } - } + int i, j, r, c; + u16 dir; req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) @@ -1969,33 +1952,38 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, req->I2CcontrollerPort = 1; req->I2CSpeed = I2C_SPEED_FAST_400K; - req->SlaveAddress = slave << 1; /* 8 bit addresses */ - req->NumCmds = MAX_SW_I2C_COMMANDS - available_bytes;; - - c = 0; - for (i = 0; i < num_done; i++) { - struct i2c_msg *msg = [i]; + req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */ + dir = msg[0].flags & I2C_M_RD; - for (j = 0; j < msg->len; j++) { - SwI2cCmd_t *cmd = >SwI2cCmds[c++]; + for (c = i = 0; i < num_msgs; i++) { + for (j = 0; j < msg[i].len; j++, c++) { + SwI2cCmd_t *cmd = >SwI2cCmds[c]; if (!(msg[i].flags & I2C_M_RD)) { /* write */ - cmd->CmdConfig |= I2C_CMD_WRITE; - cmd->RegisterAddr = msg->buf[j]; + cmd->Cmd = I2C_CMD_WRITE; + cmd->RegisterAddr = msg[i].buf[j]; + } + + if ((dir ^ msg[i].flags) & I2C_M_RD) { + /* The direction changes. +*/ + dir = msg[i].flags & I2C_M_RD; + cmd->CmdConfig |= CMDCONFIG_RESTART_MASK; } + req->NumCmds++; + /* * Insert STOP if we are at the last byte of either last * message for the transaction or the client explicitly * requires a STOP at this particular message. */ - if ((j == msg->len -1 ) && - ((i == num_done - 1) || (msg[i].flags & I2C_M_STOP))) + if ((j == msg[i].len - 1) && + ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) { + cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK; cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - -
[PATCH 41/43] drm/amdgpu: Fix koops when accessing RAS EEPROM
Debugfs RAS EEPROM files are available when the ASIC supports RAS, and when the debugfs is enabled, an also when "ras_enable" module parameter is set to 0. However in this case, we get a kernel oops when accessing some of the "ras_..." controls in debugfs. The reason for this is that struct amdgpu_ras::adev is unset. This commit sets it, thus enabling access to those facilities. Note that this facilitates EEPROM access and not necessarily RAS features or functionality. Cc: Alexander Deucher Cc: John Clements Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 16 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index edf4c02d075f48..c6ae63893dbdb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1947,11 +1947,20 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) bool exc_err_limit = false; int ret; - if (adev->ras_enabled && con) - data = >eh_data; - else + if (!con) + return 0; + + /* Allow access to RAS EEPROM via debugfs, when the ASIC +* supports RAS and debugfs is enabled, but when +* adev->ras_enabled is unset, i.e. when "ras_enable" +* module parameter is set to 0. +*/ + con->adev = adev; + + if (!adev->ras_enabled) return 0; + data = >eh_data; *data = kmalloc(sizeof(**data), GFP_KERNEL | __GFP_ZERO); if (!*data) { ret = -ENOMEM; @@ -1961,7 +1970,6 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) mutex_init(>recovery_lock); INIT_WORK(>recovery_work, amdgpu_ras_do_recovery); atomic_set(>in_recovery, 0); - con->adev = adev; max_eeprom_records_count = amdgpu_ras_eeprom_max_record_count(); amdgpu_ras_validate_threshold(adev, max_eeprom_records_count); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 31/43] drm/amdgpu: Fix width of I2C address
The I2C address is kept as a 16-bit quantity in the kernel. The I2C_TAR::I2C_TAR field is 10-bit wide. Fix the width of the I2C address for Vega20 from 8 bits to 16 bits to accommodate the full spectrum of I2C address space. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 19 +++ 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index e403ba556e5590..65035256756679 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -111,12 +111,15 @@ static void smu_v11_0_i2c_set_clock(struct i2c_adapter *control) WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_SDA_HOLD, 20); } -static void smu_v11_0_i2c_set_address(struct i2c_adapter *control, uint8_t address) +static void smu_v11_0_i2c_set_address(struct i2c_adapter *control, u16 address) { struct amdgpu_device *adev = to_amdgpu_device(control); - /* We take 7-bit addresses raw */ - WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_TAR, (address & 0xFF)); + /* The IC_TAR::IC_TAR field is 10-bits wide. +* It takes a 7-bit or 10-bit addresses as an address, +* i.e. no read/write bit--no wire format, just the address. +*/ + WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_TAR, address & 0x3FF); } static uint32_t smu_v11_0_i2c_poll_tx_status(struct i2c_adapter *control) @@ -215,8 +218,8 @@ static uint32_t smu_v11_0_i2c_poll_rx_status(struct i2c_adapter *control) * Returns 0 on success or error. */ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, - uint8_t address, uint8_t *data, - uint32_t numbytes, uint32_t i2c_flag) + u16 address, u8 *data, + u32 numbytes, u32 i2c_flag) { struct amdgpu_device *adev = to_amdgpu_device(control); uint32_t bytes_sent, reg, ret = 0; @@ -225,7 +228,7 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, bytes_sent = 0; DRM_DEBUG_DRIVER("I2C_Transmit(), address = %x, bytes = %d , data: ", -(uint16_t)address, numbytes); +address, numbytes); if (drm_debug_enabled(DRM_UT_DRIVER)) { print_hex_dump(KERN_INFO, "data: ", DUMP_PREFIX_NONE, @@ -318,8 +321,8 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, * Returns 0 on success or error. */ static uint32_t smu_v11_0_i2c_receive(struct i2c_adapter *control, -uint8_t address, uint8_t *data, -uint32_t numbytes, uint8_t i2c_flag) + u16 address, u8 *data, + u32 numbytes, u32 i2c_flag) { struct amdgpu_device *adev = to_amdgpu_device(control); uint32_t bytes_received, ret = I2C_OK; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 33/43] drm/amdgpu: Fix amdgpu_ras_eeprom_init()
No need to account for the 2 bytes of EEPROM address--this is now well abstracted away by the fixes the the lower layers. Cc: Andrey Grodzovsky Cc: Alexander Deucher Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index dc48c556398039..7d0f9e1e62dc4f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -306,7 +306,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, return ret; } - __decode_table_header_from_buff(hdr, [2]); + __decode_table_header_from_buff(hdr, buff); if (hdr->header == RAS_TABLE_HDR_VAL) { control->num_recs = (hdr->tbl_size - RAS_TABLE_HEADER_SIZE) / -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 09/43] drm/amdgpu: add I2C_CLASS_HWMON to SMU i2c buses
From: Alex Deucher Not sure that this really matters that much, but these could have various other hwmon chips on them. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 1d8f6d5180e099..3a164d93c90293 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -665,7 +665,7 @@ int smu_v11_0_i2c_control_init(struct i2c_adapter *control) mutex_init(>pm.smu_i2c_mutex); control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; + control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _v11_0_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index a6447822deb09f..404afc9979c69b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2033,7 +2033,7 @@ static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; + control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index e02db86ced6108..3303830afac7d0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2832,7 +2832,7 @@ static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter * int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; + control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index b4aa489e4a431a..1d06641ad87890 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3539,7 +3539,7 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_a int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; + control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _cichlid_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 19/43] drm/amdgpu: Fixes to the AMDGPU EEPROM driver
* When reading from the EEPROM device, there is no device limitation on the number of bytes read--they're simply sequenced out. Thus, read the whole data requested in one go. * When writing to the EEPROM device, there is a 256-byte page limit to write to before having to generate a STOP on the bus, as well as the address written to mustn't cross over the page boundary (it actually rolls over). Maximize the data written to per bus acquisition. * Return the number of bytes read/written, or -errno. * Add kernel doc. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 96 +++--- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index d02ea083a6c69b..7fdb5bd2fc8bc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -24,59 +24,99 @@ #include "amdgpu_eeprom.h" #include "amdgpu.h" -#define EEPROM_OFFSET_LENGTH 2 +/* AT24CM02 has a 256-byte write page size. + */ +#define EEPROM_PAGE_BITS 8 +#define EEPROM_PAGE_SIZE (1U << EEPROM_PAGE_BITS) +#define EEPROM_PAGE_MASK (EEPROM_PAGE_SIZE - 1) + +#define EEPROM_OFFSET_SIZE 2 +/** + * amdgpu_eeprom_xfer -- Read/write from/to an I2C EEPROM device + * @i2c_adap: pointer to the I2C adapter to use + * @slave_addr: I2C address of the slave device + * @eeprom_addr: EEPROM address from which to read/write + * @eeprom_buf: pointer to data buffer to read into/write from + * @buf_size: the size of @eeprom_buf + * @read: True if reading from the EEPROM, false if writing + * + * Returns the number of bytes read/written; -errno on error. + */ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u16 slave_addr, u16 eeprom_addr, - u8 *eeprom_buf, u16 bytes, bool read) + u8 *eeprom_buf, u16 buf_size, bool read) { - u8 eeprom_offset_buf[2]; - u16 bytes_transferred; + u8 eeprom_offset_buf[EEPROM_OFFSET_SIZE]; struct i2c_msg msgs[] = { { .addr = slave_addr, .flags = 0, - .len = EEPROM_OFFSET_LENGTH, + .len = EEPROM_OFFSET_SIZE, .buf = eeprom_offset_buf, }, { .addr = slave_addr, .flags = read ? I2C_M_RD : 0, - .len = bytes, - .buf = eeprom_buf, }, }; + const u8 *p = eeprom_buf; int r; + u16 len; + + r = 0; + for (len = 0; buf_size > 0; +buf_size -= len, eeprom_addr += len, eeprom_buf += len) { + /* Set the EEPROM address we want to write to/read from. +*/ + msgs[0].buf[0] = (eeprom_addr >> 8) & 0xff; + msgs[0].buf[1] = eeprom_addr & 0xff; - msgs[0].buf[0] = ((eeprom_addr >> 8) & 0xff); - msgs[0].buf[1] = (eeprom_addr & 0xff); + if (!read) { + /* Write the maximum amount of data, without +* crossing the device's page boundary, as per +* its spec. Partial page writes are allowed, +* starting at any location within the page, +* so long as the page boundary isn't crossed +* over (actually the page pointer rolls +* over). +* +* As per the AT24CM02 EEPROM spec, after +* writing into a page, the I2C driver MUST +* terminate the transfer, i.e. in +* "i2c_transfer()" below, with a STOP +* condition, so that the self-timed write +* cycle begins. This is implied for the +* "i2c_transfer()" abstraction. +*/ + len = min(EEPROM_PAGE_SIZE - (eeprom_addr & + EEPROM_PAGE_MASK), + (u32)buf_size); + } else { + /* Reading from the EEPROM has no limitation +* on the number of bytes read from the EEPROM +* device--they are simply sequenced out. +*/ + len = buf_size; + } + msgs[1].len = len; + msgs[1].buf = eeprom_buf; - while (msgs[1].len) { r = i2c_transfer(i2c_adap, msgs, ARRAY_SIZE(msgs)); - if (r <= 0) - return r; + if (r
[PATCH 15/43] drm/amdgpu: Send STOP for the last byte of msg only
From: Andrey Grodzovsky Let's just ignore the I2C_M_STOP hint from upper layer for SMU I2C code as there is no clean mapping between single per I2C message STOP flag at the kernel I2C layer and the SMU, per each byte STOP flag. We will just by default set it at the end of the SMU I2C message. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Andrey Grodzovsky Suggested-by: Lazar Lijo Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 4 ++-- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 4 ++-- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index a6d6ea1ef9e31b..fde03bb6ffe7c8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1981,9 +1981,9 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, cmd->CmdConfig |= I2C_CMD_WRITE; cmd->RegisterAddr = msg->buf[j]; } - if ((msg[i].flags & I2C_M_STOP) || - (!remaining_bytes)) + if (!remaining_bytes) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index e682bbd3c26d82..8bd3fa2ef7efea 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2780,9 +2780,9 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, cmd->CmdConfig |= I2C_CMD_WRITE; cmd->RegisterAddr = msg->buf[j]; } - if ((msg[i].flags & I2C_M_STOP) || - (!remaining_bytes)) + if (!remaining_bytes) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 93acf3f869227a..7c266420e31cc7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3487,9 +3487,9 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, cmd->CmdConfig |= CMDCONFIG_READWRITE_MASK; cmd->ReadWriteData = msg->buf[j]; } - if ((msg[i].flags & I2C_M_STOP) || - (!remaining_bytes)) + if (!remaining_bytes) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 24/43] drm/amdgpu: I2C class is HWMON
Set the auto-discoverable class of I2C bus to HWMON. Remove SPD. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Reviewed-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index b8d6d308fb06a0..e403ba556e5590 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -667,7 +667,7 @@ int smu_v11_0_i2c_control_init(struct i2c_adapter *control) mutex_init(>pm.smu_i2c_mutex); control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; + control->class = I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _v11_0_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 33210119a28ec1..9fccdd2d3e73ec 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2046,7 +2046,7 @@ static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; + control->class = I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _i2c_algo; control->quirks = _i2c_control_quirks; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index c9519a1a5ca633..5cecb4be57c554 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2844,7 +2844,7 @@ static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter * int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; + control->class = I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 9a14103cf9729f..2444e13c4901b3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3551,7 +3551,7 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_a int res; control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; + control->class = I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _cichlid_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 08/43] drm/amdgpu: i2c subsystem uses 7 bit addresses
From: Alex Deucher Convert from 8 bit to 7 bit. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 10 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 224da573ba1b59..2b854bc6ae34bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -29,7 +29,7 @@ #include "amdgpu_fru_eeprom.h" #include "amdgpu_eeprom.h" -#define I2C_PRODUCT_INFO_ADDR 0xAC +#define I2C_PRODUCT_INFO_ADDR 0x56 #define I2C_PRODUCT_INFO_OFFSET0xC0 static bool is_fru_eeprom_supported(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index e22a0b45f70108..2b981e96ce5b9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -28,11 +28,11 @@ #include "atom.h" #include "amdgpu_eeprom.h" -#define EEPROM_I2C_TARGET_ADDR_VEGA20 0xA0 -#define EEPROM_I2C_TARGET_ADDR_ARCTURUS0xA8 -#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0 -#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 0xA0 -#define EEPROM_I2C_TARGET_ADDR_ALDEBARAN0xA0 +#define EEPROM_I2C_TARGET_ADDR_VEGA20 0x50 +#define EEPROM_I2C_TARGET_ADDR_ARCTURUS0x54 +#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0x50 +#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 0x50 +#define EEPROM_I2C_TARGET_ADDR_ALDEBARAN0x50 /* * The 2 macros bellow represent the actual size in bytes that -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 13/43] dmr/amdgpu: Add RESTART handling also to smu_v11_0_i2c (VG20)
From: Andrey Grodzovsky Also generilize the code to accept and translate to HW bits any I2C relvent flags both for read and write. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 22 -- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 3193d566f4f87e..5a90d9351b22eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -530,13 +530,11 @@ static bool smu_v11_0_i2c_bus_unlock(struct i2c_adapter *control) /* I2C GLUE / static uint32_t smu_v11_0_i2c_read_data(struct i2c_adapter *control, - struct i2c_msg *msg) + struct i2c_msg *msg, uint32_t i2c_flag) { - uint32_t ret = 0; + uint32_t ret; - /* Now read data starting with that address */ - ret = smu_v11_0_i2c_receive(control, msg->addr, msg->buf, msg->len, - I2C_RESTART); + ret = smu_v11_0_i2c_receive(control, msg->addr, msg->buf, msg->len, i2c_flag); if (ret != I2C_OK) DRM_ERROR("ReadData() - I2C error occurred :%x", ret); @@ -545,12 +543,11 @@ static uint32_t smu_v11_0_i2c_read_data(struct i2c_adapter *control, } static uint32_t smu_v11_0_i2c_write_data(struct i2c_adapter *control, - struct i2c_msg *msg) + struct i2c_msg *msg, uint32_t i2c_flag) { uint32_t ret; - /* Send I2C_NO_STOP unless requested to stop. */ - ret = smu_v11_0_i2c_transmit(control, msg->addr, msg->buf, msg->len, ((msg->flags & I2C_M_STOP) ? 0 : I2C_NO_STOP)); + ret = smu_v11_0_i2c_transmit(control, msg->addr, msg->buf, msg->len, i2c_flag); if (ret != I2C_OK) DRM_ERROR("WriteI2CData() - I2C error occurred :%x", ret); @@ -601,12 +598,17 @@ static int smu_v11_0_i2c_xfer(struct i2c_adapter *i2c_adap, smu_v11_0_i2c_init(i2c_adap); for (i = 0; i < num; i++) { + uint32_t i2c_flag = ((msgs[i].flags & I2C_M_NOSTART) ? 0 : I2C_RESTART) || + (((msgs[i].flags & I2C_M_STOP) ? 0 : I2C_NO_STOP)); + if (msgs[i].flags & I2C_M_RD) ret = smu_v11_0_i2c_read_data(i2c_adap, - msgs + i); + msgs + i, + i2c_flag); else ret = smu_v11_0_i2c_write_data(i2c_adap, - msgs + i); + msgs + i, + i2c_flag); if (ret != I2C_OK) { num = -EIO; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 06/43] drm/amdgpu/ras: switch ras eeprom handling to use generic helper
From: Alex Deucher Use the new helper rather than doing i2c transfers directly. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 86 ++- 1 file changed, 28 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index f40c871da0c623..e22a0b45f70108 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -26,6 +26,7 @@ #include "amdgpu_ras.h" #include #include "atom.h" +#include "amdgpu_eeprom.h" #define EEPROM_I2C_TARGET_ADDR_VEGA20 0xA0 #define EEPROM_I2C_TARGET_ADDR_ARCTURUS0xA8 @@ -148,22 +149,13 @@ static int __update_table_header(struct amdgpu_ras_eeprom_control *control, { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); - struct i2c_msg msg = { - .addr = 0, - .flags = 0, - .len= EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE, - .buf= buff, - }; - - *(uint16_t *)buff = EEPROM_HDR_START; - __encode_table_header_to_buff(>tbl_hdr, buff + EEPROM_ADDRESS_SIZE); - - msg.addr = control->i2c_address; + __encode_table_header_to_buff(>tbl_hdr, buff); /* i2c may be unstable in gpu reset */ down_read(>reset_sem); - ret = i2c_transfer(>pm.smu_i2c, , 1); + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, control->i2c_address, +EEPROM_HDR_START, buff, EEPROM_TABLE_HEADER_SIZE, false); up_read(>reset_sem); if (ret < 1) @@ -289,15 +281,9 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); - unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE] = { 0 }; + unsigned char buff[EEPROM_TABLE_HEADER_SIZE] = { 0 }; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - struct i2c_msg msg = { - .addr = 0, - .flags = I2C_M_RD, - .len= EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE, - .buf= buff, - }; *exceed_err_limit = false; @@ -313,9 +299,9 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, mutex_init(>tbl_mutex); - msg.addr = control->i2c_address; /* Read/Create table header from EEPROM address 0 */ - ret = i2c_transfer(>pm.smu_i2c, , 1); + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, control->i2c_address, +EEPROM_HDR_START, buff, EEPROM_TABLE_HEADER_SIZE, true); if (ret < 1) { DRM_ERROR("Failed to read EEPROM table header, ret:%d", ret); return ret; @@ -442,6 +428,7 @@ static uint32_t __correct_eeprom_dest_address(uint32_t curr_address) bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev) { + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); if (!__is_ras_eeprom_supported(adev)) @@ -470,11 +457,11 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, int num) { int i, ret = 0; - struct i2c_msg *msgs, *msg; unsigned char *buffs, *buff; struct eeprom_table_record *record; struct amdgpu_device *adev = to_amdgpu_device(control); struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + u16 slave_addr; if (!__is_ras_eeprom_supported(adev)) return 0; @@ -486,12 +473,6 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, mutex_lock(>tbl_mutex); - msgs = kcalloc(num, sizeof(*msgs), GFP_KERNEL); - if (!msgs) { - ret = -ENOMEM; - goto free_buff; - } - /* * If saved bad pages number exceeds the bad page threshold for * the whole VRAM, update table header to mark the BAD GPU tag @@ -521,9 +502,8 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, * 256b */ for (i = 0; i < num; i++) { - buff = [i * (EEPROM_ADDRESS_SIZE + EEPROM_TABLE_RECORD_SIZE)]; + buff = [i * EEPROM_TABLE_RECORD_SIZE]; record = [i]; - msg = [i]; control->next_addr = __correct_eeprom_dest_address(control->next_addr); @@ -531,20 +511,26 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, * Update bits 16,17 of EEPROM address in I2C address by setting them * to bits 1,2 of Device address byte */
[PATCH 18/43] drm/amdgpu: Fix Vega20 I2C to be agnostic (v2)
Teach Vega20 I2C to be agnostic. Allow addressing different devices while the master holds the bus. Set STOP as per the controller's specification. v2: Qualify generating ReSTART before the 1st byte of the message, when set by the caller, as those functions are separated, as caught by Andrey G. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 4 +- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 105 + 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index fe0e9b0c4d5a38..d02ea083a6c69b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -41,10 +41,10 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, }, { .addr = slave_addr, - .flags = read ? I2C_M_RD: 0, + .flags = read ? I2C_M_RD : 0, .len = bytes, .buf = eeprom_buf, - } + }, }; int r; diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 5a90d9351b22eb..b8d6d308fb06a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -41,9 +41,7 @@ #define I2C_SW_TIMEOUT8 #define I2C_ABORT 0x10 -/* I2C transaction flags */ -#define I2C_NO_STOP1 -#define I2C_RESTART2 +#define I2C_X_RESTART BIT(31) #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) @@ -205,9 +203,6 @@ static uint32_t smu_v11_0_i2c_poll_rx_status(struct i2c_adapter *control) return ret; } - - - /** * smu_v11_0_i2c_transmit - Send a block of data over the I2C bus to a slave device. * @@ -252,21 +247,22 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, reg = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_STATUS); if (REG_GET_FIELD(reg, CKSVII2C_IC_STATUS, TFNF)) { do { - reg = 0; - /* -* Prepare transaction, no need to set RESTART. I2C engine will send -* START as soon as it sees data in TXFIFO -*/ - if (bytes_sent == 0) - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, RESTART, - (i2c_flag & I2C_RESTART) ? 1 : 0); reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, DAT, data[bytes_sent]); - /* determine if we need to send STOP bit or not */ - if (numbytes == 1) - /* Final transaction, so send stop unless I2C_NO_STOP */ - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, STOP, - (i2c_flag & I2C_NO_STOP) ? 0 : 1); + /* Final message, final byte, must +* generate a STOP, to release the +* bus, i.e. don't hold SCL low. +*/ + if (numbytes == 1 && i2c_flag & I2C_M_STOP) + reg = REG_SET_FIELD(reg, + CKSVII2C_IC_DATA_CMD, + STOP, 1); + + if (bytes_sent == 0 && i2c_flag & I2C_X_RESTART) + reg = REG_SET_FIELD(reg, + CKSVII2C_IC_DATA_CMD, + RESTART, 1); + /* Write */ reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, CMD, 0); WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_DATA_CMD, reg); @@ -341,23 +337,21 @@ static uint32_t smu_v11_0_i2c_receive(struct i2c_adapter *control, smu_v11_0_i2c_clear_status(control); - /* Prepare transaction */ - - /* Each time we disable I2C, so this is not a restart */ - if (bytes_received == 0) - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, RESTART, - (i2c_flag & I2C_RESTART) ? 1 : 0); - reg = REG_SET_FIELD(reg, CKSVII2C_IC_DATA_CMD, DAT, 0);
[PATCH 22/43] drm/amdgpu: RAS and FRU now use 19-bit I2C address
Convert RAS and FRU code to use the 19-bit I2C memory address and remove all "slave_addr", as this is now absolved into the 19-bit address. Cc: Jean Delvare Cc: John Clements Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c| 19 ++--- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 82 +++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 2 +- 3 files changed, 39 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 2b854bc6ae34bb..69b9559f840ac3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -29,8 +29,8 @@ #include "amdgpu_fru_eeprom.h" #include "amdgpu_eeprom.h" -#define I2C_PRODUCT_INFO_ADDR 0x56 -#define I2C_PRODUCT_INFO_OFFSET0xC0 +#define FRU_EEPROM_MADDR0x6 +#define I2C_PRODUCT_INFO_OFFSET 0xC0 static bool is_fru_eeprom_supported(struct amdgpu_device *adev) { @@ -62,12 +62,11 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev) } static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, - unsigned char *buff) + unsigned char *buff) { int ret, size; - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, I2C_PRODUCT_INFO_ADDR, -addrptr, buff, 1, true); + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, addrptr, buff, 1, true); if (ret < 1) { DRM_WARN("FRU: Failed to get size field"); return ret; @@ -78,8 +77,8 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, */ size = buff[0] - I2C_PRODUCT_INFO_OFFSET; - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, I2C_PRODUCT_INFO_ADDR, -addrptr + 1, buff, size, true); + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, addrptr + 1, buff, size, +true); if (ret < 1) { DRM_WARN("FRU: Failed to get data field"); return ret; @@ -91,8 +90,8 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, int amdgpu_fru_get_product_info(struct amdgpu_device *adev) { unsigned char buff[34]; - int addrptr, size; - int len; + u32 addrptr; + int size, len; if (!is_fru_eeprom_supported(adev)) return 0; @@ -115,7 +114,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) * Bytes 8-a are all 1-byte and refer to the size of the entire struct, * and the language field, so just start from 0xb, manufacturer size */ - addrptr = 0xb; + addrptr = FRU_EEPROM_MADDR + 0xb; size = amdgpu_fru_read_eeprom(adev, addrptr, buff); if (size < 1) { DRM_ERROR("Failed to read FRU Manufacturer, ret:%d", size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 2b981e96ce5b9e..f316fb11b16d9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -28,11 +28,11 @@ #include "atom.h" #include "amdgpu_eeprom.h" -#define EEPROM_I2C_TARGET_ADDR_VEGA20 0x50 -#define EEPROM_I2C_TARGET_ADDR_ARCTURUS0x54 -#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0x50 -#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 0x50 -#define EEPROM_I2C_TARGET_ADDR_ALDEBARAN0x50 +#define EEPROM_I2C_MADDR_VEGA20 0x0 +#define EEPROM_I2C_MADDR_ARCTURUS 0x4 +#define EEPROM_I2C_MADDR_ARCTURUS_D342 0x0 +#define EEPROM_I2C_MADDR_SIENNA_CICHLID 0x0 +#define EEPROM_I2C_MADDR_ALDEBARAN 0x0 /* * The 2 macros bellow represent the actual size in bytes that @@ -58,7 +58,6 @@ #define EEPROM_HDR_START 0 #define EEPROM_RECORD_START (EEPROM_HDR_START + EEPROM_TABLE_HEADER_SIZE) #define EEPROM_MAX_RECORD_NUM ((EEPROM_SIZE_BYTES - EEPROM_TABLE_HEADER_SIZE) / EEPROM_TABLE_RECORD_SIZE) -#define EEPROM_ADDR_MSB_MASK GENMASK(17, 8) #define to_amdgpu_device(x) (container_of(x, struct amdgpu_ras, eeprom_control))->adev @@ -74,43 +73,43 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) } static bool __get_eeprom_i2c_addr_arct(struct amdgpu_device *adev, - uint16_t *i2c_addr) + struct amdgpu_ras_eeprom_control *control) { struct atom_context *atom_ctx = adev->mode_info.atom_context; - if (!i2c_addr || !atom_ctx) + if (!control || !atom_ctx) return false; if (strnstr(atom_ctx->vbios_version, "D342",
[PATCH 03/43] drm/amdgpu/pm: rework i2c xfers on arcturus (v4)
From: Alex Deucher Make it generic so we can support more than just EEPROMs. v2: fix restart handling between transactions. v3: handle 7 to 8 bit addr conversion v4: Fix --> req. (Luben T) Signed-off-by: Alex Deucher Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov --- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 229 +- 1 file changed, 58 insertions(+), 171 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 094df6f87cfc41..a6447822deb09f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1936,197 +1936,84 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable) return ret; } -static void arcturus_fill_i2c_req(SwI2cRequest_t *req, bool write, - uint8_t address, uint32_t numbytes, - uint8_t *data) -{ - int i; - - req->I2CcontrollerPort = 0; - req->I2CSpeed = 2; - req->SlaveAddress = address; - req->NumCmds = numbytes; - - for (i = 0; i < numbytes; i++) { - SwI2cCmd_t *cmd = >SwI2cCmds[i]; - - /* First 2 bytes are always write for lower 2b EEPROM address */ - if (i < 2) - cmd->Cmd = 1; - else - cmd->Cmd = write; - - - /* Add RESTART for read after address filled */ - cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0; - - /* Add STOP in the end */ - cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0; - - /* Fill with data regardless if read or write to simplify code */ - cmd->RegisterAddr = data[i]; - } -} - -static int arcturus_i2c_read_data(struct i2c_adapter *control, - uint8_t address, - uint8_t *data, - uint32_t numbytes) +static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, +struct i2c_msg *msgs, int num) { - uint32_t i, ret = 0; - SwI2cRequest_t req; - struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct smu_table_context *smu_table = >smu.smu_table; struct smu_table *table = _table->driver_table; - - if (numbytes > MAX_SW_I2C_COMMANDS) { - dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", - numbytes, MAX_SW_I2C_COMMANDS); - return -EINVAL; + SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; + u16 bytes_to_transfer, remaining_bytes, msg_bytes; + u16 available_bytes = MAX_SW_I2C_COMMANDS; + int i, j, r, c; + u8 slave; + + /* only support a single slave addr per transaction */ + slave = msgs[0].addr; + for (i = 0; i < num; i++) { + if (slave != msgs[i].addr) + return -EINVAL; + bytes_to_transfer += min(msgs[i].len, available_bytes); + available_bytes -= bytes_to_transfer; } - memset(, 0, sizeof(req)); - arcturus_fill_i2c_req(, false, address, numbytes, data); - - mutex_lock(>smu.mutex); - /* Now read data starting with that address */ - ret = smu_cmn_update_table(>smu, SMU_TABLE_I2C_COMMANDS, 0, , - true); - mutex_unlock(>smu.mutex); - - if (!ret) { - SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr; - - /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */ - for (i = 0; i < numbytes; i++) - data[i] = res->SwI2cCmds[i].Data; - - dev_dbg(adev->dev, "arcturus_i2c_read_data, address = %x, bytes = %d, data :", - (uint16_t)address, numbytes); + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; - print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, - 8, 1, data, numbytes, false); - } else - dev_err(adev->dev, "arcturus_i2c_read_data - error occurred :%x", ret); + req->I2CcontrollerPort = 1; + req->I2CSpeed = I2C_SPEED_FAST_400K; + req->SlaveAddress = slave << 1; /* 8 bit addresses */ + req->NumCmds = bytes_to_transfer; - return ret; -} + remaining_bytes = bytes_to_transfer; + c = 0; + for (i = 0; i < num; i++) { + struct i2c_msg *msg = [i]; -static int arcturus_i2c_write_data(struct i2c_adapter *control, - uint8_t address, -
[PATCH 29/43] drm/amd/pm: Extend the I2C quirk table
Extend the I2C quirk table for SMU access controlled I2C adapters. Let the kernel I2C layer check that the messages all have the same address, and that their combined size doesn't exceed the maximum size of a SMU software I2C request. Suggested-by: Jean Delvare Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 5 - drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 5 - drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 5 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 9fccdd2d3e73ec..3286c704bd08df 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2036,8 +2036,11 @@ static const struct i2c_algorithm arcturus_i2c_algo = { static const struct i2c_adapter_quirks arcturus_i2c_control_quirks = { - .max_read_len = MAX_SW_I2C_COMMANDS, + .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR, + .max_read_len = MAX_SW_I2C_COMMANDS, .max_write_len = MAX_SW_I2C_COMMANDS, + .max_comb_1st_msg_len = 2, + .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2, }; static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 5cecb4be57c554..9c171122384336 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2834,8 +2834,11 @@ static const struct i2c_algorithm navi10_i2c_algo = { }; static const struct i2c_adapter_quirks navi10_i2c_control_quirks = { - .max_read_len = MAX_SW_I2C_COMMANDS, + .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR, + .max_read_len = MAX_SW_I2C_COMMANDS, .max_write_len = MAX_SW_I2C_COMMANDS, + .max_comb_1st_msg_len = 2, + .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2, }; static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 2444e13c4901b3..37cfe0ccd6863b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3541,8 +3541,11 @@ static const struct i2c_algorithm sienna_cichlid_i2c_algo = { }; static const struct i2c_adapter_quirks sienna_cichlid_i2c_control_quirks = { - .max_read_len = MAX_SW_I2C_COMMANDS, + .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR, + .max_read_len = MAX_SW_I2C_COMMANDS, .max_write_len = MAX_SW_I2C_COMMANDS, + .max_comb_1st_msg_len = 2, + .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2, }; static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 02/43] drm/amdgpu/pm: rework i2c xfers on sienna cichlid (v4)
From: Alex Deucher Make it generic so we can support more than just EEPROMs. v2: fix restart handling between transactions. v3: handle 7 to 8 bit addr conversion v4: Fix --> req. (Luben T) Signed-off-by: Alex Deucher Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov --- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 229 +- 1 file changed, 58 insertions(+), 171 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index c751f717a0daff..b4aa489e4a431a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3442,197 +3442,84 @@ static void sienna_cichlid_dump_pptable(struct smu_context *smu) dev_info(smu->adev->dev, "MmHubPadding[7] = 0x%x\n", pptable->MmHubPadding[7]); } -static void sienna_cichlid_fill_i2c_req(SwI2cRequest_t *req, bool write, - uint8_t address, uint32_t numbytes, - uint8_t *data) -{ - int i; - - req->I2CcontrollerPort = 1; - req->I2CSpeed = 2; - req->SlaveAddress = address; - req->NumCmds = numbytes; - - for (i = 0; i < numbytes; i++) { - SwI2cCmd_t *cmd = >SwI2cCmds[i]; - - /* First 2 bytes are always write for lower 2b EEPROM address */ - if (i < 2) - cmd->CmdConfig = CMDCONFIG_READWRITE_MASK; - else - cmd->CmdConfig = write ? CMDCONFIG_READWRITE_MASK : 0; - - - /* Add RESTART for read after address filled */ - cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0; - - /* Add STOP in the end */ - cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0; - - /* Fill with data regardless if read or write to simplify code */ - cmd->ReadWriteData = data[i]; - } -} - -static int sienna_cichlid_i2c_read_data(struct i2c_adapter *control, - uint8_t address, - uint8_t *data, - uint32_t numbytes) +static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) { - uint32_t i, ret = 0; - SwI2cRequest_t req; - struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct smu_table_context *smu_table = >smu.smu_table; struct smu_table *table = _table->driver_table; - - if (numbytes > MAX_SW_I2C_COMMANDS) { - dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", - numbytes, MAX_SW_I2C_COMMANDS); - return -EINVAL; + SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; + u16 bytes_to_transfer, remaining_bytes, msg_bytes; + u16 available_bytes = MAX_SW_I2C_COMMANDS; + int i, j, r, c; + u8 slave; + + /* only support a single slave addr per transaction */ + slave = msgs[0].addr; + for (i = 0; i < num; i++) { + if (slave != msgs[i].addr) + return -EINVAL; + bytes_to_transfer += min(msgs[i].len, available_bytes); + available_bytes -= bytes_to_transfer; } - memset(, 0, sizeof(req)); - sienna_cichlid_fill_i2c_req(, false, address, numbytes, data); - - mutex_lock(>smu.mutex); - /* Now read data starting with that address */ - ret = smu_cmn_update_table(>smu, SMU_TABLE_I2C_COMMANDS, 0, , - true); - mutex_unlock(>smu.mutex); - - if (!ret) { - SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr; - - /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */ - for (i = 0; i < numbytes; i++) - data[i] = res->SwI2cCmds[i].ReadWriteData; - - dev_dbg(adev->dev, "sienna_cichlid_i2c_read_data, address = %x, bytes = %d, data :", - (uint16_t)address, numbytes); + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; - print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, - 8, 1, data, numbytes, false); - } else - dev_err(adev->dev, "sienna_cichlid_i2c_read_data - error occurred :%x", ret); + req->I2CcontrollerPort = 1; + req->I2CSpeed = I2C_SPEED_FAST_400K; + req->SlaveAddress = slave << 1; /* 8 bit addresses */ + req->NumCmds = bytes_to_transfer; - return ret; -} + remaining_bytes = bytes_to_transfer; + c = 0; + for (i = 0; i < num; i++) { +
[PATCH 00/43] I2C fixes (revision 2)
I2C fixes from various people. Some RAS touch-ups too. A rebased tree can also be found here: https://gitlab.freedesktop.org/ltuikov/linux/-/commits/i2c-rework-luben Tested on Vega20 and Sienna Cichlid. This first revision includes acks, squashes patch 33 by absolving it into earlier commits it fixes, and includes a new patch, patch 40 to deal with driver aborts seen on large writes to an I2C EEPROM device. The second revision includes more Ack and R-B tags, and also includes a break up of revision 1 patch number 36, into 4 patches, in order to better show amdgpu_ras_eeprom.c rewrite. Regards, Luben Aaron Rice (1): drm/amdgpu: rework smu11 i2c for generic operation Alex Deucher (10): drm/amdgpu: add a mutex for the smu11 i2c bus (v2) drm/amdgpu/pm: rework i2c xfers on sienna cichlid (v4) drm/amdgpu/pm: rework i2c xfers on arcturus (v4) drm/amdgpu/pm: add smu i2c implementation for navi1x (v4) drm/amdgpu: add new helper for handling EEPROM i2c transfers drm/amdgpu/ras: switch ras eeprom handling to use generic helper drm/amdgpu/ras: switch fru eeprom handling to use generic helper (v2) drm/amdgpu: i2c subsystem uses 7 bit addresses drm/amdgpu: add I2C_CLASS_HWMON to SMU i2c buses drm/amdgpu: only set restart on first cmd of the smu i2c transaction Andrey Grodzovsky (6): drm/amdgpu: Remember to wait 10ms for write buffer flush v2 dmr/amdgpu: Add RESTART handling also to smu_v11_0_i2c (VG20) drm/amdgpu: Drop i > 0 restriction for issuing RESTART drm/amdgpu: Send STOP for the last byte of msg only drm/amd/pm: SMU I2C: Return number of messages processed drm/amdgpu/pm: ADD I2C quirk adapter table Luben Tuikov (26): drm/amdgpu: Fix Vega20 I2C to be agnostic (v2) drm/amdgpu: Fixes to the AMDGPU EEPROM driver drm/amdgpu: EEPROM respects I2C quirks drm/amdgpu: I2C EEPROM full memory addressing drm/amdgpu: RAS and FRU now use 19-bit I2C address drm/amdgpu: Fix wrap-around bugs in RAS drm/amdgpu: I2C class is HWMON drm/amdgpu: RAS: EEPROM --> RAS drm/amdgpu: Rename misspelled function drm/amdgpu: RAS xfer to read/write drm/amdgpu: EEPROM: add explicit read and write drm/amd/pm: Extend the I2C quirk table drm/amd/pm: Simplify managed I2C transfer functions drm/amdgpu: Fix width of I2C address drm/amdgpu: Return result fix in RAS drm/amdgpu: Fix amdgpu_ras_eeprom_init() drm/amdgpu: Simplify RAS EEPROM checksum calculations drm/amdgpu: Use explicit cardinality for clarity drm/amdgpu: Nerf buff drm/amdgpu: Some renames drm/amdgpu: Get rid of test function drm/amdgpu: Optimize EEPROM RAS table I/O drm/amdgpu: RAS EEPROM table is now in debugfs drm/amdgpu: Fix koops when accessing RAS EEPROM drm/amdgpu: Use a single loop drm/amdgpu: Correctly disable the I2C IP block drivers/gpu/drm/amd/amdgpu/Makefile |3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c |9 +- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c| 239 drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h| 37 + .../gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c| 32 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 116 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h |1 + .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 1253 +++-- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 70 +- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c |2 +- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c| 319 +++-- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h |1 + .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 238 +--- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 118 ++ .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 241 +--- 15 files changed, 1685 insertions(+), 994 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Guchun Chen Cc: Hawking Zhang Cc: Jean Delvare Cc: John Clements Cc: Lijo Lazar Cc: Stanley Yang Cc: Xinhui Pan base-commit: 5d880fc07b8caaf734a066af61aef8d8c84da04c -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 12/43] drm/amdgpu: Remember to wait 10ms for write buffer flush v2
From: Andrey Grodzovsky EEPROM spec requests this. v2: Only to be done for write data transactions. Signed-off-by: Andrey Grodzovsky Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index 10551660343278..fe0e9b0c4d5a38 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -55,6 +55,21 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, r = i2c_transfer(i2c_adap, msgs, ARRAY_SIZE(msgs)); if (r <= 0) return r; + + /* Only for write data */ + if (!msgs[1].flags) + /* +* According to EEPROM spec there is a MAX of 10 ms required for +* EEPROM to flush internal RX buffer after STOP was issued at the +* end of write transaction. During this time the EEPROM will not be +* responsive to any more commands - so wait a bit more. +* +* TODO Improve to wait for first ACK for slave address after +* internal write cycle done. +*/ + msleep(10); + + bytes_transferred = r - EEPROM_OFFSET_LENGTH; eeprom_addr += bytes_transferred; msgs[0].buf[0] = ((eeprom_addr >> 8) & 0xff); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 26/43] drm/amdgpu: Rename misspelled function
Instead of fixing the spelling in amdgpu_ras_eeprom_process_recods(), rename it to, amdgpu_ras_eeprom_xfer(), to look similar to other I2C and protocol transfer (read/write) functions. Also to keep the column span to within reason by using a shorter name. Change the "num" function parameter from "int" to "const u32" since it is the number of items (records) to xfer, i.e. their count, which cannot be a negative number. Also swap the order of parameters, keeping the pointer to records and their number next to each other, while the direction now becomes the last parameter. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c| 11 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 10 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 7 +++ 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 44a4363cace737..96a2f42d57bb2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1817,10 +1817,10 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) save_count = data->count - control->num_recs; /* only new entries are saved */ if (save_count > 0) { - if (amdgpu_ras_eeprom_process_recods(control, - >bps[control->num_recs], - true, - save_count)) { + if (amdgpu_ras_eeprom_xfer(control, + >bps[control->num_recs], + save_count, + true)) { dev_err(adev->dev, "Failed to save EEPROM table data!"); return -EIO; } @@ -1850,8 +1850,7 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) if (!bps) return -ENOMEM; - if (amdgpu_ras_eeprom_process_recods(control, bps, false, - control->num_recs)) { + if (amdgpu_ras_eeprom_xfer(control, bps, control->num_recs, false)) { dev_err(adev->dev, "Failed to load EEPROM table records!"); ret = -EIO; goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index d3678706bb736d..9e3fbc44b4bc4a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -432,9 +432,9 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev) return false; } -int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, -struct eeprom_table_record *records, -bool write, int num) +int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, + const u32 num, bool write) { int i, ret = 0; unsigned char *buffs, *buff; @@ -574,13 +574,13 @@ void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control) recs[i].retired_page = i; } - if (!amdgpu_ras_eeprom_process_recods(control, recs, true, 1)) { + if (!amdgpu_ras_eeprom_xfer(control, recs, 1, true)) { memset(recs, 0, sizeof(*recs) * 1); control->next_addr = RAS_RECORD_START; - if (!amdgpu_ras_eeprom_process_recods(control, recs, false, 1)) { + if (!amdgpu_ras_eeprom_xfer(control, recs, 1, false)) { for (i = 0; i < 1; i++) DRM_INFO("rec.address :0x%llx, rec.retired_page :%llu", recs[i].address, recs[i].retired_page); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index 4c4c3d840a35c5..6a1bd527bce57a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -82,10 +82,9 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control); bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev); -int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, - bool write, - int num); +int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, +
[PATCH 04/43] drm/amdgpu/pm: add smu i2c implementation for navi1x (v4)
From: Alex Deucher And handle more than just EEPROMs. v2: fix restart handling between transactions. v3: handle 7 to 8 bit addr conversion v4: Fix --> req. (Luben T) Signed-off-by: Alex Deucher Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov --- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 116 ++ 1 file changed, 116 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 1ba42b69ce7424..e02db86ced6108 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2735,6 +2735,120 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, return sizeof(struct gpu_metrics_v1_3); } +static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); + struct smu_table_context *smu_table = >smu.smu_table; + struct smu_table *table = _table->driver_table; + SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; + u16 bytes_to_transfer, remaining_bytes, msg_bytes; + u16 available_bytes = MAX_SW_I2C_COMMANDS; + int i, j, r, c; + u8 slave; + + /* only support a single slave addr per transaction */ + slave = msgs[0].addr; + for (i = 0; i < num; i++) { + if (slave != msgs[i].addr) + return -EINVAL; + bytes_to_transfer += min(msgs[i].len, available_bytes); + available_bytes -= bytes_to_transfer; + } + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->I2CcontrollerPort = 1; + req->I2CSpeed = I2C_SPEED_FAST_400K; + req->SlaveAddress = slave << 1; /* 8 bit addresses */ + req->NumCmds = bytes_to_transfer; + + remaining_bytes = bytes_to_transfer; + c = 0; + for (i = 0; i < num; i++) { + struct i2c_msg *msg = [i]; + + msg_bytes = min(msg->len, remaining_bytes); + for (j = 0; j < msg_bytes; j++) { + SwI2cCmd_t *cmd = >SwI2cCmds[c++]; + + remaining_bytes--; + if (!(msg[i].flags & I2C_M_RD)) { + /* write */ + cmd->CmdConfig |= I2C_CMD_WRITE; + cmd->RegisterAddr = msg->buf[j]; + } + if ((msg[i].flags & I2C_M_STOP) || + (!remaining_bytes)) + cmd->CmdConfig |= CMDCONFIG_STOP_MASK; + if ((i > 0) && !(msg[i].flags & I2C_M_NOSTART)) + cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; + } + } + mutex_lock(>smu.mutex); + r = smu_cmn_update_table(>smu, SMU_TABLE_I2C_COMMANDS, 0, req, true); + mutex_unlock(>smu.mutex); + if (r) + goto fail; + + remaining_bytes = bytes_to_transfer; + c = 0; + for (i = 0; i < num; i++) { + struct i2c_msg *msg = [i]; + + msg_bytes = min(msg->len, remaining_bytes); + for (j = 0; j < msg_bytes; j++) { + SwI2cCmd_t *cmd = >SwI2cCmds[c++]; + + remaining_bytes--; + if (msg[i].flags & I2C_M_RD) + msg->buf[j] = cmd->Data; + } + } + r = bytes_to_transfer; + +fail: + kfree(req); + + return r; +} + +static u32 navi10_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm navi10_i2c_algo = { + .master_xfer = navi10_i2c_xfer, + .functionality = navi10_i2c_func, +}; + +static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + int res; + + control->owner = THIS_MODULE; + control->class = I2C_CLASS_SPD; + control->dev.parent = >pdev->dev; + control->algo = _i2c_algo; + snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + + res = i2c_add_adapter(control); + if (res) + DRM_ERROR("Failed to register hw i2c, err: %d\n", res); + + return res; +} + +static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control) +{ + i2c_del_adapter(control); +} + static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, void **table) { @@ -3078,6 +3192,8 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_default_dpm_table = navi10_set_default_dpm_table, .dpm_set_vcn_enable = navi10_dpm_set_vcn_enable, .dpm_set_jpeg_enable =
[PATCH 14/43] drm/amdgpu: Drop i > 0 restriction for issuing RESTART
From: Andrey Grodzovsky Drop i > 0 restriction for issuing RESTART. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 843eb2357afaaf..a6d6ea1ef9e31b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1984,7 +1984,7 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index abb3647ea0a892..e682bbd3c26d82 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2783,7 +2783,7 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 9e49505a6ac109..93acf3f869227a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3490,7 +3490,7 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 11/43] drm/amdgpu: only set restart on first cmd of the smu i2c transaction
From: Alex Deucher Not sure how the firmware interprets these. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 404afc9979c69b..843eb2357afaaf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1984,7 +1984,7 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 3303830afac7d0..abb3647ea0a892 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2783,7 +2783,7 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 1d06641ad87890..9e49505a6ac109 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3490,7 +3490,7 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, if ((msg[i].flags & I2C_M_STOP) || (!remaining_bytes)) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; - if ((i > 0) && !(msg[i].flags & I2C_M_NOSTART)) + if ((i > 0) && (j == 0) && !(msg[i].flags & I2C_M_NOSTART)) cmd->CmdConfig |= CMDCONFIG_RESTART_BIT; } } -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 27/43] drm/amdgpu: RAS xfer to read/write
Wrap amdgpu_ras_eeprom_xfer(..., bool write), into amdgpu_ras_eeprom_read() and amdgpu_ras_eeprom_write(), as that makes reading and understanding the code clearer. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 9 --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 24 +++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h| 8 --- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 96a2f42d57bb2c..a9af6d0a2ed6bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1817,10 +1817,9 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) save_count = data->count - control->num_recs; /* only new entries are saved */ if (save_count > 0) { - if (amdgpu_ras_eeprom_xfer(control, - >bps[control->num_recs], - save_count, - true)) { + if (amdgpu_ras_eeprom_write(control, + >bps[control->num_recs], + save_count)) { dev_err(adev->dev, "Failed to save EEPROM table data!"); return -EIO; } @@ -1850,7 +1849,7 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) if (!bps) return -ENOMEM; - if (amdgpu_ras_eeprom_xfer(control, bps, control->num_recs, false)) { + if (amdgpu_ras_eeprom_read(control, bps, control->num_recs)) { dev_err(adev->dev, "Failed to load EEPROM table records!"); ret = -EIO; goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 9e3fbc44b4bc4a..550a31953d2da1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -432,9 +432,9 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev) return false; } -int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, - const u32 num, bool write) +static int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, + const u32 num, bool write) { int i, ret = 0; unsigned char *buffs, *buff; @@ -554,6 +554,20 @@ int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, return ret == num ? 0 : -EIO; } +int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, + const u32 num) +{ + return amdgpu_ras_eeprom_xfer(control, records, num, false); +} + +int amdgpu_ras_eeprom_write(struct amdgpu_ras_eeprom_control *control, + struct eeprom_table_record *records, + const u32 num) +{ + return amdgpu_ras_eeprom_xfer(control, records, num, true); +} + inline uint32_t amdgpu_ras_eeprom_get_record_max_length(void) { return RAS_MAX_RECORD_NUM; @@ -574,13 +588,13 @@ void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control) recs[i].retired_page = i; } - if (!amdgpu_ras_eeprom_xfer(control, recs, 1, true)) { + if (!amdgpu_ras_eeprom_write(control, recs, 1)) { memset(recs, 0, sizeof(*recs) * 1); control->next_addr = RAS_RECORD_START; - if (!amdgpu_ras_eeprom_xfer(control, recs, 1, false)) { + if (!amdgpu_ras_eeprom_read(control, recs)) { for (i = 0; i < 1; i++) DRM_INFO("rec.address :0x%llx, rec.retired_page :%llu", recs[i].address, recs[i].retired_page); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index 6a1bd527bce57a..fa9c509a8e2f2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -82,9 +82,11 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control); bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev); -int amdgpu_ras_eeprom_xfer(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *records, - const u32 num, bool write); +int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control
[PATCH 28/43] drm/amdgpu: EEPROM: add explicit read and write
Add explicit amdgpu_eeprom_read() and amdgpu_eeprom_write() for clarity. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h | 16 drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 10 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h index 417472be2712e6..966b434f0de2b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h @@ -29,4 +29,20 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, u8 *eeprom_buf, u16 bytes, bool read); +static inline int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, +u32 eeprom_addr, u8 *eeprom_buf, +u16 bytes) +{ + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + true); +} + +static inline int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, + u16 bytes) +{ + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + false); +} + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 69b9559f840ac3..7709caeb233d67 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -66,7 +66,7 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, { int ret, size; - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, addrptr, buff, 1, true); + ret = amdgpu_eeprom_read(>pm.smu_i2c, addrptr, buff, 1); if (ret < 1) { DRM_WARN("FRU: Failed to get size field"); return ret; @@ -77,8 +77,7 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, */ size = buff[0] - I2C_PRODUCT_INFO_OFFSET; - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, addrptr + 1, buff, size, -true); + ret = amdgpu_eeprom_read(>pm.smu_i2c, addrptr + 1, buff, size); if (ret < 1) { DRM_WARN("FRU: Failed to get data field"); return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 550a31953d2da1..17cea35275e46c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -151,9 +151,9 @@ static int __update_table_header(struct amdgpu_ras_eeprom_control *control, /* i2c may be unstable in gpu reset */ down_read(>reset_sem); - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, -control->i2c_address + RAS_HDR_START, -buff, RAS_TABLE_HEADER_SIZE, false); + ret = amdgpu_eeprom_write(>pm.smu_i2c, + control->i2c_address + RAS_HDR_START, + buff, RAS_TABLE_HEADER_SIZE); up_read(>reset_sem); if (ret < 1) @@ -298,9 +298,9 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, mutex_init(>tbl_mutex); /* Read/Create table header from EEPROM address 0 */ - ret = amdgpu_eeprom_xfer(>pm.smu_i2c, + ret = amdgpu_eeprom_read(>pm.smu_i2c, control->i2c_address + RAS_HDR_START, -buff, RAS_TABLE_HEADER_SIZE, true); +buff, RAS_TABLE_HEADER_SIZE); if (ret < 1) { DRM_ERROR("Failed to read EEPROM table header, ret:%d", ret); return ret; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 17/43] drm/amdgpu/pm: ADD I2C quirk adapter table
From: Andrey Grodzovsky To be used by kernel clients of the adapter. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Andrey Grodzovsky Suggested-by: Lazar Lijo Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov Reviewed-by: Alexander Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 7 +++ drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 6 ++ drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 6 ++ 3 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index c916ccc48bf67f..33210119a28ec1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2034,6 +2034,12 @@ static const struct i2c_algorithm arcturus_i2c_algo = { .functionality = arcturus_i2c_func, }; + +static const struct i2c_adapter_quirks arcturus_i2c_control_quirks = { + .max_read_len = MAX_SW_I2C_COMMANDS, + .max_write_len = MAX_SW_I2C_COMMANDS, +}; + static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -2043,6 +2049,7 @@ static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter control->class = I2C_CLASS_SPD | I2C_CLASS_HWMON; control->dev.parent = >pdev->dev; control->algo = _i2c_algo; + control->quirks = _i2c_control_quirks; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); res = i2c_add_adapter(control); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 7018716b6c8585..c9519a1a5ca633 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2833,6 +2833,11 @@ static const struct i2c_algorithm navi10_i2c_algo = { .functionality = navi10_i2c_func, }; +static const struct i2c_adapter_quirks navi10_i2c_control_quirks = { + .max_read_len = MAX_SW_I2C_COMMANDS, + .max_write_len = MAX_SW_I2C_COMMANDS, +}; + static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -2843,6 +2848,7 @@ static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter * control->dev.parent = >pdev->dev; control->algo = _i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + control->quirks = _i2c_control_quirks; res = i2c_add_adapter(control); if (res) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 8f8e5c7df44a12..9a14103cf9729f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3540,6 +3540,11 @@ static const struct i2c_algorithm sienna_cichlid_i2c_algo = { .functionality = sienna_cichlid_i2c_func, }; +static const struct i2c_adapter_quirks sienna_cichlid_i2c_control_quirks = { + .max_read_len = MAX_SW_I2C_COMMANDS, + .max_write_len = MAX_SW_I2C_COMMANDS, +}; + static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -3550,6 +3555,7 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_a control->dev.parent = >pdev->dev; control->algo = _cichlid_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + control->quirks = _cichlid_i2c_control_quirks; res = i2c_add_adapter(control); if (res) -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 20/43] drm/amdgpu: EEPROM respects I2C quirks
Consult the i2c_adapter.quirks table for the maximum read/write data length per bus transaction. Do not exceed this transaction limit. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 80 +- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index 7fdb5bd2fc8bc8..94aeda1c7f8ca0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -32,20 +32,9 @@ #define EEPROM_OFFSET_SIZE 2 -/** - * amdgpu_eeprom_xfer -- Read/write from/to an I2C EEPROM device - * @i2c_adap: pointer to the I2C adapter to use - * @slave_addr: I2C address of the slave device - * @eeprom_addr: EEPROM address from which to read/write - * @eeprom_buf: pointer to data buffer to read into/write from - * @buf_size: the size of @eeprom_buf - * @read: True if reading from the EEPROM, false if writing - * - * Returns the number of bytes read/written; -errno on error. - */ -int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, - u16 slave_addr, u16 eeprom_addr, - u8 *eeprom_buf, u16 buf_size, bool read) +static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, + u16 slave_addr, u16 eeprom_addr, + u8 *eeprom_buf, u16 buf_size, bool read) { u8 eeprom_offset_buf[EEPROM_OFFSET_SIZE]; struct i2c_msg msgs[] = { @@ -65,8 +54,8 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u16 len; r = 0; - for (len = 0; buf_size > 0; -buf_size -= len, eeprom_addr += len, eeprom_buf += len) { + for ( ; buf_size > 0; + buf_size -= len, eeprom_addr += len, eeprom_buf += len) { /* Set the EEPROM address we want to write to/read from. */ msgs[0].buf[0] = (eeprom_addr >> 8) & 0xff; @@ -120,3 +109,62 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, return r < 0 ? r : eeprom_buf - p; } + +/** + * amdgpu_eeprom_xfer -- Read/write from/to an I2C EEPROM device + * @i2c_adap: pointer to the I2C adapter to use + * @slave_addr: I2C address of the slave device + * @eeprom_addr: EEPROM address from which to read/write + * @eeprom_buf: pointer to data buffer to read into/write from + * @buf_size: the size of @eeprom_buf + * @read: True if reading from the EEPROM, false if writing + * + * Returns the number of bytes read/written; -errno on error. + */ +int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, + u16 slave_addr, u16 eeprom_addr, + u8 *eeprom_buf, u16 buf_size, bool read) +{ + const struct i2c_adapter_quirks *quirks = i2c_adap->quirks; + u16 limit; + + if (!quirks) + limit = 0; + else if (read) + limit = quirks->max_read_len; + else + limit = quirks->max_write_len; + + if (limit == 0) { + return __amdgpu_eeprom_xfer(i2c_adap, slave_addr, eeprom_addr, + eeprom_buf, buf_size, read); + } else if (limit <= EEPROM_OFFSET_SIZE) { + dev_err_ratelimited(_adap->dev, + "maddr:0x%04X size:0x%02X:quirk max_%s_len must be > %d", + eeprom_addr, buf_size, + read ? "read" : "write", EEPROM_OFFSET_SIZE); + return -EINVAL; + } else { + u16 ps; /* Partial size */ + int res = 0, r; + + /* The "limit" includes all data bytes sent/received, +* which would include the EEPROM_OFFSET_SIZE bytes. +* Account for them here. +*/ + limit -= EEPROM_OFFSET_SIZE; + for ( ; buf_size > 0; + buf_size -= ps, eeprom_addr += ps, eeprom_buf += ps) { + ps = min(limit, buf_size); + + r = __amdgpu_eeprom_xfer(i2c_adap, +slave_addr, eeprom_addr, +eeprom_buf, ps, read); + if (r < 0) + return r; + res += r; + } + + return res; + } +} -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 16/43] drm/amd/pm: SMU I2C: Return number of messages processed
From: Andrey Grodzovsky Fix from number of processed bytes to number of processed I2C messages. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Andrey Grodzovsky Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov Reviewed-by: Alexander Deucher --- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 43 +++ .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 43 +++ .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 43 +++ 3 files changed, 75 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index fde03bb6ffe7c8..c916ccc48bf67f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1943,9 +1943,8 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, struct smu_table_context *smu_table = >smu.smu_table; struct smu_table *table = _table->driver_table; SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; - u16 bytes_to_transfer, remaining_bytes, msg_bytes; - u16 available_bytes = MAX_SW_I2C_COMMANDS; - int i, j, r, c; + short available_bytes = MAX_SW_I2C_COMMANDS; + int i, j, r, c, num_done = 0; u8 slave; /* only support a single slave addr per transaction */ @@ -1953,8 +1952,15 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, for (i = 0; i < num; i++) { if (slave != msgs[i].addr) return -EINVAL; - bytes_to_transfer += min(msgs[i].len, available_bytes); - available_bytes -= bytes_to_transfer; + + available_bytes -= msgs[i].len; + if (available_bytes >= 0) { + num_done++; + } else { + /* This message and all the follwing won't be processed */ + available_bytes += msgs[i].len; + break; + } } req = kzalloc(sizeof(*req), GFP_KERNEL); @@ -1964,24 +1970,28 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, req->I2CcontrollerPort = 1; req->I2CSpeed = I2C_SPEED_FAST_400K; req->SlaveAddress = slave << 1; /* 8 bit addresses */ - req->NumCmds = bytes_to_transfer; + req->NumCmds = MAX_SW_I2C_COMMANDS - available_bytes;; - remaining_bytes = bytes_to_transfer; c = 0; - for (i = 0; i < num; i++) { + for (i = 0; i < num_done; i++) { struct i2c_msg *msg = [i]; - msg_bytes = min(msg->len, remaining_bytes); - for (j = 0; j < msg_bytes; j++) { + for (j = 0; j < msg->len; j++) { SwI2cCmd_t *cmd = >SwI2cCmds[c++]; - remaining_bytes--; if (!(msg[i].flags & I2C_M_RD)) { /* write */ cmd->CmdConfig |= I2C_CMD_WRITE; cmd->RegisterAddr = msg->buf[j]; } - if (!remaining_bytes) + + /* +* Insert STOP if we are at the last byte of either last +* message for the transaction or the client explicitly +* requires a STOP at this particular message. +*/ + if ((j == msg->len -1 ) && + ((i == num_done - 1) || (msg[i].flags & I2C_M_STOP))) cmd->CmdConfig |= CMDCONFIG_STOP_MASK; if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART)) @@ -1994,21 +2004,18 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, if (r) goto fail; - remaining_bytes = bytes_to_transfer; c = 0; - for (i = 0; i < num; i++) { + for (i = 0; i < num_done; i++) { struct i2c_msg *msg = [i]; - msg_bytes = min(msg->len, remaining_bytes); - for (j = 0; j < msg_bytes; j++) { + for (j = 0; j < msg->len; j++) { SwI2cCmd_t *cmd = >SwI2cCmds[c++]; - remaining_bytes--; if (msg[i].flags & I2C_M_RD) msg->buf[j] = cmd->Data; } } - r = bytes_to_transfer; + r = num_done; fail: kfree(req); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 8bd3fa2ef7efea..7018716b6c8585 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2742,9 +2742,8 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, struct
[PATCH 07/43] drm/amdgpu/ras: switch fru eeprom handling to use generic helper (v2)
From: Alex Deucher Use the new helper rather than doing i2c transfers directly. v2: fix typo Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- .../gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c| 22 +-- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 39b6c6bfab4533..224da573ba1b59 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -27,9 +27,9 @@ #include "smu_v11_0_i2c.h" #include "atom.h" #include "amdgpu_fru_eeprom.h" +#include "amdgpu_eeprom.h" #define I2C_PRODUCT_INFO_ADDR 0xAC -#define I2C_PRODUCT_INFO_ADDR_SIZE 0x2 #define I2C_PRODUCT_INFO_OFFSET0xC0 static bool is_fru_eeprom_supported(struct amdgpu_device *adev) @@ -65,16 +65,9 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, unsigned char *buff) { int ret, size; - struct i2c_msg msg = { - .addr = I2C_PRODUCT_INFO_ADDR, - .flags = I2C_M_RD, - .buf= buff, - }; - buff[0] = 0; - buff[1] = addrptr; - msg.len = I2C_PRODUCT_INFO_ADDR_SIZE + 1; - ret = i2c_transfer(>pm.smu_i2c, , 1); + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, I2C_PRODUCT_INFO_ADDR, +addrptr, buff, 1, true); if (ret < 1) { DRM_WARN("FRU: Failed to get size field"); return ret; @@ -83,13 +76,10 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, /* The size returned by the i2c requires subtraction of 0xC0 since the * size apparently always reports as 0xC0+actual size. */ - size = buff[2] - I2C_PRODUCT_INFO_OFFSET; - /* Add 1 since address field was 1 byte */ - buff[1] = addrptr + 1; - - msg.len = I2C_PRODUCT_INFO_ADDR_SIZE + size; - ret = i2c_transfer(>pm.smu_i2c, , 1); + size = buff[0] - I2C_PRODUCT_INFO_OFFSET; + ret = amdgpu_eeprom_xfer(>pm.smu_i2c, I2C_PRODUCT_INFO_ADDR, +addrptr + 1, buff, size, true); if (ret < 1) { DRM_WARN("FRU: Failed to get data field"); return ret; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 23/43] drm/amdgpu: Fix wrap-around bugs in RAS
Fix the size of the EEPROM from 256000 bytes to 262144 bytes (256 KiB). Fix a couple or wrap around bugs. If a valid value/address is 0 <= addr < size, the inverse of this inequality (barring negative values which make no sense here) is addr >= size. Fix this in the RAS code. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 20 +-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index f316fb11b16d9e..3ef38b90fc3a83 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -52,12 +52,11 @@ /* Bad GPU tag ‘BADG’ */ #define EEPROM_TABLE_HDR_BAD 0x42414447 -/* Assume 2 Mbit size */ -#define EEPROM_SIZE_BYTES 256000 -#define EEPROM_PAGE__SIZE_BYTES 256 -#define EEPROM_HDR_START 0 -#define EEPROM_RECORD_START (EEPROM_HDR_START + EEPROM_TABLE_HEADER_SIZE) -#define EEPROM_MAX_RECORD_NUM ((EEPROM_SIZE_BYTES - EEPROM_TABLE_HEADER_SIZE) / EEPROM_TABLE_RECORD_SIZE) +/* Assume 2-Mbit size */ +#define EEPROM_SIZE_BYTES (256 * 1024) +#define EEPROM_HDR_START0 +#define EEPROM_RECORD_START (EEPROM_HDR_START + EEPROM_TABLE_HEADER_SIZE) +#define EEPROM_MAX_RECORD_NUM ((EEPROM_SIZE_BYTES - EEPROM_TABLE_HEADER_SIZE) / EEPROM_TABLE_RECORD_SIZE) #define to_amdgpu_device(x) (container_of(x, struct amdgpu_ras, eeprom_control))->adev @@ -402,9 +401,8 @@ static uint32_t __correct_eeprom_dest_address(uint32_t curr_address) uint32_t next_address = curr_address + EEPROM_TABLE_RECORD_SIZE; /* When all EEPROM memory used jump back to 0 address */ - if (next_address > EEPROM_SIZE_BYTES) { - DRM_INFO("Reached end of EEPROM memory, jumping to 0 " -"and overriding old record"); + if (next_address >= EEPROM_SIZE_BYTES) { + DRM_INFO("Reached end of EEPROM memory, wrap around to 0."); return EEPROM_RECORD_START; } @@ -476,7 +474,9 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, } /* In case of overflow just start from beginning to not lose newest records */ - if (write && (control->next_addr + EEPROM_TABLE_RECORD_SIZE * num > EEPROM_SIZE_BYTES)) + if (write && + (control->next_addr + +EEPROM_TABLE_RECORD_SIZE * num >= EEPROM_SIZE_BYTES)) control->next_addr = EEPROM_RECORD_START; /* -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 10/43] drm/amdgpu: rework smu11 i2c for generic operation
From: Aaron Rice Handle things besides EEPROMS. Signed-off-by: Aaron Rice Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 47 +- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 3a164d93c90293..3193d566f4f87e 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -117,8 +117,7 @@ static void smu_v11_0_i2c_set_address(struct i2c_adapter *control, uint8_t addre { struct amdgpu_device *adev = to_amdgpu_device(control); - /* Convert fromr 8-bit to 7-bit address */ - address >>= 1; + /* We take 7-bit addresses raw */ WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_TAR, (address & 0xFF)); } @@ -531,22 +530,14 @@ static bool smu_v11_0_i2c_bus_unlock(struct i2c_adapter *control) /* I2C GLUE / static uint32_t smu_v11_0_i2c_read_data(struct i2c_adapter *control, - uint8_t address, - uint8_t *data, - uint32_t numbytes) + struct i2c_msg *msg) { uint32_t ret = 0; - /* First 2 bytes are dummy write to set EEPROM address */ - ret = smu_v11_0_i2c_transmit(control, address, data, 2, I2C_NO_STOP); - if (ret != I2C_OK) - goto Fail; - /* Now read data starting with that address */ - ret = smu_v11_0_i2c_receive(control, address, data + 2, numbytes - 2, + ret = smu_v11_0_i2c_receive(control, msg->addr, msg->buf, msg->len, I2C_RESTART); -Fail: if (ret != I2C_OK) DRM_ERROR("ReadData() - I2C error occurred :%x", ret); @@ -554,28 +545,16 @@ static uint32_t smu_v11_0_i2c_read_data(struct i2c_adapter *control, } static uint32_t smu_v11_0_i2c_write_data(struct i2c_adapter *control, -uint8_t address, -uint8_t *data, -uint32_t numbytes) + struct i2c_msg *msg) { uint32_t ret; - ret = smu_v11_0_i2c_transmit(control, address, data, numbytes, 0); + /* Send I2C_NO_STOP unless requested to stop. */ + ret = smu_v11_0_i2c_transmit(control, msg->addr, msg->buf, msg->len, ((msg->flags & I2C_M_STOP) ? 0 : I2C_NO_STOP)); if (ret != I2C_OK) DRM_ERROR("WriteI2CData() - I2C error occurred :%x", ret); - else - /* -* According to EEPROM spec there is a MAX of 10 ms required for -* EEPROM to flush internal RX buffer after STOP was issued at the -* end of write transaction. During this time the EEPROM will not be -* responsive to any more commands - so wait a bit more. -* -* TODO Improve to wait for first ACK for slave address after -* internal write cycle done. -*/ - msleep(10); - + return ret; } @@ -618,24 +597,16 @@ static int smu_v11_0_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { int i, ret; - struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); - - if (!adev->pm.bus_locked) { - DRM_ERROR("I2C bus unlocked, stopping transaction!"); - return -EIO; - } smu_v11_0_i2c_init(i2c_adap); for (i = 0; i < num; i++) { if (msgs[i].flags & I2C_M_RD) ret = smu_v11_0_i2c_read_data(i2c_adap, - (uint8_t)msgs[i].addr, - msgs[i].buf, msgs[i].len); + msgs + i); else ret = smu_v11_0_i2c_write_data(i2c_adap, - (uint8_t)msgs[i].addr, - msgs[i].buf, msgs[i].len); + msgs + i); if (ret != I2C_OK) { num = -EIO; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 21/43] drm/amdgpu: I2C EEPROM full memory addressing
* "eeprom_addr" is now 32-bit wide. * Remove "slave_addr" from the I2C EEPROM driver interface. The I2C EEPROM Device Type Identifier is fixed at 1010b, and the rest of the bits of the Device Address Byte/Device Select Code, are memory address bits, where the first three of those bits are the hardware selection bits. All this is now a 19-bit address and passed as "eeprom_addr". This abstracts the I2C bus for EEPROM devices for this I2C EEPROM driver. Now clients only pass the 19-bit EEPROM memory address, to the I2C EEPROM driver, as the 32-bit "eeprom_addr", from which they want to read from or write to. Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 88 +- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h | 4 +- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index 94aeda1c7f8ca0..a5a87affedabf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -24,7 +24,7 @@ #include "amdgpu_eeprom.h" #include "amdgpu.h" -/* AT24CM02 has a 256-byte write page size. +/* AT24CM02 and M24M02-R have a 256-byte write page size. */ #define EEPROM_PAGE_BITS 8 #define EEPROM_PAGE_SIZE (1U << EEPROM_PAGE_BITS) @@ -32,20 +32,72 @@ #define EEPROM_OFFSET_SIZE 2 -static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, - u16 slave_addr, u16 eeprom_addr, +/* EEPROM memory addresses are 19-bits long, which can + * be partitioned into 3, 8, 8 bits, for a total of 19. + * The upper 3 bits are sent as part of the 7-bit + * "Device Type Identifier"--an I2C concept, which for EEPROM devices + * is hard-coded as 1010b, indicating that it is an EEPROM + * device--this is the wire format, followed by the upper + * 3 bits of the 19-bit address, followed by the direction, + * followed by two bytes holding the rest of the 16-bits of + * the EEPROM memory address. The format on the wire for EEPROM + * devices is: 1010XYZD, A15:A8, A7:A0, + * Where D is the direction and sequenced out by the hardware. + * Bits XYZ are memory address bits 18, 17 and 16. + * These bits are compared to how pins 1-3 of the part are connected, + * depending on the size of the part, more on that later. + * + * Note that of this wire format, a client is in control + * of, and needs to specify only XYZ, A15:A8, A7:0, bits, + * which is exactly the EEPROM memory address, or offset, + * in order to address up to 8 EEPROM devices on the I2C bus. + * + * For instance, a 2-Mbit I2C EEPROM part, addresses all its bytes, + * using an 18-bit address, bit 17 to 0 and thus would use all but one bit of + * the 19 bits previously mentioned. The designer would then not connect + * pins 1 and 2, and pin 3 usually named "A_2" or "E2", would be connected to + * either Vcc or GND. This would allow for up to two 2-Mbit parts on + * the same bus, where one would be addressable with bit 18 as 1, and + * the other with bit 18 of the address as 0. + * + * For a 2-Mbit part, bit 18 is usually known as the "Chip Enable" or + * "Hardware Address Bit". This bit is compared to the load on pin 3 + * of the device, described above, and if there is a match, then this + * device responds to the command. This way, you can connect two + * 2-Mbit EEPROM devices on the same bus, but see one contiguous + * memory from 0 to 7h, where address 0 to 3 is in the device + * whose pin 3 is connected to GND, and address 4 to 7h is in + * the 2nd device, whose pin 3 is connected to Vcc. + * + * This addressing you encode in the 32-bit "eeprom_addr" below, + * namely the 19-bits "XYZ,A15:A0", as a single 19-bit address. For + * instance, eeprom_addr = 0x6DA01, is 110_1101_1010__0001, where + * XYZ=110b, and A15:A0=DA01h. The XYZ bits become part of the device + * address, and the rest of the address bits are sent as the memory + * address bytes. + * + * That is, for an I2C EEPROM driver everything is controlled by + * the "eeprom_addr". + * + * P.S. If you need to write, lock and read the Identification Page, + * (M24M02-DR device only, which we do not use), change the "7" to + * "0xF" in the macro below, and let the client set bit 20 to 1 in + * "eeprom_addr", and set A10 to 0 to write into it, and A10 and A1 to + * 1 to lock it permanently. + */ +#define MAKE_I2C_ADDR(_aa) ((0xA << 3) | (((_aa) >> 16) & 7)) + +static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, u8 *eeprom_buf, u16 buf_size, bool read) { u8 eeprom_offset_buf[EEPROM_OFFSET_SIZE]; struct i2c_msg msgs[] = { { - .addr = slave_addr, .flags = 0, .len
[PATCH 05/43] drm/amdgpu: add new helper for handling EEPROM i2c transfers
From: Alex Deucher Encapsulates the i2c protocol handling so other parts of the driver can just tell it the offset and size of data to write. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/Makefile| 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 67 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h | 34 +++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index c56320e78c0e1f..7d292485ca7cf2 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -57,7 +57,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \ amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \ amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ - amdgpu_fw_attestation.o amdgpu_securedisplay.o amdgpu_hdp.o + amdgpu_fw_attestation.o amdgpu_securedisplay.o amdgpu_hdp.o \ + amdgpu_eeprom.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c new file mode 100644 index 00..10551660343278 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "amdgpu_eeprom.h" +#include "amdgpu.h" + +#define EEPROM_OFFSET_LENGTH 2 + +int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, + u16 slave_addr, u16 eeprom_addr, + u8 *eeprom_buf, u16 bytes, bool read) +{ + u8 eeprom_offset_buf[2]; + u16 bytes_transferred; + struct i2c_msg msgs[] = { + { + .addr = slave_addr, + .flags = 0, + .len = EEPROM_OFFSET_LENGTH, + .buf = eeprom_offset_buf, + }, + { + .addr = slave_addr, + .flags = read ? I2C_M_RD: 0, + .len = bytes, + .buf = eeprom_buf, + } + }; + int r; + + msgs[0].buf[0] = ((eeprom_addr >> 8) & 0xff); + msgs[0].buf[1] = (eeprom_addr & 0xff); + + while (msgs[1].len) { + r = i2c_transfer(i2c_adap, msgs, ARRAY_SIZE(msgs)); + if (r <= 0) + return r; + bytes_transferred = r - EEPROM_OFFSET_LENGTH; + eeprom_addr += bytes_transferred; + msgs[0].buf[0] = ((eeprom_addr >> 8) & 0xff); + msgs[0].buf[1] = (eeprom_addr & 0xff); + msgs[1].buf += bytes_transferred; + msgs[1].len -= bytes_transferred; + } + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h new file mode 100644 index 00..9301e5678910ad --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of
[PATCH 25/43] drm/amdgpu: RAS: EEPROM --> RAS
In amdgpu_ras_eeprom.c--the interface from RAS to EEPROM, rename macros from EEPROM to RAS, to indicate that the quantities and objects are RAS specific, not EEPROM. We can decrease the RAS table, or put it in different offset of EEPROM as needed in the future. Remove EEPROM_ADDRESS_SIZE macro definition, equal to 2, from the file and calculations, as that quantity is computed and added on the stack, in the lower layer, amdgpu_eeprom_xfer(). Cc: Jean Delvare Cc: Alexander Deucher Cc: Andrey Grodzovsky Cc: Lijo Lazar Cc: Stanley Yang Cc: Hawking Zhang Signed-off-by: Luben Tuikov Acked-by: Alexander Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c| 103 +- 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 3ef38b90fc3a83..d3678706bb736d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -37,26 +37,25 @@ /* * The 2 macros bellow represent the actual size in bytes that * those entities occupy in the EEPROM memory. - * EEPROM_TABLE_RECORD_SIZE is different than sizeof(eeprom_table_record) which + * RAS_TABLE_RECORD_SIZE is different than sizeof(eeprom_table_record) which * uses uint64 to store 6b fields such as retired_page. */ -#define EEPROM_TABLE_HEADER_SIZE 20 -#define EEPROM_TABLE_RECORD_SIZE 24 - -#define EEPROM_ADDRESS_SIZE 0x2 +#define RAS_TABLE_HEADER_SIZE 20 +#define RAS_TABLE_RECORD_SIZE 24 /* Table hdr is 'AMDR' */ -#define EEPROM_TABLE_HDR_VAL 0x414d4452 -#define EEPROM_TABLE_VER 0x0001 +#define RAS_TABLE_HDR_VAL 0x414d4452 +#define RAS_TABLE_VER 0x0001 /* Bad GPU tag ‘BADG’ */ -#define EEPROM_TABLE_HDR_BAD 0x42414447 +#define RAS_TABLE_HDR_BAD 0x42414447 -/* Assume 2-Mbit size */ -#define EEPROM_SIZE_BYTES (256 * 1024) -#define EEPROM_HDR_START0 -#define EEPROM_RECORD_START (EEPROM_HDR_START + EEPROM_TABLE_HEADER_SIZE) -#define EEPROM_MAX_RECORD_NUM ((EEPROM_SIZE_BYTES - EEPROM_TABLE_HEADER_SIZE) / EEPROM_TABLE_RECORD_SIZE) +/* Assume 2-Mbit size EEPROM and take up the whole space. */ +#define RAS_TBL_SIZE_BYTES (256 * 1024) +#define RAS_HDR_START 0 +#define RAS_RECORD_START(RAS_HDR_START + RAS_TABLE_HEADER_SIZE) +#define RAS_MAX_RECORD_NUM ((RAS_TBL_SIZE_BYTES - RAS_TABLE_HEADER_SIZE) \ +/ RAS_TABLE_RECORD_SIZE) #define to_amdgpu_device(x) (container_of(x, struct amdgpu_ras, eeprom_control))->adev @@ -153,8 +152,8 @@ static int __update_table_header(struct amdgpu_ras_eeprom_control *control, /* i2c may be unstable in gpu reset */ down_read(>reset_sem); ret = amdgpu_eeprom_xfer(>pm.smu_i2c, -control->i2c_address + EEPROM_HDR_START, -buff, EEPROM_TABLE_HEADER_SIZE, false); +control->i2c_address + RAS_HDR_START, +buff, RAS_TABLE_HEADER_SIZE, false); up_read(>reset_sem); if (ret < 1) @@ -236,11 +235,11 @@ static int amdgpu_ras_eeprom_correct_header_tag( struct amdgpu_ras_eeprom_control *control, uint32_t header) { - unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE]; + unsigned char buff[RAS_TABLE_HEADER_SIZE]; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; int ret = 0; - memset(buff, 0, EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE); + memset(buff, 0, RAS_TABLE_HEADER_SIZE); mutex_lock(>tbl_mutex); hdr->header = header; @@ -252,20 +251,20 @@ static int amdgpu_ras_eeprom_correct_header_tag( int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) { - unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE] = { 0 }; + unsigned char buff[RAS_TABLE_HEADER_SIZE] = { 0 }; struct amdgpu_ras_eeprom_table_header *hdr = >tbl_hdr; int ret = 0; mutex_lock(>tbl_mutex); - hdr->header = EEPROM_TABLE_HDR_VAL; - hdr->version = EEPROM_TABLE_VER; - hdr->first_rec_offset = EEPROM_RECORD_START; - hdr->tbl_size = EEPROM_TABLE_HEADER_SIZE; + hdr->header = RAS_TABLE_HDR_VAL; + hdr->version = RAS_TABLE_VER; + hdr->first_rec_offset = RAS_RECORD_START; + hdr->tbl_size = RAS_TABLE_HEADER_SIZE; control->tbl_byte_sum = 0; __update_tbl_checksum(control, NULL, 0, 0); - control->next_addr = EEPROM_RECORD_START; + control->next_addr = RAS_RECORD_START; ret = __update_table_header(control, buff); @@ -280,7 +279,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); - unsigned char
[PATCH 01/43] drm/amdgpu: add a mutex for the smu11 i2c bus (v2)
From: Alex Deucher So we lock software as well as hardware access to the bus. v2: fix mutex handling. Signed-off-by: Alex Deucher Reviewed-by: Luben Tuikov --- drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 19 +-- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h| 1 + 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index 5c7d769aee3fba..1d8f6d5180e099 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -584,12 +584,11 @@ static void lock_bus(struct i2c_adapter *i2c, unsigned int flags) { struct amdgpu_device *adev = to_amdgpu_device(i2c); - if (!smu_v11_0_i2c_bus_lock(i2c)) { + mutex_lock(>pm.smu_i2c_mutex); + if (!smu_v11_0_i2c_bus_lock(i2c)) DRM_ERROR("Failed to lock the bus from SMU"); - return; - } - - adev->pm.bus_locked = true; + else + adev->pm.bus_locked = true; } static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags) @@ -602,12 +601,11 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) { struct amdgpu_device *adev = to_amdgpu_device(i2c); - if (!smu_v11_0_i2c_bus_unlock(i2c)) { + if (!smu_v11_0_i2c_bus_unlock(i2c)) DRM_ERROR("Failed to unlock the bus from SMU"); - return; - } - - adev->pm.bus_locked = false; + else + adev->pm.bus_locked = false; + mutex_unlock(>pm.smu_i2c_mutex); } static const struct i2c_lock_operations smu_v11_0_i2c_i2c_lock_ops = { @@ -665,6 +663,7 @@ int smu_v11_0_i2c_control_init(struct i2c_adapter *control) struct amdgpu_device *adev = to_amdgpu_device(control); int res; + mutex_init(>pm.smu_i2c_mutex); control->owner = THIS_MODULE; control->class = I2C_CLASS_SPD; control->dev.parent = >pdev->dev; diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index f6e0e7d8a00771..d03e6fa2bf1adf 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -450,6 +450,7 @@ struct amdgpu_pm { /* Used for I2C access to various EEPROMs on relevant ASICs */ struct i2c_adapter smu_i2c; + struct mutexsmu_i2c_mutex; struct list_headpm_attr_list; }; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2 umr 3/3] Enhance printing of page tables in AI+
Pulls print functions for GPUVM page tables on AI+ chips into their own set of generalized functions, so that we don't have subtly different printouts for different layers. Explicitly prints PDEs with P bit (which makes it a PTE) and makes the PTE with F bit set (further, which makes it a PDE) properly indent the next layer of the print. Prints remaining fields from the PTE and PDE printouts, such as read/write/execute bits and MTYPE from PTE. v2: Correctly handle printing translate-further PTEs Signed-off-by: Joseph Greathouse --- src/lib/read_vram.c | 184 ++-- 1 file changed, 127 insertions(+), 57 deletions(-) diff --git a/src/lib/read_vram.c b/src/lib/read_vram.c index 2998873..bea1232 100644 --- a/src/lib/read_vram.c +++ b/src/lib/read_vram.c @@ -415,6 +415,112 @@ static pte_fields_ai_t decode_pte_entry_ai(uint64_t pte_entry) return pte_fields; } +static void print_pde_fields_ai(struct umr_asic *asic, + pde_fields_ai_t pde_fields) +{ + asic->mem_funcs.vm_message( + ", PBA==0x%012" PRIx64 ", V=%" PRIu64 + ", S=%" PRIu64 ", C=%" PRIu64 + ", P=%" PRIu64 ", FS=%" PRIu64 "\n", + pde_fields.pte_base_addr, + pde_fields.valid, + pde_fields.system, + pde_fields.coherent, + pde_fields.pte, + pde_fields.frag_size); +} +static void print_base_ai(struct umr_asic *asic, + uint64_t pde_entry, uint64_t address, + uint64_t va_mask, pde_fields_ai_t pde_fields, + int is_base_not_pde) +{ + if (is_base_not_pde) + asic->mem_funcs.vm_message("BASE"); + else + asic->mem_funcs.vm_message("PDE"); + asic->mem_funcs.vm_message("=0x%016" PRIx64 ", VA=0x%012" PRIx64, + pde_entry, + address & va_mask); + print_pde_fields_ai(asic, pde_fields); +} + +static void print_pde_ai(struct umr_asic *asic, + const char * indentation, int pde_cnt, + int page_table_depth, uint64_t prev_addr, + uint64_t pde_idx, uint64_t pde_entry, uint64_t address, + uint64_t va_mask, pde_fields_ai_t pde_fields) +{ + asic->mem_funcs.vm_message("%s ", [18-pde_cnt*3]); + if (pde_fields.further) + asic->mem_funcs.vm_message("PTE-FURTHER"); + else + asic->mem_funcs.vm_message("PDE%d", page_table_depth - pde_cnt); + + asic->mem_funcs.vm_message("@{0x%" PRIx64 "/%" PRIx64 + "}=0x%016" PRIx64 ", VA=0x%012" PRIx64, + prev_addr, + pde_idx, + pde_entry, + address & va_mask); + print_pde_fields_ai(asic, pde_fields); +} + +static void print_pte_ai(struct umr_asic *asic, + const char * indentation, int pde_cnt, uint64_t prev_addr, + uint64_t pte_idx, uint64_t pte_entry, uint64_t address, + uint64_t va_mask, pte_fields_ai_t pte_fields) +{ + if (asic == NULL) { + asic->mem_funcs.vm_message("\\-> PTE"); + } else { + asic->mem_funcs.vm_message("%s ", + [18-pde_cnt*3]); + if (pte_fields.pde) + asic->mem_funcs.vm_message("PDE0-as-PTE"); + else + asic->mem_funcs.vm_message("PTE"); + asic->mem_funcs.vm_message("@{0x%" PRIx64 "/%" PRIx64"}", + prev_addr, + pte_idx); + } + asic->mem_funcs.vm_message("=0x%016" PRIx64 ", VA=0x%012" PRIx64 + ", PBA==0x%012" PRIx64 ", V=%" PRIu64 + ", S=%" PRIu64 ", C=%" PRIu64 ", Z=%" PRIu64 + ", X=%" PRIu64 ", R=%" PRIu64 ", W=%" PRIu64 + ", FS=%" PRIu64 ", T=%" PRIu64 ", MTYPE=", + pte_entry, + address & va_mask, + pte_fields.page_base_addr, + pte_fields.valid, + pte_fields.system, + pte_fields.coherent, + pte_fields.tmz, + pte_fields.execute, + pte_fields.read, + pte_fields.write, + pte_fields.fragment, + pte_fields.prt, + pte_fields.mtype); + switch (pte_fields.mtype) { + case 0: + asic->mem_funcs.vm_message("NC\n"); + break; + case 1: + asic->mem_funcs.vm_message("RW\n"); + break; + case 2: +
[PATCH 10/10] drm/amdkfd: protect svm_bo ref in case prange has forked
Keep track of all the pages inside of pranges referenced to the same svm_bo. This is done, by using the ref count inside this object. This makes sure the object has freed after the last prange is not longer at any GPU. Including references shared between a parent and child during a fork. Signed-off-by: Alex Sierra Change-Id: Ibfe5efbfed28c2d7681fe091264a5d0d5f3657b2 --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 10 -- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 10 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 10 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index acb9f64577a0..c8ca3252cbc2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -245,7 +245,7 @@ svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn) struct page *page; page = pfn_to_page(pfn); - page->zone_device_data = prange; + page->zone_device_data = prange->svm_bo; get_page(page); lock_page(page); } @@ -336,6 +336,7 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, svm_migrate_get_vram_page(prange, migrate->dst[i]); migrate->dst[i] = migrate_pfn(migrate->dst[i]); migrate->dst[i] |= MIGRATE_PFN_LOCKED; + svm_range_bo_ref(prange->svm_bo); } if (migrate->dst[i] & MIGRATE_PFN_VALID) { spage = migrate_pfn_to_page(migrate->src[i]); @@ -540,7 +541,12 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, static void svm_migrate_page_free(struct page *page) { - /* Keep this function to avoid warning */ + struct svm_range_bo *svm_bo = page->zone_device_data; + + if (svm_bo) { + pr_debug("svm_bo ref left: %d\n", kref_read(_bo->kref)); + svm_range_bo_unref(svm_bo); + } } static int diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index ebc1ae7e5193..4b5fc2375641 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -309,14 +309,6 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo) return true; } -static struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) -{ - if (svm_bo) - kref_get(_bo->kref); - - return svm_bo; -} - static void svm_range_bo_release(struct kref *kref) { struct svm_range_bo *svm_bo; @@ -355,7 +347,7 @@ static void svm_range_bo_release(struct kref *kref) kfree(svm_bo); } -static void svm_range_bo_unref(struct svm_range_bo *svm_bo) +void svm_range_bo_unref(struct svm_range_bo *svm_bo) { if (!svm_bo) return; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 27fbe1936493..21f693767a0d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -150,6 +150,14 @@ static inline void svm_range_unlock(struct svm_range *prange) mutex_unlock(>lock); } +static inline struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) +{ + if (svm_bo) + kref_get(_bo->kref); + + return svm_bo; +} + int svm_range_list_init(struct kfd_process *p); void svm_range_list_fini(struct kfd_process *p); int svm_ioctl(struct kfd_process *p, enum kfd_ioctl_svm_op op, uint64_t start, @@ -178,7 +186,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, void svm_range_free_dma_mappings(struct svm_range *prange); void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, void *owner); - +void svm_range_bo_unref(struct svm_range_bo *svm_bo); #else struct kfd_process; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 05/10] drm/amdkfd: classify and map mixed svm range pages in GPU
[Why] svm ranges can have mixed pages from device or system memory. A good example is, after a prange has been allocated in VRAM and a copy-on-write is triggered by a fork. This invalidates some pages inside the prange. Endding up in mixed pages. [How] By classifying each page inside a prange, based on its type. Device or system memory, during dma mapping call. If page corresponds to VRAM domain, a flag is set to its dma_addr entry for each GPU. Then, at the GPU page table mapping. All group of contiguous pages within the same type are mapped with their proper pte flags. v2: Instead of using ttm_res to calculate vram pfns in the svm_range. It is now done by setting the vram real physical address into drm_addr array. This makes more flexible VRAM management, plus removes the need to have a BO reference in the svm_range. v3: Remove mapping member from svm_range Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 73 ++-- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 2 +- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 2b4318646a75..3b05bc270732 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -119,11 +119,12 @@ static void svm_range_remove_notifier(struct svm_range *prange) } static int -svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr, +svm_range_dma_map_dev(struct amdgpu_device *adev, dma_addr_t **dma_addr, unsigned long *hmm_pfns, uint64_t npages) { enum dma_data_direction dir = DMA_BIDIRECTIONAL; dma_addr_t *addr = *dma_addr; + struct device *dev = adev->dev; struct page *page; int i, r; @@ -141,6 +142,14 @@ svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr, dma_unmap_page(dev, addr[i], PAGE_SIZE, dir); page = hmm_pfn_to_page(hmm_pfns[i]); + if (is_zone_device_page(page)) { + addr[i] = (hmm_pfns[i] << PAGE_SHIFT) + + adev->vm_manager.vram_base_offset - + adev->kfd.dev->pgmap.range.start; + addr[i] |= SVM_RANGE_VRAM_DOMAIN; + pr_debug("vram address detected: 0x%llx\n", addr[i]); + continue; + } addr[i] = dma_map_page(dev, page, 0, PAGE_SIZE, dir); r = dma_mapping_error(dev, addr[i]); if (r) { @@ -175,7 +184,7 @@ svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap, } adev = (struct amdgpu_device *)pdd->dev->kgd; - r = svm_range_dma_map_dev(adev->dev, >dma_addr[gpuidx], + r = svm_range_dma_map_dev(adev, >dma_addr[gpuidx], hmm_pfns, prange->npages); if (r) break; @@ -1003,21 +1012,22 @@ svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, } static uint64_t -svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) +svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange, + int domain) { struct amdgpu_device *bo_adev; uint32_t flags = prange->flags; uint32_t mapping_flags = 0; uint64_t pte_flags; - bool snoop = !prange->ttm_res; + bool snoop = (domain != SVM_RANGE_VRAM_DOMAIN); bool coherent = flags & KFD_IOCTL_SVM_FLAG_COHERENT; - if (prange->svm_bo && prange->ttm_res) + if (domain == SVM_RANGE_VRAM_DOMAIN) bo_adev = amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev); switch (adev->asic_type) { case CHIP_ARCTURUS: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1032,7 +1042,7 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) } break; case CHIP_ALDEBARAN: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1061,14 +1071,14 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE; pte_flags = AMDGPU_PTE_VALID; - pte_flags |= prange->ttm_res ? 0 : AMDGPU_PTE_SYSTEM; + pte_flags |= (domain == SVM_RANGE_VRAM_DOMAIN) ? 0 : AMDGPU_PTE_SYSTEM;
[PATCH 02/10] drm/amdkfd: add owner ref param to get hmm pages
The parameter is used in the dev_private_owner to decide if device pages in the range require to be migrated back to system memory, based if they are or not in the same memory domain. In this case, this reference could come from the same memory domain with devices connected to the same hive. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.c| 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 2741c28ff1b5..378c238c2099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -160,7 +160,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked) + bool mmap_locked, void *owner) { struct hmm_range *hmm_range; unsigned long timeout; @@ -185,6 +185,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, hmm_range->hmm_pfns = pfns; hmm_range->start = start; hmm_range->end = start + npages * PAGE_SIZE; + hmm_range->dev_private_owner = owner; /* Assuming 512MB takes maxmium 1 second to fault page address */ timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h index 7f7d37a457c3..14a3c1864085 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h @@ -34,7 +34,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked); + bool mmap_locked, void *owner); int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range); #if defined(CONFIG_HMM_MIRROR) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 7e7d8330d64b..c13f7fbfc070 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -709,7 +709,7 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages) readonly = amdgpu_ttm_tt_is_readonly(ttm); r = amdgpu_hmm_range_get_pages(>notifier, mm, pages, start, ttm->num_pages, >range, readonly, - false); + false, NULL); out_putmm: mmput(mm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index b665e9ff77e3..b939f353ac8c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1392,7 +1392,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true); + false, true, NULL); if (r) { pr_debug("failed %d to get svm range pages\n", r); goto unreserve_out; @@ -2657,7 +2657,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true); + false, true, NULL); if (!r) { amdgpu_hmm_range_get_pages_done(hmm_range); prange->validated_once = true; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 06/10] drm/amdkfd: skip invalid pages during migrations
Invalid pages can be the result of pages that have been migrated already due to copy-on-write procedure or pages that were never migrated to VRAM in first place. This is not an issue anymore, as pranges now support mixed memory domains (CPU/GPU). Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 38 +++- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index b298aa8dea4d..6fd68528c425 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -419,7 +419,6 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, size_t size; void *buf; int r = -ENOMEM; - int retry = 0; memset(, 0, sizeof(migrate)); migrate.vma = vma; @@ -438,7 +437,6 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, migrate.dst = migrate.src + npages; scratch = (dma_addr_t *)(migrate.dst + npages); -retry: r = migrate_vma_setup(); if (r) { pr_debug("failed %d prepare migrate svms 0x%p [0x%lx 0x%lx]\n", @@ -446,17 +444,9 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, goto out_free; } if (migrate.cpages != npages) { - pr_debug("collect 0x%lx/0x%llx pages, retry\n", migrate.cpages, + pr_debug("Partial migration. 0x%lx/0x%llx pages can be migrated\n", +migrate.cpages, npages); - migrate_vma_finalize(); - if (retry++ >= 3) { - r = -ENOMEM; - pr_debug("failed %d migrate svms 0x%p [0x%lx 0x%lx]\n", -r, prange->svms, prange->start, prange->last); - goto out_free; - } - - goto retry; } if (migrate.cpages) { @@ -547,9 +537,8 @@ static void svm_migrate_page_free(struct page *page) static int svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, struct migrate_vma *migrate, struct dma_fence **mfence, - dma_addr_t *scratch) + dma_addr_t *scratch, uint64_t npages) { - uint64_t npages = migrate->cpages; struct device *dev = adev->dev; uint64_t *src; dma_addr_t *dst; @@ -566,15 +555,23 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, src = (uint64_t *)(scratch + npages); dst = scratch; - for (i = 0, j = 0; i < npages; i++, j++, addr += PAGE_SIZE) { + for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) { struct page *spage; spage = migrate_pfn_to_page(migrate->src[i]); - if (!spage) { - pr_debug("failed get spage svms 0x%p [0x%lx 0x%lx]\n", + if (!spage || !is_zone_device_page(spage)) { + pr_debug("invalid page. Could be in CPU already svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start, prange->last); - r = -ENOMEM; - goto out_oom; + if (j) { + r = svm_migrate_copy_memory_gart(adev, dst + i - j, +src + i - j, j, + FROM_VRAM_TO_RAM, +mfence); + if (r) + goto out_oom; + j = 0; + } + continue; } src[i] = svm_migrate_addr(adev, spage); if (i > 0 && src[i] != src[i - 1] + PAGE_SIZE) { @@ -607,6 +604,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, migrate->dst[i] = migrate_pfn(page_to_pfn(dpage)); migrate->dst[i] |= MIGRATE_PFN_LOCKED; + j++; } r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j, @@ -664,7 +662,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, if (migrate.cpages) { r = svm_migrate_copy_to_ram(adev, prange, , , - scratch); + scratch, npages); migrate_vma_pages(); svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org
[PATCH 07/10] drm/amdkfd: skip migration for pages already in VRAM
Migration skipped for pages that are already in VRAM domain. These could be the result of previous partial migrations to SYS RAM, and prefetch back to VRAM. Ex. Coherent pages in VRAM that were not written/invalidated after a copy-on-write. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 17 + 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 6fd68528c425..8a3f21d76915 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -329,14 +329,15 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, for (i = j = 0; i < npages; i++) { struct page *spage; - dst[i] = vram_addr + (j << PAGE_SHIFT); - migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); - svm_migrate_get_vram_page(prange, migrate->dst[i]); - - migrate->dst[i] = migrate_pfn(migrate->dst[i]); - migrate->dst[i] |= MIGRATE_PFN_LOCKED; - - if (migrate->src[i] & MIGRATE_PFN_VALID) { + spage = migrate_pfn_to_page(migrate->src[i]); + if (spage && !is_zone_device_page(spage)) { + dst[i] = vram_addr + (j << PAGE_SHIFT); + migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); + svm_migrate_get_vram_page(prange, migrate->dst[i]); + migrate->dst[i] = migrate_pfn(migrate->dst[i]); + migrate->dst[i] |= MIGRATE_PFN_LOCKED; + } + if (migrate->dst[i] & MIGRATE_PFN_VALID) { spage = migrate_pfn_to_page(migrate->src[i]); src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE, DMA_TO_DEVICE); -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 03/10] drm/amdkfd: set owner ref to svm range prefault
svm_range_prefault is called right before migrations to VRAM, to make sure pages are resident in system memory before the migration. With partial migrations, this reference is used by hmm range get pages to avoid migrating pages that are already in the same VRAM domain. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 5 +++-- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 11f7f590c6ec..b298aa8dea4d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -512,7 +512,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, prange->start, prange->last, best_loc); /* FIXME: workaround for page locking bug with invalid pages */ - svm_range_prefault(prange, mm); + svm_range_prefault(prange, mm, SVM_ADEV_PGMAP_OWNER(adev)); start = prange->start << PAGE_SHIFT; end = (prange->last + 1) << PAGE_SHIFT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index b939f353ac8c..54f47b09b14a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2646,7 +2646,8 @@ svm_range_best_prefetch_location(struct svm_range *prange) /* FIXME: This is a workaround for page locking bug when some pages are * invalid during migration to VRAM */ -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner) { struct hmm_range *hmm_range; int r; @@ -2657,7 +2658,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true, NULL); + false, true, owner); if (!r) { amdgpu_hmm_range_get_pages_done(hmm_range); prange->validated_once = true; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 4297250f259d..08542fe39303 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -176,7 +176,8 @@ void schedule_deferred_list_work(struct svm_range_list *svms); void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, unsigned long offset, unsigned long npages); void svm_range_free_dma_mappings(struct svm_range *prange); -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm); +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner); #else -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 01/10] drm/amdkfd: device pgmap owner at the svm migrate init
pgmap owner member at the svm migrate init could be referenced to either adev or hive, depending on device topology. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 6 +++--- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index fd8f544f0de2..11f7f590c6ec 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -426,7 +426,7 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_SYSTEM; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -641,7 +641,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -907,7 +907,7 @@ int svm_migrate_init(struct amdgpu_device *adev) pgmap->range.start = res->start; pgmap->range.end = res->end; pgmap->ops = _migrate_pgmap_ops; - pgmap->owner = adev; + pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev); pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; r = devm_memremap_pages(adev->dev, pgmap); if (IS_ERR(r)) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 573f984b81fe..4297250f259d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -35,6 +35,9 @@ #include "amdgpu.h" #include "kfd_priv.h" +#define SVM_ADEV_PGMAP_OWNER(adev)\ + ((adev)->hive ? (void *)(adev)->hive : (void *)(adev)) + struct svm_range_bo { struct amdgpu_bo*bo; struct kref kref; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 09/10] drm/amdkfd: partially actual_loc removed
actual_loc should not be used anymore, as pranges could have mixed locations (VRAM & SYSRAM) at the same time. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 12 +--- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 71 ++-- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index f71f8d7e2b72..acb9f64577a0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -501,12 +501,6 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, struct amdgpu_device *adev; int r = 0; - if (prange->actual_loc == best_loc) { - pr_debug("svms 0x%p [0x%lx 0x%lx] already on best_loc 0x%x\n", -prange->svms, prange->start, prange->last, best_loc); - return 0; - } - adev = svm_range_get_adev_by_id(prange, best_loc); if (!adev) { pr_debug("failed to get device by id 0x%x\n", best_loc); @@ -791,11 +785,7 @@ int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, struct mm_struct *mm) { - if (!prange->actual_loc) - return svm_migrate_ram_to_vram(prange, best_loc, mm); - else - return svm_migrate_vram_to_vram(prange, best_loc, mm); - + return svm_migrate_ram_to_vram(prange, best_loc, mm); } /** diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 3b05bc270732..ebc1ae7e5193 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1421,42 +1421,38 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_reserve_bos(); - if (!prange->actual_loc) { - p = container_of(prange->svms, struct kfd_process, svms); - owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, - MAX_GPU_INSTANCE)); - for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { - if (kfd_svm_page_owner(p, idx) != owner) { - owner = NULL; - break; - } - } - r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, - prange->start << PAGE_SHIFT, - prange->npages, _range, - false, true, owner); - if (r) { - pr_debug("failed %d to get svm range pages\n", r); - goto unreserve_out; - } - - r = svm_range_dma_map(prange, ctx.bitmap, - hmm_range->hmm_pfns); - if (r) { - pr_debug("failed %d to dma map range\n", r); - goto unreserve_out; + p = container_of(prange->svms, struct kfd_process, svms); + owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, + MAX_GPU_INSTANCE)); + for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { + if (kfd_svm_page_owner(p, idx) != owner) { + owner = NULL; + break; } + } + r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, + prange->start << PAGE_SHIFT, + prange->npages, _range, + false, true, owner); + if (r) { + pr_debug("failed %d to get svm range pages\n", r); + goto unreserve_out; + } - prange->validated_once = true; + r = svm_range_dma_map(prange, ctx.bitmap, + hmm_range->hmm_pfns); + if (r) { + pr_debug("failed %d to dma map range\n", r); + goto unreserve_out; } + prange->validated_once = true; + svm_range_lock(prange); - if (!prange->actual_loc) { - if (amdgpu_hmm_range_get_pages_done(hmm_range)) { - pr_debug("hmm update the range, need validate again\n"); - r = -EAGAIN; - goto unlock_out; - } + if (amdgpu_hmm_range_get_pages_done(hmm_range)) { + pr_debug("hmm update the range, need validate again\n"); + r = -EAGAIN; + goto unlock_out; } if (!list_empty(>child_list)) { pr_debug("range split by unmap in parallel, validate again\n"); @@ -2741,20 +2737,9 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, *migrated = false; best_loc = svm_range_best_prefetch_location(prange);
[PATCH 08/10] drm/amdkfd: add invalid pages debug at vram migration
This is for debug purposes only. It conditionally generates partial migrations to test mixed CPU/GPU memory domain pages in a prange easily. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 8a3f21d76915..f71f8d7e2b72 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -404,6 +404,20 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, } } +#ifdef DEBUG_FORCE_MIXED_DOMAINS + for (i = 0, j = 0; i < npages; i += 4, j++) { + if (j & 1) + continue; + svm_migrate_put_vram_page(adev, dst[i]); + migrate->dst[i] = 0; + svm_migrate_put_vram_page(adev, dst[i + 1]); + migrate->dst[i + 1] = 0; + svm_migrate_put_vram_page(adev, dst[i + 2]); + migrate->dst[i + 2] = 0; + svm_migrate_put_vram_page(adev, dst[i + 3]); + migrate->dst[i + 3] = 0; + } +#endif out: return r; } -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 04/10] drm/amdgpu: get owner ref in validate and map
Get the proper owner reference for amdgpu_hmm_range_get_pages function. This is useful for partial migrations. To avoid migrating back to system memory, VRAM pages, that are accessible by all devices in the same memory domain. Ex. multiple devices in the same hive. Signed-off-by: Alex Sierra --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 25 - 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 54f47b09b14a..2b4318646a75 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1313,6 +1313,17 @@ static void svm_range_unreserve_bos(struct svm_validate_context *ctx) ttm_eu_backoff_reservation(>ticket, >validate_list); } +static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx) +{ + struct kfd_process_device *pdd; + struct amdgpu_device *adev; + + pdd = kfd_process_device_from_gpuidx(p, gpuidx); + adev = (struct amdgpu_device *)pdd->dev->kgd; + + return SVM_ADEV_PGMAP_OWNER(adev); +} + /* * Validation+GPU mapping with concurrent invalidation (MMU notifiers) * @@ -1343,6 +1354,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm, { struct svm_validate_context ctx; struct hmm_range *hmm_range; + struct kfd_process *p; + void *owner; + int32_t idx; int r = 0; ctx.process = container_of(prange->svms, struct kfd_process, svms); @@ -1389,10 +1403,19 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_reserve_bos(); if (!prange->actual_loc) { + p = container_of(prange->svms, struct kfd_process, svms); + owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, + MAX_GPU_INSTANCE)); + for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { + if (kfd_svm_page_owner(p, idx) != owner) { + owner = NULL; + break; + } + } r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true, NULL); + false, true, owner); if (r) { pr_debug("failed %d to get svm range pages\n", r); goto unreserve_out; -- 2.32.0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 03/10] drm/amdkfd: set owner ref to svm range prefault
On 2021-06-21 12:04 p.m., Alex Sierra wrote: svm_range_prefault is called right before migrations to VRAM, to make sure pages are resident in system memory before the migration. With partial migrations, this reference is used by hmm range get pages to avoid migrating pages that are already in the same VRAM domain. Signed-off-by: Alex Sierra Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 5 +++-- drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 11f7f590c6ec..b298aa8dea4d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -512,7 +512,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, prange->start, prange->last, best_loc); /* FIXME: workaround for page locking bug with invalid pages */ - svm_range_prefault(prange, mm); + svm_range_prefault(prange, mm, SVM_ADEV_PGMAP_OWNER(adev)); start = prange->start << PAGE_SHIFT; end = (prange->last + 1) << PAGE_SHIFT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index b939f353ac8c..54f47b09b14a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2646,7 +2646,8 @@ svm_range_best_prefetch_location(struct svm_range *prange) /* FIXME: This is a workaround for page locking bug when some pages are * invalid during migration to VRAM */ -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner) { struct hmm_range *hmm_range; int r; @@ -2657,7 +2658,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) r = amdgpu_hmm_range_get_pages(>notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, _range, - false, true, NULL); + false, true, owner); if (!r) { amdgpu_hmm_range_get_pages_done(hmm_range); prange->validated_once = true; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 4297250f259d..08542fe39303 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -176,7 +176,8 @@ void schedule_deferred_list_work(struct svm_range_list *svms); void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, unsigned long offset, unsigned long npages); void svm_range_free_dma_mappings(struct svm_range *prange); -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm); +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner); #else ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH] drm/amdgpu: fix amdgpu_preempt_mgr_new()
[Public] I've dropped it from my tree in that case. From: Christian König Sent: Monday, June 21, 2021 6:27 AM To: Alex Deucher ; Kuehling, Felix Cc: David Airlie ; Pan, Xinhui ; kernel-janit...@vger.kernel.org ; Maling list - DRI developers ; amd-gfx list ; Daniel Vetter ; Deucher, Alexander ; Dave Airlie ; Koenig, Christian ; Dan Carpenter Subject: Re: [PATCH] drm/amdgpu: fix amdgpu_preempt_mgr_new() Am 18.06.21 um 23:18 schrieb Alex Deucher: > On Fri, Jun 18, 2021 at 11:40 AM Felix Kuehling > wrote: >> Am 2021-06-18 um 4:39 a.m. schrieb Christian König: >>> Am 18.06.21 um 10:37 schrieb Dan Carpenter: There is a reversed if statement in amdgpu_preempt_mgr_new() so it always returns -ENOMEM. Fixes: 09b020bb05a5 ("Merge tag 'drm-misc-next-2021-06-09' of git://anongit.freedesktop.org/drm/drm-misc into drm-next") Signed-off-by: Dan Carpenter >>> Most be some fallout from merging it with the TTM changes. >>> >>> Anyway, patch is Reviewed-by: Christian König >> This is obviously not for amd-staging-drm-next. Christian, are you going >> to apply it to the relevant branches? > I've applied it to my drm-next branch. I already pushed it to drm-misc-next last week. Christian. > > Alex > > >> Thanks, >>Felix >> >> >>> Thanks, >>> Christian. >>> --- drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c index f6aff7ce5160..d02c8637f909 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c @@ -71,7 +71,7 @@ static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man, struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); *res = kzalloc(sizeof(**res), GFP_KERNEL); -if (*res) +if (!*res) return -ENOMEM; ttm_resource_init(tbo, place, *res); >> ___ >> amd-gfx mailing list >> amd-gfx@lists.freedesktop.org >> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfxdata=04%7C01%7Calexander.deucher%40amd.com%7C096813db12f24172870508d9349f375a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637598680703030828%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=%2Ffg7TXDA9%2F%2Fjin8T5f3V11fAv3PVvtDFluNHnhwyOGM%3Dreserved=0 > ___ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfxdata=04%7C01%7Calexander.deucher%40amd.com%7C096813db12f24172870508d9349f375a%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637598680703030828%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=%2Ffg7TXDA9%2F%2Fjin8T5f3V11fAv3PVvtDFluNHnhwyOGM%3Dreserved=0 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 9:27 PM Daniel Vetter wrote: > > On Mon, Jun 21, 2021 at 7:55 PM Jason Gunthorpe wrote: > > On Mon, Jun 21, 2021 at 07:26:14PM +0300, Oded Gabbay wrote: > > > On Mon, Jun 21, 2021 at 5:12 PM Jason Gunthorpe wrote: > > > > > > > > On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > > > > > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > > > > > > > > > Also I'm wondering which is the other driver that we share buffers > > > > > > with. The gaudi stuff doesn't have real struct pages as backing > > > > > > storage, it only fills out the dma_addr_t. That tends to blow up > > > > > > with > > > > > > other drivers, and the only place where this is guaranteed to work > > > > > > is > > > > > > if you have a dynamic importer which sets the allow_peer2peer flag. > > > > > > Adding maintainers from other subsystems who might want to chime in > > > > > > here. So even aside of the big question as-is this is broken. > > > > > > > > > > From what I can tell this driver is sending the buffers to other > > > > > instances of the same hardware, > > > > > > > > A dmabuf is consumed by something else in the kernel calling > > > > dma_buf_map_attachment() on the FD. > > > > > > > > What is the other side of this? I don't see any > > > > dma_buf_map_attachment() calls in drivers/misc, or added in this patch > > > > set. > > > > > > This patch-set is only to enable the support for the exporter side. > > > The "other side" is any generic RDMA networking device that will want > > > to perform p2p communication over PCIe with our GAUDI accelerator. > > > An example is indeed the mlnx5 card which has already integrated > > > support for being an "importer". > > > > It raises the question of how you are testing this if you aren't using > > it with the only intree driver: mlx5. > > For p2p dma-buf there's also amdgpu as a possible in-tree candiate > driver, that's why I added amdgpu folks. Otoh I'm not aware of AI+GPU > combos being much in use, at least with upstream gpu drivers (nvidia > blob is a different story ofc, but I don't care what they do in their > own world). > -Daniel > -- We have/are doing three things: 1. I wrote a simple "importer" driver that emulates an RDMA driver. It calls all the IB_UMEM_DMABUF functions, same as the mlnx5 driver does. And instead of using h/w, it accesses the bar directly. We wrote several tests that emulated the real application. i.e. asking the habanalabs driver to create dma-buf object and export its FD back to userspace. Then the userspace sends the FD to the "importer" driver, which attaches to it, get the SG list and accesses the memory on the GAUDI device. This gave me the confidence that how we integrated the exporter is basically correct/working. 2. We are trying to do a POC with a MLNX card we have, WIP. 3. We are working with another 3rd party RDMA device that its driver is now adding support for being an "importer". also WIP In both points 2&3 We haven't yet reached the actual stage of checking this feature. Another thing I want to emphasize is that we are doing p2p only through the export/import of the FD. We do *not* allow the user to mmap the dma-buf as we do not support direct IO. So there is no access to these pages through the userspace. Thanks, Oded ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH] drm/radeon: delete useless function return values & remove meaningless if(r) check code
Applied. Thanks! Alex On Mon, Jun 21, 2021 at 9:15 AM Christian König wrote: > > Am 21.06.21 um 15:05 schrieb Bernard Zhao: > > Function radeon_fence_driver_init always returns success, > > the function type maybe coule be changed to void. > > This patch first delete the check of the return > > value of the function call radeon_fence_driver_init, then, > > optimise the function declaration and function to void type. > > > > Signed-off-by: Bernard Zhao > > Reviewed-by: Christian König > > > --- > > drivers/gpu/drm/radeon/cik.c | 4 +--- > > drivers/gpu/drm/radeon/evergreen.c| 4 +--- > > drivers/gpu/drm/radeon/ni.c | 4 +--- > > drivers/gpu/drm/radeon/r100.c | 4 +--- > > drivers/gpu/drm/radeon/r300.c | 4 +--- > > drivers/gpu/drm/radeon/r420.c | 5 + > > drivers/gpu/drm/radeon/r520.c | 4 +--- > > drivers/gpu/drm/radeon/r600.c | 4 +--- > > drivers/gpu/drm/radeon/radeon.h | 2 +- > > drivers/gpu/drm/radeon/radeon_fence.c | 5 + > > drivers/gpu/drm/radeon/rs400.c| 4 +--- > > drivers/gpu/drm/radeon/rs600.c| 4 +--- > > drivers/gpu/drm/radeon/rs690.c| 4 +--- > > drivers/gpu/drm/radeon/rv515.c| 4 +--- > > drivers/gpu/drm/radeon/rv770.c| 4 +--- > > drivers/gpu/drm/radeon/si.c | 4 +--- > > 16 files changed, 16 insertions(+), 48 deletions(-) > > > > diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c > > index 42a8afa839cb..f6cf0b8fdd83 100644 > > --- a/drivers/gpu/drm/radeon/cik.c > > +++ b/drivers/gpu/drm/radeon/cik.c > > @@ -8584,9 +8584,7 @@ int cik_init(struct radeon_device *rdev) > > radeon_get_clock_info(rdev->ddev); > > > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) > > - return r; > > + radeon_fence_driver_init(rdev); > > > > /* initialize memory controller */ > > r = cik_mc_init(rdev); > > diff --git a/drivers/gpu/drm/radeon/evergreen.c > > b/drivers/gpu/drm/radeon/evergreen.c > > index 8e9e88bf1f43..36a888e1b179 100644 > > --- a/drivers/gpu/drm/radeon/evergreen.c > > +++ b/drivers/gpu/drm/radeon/evergreen.c > > @@ -5208,9 +5208,7 @@ int evergreen_init(struct radeon_device *rdev) > > /* Initialize clocks */ > > radeon_get_clock_info(rdev->ddev); > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) > > - return r; > > + radeon_fence_driver_init(rdev); > > /* initialize AGP */ > > if (rdev->flags & RADEON_IS_AGP) { > > r = radeon_agp_init(rdev); > > diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c > > index ab7bd3080217..4a364ca7a1be 100644 > > --- a/drivers/gpu/drm/radeon/ni.c > > +++ b/drivers/gpu/drm/radeon/ni.c > > @@ -2375,9 +2375,7 @@ int cayman_init(struct radeon_device *rdev) > > /* Initialize clocks */ > > radeon_get_clock_info(rdev->ddev); > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) > > - return r; > > + radeon_fence_driver_init(rdev); > > /* initialize memory controller */ > > r = evergreen_mc_init(rdev); > > if (r) > > diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c > > index fcfcaec25a9e..aa6800b0e198 100644 > > --- a/drivers/gpu/drm/radeon/r100.c > > +++ b/drivers/gpu/drm/radeon/r100.c > > @@ -4056,9 +4056,7 @@ int r100_init(struct radeon_device *rdev) > > /* initialize VRAM */ > > r100_mc_init(rdev); > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) > > - return r; > > + radeon_fence_driver_init(rdev); > > /* Memory manager */ > > r = radeon_bo_init(rdev); > > if (r) > > diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c > > index 92643dfdd8a8..621ff174dff3 100644 > > --- a/drivers/gpu/drm/radeon/r300.c > > +++ b/drivers/gpu/drm/radeon/r300.c > > @@ -1549,9 +1549,7 @@ int r300_init(struct radeon_device *rdev) > > /* initialize memory controller */ > > r300_mc_init(rdev); > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) > > - return r; > > + radeon_fence_driver_init(rdev); > > /* Memory manager */ > > r = radeon_bo_init(rdev); > > if (r) > > diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c > > index 1ed4407b91aa..7e6320e8c6a0 100644 > > --- a/drivers/gpu/drm/radeon/r420.c > > +++ b/drivers/gpu/drm/radeon/r420.c > > @@ -425,10 +425,7 @@ int r420_init(struct radeon_device *rdev) > > r300_mc_init(rdev); > > r420_debugfs(rdev); > > /* Fence driver */ > > - r = radeon_fence_driver_init(rdev); > > - if (r) { > > - return r; > > - } > > + radeon_fence_driver_init(rdev); > > /* Memory manager */ > > r = radeon_bo_init(rdev); > >
Re: [PATCH 08/12] drm/amd/display: Fix edp_bootup_bl_level initialization issue
On 2021-06-18 3:07 p.m., Bindu Ramamurthy wrote: > From: Logush Oliver > > [why] > Updating the file to fix the missing line > > Signed-off-by: Logush Oliver > Reviewed-by: Charlene Liu > Acked-by: Bindu Ramamurthy > --- > drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c > b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c > index 7d1c1b76d8d0..840d7aca17cf 100644 > --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c > +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c > @@ -2140,7 +2140,7 @@ static enum bp_result get_integrated_info_v2_1( > info_v2_1->edp1_info.edp_pwr_down_bloff_to_vary_bloff; > info->edp1_info.edp_panel_bpc = > info_v2_1->edp1_info.edp_panel_bpc; > - info->edp1_info.edp_bootup_bl_level = > + info->edp1_info.edp_bootup_bl_level = > info_v2_1->edp1_info.edp_bootup_bl_level; > This hints at a previous patch not building successfully. Please ensure all patches in the series are building. It can be easily checked with 'git rebase -i --exec make'. Make sure this gets squashed with the faulty patch before merging. Thanks, Harry > info->edp2_info.edp_backlight_pwm_hz = > le16_to_cpu(info_v2_1->edp2_info.edp_backlight_pwm_hz); > ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 7:55 PM Jason Gunthorpe wrote: > On Mon, Jun 21, 2021 at 07:26:14PM +0300, Oded Gabbay wrote: > > On Mon, Jun 21, 2021 at 5:12 PM Jason Gunthorpe wrote: > > > > > > On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > > > > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > > > > > > > Also I'm wondering which is the other driver that we share buffers > > > > > with. The gaudi stuff doesn't have real struct pages as backing > > > > > storage, it only fills out the dma_addr_t. That tends to blow up with > > > > > other drivers, and the only place where this is guaranteed to work is > > > > > if you have a dynamic importer which sets the allow_peer2peer flag. > > > > > Adding maintainers from other subsystems who might want to chime in > > > > > here. So even aside of the big question as-is this is broken. > > > > > > > > From what I can tell this driver is sending the buffers to other > > > > instances of the same hardware, > > > > > > A dmabuf is consumed by something else in the kernel calling > > > dma_buf_map_attachment() on the FD. > > > > > > What is the other side of this? I don't see any > > > dma_buf_map_attachment() calls in drivers/misc, or added in this patch > > > set. > > > > This patch-set is only to enable the support for the exporter side. > > The "other side" is any generic RDMA networking device that will want > > to perform p2p communication over PCIe with our GAUDI accelerator. > > An example is indeed the mlnx5 card which has already integrated > > support for being an "importer". > > It raises the question of how you are testing this if you aren't using > it with the only intree driver: mlx5. For p2p dma-buf there's also amdgpu as a possible in-tree candiate driver, that's why I added amdgpu folks. Otoh I'm not aware of AI+GPU combos being much in use, at least with upstream gpu drivers (nvidia blob is a different story ofc, but I don't care what they do in their own world). -Daniel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 07:26:14PM +0300, Oded Gabbay wrote: > On Mon, Jun 21, 2021 at 5:12 PM Jason Gunthorpe wrote: > > > > On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > > > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > > > > > Also I'm wondering which is the other driver that we share buffers > > > > with. The gaudi stuff doesn't have real struct pages as backing > > > > storage, it only fills out the dma_addr_t. That tends to blow up with > > > > other drivers, and the only place where this is guaranteed to work is > > > > if you have a dynamic importer which sets the allow_peer2peer flag. > > > > Adding maintainers from other subsystems who might want to chime in > > > > here. So even aside of the big question as-is this is broken. > > > > > > From what I can tell this driver is sending the buffers to other > > > instances of the same hardware, > > > > A dmabuf is consumed by something else in the kernel calling > > dma_buf_map_attachment() on the FD. > > > > What is the other side of this? I don't see any > > dma_buf_map_attachment() calls in drivers/misc, or added in this patch > > set. > > This patch-set is only to enable the support for the exporter side. > The "other side" is any generic RDMA networking device that will want > to perform p2p communication over PCIe with our GAUDI accelerator. > An example is indeed the mlnx5 card which has already integrated > support for being an "importer". It raises the question of how you are testing this if you aren't using it with the only intree driver: mlx5. Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 5:12 PM Jason Gunthorpe wrote: > > On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > > > Also I'm wondering which is the other driver that we share buffers > > > with. The gaudi stuff doesn't have real struct pages as backing > > > storage, it only fills out the dma_addr_t. That tends to blow up with > > > other drivers, and the only place where this is guaranteed to work is > > > if you have a dynamic importer which sets the allow_peer2peer flag. > > > Adding maintainers from other subsystems who might want to chime in > > > here. So even aside of the big question as-is this is broken. > > > > From what I can tell this driver is sending the buffers to other > > instances of the same hardware, > > A dmabuf is consumed by something else in the kernel calling > dma_buf_map_attachment() on the FD. > > What is the other side of this? I don't see any > dma_buf_map_attachment() calls in drivers/misc, or added in this patch > set. This patch-set is only to enable the support for the exporter side. The "other side" is any generic RDMA networking device that will want to perform p2p communication over PCIe with our GAUDI accelerator. An example is indeed the mlnx5 card which has already integrated support for being an "importer". This is *not* used for communication with another GAUDI device. If I want to communicate with another GAUDI device, our userspace communications library will use our internal network links, without any need for dma-buf. Oded > > AFAIK the only viable in-tree other side is in mlx5 (look in > umem_dmabuf.c) > > Though as we already talked habana has their own networking (out of > tree, presumably) so I suspect this is really to support some out of > tree stuff?? > > Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [kbuild-all] Re: [PATCH] drm/radeon: Fix NULL dereference when updating memory stats
On Mon, Jun 21, 2021 at 10:41:57PM +0800, kernel test robot wrote: > Hi Mikel, > > Thank you for the patch! Yet something to improve: > > [auto build test ERROR on next-20210618] > [cannot apply to linus/master v5.13-rc7 v5.13-rc6 v5.13-rc5 v5.13-rc7] > [If your patch is applied to the wrong git tree, kindly drop us a note. > And when submitting patch, we suggest to use '--base' as documented in > https://git-scm.com/docs/git-format-patch] > > url: > https://github.com/0day-ci/linux/commits/Mikel-Rychliski/drm-radeon-Fix-NULL-dereference-when-updating-memory-stats/20210621-091140 > base:e71e3a48a7e89fa71fb70bf4602367528864d2ff > config: mips-allyesconfig (attached as .config) > compiler: mips-linux-gcc (GCC) 9.3.0 > reproduce (this is a W=1 build): > wget > https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O > ~/bin/make.cross > chmod +x ~/bin/make.cross > # > https://github.com/0day-ci/linux/commit/e5ec8682645a1ee2553fcb073d000802c11d2cb5 > git remote add linux-review https://github.com/0day-ci/linux > git fetch --no-tags linux-review > Mikel-Rychliski/drm-radeon-Fix-NULL-dereference-when-updating-memory-stats/20210621-091140 > git checkout e5ec8682645a1ee2553fcb073d000802c11d2cb5 > # save the attached .config to linux build tree > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross > ARCH=mips > > If you fix the issue, kindly add following tag as appropriate > Reported-by: kernel test robot > > All errors (new ones prefixed by >>): Sorry for the broken report, kindly ignore this, we will fix this asap. > > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/accessibility/speakup/speakup_decpc.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/base/test/test_async_driver_probe.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/i2c/i2c-stub.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_nandbiterrs.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_nandecctest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_oobtest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_pagetest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_readtest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_speedtest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_stresstest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_subpagetest.ko', > >> needed by '__modinst'. > >> make[2]: *** No rule to make target > >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_torturetest.ko', > >> needed by '__modinst'. > &
Re: [PATCH V3 1/7] drm/amdgpu: correct tcp harvest setting
One minor comment below, apart from that the series looks good. Reviewed-by: Lijo Lazar On 6/21/2021 12:30 PM, Evan Quan wrote: Add missing settings for SQC bits. And correct some confusing logics around active wgp bitmap calculation. Change-Id: If4992e175fd61d5609b00328cbe21f487517d039 Signed-off-by: Evan Quan --- V1->V2: - restore correct tcp_harvest setting for NV10 and NV12 - move asic type guard upper layer for better readability --- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 103 ++--- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 15ae9e33b925..384b95fbad8b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -5090,47 +5090,50 @@ static void gfx_v10_0_tcp_harvest(struct amdgpu_device *adev) 4 + /* RMI */ 1); /* SQG */ - if (adev->asic_type == CHIP_NAVI10 || - adev->asic_type == CHIP_NAVI14 || - adev->asic_type == CHIP_NAVI12) { - mutex_lock(>grbm_idx_mutex); - for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { - for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { - gfx_v10_0_select_se_sh(adev, i, j, 0x); - wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev); - /* -* Set corresponding TCP bits for the inactive WGPs in -* GCRD_SA_TARGETS_DISABLE -*/ - gcrd_targets_disable_tcp = 0; - /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */ - utcl_invreq_disable = 0; - - for (k = 0; k < max_wgp_per_sh; k++) { - if (!(wgp_active_bitmap & (1 << k))) { - gcrd_targets_disable_tcp |= 3 << (2 * k); - utcl_invreq_disable |= (3 << (2 * k)) | - (3 << (2 * (max_wgp_per_sh + k))); - } + mutex_lock(>grbm_idx_mutex); + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { + gfx_v10_0_select_se_sh(adev, i, j, 0x); + wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev); + /* +* Set corresponding TCP bits for the inactive WGPs in +* GCRD_SA_TARGETS_DISABLE +*/ + gcrd_targets_disable_tcp = 0; + /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */ + utcl_invreq_disable = 0; + + for (k = 0; k < max_wgp_per_sh; k++) { + if (!(wgp_active_bitmap & (1 << k))) { + gcrd_targets_disable_tcp |= 3 << (2 * k); + gcrd_targets_disable_tcp |= 1 << (k + (max_wgp_per_sh * 2)); + utcl_invreq_disable |= (3 << (2 * k)) | + (3 << (2 * (max_wgp_per_sh + k))); } - - tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE); - /* only override TCP & SQC bits */ - tmp &= 0x << (4 * max_wgp_per_sh); - tmp |= (utcl_invreq_disable & utcl_invreq_disable_mask); - WREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE, tmp); - - tmp = RREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE); - /* only override TCP bits */ - tmp &= 0x << (2 * max_wgp_per_sh); - tmp |= (gcrd_targets_disable_tcp & gcrd_targets_disable_mask); - WREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE, tmp); } - } - gfx_v10_0_select_se_sh(adev, 0x, 0x, 0x); - mutex_unlock(>grbm_idx_mutex); + tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE); + /* only override TCP & SQC bits */ + if (adev->asic_type == CHIP_NAVI14) + tmp &= 0xff00; + else + tmp &=0xfff0; For the disable field mask calculation (which is the value that is applied finally), there is no
Re: [PATCH 1/3] drm/nouveau: wait for moving fence after pinning
On Mon, Jun 21, 2021 at 5:49 PM Christian König wrote: > > Am 21.06.21 um 16:54 schrieb Daniel Vetter: > > On Mon, Jun 21, 2021 at 03:03:26PM +0200, Christian König wrote: > >> We actually need to wait for the moving fence after pinning > >> the BO to make sure that the pin is completed. > >> > >> Signed-off-by: Christian König > >> CC: sta...@kernel.org > >> --- > >> drivers/gpu/drm/nouveau/nouveau_prime.c | 8 +++- > >> 1 file changed, 7 insertions(+), 1 deletion(-) > >> > >> diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c > >> b/drivers/gpu/drm/nouveau/nouveau_prime.c > >> index 347488685f74..591738545eba 100644 > >> --- a/drivers/gpu/drm/nouveau/nouveau_prime.c > >> +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c > >> @@ -93,7 +93,13 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj) > >> if (ret) > >> return -EINVAL; > >> > >> -return 0; > >> +if (nvbo->bo.moving) { > > Don't we need to hold the dma_resv to read this? We can grab a reference > > and then unlock, but I think just unlocked wait can go boom pretty easily > > (since we don't hold a reference or lock so someone else can jump in and > > free the moving fence). > > The moving fence is only modified while the BO is moved and since we > have just successfully pinned it Yeah ... so probably correct, but really tricky. Just wrapping a ttm_bo_reserve/unreserve around the code you add should be enough and get the job done? > But in general I agree that it would be better to avoid this. I just > didn't wanted to open a bigger can of worms by changing nouveau so much. Yeah, but I'm kinda thinking of some helpers to wait for the move fence (so that later on we can switch from having the exclusive fence to the move fence do that, maybe). And then locking checks in there would be nice. Also avoids the case of explaining why lockless here is fine, but lockless wait for the exclusive fence in e.g. a dynami dma-buf importer is very much not fine at all. Just all around less trouble. -Daniel > > Christian. > > > -Daniel > > > >> +ret = dma_fence_wait(nvbo->bo.moving, true); > >> +if (ret) > >> +nouveau_bo_unpin(nvbo); > >> +} > >> + > >> +return ret; > >> } > >> > >> void nouveau_gem_prime_unpin(struct drm_gem_object *obj) > >> -- > >> 2.25.1 > >> > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/3] drm/nouveau: wait for moving fence after pinning
Am 21.06.21 um 16:54 schrieb Daniel Vetter: On Mon, Jun 21, 2021 at 03:03:26PM +0200, Christian König wrote: We actually need to wait for the moving fence after pinning the BO to make sure that the pin is completed. Signed-off-by: Christian König CC: sta...@kernel.org --- drivers/gpu/drm/nouveau/nouveau_prime.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index 347488685f74..591738545eba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -93,7 +93,13 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj) if (ret) return -EINVAL; - return 0; + if (nvbo->bo.moving) { Don't we need to hold the dma_resv to read this? We can grab a reference and then unlock, but I think just unlocked wait can go boom pretty easily (since we don't hold a reference or lock so someone else can jump in and free the moving fence). The moving fence is only modified while the BO is moved and since we have just successfully pinned it But in general I agree that it would be better to avoid this. I just didn't wanted to open a bigger can of worms by changing nouveau so much. Christian. -Daniel + ret = dma_fence_wait(nvbo->bo.moving, true); + if (ret) + nouveau_bo_unpin(nvbo); + } + + return ret; } void nouveau_gem_prime_unpin(struct drm_gem_object *obj) -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
On 6/21/2021 1:35 PM, Christian König wrote: Am 21.06.21 um 13:27 schrieb Das, Nirmoy: On 6/21/2021 1:18 PM, Christian König wrote: Am 21.06.21 um 13:10 schrieb Das, Nirmoy: On 6/21/2021 12:59 PM, Christian König wrote: Am 21.06.21 um 12:56 schrieb Das, Nirmoy: On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? The problem is you drop and re-take the lock now at the wrong time. I see the problem. I don't think what you try to do here is possible at all. Does it makes sense to resend without amdgpu_vm_handle_fault() changes ? Some other changes don't make sense to me as well. For example: pasid = amdgpu_pasid_alloc(16); Why do you want to allocate a hard coded pasid number here? This is from original amdgpu_driver_open_kms(). We are allocating a pasid number and passing that to amdgpu_vm_init(). I wanted to move that to vmcode with this patch. That doesn't make sense. The pasid is a hardware identify which is unrelated to the VM in general and might at some point passed in from external. Ok, makes sense. I will remove that part then. Nirmoy Please keep that as parameter to the VM code if possible. Christian. Regards, Nirmoy Christian. Christian. Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + +
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
Am 21.06.21 um 13:27 schrieb Das, Nirmoy: On 6/21/2021 1:18 PM, Christian König wrote: Am 21.06.21 um 13:10 schrieb Das, Nirmoy: On 6/21/2021 12:59 PM, Christian König wrote: Am 21.06.21 um 12:56 schrieb Das, Nirmoy: On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? The problem is you drop and re-take the lock now at the wrong time. I see the problem. I don't think what you try to do here is possible at all. Does it makes sense to resend without amdgpu_vm_handle_fault() changes ? Some other changes don't make sense to me as well. For example: pasid = amdgpu_pasid_alloc(16); Why do you want to allocate a hard coded pasid number here? This is from original amdgpu_driver_open_kms(). We are allocating a pasid number and passing that to amdgpu_vm_init(). I wanted to move that to vmcode with this patch. That doesn't make sense. The pasid is a hardware identify which is unrelated to the VM in general and might at some point passed in from external. Please keep that as parameter to the VM code if possible. Christian. Regards, Nirmoy Christian. Christian. Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); +
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
On 6/21/2021 1:18 PM, Christian König wrote: Am 21.06.21 um 13:10 schrieb Das, Nirmoy: On 6/21/2021 12:59 PM, Christian König wrote: Am 21.06.21 um 12:56 schrieb Das, Nirmoy: On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? The problem is you drop and re-take the lock now at the wrong time. I see the problem. I don't think what you try to do here is possible at all. Does it makes sense to resend without amdgpu_vm_handle_fault() changes ? Some other changes don't make sense to me as well. For example: pasid = amdgpu_pasid_alloc(16); Why do you want to allocate a hard coded pasid number here? This is from original amdgpu_driver_open_kms(). We are allocating a pasid number and passing that to amdgpu_vm_init(). I wanted to move that to vmcode with this patch. Regards, Nirmoy Christian. Christian. Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + + return vm; +} + /* * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS * happens while holding this lock anywhere to prevent deadlocks when @@ -2859,17 +2922,17 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm,
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 04:20:35PM +0200, Daniel Vetter wrote: > Also unless we're actually doing this properly there's zero incentive for > me to review the kernel code and check whether it follows the rules > correctly, so you have excellent chances that you just break the rules. > And dma_buf/fence are tricky enough that you pretty much guaranteed to > break the rules if you're not involved in the discussions. Just now we > have a big one where everyone involved (who's been doing this for 10+ > years all at least) realizes we've fucked up big time. This is where I come from on dmabuf, it is fiendishly complicated. Don't use it unless you absoultely have to, are in DRM, and have people like Daniel helping to make sure you use it right. It's whole premise and design is compromised by specialty historical implementation choices on the GPU side. Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
On 6/21/2021 12:59 PM, Christian König wrote: Am 21.06.21 um 12:56 schrieb Das, Nirmoy: On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? The problem is you drop and re-take the lock now at the wrong time. I see the problem. I don't think what you try to do here is possible at all. Does it makes sense to resend without amdgpu_vm_handle_fault() changes ? Christian. Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + + return vm; +} + /* * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS * happens while holding this lock anywhere to prevent deadlocks when @@ -2859,17 +2922,17 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) * * @adev: amdgpu_device pointer * @vm: requested vm - * @pasid: Process address space identifier * * Init @vm fields. * * Returns: * 0 for success, error for failure. */ -int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) +int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo *root_bo; struct amdgpu_bo_vm *root; + unsigned int
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
Am 21.06.21 um 12:56 schrieb Das, Nirmoy: On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? The problem is you drop and re-take the lock now at the wrong time. I don't think what you try to do here is possible at all. Christian. Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + + return vm; +} + /* * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS * happens while holding this lock anywhere to prevent deadlocks when @@ -2859,17 +2922,17 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) * * @adev: amdgpu_device pointer * @vm: requested vm - * @pasid: Process address space identifier * * Init @vm fields. * * Returns: * 0 for success, error for failure. */ -int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) +int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo *root_bo; struct amdgpu_bo_vm *root; + unsigned int pasid; int r, i; vm->va = RB_ROOT_CACHED; @@ -2940,19 +3003,15 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
On 6/21/2021 12:26 PM, Christian König wrote: Well you completely break the handling in amdgpu_vm_handle_fault() with this. I see one issue with: if (!vm || (vm && vm->root.bo != root)) . I will split it and resend. Am I missing something else ? Regards, Nirmoy Christian. Am 21.06.21 um 11:47 schrieb Das, Nirmoy: ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, + struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + + return vm; +} + /* * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS * happens while holding this lock anywhere to prevent deadlocks when @@ -2859,17 +2922,17 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) * * @adev: amdgpu_device pointer * @vm: requested vm - * @pasid: Process address space identifier * * Init @vm fields. * * Returns: * 0 for success, error for failure. */ -int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) +int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo *root_bo; struct amdgpu_bo_vm *root; + unsigned int pasid; int r, i; vm->va = RB_ROOT_CACHED; @@ -2940,19 +3003,15 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) amdgpu_bo_unreserve(vm->root.bo); - if (pasid) { - unsigned long flags; - - spin_lock_irqsave(>vm_manager.pasid_lock, flags); - r =
Re: [PATCH 3/3] drm/amdgpu: wait for moving fence after pinning
On Mon, Jun 21, 2021 at 03:03:28PM +0200, Christian König wrote: > We actually need to wait for the moving fence after pinning > the BO to make sure that the pin is completed. > > Signed-off-by: Christian König > CC: sta...@kernel.org > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 14 +- > 1 file changed, 13 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c > index baa980a477d9..37ec59365080 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c > @@ -214,9 +214,21 @@ static int amdgpu_dma_buf_pin(struct dma_buf_attachment > *attach) > { > struct drm_gem_object *obj = attach->dmabuf->priv; > struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); > + int r; > > /* pin buffer into GTT */ > - return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); > + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); > + if (r) > + return r; > + > + if (bo->tbo.moving) { dma-buf.c guarantees we have the reservation here, so we're fine. Reviewed-by: Daniel Vetter > + r = dma_fence_wait(bo->tbo.moving, true); > + if (r) { > + amdgpu_bo_unpin(bo); > + return r; > + } > + } > + return 0; > } > > /** > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 2/3] drm/radeon: wait for moving fence after pinning
On Mon, Jun 21, 2021 at 03:03:27PM +0200, Christian König wrote: > We actually need to wait for the moving fence after pinning > the BO to make sure that the pin is completed. > > Signed-off-by: Christian König > CC: sta...@kernel.org > --- > drivers/gpu/drm/radeon/radeon_prime.c | 16 +--- > 1 file changed, 13 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/radeon/radeon_prime.c > b/drivers/gpu/drm/radeon/radeon_prime.c > index 42a87948e28c..4a90807351e7 100644 > --- a/drivers/gpu/drm/radeon/radeon_prime.c > +++ b/drivers/gpu/drm/radeon/radeon_prime.c > @@ -77,9 +77,19 @@ int radeon_gem_prime_pin(struct drm_gem_object *obj) > > /* pin buffer into GTT */ > ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL); > - if (likely(ret == 0)) > - bo->prime_shared_count++; > - > + if (unlikely(ret)) > + goto error; > + > + if (bo->tbo.moving) { > + ret = dma_fence_wait(bo->tbo.moving, false); Here we wait whil holding the reservation, so we should be all fine. Maybe not the nicest to wait while locked, but also I don't think it'll matter. Reviewed-by: Daniel Vetter > + if (unlikely(ret)) { > + radeon_bo_unpin(bo); > + goto error; > + } > + } > + > + bo->prime_shared_count++; > +error: > radeon_bo_unreserve(bo); > return ret; > } > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/3] drm/nouveau: wait for moving fence after pinning
On Mon, Jun 21, 2021 at 03:03:26PM +0200, Christian König wrote: > We actually need to wait for the moving fence after pinning > the BO to make sure that the pin is completed. > > Signed-off-by: Christian König > CC: sta...@kernel.org > --- > drivers/gpu/drm/nouveau/nouveau_prime.c | 8 +++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c > b/drivers/gpu/drm/nouveau/nouveau_prime.c > index 347488685f74..591738545eba 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_prime.c > +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c > @@ -93,7 +93,13 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj) > if (ret) > return -EINVAL; > > - return 0; > + if (nvbo->bo.moving) { Don't we need to hold the dma_resv to read this? We can grab a reference and then unlock, but I think just unlocked wait can go boom pretty easily (since we don't hold a reference or lock so someone else can jump in and free the moving fence). -Daniel > + ret = dma_fence_wait(nvbo->bo.moving, true); > + if (ret) > + nouveau_bo_unpin(nvbo); > + } > + > + return ret; > } > > void nouveau_gem_prime_unpin(struct drm_gem_object *obj) > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH] drm/radeon: Fix NULL dereference when updating memory stats
Hi Mikel, Thank you for the patch! Yet something to improve: [auto build test ERROR on next-20210618] [cannot apply to linus/master v5.13-rc7 v5.13-rc6 v5.13-rc5 v5.13-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Mikel-Rychliski/drm-radeon-Fix-NULL-dereference-when-updating-memory-stats/20210621-091140 base:e71e3a48a7e89fa71fb70bf4602367528864d2ff config: mips-allyesconfig (attached as .config) compiler: mips-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/e5ec8682645a1ee2553fcb073d000802c11d2cb5 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Mikel-Rychliski/drm-radeon-Fix-NULL-dereference-when-updating-memory-stats/20210621-091140 git checkout e5ec8682645a1ee2553fcb073d000802c11d2cb5 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All errors (new ones prefixed by >>): >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/accessibility/speakup/speakup_decpc.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/base/test/test_async_driver_probe.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/i2c/i2c-stub.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_nandbiterrs.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_nandecctest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_oobtest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_pagetest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_readtest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_speedtest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_stresstest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_subpagetest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/mtd/tests/mtd_torturetest.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/ntb/hw/epf/ntb_hw_epf.ko', >> needed by '__modinst'. >> make[2]: *** No rule to make target >> '/tmp/kernel/mips-allyesconfig/gcc-9.3.0/e5ec8682645a1ee2553fcb073d000802c11d2cb5/lib/modules/5.13.0-rc6-next-20210618+/kernel/drivers/scsi/mpi3mr/mpi3mr.ko', >> needed by '__modinst'. >&g
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > Mission acomplished, we've gone full circle, and the totally-not-a-gpu > driver is now trying to use gpu infrastructure. And seems to have > gained vram meanwhile too. Next up is going to be synchronization > using dma_fence so you can pass buffers back without stalls > among drivers. Well, we can't even see the other side of this so who knows This is a new uAPI, where is the userspace? In RDMA at least I require to see the new userspace and test suite before changes to include/uapi/rdma can go ahead. > Doug/Jason from infiniband: Should we add linux-rdma to the dma-buf > wildcard match so that you can catch these next time around too? At > least when people use scripts/get_maintainers.pl correctly. All the > other subsystems using dma-buf are on there already (dri-devel, > linux-media and linaro-mm-sig for android/arm embedded stuff). My bigger concern is this doesn't seem to be implementing PCI P2P DMA correctly. This is following the same hacky NULL page approach that Christoph Hellwig already NAK'd for AMD. This should not be allowed to proliferate. I would be much happier seeing this be done using the approach of Logan's series here: https://lore.kernel.org/linux-block/20210513223203.5542-1-log...@deltatee.com/ Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > On Fri, Jun 18, 2021 at 2:36 PM Oded Gabbay wrote: > > > User process might want to share the device memory with another > > > driver/device, and to allow it to access it over PCIe (P2P). > > > > > > To enable this, we utilize the dma-buf mechanism and add a dma-buf > > > exporter support, so the other driver can import the device memory and > > > access it. > > > > > > The device memory is allocated using our existing allocation uAPI, > > > where the user will get a handle that represents the allocation. > > > > > > The user will then need to call the new > > > uAPI (HL_MEM_OP_EXPORT_DMABUF_FD) and give the handle as a parameter. > > > > > > The driver will return a FD that represents the DMA-BUF object that > > > was created to match that allocation. > > > > > > Signed-off-by: Oded Gabbay > > > Reviewed-by: Tomer Tayar > > > > Mission acomplished, we've gone full circle, and the totally-not-a-gpu > > driver is now trying to use gpu infrastructure. And seems to have > > gained vram meanwhile too. Next up is going to be synchronization > > using dma_fence so you can pass buffers back without stalls > > among drivers. > > What's wrong with other drivers using dmabufs and even dma_fence? It's > a common problem when shuffling memory around systems, why is that > somehow only allowed for gpu drivers? > > There are many users of these structures in the kernel today that are > not gpu drivers (tee, fastrpc, virtio, xen, IB, etc) as this is a common > thing that drivers want to do (throw chunks of memory around from > userspace to hardware). > > I'm not trying to be a pain here, but I really do not understand why > this is a problem. A kernel api is present, why not use it by other > in-kernel drivers? We had the problem in the past where subsystems were > trying to create their own interfaces for the same thing, which is why > you all created the dmabuf api to help unify this. It's the same thing as ever. 90% of an accel driver are in userspace, that's where all the fun is, that's where the big picture review needs to happen, and we've very conveniently bypassed all that a few years back because it was too annoying. Once we have the full driver stack and can start reviewing it I have no objections to totally-not-gpus using all this stuff too. But until we can do that this is all just causing headaches. Ofc if you assume that userspace doesn't matter then you don't care, which is where this giantic disconnect comes from. Also unless we're actually doing this properly there's zero incentive for me to review the kernel code and check whether it follows the rules correctly, so you have excellent chances that you just break the rules. And dma_buf/fence are tricky enough that you pretty much guaranteed to break the rules if you're not involved in the discussions. Just now we have a big one where everyone involved (who's been doing this for 10+ years all at least) realizes we've fucked up big time. Anyway we've had this discussion, we're not going to move anyone here at all, so *shrug*. I'll keep seeing accelarators in drivers/misc as blantant bypassing of review by actual accelerator pieces, you keep seing dri-devel as ... well I dunno, people who don't know what they're talking about maybe. Or not relevant to your totally-not-a-gpu thing. > > Also I'm wondering which is the other driver that we share buffers > > with. The gaudi stuff doesn't have real struct pages as backing > > storage, it only fills out the dma_addr_t. That tends to blow up with > > other drivers, and the only place where this is guaranteed to work is > > if you have a dynamic importer which sets the allow_peer2peer flag. > > Adding maintainers from other subsystems who might want to chime in > > here. So even aside of the big question as-is this is broken. > > From what I can tell this driver is sending the buffers to other > instances of the same hardware, as that's what is on the other "end" of > the network connection. No different from IB's use of RDMA, right? There's no import afaict, but maybe I missed it. Assuming I haven't missed it the importing necessarily has to happen by some other drivers. -Daniel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH v3 1/2] habanalabs: define uAPI to export FD for DMA-BUF
On Mon, Jun 21, 2021 at 03:02:10PM +0200, Greg KH wrote: > On Mon, Jun 21, 2021 at 02:28:48PM +0200, Daniel Vetter wrote: > > Also I'm wondering which is the other driver that we share buffers > > with. The gaudi stuff doesn't have real struct pages as backing > > storage, it only fills out the dma_addr_t. That tends to blow up with > > other drivers, and the only place where this is guaranteed to work is > > if you have a dynamic importer which sets the allow_peer2peer flag. > > Adding maintainers from other subsystems who might want to chime in > > here. So even aside of the big question as-is this is broken. > > From what I can tell this driver is sending the buffers to other > instances of the same hardware, A dmabuf is consumed by something else in the kernel calling dma_buf_map_attachment() on the FD. What is the other side of this? I don't see any dma_buf_map_attachment() calls in drivers/misc, or added in this patch set. AFAIK the only viable in-tree other side is in mlx5 (look in umem_dmabuf.c) Though as we already talked habana has their own networking (out of tree, presumably) so I suspect this is really to support some out of tree stuff?? Jason ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/1] drm/amdgpu: add helper function for vm pasid
ping. On 6/17/2021 3:03 PM, Nirmoy Das wrote: Cleanup code related to vm pasid by adding helper function. This reduces lots code duplication. Signed-off-by: Nirmoy Das --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 176 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +- 3 files changed, 96 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index cbb932f97355..27851fb0e25b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1149,7 +1149,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; - int r, pasid; + int r; /* Ensure IB tests are run on ring */ flush_delayed_work(>delayed_init_work); @@ -1172,15 +1172,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - pasid = amdgpu_pasid_alloc(16); - if (pasid < 0) { - dev_warn(adev->dev, "No more PASIDs available!"); - pasid = 0; - } - - r = amdgpu_vm_init(adev, >vm, pasid); + r = amdgpu_vm_init(adev, >vm); if (r) - goto error_pasid; + goto free_fpriv; fpriv->prt_va = amdgpu_vm_bo_add(adev, >vm, NULL); if (!fpriv->prt_va) { @@ -1208,10 +1202,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) error_vm: amdgpu_vm_fini(adev, >vm); -error_pasid: - if (pasid) - amdgpu_pasid_free(pasid); - +free_fpriv: kfree(fpriv); out_suspend: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63975bda8e76..562c2c48a3a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -87,6 +87,69 @@ struct amdgpu_prt_cb { struct dma_fence_cb cb; }; +static int amdgpu_vm_pasid_alloc(struct amdgpu_device *adev, +struct amdgpu_vm *vm, unsigned int pasid) +{ + unsigned long flags; + int r; + + if (!pasid) + return 0; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + r = idr_alloc(>vm_manager.pasid_idr, vm, pasid, pasid + 1, + GFP_ATOMIC); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + if (r < 0) + return r; + + vm->pasid = pasid; + return 0; +} +static void amdgpu_vm_pasid_remove_id(struct amdgpu_device *adev, + unsigned int pasid) +{ + unsigned long flags; + + if (!pasid) + return; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + idr_remove(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + +} + +static void amdgpu_vm_pasid_remove(struct amdgpu_device *adev, + struct amdgpu_vm *vm) +{ + amdgpu_vm_pasid_remove_id(adev, vm->pasid); + vm->pasid = 0; +} + +static void amdgpu_vm_pasid_free(struct amdgpu_device *adev, +struct amdgpu_vm *vm) +{ + if (!vm->pasid) + return; + + amdgpu_pasid_free(vm->pasid); + amdgpu_vm_pasid_remove(adev, vm); +} + +static struct amdgpu_vm *amdgpu_vm_pasid_find(struct amdgpu_device *adev, + unsigned int pasid) +{ + struct amdgpu_vm *vm; + unsigned long flags; + + spin_lock_irqsave(>vm_manager.pasid_lock, flags); + vm = idr_find(>vm_manager.pasid_idr, pasid); + spin_unlock_irqrestore(>vm_manager.pasid_lock, flags); + + return vm; +} + /* * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS * happens while holding this lock anywhere to prevent deadlocks when @@ -2859,17 +2922,17 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) * * @adev: amdgpu_device pointer * @vm: requested vm - * @pasid: Process address space identifier * * Init @vm fields. * * Returns: * 0 for success, error for failure. */ -int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) +int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo *root_bo; struct amdgpu_bo_vm *root; + unsigned int pasid; int r, i; vm->va = RB_ROOT_CACHED; @@ -2940,19 +3003,15 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid) amdgpu_bo_unreserve(vm->root.bo); - if (pasid) { - unsigned long flags; - - spin_lock_irqsave(>vm_manager.pasid_lock, flags); - r = idr_alloc(>vm_manager.pasid_idr, vm, pasid,