Re: [PATCH] mmc: dw_mmc: Fix PIO mode with support of highmem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 02/09/2012 02:23 PM, Seungwon Jeon wrote:

> I found the following file was added recently.
> "drivers/mmc/host/dw_mmc-pltfm.c"
> I feel sorry about that, I didn't catch it.
> This file needs to include "linux/scatterlist.h" with current patch
> (which is related with "struct sg_mapping_iter"). I'll fix it.

Right..
If you will resend the patch after fixed, i will test with your patch.
Maybe looks good to me...

Best Regards,
Jaehoon Chung

> 
> Best regards,
> Seungwon Jeon
> 
> Seungwon Jeon wrote:
>> Hi Jaehoon.
>> Oops, I'll check it.
>>
>> Thanks.
>>
>> Jaehoon Chung wrote:
>>> Hi Seungwon
>>>
>>> This patch didn't build..plz check.
>>>
>>> Best Regards,
>>> Jaehoon Chung
>>>
>>> On 02/06/2012 04:57 PM, Seungwon Jeon wrote:
>>>
>>>> Current PIO mode makes a kernel crash with CONFIG_HIGHMEM.
>>>> High memory pages have a NULL from sg_virt(sg).
>>>> This patch fixes the following problem.
>>>>
>>>> Unable to handle kernel NULL pointer dereference at virtual address 00000000
>>>> pgd = c0004000
>>>> [00000000] *pgd=00000000
>>>> Internal error: Oops: 817 [#1] PREEMPT SMP
>>>> Modules linked in:
>>>> CPU: 0    Not tainted  (3.0.15-01423-gdbf465f #589)
>>>> PC is at dw_mci_pull_data32+0x4c/0x9c
>>>> LR is at dw_mci_read_data_pio+0x54/0x1f0
>>>> pc : [<c0358824>]    lr : [<c035988c>]    psr: 20000193
>>>> sp : c0619d48  ip : c0619d70  fp : c0619d6c
>>>> r10: 00000000  r9 : 00000002  r8 : 00001000
>>>> r7 : 00000200  r6 : 00000000  r5 : e1dd3100  r4 : 00000000
>>>> r3 : 65622023  r2 : 0000007f  r1 : eeb96000  r0 : e1dd3100
>>>> Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment
>>>> kernel
>>>> Control: 10c5387d  Table: 61e2004a  DAC: 00000015
>>>> Process swapper (pid: 0, stack limit = 0xc06182f0)
>>>> Stack: (0xc0619d48 to 0xc061a000)
>>>> 9d40:                   e1dd3100 e1a4f000 00000000 e1dd3100 e1a4f000 00000200
>>>> 9d60: c0619da4 c0619d70 c035988c c03587e4 c0619d9c e18158f4 e1dd3100 e1dd3100
>>>> 9d80: 00000020 00000000 00000000 00000020 c06e8a84 00000000 c0619e04 c0619da8
>>>> 9da0: c0359b24 c0359844 e18158f4 e1dd3164 e1dd3168 e1dd3150 3d02fc79 e1dd3154
>>>> 9dc0: e1dd3178 00000000 00000020 00000000 e1dd3150 00000000 c10dd7e8 e1a84900
>>>> 9de0: c061e7cc 00000000 00000000 0000008d c06e8a84 c061e780 c0619e4c c0619e08
>>>> 9e00: c00c4738 c0359a34 3d02fc79 00000000 c0619e4c c05a1698 c05a1670 c05a165c
>>>> 9e20: c04de8b0 c061e780 c061e7cc e1a84900 ffffed68 0000008d c0618000 00000000
>>>> 9e40: c0619e6c c0619e50 c00c48b4 c00c46c8 c061e780 c00423ac c061e7cc ffffed68
>>>> 9e60: c0619e8c c0619e70 c00c7358 c00c487c 0000008d ffffee38 c0618000 ffffed68
>>>> 9e80: c0619ea4 c0619e90 c00c4258 c00c72b0 c00423ac ffffee38 c0619ecc c0619ea8
>>>> 9ea0: c004241c c00c4234 ffffffff f8810000 0000006d 00000002 00000001 7fffffff
>>>> 9ec0: c0619f44 c0619ed0 c0048bc0 c00423c4 220ae7a9 00000000 386f0d30 0005d3a4
>>>> 9ee0: c00423ac c10dd0b8 c06f2cd8 c0618000 c0594778 c003a674 7fffffff c0619f44
>>>> 9f00: 386f0d30 c0619f18 c00a6f94 c005be3c 80000013 ffffffff 386f0d30 0005d3a4
>>>> 9f20: 386f0d30 0005d2d1 c10dd0a8 c10dd0b8 c06f2cd8 c0618000 c0619f74 c0619f48
>>>> 9f40: c0345858 c005be00 c00a2440 c0618000 c0618000 c00410d8 c06c1944 c00410fc
>>>> 9f60: c0594778 c003a674 c0619f9c c0619f78 c004a7e8 c03457b4 c0618000 c06c18f8
>>>> 9f80: 00000000 c0039c70 c06c18d4 c003a674 c0619fb4 c0619fa0 c04ceafc c004a714
>>>> 9fa0: c06287b4 c06c18f8 c0619ff4 c0619fb8 c0008b68 c04cea68 c0008578 00000000
>>>> 9fc0: 00000000 c003a674 00000000 10c5387d c0628658 c003aa78 c062f1c4 4000406a
>>>> 9fe0: 413fc090 00000000 00000000 c0619ff8 40008044 c0008858 00000000 00000000
>>>> Backtrace:
>>>> [<c03587d8>] (dw_mci_pull_data32+0x0/0x9c) from [<c035988c>] (dw_mci_read_data_pio+0x54/0x1f0)
>>>>  r6:00000200 r5:e1a4f000 r4:e1dd3100
>>>>  [<c0359838>] (dw_mci_read_data_pio+0x0/0x1f0) from [<c0359b24>] (dw_mci_interrupt+0xfc/0x4a4)
>>>> [<c0359a28>] (dw_mci_interrupt+0x0/0x4a4) from [<c00c4738>] (handle_irq_event_percpu+0x7c/0x1b4)
>>>> [<c00c46bc>] (handle_irq_event_percpu+0x0/0x1b4) from [<c00c48b4>] (handle_irq_event+0x44/0x64)
>>>> [<c00c4870>] (handle_irq_event+0x0/0x64) from [<c00c7358>] (handle_fasteoi_irq+0xb4/0x124)
>>>>  r7:ffffed68 r6:c061e7cc r5:c00423ac r4:c061e780
>>>>  [<c00c72a4>] (handle_fasteoi_irq+0x0/0x124) from [<c00c4258>] (generic_handle_irq+0x30/0x38)
>>>>  r7:ffffed68 r6:c0618000 r5:ffffee38 r4:0000008d
>>>>  [<c00c4228>] (generic_handle_irq+0x0/0x38) from [<c004241c>] (asm_do_IRQ+0x64/0xe0)
>>>>  r5:ffffee38 r4:c00423ac
>>>>  [<c00423b8>] (asm_do_IRQ+0x0/0xe0) from [<c0048bc0>] (__irq_svc+0x80/0x14c)
>>>> Exception stack(0xc0619ed0 to 0xc0619f18)
>>>>
>>>> Signed-off-by: Seungwon Jeon <tgih.jun@xxxxxxxxxxx>
>>>> ---
>>>>  drivers/mmc/host/dw_mmc.c  |  143 +++++++++++++++++++++++---------------------
>>>>  include/linux/mmc/dw_mmc.h |    4 +-
>>>>  2 files changed, 77 insertions(+), 70 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>>>> index dee839e..22aba57 100644
>>>> --- a/drivers/mmc/host/dw_mmc.c
>>>> +++ b/drivers/mmc/host/dw_mmc.c
>>>> @@ -575,8 +575,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
>>>>  		host->dir_status = DW_MCI_SEND_STATUS;
>>>>
>>>>  	if (dw_mci_submit_data_dma(host, data)) {
>>>> +		int flags = SG_MITER_ATOMIC;
>>>> +		if (host->data->flags & MMC_DATA_READ)
>>>> +			flags |= SG_MITER_TO_SG;
>>>> +		else
>>>> +			flags |= SG_MITER_FROM_SG;
>>>> +
>>>> +		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
>>>>  		host->sg = data->sg;
>>>> -		host->pio_offset = 0;
>>>>  		host->part_buf_start = 0;
>>>>  		host->part_buf_count = 0;
>>>>
>>>> @@ -1047,6 +1053,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>>>>  				 * generates a block interrupt, hence setting
>>>>  				 * the scatter-gather pointer to NULL.
>>>>  				 */
>>>> +				sg_miter_stop(&host->sg_miter);
>>>>  				host->sg = NULL;
>>>>  				ctrl = mci_readl(host, CTRL);
>>>>  				ctrl |= SDMMC_CTRL_FIFO_RESET;
>>>> @@ -1386,54 +1393,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
>>>>
>>>>  static void dw_mci_read_data_pio(struct dw_mci *host)
>>>>  {
>>>> -	struct scatterlist *sg = host->sg;
>>>> -	void *buf = sg_virt(sg);
>>>> -	unsigned int offset = host->pio_offset;
>>>> +	struct sg_mapping_iter *sg_miter = &host->sg_miter;
>>>> +	void *buf;
>>>> +	unsigned int offset;
>>>>  	struct mmc_data	*data = host->data;
>>>>  	int shift = host->data_shift;
>>>>  	u32 status;
>>>>  	unsigned int nbytes = 0, len;
>>>> +	unsigned int remain, fcnt;
>>>>
>>>>  	do {
>>>> -		len = host->part_buf_count +
>>>> -			(SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift);
>>>> -		if (offset + len <= sg->length) {
>>>> +		if (!sg_miter_next(sg_miter))
>>>> +			goto done;
>>>> +
>>>> +		host->sg = sg_miter->__sg;
>>>> +		buf = sg_miter->addr;
>>>> +		remain = sg_miter->length;
>>>> +		offset = 0;
>>>> +
>>>> +		do {
>>>> +			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
>>>> +					<< shift) + host->part_buf_count;
>>>> +			len = min(remain, fcnt);
>>>> +			if (!len)
>>>> +				break;
>>>>  			dw_mci_pull_data(host, (void *)(buf + offset), len);
>>>> -
>>>>  			offset += len;
>>>>  			nbytes += len;
>>>> -
>>>> -			if (offset == sg->length) {
>>>> -				flush_dcache_page(sg_page(sg));
>>>> -				host->sg = sg = sg_next(sg);
>>>> -				if (!sg)
>>>> -					goto done;
>>>> -
>>>> -				offset = 0;
>>>> -				buf = sg_virt(sg);
>>>> -			}
>>>> -		} else {
>>>> -			unsigned int remaining = sg->length - offset;
>>>> -			dw_mci_pull_data(host, (void *)(buf + offset),
>>>> -					 remaining);
>>>> -			nbytes += remaining;
>>>> -
>>>> -			flush_dcache_page(sg_page(sg));
>>>> -			host->sg = sg = sg_next(sg);
>>>> -			if (!sg)
>>>> -				goto done;
>>>> -
>>>> -			offset = len - remaining;
>>>> -			buf = sg_virt(sg);
>>>> -			dw_mci_pull_data(host, buf, offset);
>>>> -			nbytes += offset;
>>>> -		}
>>>> +			remain -= len;
>>>> +		} while (remain);
>>>> +		sg_miter->consumed = offset;
>>>>
>>>>  		status = mci_readl(host, MINTSTS);
>>>>  		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
>>>>  		if (status & DW_MCI_DATA_ERROR_FLAGS) {
>>>>  			host->data_status = status;
>>>>  			data->bytes_xfered += nbytes;
>>>> +			sg_miter_stop(sg_miter);
>>>> +			host->sg = NULL;
>>>>  			smp_wmb();
>>>>
>>>>  			set_bit(EVENT_DATA_ERROR, &host->pending_events);
>>>> @@ -1442,65 +1439,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
>>>>  			return;
>>>>  		}
>>>>  	} while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
>>>> -	host->pio_offset = offset;
>>>>  	data->bytes_xfered += nbytes;
>>>> +
>>>> +	if (!remain) {
>>>> +		if (!sg_miter_next(sg_miter))
>>>> +			goto done;
>>>> +		sg_miter->consumed = 0;
>>>> +	}
>>>> +	sg_miter_stop(sg_miter);
>>>>  	return;
>>>>
>>>>  done:
>>>>  	data->bytes_xfered += nbytes;
>>>> +	sg_miter_stop(sg_miter);
>>>> +	host->sg = NULL;
>>>>  	smp_wmb();
>>>>  	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
>>>>  }
>>>>
>>>>  static void dw_mci_write_data_pio(struct dw_mci *host)
>>>>  {
>>>> -	struct scatterlist *sg = host->sg;
>>>> -	void *buf = sg_virt(sg);
>>>> -	unsigned int offset = host->pio_offset;
>>>> +	struct sg_mapping_iter *sg_miter = &host->sg_miter;
>>>> +	void *buf;
>>>> +	unsigned int offset;
>>>>  	struct mmc_data	*data = host->data;
>>>>  	int shift = host->data_shift;
>>>>  	u32 status;
>>>>  	unsigned int nbytes = 0, len;
>>>> +	unsigned int fifo_depth = host->fifo_depth;
>>>> +	unsigned int remain, fcnt;
>>>>
>>>>  	do {
>>>> -		len = ((host->fifo_depth -
>>>> -			SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift)
>>>> -			- host->part_buf_count;
>>>> -		if (offset + len <= sg->length) {
>>>> +		if (!sg_miter_next(sg_miter))
>>>> +			goto done;
>>>> +
>>>> +		host->sg = sg_miter->__sg;
>>>> +		buf = sg_miter->addr;
>>>> +		remain = sg_miter->length;
>>>> +		offset = 0;
>>>> +
>>>> +		do {
>>>> +			fcnt = ((fifo_depth -
>>>> +				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
>>>> +					<< shift) - host->part_buf_count;
>>>> +			len = min(remain, fcnt);
>>>> +			if (!len)
>>>> +				break;
>>>>  			host->push_data(host, (void *)(buf + offset), len);
>>>> -
>>>>  			offset += len;
>>>>  			nbytes += len;
>>>> -			if (offset == sg->length) {
>>>> -				host->sg = sg = sg_next(sg);
>>>> -				if (!sg)
>>>> -					goto done;
>>>> -
>>>> -				offset = 0;
>>>> -				buf = sg_virt(sg);
>>>> -			}
>>>> -		} else {
>>>> -			unsigned int remaining = sg->length - offset;
>>>> -
>>>> -			host->push_data(host, (void *)(buf + offset),
>>>> -					remaining);
>>>> -			nbytes += remaining;
>>>> -
>>>> -			host->sg = sg = sg_next(sg);
>>>> -			if (!sg)
>>>> -				goto done;
>>>> -
>>>> -			offset = len - remaining;
>>>> -			buf = sg_virt(sg);
>>>> -			host->push_data(host, (void *)buf, offset);
>>>> -			nbytes += offset;
>>>> -		}
>>>> +			remain -= len;
>>>> +		} while (remain);
>>>> +		sg_miter->consumed = offset;
>>>>
>>>>  		status = mci_readl(host, MINTSTS);
>>>>  		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
>>>>  		if (status & DW_MCI_DATA_ERROR_FLAGS) {
>>>>  			host->data_status = status;
>>>>  			data->bytes_xfered += nbytes;
>>>> +			sg_miter_stop(sg_miter);
>>>> +			host->sg = NULL;
>>>>
>>>>  			smp_wmb();
>>>>
>>>> @@ -1510,12 +1508,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
>>>>  			return;
>>>>  		}
>>>>  	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
>>>> -	host->pio_offset = offset;
>>>>  	data->bytes_xfered += nbytes;
>>>> +
>>>> +	if (!remain) {
>>>> +		if (!sg_miter_next(sg_miter))
>>>> +			goto done;
>>>> +		sg_miter->consumed = 0;
>>>> +	}
>>>> +	sg_miter_stop(sg_miter);
>>>>  	return;
>>>>
>>>>  done:
>>>>  	data->bytes_xfered += nbytes;
>>>> +	sg_miter_stop(sg_miter);
>>>> +	host->sg = NULL;
>>>>  	smp_wmb();
>>>>  	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
>>>>  }
>>>> @@ -1718,6 +1724,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
>>>>  				 * block interrupt, hence setting the
>>>>  				 * scatter-gather pointer to NULL.
>>>>  				 */
>>>> +				sg_miter_stop(&host->sg_miter);
>>>>  				host->sg = NULL;
>>>>
>>>>  				ctrl = mci_readl(host, CTRL);
>>>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>>>> index b4c031d..64ccd05 100644
>>>> --- a/include/linux/mmc/dw_mmc.h
>>>> +++ b/include/linux/mmc/dw_mmc.h
>>>> @@ -40,7 +40,7 @@ struct mmc_data;
>>>>   * @lock: Spinlock protecting the queue and associated data.
>>>>   * @regs: Pointer to MMIO registers.
>>>>   * @sg: Scatterlist entry currently being processed by PIO code, if any.
>>>> - * @pio_offset: Offset into the current scatterlist entry.
>>>> + * @sg_miter: PIO mapping scatterlist iterator.
>>>>   * @cur_slot: The slot which is currently using the controller.
>>>>   * @mrq: The request currently being processed on @cur_slot,
>>>>   *	or NULL if the controller is idle.
>>>> @@ -117,7 +117,7 @@ struct dw_mci {
>>>>  	void __iomem		*regs;
>>>>
>>>>  	struct scatterlist	*sg;
>>>> -	unsigned int		pio_offset;
>>>> +	struct sg_mapping_iter	sg_miter;
>>>>
>>>>  	struct dw_mci_slot	*cur_slot;
>>>>  	struct mmc_request	*mrq;
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux