From 17834450c14109e86d4dee1b02a1712facdb671e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 15 Feb 2012 09:40:27 -0800 Subject: [PATCH] 3.2-stable patches added patches: mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch --- ...sdioirq-when-soft-reset-is-performed.patch | 39 ++ ...fix-pio-mode-with-support-of-highmem.patch | 349 ++++++++++++++++++ queue-3.2/series | 3 + ...-evtchns-if-xen_have_vector_callback.patch | 28 ++ 4 files changed, 419 insertions(+) create mode 100644 queue-3.2/mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch create mode 100644 queue-3.2/mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch create mode 100644 queue-3.2/xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch diff --git a/queue-3.2/mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch b/queue-3.2/mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch new file mode 100644 index 00000000000..39bc9ebe70a --- /dev/null +++ b/queue-3.2/mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch @@ -0,0 +1,39 @@ +From 18ee684b8ab666329e0a0a72d8b70f16fb0e2243 Mon Sep 17 00:00:00 2001 +From: Ludovic Desroches +Date: Thu, 9 Feb 2012 11:55:29 +0100 +Subject: mmc: atmel-mci: save and restore sdioirq when soft reset is performed + +From: Ludovic Desroches + +commit 18ee684b8ab666329e0a0a72d8b70f16fb0e2243 upstream. + +Sometimes a software reset is needed. Then some registers are saved and +restored but the interrupt mask register is missing. It causes issues +with sdio devices whose interrupts are masked after reset. + +Signed-off-by: Ludovic Desroches +Signed-off-by: Nicolas Ferre +Signed-off-by: Chris Ball +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/atmel-mci.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -965,11 +965,14 @@ static void atmci_start_request(struct a + host->data_status = 0; + + if (host->need_reset) { ++ iflags = atmci_readl(host, ATMCI_IMR); ++ iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); + atmci_writel(host, ATMCI_MR, host->mode_reg); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); ++ atmci_writel(host, ATMCI_IER, iflags); + host->need_reset = false; + } + atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); diff --git a/queue-3.2/mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch b/queue-3.2/mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch new file mode 100644 index 00000000000..02b58c8ee29 --- /dev/null +++ b/queue-3.2/mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch @@ -0,0 +1,349 @@ +From f9c2a0dc42a6938ff2a80e55ca2bbd1d5581c72e Mon Sep 17 00:00:00 2001 +From: Seungwon Jeon +Date: Thu, 9 Feb 2012 14:32:43 +0900 +Subject: mmc: dw_mmc: Fix PIO mode with support of highmem + +From: Seungwon Jeon + +commit f9c2a0dc42a6938ff2a80e55ca2bbd1d5581c72e upstream. + +Current PIO mode makes a kernel crash with CONFIG_HIGHMEM. +Highmem 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 : [] lr : [] 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 +xkernel +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: +[] (dw_mci_pull_data32+0x0/0x9c) from [] (dw_mci_read_data_pio+0x54/0x1f0) + r6:00000200 r5:e1a4f000 r4:e1dd3100 + [] (dw_mci_read_data_pio+0x0/0x1f0) from [] (dw_mci_interrupt+0xfc/0x4a4) +[] (dw_mci_interrupt+0x0/0x4a4) from [] (handle_irq_event_percpu+0x7c/0x1b4) +[] (handle_irq_event_percpu+0x0/0x1b4) from [] (handle_irq_event+0x44/0x64) +[] (handle_irq_event+0x0/0x64) from [] (handle_fasteoi_irq+0xb4/0x124) + r7:ffffed68 r6:c061e7cc r5:c00423ac r4:c061e780 + [] (handle_fasteoi_irq+0x0/0x124) from [] (generic_handle_irq+0x30/0x38) + r7:ffffed68 r6:c0618000 r5:ffffee38 r4:0000008d + [] (generic_handle_irq+0x0/0x38) from [] (asm_do_IRQ+0x64/0xe0) + r5:ffffee38 r4:c00423ac + [] (asm_do_IRQ+0x0/0xe0) from [] (__irq_svc+0x80/0x14c) +Exception stack(0xc0619ed0 to 0xc0619f18) + +Signed-off-by: Seungwon Jeon +Acked-by: Will Newton +Signed-off-by: Chris Ball +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/dw_mmc.c | 144 +++++++++++++++++++++++---------------------- + include/linux/mmc/dw_mmc.h | 6 + + 2 files changed, 79 insertions(+), 71 deletions(-) + +--- a/drivers/mmc/host/dw_mmc.c ++++ b/drivers/mmc/host/dw_mmc.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw + 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; + +@@ -953,6 +958,7 @@ static void dw_mci_tasklet_func(unsigned + * 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; +@@ -1286,54 +1292,44 @@ static void dw_mci_pull_data(struct dw_m + + 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) { +- dw_mci_pull_data(host, (void *)(buf + offset), len); ++ 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); +@@ -1342,65 +1338,66 @@ static void dw_mci_read_data_pio(struct + 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) { +- host->push_data(host, (void *)(buf + offset), len); ++ 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(); + +@@ -1410,12 +1407,20 @@ static void dw_mci_write_data_pio(struct + 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); + } +@@ -1618,6 +1623,7 @@ static void dw_mci_work_routine_card(str + * block interrupt, hence setting the + * scatter-gather pointer to NULL. + */ ++ sg_miter_stop(&host->sg_miter); + host->sg = NULL; + + ctrl = mci_readl(host, CTRL); +--- a/include/linux/mmc/dw_mmc.h ++++ b/include/linux/mmc/dw_mmc.h +@@ -14,6 +14,8 @@ + #ifndef LINUX_MMC_DW_MMC_H + #define LINUX_MMC_DW_MMC_H + ++#include ++ + #define MAX_MCI_SLOTS 2 + + enum dw_mci_state { +@@ -40,7 +42,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. +@@ -115,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; diff --git a/queue-3.2/series b/queue-3.2/series index 74b048eb3b6..e1489fa99fc 100644 --- a/queue-3.2/series +++ b/queue-3.2/series @@ -23,3 +23,6 @@ backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch alsa-intel8x0-fix-default-inaudible-sound-on-gateway-m520.patch alsa-hda-fix-initialization-of-secondary-capture-source-on-vt1705.patch alsa-hda-fix-silent-speaker-output-on-acer-aspire-6935.patch +mmc-atmel-mci-save-and-restore-sdioirq-when-soft-reset-is-performed.patch +mmc-dw_mmc-fix-pio-mode-with-support-of-highmem.patch +xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch diff --git a/queue-3.2/xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch b/queue-3.2/xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch new file mode 100644 index 00000000000..e1ab362b8b2 --- /dev/null +++ b/queue-3.2/xen-pvhvm-do-not-remap-pirqs-onto-evtchns-if-xen_have_vector_callback.patch @@ -0,0 +1,28 @@ +From 207d543f472c1ac9552df79838dc807cbcaa9740 Mon Sep 17 00:00:00 2001 +From: Stefano Stabellini +Date: Mon, 30 Jan 2012 14:31:46 +0000 +Subject: xen pvhvm: do not remap pirqs onto evtchns if !xen_have_vector_callback + +From: Stefano Stabellini + +commit 207d543f472c1ac9552df79838dc807cbcaa9740 upstream. + +Signed-off-by: Stefano Stabellini +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/pci/xen.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/pci/xen.c ++++ b/arch/x86/pci/xen.c +@@ -374,7 +374,7 @@ int __init pci_xen_init(void) + + int __init pci_xen_hvm_init(void) + { +- if (!xen_feature(XENFEAT_hvm_pirqs)) ++ if (!xen_have_vector_callback || !xen_feature(XENFEAT_hvm_pirqs)) + return 0; + + #ifdef CONFIG_ACPI -- 2.47.3