Re: [Freedreno] [PATCH 2/2] drm/msm/adreno: Add A6XX device support

2018-02-14 Thread Jordan Crouse
On Thu, Feb 01, 2018 at 11:32:25AM +0100, Lucas Stach wrote:
> Hi Jordan,
> 
> just some drive-by comments:

Drive by comments are the best.

> Am Mittwoch, den 31.01.2018, 11:25 -0700 schrieb Jordan Crouse:
> > Add support for the A6XX family of Adreno GPUs. The biggest addition
> > is the GMU (Graphics Management Unit) which takes over most of the
> > power management of the GPU itself but in a ironic twist of fate
> > needs a goodly amount of management itself. Add support for the
> > A6XX core code, the GMU and the HFI (hardware firmware interface)
> > queue that the CPU uses to communicate with the GMU.
> > 
> > > Signed-off-by: Jordan Crouse 
> > ---
> [...]
> > +static int a6xx_hfi_queue_read(struct a6xx_hfi_queue *queue, u32 *data,
> > > + u32 dwords)
> > +{
> > > + struct a6xx_hfi_queue_header *header = queue->header;
> > > + u32 i, hdr, index = header->read_index;
> > +
> > > + if (header->read_index == header->write_index) {
> > > + header->rx_request = 1;
> > > + return 0;
> > > + }
> > +
> > > + hdr = queue->data[index];
> > +
> > > + /*
> > > +  * If we are to assume that the GMU firmware is in fact a rational actor
> > > +  * and is programmed to not send us a larger response than we expect
> > > +  * then we can also assume that if the header size is unexpectedly large
> > > +  * that it is due to memory corruption and/or hardware failure. In this
> > > +  * case the only reasonable course of action is to BUG() to help harden
> > > +  * the failure.
> > > +  */
> > +
> > +   BUG_ON(HFI_HEADER_SIZE(hdr) > dwords);
> 
> Don't ever BUG the kernel due to a peripheral acting up, until you are
> really certain that it has corrupted memory it doesn't own, which would
> be written back to persistent storage. That's the only valid
> justification for a BUG.

Acknowledged. In the final version we'll try to zap the hardware and recover
cleanly but I don't have that coded up yet.  Don't worry, I wouldn't let it
merge with a BUG().

> > +
> > > + for (i = 0; i < HFI_HEADER_SIZE(hdr); i++) {
> > > + data[i] = queue->data[index];
> > > + index = (index + 1) % header->size;
> > > + }
> > +
> > > + header->read_index = index;
> > > + return HFI_HEADER_SIZE(hdr);
> > +}
> > +
> > +static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
> > > + struct a6xx_hfi_queue *queue, u32 *data, u32 dwords)
> > +{
> > > + struct a6xx_hfi_queue_header *header = queue->header;
> > > + u32 i, space, index = header->write_index;
> > +
> > > + spin_lock(&queue->lock);
> > +
> > > + space = CIRC_SPACE(header->write_index, header->read_index,
> > > + header->size);
> > > + if (space < dwords) {
> > > + header->dropped++;
> > > + spin_unlock(&queue->lock);
> > > + return -ENOSPC;
> > > + }
> > +
> > > + for (i = 0; i < dwords; i++) {
> > > + queue->data[index] = data[i];
> > > + index = (index + 1) % header->size;
> > > + }
> > +
> > > + header->write_index = index;
> > > + spin_unlock(&queue->lock);
> > +
> > > + /* Make sure the command is written to the queue */
> > > + wmb();
> 
> The above memory barrier is unnecessary. The gmu_write below is a
> wrapper around writel, which already includes the write barrier.

Thanks.  I got this one and a few others I found too.

> > +   gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
> > > + return 0;
> > +}
> 
> [...]
> > +static int a6xx_hfi_send_msg(struct a6xx_gmu *gmu, int id,
> > > + void *data, u32 size, u32 *payload, u32 payload_size)
> > +{
> > > + struct a6xx_hfi_queue *queue = &gmu->queues[HFI_COMMAND_QUEUE];
> > > + struct a6xx_hfi_response resp = { 0 };
> > > + int ret, dwords = size >> 2;
> > > + u32 seqnum;
> > +
> > > + seqnum = atomic_inc_return(&queue->seqnum) % 0xfff;
> > +
> > > + /* First dword of the message is the message header - fill it in */
> > > + *((u32 *) data) = (seqnum << 20) | (HFI_MSG_CMD << 16) |
> > > + (dwords << 8) | id;
> > +
> > > + init_completion(&resp.complete);
> > > + resp.id = id;
> > > + resp.seqnum = seqnum;
> > +
> > > + spin_lock_bh(&hfi_ack_lock);
> > > + list_add_tail(&resp.node, &hfi_ack_list);
> > > + spin_unlock_bh(&hfi_ack_lock);
> 
> What are you protecting against here by using the _bh spinlock
> variants?

We use a tasklet from the interrupt to process responses. The
commands are entirely serialized right now so this is mostly wasted
cycles but we are planning for a brave future where the commands
may be asynchronous.

> Regards,
> Lucas

Thanks,
Jordan
-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [PATCH 2/2] drm/msm/adreno: Add A6XX device support

2018-02-01 Thread kbuild test robot
Hi Jordan,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robclark/msm-next]
[also build test ERROR on next-20180201]
[cannot apply to v4.15]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Jordan-Crouse/drm-msm-Add-support-for-Adreno-a6xx/20180201-224050
base:   git://people.freedesktop.org/~robclark/linux msm-next
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   drivers/gpu/drm/msm/adreno/a6xx_gpu.c: In function 'a6xx_ucode_init':
>> drivers/gpu/drm/msm/adreno/a6xx_gpu.c:301:22: error: implicit declaration of 
>> function 'adreno_request_fw_bo'; did you mean 'adreno_request_fw'? 
>> [-Werror=implicit-function-declaration]
  a6xx_gpu->sqe_bo = adreno_request_fw_bo(gpu,
 ^~~~
 adreno_request_fw
>> drivers/gpu/drm/msm/adreno/a6xx_gpu.c:301:20: warning: assignment makes 
>> pointer from integer without a cast [-Wint-conversion]
  a6xx_gpu->sqe_bo = adreno_request_fw_bo(gpu,
   ^
   cc1: some warnings being treated as errors
--
>> drivers/gpu/drm/msm/adreno/a6xx_gmu.c:17:10: fatal error: soc/qcom/cmd-db.h: 
>> No such file or directory
#include 
 ^~~
   compilation terminated.

vim +301 drivers/gpu/drm/msm/adreno/a6xx_gpu.c

   294  
   295  static int a6xx_ucode_init(struct msm_gpu *gpu)
   296  {
   297  struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
   298  struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
   299  
   300  if (!a6xx_gpu->sqe_bo) {
 > 301  a6xx_gpu->sqe_bo = adreno_request_fw_bo(gpu,
   302  adreno_gpu->info->pm4fw, &a6xx_gpu->sqe_iova);
   303  
   304  if (IS_ERR(a6xx_gpu->sqe_bo)) {
   305  int ret = PTR_ERR(a6xx_gpu->sqe_bo);
   306  
   307  a6xx_gpu->sqe_bo = NULL;
   308  DRM_DEV_ERROR(&gpu->pdev->dev,
   309  "Could not allocate SQE ucode: %d\n", 
ret);
   310  
   311  return ret;
   312  }
   313  }
   314  
   315  gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE_LO,
   316  REG_A6XX_CP_SQE_INSTR_BASE_HI, a6xx_gpu->sqe_iova);
   317  
   318  return 0;
   319  }
   320  

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [PATCH 2/2] drm/msm/adreno: Add A6XX device support

2018-02-01 Thread Lucas Stach
Hi Jordan,

just some drive-by comments:

Am Mittwoch, den 31.01.2018, 11:25 -0700 schrieb Jordan Crouse:
> Add support for the A6XX family of Adreno GPUs. The biggest addition
> is the GMU (Graphics Management Unit) which takes over most of the
> power management of the GPU itself but in a ironic twist of fate
> needs a goodly amount of management itself. Add support for the
> A6XX core code, the GMU and the HFI (hardware firmware interface)
> queue that the CPU uses to communicate with the GMU.
> 
> > Signed-off-by: Jordan Crouse 
> ---
[...]
> +static int a6xx_hfi_queue_read(struct a6xx_hfi_queue *queue, u32 *data,
> > +   u32 dwords)
> +{
> > +   struct a6xx_hfi_queue_header *header = queue->header;
> > +   u32 i, hdr, index = header->read_index;
> +
> > +   if (header->read_index == header->write_index) {
> > +   header->rx_request = 1;
> > +   return 0;
> > +   }
> +
> > +   hdr = queue->data[index];
> +
> > +   /*
> > +    * If we are to assume that the GMU firmware is in fact a rational actor
> > +    * and is programmed to not send us a larger response than we expect
> > +    * then we can also assume that if the header size is unexpectedly large
> > +    * that it is due to memory corruption and/or hardware failure. In this
> > +    * case the only reasonable course of action is to BUG() to help harden
> > +    * the failure.
> > +    */
> +
> + BUG_ON(HFI_HEADER_SIZE(hdr) > dwords);

Don't ever BUG the kernel due to a peripheral acting up, until you are
really certain that it has corrupted memory it doesn't own, which would
be written back to persistent storage. That's the only valid
justification for a BUG.

> +
> > +   for (i = 0; i < HFI_HEADER_SIZE(hdr); i++) {
> > +   data[i] = queue->data[index];
> > +   index = (index + 1) % header->size;
> > +   }
> +
> > +   header->read_index = index;
> > +   return HFI_HEADER_SIZE(hdr);
> +}
> +
> +static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
> > +   struct a6xx_hfi_queue *queue, u32 *data, u32 dwords)
> +{
> > +   struct a6xx_hfi_queue_header *header = queue->header;
> > +   u32 i, space, index = header->write_index;
> +
> > +   spin_lock(&queue->lock);
> +
> > +   space = CIRC_SPACE(header->write_index, header->read_index,
> > +   header->size);
> > +   if (space < dwords) {
> > +   header->dropped++;
> > +   spin_unlock(&queue->lock);
> > +   return -ENOSPC;
> > +   }
> +
> > +   for (i = 0; i < dwords; i++) {
> > +   queue->data[index] = data[i];
> > +   index = (index + 1) % header->size;
> > +   }
> +
> > +   header->write_index = index;
> > +   spin_unlock(&queue->lock);
> +
> > +   /* Make sure the command is written to the queue */
> > +   wmb();

The above memory barrier is unnecessary. The gmu_write below is a
wrapper around writel, which already includes the write barrier.

> + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
> > +   return 0;
> +}

[...]
> +static int a6xx_hfi_send_msg(struct a6xx_gmu *gmu, int id,
> > +   void *data, u32 size, u32 *payload, u32 payload_size)
> +{
> > +   struct a6xx_hfi_queue *queue = &gmu->queues[HFI_COMMAND_QUEUE];
> > +   struct a6xx_hfi_response resp = { 0 };
> > +   int ret, dwords = size >> 2;
> > +   u32 seqnum;
> +
> > +   seqnum = atomic_inc_return(&queue->seqnum) % 0xfff;
> +
> > +   /* First dword of the message is the message header - fill it in */
> > +   *((u32 *) data) = (seqnum << 20) | (HFI_MSG_CMD << 16) |
> > +   (dwords << 8) | id;
> +
> > +   init_completion(&resp.complete);
> > +   resp.id = id;
> > +   resp.seqnum = seqnum;
> +
> > +   spin_lock_bh(&hfi_ack_lock);
> > +   list_add_tail(&resp.node, &hfi_ack_list);
> > +   spin_unlock_bh(&hfi_ack_lock);

What are you protecting against here by using the _bh spinlock
variants?

> + ret = a6xx_hfi_queue_write(gmu, queue, data, dwords);
> > +   if (ret) {
> > +   dev_err(gmu->dev, "Unable to send message %s id %d\n",
> > +   a6xx_hfi_msg_id[id], seqnum);
> > +   goto out;
> > +   }
> +
> > +   /* Wait up to 5 seconds for the response */
> > +   ret = wait_for_completion_timeout(&resp.complete,
> > +   msecs_to_jiffies(5000));
> > +   if (!ret) {
> > +   dev_err(gmu->dev,
> > +   "Message %s id %d timed out waiting for response\n",
> > +   a6xx_hfi_msg_id[id], seqnum);
> > +   ret = -ETIMEDOUT;
> > +   } else
> > +   ret = 0;
> +
> +out:
> > +   spin_lock_bh(&hfi_ack_lock);
> > +   list_del(&resp.node);
> > +   spin_unlock_bh(&hfi_ack_lock);
> +
> > +   if (ret)
> > +   return ret;
> +
> > +   if (resp.error) {
> > +   dev_err(gmu->dev, "Message %s id %d returned error %d\n",
> > +   a6xx_hfi_msg_id[id], seqnum, resp.error);
> > +   return -EINVAL;
> > +   }
> +
> > +   if (payload && payload_size) {
> > +   int copy = min_t(u32, payload_size, sizeof(resp.payload));
>