diff mbox

drm/i915: Add GuC css header parser

Message ID 1441234355-7524-1-git-send-email-yu.dai@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

yu.dai@intel.com Sept. 2, 2015, 10:52 p.m. UTC
From: Alex Dai <yu.dai@intel.com>

By using information from GuC css header, we can eliminate some
hard code w.r.t size of some components of firmware.

Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h        |  2 +-
 drivers/gpu/drm/i915/intel_guc_fwif.h   | 36 +++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c | 91 ++++++++++++++++++++++-----------
 3 files changed, 98 insertions(+), 31 deletions(-)

Comments

Jani Nikula Sept. 3, 2015, 7:36 a.m. UTC | #1
On Thu, 03 Sep 2015, yu.dai@intel.com wrote:
> From: Alex Dai <yu.dai@intel.com>
>
> By using information from GuC css header, we can eliminate some
> hard code w.r.t size of some components of firmware.
>
> Signed-off-by: Alex Dai <yu.dai@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc.h        |  2 +-
>  drivers/gpu/drm/i915/intel_guc_fwif.h   | 36 +++++++++++++
>  drivers/gpu/drm/i915/intel_guc_loader.c | 91 ++++++++++++++++++++++-----------
>  3 files changed, 98 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index 4ec2d27..e1389fc 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -71,6 +71,7 @@ struct intel_guc_fw {
>  	struct drm_i915_gem_object *	guc_fw_obj;
>  	enum intel_guc_fw_status	guc_fw_fetch_status;
>  	enum intel_guc_fw_status	guc_fw_load_status;
> +	struct guc_css_header		guc_fw_header;
>  
>  	uint16_t			guc_fw_major_wanted;
>  	uint16_t			guc_fw_minor_wanted;
> @@ -80,7 +81,6 @@ struct intel_guc_fw {
>  
>  struct intel_guc {
>  	struct intel_guc_fw guc_fw;
> -
>  	uint32_t log_flags;
>  	struct drm_i915_gem_object *log_obj;
>  
> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
> index e1f47ba..d6cb4e8 100644
> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
> @@ -122,6 +122,42 @@
>  
>  #define GUC_CTL_MAX_DWORDS		(GUC_CTL_RSRVD + 1)
>  
> +struct guc_css_header {
> +	uint32_t module_type;
> +	uint32_t header_len; /* header length plus size of all other keys */
> +	uint32_t header_version;
> +	uint32_t module_id;
> +	uint32_t module_vendor;
> +	union {
> +		struct {
> +			uint8_t day;
> +			uint8_t month;
> +			uint16_t year;
> +		};
> +		uint32_t date;
> +	};
> +	uint32_t size; /* uCode size plus header_len */
> +	uint32_t key_size;
> +	uint32_t modulus_size;
> +	uint32_t exponent_size;
> +	union {
> +		struct {
> +			uint8_t hour;
> +			uint8_t min;
> +			uint16_t sec;
> +		};
> +		uint32_t time;
> +	};
> +
> +	char username[8];
> +	char buildnumber[12];
> +	uint32_t device_id;
> +	uint32_t guc_sw_version;
> +	uint32_t prod_preprod_fw;
> +	uint32_t reserved[12];
> +	uint32_t header_info;
> +};

Drive-by review, this will need __packed.

BR,
Jani.


> +
>  struct guc_doorbell_info {
>  	u32 db_status;
>  	u32 cookie;
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 5823615..96826ae 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -215,18 +215,24 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
>  		((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
>  }
>  
> -/*
> +/**
>   * Transfer the firmware image to RAM for execution by the microcontroller.
>   *
>   * GuC Firmware layout:
> - * +-------------------------------+  ----
> - * |          CSS header           |  128B
> + * +-------------------------------+
> + * |        guc_css_header         |
>   * | contains major/minor version  |
> - * +-------------------------------+  ----
> + * +-------------------------------+
>   * |             uCode             |
> - * +-------------------------------+  ----
> - * |         RSA signature         |  256B
> - * +-------------------------------+  ----
> + * +-------------------------------+
> + * |         RSA signature         |
> + * +-------------------------------+
> + * |          modulus key          |
> + * +-------------------------------+
> + * |          exponent val         |
> + * +-------------------------------+
> + * The firmware may or may not have modulus key and exponent data. The header,
> + * uCode and RSA signature are must-have components that will be used by driver.
>   *
>   * Architecturally, the DMA engine is bidirectional, and can potentially even
>   * transfer between GTT locations. This functionality is left out of the API
> @@ -236,30 +242,39 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
>   * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
>   */
>  
> -#define UOS_CSS_HEADER_OFFSET		0
> -#define UOS_VER_MINOR_OFFSET		0x44
> -#define UOS_VER_MAJOR_OFFSET		0x46
> -#define UOS_CSS_HEADER_SIZE		0x80
> -#define UOS_RSA_SIG_SIZE		0x100
> -
>  static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
>  {
>  	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
> +	struct guc_css_header *header = &guc_fw->guc_fw_header;
>  	struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
>  	unsigned long offset;
>  	struct sg_table *sg = fw_obj->pages;
> -	u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
> +	u32 status, header_size, rsa_size, ucode_size, *rsa;
>  	int i, ret = 0;
>  
> -	/* uCode size, also is where RSA signature starts */
> -	offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
> -	I915_WRITE(DMA_COPY_SIZE, ucode_size);
> +	/* The header plus uCode will be copied to WOPCM via DMA, excluding any
> +	 * other components */
> +	header_size = (header->header_len - header->key_size -
> +		header->modulus_size - header->exponent_size) * sizeof(u32);
> +	ucode_size = (header->size - header->header_len) * sizeof(u32);
> +
> +	I915_WRITE(DMA_COPY_SIZE, header_size + ucode_size);
> +
> +	/* where RSA signature starts */
> +	offset = header_size + ucode_size;
> +
> +	rsa_size = header->key_size * sizeof(u32);
> +	rsa = kmalloc(rsa_size, GFP_KERNEL);
> +	if (!rsa)
> +		return -ENOMEM;
>  
>  	/* Copy RSA signature from the fw image to HW for verification */
> -	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
> -	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
> +	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, rsa_size, offset);
> +	for (i = 0; i < rsa_size / sizeof(u32); i++)
>  		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]);
>  
> +	kfree(rsa);
> +
>  	/* Set the source address for the new blob */
>  	offset = i915_gem_obj_ggtt_offset(fw_obj);
>  	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
> @@ -458,10 +473,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  {
>  	struct drm_i915_gem_object *obj;
>  	const struct firmware *fw;
> -	const u8 *css_header;
> -	const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
> -	const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
> -			- 0x8000; /* 32k reserved (8K stack + 24k context) */
> +	struct guc_css_header *css_header = &guc_fw->guc_fw_header;
> +	size_t size;
>  	int err;
>  
>  	DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
> @@ -475,12 +488,31 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  
>  	DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
>  		guc_fw->guc_fw_path, fw);
> -	DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
> -		fw->size, minsize, maxsize);
>  
> -	/* Check the size of the blob befoe examining buffer contents */
> -	if (fw->size < minsize || fw->size > maxsize)
> +	/* Check the size of the blob before examining buffer contents */
> +	if (fw->size < sizeof(struct guc_css_header)) {
> +		DRM_ERROR("Firmware header is missing\n");
> +		goto fail;
> +	}
> +
> +	memcpy(css_header, fw->data, sizeof(struct guc_css_header));
> +
> +	/* At least, it should have header, uCode and RSA. Size of all three. */
> +	size = (css_header->size - css_header->modulus_size -
> +			css_header->exponent_size) * sizeof(u32);
> +	if (fw->size < size) {
> +		DRM_ERROR("Missing firmware components\n");
> +		goto fail;
> +	}
> +
> +	/* Header and uCode will be loaded to WOPCM. Size of the two. */
> +	size -= css_header->key_size * sizeof(u32);
> +
> +	/* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
> +	if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
> +		DRM_ERROR("Firmware is too large to fit in WOPCM\n");
>  		goto fail;
> +	}
>  
>  	/*
>  	 * The GuC firmware image has the version number embedded at a well-known
> @@ -488,9 +520,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  	 * TWO bytes each (i.e. u16), although all pointers and offsets are defined
>  	 * in terms of bytes (u8).
>  	 */
> -	css_header = fw->data + UOS_CSS_HEADER_OFFSET;
> -	guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
> -	guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
> +	guc_fw->guc_fw_major_found = css_header->guc_sw_version >> 16;
> +	guc_fw->guc_fw_minor_found = css_header->guc_sw_version & 0xFFFF;
>  
>  	if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
>  	    guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
> -- 
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
yu.dai@intel.com Sept. 3, 2015, 4:52 p.m. UTC | #2
On 09/03/2015 12:36 AM, Jani Nikula wrote:
> On Thu, 03 Sep 2015, yu.dai@intel.com wrote:
> > From: Alex Dai <yu.dai@intel.com>
> >
> > By using information from GuC css header, we can eliminate some
> > hard code w.r.t size of some components of firmware.
> >
> > Signed-off-by: Alex Dai <yu.dai@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_guc.h        |  2 +-
> >  drivers/gpu/drm/i915/intel_guc_fwif.h   | 36 +++++++++++++
> >  drivers/gpu/drm/i915/intel_guc_loader.c | 91 ++++++++++++++++++++++-----------
> >  3 files changed, 98 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> > index 4ec2d27..e1389fc 100644
> > --- a/drivers/gpu/drm/i915/intel_guc.h
> > +++ b/drivers/gpu/drm/i915/intel_guc.h
> > @@ -71,6 +71,7 @@ struct intel_guc_fw {
> >  	struct drm_i915_gem_object *	guc_fw_obj;
> >  	enum intel_guc_fw_status	guc_fw_fetch_status;
> >  	enum intel_guc_fw_status	guc_fw_load_status;
> > +	struct guc_css_header		guc_fw_header;
> >
> >  	uint16_t			guc_fw_major_wanted;
> >  	uint16_t			guc_fw_minor_wanted;
> > @@ -80,7 +81,6 @@ struct intel_guc_fw {
> >
> >  struct intel_guc {
> >  	struct intel_guc_fw guc_fw;
> > -
> >  	uint32_t log_flags;
> >  	struct drm_i915_gem_object *log_obj;
> >
> > diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
> > index e1f47ba..d6cb4e8 100644
> > --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
> > +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
> > @@ -122,6 +122,42 @@
> >
> >  #define GUC_CTL_MAX_DWORDS		(GUC_CTL_RSRVD + 1)
> >
> > +struct guc_css_header {
> > +	uint32_t module_type;
> > +	uint32_t header_len; /* header length plus size of all other keys */
> > +	uint32_t header_version;
> > +	uint32_t module_id;
> > +	uint32_t module_vendor;
> > +	union {
> > +		struct {
> > +			uint8_t day;
> > +			uint8_t month;
> > +			uint16_t year;
> > +		};
> > +		uint32_t date;
> > +	};
> > +	uint32_t size; /* uCode size plus header_len */
> > +	uint32_t key_size;
> > +	uint32_t modulus_size;
> > +	uint32_t exponent_size;
> > +	union {
> > +		struct {
> > +			uint8_t hour;
> > +			uint8_t min;
> > +			uint16_t sec;
> > +		};
> > +		uint32_t time;
> > +	};
> > +
> > +	char username[8];
> > +	char buildnumber[12];
> > +	uint32_t device_id;
> > +	uint32_t guc_sw_version;
> > +	uint32_t prod_preprod_fw;
> > +	uint32_t reserved[12];
> > +	uint32_t header_info;
> > +};
>
> Drive-by review, this will need __packed.
>
>
Yes, will correct this in next version. Thanks, -Alex
Daniel Vetter Sept. 4, 2015, 8:13 a.m. UTC | #3
On Wed, Sep 02, 2015 at 03:52:35PM -0700, yu.dai@intel.com wrote:
> From: Alex Dai <yu.dai@intel.com>
> 
> By using information from GuC css header, we can eliminate some
> hard code w.r.t size of some components of firmware.
> 
> Signed-off-by: Alex Dai <yu.dai@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc.h        |  2 +-
>  drivers/gpu/drm/i915/intel_guc_fwif.h   | 36 +++++++++++++
>  drivers/gpu/drm/i915/intel_guc_loader.c | 91 ++++++++++++++++++++++-----------
>  3 files changed, 98 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index 4ec2d27..e1389fc 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -71,6 +71,7 @@ struct intel_guc_fw {
>  	struct drm_i915_gem_object *	guc_fw_obj;
>  	enum intel_guc_fw_status	guc_fw_fetch_status;
>  	enum intel_guc_fw_status	guc_fw_load_status;
> +	struct guc_css_header		guc_fw_header;
>  
>  	uint16_t			guc_fw_major_wanted;
>  	uint16_t			guc_fw_minor_wanted;
> @@ -80,7 +81,6 @@ struct intel_guc_fw {
>  
>  struct intel_guc {
>  	struct intel_guc_fw guc_fw;
> -
>  	uint32_t log_flags;
>  	struct drm_i915_gem_object *log_obj;
>  
> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
> index e1f47ba..d6cb4e8 100644
> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
> @@ -122,6 +122,42 @@
>  
>  #define GUC_CTL_MAX_DWORDS		(GUC_CTL_RSRVD + 1)
>  
> +struct guc_css_header {
> +	uint32_t module_type;
> +	uint32_t header_len; /* header length plus size of all other keys */
> +	uint32_t header_version;
> +	uint32_t module_id;
> +	uint32_t module_vendor;
> +	union {
> +		struct {
> +			uint8_t day;
> +			uint8_t month;
> +			uint16_t year;
> +		};
> +		uint32_t date;
> +	};
> +	uint32_t size; /* uCode size plus header_len */
> +	uint32_t key_size;
> +	uint32_t modulus_size;
> +	uint32_t exponent_size;
> +	union {
> +		struct {
> +			uint8_t hour;
> +			uint8_t min;
> +			uint16_t sec;
> +		};
> +		uint32_t time;
> +	};
> +
> +	char username[8];
> +	char buildnumber[12];
> +	uint32_t device_id;
> +	uint32_t guc_sw_version;
> +	uint32_t prod_preprod_fw;
> +	uint32_t reserved[12];
> +	uint32_t header_info;
> +};
> +
>  struct guc_doorbell_info {
>  	u32 db_status;
>  	u32 cookie;
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 5823615..96826ae 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -215,18 +215,24 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
>  		((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
>  }
>  
> -/*
> +/**

You need at least a DOC: here plus add a line to pull this into the
drm.tmpl for kerneldoc to pick this up. Otherwise it'll complain. But I'd
really like this to be in the docbook, that's for sure.
-Daniel


>   * Transfer the firmware image to RAM for execution by the microcontroller.
>   *
>   * GuC Firmware layout:
> - * +-------------------------------+  ----
> - * |          CSS header           |  128B
> + * +-------------------------------+
> + * |        guc_css_header         |
>   * | contains major/minor version  |
> - * +-------------------------------+  ----
> + * +-------------------------------+
>   * |             uCode             |
> - * +-------------------------------+  ----
> - * |         RSA signature         |  256B
> - * +-------------------------------+  ----
> + * +-------------------------------+
> + * |         RSA signature         |
> + * +-------------------------------+
> + * |          modulus key          |
> + * +-------------------------------+
> + * |          exponent val         |
> + * +-------------------------------+
> + * The firmware may or may not have modulus key and exponent data. The header,
> + * uCode and RSA signature are must-have components that will be used by driver.
>   *
>   * Architecturally, the DMA engine is bidirectional, and can potentially even
>   * transfer between GTT locations. This functionality is left out of the API
> @@ -236,30 +242,39 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
>   * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
>   */
>  
> -#define UOS_CSS_HEADER_OFFSET		0
> -#define UOS_VER_MINOR_OFFSET		0x44
> -#define UOS_VER_MAJOR_OFFSET		0x46
> -#define UOS_CSS_HEADER_SIZE		0x80
> -#define UOS_RSA_SIG_SIZE		0x100
> -
>  static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
>  {
>  	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
> +	struct guc_css_header *header = &guc_fw->guc_fw_header;
>  	struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
>  	unsigned long offset;
>  	struct sg_table *sg = fw_obj->pages;
> -	u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
> +	u32 status, header_size, rsa_size, ucode_size, *rsa;
>  	int i, ret = 0;
>  
> -	/* uCode size, also is where RSA signature starts */
> -	offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
> -	I915_WRITE(DMA_COPY_SIZE, ucode_size);
> +	/* The header plus uCode will be copied to WOPCM via DMA, excluding any
> +	 * other components */
> +	header_size = (header->header_len - header->key_size -
> +		header->modulus_size - header->exponent_size) * sizeof(u32);
> +	ucode_size = (header->size - header->header_len) * sizeof(u32);
> +
> +	I915_WRITE(DMA_COPY_SIZE, header_size + ucode_size);
> +
> +	/* where RSA signature starts */
> +	offset = header_size + ucode_size;
> +
> +	rsa_size = header->key_size * sizeof(u32);
> +	rsa = kmalloc(rsa_size, GFP_KERNEL);
> +	if (!rsa)
> +		return -ENOMEM;
>  
>  	/* Copy RSA signature from the fw image to HW for verification */
> -	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
> -	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
> +	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, rsa_size, offset);
> +	for (i = 0; i < rsa_size / sizeof(u32); i++)
>  		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]);
>  
> +	kfree(rsa);
> +
>  	/* Set the source address for the new blob */
>  	offset = i915_gem_obj_ggtt_offset(fw_obj);
>  	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
> @@ -458,10 +473,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  {
>  	struct drm_i915_gem_object *obj;
>  	const struct firmware *fw;
> -	const u8 *css_header;
> -	const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
> -	const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
> -			- 0x8000; /* 32k reserved (8K stack + 24k context) */
> +	struct guc_css_header *css_header = &guc_fw->guc_fw_header;
> +	size_t size;
>  	int err;
>  
>  	DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
> @@ -475,12 +488,31 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  
>  	DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
>  		guc_fw->guc_fw_path, fw);
> -	DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
> -		fw->size, minsize, maxsize);
>  
> -	/* Check the size of the blob befoe examining buffer contents */
> -	if (fw->size < minsize || fw->size > maxsize)
> +	/* Check the size of the blob before examining buffer contents */
> +	if (fw->size < sizeof(struct guc_css_header)) {
> +		DRM_ERROR("Firmware header is missing\n");
> +		goto fail;
> +	}
> +
> +	memcpy(css_header, fw->data, sizeof(struct guc_css_header));
> +
> +	/* At least, it should have header, uCode and RSA. Size of all three. */
> +	size = (css_header->size - css_header->modulus_size -
> +			css_header->exponent_size) * sizeof(u32);
> +	if (fw->size < size) {
> +		DRM_ERROR("Missing firmware components\n");
> +		goto fail;
> +	}
> +
> +	/* Header and uCode will be loaded to WOPCM. Size of the two. */
> +	size -= css_header->key_size * sizeof(u32);
> +
> +	/* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
> +	if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
> +		DRM_ERROR("Firmware is too large to fit in WOPCM\n");
>  		goto fail;
> +	}
>  
>  	/*
>  	 * The GuC firmware image has the version number embedded at a well-known
> @@ -488,9 +520,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
>  	 * TWO bytes each (i.e. u16), although all pointers and offsets are defined
>  	 * in terms of bytes (u8).
>  	 */
> -	css_header = fw->data + UOS_CSS_HEADER_OFFSET;
> -	guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
> -	guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
> +	guc_fw->guc_fw_major_found = css_header->guc_sw_version >> 16;
> +	guc_fw->guc_fw_minor_found = css_header->guc_sw_version & 0xFFFF;
>  
>  	if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
>  	    guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 4ec2d27..e1389fc 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -71,6 +71,7 @@  struct intel_guc_fw {
 	struct drm_i915_gem_object *	guc_fw_obj;
 	enum intel_guc_fw_status	guc_fw_fetch_status;
 	enum intel_guc_fw_status	guc_fw_load_status;
+	struct guc_css_header		guc_fw_header;
 
 	uint16_t			guc_fw_major_wanted;
 	uint16_t			guc_fw_minor_wanted;
@@ -80,7 +81,6 @@  struct intel_guc_fw {
 
 struct intel_guc {
 	struct intel_guc_fw guc_fw;
-
 	uint32_t log_flags;
 	struct drm_i915_gem_object *log_obj;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index e1f47ba..d6cb4e8 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -122,6 +122,42 @@ 
 
 #define GUC_CTL_MAX_DWORDS		(GUC_CTL_RSRVD + 1)
 
+struct guc_css_header {
+	uint32_t module_type;
+	uint32_t header_len; /* header length plus size of all other keys */
+	uint32_t header_version;
+	uint32_t module_id;
+	uint32_t module_vendor;
+	union {
+		struct {
+			uint8_t day;
+			uint8_t month;
+			uint16_t year;
+		};
+		uint32_t date;
+	};
+	uint32_t size; /* uCode size plus header_len */
+	uint32_t key_size;
+	uint32_t modulus_size;
+	uint32_t exponent_size;
+	union {
+		struct {
+			uint8_t hour;
+			uint8_t min;
+			uint16_t sec;
+		};
+		uint32_t time;
+	};
+
+	char username[8];
+	char buildnumber[12];
+	uint32_t device_id;
+	uint32_t guc_sw_version;
+	uint32_t prod_preprod_fw;
+	uint32_t reserved[12];
+	uint32_t header_info;
+};
+
 struct guc_doorbell_info {
 	u32 db_status;
 	u32 cookie;
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 5823615..96826ae 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -215,18 +215,24 @@  static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
 		((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
 }
 
-/*
+/**
  * Transfer the firmware image to RAM for execution by the microcontroller.
  *
  * GuC Firmware layout:
- * +-------------------------------+  ----
- * |          CSS header           |  128B
+ * +-------------------------------+
+ * |        guc_css_header         |
  * | contains major/minor version  |
- * +-------------------------------+  ----
+ * +-------------------------------+
  * |             uCode             |
- * +-------------------------------+  ----
- * |         RSA signature         |  256B
- * +-------------------------------+  ----
+ * +-------------------------------+
+ * |         RSA signature         |
+ * +-------------------------------+
+ * |          modulus key          |
+ * +-------------------------------+
+ * |          exponent val         |
+ * +-------------------------------+
+ * The firmware may or may not have modulus key and exponent data. The header,
+ * uCode and RSA signature are must-have components that will be used by driver.
  *
  * Architecturally, the DMA engine is bidirectional, and can potentially even
  * transfer between GTT locations. This functionality is left out of the API
@@ -236,30 +242,39 @@  static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
  * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
  */
 
-#define UOS_CSS_HEADER_OFFSET		0
-#define UOS_VER_MINOR_OFFSET		0x44
-#define UOS_VER_MAJOR_OFFSET		0x46
-#define UOS_CSS_HEADER_SIZE		0x80
-#define UOS_RSA_SIG_SIZE		0x100
-
 static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+	struct guc_css_header *header = &guc_fw->guc_fw_header;
 	struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
 	unsigned long offset;
 	struct sg_table *sg = fw_obj->pages;
-	u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
+	u32 status, header_size, rsa_size, ucode_size, *rsa;
 	int i, ret = 0;
 
-	/* uCode size, also is where RSA signature starts */
-	offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
-	I915_WRITE(DMA_COPY_SIZE, ucode_size);
+	/* The header plus uCode will be copied to WOPCM via DMA, excluding any
+	 * other components */
+	header_size = (header->header_len - header->key_size -
+		header->modulus_size - header->exponent_size) * sizeof(u32);
+	ucode_size = (header->size - header->header_len) * sizeof(u32);
+
+	I915_WRITE(DMA_COPY_SIZE, header_size + ucode_size);
+
+	/* where RSA signature starts */
+	offset = header_size + ucode_size;
+
+	rsa_size = header->key_size * sizeof(u32);
+	rsa = kmalloc(rsa_size, GFP_KERNEL);
+	if (!rsa)
+		return -ENOMEM;
 
 	/* Copy RSA signature from the fw image to HW for verification */
-	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
-	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
+	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, rsa_size, offset);
+	for (i = 0; i < rsa_size / sizeof(u32); i++)
 		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]);
 
+	kfree(rsa);
+
 	/* Set the source address for the new blob */
 	offset = i915_gem_obj_ggtt_offset(fw_obj);
 	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
@@ -458,10 +473,8 @@  static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 {
 	struct drm_i915_gem_object *obj;
 	const struct firmware *fw;
-	const u8 *css_header;
-	const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
-	const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
-			- 0x8000; /* 32k reserved (8K stack + 24k context) */
+	struct guc_css_header *css_header = &guc_fw->guc_fw_header;
+	size_t size;
 	int err;
 
 	DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
@@ -475,12 +488,31 @@  static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 
 	DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
 		guc_fw->guc_fw_path, fw);
-	DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
-		fw->size, minsize, maxsize);
 
-	/* Check the size of the blob befoe examining buffer contents */
-	if (fw->size < minsize || fw->size > maxsize)
+	/* Check the size of the blob before examining buffer contents */
+	if (fw->size < sizeof(struct guc_css_header)) {
+		DRM_ERROR("Firmware header is missing\n");
+		goto fail;
+	}
+
+	memcpy(css_header, fw->data, sizeof(struct guc_css_header));
+
+	/* At least, it should have header, uCode and RSA. Size of all three. */
+	size = (css_header->size - css_header->modulus_size -
+			css_header->exponent_size) * sizeof(u32);
+	if (fw->size < size) {
+		DRM_ERROR("Missing firmware components\n");
+		goto fail;
+	}
+
+	/* Header and uCode will be loaded to WOPCM. Size of the two. */
+	size -= css_header->key_size * sizeof(u32);
+
+	/* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
+	if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
+		DRM_ERROR("Firmware is too large to fit in WOPCM\n");
 		goto fail;
+	}
 
 	/*
 	 * The GuC firmware image has the version number embedded at a well-known
@@ -488,9 +520,8 @@  static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 	 * TWO bytes each (i.e. u16), although all pointers and offsets are defined
 	 * in terms of bytes (u8).
 	 */
-	css_header = fw->data + UOS_CSS_HEADER_OFFSET;
-	guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
-	guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
+	guc_fw->guc_fw_major_found = css_header->guc_sw_version >> 16;
+	guc_fw->guc_fw_minor_found = css_header->guc_sw_version & 0xFFFF;
 
 	if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
 	    guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {