diff mbox series

[1/2] powerpc/spufs: fix copy_to_user while atomic

Message ID 20200429070303.17599-1-jk@ozlabs.org (mailing list archive)
State Not Applicable
Headers show
Series [1/2] powerpc/spufs: fix copy_to_user while atomic | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch powerpc/merge (54dc28ff5e0b3585224d49a31b53e030342ca5c3)
snowpatch_ozlabs/checkpatch warning total: 0 errors, 0 warnings, 3 checks, 234 lines checked
snowpatch_ozlabs/needsstable warning Please consider tagging this patch for stable!

Commit Message

Jeremy Kerr April 29, 2020, 7:03 a.m. UTC
Currently, we may perform a copy_to_user (through
simple_read_from_buffer()) while holding a context's register_lock,
while accessing the context save area.

This change uses a temporary buffer for the context save area data,
which we then pass to simple_read_from_buffer.

Includes changes from Christoph Hellwig <hch@lst.de>.

Fixes: bf1ab978be23 ("[POWERPC] coredump: Add SPU elf notes to coredump.")
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 arch/powerpc/platforms/cell/spufs/file.c | 113 +++++++++++++++--------
 1 file changed, 75 insertions(+), 38 deletions(-)

Comments

Christoph Hellwig May 4, 2020, 1:04 p.m. UTC | #1
powerpc mantainers,

are you going to pick this up for the next -rc1?  I'm waiting for it to
hit upstream before resending the coredump series.

On Wed, Apr 29, 2020 at 03:03:02PM +0800, Jeremy Kerr wrote:
> Currently, we may perform a copy_to_user (through
> simple_read_from_buffer()) while holding a context's register_lock,
> while accessing the context save area.
> 
> This change uses a temporary buffer for the context save area data,
> which we then pass to simple_read_from_buffer.
> 
> Includes changes from Christoph Hellwig <hch@lst.de>.
> 
> Fixes: bf1ab978be23 ("[POWERPC] coredump: Add SPU elf notes to coredump.")
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> ---
>  arch/powerpc/platforms/cell/spufs/file.c | 113 +++++++++++++++--------
>  1 file changed, 75 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
> index c0f950a3f4e1..b4e1ef650b40 100644
> --- a/arch/powerpc/platforms/cell/spufs/file.c
> +++ b/arch/powerpc/platforms/cell/spufs/file.c
> @@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
>  static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
>  				   size_t len, loff_t *pos)
>  {
> -	int ret;
>  	struct spu_context *ctx = file->private_data;
> +	u32 stat, data;
> +	int ret;
>  
>  	if (!access_ok(buf, len))
>  		return -EFAULT;
> @@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
>  	if (ret)
>  		return ret;
>  	spin_lock(&ctx->csa.register_lock);
> -	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
> +	stat = ctx->csa.prob.mb_stat_R;
> +	data = ctx->csa.prob.pu_mb_R;
>  	spin_unlock(&ctx->csa.register_lock);
>  	spu_release_saved(ctx);
>  
> -	return ret;
> +	/* EOF if there's no entry in the mbox */
> +	if (!(stat & 0x0000ff))
> +		return 0;
> +
> +	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
>  }
>  
>  static const struct file_operations spufs_mbox_info_fops = {
> @@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
>  				   size_t len, loff_t *pos)
>  {
>  	struct spu_context *ctx = file->private_data;
> +	u32 stat, data;
>  	int ret;
>  
>  	if (!access_ok(buf, len))
> @@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
>  	if (ret)
>  		return ret;
>  	spin_lock(&ctx->csa.register_lock);
> -	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
> +	stat = ctx->csa.prob.mb_stat_R;
> +	data = ctx->csa.priv2.puint_mb_R;
>  	spin_unlock(&ctx->csa.register_lock);
>  	spu_release_saved(ctx);
>  
> -	return ret;
> +	/* EOF if there's no entry in the ibox */
> +	if (!(stat & 0xff0000))
> +		return 0;
> +
> +	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
>  }
>  
>  static const struct file_operations spufs_ibox_info_fops = {
> @@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = {
>  	.llseek  = generic_file_llseek,
>  };
>  
> +static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
> +{
> +	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
> +}
> +
>  static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
>  			char __user *buf, size_t len, loff_t *pos)
>  {
> @@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
>  	u32 wbox_stat;
>  
>  	wbox_stat = ctx->csa.prob.mb_stat_R;
> -	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
> +	cnt = spufs_wbox_info_cnt(ctx);
>  	for (i = 0; i < cnt; i++) {
>  		data[i] = ctx->csa.spu_mailbox_data[i];
>  	}
> @@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
>  				   size_t len, loff_t *pos)
>  {
>  	struct spu_context *ctx = file->private_data;
> -	int ret;
> +	u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
> +	int ret, count;
>  
>  	if (!access_ok(buf, len))
>  		return -EFAULT;
> @@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
>  	if (ret)
>  		return ret;
>  	spin_lock(&ctx->csa.register_lock);
> -	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
> +	count = spufs_wbox_info_cnt(ctx);
> +	memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
>  	spin_unlock(&ctx->csa.register_lock);
>  	spu_release_saved(ctx);
>  
> -	return ret;
> +	return simple_read_from_buffer(buf, len, pos, &data,
> +				count * sizeof(u32));
>  }
>  
>  static const struct file_operations spufs_wbox_info_fops = {
> @@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = {
>  	.llseek  = generic_file_llseek,
>  };
>  
> -static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
> -			char __user *buf, size_t len, loff_t *pos)
> +static void ___spufs_dma_info_read(struct spu_context *ctx,
> +		struct spu_dma_info *info)
>  {
> -	struct spu_dma_info info;
> -	struct mfc_cq_sr *qp, *spuqp;
>  	int i;
>  
> -	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
> -	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
> -	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
> -	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
> -	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
> +	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
> +	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
> +	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
> +	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
> +	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
>  	for (i = 0; i < 16; i++) {
> -		qp = &info.dma_info_command_data[i];
> -		spuqp = &ctx->csa.priv2.spuq[i];
> +		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
> +		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
>  
>  		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
>  		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
>  		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
>  		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
>  	}
> +}
> +
> +static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
> +			char __user *buf, size_t len, loff_t *pos)
> +{
> +	struct spu_dma_info info;
> +
> +	___spufs_dma_info_read(ctx, &info);
>  
>  	return simple_read_from_buffer(buf, len, pos, &info,
>  				sizeof info);
> @@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
>  			      size_t len, loff_t *pos)
>  {
>  	struct spu_context *ctx = file->private_data;
> +	struct spu_dma_info info;
>  	int ret;
>  
>  	if (!access_ok(buf, len))
> @@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
>  	if (ret)
>  		return ret;
>  	spin_lock(&ctx->csa.register_lock);
> -	ret = __spufs_dma_info_read(ctx, buf, len, pos);
> +	___spufs_dma_info_read(ctx, &info);
>  	spin_unlock(&ctx->csa.register_lock);
>  	spu_release_saved(ctx);
>  
> -	return ret;
> +	return simple_read_from_buffer(buf, len, pos, &info,
> +				sizeof(info));
>  }
>  
>  static const struct file_operations spufs_dma_info_fops = {
> @@ -2136,13 +2164,31 @@ static const struct file_operations spufs_dma_info_fops = {
>  	.llseek = no_llseek,
>  };
>  
> +static void ___spufs_proxydma_info_read(struct spu_context *ctx,
> +		struct spu_proxydma_info *info)
> +{
> +	int i;
> +
> +	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
> +	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
> +	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
> +
> +	for (i = 0; i < 8; i++) {
> +		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
> +		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
> +
> +		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
> +		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
> +		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
> +		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
> +	}
> +}
> +
>  static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
>  			char __user *buf, size_t len, loff_t *pos)
>  {
>  	struct spu_proxydma_info info;
> -	struct mfc_cq_sr *qp, *puqp;
>  	int ret = sizeof info;
> -	int i;
>  
>  	if (len < ret)
>  		return -EINVAL;
> @@ -2150,18 +2196,7 @@ static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
>  	if (!access_ok(buf, len))
>  		return -EFAULT;
>  
> -	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
> -	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
> -	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
> -	for (i = 0; i < 8; i++) {
> -		qp = &info.proxydma_info_command_data[i];
> -		puqp = &ctx->csa.priv2.puq[i];
> -
> -		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
> -		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
> -		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
> -		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
> -	}
> +	___spufs_proxydma_info_read(ctx, &info);
>  
>  	return simple_read_from_buffer(buf, len, pos, &info,
>  				sizeof info);
> @@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
>  				   size_t len, loff_t *pos)
>  {
>  	struct spu_context *ctx = file->private_data;
> +	struct spu_proxydma_info info;
>  	int ret;
>  
>  	ret = spu_acquire_saved(ctx);
>  	if (ret)
>  		return ret;
>  	spin_lock(&ctx->csa.register_lock);
> -	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
> +	___spufs_proxydma_info_read(ctx, &info);
>  	spin_unlock(&ctx->csa.register_lock);
>  	spu_release_saved(ctx);
>  
> -	return ret;
> +	return simple_read_from_buffer(buf, len, pos, &info,
> +				sizeof(info));
>  }
>  
>  static const struct file_operations spufs_proxydma_info_fops = {
> -- 
> 2.17.1
---end quoted text---
Michael Ellerman May 5, 2020, 7:20 a.m. UTC | #2
Christoph Hellwig <hch@lst.de> writes:
> powerpc mantainers,

There's only one of me.

> are you going to pick this up for the next -rc1?  I'm waiting for it to
> hit upstream before resending the coredump series.

I thought you were going to take it in your series. 

Otherwise you'll be waiting 4 or more weeks before this hits rc1.

I can put it in a topic branch if you're worried about merge conflicts.

There's also the fcheck() RCU fix I need to repost as a proper patch, it
seems to work.

cheers

> On Wed, Apr 29, 2020 at 03:03:02PM +0800, Jeremy Kerr wrote:
>> Currently, we may perform a copy_to_user (through
>> simple_read_from_buffer()) while holding a context's register_lock,
>> while accessing the context save area.
>> 
>> This change uses a temporary buffer for the context save area data,
>> which we then pass to simple_read_from_buffer.
>> 
>> Includes changes from Christoph Hellwig <hch@lst.de>.
>> 
>> Fixes: bf1ab978be23 ("[POWERPC] coredump: Add SPU elf notes to coredump.")
>> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
>> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
>> Reviewed-by: Christoph Hellwig <hch@lst.de>
>> ---
>>  arch/powerpc/platforms/cell/spufs/file.c | 113 +++++++++++++++--------
>>  1 file changed, 75 insertions(+), 38 deletions(-)
>> 
>> diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
>> index c0f950a3f4e1..b4e1ef650b40 100644
>> --- a/arch/powerpc/platforms/cell/spufs/file.c
>> +++ b/arch/powerpc/platforms/cell/spufs/file.c
>> @@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
>>  static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
>>  				   size_t len, loff_t *pos)
>>  {
>> -	int ret;
>>  	struct spu_context *ctx = file->private_data;
>> +	u32 stat, data;
>> +	int ret;
>>  
>>  	if (!access_ok(buf, len))
>>  		return -EFAULT;
>> @@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
>>  	if (ret)
>>  		return ret;
>>  	spin_lock(&ctx->csa.register_lock);
>> -	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
>> +	stat = ctx->csa.prob.mb_stat_R;
>> +	data = ctx->csa.prob.pu_mb_R;
>>  	spin_unlock(&ctx->csa.register_lock);
>>  	spu_release_saved(ctx);
>>  
>> -	return ret;
>> +	/* EOF if there's no entry in the mbox */
>> +	if (!(stat & 0x0000ff))
>> +		return 0;
>> +
>> +	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
>>  }
>>  
>>  static const struct file_operations spufs_mbox_info_fops = {
>> @@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
>>  				   size_t len, loff_t *pos)
>>  {
>>  	struct spu_context *ctx = file->private_data;
>> +	u32 stat, data;
>>  	int ret;
>>  
>>  	if (!access_ok(buf, len))
>> @@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
>>  	if (ret)
>>  		return ret;
>>  	spin_lock(&ctx->csa.register_lock);
>> -	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
>> +	stat = ctx->csa.prob.mb_stat_R;
>> +	data = ctx->csa.priv2.puint_mb_R;
>>  	spin_unlock(&ctx->csa.register_lock);
>>  	spu_release_saved(ctx);
>>  
>> -	return ret;
>> +	/* EOF if there's no entry in the ibox */
>> +	if (!(stat & 0xff0000))
>> +		return 0;
>> +
>> +	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
>>  }
>>  
>>  static const struct file_operations spufs_ibox_info_fops = {
>> @@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = {
>>  	.llseek  = generic_file_llseek,
>>  };
>>  
>> +static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
>> +{
>> +	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
>> +}
>> +
>>  static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
>>  			char __user *buf, size_t len, loff_t *pos)
>>  {
>> @@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
>>  	u32 wbox_stat;
>>  
>>  	wbox_stat = ctx->csa.prob.mb_stat_R;
>> -	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
>> +	cnt = spufs_wbox_info_cnt(ctx);
>>  	for (i = 0; i < cnt; i++) {
>>  		data[i] = ctx->csa.spu_mailbox_data[i];
>>  	}
>> @@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
>>  				   size_t len, loff_t *pos)
>>  {
>>  	struct spu_context *ctx = file->private_data;
>> -	int ret;
>> +	u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
>> +	int ret, count;
>>  
>>  	if (!access_ok(buf, len))
>>  		return -EFAULT;
>> @@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
>>  	if (ret)
>>  		return ret;
>>  	spin_lock(&ctx->csa.register_lock);
>> -	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
>> +	count = spufs_wbox_info_cnt(ctx);
>> +	memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
>>  	spin_unlock(&ctx->csa.register_lock);
>>  	spu_release_saved(ctx);
>>  
>> -	return ret;
>> +	return simple_read_from_buffer(buf, len, pos, &data,
>> +				count * sizeof(u32));
>>  }
>>  
>>  static const struct file_operations spufs_wbox_info_fops = {
>> @@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = {
>>  	.llseek  = generic_file_llseek,
>>  };
>>  
>> -static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
>> -			char __user *buf, size_t len, loff_t *pos)
>> +static void ___spufs_dma_info_read(struct spu_context *ctx,
>> +		struct spu_dma_info *info)
>>  {
>> -	struct spu_dma_info info;
>> -	struct mfc_cq_sr *qp, *spuqp;
>>  	int i;
>>  
>> -	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
>> -	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
>> -	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
>> -	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
>> -	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
>> +	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
>> +	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
>> +	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
>> +	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
>> +	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
>>  	for (i = 0; i < 16; i++) {
>> -		qp = &info.dma_info_command_data[i];
>> -		spuqp = &ctx->csa.priv2.spuq[i];
>> +		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
>> +		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
>>  
>>  		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
>>  		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
>>  		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
>>  		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
>>  	}
>> +}
>> +
>> +static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
>> +			char __user *buf, size_t len, loff_t *pos)
>> +{
>> +	struct spu_dma_info info;
>> +
>> +	___spufs_dma_info_read(ctx, &info);
>>  
>>  	return simple_read_from_buffer(buf, len, pos, &info,
>>  				sizeof info);
>> @@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
>>  			      size_t len, loff_t *pos)
>>  {
>>  	struct spu_context *ctx = file->private_data;
>> +	struct spu_dma_info info;
>>  	int ret;
>>  
>>  	if (!access_ok(buf, len))
>> @@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
>>  	if (ret)
>>  		return ret;
>>  	spin_lock(&ctx->csa.register_lock);
>> -	ret = __spufs_dma_info_read(ctx, buf, len, pos);
>> +	___spufs_dma_info_read(ctx, &info);
>>  	spin_unlock(&ctx->csa.register_lock);
>>  	spu_release_saved(ctx);
>>  
>> -	return ret;
>> +	return simple_read_from_buffer(buf, len, pos, &info,
>> +				sizeof(info));
>>  }
>>  
>>  static const struct file_operations spufs_dma_info_fops = {
>> @@ -2136,13 +2164,31 @@ static const struct file_operations spufs_dma_info_fops = {
>>  	.llseek = no_llseek,
>>  };
>>  
>> +static void ___spufs_proxydma_info_read(struct spu_context *ctx,
>> +		struct spu_proxydma_info *info)
>> +{
>> +	int i;
>> +
>> +	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
>> +	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
>> +	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
>> +
>> +	for (i = 0; i < 8; i++) {
>> +		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
>> +		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
>> +
>> +		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
>> +		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
>> +		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
>> +		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
>> +	}
>> +}
>> +
>>  static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
>>  			char __user *buf, size_t len, loff_t *pos)
>>  {
>>  	struct spu_proxydma_info info;
>> -	struct mfc_cq_sr *qp, *puqp;
>>  	int ret = sizeof info;
>> -	int i;
>>  
>>  	if (len < ret)
>>  		return -EINVAL;
>> @@ -2150,18 +2196,7 @@ static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
>>  	if (!access_ok(buf, len))
>>  		return -EFAULT;
>>  
>> -	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
>> -	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
>> -	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
>> -	for (i = 0; i < 8; i++) {
>> -		qp = &info.proxydma_info_command_data[i];
>> -		puqp = &ctx->csa.priv2.puq[i];
>> -
>> -		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
>> -		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
>> -		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
>> -		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
>> -	}
>> +	___spufs_proxydma_info_read(ctx, &info);
>>  
>>  	return simple_read_from_buffer(buf, len, pos, &info,
>>  				sizeof info);
>> @@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
>>  				   size_t len, loff_t *pos)
>>  {
>>  	struct spu_context *ctx = file->private_data;
>> +	struct spu_proxydma_info info;
>>  	int ret;
>>  
>>  	ret = spu_acquire_saved(ctx);
>>  	if (ret)
>>  		return ret;
>>  	spin_lock(&ctx->csa.register_lock);
>> -	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
>> +	___spufs_proxydma_info_read(ctx, &info);
>>  	spin_unlock(&ctx->csa.register_lock);
>>  	spu_release_saved(ctx);
>>  
>> -	return ret;
>> +	return simple_read_from_buffer(buf, len, pos, &info,
>> +				sizeof(info));
>>  }
>>  
>>  static const struct file_operations spufs_proxydma_info_fops = {
>> -- 
>> 2.17.1
> ---end quoted text---
Christoph Hellwig May 5, 2020, 7:30 a.m. UTC | #3
On Tue, May 05, 2020 at 05:20:54PM +1000, Michael Ellerman wrote:
> Christoph Hellwig <hch@lst.de> writes:
> > powerpc mantainers,
> 
> There's only one of me.
> 
> > are you going to pick this up for the next -rc1?  I'm waiting for it to
> > hit upstream before resending the coredump series.
> 
> I thought you were going to take it in your series. 

Ok, I'll pick it up.
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index c0f950a3f4e1..b4e1ef650b40 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -1978,8 +1978,9 @@  static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
 static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
-	int ret;
 	struct spu_context *ctx = file->private_data;
+	u32 stat, data;
+	int ret;
 
 	if (!access_ok(buf, len))
 		return -EFAULT;
@@ -1988,11 +1989,16 @@  static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
+	stat = ctx->csa.prob.mb_stat_R;
+	data = ctx->csa.prob.pu_mb_R;
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	/* EOF if there's no entry in the mbox */
+	if (!(stat & 0x0000ff))
+		return 0;
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
 }
 
 static const struct file_operations spufs_mbox_info_fops = {
@@ -2019,6 +2025,7 @@  static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	u32 stat, data;
 	int ret;
 
 	if (!access_ok(buf, len))
@@ -2028,11 +2035,16 @@  static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
+	stat = ctx->csa.prob.mb_stat_R;
+	data = ctx->csa.priv2.puint_mb_R;
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	/* EOF if there's no entry in the ibox */
+	if (!(stat & 0xff0000))
+		return 0;
+
+	return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
 }
 
 static const struct file_operations spufs_ibox_info_fops = {
@@ -2041,6 +2053,11 @@  static const struct file_operations spufs_ibox_info_fops = {
 	.llseek  = generic_file_llseek,
 };
 
+static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
+{
+	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
+}
+
 static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
 			char __user *buf, size_t len, loff_t *pos)
 {
@@ -2049,7 +2066,7 @@  static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
 	u32 wbox_stat;
 
 	wbox_stat = ctx->csa.prob.mb_stat_R;
-	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
+	cnt = spufs_wbox_info_cnt(ctx);
 	for (i = 0; i < cnt; i++) {
 		data[i] = ctx->csa.spu_mailbox_data[i];
 	}
@@ -2062,7 +2079,8 @@  static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
-	int ret;
+	u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
+	int ret, count;
 
 	if (!access_ok(buf, len))
 		return -EFAULT;
@@ -2071,11 +2089,13 @@  static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
+	count = spufs_wbox_info_cnt(ctx);
+	memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &data,
+				count * sizeof(u32));
 }
 
 static const struct file_operations spufs_wbox_info_fops = {
@@ -2084,27 +2104,33 @@  static const struct file_operations spufs_wbox_info_fops = {
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static void ___spufs_dma_info_read(struct spu_context *ctx,
+		struct spu_dma_info *info)
 {
-	struct spu_dma_info info;
-	struct mfc_cq_sr *qp, *spuqp;
 	int i;
 
-	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
-	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
-	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
-	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
-	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
+	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
+	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
+	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
+	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
+	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
 	for (i = 0; i < 16; i++) {
-		qp = &info.dma_info_command_data[i];
-		spuqp = &ctx->csa.priv2.spuq[i];
+		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
+		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
 
 		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
 		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
 	}
+}
+
+static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
+			char __user *buf, size_t len, loff_t *pos)
+{
+	struct spu_dma_info info;
+
+	___spufs_dma_info_read(ctx, &info);
 
 	return simple_read_from_buffer(buf, len, pos, &info,
 				sizeof info);
@@ -2114,6 +2140,7 @@  static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 			      size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_dma_info info;
 	int ret;
 
 	if (!access_ok(buf, len))
@@ -2123,11 +2150,12 @@  static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_dma_info_read(ctx, buf, len, pos);
+	___spufs_dma_info_read(ctx, &info);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof(info));
 }
 
 static const struct file_operations spufs_dma_info_fops = {
@@ -2136,13 +2164,31 @@  static const struct file_operations spufs_dma_info_fops = {
 	.llseek = no_llseek,
 };
 
+static void ___spufs_proxydma_info_read(struct spu_context *ctx,
+		struct spu_proxydma_info *info)
+{
+	int i;
+
+	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
+	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
+	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
+
+	for (i = 0; i < 8; i++) {
+		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
+		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
+
+		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
+		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
+		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
+		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
+	}
+}
+
 static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
 			char __user *buf, size_t len, loff_t *pos)
 {
 	struct spu_proxydma_info info;
-	struct mfc_cq_sr *qp, *puqp;
 	int ret = sizeof info;
-	int i;
 
 	if (len < ret)
 		return -EINVAL;
@@ -2150,18 +2196,7 @@  static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
 	if (!access_ok(buf, len))
 		return -EFAULT;
 
-	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
-	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
-	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
-	for (i = 0; i < 8; i++) {
-		qp = &info.proxydma_info_command_data[i];
-		puqp = &ctx->csa.priv2.puq[i];
-
-		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
-		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
-		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
-		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
-	}
+	___spufs_proxydma_info_read(ctx, &info);
 
 	return simple_read_from_buffer(buf, len, pos, &info,
 				sizeof info);
@@ -2171,17 +2206,19 @@  static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_proxydma_info info;
 	int ret;
 
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
+	___spufs_proxydma_info_read(ctx, &info);
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
-	return ret;
+	return simple_read_from_buffer(buf, len, pos, &info,
+				sizeof(info));
 }
 
 static const struct file_operations spufs_proxydma_info_fops = {