* Re: PROBLEM: USB isochronous urb leak on EHCI driver
From: Greg KH @ 2014-12-15 21:48 UTC (permalink / raw)
To: Michael Tessier; +Cc: linuxppc-dev@lists.ozlabs.org, linux-usb@vger.kernel.org
In-Reply-To: <66A26A9AA227D947AF088537F041526E1FF44F@VSVR-EX10-MB1.pocatec.com>
On Mon, Dec 15, 2014 at 08:53:20PM +0000, Michael Tessier wrote:
> <5>Linux version 2.6.31-770-g0e46b52-0897 (michael.tessier@vsvr-compile-01.pocatec.com) (gcc version 4.1.2) #12 PREEMPT Mon Nov 24 18:34:19 EST 2014
That is a _very_ old and obsolete kernel version, you need to get
support from the company that is forcing you to stay on that version, as
you are paying them for this.
There is nothing the community can do with a kernel version like this,
sorry.
best of luck,
greg k-h
^ permalink raw reply
* Re: PROBLEM: USB isochronous urb leak on EHCI driver
From: Fabio Estevam @ 2014-12-15 23:13 UTC (permalink / raw)
To: Michael Tessier; +Cc: linuxppc-dev@lists.ozlabs.org, linux-usb@vger.kernel.org
In-Reply-To: <66A26A9AA227D947AF088537F041526E1FF44F@VSVR-EX10-MB1.pocatec.com>
On Mon, Dec 15, 2014 at 6:53 PM, Michael Tessier
<michael.tessier@axiontech.ca> wrote:
> Before attempting to upgrade to an earlier kernel driver (this is
> a fairly big amount of work), I would really like to know if this
> problem would still be in the 3.x kernels. Has anyone seen that
> issue in 3.x kernels?
In fact it is very simple to test USB on a 3.18 kernel with your hardware.
You only need a minimal dts file with the usb/serial nodes enabled.
Take a loot at arch/arm/boot/dts/imx51-babbage.dts for a reference.
I tested USB earlier today on this board with 3.18 and it worked fine.
You need this patch:
http://www.spinics.net/lists/arm-kernel/msg385739.html
Regards,
Fabio Estevam
^ permalink raw reply
* Re: [PATCH 7/7] CXL: Unmap MMIO regions when detaching a context
From: Michael Ellerman @ 2014-12-15 23:32 UTC (permalink / raw)
To: Ian Munsie
Cc: cbe-oss-dev, Philippe Bergheaud, mikey, Aneesh Kumar K.V,
linux-kernel, linuxppc-dev, anton, jk
In-Reply-To: <1418613792-sup-5165@delenn.ozlabs.ibm.com>
On Mon, 2014-12-15 at 14:32 +1100, Ian Munsie wrote:
> Excerpts from Ian Munsie's message of 2014-12-08 19:18:01 +1100:
> > From: Ian Munsie <imunsie@au1.ibm.com>
> >
> > If we need to force detach a context (e.g. due to EEH or simply force
> > unbinding the driver) we should prevent the userspace contexts from
> > being able to access the Problem State Area MMIO region further, which
> > they may have mapped with mmap().
> >
> > This patch unmaps any mapped MMIO regions when detaching a userspace
> > context.
>
> Might want to drop this one for now - Philippe found that it sometimes
> causes an issue when multiple contexts are using the afu. Seems that
> unmap_mapping_range() unmapped a bit more than I expected.
Sorry, it's already in next.
https://git.kernel.org/cgit/linux/kernel/git/mpe/linux.git/commit/?h=next&id=b123429e6a9e8d03aacf888d23262835f0081448
Send me a revert or a fixup.
cheers
^ permalink raw reply
* Re: Disabled LocalPlus Controller (LPC) clock on MPC512x
From: Alexander Popov @ 2014-12-16 12:00 UTC (permalink / raw)
To: Matteo Facchinetti; +Cc: Gerhard Sittig, linuxppc-dev, linux-kernel
In-Reply-To: <547D98DF.9000708@sirius-es.it>
02.12.2014 13:47, Matteo Facchinetti пишет:
> On 26/11/2014 12:49, Alexander Popov wrote:
>> Hello.
> Hi.
Thanks for your reply, Matteo.
I've looked deeper and have more information about the crash.
>> My Freescale TWR-MPC5125 board instantly reboots if I touch
>> any physical address on the LocalPlus Bus (LPB) for the first time
>> when Linux has already booted.
>>
>> This effect is reproduced by using /dev/mem or loading a kernel module
>> which works with any peripherals on LPB.
>>
>> It took me some time to find out that such crash is caused by
>> clk_disable_unused() in drivers/clk/clk.c, which disables
>> LocalPlus Controller (LPC) clock if I don't touch LPB addresses in the
>> previous initcalls.
My first diagnosis was not correct: clk_disable_unused() doesn't disable
LPC clock because in arch/powerpc/platforms/512x/clock-commonclk.c
we call:
clk_prepare_enable(clks[MPC512x_CLK_LPC]);
But clk_disable_unused() disables NFC clock as unused which seems to be
a real reason of board crash.
>> So starting Linux with clk_ignore_unused bootparam
>> or inserting dummy LPB reading to some initcall is a temporary fix.
In fact clk_ignore_unused bootparam helps to avoid disabling NFC clock.
The board crash is reproduced again if I perform the following steps:
1. disable NFC clock in uboot by clearing NFC_EN bit in SCCR1 register,
2. boot Linux with clk_ignore_unused,
3. touch any LPB address.
At the same time disabling NFC clock and reading from LPB certainly
in uboot doesn't make MPC5125 reset instantly. So I can't reproduce
the crash in uboot. It looks like we do something wrong in Linux.
> - may be good to enable MPC512x_CLK_LPC only when localbus is enabled
> by the dts
> - if enabled, MPC512x_CLK_LPC have to setup with CLK_IGNORE_UNUSED
> flag because never get claimed by any driver.
This approach didn't help to fix the crash because in fact
clk_disable_unused() doesn't disable LPC clock as I wrote above.
> I put in CC "Gerhard Sittig" also beacuse it might be interesting to
> know his point of view as the author of mpc512x common clock driver.
Surely. Thanks.
Best regards,
Alexander
^ permalink raw reply
* [PATCH 06/11] powerpc/8xx: Remove duplicated code in set_context()
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index aa45225..b227902e 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -848,23 +848,21 @@ _GLOBAL(set_context)
li r5, (swapper_pg_dir-PAGE_OFFSET)@l
sub r4, r4, r5
+ tophys (r4, r4)
#ifdef CONFIG_8xx_CPU6
lis r6, cpu6_errata_word@h
ori r6, r6, cpu6_errata_word@l
- tophys (r4, r4)
li r7, 0x3f80
stw r7, 12(r6)
lwz r7, 12(r6)
+#endif
mtspr SPRN_M_TW, r4 /* Update MMU base address */
+#ifdef CONFIG_8xx_CPU6
li r7, 0x3380
stw r7, 12(r6)
lwz r7, 12(r6)
- mtspr SPRN_M_CASID, r3 /* Update context */
-#else
- mtspr SPRN_M_CASID,r3 /* Update context */
- tophys (r4, r4)
- mtspr SPRN_M_TW, r4 /* and pgd */
#endif
+ mtspr SPRN_M_CASID, r3 /* Update context */
SYNC
blr
--
2.1.0
^ permalink raw reply related
* [PATCH 01/11] powerpc/8xx: remove remaining unnecessary code in FixupDAR
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
Since commit 33fb845a6f01 ("powerpc/8xx: Don't use MD_TWC for walk"), MD_EPN and
MD_TWC are not writen anymore in FixupDAR so saving r3 has become useless.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 3d4b8ee..79b8a23 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -532,9 +532,6 @@ DARFixed:/* Return from dcbx instruction bug workaround */
/* define if you don't want to use self modifying code */
#define NO_SELF_MODIFYING_CODE
FixupDAR:/* Entry point for dcbx workaround. */
-#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
-#endif
mtspr SPRN_SPRG_SCRATCH2, r10
/* fetch instruction from memory. */
mfspr r10, SPRN_SRR0
@@ -551,9 +548,6 @@ FixupDAR:/* Entry point for dcbx workaround. */
/* Extract level 2 index */
rlwinm r11, r11, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
lwzx r11, r10, r11 /* Get the pte */
-#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
-#endif
/* concat physical page address(r11) and page offset(r10) */
mfspr r10, SPRN_SRR0
rlwimi r11, r10, 0, 32 - PAGE_SHIFT, 31
--
2.1.0
^ permalink raw reply related
* [PATCH 03/11] powerpc32: Use kmem_cache memory for PGDIR
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
When pages are not 4K, PGDIR table is allocated with kmalloc(). In order to
optimise TLB handlers, aligned memory is needed. kmalloc() doesn't provide
aligned memory blocks, so lets use a kmem_cache pool instead.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/pgtable-ppc32.h | 4 ++++
arch/powerpc/mm/pgtable_32.c | 16 ++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index 543bb8e..d323e8b 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -346,10 +346,14 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
+#ifndef CONFIG_PPC_4K_PAGES
+void pgtable_cache_init(void);
+#else
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
+#endif
extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
pmd_t **pmdp);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index cf11342..730dc2d 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -73,13 +73,25 @@ extern unsigned long p_mapped_by_tlbcam(phys_addr_t pa);
#define PGDIR_ORDER (32 + PGD_T_LOG2 - PGDIR_SHIFT)
+#ifndef CONFIG_PPC_4K_PAGES
+static struct kmem_cache *pgtable_cache;
+
+void pgtable_cache_init(void)
+{
+ pgtable_cache = kmem_cache_create("PGDIR cache", 1 << PGDIR_ORDER,
+ 1 << PGDIR_ORDER, 0, NULL);
+ if (pgtable_cache == NULL)
+ panic("Couldn't allocate pgtable caches");
+}
+#endif
+
pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *ret;
/* pgdir take page or two with 4K pages and a page fraction otherwise */
#ifndef CONFIG_PPC_4K_PAGES
- ret = kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
+ ret = kmem_cache_alloc(pgtable_cache, GFP_KERNEL | __GFP_ZERO);
#else
ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
PGDIR_ORDER - PAGE_SHIFT);
@@ -90,7 +102,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
#ifndef CONFIG_PPC_4K_PAGES
- kfree((void *)pgd);
+ kmem_cache_free(pgtable_cache, (void *)pgd);
#else
free_pages((unsigned long)pgd, PGDIR_ORDER - PAGE_SHIFT);
#endif
--
2.1.0
^ permalink raw reply related
* [PATCH 00/11] powerpc8xx: Further optimisation of TLB handling
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
This patchset provides a further optimisation of TLB handling in the 8xx.
Main changes are based on:
- Using processor handling of PGD/PTE Validity bits instead of testing ourselves
the entries validity
- Aligning PGD address to allow direct bit manipulation
- Not saving registers like CR when not needed
It also adds support to any TASK_SIZE
Patchset:
01 - powerpc/8xx: remove remaining unnecessary code in FixupDAR
02 - powerpc/8xx: remove tests on PGDIR entry validity
03 - powerpc32: Use kmem_cache memory for PGDIR
04 - powerpc/8xx: Take benefit of aligned PGDIR
05 - powerpc/8xx: Optimise access to swapper_pg_dir
06 - powerpc/8xx: Remove duplicated code in set_context()
07 - powerpc/8xx: macro for handling CPU15 errata
08 - powerpc/8xx: Handle CR out of exception PROLOG/EPILOG
09 - powerpc/8xx: dont save CR in SCRATCH registers
10 - powerpc/8xx: Use SPRG2 instead of DAR for saving r3
11 - powerpc/8xx: Add support for TASK_SIZE greater than 0x80000000
All changes have been successfully tested on MPC885
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Tested-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/page.h | 8 +++----
arch/powerpc/include/asm/pgtable-ppc32.h | 37 +++++++++++++++++++++-----------
arch/powerpc/include/asm/pgtable.h | 17 ++++++++-------
arch/powerpc/include/asm/pte-8xx.h | 1 +
arch/powerpc/include/asm/pte-common.h | 3 +++
arch/powerpc/kernel/head_8xx.S | 3 ---
arch/powerpc/mm/pgtable_32.c | 14 ++++++++++++
7 files changed, 56 insertions(+), 27 deletions(-)
^ permalink raw reply
* [PATCH 07/11] powerpc/8xx: macro for handling CPU15 errata
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
Having a macro will help keep clear code.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index b227902e..b3f3cb5 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -297,6 +297,17 @@ SystemCall:
* We have to use the MD_xxx registers for the tablewalk because the
* equivalent MI_xxx registers only perform the attribute functions.
*/
+
+#ifdef CONFIG_8xx_CPU15
+#define DO_8xx_CPU15(tmp, addr) \
+ addi tmp, addr, PAGE_SIZE; \
+ tlbie tmp; \
+ addi tmp, addr, PAGE_SIZE; \
+ tlbie tmp
+#else
+#define DO_8xx_CPU15(tmp, addr)
+#endif
+
InstructionTLBMiss:
#ifdef CONFIG_8xx_CPU6
mtspr SPRN_DAR, r3
@@ -304,12 +315,7 @@ InstructionTLBMiss:
EXCEPTION_PROLOG_0
mtspr SPRN_SPRG_SCRATCH2, r10
mfspr r10, SPRN_SRR0 /* Get effective address of fault */
-#ifdef CONFIG_8xx_CPU15
- addi r11, r10, PAGE_SIZE
- tlbie r11
- addi r11, r10, -PAGE_SIZE
- tlbie r11
-#endif
+ DO_8xx_CPU15(r11, r10)
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
--
2.1.0
^ permalink raw reply related
* [PATCH 02/11] powerpc/8xx: remove tests on PGDIR entry validity
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
Kernel MMU handling code handles validity of entries via _PMD_PRESENT which
corresponds to V bit in MD_TWC and MI_TWC. When the V bit is not set, MPC8xx
triggers TLBError exception. So we don't have to check that and branch ourself
to TLBError. We can set TLB entries with non present entries, remove all those
tests and let the 8xx handle it. This reduce the number of cycle when the
entries are valid which is the case most of the time, and doesn't significantly
increase the time for handling invalid entries.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 41 ++++++++---------------------------------
1 file changed, 8 insertions(+), 33 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 79b8a23..2c329f1 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -329,12 +329,9 @@ InstructionTLBMiss:
/* Extract level 1 index */
rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwzx r11, r10, r11 /* Get the level 1 entry */
- rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
- beq 2f /* If zero, don't try to find a pte */
+ rlwinm r10, r11,0,0,19 /* Extract page descriptor page address */
- /* We have a pte table, so load the MI_TWC with the attributes
- * for this "segment."
- */
+ /* Load the MI_TWC with the attributes for this "segment." */
MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */
mfspr r11, SPRN_SRR0 /* Get effective address of fault */
/* Extract level 2 index */
@@ -342,13 +339,11 @@ InstructionTLBMiss:
lwzx r10, r10, r11 /* Get the pte */
#ifdef CONFIG_SWAP
- andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT
- cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT
- li r11, RPN_PATTERN
- bne- cr0, 2f
-#else
- li r11, RPN_PATTERN
+ rlwinm r11, r10, 32-5, _PAGE_PRESENT
+ and r11, r11, r10
+ rlwimi r10, r11, 0, _PAGE_PRESENT
#endif
+ li r11, RPN_PATTERN
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21 and 28 must be clear.
* Software indicator bits 24, 25, 26, and 27 must be
@@ -366,21 +361,6 @@ InstructionTLBMiss:
mfspr r10, SPRN_SPRG_SCRATCH2
EXCEPTION_EPILOG_0
rfi
-2:
- mfspr r10, SPRN_SRR1
- /* clear all error bits as TLB Miss
- * sets a few unconditionally
- */
- rlwinm r10, r10, 0, 0xffff
- mtspr SPRN_SRR1, r10
-
- /* Restore registers */
-#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
- mtspr SPRN_DAR, r11 /* Tag DAR */
-#endif
- mfspr r10, SPRN_SPRG_SCRATCH2
- b InstructionTLBError1
. = 0x1200
DataStoreTLBMiss:
@@ -403,8 +383,6 @@ DataStoreTLBMiss:
/* Extract level 1 index */
rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwzx r11, r10, r11 /* Get the level 1 entry */
- rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
- beq 2f /* If zero, don't try to find a pte */
/* We have a pte table, so load fetch the pte from the table.
*/
@@ -450,7 +428,7 @@ DataStoreTLBMiss:
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
-2: li r11, RPN_PATTERN
+ li r11, RPN_PATTERN
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
MTSPR_CPU6(SPRN_MD_RPN, r10, r3) /* Update TLB entry */
@@ -469,10 +447,7 @@ DataStoreTLBMiss:
*/
. = 0x1300
InstructionTLBError:
- EXCEPTION_PROLOG_0
-InstructionTLBError1:
- EXCEPTION_PROLOG_1
- EXCEPTION_PROLOG_2
+ EXCEPTION_PROLOG
mr r4,r12
mr r5,r9
andis. r10,r5,0x4000
--
2.1.0
^ permalink raw reply related
* [PATCH 05/11] powerpc/8xx: Optimise access to swapper_pg_dir
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
All accessed to PGD entries are done via 0(r11).
By using lower part of swapper_pg_dir as load index to r11, we can remove the
ori instruction.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index ae05f28..aa45225 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -322,13 +322,12 @@ InstructionTLBMiss:
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
#ifdef CONFIG_MODULES
beq 3f
- lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
- ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
+ lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
#endif
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwz r11, 0(r11) /* Get the level 1 entry */
+ lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
/* Load the MI_TWC with the attributes for this "segment." */
MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */
@@ -376,12 +375,11 @@ DataStoreTLBMiss:
andis. r11, r10, 0x8000
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
beq 3f
- lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
- ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
+ lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwz r11, 0(r11) /* Get the level 1 entry */
+ lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
/* We have a pte table, so load fetch the pte from the table.
*/
@@ -510,12 +508,11 @@ FixupDAR:/* Entry point for dcbx workaround. */
mfspr r10, SPRN_SRR0
andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
- beq- 3f /* Branch if user space */
- lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
- ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
+ beq 3f
+ lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
/* Insert level 1 index */
3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwz r11, 0(r11) /* Get the level 1 entry */
+ lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */
/* Insert level 2 index */
rlwimi r11, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
@@ -670,8 +667,7 @@ start_here:
* init's THREAD like the context switch code does, but this is
* easier......until someone changes init's static structures.
*/
- lis r6, swapper_pg_dir@h
- ori r6, r6, swapper_pg_dir@l
+ lis r6, swapper_pg_dir@ha
tophys(r6,r6)
#ifdef CONFIG_8xx_CPU6
lis r4, cpu6_errata_word@h
@@ -850,6 +846,8 @@ _GLOBAL(set_context)
stw r4, 0x4(r5)
#endif
+ li r5, (swapper_pg_dir-PAGE_OFFSET)@l
+ sub r4, r4, r5
#ifdef CONFIG_8xx_CPU6
lis r6, cpu6_errata_word@h
ori r6, r6, cpu6_errata_word@l
--
2.1.0
^ permalink raw reply related
* [PATCH 11/11] powerpc/8xx: Add support for TASK_SIZE greater than 0x80000000
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
By default, TASK_SIZE is set to 0x80000000 for PPC_8xx, which is most likely
sufficient for most cases. However, kernel configuration allows to set TASK_SIZE
to another value, so the 8xx shall handle it.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index dbe110e..d380658 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -48,6 +48,19 @@
mtspr spr, reg
#endif
+/* Macro to test if an address is a kernel address */
+#if CONFIG_TASK_SIZE <= 0x80000000
+#define IS_KERNEL(tmp, addr) \
+ andis. tmp, addr, 0x8000 /* Address >= 0x80000000 */
+#define BRANCH_UNLESS_KERNEL(label) beq label
+#else
+#define IS_KERNEL(tmp, addr) \
+ rlwinm tmp, addr, 16, 16, 31; \
+ cmpli cr0, tmp, PAGE_OFFSET >> 16
+#define BRANCH_UNLESS_KERNEL(label) blt label
+#endif
+
+
/*
* Value for the bits that have fixed value in RPN entries.
* Also used for tagging DAR for DTLBerror.
@@ -323,15 +336,15 @@ InstructionTLBMiss:
mfspr r10, SPRN_SRR0 /* Get effective address of fault */
DO_8xx_CPU15(r11, r10)
mfcr r3
- andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
+ IS_KERNEL(r11, r10)
#else
mfspr r11, SPRN_SRR0 /* Get effective address of fault */
DO_8xx_CPU15(r10, r11)
mfcr r10
- andis. r11, r11, 0x8000 /* Address >= 0x80000000 */
+ IS_KERNEL(r11, r11)
#endif
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
#ifdef CONFIG_8xx_CPU6
@@ -390,14 +403,14 @@ DataStoreTLBMiss:
mtspr SPRN_SPRG_SCRATCH2, r3
mfcr r3
mfspr r10, SPRN_MD_EPN
- andis. r11, r10, 0x8000
+ IS_KERNEL(r11, r10)
#else
mfcr r10
mfspr r11, SPRN_MD_EPN
- andis. r11, r11, 0x8000
+ IS_KERNEL(r11, r11)
#endif
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
#ifdef CONFIG_8xx_CPU6
@@ -536,9 +549,9 @@ FixupDAR:/* Entry point for dcbx workaround. */
mtspr SPRN_SPRG_SCRATCH2, r10
/* fetch instruction from memory. */
mfspr r10, SPRN_SRR0
- andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
+ IS_KERNEL(r11, r10)
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
/* Insert level 1 index */
3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
--
2.1.0
^ permalink raw reply related
* [PATCH 08/11] powerpc/8xx: Handle CR out of exception PROLOG/EPILOG
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
In order to be able to reduce scope during which CR is saved, we take
CR saving/restoring out of exception PROLOG and EPILOG
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index b3f3cb5..c89aed9 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -116,13 +116,13 @@ turn_on_mmu:
*/
#define EXCEPTION_PROLOG \
EXCEPTION_PROLOG_0; \
+ mfcr r10; \
EXCEPTION_PROLOG_1; \
EXCEPTION_PROLOG_2
#define EXCEPTION_PROLOG_0 \
mtspr SPRN_SPRG_SCRATCH0,r10; \
- mtspr SPRN_SPRG_SCRATCH1,r11; \
- mfcr r10
+ mtspr SPRN_SPRG_SCRATCH1,r11
#define EXCEPTION_PROLOG_1 \
mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \
@@ -162,7 +162,6 @@ turn_on_mmu:
* Exception exit code.
*/
#define EXCEPTION_EPILOG_0 \
- mtcr r10; \
mfspr r10,SPRN_SPRG_SCRATCH0; \
mfspr r11,SPRN_SPRG_SCRATCH1
@@ -313,6 +312,7 @@ InstructionTLBMiss:
mtspr SPRN_DAR, r3
#endif
EXCEPTION_PROLOG_0
+ mfcr r10
mtspr SPRN_SPRG_SCRATCH2, r10
mfspr r10, SPRN_SRR0 /* Get effective address of fault */
DO_8xx_CPU15(r11, r10)
@@ -363,6 +363,7 @@ InstructionTLBMiss:
mtspr SPRN_DAR, r11 /* Tag DAR */
#endif
mfspr r10, SPRN_SPRG_SCRATCH2
+ mtcr r10
EXCEPTION_EPILOG_0
rfi
@@ -372,6 +373,7 @@ DataStoreTLBMiss:
mtspr SPRN_DAR, r3
#endif
EXCEPTION_PROLOG_0
+ mfcr r10
mtspr SPRN_SPRG_SCRATCH2, r10
mfspr r10, SPRN_MD_EPN
@@ -440,6 +442,7 @@ DataStoreTLBMiss:
#endif
mtspr SPRN_DAR, r11 /* Tag DAR */
mfspr r10, SPRN_SPRG_SCRATCH2
+ mtcr r10
EXCEPTION_EPILOG_0
rfi
@@ -465,6 +468,7 @@ InstructionTLBError:
. = 0x1400
DataTLBError:
EXCEPTION_PROLOG_0
+ mfcr r10
mfspr r11, SPRN_DAR
cmpwi cr0, r11, RPN_PATTERN
--
2.1.0
^ permalink raw reply related
* [PATCH 10/11] powerpc/8xx: Use SPRG2 instead of DAR for saving r3
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
We now have SPRG2 available as in it not used anymore for saving CR, so we don't
need to crash DAR anymore for saving r3 for CPU6 ERRATA handling.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index a073918..dbe110e 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -310,7 +310,7 @@ SystemCall:
InstructionTLBMiss:
EXCEPTION_PROLOG_0
#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
+ mtspr SPRN_SPRG_SCRATCH2, r3
#endif
/* If we are faulting a kernel address, we have to use the
@@ -374,8 +374,7 @@ InstructionTLBMiss:
/* Restore registers */
#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
- mtspr SPRN_DAR, r11 /* Tag DAR */
+ mfspr r3, SPRN_SPRG_SCRATCH2
#endif
EXCEPTION_EPILOG_0
rfi
@@ -388,7 +387,7 @@ DataStoreTLBMiss:
* kernel page tables.
*/
#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
+ mtspr SPRN_SPRG_SCRATCH2, r3
mfcr r3
mfspr r10, SPRN_MD_EPN
andis. r11, r10, 0x8000
@@ -461,7 +460,7 @@ DataStoreTLBMiss:
/* Restore registers */
#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
+ mfspr r3, SPRN_SPRG_SCRATCH2
#endif
mtspr SPRN_DAR, r11 /* Tag DAR */
EXCEPTION_EPILOG_0
--
2.1.0
^ permalink raw reply related
* [PATCH 09/11] powerpc/8xx: dont save CR in SCRATCH registers
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
CR only needs to be preserved when checking if we are handling a kernel address.
So we can preserve CR in a register:
- In ITLBMiss, check is done only when CONFIG_MODULES is defined. Otherwise we
don't need to do anything at all with CR.
- If CONFIG_8xx_CPU6 is defined, we have r3 available for saving CR
- Otherwise, we use r10, then we reload SRR0/MD_EPN into r10 when CR is restored
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 53 +++++++++++++++++++++++++++++-------------
1 file changed, 37 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index c89aed9..a073918 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -308,14 +308,10 @@ SystemCall:
#endif
InstructionTLBMiss:
+ EXCEPTION_PROLOG_0
#ifdef CONFIG_8xx_CPU6
mtspr SPRN_DAR, r3
#endif
- EXCEPTION_PROLOG_0
- mfcr r10
- mtspr SPRN_SPRG_SCRATCH2, r10
- mfspr r10, SPRN_SRR0 /* Get effective address of fault */
- DO_8xx_CPU15(r11, r10)
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
@@ -323,14 +319,33 @@ InstructionTLBMiss:
#ifdef CONFIG_MODULES
/* Only modules will cause ITLB Misses as we always
* pin the first 8MB of kernel memory */
+#ifdef CONFIG_8xx_CPU6
+ mfspr r10, SPRN_SRR0 /* Get effective address of fault */
+ DO_8xx_CPU15(r11, r10)
+ mfcr r3
andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
+#else
+ mfspr r11, SPRN_SRR0 /* Get effective address of fault */
+ DO_8xx_CPU15(r10, r11)
+ mfcr r10
+ andis. r11, r11, 0x8000 /* Address >= 0x80000000 */
#endif
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
-#ifdef CONFIG_MODULES
beq 3f
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
+#ifdef CONFIG_8xx_CPU6
+ mtcr r3
+#else
+ mtcr r10
+ mfspr r10, SPRN_SRR0 /* Get effective address of fault */
#endif
+#else /* CONFIG_MODULES */
+ mfspr r10, SPRN_SRR0 /* Get effective address of fault */
+ DO_8xx_CPU15(r11, r10)
+ mfspr r11, SPRN_M_TW /* Get level 1 table base address */
+#endif /* CONFIG_MODULES */
+
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
@@ -362,29 +377,37 @@ InstructionTLBMiss:
mfspr r3, SPRN_DAR
mtspr SPRN_DAR, r11 /* Tag DAR */
#endif
- mfspr r10, SPRN_SPRG_SCRATCH2
- mtcr r10
EXCEPTION_EPILOG_0
rfi
. = 0x1200
DataStoreTLBMiss:
-#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
-#endif
EXCEPTION_PROLOG_0
- mfcr r10
- mtspr SPRN_SPRG_SCRATCH2, r10
- mfspr r10, SPRN_MD_EPN
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
+#ifdef CONFIG_8xx_CPU6
+ mtspr SPRN_DAR, r3
+ mfcr r3
+ mfspr r10, SPRN_MD_EPN
andis. r11, r10, 0x8000
+#else
+ mfcr r10
+ mfspr r11, SPRN_MD_EPN
+ andis. r11, r11, 0x8000
+#endif
mfspr r11, SPRN_M_TW /* Get level 1 table base address */
beq 3f
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
+#ifdef CONFIG_8xx_CPU6
+ mtcr r3
+#else
+ mtcr r10
+ mfspr r10, SPRN_MD_EPN
+#endif
+
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
@@ -441,8 +464,6 @@ DataStoreTLBMiss:
mfspr r3, SPRN_DAR
#endif
mtspr SPRN_DAR, r11 /* Tag DAR */
- mfspr r10, SPRN_SPRG_SCRATCH2
- mtcr r10
EXCEPTION_EPILOG_0
rfi
--
2.1.0
^ permalink raw reply related
* [PATCH 04/11] powerpc/8xx: Take benefit of aligned PGDIR
From: Christophe Leroy @ 2014-12-16 15:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
scottwood
Cc: linuxppc-dev, linux-kernel
L1 base address is now aligned so we can insert L1 index into r11 directly and
then preserve r10
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/head_8xx.S | 34 +++++++++++++++-------------------
1 file changed, 15 insertions(+), 19 deletions(-)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 2c329f1..ae05f28 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -326,16 +326,15 @@ InstructionTLBMiss:
ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
3:
#endif
- /* Extract level 1 index */
- rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwzx r11, r10, r11 /* Get the level 1 entry */
- rlwinm r10, r11,0,0,19 /* Extract page descriptor page address */
+ /* Insert level 1 index */
+ rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
+ lwz r11, 0(r11) /* Get the level 1 entry */
/* Load the MI_TWC with the attributes for this "segment." */
MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */
- mfspr r11, SPRN_SRR0 /* Get effective address of fault */
+ rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */
/* Extract level 2 index */
- rlwinm r11, r11, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
+ rlwinm r10, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
lwzx r10, r10, r11 /* Get the pte */
#ifdef CONFIG_SWAP
@@ -380,13 +379,12 @@ DataStoreTLBMiss:
lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
3:
- /* Extract level 1 index */
- rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwzx r11, r10, r11 /* Get the level 1 entry */
+ /* Insert level 1 index */
+ rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
+ lwz r11, 0(r11) /* Get the level 1 entry */
/* We have a pte table, so load fetch the pte from the table.
*/
- mfspr r10, SPRN_MD_EPN /* Get address of fault */
/* Extract level 2 index */
rlwinm r10, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
rlwimi r10, r11, 0, 0, 32 - PAGE_SHIFT - 1 /* Add level 2 base */
@@ -515,16 +513,14 @@ FixupDAR:/* Entry point for dcbx workaround. */
beq- 3f /* Branch if user space */
lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
- /* Extract level 1 index */
-3: rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
- lwzx r11, r10, r11 /* Get the level 1 entry */
- rlwinm r10, r11,0,0,19 /* Extract page descriptor page address */
- mfspr r11, SPRN_SRR0 /* Get effective address of fault */
- /* Extract level 2 index */
- rlwinm r11, r11, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
- lwzx r11, r10, r11 /* Get the pte */
+ /* Insert level 1 index */
+3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
+ lwz r11, 0(r11) /* Get the level 1 entry */
+ rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */
+ /* Insert level 2 index */
+ rlwimi r11, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
+ lwz r11, 0(r11) /* Get the pte */
/* concat physical page address(r11) and page offset(r10) */
- mfspr r10, SPRN_SRR0
rlwimi r11, r10, 0, 32 - PAGE_SHIFT, 31
lwz r11,0(r11)
/* Check if it really is a dcbx instruction. */
--
2.1.0
^ permalink raw reply related
* Re: [PATCH 13/18] powerpc/uaccess: fix sparse errors
From: Michael S. Tsirkin @ 2014-12-16 16:47 UTC (permalink / raw)
To: linux-kernel; +Cc: linux-arch, Arnd Bergmann, Paul Mackerras, linuxppc-dev
In-Reply-To: <1418575877-21488-14-git-send-email-mst@redhat.com>
On Sun, Dec 14, 2014 at 06:52:51PM +0200, Michael S. Tsirkin wrote:
> virtio wants to read bitwise types from userspace using get_user. At the
> moment this triggers sparse errors, since the value is passed through an
> integer.
>
> Fix that up using __force.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Ping.
Do powerpc maintainers consider fixing sparse errors
applicable for 3.19?
If yes, can you pls merge this patch?
> ---
> arch/powerpc/include/asm/uaccess.h | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
> index 9485b43..a0c071d 100644
> --- a/arch/powerpc/include/asm/uaccess.h
> +++ b/arch/powerpc/include/asm/uaccess.h
> @@ -284,7 +284,7 @@ do { \
> if (!is_kernel_addr((unsigned long)__gu_addr)) \
> might_fault(); \
> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> - (x) = (__typeof__(*(ptr)))__gu_val; \
> + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> __gu_err; \
> })
> #endif /* __powerpc64__ */
> @@ -297,7 +297,7 @@ do { \
> might_fault(); \
> if (access_ok(VERIFY_READ, __gu_addr, (size))) \
> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> - (x) = (__typeof__(*(ptr)))__gu_val; \
> + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> __gu_err; \
> })
>
> @@ -308,7 +308,7 @@ do { \
> const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
> __chk_user_ptr(ptr); \
> __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> - (x) = (__typeof__(*(ptr)))__gu_val; \
> + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> __gu_err; \
> })
>
> --
> MST
>
^ permalink raw reply
* [PATCH v2 0/3] powerpc/pstore: Add pstore support for nvram partitions
From: Hari Bathini @ 2014-12-16 18:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Mahesh J Salgaonkar
This patch series adds pstore support on powernv platform to
read different nvram partitions and write compressed data to
oops-log nvram partition. As pseries platform already has
pstore support, this series moves most of the common code
for pseries and powernv platforms to a common file. Tested
the patches successfully on both pseries and powernv
platforms.
---
Hari Bathini (3):
powerpc/nvram: move generic code for nvram and pstore
pstore: Add pstore type id for firmware partition
pstore: add pstore support on powernv
arch/powerpc/include/asm/nvram.h | 50 ++
arch/powerpc/include/asm/rtas.h | 2
arch/powerpc/kernel/nvram_64.c | 681 +++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal-nvram.c | 10
arch/powerpc/platforms/pseries/nvram.c | 665 --------------------------
fs/pstore/inode.c | 3
include/linux/pstore.h | 1
7 files changed, 751 insertions(+), 661 deletions(-)
--
- Hari
^ permalink raw reply
* [PATCH v2 1/3] powerpc/nvram: move generic code for nvram and pstore
From: Hari Bathini @ 2014-12-16 18:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Mahesh J Salgaonkar
In-Reply-To: <20141216180442.7778.38272.stgit@localhost.localdomain>
With minor checks, we can move most of the code for nvram
under pseries to a common place to be re-used by other
powerpc platforms like powernv. This patch moves such
common code to arch/powerpc/kernel/nvram_64.c file.
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/nvram.h | 50 ++
arch/powerpc/include/asm/rtas.h | 2
arch/powerpc/kernel/nvram_64.c | 660 ++++++++++++++++++++++++++++++++
arch/powerpc/platforms/pseries/nvram.c | 665 --------------------------------
4 files changed, 716 insertions(+), 661 deletions(-)
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index b0fe0fe..09a518b 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -9,12 +9,43 @@
#ifndef _ASM_POWERPC_NVRAM_H
#define _ASM_POWERPC_NVRAM_H
-
+#include <linux/types.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <uapi/asm/nvram.h>
+/*
+ * Set oops header version to distinguish between old and new format header.
+ * lnx,oops-log partition max size is 4000, header version > 4000 will
+ * help in identifying new header.
+ */
+#define OOPS_HDR_VERSION 5000
+
+struct err_log_info {
+ __be32 error_type;
+ __be32 seq_num;
+};
+
+struct nvram_os_partition {
+ const char *name;
+ int req_size; /* desired size, in bytes */
+ int min_size; /* minimum acceptable size (0 means req_size) */
+ long size; /* size of data portion (excluding err_log_info) */
+ long index; /* offset of data portion of partition */
+ bool os_partition; /* partition initialized by OS, not FW */
+};
+
+struct oops_log_info {
+ __be16 version;
+ __be16 report_length;
+ __be64 timestamp;
+} __attribute__((packed));
+
+extern struct nvram_os_partition oops_log_partition;
+
#ifdef CONFIG_PPC_PSERIES
+extern struct nvram_os_partition rtas_log_partition;
+
extern int nvram_write_error_log(char * buff, int length,
unsigned int err_type, unsigned int err_seq);
extern int nvram_read_error_log(char * buff, int length,
@@ -50,6 +81,23 @@ extern void pmac_xpram_write(int xpaddr, u8 data);
/* Synchronize NVRAM */
extern void nvram_sync(void);
+/* Initialize NVRAM OS partition */
+extern int __init nvram_init_os_partition(struct nvram_os_partition *part);
+
+/* Initialize NVRAM oops partition */
+extern void __init nvram_init_oops_partition(int rtas_partition_exists);
+
+/* Read a NVRAM partition */
+extern int nvram_read_partition(struct nvram_os_partition *part, char *buff,
+ int length, unsigned int *err_type,
+ unsigned int *error_log_cnt);
+
+/* Write to NVRAM OS partition */
+extern int nvram_write_os_partition(struct nvram_os_partition *part,
+ char *buff, int length,
+ unsigned int err_type,
+ unsigned int error_log_cnt);
+
/* Determine NVRAM size */
extern ssize_t nvram_get_size(void);
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index b390f55..a033fe9 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -343,6 +343,8 @@ extern int early_init_dt_scan_rtas(unsigned long node,
extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
#ifdef CONFIG_PPC_PSERIES
+extern unsigned long last_rtas_event;
+extern int clobbering_unread_rtas_event(void);
extern int pseries_devicetree_update(s32 scope);
extern void post_mobility_fixup(void);
#endif
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 34f7c9b..dbff7f0 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -26,6 +26,9 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/kmsg_dump.h>
+#include <linux/pstore.h>
+#include <linux/zlib.h>
#include <asm/uaccess.h>
#include <asm/nvram.h>
#include <asm/rtas.h>
@@ -54,6 +57,663 @@ struct nvram_partition {
static LIST_HEAD(nvram_partitions);
+#ifdef CONFIG_PPC_PSERIES
+struct nvram_os_partition rtas_log_partition = {
+ .name = "ibm,rtas-log",
+ .req_size = 2079,
+ .min_size = 1055,
+ .index = -1,
+ .os_partition = true
+};
+#endif
+
+struct nvram_os_partition oops_log_partition = {
+ .name = "lnx,oops-log",
+ .req_size = 4000,
+ .min_size = 2000,
+ .index = -1,
+ .os_partition = true
+};
+
+static const char *nvram_os_partitions[] = {
+#ifdef CONFIG_PPC_PSERIES
+ "ibm,rtas-log",
+#endif
+ "lnx,oops-log",
+ NULL
+};
+
+static void oops_to_nvram(struct kmsg_dumper *dumper,
+ enum kmsg_dump_reason reason);
+
+static struct kmsg_dumper nvram_kmsg_dumper = {
+ .dump = oops_to_nvram
+};
+
+/*
+ * For capturing and compressing an oops or panic report...
+
+ * big_oops_buf[] holds the uncompressed text we're capturing.
+ *
+ * oops_buf[] holds the compressed text, preceded by a oops header.
+ * oops header has u16 holding the version of oops header (to differentiate
+ * between old and new format header) followed by u16 holding the length of
+ * the compressed* text (*Or uncompressed, if compression fails.) and u64
+ * holding the timestamp. oops_buf[] gets written to NVRAM.
+ *
+ * oops_log_info points to the header. oops_data points to the compressed text.
+ *
+ * +- oops_buf
+ * | +- oops_data
+ * v v
+ * +-----------+-----------+-----------+------------------------+
+ * | version | length | timestamp | text |
+ * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) |
+ * +-----------+-----------+-----------+------------------------+
+ * ^
+ * +- oops_log_info
+ *
+ * We preallocate these buffers during init to avoid kmalloc during oops/panic.
+ */
+static size_t big_oops_buf_sz;
+static char *big_oops_buf, *oops_buf;
+static char *oops_data;
+static size_t oops_data_sz;
+
+/* Compression parameters */
+#define COMPR_LEVEL 6
+#define WINDOW_BITS 12
+#define MEM_LEVEL 4
+static struct z_stream_s stream;
+
+#ifdef CONFIG_PSTORE
+#ifdef CONFIG_PPC_PSERIES
+static struct nvram_os_partition of_config_partition = {
+ .name = "of-config",
+ .index = -1,
+ .os_partition = false
+};
+#endif
+
+static struct nvram_os_partition common_partition = {
+ .name = "common",
+ .index = -1,
+ .os_partition = false
+};
+
+static enum pstore_type_id nvram_type_ids[] = {
+ PSTORE_TYPE_DMESG,
+ PSTORE_TYPE_PPC_COMMON,
+ -1,
+ -1,
+ -1
+};
+static int read_type;
+#endif
+
+/* nvram_write_os_partition
+ *
+ * We need to buffer the error logs into nvram to ensure that we have
+ * the failure information to decode. If we have a severe error there
+ * is no way to guarantee that the OS or the machine is in a state to
+ * get back to user land and write the error to disk. For example if
+ * the SCSI device driver causes a Machine Check by writing to a bad
+ * IO address, there is no way of guaranteeing that the device driver
+ * is in any state that is would also be able to write the error data
+ * captured to disk, thus we buffer it in NVRAM for analysis on the
+ * next boot.
+ *
+ * In NVRAM the partition containing the error log buffer will looks like:
+ * Header (in bytes):
+ * +-----------+----------+--------+------------+------------------+
+ * | signature | checksum | length | name | data |
+ * |0 |1 |2 3|4 15|16 length-1|
+ * +-----------+----------+--------+------------+------------------+
+ *
+ * The 'data' section would look like (in bytes):
+ * +--------------+------------+-----------------------------------+
+ * | event_logged | sequence # | error log |
+ * |0 3|4 7|8 error_log_size-1|
+ * +--------------+------------+-----------------------------------+
+ *
+ * event_logged: 0 if event has not been logged to syslog, 1 if it has
+ * sequence #: The unique sequence # for each event. (until it wraps)
+ * error log: The error log from event_scan
+ */
+int nvram_write_os_partition(struct nvram_os_partition *part,
+ char *buff, int length,
+ unsigned int err_type,
+ unsigned int error_log_cnt)
+{
+ int rc;
+ loff_t tmp_index;
+ struct err_log_info info;
+
+ if (part->index == -1)
+ return -ESPIPE;
+
+ if (length > part->size)
+ length = part->size;
+
+ info.error_type = cpu_to_be32(err_type);
+ info.seq_num = cpu_to_be32(error_log_cnt);
+
+ tmp_index = part->index;
+
+ rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info),
+ &tmp_index);
+ if (rc <= 0) {
+ pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ rc = ppc_md.nvram_write(buff, length, &tmp_index);
+ if (rc <= 0) {
+ pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/* nvram_read_partition
+ *
+ * Reads nvram partition for at most 'length'
+ */
+int nvram_read_partition(struct nvram_os_partition *part, char *buff,
+ int length, unsigned int *err_type,
+ unsigned int *error_log_cnt)
+{
+ int rc;
+ loff_t tmp_index;
+ struct err_log_info info;
+
+ if (part->index == -1)
+ return -1;
+
+ if (length > part->size)
+ length = part->size;
+
+ tmp_index = part->index;
+
+ if (part->os_partition) {
+ rc = ppc_md.nvram_read((char *)&info,
+ sizeof(struct err_log_info),
+ &tmp_index);
+ if (rc <= 0) {
+ pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
+ return rc;
+ }
+ }
+
+ rc = ppc_md.nvram_read(buff, length, &tmp_index);
+ if (rc <= 0) {
+ pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ if (part->os_partition) {
+ *error_log_cnt = be32_to_cpu(info.seq_num);
+ *err_type = be32_to_cpu(info.error_type);
+ }
+
+ return 0;
+}
+
+/* nvram_init_os_partition
+ *
+ * This sets up a partition with an "OS" signature.
+ *
+ * The general strategy is the following:
+ * 1.) If a partition with the indicated name already exists...
+ * - If it's large enough, use it.
+ * - Otherwise, recycle it and keep going.
+ * 2.) Search for a free partition that is large enough.
+ * 3.) If there's not a free partition large enough, recycle any obsolete
+ * OS partitions and try again.
+ * 4.) Will first try getting a chunk that will satisfy the requested size.
+ * 5.) If a chunk of the requested size cannot be allocated, then try finding
+ * a chunk that will satisfy the minum needed.
+ *
+ * Returns 0 on success, else -1.
+ */
+int __init nvram_init_os_partition(struct nvram_os_partition *part)
+{
+ loff_t p;
+ int size;
+
+ /* Look for ours */
+ p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
+
+ /* Found one but too small, remove it */
+ if (p && size < part->min_size) {
+ pr_info("nvram: Found too small %s partition,"
+ " removing it...\n", part->name);
+ nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
+ p = 0;
+ }
+
+ /* Create one if we didn't find */
+ if (!p) {
+ p = nvram_create_partition(part->name, NVRAM_SIG_OS,
+ part->req_size, part->min_size);
+ if (p == -ENOSPC) {
+ pr_info("nvram: No room to create %s partition, "
+ "deleting any obsolete OS partitions...\n",
+ part->name);
+ nvram_remove_partition(NULL, NVRAM_SIG_OS,
+ nvram_os_partitions);
+ p = nvram_create_partition(part->name, NVRAM_SIG_OS,
+ part->req_size, part->min_size);
+ }
+ }
+
+ if (p <= 0) {
+ pr_err("nvram: Failed to find or create %s"
+ " partition, err %d\n", part->name, (int)p);
+ return -1;
+ }
+
+ part->index = p;
+ part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
+
+ return 0;
+}
+
+/* Derived from logfs_compress() */
+static int nvram_compress(const void *in, void *out, size_t inlen,
+ size_t outlen)
+{
+ int err, ret;
+
+ ret = -EIO;
+ err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
+ MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (err != Z_OK)
+ goto error;
+
+ stream.next_in = in;
+ stream.avail_in = inlen;
+ stream.total_in = 0;
+ stream.next_out = out;
+ stream.avail_out = outlen;
+ stream.total_out = 0;
+
+ err = zlib_deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto error;
+
+ err = zlib_deflateEnd(&stream);
+ if (err != Z_OK)
+ goto error;
+
+ if (stream.total_out >= stream.total_in)
+ goto error;
+
+ ret = stream.total_out;
+error:
+ return ret;
+}
+
+/* Compress the text from big_oops_buf into oops_buf. */
+static int zip_oops(size_t text_len)
+{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
+ int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len,
+ oops_data_sz);
+ if (zipped_len < 0) {
+ pr_err("nvram: compression failed; returned %d\n", zipped_len);
+ pr_err("nvram: logging uncompressed oops/panic report\n");
+ return -1;
+ }
+ oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
+ oops_hdr->report_length = cpu_to_be16(zipped_len);
+ oops_hdr->timestamp = cpu_to_be64(get_seconds());
+ return 0;
+}
+
+#ifdef CONFIG_PSTORE
+static int nvram_pstore_open(struct pstore_info *psi)
+{
+ /* Reset the iterator to start reading partitions again */
+ read_type = -1;
+ return 0;
+}
+
+/**
+ * nvram_pstore_write - pstore write callback for nvram
+ * @type: Type of message logged
+ * @reason: reason behind dump (oops/panic)
+ * @id: identifier to indicate the write performed
+ * @part: pstore writes data to registered buffer in parts,
+ * part number will indicate the same.
+ * @count: Indicates oops count
+ * @compressed: Flag to indicate the log is compressed
+ * @size: number of bytes written to the registered buffer
+ * @psi: registered pstore_info structure
+ *
+ * Called by pstore_dump() when an oops or panic report is logged in the
+ * printk buffer.
+ * Returns 0 on successful write.
+ */
+static int nvram_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason,
+ u64 *id, unsigned int part, int count,
+ bool compressed, size_t size,
+ struct pstore_info *psi)
+{
+ int rc;
+ unsigned int err_type = ERR_TYPE_KERNEL_PANIC;
+ struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
+
+ /* part 1 has the recent messages from printk buffer */
+ if (part > 1 || (type != PSTORE_TYPE_DMESG))
+ return -1;
+
+#ifdef CONFIG_PPC_PSERIES
+ if (clobbering_unread_rtas_event())
+ return -1;
+#endif
+
+ oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
+ oops_hdr->report_length = cpu_to_be16(size);
+ oops_hdr->timestamp = cpu_to_be64(get_seconds());
+
+ if (compressed)
+ err_type = ERR_TYPE_KERNEL_PANIC_GZ;
+
+ rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
+ (int) (sizeof(*oops_hdr) + size), err_type, count);
+
+ if (rc != 0)
+ return rc;
+
+ *id = part;
+ return 0;
+}
+
+/*
+ * Reads the oops/panic report, rtas, of-config and common partition.
+ * Returns the length of the data we read from each partition.
+ * Returns 0 if we've been called before.
+ */
+static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *time, char **buf,
+ bool *compressed, struct pstore_info *psi)
+{
+ struct oops_log_info *oops_hdr;
+ unsigned int err_type, id_no, size = 0;
+ struct nvram_os_partition *part = NULL;
+ char *buff = NULL;
+ int sig = 0;
+ loff_t p;
+
+ read_type++;
+
+ switch (nvram_type_ids[read_type]) {
+ case PSTORE_TYPE_DMESG:
+ part = &oops_log_partition;
+ *type = PSTORE_TYPE_DMESG;
+ break;
+ case PSTORE_TYPE_PPC_COMMON:
+ sig = NVRAM_SIG_SYS;
+ part = &common_partition;
+ *type = PSTORE_TYPE_PPC_COMMON;
+ *id = PSTORE_TYPE_PPC_COMMON;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ break;
+#ifdef CONFIG_PPC_PSERIES
+ case PSTORE_TYPE_PPC_RTAS:
+ part = &rtas_log_partition;
+ *type = PSTORE_TYPE_PPC_RTAS;
+ time->tv_sec = last_rtas_event;
+ time->tv_nsec = 0;
+ break;
+ case PSTORE_TYPE_PPC_OF:
+ sig = NVRAM_SIG_OF;
+ part = &of_config_partition;
+ *type = PSTORE_TYPE_PPC_OF;
+ *id = PSTORE_TYPE_PPC_OF;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ if (!part->os_partition) {
+ p = nvram_find_partition(part->name, sig, &size);
+ if (p <= 0) {
+ pr_err("nvram: Failed to find partition %s, "
+ "err %d\n", part->name, (int)p);
+ return 0;
+ }
+ part->index = p;
+ part->size = size;
+ }
+
+ buff = kmalloc(part->size, GFP_KERNEL);
+
+ if (!buff)
+ return -ENOMEM;
+
+ if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
+ kfree(buff);
+ return 0;
+ }
+
+ *count = 0;
+
+ if (part->os_partition)
+ *id = id_no;
+
+ if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
+ size_t length, hdr_size;
+
+ oops_hdr = (struct oops_log_info *)buff;
+ if (be16_to_cpu(oops_hdr->version) < OOPS_HDR_VERSION) {
+ /* Old format oops header had 2-byte record size */
+ hdr_size = sizeof(u16);
+ length = be16_to_cpu(oops_hdr->version);
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ } else {
+ hdr_size = sizeof(*oops_hdr);
+ length = be16_to_cpu(oops_hdr->report_length);
+ time->tv_sec = be64_to_cpu(oops_hdr->timestamp);
+ time->tv_nsec = 0;
+ }
+ *buf = kmalloc(length, GFP_KERNEL);
+ if (*buf == NULL)
+ return -ENOMEM;
+ memcpy(*buf, buff + hdr_size, length);
+ kfree(buff);
+
+ if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
+ *compressed = true;
+ else
+ *compressed = false;
+ return length;
+ }
+
+ *buf = buff;
+ return part->size;
+}
+
+static struct pstore_info nvram_pstore_info = {
+ .owner = THIS_MODULE,
+ .name = "nvram",
+ .open = nvram_pstore_open,
+ .read = nvram_pstore_read,
+ .write = nvram_pstore_write,
+};
+
+static int nvram_pstore_init(void)
+{
+ int rc = 0;
+
+ nvram_type_ids[2] = PSTORE_TYPE_PPC_RTAS;
+ nvram_type_ids[3] = PSTORE_TYPE_PPC_OF;
+
+ nvram_pstore_info.buf = oops_data;
+ nvram_pstore_info.bufsize = oops_data_sz;
+
+ spin_lock_init(&nvram_pstore_info.buf_lock);
+
+ rc = pstore_register(&nvram_pstore_info);
+ if (rc != 0)
+ pr_err("nvram: pstore_register() failed, defaults to "
+ "kmsg_dump; returned %d\n", rc);
+
+ return rc;
+}
+#else
+static int nvram_pstore_init(void)
+{
+ return -1;
+}
+#endif
+
+void __init nvram_init_oops_partition(int rtas_partition_exists)
+{
+ int rc;
+
+ rc = nvram_init_os_partition(&oops_log_partition);
+ if (rc != 0) {
+#ifdef CONFIG_PPC_PSERIES
+ if (!rtas_partition_exists) {
+ pr_err("nvram: Failed to initialize oops partition!");
+ return;
+ }
+ pr_notice("nvram: Using %s partition to log both"
+ " RTAS errors and oops/panic reports\n",
+ rtas_log_partition.name);
+ memcpy(&oops_log_partition, &rtas_log_partition,
+ sizeof(rtas_log_partition));
+#else
+ pr_err("nvram: Failed to initialize oops partition!");
+ return;
+#endif
+ }
+ oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL);
+ if (!oops_buf) {
+ pr_err("nvram: No memory for %s partition\n",
+ oops_log_partition.name);
+ return;
+ }
+ oops_data = oops_buf + sizeof(struct oops_log_info);
+ oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
+
+ rc = nvram_pstore_init();
+
+ if (!rc)
+ return;
+
+ /*
+ * Figure compression (preceded by elimination of each line's <n>
+ * severity prefix) will reduce the oops/panic report to at most
+ * 45% of its original size.
+ */
+ big_oops_buf_sz = (oops_data_sz * 100) / 45;
+ big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
+ if (big_oops_buf) {
+ stream.workspace = kmalloc(zlib_deflate_workspacesize(
+ WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
+ if (!stream.workspace) {
+ pr_err("nvram: No memory for compression workspace; "
+ "skipping compression of %s partition data\n",
+ oops_log_partition.name);
+ kfree(big_oops_buf);
+ big_oops_buf = NULL;
+ }
+ } else {
+ pr_err("No memory for uncompressed %s data; "
+ "skipping compression\n", oops_log_partition.name);
+ stream.workspace = NULL;
+ }
+
+ rc = kmsg_dump_register(&nvram_kmsg_dumper);
+ if (rc != 0) {
+ pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
+ kfree(oops_buf);
+ kfree(big_oops_buf);
+ kfree(stream.workspace);
+ }
+}
+
+/*
+ * This is our kmsg_dump callback, called after an oops or panic report
+ * has been written to the printk buffer. We want to capture as much
+ * of the printk buffer as possible. First, capture as much as we can
+ * that we think will compress sufficiently to fit in the lnx,oops-log
+ * partition. If that's too much, go back and capture uncompressed text.
+ */
+static void oops_to_nvram(struct kmsg_dumper *dumper,
+ enum kmsg_dump_reason reason)
+{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
+ static unsigned int oops_count = 0;
+ static bool panicking = false;
+ static DEFINE_SPINLOCK(lock);
+ unsigned long flags;
+ size_t text_len;
+ unsigned int err_type = ERR_TYPE_KERNEL_PANIC_GZ;
+ int rc = -1;
+
+ switch (reason) {
+ case KMSG_DUMP_RESTART:
+ case KMSG_DUMP_HALT:
+ case KMSG_DUMP_POWEROFF:
+ /* These are almost always orderly shutdowns. */
+ return;
+ case KMSG_DUMP_OOPS:
+ break;
+ case KMSG_DUMP_PANIC:
+ panicking = true;
+ break;
+ case KMSG_DUMP_EMERG:
+ if (panicking)
+ /* Panic report already captured. */
+ return;
+ break;
+ default:
+ pr_err("%s: ignoring unrecognized KMSG_DUMP_* reason %d\n",
+ __func__, (int) reason);
+ return;
+ }
+
+#ifdef CONFIG_PPC_PSERIES
+ if (clobbering_unread_rtas_event())
+ return;
+#endif
+
+ if (!spin_trylock_irqsave(&lock, flags))
+ return;
+
+ if (big_oops_buf) {
+ kmsg_dump_get_buffer(dumper, false,
+ big_oops_buf, big_oops_buf_sz, &text_len);
+ rc = zip_oops(text_len);
+ }
+ if (rc != 0) {
+ kmsg_dump_rewind(dumper);
+ kmsg_dump_get_buffer(dumper, false,
+ oops_data, oops_data_sz, &text_len);
+ err_type = ERR_TYPE_KERNEL_PANIC;
+ oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
+ oops_hdr->report_length = cpu_to_be16(text_len);
+ oops_hdr->timestamp = cpu_to_be64(get_seconds());
+ }
+
+ (void) nvram_write_os_partition(&oops_log_partition, oops_buf,
+ (int) (sizeof(*oops_hdr) + text_len), err_type,
+ ++oops_count);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
{
int size;
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 054a0ed..97b8fc6 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -30,129 +30,17 @@
/* Max bytes to read/write in one go */
#define NVRW_CNT 0x20
-/*
- * Set oops header version to distinguish between old and new format header.
- * lnx,oops-log partition max size is 4000, header version > 4000 will
- * help in identifying new header.
- */
-#define OOPS_HDR_VERSION 5000
-
static unsigned int nvram_size;
static int nvram_fetch, nvram_store;
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
static DEFINE_SPINLOCK(nvram_lock);
-struct err_log_info {
- __be32 error_type;
- __be32 seq_num;
-};
-
-struct nvram_os_partition {
- const char *name;
- int req_size; /* desired size, in bytes */
- int min_size; /* minimum acceptable size (0 means req_size) */
- long size; /* size of data portion (excluding err_log_info) */
- long index; /* offset of data portion of partition */
- bool os_partition; /* partition initialized by OS, not FW */
-};
-
-static struct nvram_os_partition rtas_log_partition = {
- .name = "ibm,rtas-log",
- .req_size = 2079,
- .min_size = 1055,
- .index = -1,
- .os_partition = true
-};
-
-static struct nvram_os_partition oops_log_partition = {
- .name = "lnx,oops-log",
- .req_size = 4000,
- .min_size = 2000,
- .index = -1,
- .os_partition = true
-};
-
-static const char *pseries_nvram_os_partitions[] = {
- "ibm,rtas-log",
- "lnx,oops-log",
- NULL
-};
-
-struct oops_log_info {
- __be16 version;
- __be16 report_length;
- __be64 timestamp;
-} __attribute__((packed));
-
-static void oops_to_nvram(struct kmsg_dumper *dumper,
- enum kmsg_dump_reason reason);
-
-static struct kmsg_dumper nvram_kmsg_dumper = {
- .dump = oops_to_nvram
-};
-
/* See clobbering_unread_rtas_event() */
#define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */
static unsigned long last_unread_rtas_event; /* timestamp */
-/*
- * For capturing and compressing an oops or panic report...
-
- * big_oops_buf[] holds the uncompressed text we're capturing.
- *
- * oops_buf[] holds the compressed text, preceded by a oops header.
- * oops header has u16 holding the version of oops header (to differentiate
- * between old and new format header) followed by u16 holding the length of
- * the compressed* text (*Or uncompressed, if compression fails.) and u64
- * holding the timestamp. oops_buf[] gets written to NVRAM.
- *
- * oops_log_info points to the header. oops_data points to the compressed text.
- *
- * +- oops_buf
- * | +- oops_data
- * v v
- * +-----------+-----------+-----------+------------------------+
- * | version | length | timestamp | text |
- * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) |
- * +-----------+-----------+-----------+------------------------+
- * ^
- * +- oops_log_info
- *
- * We preallocate these buffers during init to avoid kmalloc during oops/panic.
- */
-static size_t big_oops_buf_sz;
-static char *big_oops_buf, *oops_buf;
-static char *oops_data;
-static size_t oops_data_sz;
-
-/* Compression parameters */
-#define COMPR_LEVEL 6
-#define WINDOW_BITS 12
-#define MEM_LEVEL 4
-static struct z_stream_s stream;
-
#ifdef CONFIG_PSTORE
-static struct nvram_os_partition of_config_partition = {
- .name = "of-config",
- .index = -1,
- .os_partition = false
-};
-
-static struct nvram_os_partition common_partition = {
- .name = "common",
- .index = -1,
- .os_partition = false
-};
-
-static enum pstore_type_id nvram_type_ids[] = {
- PSTORE_TYPE_DMESG,
- PSTORE_TYPE_PPC_RTAS,
- PSTORE_TYPE_PPC_OF,
- PSTORE_TYPE_PPC_COMMON,
- -1
-};
-static int read_type;
-static unsigned long last_rtas_event;
+unsigned long last_rtas_event;
#endif
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
@@ -246,73 +134,11 @@ static ssize_t pSeries_nvram_get_size(void)
return nvram_size ? nvram_size : -ENODEV;
}
-
-/* nvram_write_os_partition, nvram_write_error_log
+/* nvram_write_error_log
*
* We need to buffer the error logs into nvram to ensure that we have
- * the failure information to decode. If we have a severe error there
- * is no way to guarantee that the OS or the machine is in a state to
- * get back to user land and write the error to disk. For example if
- * the SCSI device driver causes a Machine Check by writing to a bad
- * IO address, there is no way of guaranteeing that the device driver
- * is in any state that is would also be able to write the error data
- * captured to disk, thus we buffer it in NVRAM for analysis on the
- * next boot.
- *
- * In NVRAM the partition containing the error log buffer will looks like:
- * Header (in bytes):
- * +-----------+----------+--------+------------+------------------+
- * | signature | checksum | length | name | data |
- * |0 |1 |2 3|4 15|16 length-1|
- * +-----------+----------+--------+------------+------------------+
- *
- * The 'data' section would look like (in bytes):
- * +--------------+------------+-----------------------------------+
- * | event_logged | sequence # | error log |
- * |0 3|4 7|8 error_log_size-1|
- * +--------------+------------+-----------------------------------+
- *
- * event_logged: 0 if event has not been logged to syslog, 1 if it has
- * sequence #: The unique sequence # for each event. (until it wraps)
- * error log: The error log from event_scan
+ * the failure information to decode.
*/
-static int nvram_write_os_partition(struct nvram_os_partition *part,
- char *buff, int length,
- unsigned int err_type,
- unsigned int error_log_cnt)
-{
- int rc;
- loff_t tmp_index;
- struct err_log_info info;
-
- if (part->index == -1) {
- return -ESPIPE;
- }
-
- if (length > part->size) {
- length = part->size;
- }
-
- info.error_type = cpu_to_be32(err_type);
- info.seq_num = cpu_to_be32(error_log_cnt);
-
- tmp_index = part->index;
-
- rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
- if (rc <= 0) {
- pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
- return rc;
- }
-
- rc = ppc_md.nvram_write(buff, length, &tmp_index);
- if (rc <= 0) {
- pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
- return rc;
- }
-
- return 0;
-}
-
int nvram_write_error_log(char * buff, int length,
unsigned int err_type, unsigned int error_log_cnt)
{
@@ -328,50 +154,6 @@ int nvram_write_error_log(char * buff, int length,
return rc;
}
-/* nvram_read_partition
- *
- * Reads nvram partition for at most 'length'
- */
-static int nvram_read_partition(struct nvram_os_partition *part, char *buff,
- int length, unsigned int *err_type,
- unsigned int *error_log_cnt)
-{
- int rc;
- loff_t tmp_index;
- struct err_log_info info;
-
- if (part->index == -1)
- return -1;
-
- if (length > part->size)
- length = part->size;
-
- tmp_index = part->index;
-
- if (part->os_partition) {
- rc = ppc_md.nvram_read((char *)&info,
- sizeof(struct err_log_info),
- &tmp_index);
- if (rc <= 0) {
- pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
- return rc;
- }
- }
-
- rc = ppc_md.nvram_read(buff, length, &tmp_index);
- if (rc <= 0) {
- pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
- return rc;
- }
-
- if (part->os_partition) {
- *error_log_cnt = be32_to_cpu(info.seq_num);
- *err_type = be32_to_cpu(info.error_type);
- }
-
- return 0;
-}
-
/* nvram_read_error_log
*
* Reads nvram for error log for at most 'length'
@@ -407,67 +189,6 @@ int nvram_clear_error_log(void)
return 0;
}
-/* pseries_nvram_init_os_partition
- *
- * This sets up a partition with an "OS" signature.
- *
- * The general strategy is the following:
- * 1.) If a partition with the indicated name already exists...
- * - If it's large enough, use it.
- * - Otherwise, recycle it and keep going.
- * 2.) Search for a free partition that is large enough.
- * 3.) If there's not a free partition large enough, recycle any obsolete
- * OS partitions and try again.
- * 4.) Will first try getting a chunk that will satisfy the requested size.
- * 5.) If a chunk of the requested size cannot be allocated, then try finding
- * a chunk that will satisfy the minum needed.
- *
- * Returns 0 on success, else -1.
- */
-static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
- *part)
-{
- loff_t p;
- int size;
-
- /* Look for ours */
- p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
-
- /* Found one but too small, remove it */
- if (p && size < part->min_size) {
- pr_info("nvram: Found too small %s partition,"
- " removing it...\n", part->name);
- nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
- p = 0;
- }
-
- /* Create one if we didn't find */
- if (!p) {
- p = nvram_create_partition(part->name, NVRAM_SIG_OS,
- part->req_size, part->min_size);
- if (p == -ENOSPC) {
- pr_info("nvram: No room to create %s partition, "
- "deleting any obsolete OS partitions...\n",
- part->name);
- nvram_remove_partition(NULL, NVRAM_SIG_OS,
- pseries_nvram_os_partitions);
- p = nvram_create_partition(part->name, NVRAM_SIG_OS,
- part->req_size, part->min_size);
- }
- }
-
- if (p <= 0) {
- pr_err("nvram: Failed to find or create %s"
- " partition, err %d\n", part->name, (int)p);
- return -1;
- }
-
- part->index = p;
- part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
-
- return 0;
-}
-
/*
* Are we using the ibm,rtas-log for oops/panic reports? And if so,
* would logging this oops/panic overwrite an RTAS event that rtas_errd
@@ -476,7 +197,7 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
* We assume that if rtas_errd hasn't read the RTAS event in
* NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
*/
-static int clobbering_unread_rtas_event(void)
+int clobbering_unread_rtas_event(void)
{
return (oops_log_partition.index == rtas_log_partition.index
&& last_unread_rtas_event
@@ -484,313 +205,6 @@ static int clobbering_unread_rtas_event(void)
NVRAM_RTAS_READ_TIMEOUT);
}
-/* Derived from logfs_compress() */
-static int nvram_compress(const void *in, void *out, size_t inlen,
- size_t outlen)
-{
- int err, ret;
-
- ret = -EIO;
- err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
- MEM_LEVEL, Z_DEFAULT_STRATEGY);
- if (err != Z_OK)
- goto error;
-
- stream.next_in = in;
- stream.avail_in = inlen;
- stream.total_in = 0;
- stream.next_out = out;
- stream.avail_out = outlen;
- stream.total_out = 0;
-
- err = zlib_deflate(&stream, Z_FINISH);
- if (err != Z_STREAM_END)
- goto error;
-
- err = zlib_deflateEnd(&stream);
- if (err != Z_OK)
- goto error;
-
- if (stream.total_out >= stream.total_in)
- goto error;
-
- ret = stream.total_out;
-error:
- return ret;
-}
-
-/* Compress the text from big_oops_buf into oops_buf. */
-static int zip_oops(size_t text_len)
-{
- struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
- int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len,
- oops_data_sz);
- if (zipped_len < 0) {
- pr_err("nvram: compression failed; returned %d\n", zipped_len);
- pr_err("nvram: logging uncompressed oops/panic report\n");
- return -1;
- }
- oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
- oops_hdr->report_length = cpu_to_be16(zipped_len);
- oops_hdr->timestamp = cpu_to_be64(get_seconds());
- return 0;
-}
-
-#ifdef CONFIG_PSTORE
-static int nvram_pstore_open(struct pstore_info *psi)
-{
- /* Reset the iterator to start reading partitions again */
- read_type = -1;
- return 0;
-}
-
-/**
- * nvram_pstore_write - pstore write callback for nvram
- * @type: Type of message logged
- * @reason: reason behind dump (oops/panic)
- * @id: identifier to indicate the write performed
- * @part: pstore writes data to registered buffer in parts,
- * part number will indicate the same.
- * @count: Indicates oops count
- * @compressed: Flag to indicate the log is compressed
- * @size: number of bytes written to the registered buffer
- * @psi: registered pstore_info structure
- *
- * Called by pstore_dump() when an oops or panic report is logged in the
- * printk buffer.
- * Returns 0 on successful write.
- */
-static int nvram_pstore_write(enum pstore_type_id type,
- enum kmsg_dump_reason reason,
- u64 *id, unsigned int part, int count,
- bool compressed, size_t size,
- struct pstore_info *psi)
-{
- int rc;
- unsigned int err_type = ERR_TYPE_KERNEL_PANIC;
- struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
-
- /* part 1 has the recent messages from printk buffer */
- if (part > 1 || type != PSTORE_TYPE_DMESG ||
- clobbering_unread_rtas_event())
- return -1;
-
- oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
- oops_hdr->report_length = cpu_to_be16(size);
- oops_hdr->timestamp = cpu_to_be64(get_seconds());
-
- if (compressed)
- err_type = ERR_TYPE_KERNEL_PANIC_GZ;
-
- rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
- (int) (sizeof(*oops_hdr) + size), err_type, count);
-
- if (rc != 0)
- return rc;
-
- *id = part;
- return 0;
-}
-
-/*
- * Reads the oops/panic report, rtas, of-config and common partition.
- * Returns the length of the data we read from each partition.
- * Returns 0 if we've been called before.
- */
-static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
- int *count, struct timespec *time, char **buf,
- bool *compressed, struct pstore_info *psi)
-{
- struct oops_log_info *oops_hdr;
- unsigned int err_type, id_no, size = 0;
- struct nvram_os_partition *part = NULL;
- char *buff = NULL;
- int sig = 0;
- loff_t p;
-
- read_type++;
-
- switch (nvram_type_ids[read_type]) {
- case PSTORE_TYPE_DMESG:
- part = &oops_log_partition;
- *type = PSTORE_TYPE_DMESG;
- break;
- case PSTORE_TYPE_PPC_RTAS:
- part = &rtas_log_partition;
- *type = PSTORE_TYPE_PPC_RTAS;
- time->tv_sec = last_rtas_event;
- time->tv_nsec = 0;
- break;
- case PSTORE_TYPE_PPC_OF:
- sig = NVRAM_SIG_OF;
- part = &of_config_partition;
- *type = PSTORE_TYPE_PPC_OF;
- *id = PSTORE_TYPE_PPC_OF;
- time->tv_sec = 0;
- time->tv_nsec = 0;
- break;
- case PSTORE_TYPE_PPC_COMMON:
- sig = NVRAM_SIG_SYS;
- part = &common_partition;
- *type = PSTORE_TYPE_PPC_COMMON;
- *id = PSTORE_TYPE_PPC_COMMON;
- time->tv_sec = 0;
- time->tv_nsec = 0;
- break;
- default:
- return 0;
- }
-
- if (!part->os_partition) {
- p = nvram_find_partition(part->name, sig, &size);
- if (p <= 0) {
- pr_err("nvram: Failed to find partition %s, "
- "err %d\n", part->name, (int)p);
- return 0;
- }
- part->index = p;
- part->size = size;
- }
-
- buff = kmalloc(part->size, GFP_KERNEL);
-
- if (!buff)
- return -ENOMEM;
-
- if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
- kfree(buff);
- return 0;
- }
-
- *count = 0;
-
- if (part->os_partition)
- *id = id_no;
-
- if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
- size_t length, hdr_size;
-
- oops_hdr = (struct oops_log_info *)buff;
- if (be16_to_cpu(oops_hdr->version) < OOPS_HDR_VERSION) {
- /* Old format oops header had 2-byte record size */
- hdr_size = sizeof(u16);
- length = be16_to_cpu(oops_hdr->version);
- time->tv_sec = 0;
- time->tv_nsec = 0;
- } else {
- hdr_size = sizeof(*oops_hdr);
- length = be16_to_cpu(oops_hdr->report_length);
- time->tv_sec = be64_to_cpu(oops_hdr->timestamp);
- time->tv_nsec = 0;
- }
- *buf = kmalloc(length, GFP_KERNEL);
- if (*buf == NULL)
- return -ENOMEM;
- memcpy(*buf, buff + hdr_size, length);
- kfree(buff);
-
- if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
- *compressed = true;
- else
- *compressed = false;
- return length;
- }
-
- *buf = buff;
- return part->size;
-}
-
-static struct pstore_info nvram_pstore_info = {
- .owner = THIS_MODULE,
- .name = "nvram",
- .open = nvram_pstore_open,
- .read = nvram_pstore_read,
- .write = nvram_pstore_write,
-};
-
-static int nvram_pstore_init(void)
-{
- int rc = 0;
-
- nvram_pstore_info.buf = oops_data;
- nvram_pstore_info.bufsize = oops_data_sz;
-
- spin_lock_init(&nvram_pstore_info.buf_lock);
-
- rc = pstore_register(&nvram_pstore_info);
- if (rc != 0)
- pr_err("nvram: pstore_register() failed, defaults to "
- "kmsg_dump; returned %d\n", rc);
-
- return rc;
-}
-#else
-static int nvram_pstore_init(void)
-{
- return -1;
-}
-#endif
-
-static void __init nvram_init_oops_partition(int rtas_partition_exists)
-{
- int rc;
-
- rc = pseries_nvram_init_os_partition(&oops_log_partition);
- if (rc != 0) {
- if (!rtas_partition_exists)
- return;
- pr_notice("nvram: Using %s partition to log both"
- " RTAS errors and oops/panic reports\n",
- rtas_log_partition.name);
- memcpy(&oops_log_partition, &rtas_log_partition,
- sizeof(rtas_log_partition));
- }
- oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL);
- if (!oops_buf) {
- pr_err("nvram: No memory for %s partition\n",
- oops_log_partition.name);
- return;
- }
- oops_data = oops_buf + sizeof(struct oops_log_info);
- oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
-
- rc = nvram_pstore_init();
-
- if (!rc)
- return;
-
- /*
- * Figure compression (preceded by elimination of each line's <n>
- * severity prefix) will reduce the oops/panic report to at most
- * 45% of its original size.
- */
- big_oops_buf_sz = (oops_data_sz * 100) / 45;
- big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
- if (big_oops_buf) {
- stream.workspace = kmalloc(zlib_deflate_workspacesize(
- WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
- if (!stream.workspace) {
- pr_err("nvram: No memory for compression workspace; "
- "skipping compression of %s partition data\n",
- oops_log_partition.name);
- kfree(big_oops_buf);
- big_oops_buf = NULL;
- }
- } else {
- pr_err("No memory for uncompressed %s data; "
- "skipping compression\n", oops_log_partition.name);
- stream.workspace = NULL;
- }
-
- rc = kmsg_dump_register(&nvram_kmsg_dumper);
- if (rc != 0) {
- pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
- kfree(oops_buf);
- kfree(big_oops_buf);
- kfree(stream.workspace);
- }
-}
-
static int __init pseries_nvram_init_log_partitions(void)
{
int rc;
@@ -798,7 +212,7 @@ static int __init pseries_nvram_init_log_partitions(void)
/* Scan nvram for partitions */
nvram_scan_partitions();
- rc = pseries_nvram_init_os_partition(&rtas_log_partition);
+ rc = nvram_init_os_partition(&rtas_log_partition);
nvram_init_oops_partition(rc == 0);
return 0;
}
@@ -834,72 +248,3 @@ int __init pSeries_nvram_init(void)
return 0;
}
-
-/*
- * This is our kmsg_dump callback, called after an oops or panic report
- * has been written to the printk buffer. We want to capture as much
- * of the printk buffer as possible. First, capture as much as we can
- * that we think will compress sufficiently to fit in the lnx,oops-log
- * partition. If that's too much, go back and capture uncompressed text.
- */
-static void oops_to_nvram(struct kmsg_dumper *dumper,
- enum kmsg_dump_reason reason)
-{
- struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
- static unsigned int oops_count = 0;
- static bool panicking = false;
- static DEFINE_SPINLOCK(lock);
- unsigned long flags;
- size_t text_len;
- unsigned int err_type = ERR_TYPE_KERNEL_PANIC_GZ;
- int rc = -1;
-
- switch (reason) {
- case KMSG_DUMP_RESTART:
- case KMSG_DUMP_HALT:
- case KMSG_DUMP_POWEROFF:
- /* These are almost always orderly shutdowns. */
- return;
- case KMSG_DUMP_OOPS:
- break;
- case KMSG_DUMP_PANIC:
- panicking = true;
- break;
- case KMSG_DUMP_EMERG:
- if (panicking)
- /* Panic report already captured. */
- return;
- break;
- default:
- pr_err("%s: ignoring unrecognized KMSG_DUMP_* reason %d\n",
- __func__, (int) reason);
- return;
- }
-
- if (clobbering_unread_rtas_event())
- return;
-
- if (!spin_trylock_irqsave(&lock, flags))
- return;
-
- if (big_oops_buf) {
- kmsg_dump_get_buffer(dumper, false,
- big_oops_buf, big_oops_buf_sz, &text_len);
- rc = zip_oops(text_len);
- }
- if (rc != 0) {
- kmsg_dump_rewind(dumper);
- kmsg_dump_get_buffer(dumper, false,
- oops_data, oops_data_sz, &text_len);
- err_type = ERR_TYPE_KERNEL_PANIC;
- oops_hdr->version = cpu_to_be16(OOPS_HDR_VERSION);
- oops_hdr->report_length = cpu_to_be16(text_len);
- oops_hdr->timestamp = cpu_to_be64(get_seconds());
- }
-
- (void) nvram_write_os_partition(&oops_log_partition, oops_buf,
- (int) (sizeof(*oops_hdr) + text_len), err_type,
- ++oops_count);
-
- spin_unlock_irqrestore(&lock, flags);
-}
^ permalink raw reply related
* [PATCH v2 2/3] pstore: Add pstore type id for firmware partition
From: Hari Bathini @ 2014-12-16 18:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Mahesh J Salgaonkar
In-Reply-To: <20141216180442.7778.38272.stgit@localhost.localdomain>
This patch adds a pstore type id to be used for opal specific
nvram partitions.
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
fs/pstore/inode.c | 3 +++
include/linux/pstore.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 5041660..8e0c009 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -359,6 +359,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
case PSTORE_TYPE_PPC_COMMON:
sprintf(name, "powerpc-common-%s-%lld", psname, id);
break;
+ case PSTORE_TYPE_PPC_OPAL:
+ sprintf(name, "powerpc-opal-%s-%lld", psname, id);
+ break;
case PSTORE_TYPE_UNKNOWN:
sprintf(name, "unknown-%s-%lld", psname, id);
break;
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index ece0c6b..af44980 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -39,6 +39,7 @@ enum pstore_type_id {
PSTORE_TYPE_PPC_RTAS = 4,
PSTORE_TYPE_PPC_OF = 5,
PSTORE_TYPE_PPC_COMMON = 6,
+ PSTORE_TYPE_PPC_OPAL = 7,
PSTORE_TYPE_UNKNOWN = 255
};
^ permalink raw reply related
* [PATCH v2 3/3] pstore: add pstore support on powernv
From: Hari Bathini @ 2014-12-16 18:06 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Mahesh J Salgaonkar
In-Reply-To: <20141216180442.7778.38272.stgit@localhost.localdomain>
This patch extends pstore, a generic interface to platform dependent
persistent storage, support for powernv platform to capture certain
useful information, during dying moments. Such support is already in
place for pseries platform. This patch re-uses most of that code.
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
arch/powerpc/kernel/nvram_64.c | 25 +++++++++++++++++++++++--
arch/powerpc/platforms/powernv/opal-nvram.c | 10 ++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index dbff7f0..3afbc91 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -127,6 +127,14 @@ static size_t oops_data_sz;
static struct z_stream_s stream;
#ifdef CONFIG_PSTORE
+#ifdef CONFIG_PPC_POWERNV
+static struct nvram_os_partition skiboot_partition = {
+ .name = "ibm,skiboot",
+ .index = -1,
+ .os_partition = false
+};
+#endif
+
#ifdef CONFIG_PPC_PSERIES
static struct nvram_os_partition of_config_partition = {
.name = "of-config",
@@ -479,6 +487,16 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
time->tv_nsec = 0;
break;
#endif
+#ifdef CONFIG_PPC_POWERNV
+ case PSTORE_TYPE_PPC_OPAL:
+ sig = NVRAM_SIG_FW;
+ part = &skiboot_partition;
+ *type = PSTORE_TYPE_PPC_OPAL;
+ *id = PSTORE_TYPE_PPC_OPAL;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ break;
+#endif
default:
return 0;
}
@@ -554,8 +572,11 @@ static int nvram_pstore_init(void)
{
int rc = 0;
- nvram_type_ids[2] = PSTORE_TYPE_PPC_RTAS;
- nvram_type_ids[3] = PSTORE_TYPE_PPC_OF;
+ if (machine_is(pseries)) {
+ nvram_type_ids[2] = PSTORE_TYPE_PPC_RTAS;
+ nvram_type_ids[3] = PSTORE_TYPE_PPC_OF;
+ } else
+ nvram_type_ids[2] = PSTORE_TYPE_PPC_OPAL;
nvram_pstore_info.buf = oops_data;
nvram_pstore_info.bufsize = oops_data_sz;
diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c
index f9896fd..9db4398 100644
--- a/arch/powerpc/platforms/powernv/opal-nvram.c
+++ b/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <asm/opal.h>
+#include <asm/nvram.h>
#include <asm/machdep.h>
static unsigned int nvram_size;
@@ -62,6 +63,15 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
return count;
}
+static int __init opal_nvram_init_log_partitions(void)
+{
+ /* Scan nvram for partitions */
+ nvram_scan_partitions();
+ nvram_init_oops_partition(0);
+ return 0;
+}
+machine_arch_initcall(powernv, opal_nvram_init_log_partitions);
+
void __init opal_nvram_init(void)
{
struct device_node *np;
^ permalink raw reply related
* Re: [PATCH 13/18] powerpc/uaccess: fix sparse errors
From: Michael Ellerman @ 2014-12-16 23:50 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-arch, Arnd Bergmann, linux-kernel, Paul Mackerras,
linuxppc-dev
In-Reply-To: <20141216164746.GB21876@redhat.com>
On Tue, 2014-12-16 at 18:47 +0200, Michael S. Tsirkin wrote:
> On Sun, Dec 14, 2014 at 06:52:51PM +0200, Michael S. Tsirkin wrote:
> > virtio wants to read bitwise types from userspace using get_user. At the
> > moment this triggers sparse errors, since the value is passed through an
> > integer.
> >
> > Fix that up using __force.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> Ping.
Ping? You only sent it two days ago. And you only responded to my questions
yesterday evening.
> Do powerpc maintainers consider fixing sparse errors
> applicable for 3.19?
Yeah, with your expanded explanation I'm fine with it.
> If yes, can you pls merge this patch?
Yes I will.
cheers
^ permalink raw reply
* Re: [PATCH v2 1/3] powerpc/nvram: move generic code for nvram and pstore
From: Michael Ellerman @ 2014-12-17 0:03 UTC (permalink / raw)
To: Hari Bathini; +Cc: linuxppc-dev, Mahesh J Salgaonkar
In-Reply-To: <20141216180530.7778.23702.stgit@localhost.localdomain>
On Tue, 2014-12-16 at 23:35 +0530, Hari Bathini wrote:
> With minor checks, we can move most of the code for nvram
> under pseries to a common place to be re-used by other
> powerpc platforms like powernv. This patch moves such
> common code to arch/powerpc/kernel/nvram_64.c file.
Sharing the code is great.
But, you need to keep in mind that it is very common for us to build kernels
with both POWERNV=y and PSERIES=y.
So you need to make sure you're only using CONFIG_PPC_PSERIES to protect things
that are optional on pseries. Not things that we *shouldn't* be doing on
powernv.
For example the logic in nvram_init_oops_partition() looks like it might do the
wrong thing for PSERIES=y POWERNV=y.
> diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
> index b390f55..a033fe9 100644
> --- a/arch/powerpc/include/asm/rtas.h
> +++ b/arch/powerpc/include/asm/rtas.h
> @@ -343,6 +343,8 @@ extern int early_init_dt_scan_rtas(unsigned long node,
> extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
>
> #ifdef CONFIG_PPC_PSERIES
> +extern unsigned long last_rtas_event;
> +extern int clobbering_unread_rtas_event(void);
You should add an empty version of this for !PSERIES, so you don't have to
ifdef all the call sites.
cheers
^ permalink raw reply
* Re: [PATCH 13/18] powerpc/uaccess: fix sparse errors
From: Benjamin Herrenschmidt @ 2014-12-17 0:52 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-arch, Arnd Bergmann, linux-kernel, Paul Mackerras,
linuxppc-dev
In-Reply-To: <20141216164746.GB21876@redhat.com>
On Tue, 2014-12-16 at 18:47 +0200, Michael S. Tsirkin wrote:
> On Sun, Dec 14, 2014 at 06:52:51PM +0200, Michael S. Tsirkin wrote:
> > virtio wants to read bitwise types from userspace using get_user. At the
> > moment this triggers sparse errors, since the value is passed through an
> > integer.
> >
> > Fix that up using __force.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> Ping.
> Do powerpc maintainers consider fixing sparse errors
> applicable for 3.19?
> If yes, can you pls merge this patch?
Relax :-) Our patches are tracked in Patchwork and such fixes aren't
necessarily constrained by the merge window. Michael will probably
pick it up but don't expect systematic replies to patches in 2 days ...
Also, when sending a series like that where one of us only gets
CCed on one of the patch, it helps to make it clear whether you
only expect an ack or whether you expect us to take the patch.
Cheers,
Ben.
> > ---
> > arch/powerpc/include/asm/uaccess.h | 6 +++---
> > 1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
> > index 9485b43..a0c071d 100644
> > --- a/arch/powerpc/include/asm/uaccess.h
> > +++ b/arch/powerpc/include/asm/uaccess.h
> > @@ -284,7 +284,7 @@ do { \
> > if (!is_kernel_addr((unsigned long)__gu_addr)) \
> > might_fault(); \
> > __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> > - (x) = (__typeof__(*(ptr)))__gu_val; \
> > + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> > __gu_err; \
> > })
> > #endif /* __powerpc64__ */
> > @@ -297,7 +297,7 @@ do { \
> > might_fault(); \
> > if (access_ok(VERIFY_READ, __gu_addr, (size))) \
> > __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> > - (x) = (__typeof__(*(ptr)))__gu_val; \
> > + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> > __gu_err; \
> > })
> >
> > @@ -308,7 +308,7 @@ do { \
> > const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
> > __chk_user_ptr(ptr); \
> > __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
> > - (x) = (__typeof__(*(ptr)))__gu_val; \
> > + (x) = (__force __typeof__(*(ptr)))__gu_val; \
> > __gu_err; \
> > })
> >
> > --
> > MST
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH 1/3] powerpc: Don't use local named register variable in current_thread_info
From: Alexander Graf @ 2014-12-17 1:16 UTC (permalink / raw)
To: Anton Blanchard, benh, paulus, mpe, ulrich.weigand
Cc: Scott Wood, linuxppc-dev
In-Reply-To: <1414727247-31838-1-git-send-email-anton__19440.5086375356$1414727300$gmane$org@samba.org>
On 31.10.14 04:47, Anton Blanchard wrote:
> LLVM doesn't support local named register variables and is unlikely
> to. current_thread_info is using one, fix it by moving it out and
> calling it __current_r1().
>
> I gave it a bit of an obscure name because we don't want anyone else
> using it - they should use current_stack_pointer(). This specific
> case is performance critical and we can't afford to call a function
> to get it. Furthermore it isn't important to know exactly where in
> the stack we are since we mask the lower bits.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
Git bisect managed to point me to this commit as the offender for OOPSes
on e5500 and e6500 (and maybe the G4 as well, not sure).
Doing a git revert of this commit on top of linus/master makes things
work fine for me again.
Alex
Oops: Kernel access of bad area, sig: 11 [#2]
SMP NR_CPUS=16 CoreNet Generic
Modules linked in:
CPU: 1 PID: 339 Comm: kworker/1:1 Tainted: G D
3.18.0-09423-g988adfd #1
Workqueue: rpciod .rpc_async_schedule
task: c0000001f6397500 ti: c0000001f6638000 task.ti: c0000001f6638000
NIP: c0000000004817a4 LR: c0000000004817a4 CTR: 0000000000000000
REGS: c0000001f663b0e0 TRAP: 0300 Tainted: G D
(3.18.0-09423-g988adfd)
MSR: 0000000080029000 <CE,EE,ME> CR: 24ad2e42 XER: 00000000
DEAR: 202031303438355f ESR: 0000000000000000 SOFTE: 1
GPR00: c0000000004817a4 c0000001f663b360 c000000000988028 000000007f24333d
GPR04: 5ff5738c1f2ebfb1 0000000000000000 0000000000000000 00000000000008f8
GPR08: c000000000480ae8 2020313034383537 36204b4220617320 6469726563740a31
GPR12: 3937302d30312d30 c00000000fff8780 c00000000007f988 c0000001f64c1600
GPR16: 0000000000000000 0000000000000000 0000000000000000 00000000000005dc
GPR20: c0000000009b8028 c00000007e034200 0000000000000548 c000000000000000
GPR24: c0000001f663b4b0 00000000b225831e 0000000000000000 0000000000000080
GPR28: 0000000000000548 00000000000008f8 0000000000000548 0000000000000094
NIP [c0000000004817a4] .__skb_checksum+0x194/0x378
LR [c0000000004817a4] .__skb_checksum+0x194/0x378
Call Trace:
[c0000001f663b360] [c0000000004817a4] .__skb_checksum+0x194/0x378
(unreliable)
[c0000001f663b440] [c0000000004819b4] .skb_checksum+0x2c/0x3c
[c0000001f663b4c0] [c0000000004fd0a8] .udp4_hwcsum+0xa8/0x16c
[c0000001f663b560] [c0000000004fd440] .udp_send_skb+0x2d4/0x370
[c0000001f663b600] [c0000000004fd51c] .udp_push_pending_frames+0x40/0x94
[c0000001f663b680] [c0000000004fec08] .udp_sendpage+0x150/0x1b4
[c0000001f663b770] [c00000000050ae54] .inet_sendpage+0xa0/0x120
[c0000001f663b810] [c00000000059c8cc] .xs_sendpages+0x2d0/0x30c
[c0000001f663b8d0] [c00000000059cae4] .xs_udp_send_request+0x58/0x120
[c0000001f663b970] [c000000000598f04] .xprt_transmit+0x80/0x36c
[c0000001f663ba20] [c0000000005942d8] .call_transmit+0x19c/0x254
[c0000001f663bab0] [c00000000059ff64] .__rpc_execute+0xbc/0x3c0
[c0000001f663bb90] [c0000000000797f8] .process_one_work+0x1c0/0x474
[c0000001f663bc40] [c00000000007a518] .worker_thread+0x17c/0x54c
[c0000001f663bd30] [c00000000007fa8c] .kthread+0x104/0x124
[c0000001f663be30] [c000000000000884] .ret_from_kernel_thread+0x58/0xd4
Instruction dump:
7d1f3a14 7c6a1850 e9580000 7fbd4050 786334e4 e90a0000 7c63ba14 f8490028
7c63ea14 7d0903a6 e84a0008 4e800421 <e8490028> 7c641b78 78270464 e9580008
---[ end trace 51b7414695b0cafe ]---
note: kworker/1:1[339] exited with preempt_count 1
Unable to handle kernel paging request for data at address
0xffffffffffffffd8
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox