On 2020-01-16 3:29 p.m., Bhawanpreet Lakha wrote: > [Why] > We need to set/get SRM and linux kernel is not suppose to write to the "We need to set/get SRM from/to PSP FW..." > storage, so we need to provide a interface. > an interface. Highlight that we expect these to be exercised by usermode scripts that run at boot, shutdown, suspend, and resume. Harry > [How] > Provide interface so usermode can set/get srm > > Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@xxxxxxx> > Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@xxxxxxx> > --- > .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 124 +++++++++++++++++- > .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 6 + > 2 files changed, 128 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c > index a269916f7dd6..a191c84ad8eb 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c > @@ -28,6 +28,8 @@ > #include "amdgpu_dm.h" > #include "dm_helpers.h" > #include <drm/drm_hdcp.h> > +#include "hdcp_psp.h" > + > > static bool > lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size) > @@ -67,6 +69,16 @@ lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size) > return dm_helpers_dp_read_dpcd(link->ctx, link, address, data, size); > } > > +static uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size) > +{ > + return NULL; > +} > + > +static int psp_set_srm(struct psp_context *psp, uint8_t *srm, uint32_t srm_size, uint32_t *srm_version) > +{ > + return 0; > +} > + > static void process_output(struct hdcp_workqueue *hdcp_work) > { > struct mod_hdcp_output output = hdcp_work->output; > @@ -88,6 +100,18 @@ static void process_output(struct hdcp_workqueue *hdcp_work) > schedule_delayed_work(&hdcp_work->property_validate_dwork, msecs_to_jiffies(0)); > } > > +static void link_lock(struct hdcp_workqueue *work, bool lock) > +{ > + > + int i = 0; > + > + for (i = 0; i < work->max_link; i++) { > + if (lock) > + mutex_lock(&work[i].mutex); > + else > + mutex_unlock(&work[i].mutex); > + } > +} > void hdcp_update_display(struct hdcp_workqueue *hdcp_work, > unsigned int link_index, > struct amdgpu_dm_connector *aconnector, > @@ -302,7 +326,8 @@ void hdcp_destroy(struct hdcp_workqueue *hdcp_work) > } > > kfree(hdcp_work); > - > + kfree(hdcp_work->srm); > + kfree(hdcp_work->srm_temp); > } > > static void update_config(void *handle, struct cp_psp_stream_config *config) > @@ -338,6 +363,84 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) > hdcp_update_display(hdcp_work, link_index, aconnector, DRM_MODE_HDCP_CONTENT_TYPE0, false); > } > > + > +/* > + * This can be called twice, because SRM_SIZE > PAGE_SIZE. > + * > + * We set the SRM on each call, if SRM_SIZE > PAGE_SIZE, PSP will fail on the > + * first call but pass on the second call. > + * > + * Because of this we are not throwing any errors as it will stop the next call. > + * So it is a good idea to call the "read" sysfs to verify that the SRM was set > + * > + */ > +static ssize_t srm_data_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buffer, > + loff_t pos, size_t count) > +{ > + struct hdcp_workqueue *work; > + uint32_t srm_version = 0; > + > + work = container_of(bin_attr, struct hdcp_workqueue, attr); > + link_lock(work, true); > + > + memcpy(work->srm_temp + pos, buffer, count); > + > + if (!psp_set_srm(work->hdcp.config.psp.handle, work->srm_temp, pos + count, &srm_version)) { > + DRM_DEBUG_DRIVER("HDCP SRM SET version 0x%X", srm_version); > + memcpy(work->srm, work->srm_temp, pos + count); > + work->srm_size = pos + count; > + work->srm_version = srm_version; > + } > + > + > + link_lock(work, false); > + > + return count; > +} > + > +static ssize_t srm_data_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buffer, > + loff_t pos, size_t count) > +{ > + struct hdcp_workqueue *work; > + uint8_t *srm = NULL; > + uint32_t srm_version; > + uint32_t srm_size; > + size_t ret = count; > + > + work = container_of(bin_attr, struct hdcp_workqueue, attr); > + > + link_lock(work, true); > + > + srm = psp_get_srm(work->hdcp.config.psp.handle, &srm_version, &srm_size); > + > + if (!srm) > + return -EINVAL; > + > + if (pos >= srm_size) > + ret = 0; > + > + if (srm_size - pos < count) { > + memcpy(buffer, srm + pos, srm_size - pos); > + ret = srm_size - pos; > + goto ret; > + } > + > + memcpy(buffer, srm + pos, count); > + > +ret: > + link_lock(work, false); > + return ret; > +} > + > + > +static const struct bin_attribute data_attr = { > + .attr = {.name = "hdcp_srm", .mode = 0664}, > + .size = PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, /* Limit SRM size */ > + .write = srm_data_write, > + .read = srm_data_read, > +}; > + > + > struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct cp_psp *cp_psp, struct dc *dc) > { > > @@ -348,10 +451,19 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct > if (hdcp_work == NULL) > goto fail_alloc_context; > > + hdcp_work->srm = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm), GFP_KERNEL); > + > + if (hdcp_work->srm == NULL) > + goto fail_alloc_context; > + > + hdcp_work->srm_temp = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm_temp), GFP_KERNEL); > + > + if (hdcp_work->srm_temp == NULL) > + goto fail_alloc_context; > + > hdcp_work->max_link = max_caps; > > for (i = 0; i < max_caps; i++) { > - > mutex_init(&hdcp_work[i].mutex); > > INIT_WORK(&hdcp_work[i].cpirq_work, event_cpirq); > @@ -371,10 +483,18 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct > cp_psp->funcs.update_stream_config = update_config; > cp_psp->handle = hdcp_work; > > + /* File created at /sys/class/drm/card0/device/hdcp_srm*/ > + hdcp_work[0].attr = data_attr; > + > + if (sysfs_create_bin_file(&adev->dev->kobj, &hdcp_work[0].attr)) > + DRM_WARN("Failed to create device file hdcp_srm"); > + > return hdcp_work; > > fail_alloc_context: > kfree(hdcp_work); > + kfree(hdcp_work->srm); > + kfree(hdcp_work->srm_temp); > > return NULL; > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h > index 331b50825510..5159b3a5e5b0 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h > @@ -53,6 +53,12 @@ struct hdcp_workqueue { > > enum mod_hdcp_encryption_status encryption_status; > uint8_t max_link; > + > + uint8_t *srm; > + uint8_t *srm_temp; > + uint32_t srm_version; > + uint32_t srm_size; > + struct bin_attribute attr; > }; > > void hdcp_update_display(struct hdcp_workqueue *hdcp_work, > _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx