* Re: RFC on writel and writel_relaxed
From: David Miller @ 2018-03-29 14:04 UTC (permalink / raw)
To: okaya
Cc: benh, torvalds, alexander.duyck, will.deacon, arnd, jgg,
David.Laight, oohall, linuxppc-dev, linux-rdma, alexander.h.duyck,
paulmck, netdev, linus971
In-Reply-To: <29fe17e0-9978-dc43-d02c-de8fabdc66c2@codeaurora.org>
From: Sinan Kaya <okaya@codeaurora.org>
Date: Thu, 29 Mar 2018 09:56:01 -0400
> sparc question sent
Sparc never lets physical memory accesses pass MMIO, and vice versa.
They are always strongly ordered amongst eachother.
Therefore no explicit barrier instructions are necessary.
^ permalink raw reply
* Re: RFC on writel and writel_relaxed
From: Sinan Kaya @ 2018-03-29 13:56 UTC (permalink / raw)
To: David Miller, benh
Cc: torvalds, alexander.duyck, will.deacon, arnd, jgg, David.Laight,
oohall, linuxppc-dev, linux-rdma, alexander.h.duyck, paulmck,
netdev, linus971
In-Reply-To: <20180328.115509.481837809903086401.davem@davemloft.net>
On 3/28/2018 11:55 AM, David Miller wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Date: Thu, 29 Mar 2018 02:13:16 +1100
>
>> Let's fix all archs, it's way easier than fixing all drivers. Half of
>> the archs are unused or dead anyway.
>
> Agreed.
>
I pinged most of the maintainers yesterday.
Which arches do we care about these days?
I have not been paying attention any other architecture besides arm64.
arch status detail
------ ------------- ------------------------------------
alpha question sent
arc question sent ysato@users.sourceforge.jp will fix it.
arm no issues
arm64 no issues
blackfin question sent about to be removed
c6x question sent
cris question sent
frv
h8300 question sent
hexagon question sent
ia64 no issues confirmed by Tony Luck
m32r
m68k question sent
metag
microblaze question sent
mips question sent
mn10300 question sent
nios2 question sent
openrisc no issues shorne@gmail.com says should no issues
parisc no issues grantgrundler@gmail.com says most probably no problem but still looking
powerpc no issues
riscv question sent
s390 question sent
score question sent
sh question sent
sparc question sent
tile question sent
unicore32 question sent
x86 no issues
xtensa question sent
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* Re: [PATCH v4 14/16] powerpc: Use generic free_initrd_mem.
From: Michael Ellerman @ 2018-03-29 13:19 UTC (permalink / raw)
To: Shea Levy, Joe Perches, linux-riscv, linux-kernel
Cc: Benjamin Herrenschmidt, Paul Mackerras, Michal Hocko,
Vlastimil Babka, Andrew Morton, Dan Williams, Christophe Leroy,
Oliver O'Halloran, linuxppc-dev
In-Reply-To: <874lkzudkc.fsf@xps13.shealevy.com>
Shea Levy <shea@shealevy.com> writes:
> Joe Perches <joe@perches.com> writes:
>
>> On Wed, 2018-03-28 at 16:36 -0400, Shea Levy wrote:
>>> Signed-off-by: Shea Levy <shea@shealevy.com>
>>
>> Most people seem to want some form of commit message
>> and not just your sign-off.
>>
>
> Ah, if the subject is insufficient I can add some more detail.
Yeah please do.
Seeing this patch in isolation, with no change log, I might think it's
safe for me to just apply it.
But that would break the build because I don't have patch 1.
So for starters you need to explain that part, eg something like:
A previous patch in the series added a weak definition of
free_initrd_mem() in init/initramfs.c.
The powerpc implementation is identical, so it can be removed allowing
the generic version to be used.
Then you could also tell me if you did/didn't build/boot test it.
cheers
^ permalink raw reply
* Re: [PATCH v9 00/24] Speculative page faults
From: Laurent Dufour @ 2018-03-29 12:49 UTC (permalink / raw)
To: Ganesh Mahendran
Cc: paulmck, Peter Zijlstra, Andrew Morton, kirill, ak, Michal Hocko,
dave, jack, Matthew Wilcox, benh, mpe, paulus, Thomas Gleixner,
Ingo Molnar, hpa, Will Deacon, Sergey Senozhatsky,
Andrea Arcangeli, Alexei Starovoitov, kemi.wang,
Sergey Senozhatsky, Daniel Jordan, linux-kernel, Linux-MM, haren,
khandual, npiggin, Balbir Singh, Tim Chen, linuxppc-dev, x86
In-Reply-To: <CADAEsF8XR=MbD_rUh02GhJm1q=WUdBcwBeoc8ZYbYD=tCZj8Tw@mail.gmail.com>
On 22/03/2018 02:21, Ganesh Mahendran wrote:
> Hi, Laurent
>
> 2018-03-14 1:59 GMT+08:00 Laurent Dufour <ldufour@linux.vnet.ibm.com>:
>> This is a port on kernel 4.16 of the work done by Peter Zijlstra to
>> handle page fault without holding the mm semaphore [1].
>>
>> The idea is to try to handle user space page faults without holding the
>> mmap_sem. This should allow better concurrency for massively threaded
>> process since the page fault handler will not wait for other threads memory
>> layout change to be done, assuming that this change is done in another part
>> of the process's memory space. This type page fault is named speculative
>> page fault. If the speculative page fault fails because of a concurrency is
>> detected or because underlying PMD or PTE tables are not yet allocating, it
>> is failing its processing and a classic page fault is then tried.
>>
>> The speculative page fault (SPF) has to look for the VMA matching the fault
>> address without holding the mmap_sem, this is done by introducing a rwlock
>> which protects the access to the mm_rb tree. Previously this was done using
>> SRCU but it was introducing a lot of scheduling to process the VMA's
>> freeing
>> operation which was hitting the performance by 20% as reported by Kemi Wang
>> [2].Using a rwlock to protect access to the mm_rb tree is limiting the
>> locking contention to these operations which are expected to be in a O(log
>> n)
>> order. In addition to ensure that the VMA is not freed in our back a
>> reference count is added and 2 services (get_vma() and put_vma()) are
>> introduced to handle the reference count. When a VMA is fetch from the RB
>> tree using get_vma() is must be later freeed using put_vma(). Furthermore,
>> to allow the VMA to be used again by the classic page fault handler a
>> service is introduced can_reuse_spf_vma(). This service is expected to be
>> called with the mmap_sem hold. It checked that the VMA is still matching
>> the specified address and is releasing its reference count as the mmap_sem
>> is hold it is ensure that it will not be freed in our back. In general, the
>> VMA's reference count could be decremented when holding the mmap_sem but it
>> should not be increased as holding the mmap_sem is ensuring that the VMA is
>> stable. I can't see anymore the overhead I got while will-it-scale
>> benchmark anymore.
>>
>> The VMA's attributes checked during the speculative page fault processing
>> have to be protected against parallel changes. This is done by using a per
>> VMA sequence lock. This sequence lock allows the speculative page fault
>> handler to fast check for parallel changes in progress and to abort the
>> speculative page fault in that case.
>>
>> Once the VMA is found, the speculative page fault handler would check for
>> the VMA's attributes to verify that the page fault has to be handled
>> correctly or not. Thus the VMA is protected through a sequence lock which
>> allows fast detection of concurrent VMA changes. If such a change is
>> detected, the speculative page fault is aborted and a *classic* page fault
>> is tried. VMA sequence lockings are added when VMA attributes which are
>> checked during the page fault are modified.
>>
>> When the PTE is fetched, the VMA is checked to see if it has been changed,
>> so once the page table is locked, the VMA is valid, so any other changes
>> leading to touching this PTE will need to lock the page table, so no
>> parallel change is possible at this time.
>>
>> The locking of the PTE is done with interrupts disabled, this allows to
>> check for the PMD to ensure that there is not an ongoing collapsing
>> operation. Since khugepaged is firstly set the PMD to pmd_none and then is
>> waiting for the other CPU to have catch the IPI interrupt, if the pmd is
>> valid at the time the PTE is locked, we have the guarantee that the
>> collapsing opertion will have to wait on the PTE lock to move foward. This
>> allows the SPF handler to map the PTE safely. If the PMD value is different
>> than the one recorded at the beginning of the SPF operation, the classic
>> page fault handler will be called to handle the operation while holding the
>> mmap_sem. As the PTE lock is done with the interrupts disabled, the lock is
>> done using spin_trylock() to avoid dead lock when handling a page fault
>> while a TLB invalidate is requested by an other CPU holding the PTE.
>>
>> Support for THP is not done because when checking for the PMD, we can be
>> confused by an in progress collapsing operation done by khugepaged. The
>> issue is that pmd_none() could be true either if the PMD is not already
>> populated or if the underlying PTE are in the way to be collapsed. So we
>> cannot safely allocate a PMD if pmd_none() is true.
>>
>> This series a new software performance event named 'speculative-faults' or
>> 'spf'. It counts the number of successful page fault event handled in a
>> speculative way. When recording 'faults,spf' events, the faults one is
>> counting the total number of page fault events while 'spf' is only counting
>> the part of the faults processed in a speculative way.
>>
>> There are some trace events introduced by this series. They allow to
>> identify why the page faults where not processed in a speculative way. This
>> doesn't take in account the faults generated by a monothreaded process
>> which directly processed while holding the mmap_sem. This trace events are
>> grouped in a system named 'pagefault', they are:
>> - pagefault:spf_pte_lock : if the pte was already locked by another thread
>> - pagefault:spf_vma_changed : if the VMA has been changed in our back
>> - pagefault:spf_vma_noanon : the vma->anon_vma field was not yet set.
>> - pagefault:spf_vma_notsup : the VMA's type is not supported
>> - pagefault:spf_vma_access : the VMA's access right are not respected
>> - pagefault:spf_pmd_changed : the upper PMD pointer has changed in our
>> back.
>>
>> To record all the related events, the easier is to run perf with the
>> following arguments :
>> $ perf stat -e 'faults,spf,pagefault:*' <command>
>>
>> This series builds on top of v4.16-rc2-mmotm-2018-02-21-14-48 and is
>> functional on x86 and PowerPC.
>>
>> ---------------------
>> Real Workload results
>>
>> As mentioned in previous email, we did non official runs using a "popular
>> in memory multithreaded database product" on 176 cores SMT8 Power system
>> which showed a 30% improvements in the number of transaction processed per
>> second. This run has been done on the v6 series, but changes introduced in
>> this new verion should not impact the performance boost seen.
>>
>> Here are the perf data captured during 2 of these runs on top of the v8
>> series:
>> vanilla spf
>> faults 89.418 101.364
>> spf n/a 97.989
>>
>> With the SPF kernel, most of the page fault were processed in a speculative
>> way.
>>
>> ------------------
>> Benchmarks results
>>
>> Base kernel is v4.16-rc4-mmotm-2018-03-09-16-34
>> SPF is BASE + this series
>>
>> Kernbench:
>> ----------
>> Here are the results on a 16 CPUs X86 guest using kernbench on a 4.13-rc4
>> kernel (kernel is build 5 times):
>>
>> Average Half load -j 8
>> Run (std deviation)
>> BASE SPF
>> Elapsed Time 151.36 (1.40139) 151.748 (1.09716) 0.26%
>> User Time 1023.19 (3.58972) 1027.35 (2.30396) 0.41%
>> System Time 125.026 (1.8547) 124.504 (0.980015) -0.42%
>> Percent CPU 758.2 (5.54076) 758.6 (3.97492) 0.05%
>> Context Switches 54924 (453.634) 54851 (382.293) -0.13%
>> Sleeps 105589 (704.581) 105282 (435.502) -0.29%
>>
>> Average Optimal load -j 16
>> Run (std deviation)
>> BASE SPF
>> Elapsed Time 74.804 (1.25139) 74.368 (0.406288) -0.58%
>> User Time 962.033 (64.5125) 963.93 (66.8797) 0.20%
>> System Time 110.771 (15.0817) 110.387 (14.8989) -0.35%
>> Percent CPU 1045.7 (303.387) 1049.1 (306.255) 0.33%
>> Context Switches 76201.8 (22433.1) 76170.4 (22482.9) -0.04%
>> Sleeps 110289 (5024.05) 110220 (5248.58) -0.06%
>>
>> During a run on the SPF, perf events were captured:
>> Performance counter stats for '../kernbench -M':
>> 510334017 faults
>> 200 spf
>> 0 pagefault:spf_pte_lock
>> 0 pagefault:spf_vma_changed
>> 0 pagefault:spf_vma_noanon
>> 2174 pagefault:spf_vma_notsup
>> 0 pagefault:spf_vma_access
>> 0 pagefault:spf_pmd_changed
>>
>> Very few speculative page fault were recorded as most of the processes
>> involved are monothreaded (sounds that on this architecture some threads
>> were created during the kernel build processing).
>>
>> Here are the kerbench results on a 80 CPUs Power8 system:
>>
>> Average Half load -j 40
>> Run (std deviation)
>> BASE SPF
>> Elapsed Time 116.958 (0.73401) 117.43 (0.927497) 0.40%
>> User Time 4472.35 (7.85792) 4480.16 (19.4909) 0.17%
>> System Time 136.248 (0.587639) 136.922 (1.09058) 0.49%
>> Percent CPU 3939.8 (20.6567) 3931.2 (17.2829) -0.22%
>> Context Switches 92445.8 (236.672) 92720.8 (270.118) 0.30%
>> Sleeps 318475 (1412.6) 317996 (1819.07) -0.15%
>>
>> Average Optimal load -j 80
>> Run (std deviation)
>> BASE SPF
>> Elapsed Time 106.976 (0.406731) 107.72 (0.329014) 0.70%
>> User Time 5863.47 (1466.45) 5865.38 (1460.27) 0.03%
>> System Time 159.995 (25.0393) 160.329 (24.6921) 0.21%
>> Percent CPU 5446.2 (1588.23) 5416 (1565.34) -0.55%
>> Context Switches 223018 (137637) 224867 (139305) 0.83%
>> Sleeps 330846 (13127.3) 332348 (15556.9) 0.45%
>>
>> During a run on the SPF, perf events were captured:
>> Performance counter stats for '../kernbench -M':
>> 116612488 faults
>> 0 spf
>> 0 pagefault:spf_pte_lock
>> 0 pagefault:spf_vma_changed
>> 0 pagefault:spf_vma_noanon
>> 473 pagefault:spf_vma_notsup
>> 0 pagefault:spf_vma_access
>> 0 pagefault:spf_pmd_changed
>>
>> Most of the processes involved are monothreaded so SPF is not activated but
>> there is no impact on the performance.
>>
>> Ebizzy:
>> -------
>> The test is counting the number of records per second it can manage, the
>> higher is the best. I run it like this 'ebizzy -mTRp'. To get consistent
>> result I repeated the test 100 times and measure the average result. The
>> number is the record processes per second, the higher is the best.
>>
>> BASE SPF delta
>> 16 CPUs x86 VM 14902.6 95905.16 543.55%
>> 80 CPUs P8 node 37240.24 78185.67 109.95%
>>
>> Here are the performance counter read during a run on a 16 CPUs x86 VM:
>> Performance counter stats for './ebizzy -mRTp':
>> 888157 faults
>> 884773 spf
>> 92 pagefault:spf_pte_lock
>> 2379 pagefault:spf_vma_changed
>> 0 pagefault:spf_vma_noanon
>> 80 pagefault:spf_vma_notsup
>> 0 pagefault:spf_vma_access
>> 0 pagefault:spf_pmd_changed
>>
>> And the ones captured during a run on a 80 CPUs Power node:
>> Performance counter stats for './ebizzy -mRTp':
>> 762134 faults
>> 728663 spf
>> 19101 pagefault:spf_pte_lock
>> 13969 pagefault:spf_vma_changed
>> 0 pagefault:spf_vma_noanon
>> 272 pagefault:spf_vma_notsup
>> 0 pagefault:spf_vma_access
>> 0 pagefault:spf_pmd_changed
>>
>> In ebizzy's case most of the page fault were handled in a speculative way,
>> leading the ebizzy performance boost.
>
> We ported the SPF to kernel 4.9 in android devices.
> For the app launch time, It improves about 15% average. For the apps
> which have hundreds of threads, it will be about 20%.
Hi Ganesh,
Thanks for sharing these great and encouraging results.
Could you please detail a bit more about your system configuration and
application ?
Laurent.
> Thanks.
>
>>
>> ------------------
>> Changes since v8:
>> - Don't check PMD when locking the pte when THP is disabled
>> Thanks to Daniel Jordan for reporting this.
>> - Rebase on 4.16
>> Changes since v7:
>> - move pte_map_lock() and pte_spinlock() upper in mm/memory.c (patch 4 &
>> 5)
>> - make pte_unmap_same() compatible with the speculative page fault (patch
>> 6)
>> Changes since v6:
>> - Rename config variable to CONFIG_SPECULATIVE_PAGE_FAULT (patch 1)
>> - Review the way the config variable is set (patch 1 to 3)
>> - Introduce mm_rb_write_*lock() in mm/mmap.c (patch 18)
>> - Merge patch introducing pte try locking in the patch 18.
>> Changes since v5:
>> - use rwlock agains the mm RB tree in place of SRCU
>> - add a VMA's reference count to protect VMA while using it without
>> holding the mmap_sem.
>> - check PMD value to detect collapsing operation
>> - don't try speculative page fault for mono threaded processes
>> - try to reuse the fetched VMA if VM_RETRY is returned
>> - go directly to the error path if an error is detected during the SPF
>> path
>> - fix race window when moving VMA in move_vma()
>> Changes since v4:
>> - As requested by Andrew Morton, use CONFIG_SPF and define it earlier in
>> the series to ease bisection.
>> Changes since v3:
>> - Don't build when CONFIG_SMP is not set
>> - Fixed a lock dependency warning in __vma_adjust()
>> - Use READ_ONCE to access p*d values in handle_speculative_fault()
>> - Call memcp_oom() service in handle_speculative_fault()
>> Changes since v2:
>> - Perf event is renamed in PERF_COUNT_SW_SPF
>> - On Power handle do_page_fault()'s cleaning
>> - On Power if the VM_FAULT_ERROR is returned by
>> handle_speculative_fault(), do not retry but jump to the error path
>> - If VMA's flags are not matching the fault, directly returns
>> VM_FAULT_SIGSEGV and not VM_FAULT_RETRY
>> - Check for pud_trans_huge() to avoid speculative path
>> - Handles _vm_normal_page()'s introduced by 6f16211df3bf
>> ("mm/device-public-memory: device memory cache coherent with CPU")
>> - add and review few comments in the code
>> Changes since v1:
>> - Remove PERF_COUNT_SW_SPF_FAILED perf event.
>> - Add tracing events to details speculative page fault failures.
>> - Cache VMA fields values which are used once the PTE is unlocked at the
>> end of the page fault events.
>> - Ensure that fields read during the speculative path are written and read
>> using WRITE_ONCE and READ_ONCE.
>> - Add checks at the beginning of the speculative path to abort it if the
>> VMA is known to not be supported.
>> Changes since RFC V5 [5]
>> - Port to 4.13 kernel
>> - Merging patch fixing lock dependency into the original patch
>> - Replace the 2 parameters of vma_has_changed() with the vmf pointer
>> - In patch 7, don't call __do_fault() in the speculative path as it may
>> want to unlock the mmap_sem.
>> - In patch 11-12, don't check for vma boundaries when
>> page_add_new_anon_rmap() is called during the spf path and protect against
>> anon_vma pointer's update.
>> - In patch 13-16, add performance events to report number of successful
>> and failed speculative events.
>>
>> [1]
>> http://linux-kernel.2935.n7.nabble.com/RFC-PATCH-0-6-Another-go-at-speculative-page-faults-tt965642.html#none
>> [2] https://patchwork.kernel.org/patch/9999687/
>>
>>
>> Laurent Dufour (20):
>> mm: Introduce CONFIG_SPECULATIVE_PAGE_FAULT
>> x86/mm: Define CONFIG_SPECULATIVE_PAGE_FAULT
>> powerpc/mm: Define CONFIG_SPECULATIVE_PAGE_FAULT
>> mm: Introduce pte_spinlock for FAULT_FLAG_SPECULATIVE
>> mm: make pte_unmap_same compatible with SPF
>> mm: Protect VMA modifications using VMA sequence count
>> mm: protect mremap() against SPF hanlder
>> mm: Protect SPF handler against anon_vma changes
>> mm: Cache some VMA fields in the vm_fault structure
>> mm/migrate: Pass vm_fault pointer to migrate_misplaced_page()
>> mm: Introduce __lru_cache_add_active_or_unevictable
>> mm: Introduce __maybe_mkwrite()
>> mm: Introduce __vm_normal_page()
>> mm: Introduce __page_add_new_anon_rmap()
>> mm: Protect mm_rb tree with a rwlock
>> mm: Adding speculative page fault failure trace events
>> perf: Add a speculative page fault sw event
>> perf tools: Add support for the SPF perf event
>> mm: Speculative page fault handler return VMA
>> powerpc/mm: Add speculative page fault
>>
>> Peter Zijlstra (4):
>> mm: Prepare for FAULT_FLAG_SPECULATIVE
>> mm: VMA sequence count
>> mm: Provide speculative fault infrastructure
>> x86/mm: Add speculative pagefault handling
>>
>> arch/powerpc/Kconfig | 1 +
>> arch/powerpc/mm/fault.c | 31 +-
>> arch/x86/Kconfig | 1 +
>> arch/x86/mm/fault.c | 38 ++-
>> fs/proc/task_mmu.c | 5 +-
>> fs/userfaultfd.c | 17 +-
>> include/linux/hugetlb_inline.h | 2 +-
>> include/linux/migrate.h | 4 +-
>> include/linux/mm.h | 92 +++++-
>> include/linux/mm_types.h | 7 +
>> include/linux/pagemap.h | 4 +-
>> include/linux/rmap.h | 12 +-
>> include/linux/swap.h | 10 +-
>> include/trace/events/pagefault.h | 87 +++++
>> include/uapi/linux/perf_event.h | 1 +
>> kernel/fork.c | 3 +
>> mm/Kconfig | 3 +
>> mm/hugetlb.c | 2 +
>> mm/init-mm.c | 3 +
>> mm/internal.h | 20 ++
>> mm/khugepaged.c | 5 +
>> mm/madvise.c | 6 +-
>> mm/memory.c | 594 ++++++++++++++++++++++++++++++----
>> mm/mempolicy.c | 51 ++-
>> mm/migrate.c | 4 +-
>> mm/mlock.c | 13 +-
>> mm/mmap.c | 211 +++++++++---
>> mm/mprotect.c | 4 +-
>> mm/mremap.c | 13 +
>> mm/rmap.c | 5 +-
>> mm/swap.c | 6 +-
>> mm/swap_state.c | 8 +-
>> tools/include/uapi/linux/perf_event.h | 1 +
>> tools/perf/util/evsel.c | 1 +
>> tools/perf/util/parse-events.c | 4 +
>> tools/perf/util/parse-events.l | 1 +
>> tools/perf/util/python.c | 1 +
>> 37 files changed, 1097 insertions(+), 174 deletions(-)
>> create mode 100644 include/trace/events/pagefault.h
>>
>> --
>> 2.7.4
>>
>
^ permalink raw reply
* Re: [PATCH 00/14] numa aware allocation for pacas, stacks, pagetables
From: Nicholas Piggin @ 2018-03-29 12:04 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
In-Reply-To: <87in9f1k2j.fsf@concordia.ellerman.id.au>
On Thu, 29 Mar 2018 17:18:12 +1100
Michael Ellerman <mpe@ellerman.id.au> wrote:
> Nicholas Piggin <npiggin@gmail.com> writes:
> > On Wed, 07 Mar 2018 21:50:04 +1100
> > Michael Ellerman <mpe@ellerman.id.au> wrote:
> >> Nicholas Piggin <npiggin@gmail.com> writes:
> >> > This series allows numa aware allocations for various early data
> >> > structures for radix. Hash still has a bolted SLB limitation that
> >> > prevents at least pacas and stacks from node-affine allocations.
> >> >
> >> > Fixed up a number of bugs, got pSeries working, added a couple more
> >> > cases where page tables can be allocated node-local.
> >>
> >> Few problems in here:
> >>
> >> FAILURE kernel-build-linux » powerpc,gcc_ubuntu_be,pmac32
> >> arch/powerpc/kernel/prom.c:748:2: error: implicit declaration of function 'allocate_paca_ptrs' [-Werror=implicit-function-declaration]
> >>
> >> FAILURE kernel-build-linux » powerpc,gcc_ubuntu_le,powernv
> >> arch/powerpc/include/asm/paca.h:49:33: error: 'struct paca_struct' has no member named 'lppaca_ptr'
> >> arch/powerpc/include/asm/paca.h:49:33: error: 'struct paca_struct' has no member named 'lppaca_ptr'
> >>
> >> Did I miss a follow-up or something?
> >
> > Here's a patch that applies to "powerpc/64: defer paca allocation
> > until memory topology is discovered". The first hunk fixes the ppc32
> > issue, and the second hunk avoids freeing the cpu_to_phys_id array
> > if the platform didn't allocate it. But I've just realized that
> > should go into the previous patch (which is missing the
> > memblock_free).
> > --
> ...
> > diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> > index 56f7a2b793e0..2ba05acc2973 100644
> > --- a/arch/powerpc/kernel/setup-common.c
> > +++ b/arch/powerpc/kernel/setup-common.c
> > @@ -854,8 +854,10 @@ static void smp_setup_pacas(void)
> > set_hard_smp_processor_id(cpu, cpu_to_phys_id[cpu]);
> > }
> >
> > - memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32));
> > - cpu_to_phys_id = NULL;
> > + if (cpu_to_phys_id) {
> > + memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32));
> > + cpu_to_phys_id = NULL;
> > + }
> > }
> > #endif
>
> Where did you want that?
Patch 8 should have
if (cpu_to_phys_id) {
memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32));
cpu_to_phys_id = NULL;
}
Right after its ight after the set_hard_smp_processor_id() loop. Patch 9
moves it all to smp_setup_pacas plus the allocate_paca() call in the loop.
I think that makes sense.
Thanks for fixing it all up, had a few rough edges.
^ permalink raw reply
* Re: [PATCH] powerpc: Clear branch trap (MSR.BE) before delivering SIGTRAP
From: Matt Evans @ 2018-03-29 11:54 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
In-Reply-To: <C8B54188-179A-475D-B06A-A25426EF6932@ozlabs.org>
Hi Michael,
> On 28 Mar 2018, at 11:36, Matt Evans <matt@ozlabs.org> wrote:
>=20
> Howdy Michael,
>=20
>> On 28 Mar 2018, at 06:54, Michael Ellerman <mpe@ellerman.id.au> =
wrote:
>>=20
>> Matt Evans <matt@ozlabs.org> writes:
>>=20
>>> When using SIG_DBG_BRANCH_TRACING, MSR.BE is left enabled in the
>>> user context when single_step_exception() prepares the SIGTRAP
>>> delivery. The resulting branch-trap-within-the-SIGTRAP-handler
>>> isn't healthy.
>>>=20
>>> Commit 2538c2d08f46141550a1e68819efa8fe31c6e3dc broke this, by
>>> replacing an MSR mask operation of ~(MSR_SE | MSR_BE) with a call
>>> to clear_single_step() which only clears MSR_SE.
>>>=20
>>> This patch adds a new helper, clear_br_trace(), which clears the
>>> debug trap before invoking the signal handler. This helper is a
>>> NOP for BookE as SIG_DBG_BRANCH_TRACING isn't supported on BookE.
>>>=20
>>> Signed-off-by: Matt Evans <matt@ozlabs.org>
>>=20
>> Hi Matt!
>>=20
>> It seems we might not be regularly testing this code :}
>=20
> I know, rite? ;-)
>=20
>> How did you hit/find the bug? And do you have a test case by any =
chance?
>>=20
>> I found the test code at the bottom of:
>> https://lwn.net/Articles/114587/
>>=20
>> But it didn't immediately work.
>=20
> I'm using this feature as part of a debug harness I wrote to log a =
program=E2=80=99s control flow (to create a =E2=80=9Cknown good=E2=80=9D =
pattern to compare a PPC interpreter against). So at least the feature =
has /one/ user. ;-)
>=20
> The symptoms of the bug are that if you use single-stepping you get a =
sequence of SIGTRAPs representing each instruction completion (good), =
but if you use branch tracing the process just dies with SIGTRAP (looks =
like it=E2=80=99s never caught by the signal handler). What=E2=80=99s =
really happening is that there /is/ a signal delivered to the handler, =
but (because branch tracing is left on) that then causes a second debug =
exception from the handler itself, i.e. whilst SIGTRAP=E2=80=99s masked.
>=20
> OK, let me have a dig to reduce my program to something very basic and =
I=E2=80=99ll post something =E2=80=94 sorry, I should=E2=80=99ve got a =
PoC ready before. (I did start out inspired by that post you linked to, =
but IIRC I don=E2=80=99t think it worked out of the box for me either.)
I=E2=80=99ve put a simple SIG_DBG_BRANCH_TRACING test program here:
http://ozlabs.org/~matt/files/sig_dbg_brtrace_test.c
It=E2=80=99s commented regarding expected output. I=E2=80=99ve only =
tested this on a G4 =E2=80=94 it should work on PPC64 too but the ISA =
says support for branch tracing is optional for an implementation. =
I=E2=80=99d be interested in what POWERx does. :)
Cheers,
Matt
^ permalink raw reply
* [PATCH v5 14/16] powerpc: Switch to generic free_initrd_mem.
From: Shea Levy @ 2018-03-29 11:32 UTC (permalink / raw)
To: linux-riscv, linux-kernel
Cc: Shea Levy, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, linuxppc-dev
In-Reply-To: <20180329113207.30674-1-shea@shealevy.com>
The generic implementation is functionally identical.
Signed-off-by: Shea Levy <shea@shealevy.com>
---
arch/powerpc/mm/mem.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index fe8c61149fb8..e85b2a3cd264 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -404,13 +404,6 @@ void free_initmem(void)
free_initmem_default(POISON_FREE_INITMEM);
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
- free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
/*
* This is called when a page has been modified by the kernel.
* It just marks the page as not i-cache clean. We do the i-cache
--
2.16.2
^ permalink raw reply related
* Re: RFC on writel and writel_relaxed
From: Will Deacon @ 2018-03-29 9:20 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Nicholas Piggin, David Miller, paulmck, arnd, linux-rdma,
linuxppc-dev, linus971, alexander.duyck, okaya, jgg, David.Laight,
oohall, netdev, alexander.h.duyck, torvalds
In-Reply-To: <1522272692.21446.42.camel@kernel.crashing.org>
On Thu, Mar 29, 2018 at 08:31:32AM +1100, Benjamin Herrenschmidt wrote:
> On Thu, 2018-03-29 at 02:23 +1000, Nicholas Piggin wrote:
> > This is a variation on the mandatory write barrier that causes writes to weakly
> > ordered I/O regions to be partially ordered. Its effects may go beyond the
> > CPU->Hardware interface and actually affect the hardware at some level.
> >
> > How can a driver writer possibly get that right?
> >
> > IIRC it was added for some big ia64 system that was really expensive
> > to implement the proper wmb() semantics on. So wmb() semantics were
> > quietly downgraded, then the subsequently broken drivers they cared
> > about were fixed by adding the stronger mmiowb().
> >
> > What should have happened was wmb and writel remained correct, sane, and
> > expensive, and they add an mmio_wmb() to order MMIO stores made by the
> > writel_relaxed accessors, then use that to speed up the few drivers they
> > care about.
> >
> > Now that ia64 doesn't matter too much, can we deprecate mmiowb and just
> > make wmb ordering talk about stores to the device, not to some
> > intermediate stage of the interconnect where it can be subsequently
> > reordered wrt the device? Drivers can be converted back to using wmb
> > or writel gradually.
>
> I was under the impression that mmiowb was specifically about ordering
> writel's with a subsequent spin_unlock, without it, MMIOs from
> different CPUs (within the same lock) would still arrive OO.
>
> If that's indeed the case, I would suggest ia64 switches to a similar
> per-cpu flag trick powerpc uses.
... or we could remove ia64.
/me runs for cover
Will
^ permalink raw reply
* Re: RFC on writel and writel_relaxed
From: Will Deacon @ 2018-03-29 9:19 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Benjamin Herrenschmidt, Arnd Bergmann, Sinan Kaya, David Laight,
Oliver, open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
linux-rdma@vger.kernel.org, Paul E. McKenney, Peter Zijlstra,
Ingo Molnar, Jonathan Corbet
In-Reply-To: <20180328165732.GA4546@ziepe.ca>
On Wed, Mar 28, 2018 at 10:57:32AM -0600, Jason Gunthorpe wrote:
> On Wed, Mar 28, 2018 at 11:13:45AM +0100, Will Deacon wrote:
> > On Wed, Mar 28, 2018 at 09:01:27PM +1100, Benjamin Herrenschmidt wrote:
> > > On Wed, 2018-03-28 at 11:55 +0200, Arnd Bergmann wrote:
> > > > > powerpc and ARM can't quite make them synchronous I think, but at least
> > > > > they should have the same semantics as writel.
> > > >
> > > > One thing that ARM does IIRC is that it only guarantees to order writel() within
> > > > one device, and the memory mapped PCI I/O space window almost certainly
> > > > counts as a separate device to the CPU.
> > >
> > > That sounds bogus.
> >
> > To elaborate, if you do the following on arm:
> >
> > writel(DEVICE_FOO);
> > writel(DEVICE_BAR);
> >
> > we generally cannot guarantee in which order those accesses will hit the
> > devices even if we add every barrier under the sun. You'd need something
> > in between, specific to DEVICE_FOO (probably a read-back) to really push
> > the first write out. This doesn't sound like it would be that uncommon to
> > me.
>
> The PCI posted write does not require the above to execute 'in order'
> only that any bus segment shared by the two devices have the writes
> issued in CPU order. ie at a shared PCI root port for instance.
>
> If I recall this is very similar to the ordering that ARM's on-chip
> AXI interconnect is supposed to provide.. So I'd be very surprised if
> a modern ARM64 has an meaningful difference from x86 here.
>From the architectural perspective, writes to different "peripherals" are
not ordered with respect to each other. The first writel will complete once
it gets its write acknowledgement, but this may not necessarily come from
the endpoint -- it could come from an intermediate buffer past the point of
serialisation (i.e. the write will then be ordered with respect to other
accesses to that same endpoint). The PCI root port would look like one
peripheral here.
> When talking about ordering between the devices, the relevant question
> is what happens if the writel(DEVICE_BAR) triggers DEVICE_BAR to DMA
> from the DEVICE_FOO. 'ordered' means that in this case
> writel(DEVICE_FOO) must be presented to FOO before anything generated
> by BAR.
Yes, and that isn't the case for arm because the writes can still be
buffered.
Will
^ permalink raw reply
* Re: [PATCH v8 22/24] mm: Speculative page fault handler return VMA
From: Laurent Dufour @ 2018-03-29 7:50 UTC (permalink / raw)
To: Ganesh Mahendran
Cc: Paul McKenney, Peter Zijlstra, Andrew Morton, kirill, ak,
Michal Hocko, dave, jack, Matthew Wilcox, benh, mpe, paulus,
Thomas Gleixner, Ingo Molnar, hpa, Will Deacon,
Sergey Senozhatsky, Andrea Arcangeli, Alexei Starovoitov,
kemi.wang, Sergey Senozhatsky, Daniel Jordan, linux-kernel,
Linux-MM, haren, khandual, npiggin, Balbir Singh, Tim Chen,
linuxppc-dev, x86
In-Reply-To: <CADAEsF8wRRG7CUFxTS49mj6mtxgJER+1x2u=0kTq+fQo5m+gTg@mail.gmail.com>
On 29/03/2018 05:06, Ganesh Mahendran wrote:
> 2018-03-29 10:26 GMT+08:00 Ganesh Mahendran <opensource.ganesh@gmail.com>:
>> Hi, Laurent
>>
>> 2018-02-16 23:25 GMT+08:00 Laurent Dufour <ldufour@linux.vnet.ibm.com>:
>>> When the speculative page fault handler is returning VM_RETRY, there is a
>>> chance that VMA fetched without grabbing the mmap_sem can be reused by the
>>> legacy page fault handler. By reusing it, we avoid calling find_vma()
>>> again. To achieve, that we must ensure that the VMA structure will not be
>>> freed in our back. This is done by getting the reference on it (get_vma())
>>> and by assuming that the caller will call the new service
>>> can_reuse_spf_vma() once it has grabbed the mmap_sem.
>>>
>>> can_reuse_spf_vma() is first checking that the VMA is still in the RB tree
>>> , and then that the VMA's boundaries matched the passed address and release
>>> the reference on the VMA so that it can be freed if needed.
>>>
>>> In the case the VMA is freed, can_reuse_spf_vma() will have returned false
>>> as the VMA is no more in the RB tree.
>>
>> when I applied this patch to arm64, I got a crash:
Hi Ganesh,
Glad to see that you're enabling it on arm64.
I didn't give this arch a try, so feel free to propose patches on top of the
SPF series for this, I'll do my best to give them updated.
>>
>> [ 6.088296] Unable to handle kernel NULL pointer dereference at
>> virtual address 00000000
>> [ 6.088307] pgd = ffffff9d67735000
>> [ 6.088313] [00000000] *pgd=00000001795e3003,
>> *pud=00000001795e3003, *pmd=0000000000000000
>> [ 6.088372] ------------[ cut here ]------------
>> [ 6.088377] Kernel BUG at ffffff9d64f65960 [verbose debug info unavailable]
>> [ 6.088384] Internal error: Oops - BUG: 96000045 [#1] PREEMPT SMP
>> [ 6.088389] BUG: Bad rss-counter state mm:ffffffe8f3861040 idx:0 val:90
>> [ 6.088393] BUG: Bad rss-counter state mm:ffffffe8f3861040 idx:1 val:58
>> [ 6.088398] Modules linked in:
>> [ 6.088408] CPU: 1 PID: 621 Comm: qseecomd Not tainted 4.4.78-perf+ #88
>> [ 6.088413] Hardware name: Qualcomm Technologies, Inc. SDM 636
>> PM660 + PM660L MTP E7S (DT)
>> [ 6.088419] task: ffffffe8f6208000 ti: ffffffe872a8c000 task.ti:
>> ffffffe872a8c000
>> [ 6.088432] PC is at __rb_erase_color+0x108/0x240
>> [ 6.088441] LR is at vma_interval_tree_remove+0x244/0x24c
>> [ 6.088447] pc : [<ffffff9d64f65960>] lr : [<ffffff9d64d9c2d8>]
>> pstate: 604001c5
>> [ 6.088451] sp : ffffffe872a8fa50
>> [ 6.088455] x29: ffffffe872a8fa50 x28: 0000000000000008
>> [ 6.088462] x27: 0000000000000009 x26: 0000000000000000
>> [ 6.088470] x25: ffffffe8f458fb80 x24: 000000768ff87000
>> [ 6.088477] x23: 0000000000000000 x22: 0000000000000000
>> [ 6.088484] x21: ffffff9d64d9be7c x20: ffffffe8f3ff0680
>> [ 6.088492] x19: ffffffe8f212e9b0 x18: 0000000000000074
>> [ 6.088499] x17: 0000000000000007 x16: 000000000000000e
>> [ 6.088507] x15: ffffff9d65c88000 x14: 0000000000000001
>> [ 6.088514] x13: 0000000000192d76 x12: 0000000000989680
>> [ 6.088521] x11: 00000000001fffff x10: ffffff9d661ded1b
>> [ 6.088528] x9 : 0000007691759000 x8 : 0000000007691759
>> [ 6.088535] x7 : 0000000000000000 x6 : ffffffe871ebada8
>> [ 6.088541] x5 : 00000000000000e1 x4 : ffffffe8f212e958
>> [ 6.088548] x3 : 00000000000000e9 x2 : 0000000000000000
>> [ 6.088555] x1 : ffffffe8f212f110 x0 : ffffffe8f212e9b1
>> [ 6.088564]
>> [ 6.088564] PC: 0xffffff9d64f65920:
>> [ 6.088568] 5920 f9000002 aa0103e0 aa1603e1 d63f02a0 aa1603e1
>> f9400822 f9000662 f9000833
>> [ 6.088590] 5940 1400003b f9400a61 f9400020 370002c0 f9400436
>> b2400260 f9000a76 f9000433
>> [ 6.088610] 5960 f90002c0 f9400260 f9000020 f9000261 f27ef400
>> 54000100 f9400802 eb13005f
>> [ 6.088630] 5980 54000061 f9000801 14000004 f9000401 14000002
>> f9000281 aa1303e0 d63f02a0
>> [ 6.088652]
>> [ 6.088652] LR: 0xffffff9d64d9c298:
>> [ 6.088656] c298 f9403083 b4000083 f9400c63 eb03005f 9a832042
>> f9403883 eb02007f 540000a0
>> [ 6.088676] c2b8 f9003882 f9402c82 927ef442 b5fffd22 b4000080
>> f0ffffe2 9139f042 94072561
>> [ 6.088695] c2d8 a8c17bfd d65f03c0 a9bf7bfd 910003fd f9400003
>> d2800000 b40000e3 f9400c65
>> [ 6.088715] c2f8 d1016063 eb0100bf 54000063 aa0303e0 97fffef2
>> a8c17bfd d65f03c0 a9bf7bfd
>> [ 6.088735]
>> [ 6.088735] SP: 0xffffffe872a8fa10:
>> [ 6.088740] fa10 64d9c2d8 ffffff9d 72a8fa50 ffffffe8 64f65960
>> ffffff9d 604001c5 00000000
>> [ 6.088759] fa30 71d67d70 ffffffe8 71c281e8 ffffffe8 00000000
>> 00000080 64daa90c ffffff9d
>> [ 6.088779] fa50 72a8fa90 ffffffe8 64d9c2d8 ffffff9d 71ebada8
>> ffffffe8 f3ff0678 ffffffe8
>> [ 6.088799] fa70 72a8fb80 ffffffe8 00000000 00000000 00000000
>> 00000000 00000001 00000000
>> [ 6.088818]
>> [ 6.088823] Process qseecomd (pid: 621, stack limit = 0xffffffe872a8c028)
>> [ 6.088828] Call trace:
>> [ 6.088834] Exception stack(0xffffffe872a8f860 to 0xffffffe872a8f990)
>> [ 6.088841] f860: ffffffe8f212e9b0 0000008000000000
>> 0000000082b37000 ffffff9d64f65960
>> [ 6.088848] f880: 00000000604001c5 ffffff9d672c8680
>> ffffff9d672c9c00 ffffff9d672d3ab7
>> [ 6.088855] f8a0: ffffffe872a8f8f0 ffffff9d64db9bfc
>> 0000000000000000 ffffffe8f9402c00
>> [ 6.088861] f8c0: ffffffe872a8c000 0000000000000000
>> ffffffe872a8f920 ffffff9d64db9bfc
>> [ 6.088867] f8e0: 0000000000000000 ffffffe8f9402b00
>> ffffffe872a8fa10 ffffff9d64dba568
>> [ 6.088874] f900: ffffffbe61c759c0 ffffffe871d67d70
>> ffffffe8f9402c00 1de56fb006cba396
>> [ 6.088881] f920: ffffffe8f212e9b1 ffffffe8f212f110
>> 0000000000000000 00000000000000e9
>> [ 6.088888] f940: ffffffe8f212e958 00000000000000e1
>> ffffffe871ebada8 0000000000000000
>> [ 6.088895] f960: 0000000007691759 0000007691759000
>> ffffff9d661ded1b 00000000001fffff
>> [ 6.088901] f980: 0000000000989680 0000000000192d76
>> [ 6.088908] [<ffffff9d64f65960>] __rb_erase_color+0x108/0x240
>> [ 6.088915] [<ffffff9d64d9c2d8>] vma_interval_tree_remove+0x244/0x24c
>> [ 6.088924] [<ffffff9d64da4b5c>] __remove_shared_vm_struct+0x74/0x88
>> [ 6.088930] [<ffffff9d64da52b8>] unlink_file_vma+0x40/0x54
>> [ 6.088937] [<ffffff9d64d9f928>] free_pgtables+0xb8/0xfc
>> [ 6.088945] [<ffffff9d64da6b84>] exit_mmap+0x78/0x13c
>> [ 6.088953] [<ffffff9d64c9f5f4>] mmput+0x40/0xe8
>> [ 6.088961] [<ffffff9d64ca5af0>] do_exit+0x3ac/0x8d8
>> [ 6.088966] [<ffffff9d64ca6090>] do_group_exit+0x44/0x9c
>> [ 6.088974] [<ffffff9d64cb10d0>] get_signal+0x4e8/0x524
>> [ 6.088981] [<ffffff9d64c87ea0>] do_signal+0xac/0x93c
>> [ 6.088989] [<ffffff9d64c88a0c>] do_notify_resume+0x18/0x58
>> [ 6.088995] [<ffffff9d64c83038>] work_pending+0x10/0x14
>> [ 6.089003] Code: f9400436 b2400260 f9000a76 f9000433 (f90002c0)
>> [ 6.089009] ---[ end trace 224ce5f97841b6a5 ]---
>> [ 6.110819] Kernel panic - not syncing: Fatal exception
>>
>> Thanks.
>
> Fixed by below patch:
I guess you don't have only the following patch to enable that feature on arm64...
Please send the complete set of patch so that I could review this.
Thanks,
Laurent.
>
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index f6838c0..9c61b0e 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -240,18 +240,18 @@
>
> static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
> unsigned int mm_flags, unsigned long vm_flags,
> - struct task_struct *tsk, struct vm_area_struct *spf_vma)
> + struct task_struct *tsk, struct vm_area_struct **spf_vma)
> {
> struct vm_area_struct *vma;
> int fault;
>
> #ifdef CONFIG_SPECULATIVE_PAGE_FAULT
> - if (spf_vma) {
> - if (can_reuse_spf_vma(spf_vma, addr))
> - vma = spf_vma;
> + if (*spf_vma) {
> + if (can_reuse_spf_vma(*spf_vma, addr))
> + vma = *spf_vma;
> else
> vma = find_vma(mm, addr);
> - spf_vma = NULL;
> + *spf_vma = NULL;
> } else
> #endif
> vma = find_vma(mm, addr);
> @@ -393,7 +389,7 @@
> #endif
> }
>
> - fault = __do_page_fault(mm, addr, mm_flags, vm_flags, tsk, spf_vma);
> + fault = __do_page_fault(mm, addr, mm_flags, vm_flags, tsk, &spf_vma);
>
> /*
> * If we need to retry but a fatal signal is pending, handle the
> @@ -480,6 +476,11 @@
> return 0;
>
> no_context:
> + if (spf_vma) {
> + put_vma(spf_vma);
> + spf_vma = NULL;
> + }
> +
> __do_kernel_fault(mm, addr, esr, regs);
> return 0;
> }
>
>
>>
>>>
>>> Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com>
>>> ---
>>> include/linux/mm.h | 5 +-
>>> mm/memory.c | 136 +++++++++++++++++++++++++++++++++--------------------
>>> 2 files changed, 88 insertions(+), 53 deletions(-)
>>>
>>> diff --git a/include/linux/mm.h b/include/linux/mm.h
>>> index c383a4e2ceb3..0cd31a37bb3d 100644
>>> --- a/include/linux/mm.h
>>> +++ b/include/linux/mm.h
>>> @@ -1355,7 +1355,10 @@ extern int handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
>>> unsigned int flags);
>>> #ifdef CONFIG_SPECULATIVE_PAGE_FAULT
>>> extern int handle_speculative_fault(struct mm_struct *mm,
>>> - unsigned long address, unsigned int flags);
>>> + unsigned long address, unsigned int flags,
>>> + struct vm_area_struct **vma);
>>> +extern bool can_reuse_spf_vma(struct vm_area_struct *vma,
>>> + unsigned long address);
>>> #endif /* CONFIG_SPECULATIVE_PAGE_FAULT */
>>> extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
>>> unsigned long address, unsigned int fault_flags,
>>> diff --git a/mm/memory.c b/mm/memory.c
>>> index 2ef686405154..1f5ce5ff79af 100644
>>> --- a/mm/memory.c
>>> +++ b/mm/memory.c
>>> @@ -4307,13 +4307,22 @@ static int __handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
>>> /* This is required by vm_normal_page() */
>>> #error "Speculative page fault handler requires __HAVE_ARCH_PTE_SPECIAL"
>>> #endif
>>> -
>>> /*
>>> * vm_normal_page() adds some processing which should be done while
>>> * hodling the mmap_sem.
>>> */
>>> +
>>> +/*
>>> + * Tries to handle the page fault in a speculative way, without grabbing the
>>> + * mmap_sem.
>>> + * When VM_FAULT_RETRY is returned, the vma pointer is valid and this vma must
>>> + * be checked later when the mmap_sem has been grabbed by calling
>>> + * can_reuse_spf_vma().
>>> + * This is needed as the returned vma is kept in memory until the call to
>>> + * can_reuse_spf_vma() is made.
>>> + */
>>> int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> - unsigned int flags)
>>> + unsigned int flags, struct vm_area_struct **vma)
>>> {
>>> struct vm_fault vmf = {
>>> .address = address,
>>> @@ -4322,7 +4331,6 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> p4d_t *p4d, p4dval;
>>> pud_t pudval;
>>> int seq, ret = VM_FAULT_RETRY;
>>> - struct vm_area_struct *vma;
>>> #ifdef CONFIG_NUMA
>>> struct mempolicy *pol;
>>> #endif
>>> @@ -4331,14 +4339,16 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> flags &= ~(FAULT_FLAG_ALLOW_RETRY|FAULT_FLAG_KILLABLE);
>>> flags |= FAULT_FLAG_SPECULATIVE;
>>>
>>> - vma = get_vma(mm, address);
>>> - if (!vma)
>>> + *vma = get_vma(mm, address);
>>> + if (!*vma)
>>> return ret;
>>> + vmf.vma = *vma;
>>>
>>> - seq = raw_read_seqcount(&vma->vm_sequence); /* rmb <-> seqlock,vma_rb_erase() */
>>> + /* rmb <-> seqlock,vma_rb_erase() */
>>> + seq = raw_read_seqcount(&vmf.vma->vm_sequence);
>>> if (seq & 1) {
>>> - trace_spf_vma_changed(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> /*
>>> @@ -4346,9 +4356,9 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> * with the VMA.
>>> * This include huge page from hugetlbfs.
>>> */
>>> - if (vma->vm_ops) {
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + if (vmf.vma->vm_ops) {
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> /*
>>> @@ -4356,18 +4366,18 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> * because vm_next and vm_prev must be safe. This can't be guaranteed
>>> * in the speculative path.
>>> */
>>> - if (unlikely(!vma->anon_vma)) {
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + if (unlikely(!vmf.vma->anon_vma)) {
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> - vmf.vma_flags = READ_ONCE(vma->vm_flags);
>>> - vmf.vma_page_prot = READ_ONCE(vma->vm_page_prot);
>>> + vmf.vma_flags = READ_ONCE(vmf.vma->vm_flags);
>>> + vmf.vma_page_prot = READ_ONCE(vmf.vma->vm_page_prot);
>>>
>>> /* Can't call userland page fault handler in the speculative path */
>>> if (unlikely(vmf.vma_flags & VM_UFFD_MISSING)) {
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> if (vmf.vma_flags & VM_GROWSDOWN || vmf.vma_flags & VM_GROWSUP) {
>>> @@ -4376,48 +4386,39 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> * boundaries but we want to trace it as not supported instead
>>> * of changed.
>>> */
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> - if (address < READ_ONCE(vma->vm_start)
>>> - || READ_ONCE(vma->vm_end) <= address) {
>>> - trace_spf_vma_changed(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + if (address < READ_ONCE(vmf.vma->vm_start)
>>> + || READ_ONCE(vmf.vma->vm_end) <= address) {
>>> + trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> - if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
>>> + if (!arch_vma_access_permitted(vmf.vma, flags & FAULT_FLAG_WRITE,
>>> flags & FAULT_FLAG_INSTRUCTION,
>>> - flags & FAULT_FLAG_REMOTE)) {
>>> - trace_spf_vma_access(_RET_IP_, vma, address);
>>> - ret = VM_FAULT_SIGSEGV;
>>> - goto out_put;
>>> - }
>>> + flags & FAULT_FLAG_REMOTE))
>>> + goto out_segv;
>>>
>>> /* This is one is required to check that the VMA has write access set */
>>> if (flags & FAULT_FLAG_WRITE) {
>>> - if (unlikely(!(vmf.vma_flags & VM_WRITE))) {
>>> - trace_spf_vma_access(_RET_IP_, vma, address);
>>> - ret = VM_FAULT_SIGSEGV;
>>> - goto out_put;
>>> - }
>>> - } else if (unlikely(!(vmf.vma_flags & (VM_READ|VM_EXEC|VM_WRITE)))) {
>>> - trace_spf_vma_access(_RET_IP_, vma, address);
>>> - ret = VM_FAULT_SIGSEGV;
>>> - goto out_put;
>>> - }
>>> + if (unlikely(!(vmf.vma_flags & VM_WRITE)))
>>> + goto out_segv;
>>> + } else if (unlikely(!(vmf.vma_flags & (VM_READ|VM_EXEC|VM_WRITE))))
>>> + goto out_segv;
>>>
>>> #ifdef CONFIG_NUMA
>>> /*
>>> * MPOL_INTERLEAVE implies additional check in mpol_misplaced() which
>>> * are not compatible with the speculative page fault processing.
>>> */
>>> - pol = __get_vma_policy(vma, address);
>>> + pol = __get_vma_policy(vmf.vma, address);
>>> if (!pol)
>>> pol = get_task_policy(current);
>>> if (pol && pol->mode == MPOL_INTERLEAVE) {
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>> #endif
>>>
>>> @@ -4479,9 +4480,8 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> vmf.pte = NULL;
>>> }
>>>
>>> - vmf.vma = vma;
>>> - vmf.pgoff = linear_page_index(vma, address);
>>> - vmf.gfp_mask = __get_fault_gfp_mask(vma);
>>> + vmf.pgoff = linear_page_index(vmf.vma, address);
>>> + vmf.gfp_mask = __get_fault_gfp_mask(vmf.vma);
>>> vmf.sequence = seq;
>>> vmf.flags = flags;
>>>
>>> @@ -4491,16 +4491,22 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> * We need to re-validate the VMA after checking the bounds, otherwise
>>> * we might have a false positive on the bounds.
>>> */
>>> - if (read_seqcount_retry(&vma->vm_sequence, seq)) {
>>> - trace_spf_vma_changed(_RET_IP_, vma, address);
>>> - goto out_put;
>>> + if (read_seqcount_retry(&vmf.vma->vm_sequence, seq)) {
>>> + trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
>>> + return ret;
>>> }
>>>
>>> mem_cgroup_oom_enable();
>>> ret = handle_pte_fault(&vmf);
>>> mem_cgroup_oom_disable();
>>>
>>> - put_vma(vma);
>>> + /*
>>> + * If there is no need to retry, don't return the vma to the caller.
>>> + */
>>> + if (!(ret & VM_FAULT_RETRY)) {
>>> + put_vma(vmf.vma);
>>> + *vma = NULL;
>>> + }
>>>
>>> /*
>>> * The task may have entered a memcg OOM situation but
>>> @@ -4513,9 +4519,35 @@ int handle_speculative_fault(struct mm_struct *mm, unsigned long address,
>>> return ret;
>>>
>>> out_walk:
>>> - trace_spf_vma_notsup(_RET_IP_, vma, address);
>>> + trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
>>> local_irq_enable();
>>> -out_put:
>>> + return ret;
>>> +
>>> +out_segv:
>>> + trace_spf_vma_access(_RET_IP_, vmf.vma, address);
>>> + /*
>>> + * We don't return VM_FAULT_RETRY so the caller is not expected to
>>> + * retrieve the fetched VMA.
>>> + */
>>> + put_vma(vmf.vma);
>>> + *vma = NULL;
>>> + return VM_FAULT_SIGSEGV;
>>> +}
>>> +
>>> +/*
>>> + * This is used to know if the vma fetch in the speculative page fault handler
>>> + * is still valid when trying the regular fault path while holding the
>>> + * mmap_sem.
>>> + * The call to put_vma(vma) must be made after checking the vma's fields, as
>>> + * the vma may be freed by put_vma(). In such a case it is expected that false
>>> + * is returned.
>>> + */
>>> +bool can_reuse_spf_vma(struct vm_area_struct *vma, unsigned long address)
>>> +{
>>> + bool ret;
>>> +
>>> + ret = !RB_EMPTY_NODE(&vma->vm_rb) &&
>>> + vma->vm_start <= address && address < vma->vm_end;
>>> put_vma(vma);
>>> return ret;
>>> }
>>> --
>>> 2.7.4
>>>
>
^ permalink raw reply
* linux-next: build failure after merge of the powerpc tree
From: Stephen Rothwell @ 2018-03-29 7:43 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, PowerPC
Cc: Linux-Next Mailing List, Linux Kernel Mailing List
[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]
Hi all,
After merging the powerpc tree, today's linux-next build (powerpc64
allnoconfig) failed like this:
WARNING: vmlinux.o(.text+0x12e34): Section mismatch in reference from the function .setup_rfi_flush() to the function .init.text:.ppc64_bolted_size()
The function .setup_rfi_flush() references
the function __init .ppc64_bolted_size().
This is often because .setup_rfi_flush lacks a __init
annotation or the annotation of .ppc64_bolted_size is wrong.
WARNING: vmlinux.o(.text+0x12e64): Section mismatch in reference from the function .setup_rfi_flush() to the function .init.text:.memblock_alloc_base()
The function .setup_rfi_flush() references
the function __init .memblock_alloc_base().
This is often because .setup_rfi_flush lacks a __init
annotation or the annotation of .memblock_alloc_base is wrong.
FATAL: modpost: Section mismatches detected.
Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
Caused by commit
abf110f3e1ce ("powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again")
I have left it broken for now.
--
Cheers,
Stephen Rothwell
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH V2] powerpc/fscr: Enable interrupts earlier before calling get_user()
From: Anshuman Khandual @ 2018-03-29 6:23 UTC (permalink / raw)
To: linuxppc-dev
The function get_user() can sleep while trying to fetch instruction
from user address space and causes the following warning from the
scheduler.
BUG: sleeping function called from invalid context
Though interrupts get enabled back but it happens bit later after
get_user() is called. This change moves enabling these interrupts
earlier covering the function get_user(). While at this, lets check
for kernel mode and crash as this interrupt should not have been
triggered from the kernel context.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
Changes in V2:
- Moved facility string detection earlier in the function
- Used pr_emerg() and die() instead of BUG_ON() if kernel context
- Removed redundant user_mode() check at the end
arch/powerpc/kernel/traps.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1e48d15..317593d 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1612,6 +1612,22 @@ void facility_unavailable_exception(struct pt_regs *regs)
value = mfspr(SPRN_FSCR);
status = value >> 56;
+ if ((hv || status >= 2) &&
+ (status < ARRAY_SIZE(facility_strings)) &&
+ facility_strings[status])
+ facility = facility_strings[status];
+
+ /* We should not have taken this interrupt in kernel */
+ if (!user_mode(regs)) {
+ pr_emerg("Facility '%s' unavailable (%d) exception in kernel"
+ " mode at %lx\n", facility, status, regs->nip);
+ die("Unexpected facility unavailable exception", regs, SIGABRT);
+ }
+
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
if (status == FSCR_DSCR_LG) {
/*
* User is accessing the DSCR register using the problem
@@ -1678,25 +1694,11 @@ void facility_unavailable_exception(struct pt_regs *regs)
return;
}
- if ((hv || status >= 2) &&
- (status < ARRAY_SIZE(facility_strings)) &&
- facility_strings[status])
- facility = facility_strings[status];
-
- /* We restore the interrupt state now */
- if (!arch_irq_disabled_regs(regs))
- local_irq_enable();
-
pr_err_ratelimited("%sFacility '%s' unavailable (%d), exception at 0x%lx, MSR=%lx\n",
hv ? "Hypervisor " : "", facility, status, regs->nip, regs->msr);
out:
- if (user_mode(regs)) {
- _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
- return;
- }
-
- die("Unexpected facility unavailable exception", regs, SIGABRT);
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
#endif
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH 00/14] numa aware allocation for pacas, stacks, pagetables
From: Michael Ellerman @ 2018-03-29 6:18 UTC (permalink / raw)
To: Nicholas Piggin; +Cc: linuxppc-dev
In-Reply-To: <20180308120412.1cbe9ace@roar.ozlabs.ibm.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> On Wed, 07 Mar 2018 21:50:04 +1100
> Michael Ellerman <mpe@ellerman.id.au> wrote:
>> Nicholas Piggin <npiggin@gmail.com> writes:
>> > This series allows numa aware allocations for various early data
>> > structures for radix. Hash still has a bolted SLB limitation that
>> > prevents at least pacas and stacks from node-affine allocations.
>> >
>> > Fixed up a number of bugs, got pSeries working, added a couple more
>> > cases where page tables can be allocated node-local.=20=20
>>=20
>> Few problems in here:
>>=20
>> FAILURE kernel-build-linux =C2=BB powerpc,gcc_ubuntu_be,pmac32
>> arch/powerpc/kernel/prom.c:748:2: error: implicit declaration of funct=
ion 'allocate_paca_ptrs' [-Werror=3Dimplicit-function-declaration]
>>=20
>> FAILURE kernel-build-linux =C2=BB powerpc,gcc_ubuntu_le,powernv
>> arch/powerpc/include/asm/paca.h:49:33: error: 'struct paca_struct' has=
no member named 'lppaca_ptr'
>> arch/powerpc/include/asm/paca.h:49:33: error: 'struct paca_struct' has=
no member named 'lppaca_ptr'
>>=20
>> Did I miss a follow-up or something?
>
> Here's a patch that applies to "powerpc/64: defer paca allocation
> until memory topology is discovered". The first hunk fixes the ppc32
> issue, and the second hunk avoids freeing the cpu_to_phys_id array
> if the platform didn't allocate it. But I've just realized that
> should go into the previous patch (which is missing the
> memblock_free).
> --
...
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/set=
up-common.c
> index 56f7a2b793e0..2ba05acc2973 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -854,8 +854,10 @@ static void smp_setup_pacas(void)
> set_hard_smp_processor_id(cpu, cpu_to_phys_id[cpu]);
> }
>=20=20
> - memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32));
> - cpu_to_phys_id =3D NULL;
> + if (cpu_to_phys_id) {
> + memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32));
> + cpu_to_phys_id =3D NULL;
> + }
> }
> #endif
=20
Where did you want that?
cheers
^ permalink raw reply
* [PATCH] hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common()
From: Stewart Smith @ 2018-03-29 6:02 UTC (permalink / raw)
To: linuxppc-dev, benh, mpe; +Cc: Stewart Smith
time_init() will set up tb_ticks_per_usec based on reality.
time_init() is called *after* udbg_init_opal_common() during boot.
from arch/powerpc/kernel/time.c:
unsigned long tb_ticks_per_usec = 100; /* sane default */
Currently, all powernv systems have a timebase frequency of 512mhz
(512000000/1000000 == 0x200) - although there's nothing written
down anywhere that I can find saying that we couldn't make that
different based on the requirements in the ISA.
So, we've been (accidentally) thwacking the (currently) correct
(for powernv at least) value for tb_ticks_per_usec earlier than
we otherwise would have.
The "sane default" seems to be adequate for our purposes between
udbg_init_opal_common() and time_init() being called, and if it isn't,
then we should probably be setting it somewhere that isn't hvc_opal.c!
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
---
drivers/tty/hvc/hvc_opal.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 2ed07ca6389e..9645c0062a90 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -318,7 +318,6 @@ static void udbg_init_opal_common(void)
udbg_putc = udbg_opal_putc;
udbg_getc = udbg_opal_getc;
udbg_getc_poll = udbg_opal_getc_poll;
- tb_ticks_per_usec = 0x200; /* Make udelay not suck */
}
void __init hvc_opal_init_early(void)
--
2.14.3
^ permalink raw reply related
* [PATCH 4/5] powerpc/pm: add sleep and deep sleep on QorIQ SoCs
From: Ran Wang @ 2018-03-29 1:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Rob Herring, Mark Rutland, Scott Wood, Kumar Gala, Li Yang
Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, devicetree,
linux-arm-kernel, Ran Wang
In-Reply-To: <20180329013143.22527-1-ran.wang_1@nxp.com>
In sleep mode, the clocks of CPU core and unused IP blocks are turned
off (IP blocks allowed to wake up system will running).
Some QorIQ SoCs like MPC8536, P1022 and T104x, have deep sleep PM mode
in addtion to the sleep PM mode. While in deep sleep mode,
additionally, the power supply is removed from CPU core and most IP
blocks. Only the blocks needed to wake up the chip out of deep sleep
are ON.
This feature supports 32-bit and 36-bit address space.
The sleep mode is equal to the Standby state in Linux. The deep sleep
mode is equal to the Suspend-to-RAM state of Linux Power Management.
Command to enter sleep mode.
echo standby > /sys/power/state
Command to enter deep sleep mode.
echo mem > /sys/power/state
Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Xie Xiaobo <X.Xie@freescale.com>
Signed-off-by: Zhao Qiang <B45475@freescale.com>
Signed-off-by: Shengzhou Liu <Shengzhou.Liu@freescale.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
arch/powerpc/include/asm/cacheflush.h | 7 +
arch/powerpc/include/asm/fsl_pm.h | 31 +
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/fsl_booke_entry_mapping.S | 10 +
arch/powerpc/kernel/fsl_pm.c | 49 +
arch/powerpc/kernel/head_64.S | 2 +-
arch/powerpc/platforms/85xx/Kconfig | 6 +
arch/powerpc/platforms/85xx/Makefile | 2 +
arch/powerpc/platforms/85xx/deepsleep.c | 349 ++++++++
arch/powerpc/platforms/85xx/qoriq_pm.c | 223 +++++
arch/powerpc/platforms/85xx/sleep.S | 1192 +++++++++++++++++++++++++
arch/powerpc/platforms/86xx/Kconfig | 1 +
arch/powerpc/sysdev/fsl_pmc.c | 176 ++++-
arch/powerpc/sysdev/fsl_soc.c | 31 +
arch/powerpc/sysdev/fsl_soc.h | 18 +
15 files changed, 2078 insertions(+), 20 deletions(-)
create mode 100644 arch/powerpc/kernel/fsl_pm.c
create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
create mode 100644 arch/powerpc/platforms/85xx/sleep.S
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b77f036..a5411af 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -31,6 +31,13 @@
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+extern void __flush_disable_L1(void);
+#ifdef CONFIG_FSL_SOC_BOOKE
+extern void flush_dcache_L1(void);
+#else
+#define flush_dcache_L1() do { } while (0)
+#endif
+
extern void flush_icache_range(unsigned long, unsigned long);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
index 47df55e..510e5d2 100644
--- a/arch/powerpc/include/asm/fsl_pm.h
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -11,6 +11,9 @@
#ifndef __PPC_FSL_PM_H
#define __PPC_FSL_PM_H
+#ifndef __ASSEMBLY__
+#include <linux/suspend.h>
+
#define E500_PM_PH10 1
#define E500_PM_PH15 2
#define E500_PM_PH20 3
@@ -46,6 +49,34 @@ struct fsl_pm_ops {
extern const struct fsl_pm_ops *qoriq_pm_ops;
+struct fsm_reg_vals {
+ u32 offset;
+ u32 value;
+};
+
+void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val);
+void fsl_epu_setup_default(void __iomem *epu_base);
+void fsl_npc_setup_default(void __iomem *npc_base);
+void fsl_fsm_clean(void __iomem *base, struct fsm_reg_vals *val);
+void fsl_epu_clean_default(void __iomem *epu_base);
+
+extern int fsl_dp_iomap(void);
+extern void fsl_dp_iounmap(void);
+
+extern int fsl_enter_epu_deepsleep(void);
+extern void fsl_dp_enter_low(void __iomem *ccsr_base, void __iomem *dcsr_base,
+ void __iomem *pld_base, int pld_flag);
+extern void fsl_booke_deep_sleep_resume(void);
+
int __init fsl_rcpm_init(void);
+void set_pm_suspend_state(suspend_state_t state);
+suspend_state_t pm_suspend_state(void);
+
+void fsl_set_power_except(struct device *dev, int on);
+#endif /* __ASSEMBLY__ */
+
+#define T1040QDS_TETRA_FLAG 1
+#define T104xRDB_CPLD_FLAG 2
+
#endif /* __PPC_FSL_PM_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1b6bc7f..f191269 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_FA_DUMP) += fadump.o
+obj-$(CONFIG_FSL_SOC) += fsl_pm.o
ifeq ($(CONFIG_PPC32),y)
obj-$(CONFIG_E500) += idle_e500.o
endif
diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
index ea06528..0e3484d 100644
--- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
+++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
@@ -174,6 +174,10 @@ skpinv: addi r6,r6,1 /* Increment */
lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@l
mtspr SPRN_MAS2,r6
+#ifdef ENTRY_DEEPSLEEP_SETUP
+ LOAD_REG_IMMEDIATE(r8, MEMORY_START)
+ ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
+#endif
mtspr SPRN_MAS3,r8
tlbwe
@@ -216,12 +220,18 @@ next_tlb_setup:
#error You need to specify the mapping or not use this at all.
#endif
+#ifdef ENTRY_DEEPSLEEP_SETUP
+ LOAD_REG_ADDR(r6, 2f)
+ mfmsr r7
+ rlwinm r7,r7,0,~(MSR_IS|MSR_DS)
+#else
lis r7,MSR_KERNEL@h
ori r7,r7,MSR_KERNEL@l
bl 1f /* Find our address */
1: mflr r9
rlwimi r6,r9,0,20,31
addi r6,r6,(2f - 1b)
+#endif
mtspr SPRN_SRR0,r6
mtspr SPRN_SRR1,r7
rfi /* start execution out of TLB1[0] entry */
diff --git a/arch/powerpc/kernel/fsl_pm.c b/arch/powerpc/kernel/fsl_pm.c
new file mode 100644
index 0000000..f328c4e
--- /dev/null
+++ b/arch/powerpc/kernel/fsl_pm.c
@@ -0,0 +1,49 @@
+/*
+ * Freescale General Power Management Implementation
+ *
+ * Copyright 2018 NXP
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <linux/suspend.h>
+#include <asm/fsl_pm.h>
+
+static suspend_state_t pm_state;
+
+void set_pm_suspend_state(suspend_state_t state)
+{
+ pm_state = state;
+}
+
+suspend_state_t pm_suspend_state(void)
+{
+ return pm_state;
+}
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index a61151a..3f0b397 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -863,7 +863,7 @@ _GLOBAL(start_secondary_resume)
/*
* This subroutine clobbers r11 and r12
*/
-enable_64b_mode:
+_GLOBAL(enable_64b_mode)
mfmsr r11 /* grab the current MSR */
#ifdef CONFIG_PPC_BOOK3E
oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 68920d4..b2fbefe 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -10,6 +10,8 @@ menuconfig FSL_SOC_BOOKE
select SERIAL_8250_EXTENDED if SERIAL_8250
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
select FSL_CORENET_RCPM if PPC_E500MC
+ select FSL_QORIQ_PM if SUSPEND && PPC_E500MC
+ select FSL_PMC if SUSPEND && !PPC_E500MC
default y
if FSL_SOC_BOOKE
@@ -292,3 +294,7 @@ endif # FSL_SOC_BOOKE
config TQM85xx
bool
+
+config FSL_QORIQ_PM
+ bool
+ select FSL_SLEEP_FSM
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index d1dd0dc..8e9f369 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,9 @@
# Makefile for the PowerPC 85xx linux kernel.
#
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SUSPEND) += sleep.o
obj-$(CONFIG_FSL_PMC) += mpc85xx_pm_ops.o
+obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o deepsleep.o
obj-y += common.o
diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c
new file mode 100644
index 0000000..183d55c
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -0,0 +1,349 @@
+/*
+ * Support deep sleep feature for T104x
+ *
+ * Copyright 2018 NXP
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/machdep.h>
+#include <asm/fsl_pm.h>
+
+#define SIZE_1MB 0x100000
+#define SIZE_2MB 0x200000
+
+#define CPC_CPCHDBCR0 0x10f00
+#define CPC_CPCHDBCR0_SPEC_DIS 0x08000000
+
+#define CCSR_SCFG_DPSLPCR 0xfc000
+#define CCSR_SCFG_DPSLPCR_WDRR_EN 0x1
+#define CCSR_SCFG_SPARECR2 0xfc504
+#define CCSR_SCFG_SPARECR3 0xfc508
+
+#define CCSR_GPIO1_GPDIR 0x130000
+#define CCSR_GPIO1_GPODR 0x130004
+#define CCSR_GPIO1_GPDAT 0x130008
+#define CCSR_GPIO1_GPDIR_29 0x4
+
+#define RCPM_BLOCK_OFFSET 0x00022000
+#define EPU_BLOCK_OFFSET 0x00000000
+#define NPC_BLOCK_OFFSET 0x00001000
+
+#define CSTTACR0 0xb00
+#define CG1CR0 0x31c
+
+#define CCSR_LAW_BASE 0xC00
+#define DCFG_BRR 0xE4 /* boot release register */
+#define LCC_BSTRH 0x20 /* Boot space translation register high */
+#define LCC_BSTRL 0x24 /* Boot space translation register low */
+#define LCC_BSTAR 0x28 /* Boot space translation attribute register */
+#define RCPM_PCTBENR 0x1A0 /* Physical Core Timebase Enable Register */
+#define RCPM_BASE 0xE2000
+#define DCFG_BASE 0xE0000
+
+/* 128 bytes buffer for restoring data broke by DDR training initialization */
+#define DDR_BUF_SIZE 128
+static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
+
+static void *dcsr_base, *ccsr_base, *pld_base;
+static int pld_flag;
+
+/* for law */
+struct fsl_law {
+ u32 lawbarh; /* LAWn base address high */
+ u32 lawbarl; /* LAWn base address low */
+ u32 lawar; /* LAWn attributes */
+ u32 reserved;
+};
+
+struct fsl_law *saved_law;
+static u32 num_laws;
+
+/* for nonboot cpu */
+struct fsl_bstr {
+ u32 bstrh;
+ u32 bstrl;
+ u32 bstar;
+ u32 cpu_mask;
+};
+static struct fsl_bstr saved_bstr;
+
+int fsl_dp_iomap(void)
+{
+ struct device_node *np;
+ int ret = 0;
+ phys_addr_t ccsr_phy_addr, dcsr_phy_addr;
+
+ saved_law = NULL;
+ ccsr_base = NULL;
+ dcsr_base = NULL;
+ pld_base = NULL;
+
+ ccsr_phy_addr = get_immrbase();
+ if (ccsr_phy_addr == -1) {
+ pr_err("%s: Can't get the address of CCSR\n", __func__);
+ ret = -EINVAL;
+ goto ccsr_err;
+ }
+ ccsr_base = ioremap(ccsr_phy_addr, SIZE_2MB);
+ if (!ccsr_base) {
+ ret = -ENOMEM;
+ goto ccsr_err;
+ }
+
+ dcsr_phy_addr = get_dcsrbase();
+ if (dcsr_phy_addr == -1) {
+ pr_err("%s: Can't get the address of DCSR\n", __func__);
+ ret = -EINVAL;
+ goto dcsr_err;
+ }
+ dcsr_base = ioremap(dcsr_phy_addr, SIZE_1MB);
+ if (!dcsr_base) {
+ ret = -ENOMEM;
+ goto dcsr_err;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,tetra-fpga");
+ if (np) {
+ pld_flag = T1040QDS_TETRA_FLAG;
+ } else {
+ np = of_find_compatible_node(NULL, NULL, "fsl,deepsleep-cpld");
+ if (np) {
+ pld_flag = T104xRDB_CPLD_FLAG;
+ } else {
+ pr_err("%s: Can't find the FPGA/CPLD node\n",
+ __func__);
+ ret = -EINVAL;
+ goto pld_err;
+ }
+ }
+ pld_base = of_iomap(np, 0);
+ of_node_put(np);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
+ if (!np) {
+ pr_err("%s: Can't find the node of \"law\"\n", __func__);
+ ret = -EINVAL;
+ goto alloc_err;
+ }
+ ret = of_property_read_u32(np, "fsl,num-laws", &num_laws);
+ if (ret) {
+ ret = -EINVAL;
+ goto alloc_err;
+ }
+
+ saved_law = kzalloc(sizeof(*saved_law) * num_laws, GFP_KERNEL);
+ if (!saved_law) {
+ ret = -ENOMEM;
+ goto alloc_err;
+ }
+ of_node_put(np);
+
+ return 0;
+
+alloc_err:
+ iounmap(pld_base);
+ pld_base = NULL;
+pld_err:
+ iounmap(dcsr_base);
+ dcsr_base = NULL;
+dcsr_err:
+ iounmap(ccsr_base);
+ ccsr_base = NULL;
+ccsr_err:
+ return ret;
+}
+
+void fsl_dp_iounmap(void)
+{
+ if (dcsr_base) {
+ iounmap(dcsr_base);
+ dcsr_base = NULL;
+ }
+
+ if (ccsr_base) {
+ iounmap(ccsr_base);
+ ccsr_base = NULL;
+ }
+
+ if (pld_base) {
+ iounmap(pld_base);
+ pld_base = NULL;
+ }
+
+ kfree(saved_law);
+ saved_law = NULL;
+}
+
+static void fsl_dp_ddr_save(void *ccsr_base)
+{
+ u32 ddr_buff_addr;
+
+ /*
+ * DDR training initialization will break 128 bytes at the beginning
+ * of DDR, therefore, save them so that the bootloader will restore
+ * them. Assume that DDR is mapped to the address space started with
+ * CONFIG_PAGE_OFFSET.
+ */
+ memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE);
+
+ /* assume ddr_buff is in the physical address space of 4GB */
+ ddr_buff_addr = (u32)(__pa(ddr_buff) & 0xffffffff);
+
+ /*
+ * the bootloader will restore the first 128 bytes of DDR from
+ * the location indicated by the register SPARECR3
+ */
+ out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
+}
+
+static void fsl_dp_mp_save(void *ccsr)
+{
+ struct fsl_bstr *dst = &saved_bstr;
+
+ dst->bstrh = in_be32(ccsr + LCC_BSTRH);
+ dst->bstrl = in_be32(ccsr + LCC_BSTRL);
+ dst->bstar = in_be32(ccsr + LCC_BSTAR);
+ dst->cpu_mask = in_be32(ccsr + DCFG_BASE + DCFG_BRR);
+}
+
+static void fsl_dp_mp_restore(void *ccsr)
+{
+ struct fsl_bstr *src = &saved_bstr;
+
+ out_be32(ccsr + LCC_BSTRH, src->bstrh);
+ out_be32(ccsr + LCC_BSTRL, src->bstrl);
+ out_be32(ccsr + LCC_BSTAR, src->bstar);
+
+ /* release the nonboot cpus */
+ out_be32(ccsr + DCFG_BASE + DCFG_BRR, src->cpu_mask);
+
+ /* enable the time base */
+ out_be32(ccsr + RCPM_BASE + RCPM_PCTBENR, src->cpu_mask);
+ /* read back to sync write */
+ in_be32(ccsr + RCPM_BASE + RCPM_PCTBENR);
+}
+
+static void fsl_dp_law_save(void *ccsr)
+{
+ int i;
+ struct fsl_law *dst = saved_law;
+ struct fsl_law *src = (void *)(ccsr + CCSR_LAW_BASE);
+
+ for (i = 0; i < num_laws; i++) {
+ dst->lawbarh = in_be32(&src->lawbarh);
+ dst->lawbarl = in_be32(&src->lawbarl);
+ dst->lawar = in_be32(&src->lawar);
+ dst++;
+ src++;
+ }
+}
+
+static void fsl_dp_law_restore(void *ccsr)
+{
+ int i;
+ struct fsl_law *src = saved_law;
+ struct fsl_law *dst = (void *)(ccsr + CCSR_LAW_BASE);
+
+ for (i = 0; i < num_laws - 1; i++) {
+ out_be32(&dst->lawar, 0);
+ out_be32(&dst->lawbarl, src->lawbarl);
+ out_be32(&dst->lawbarh, src->lawbarh);
+ out_be32(&dst->lawar, src->lawar);
+
+ /* Read back so that we sync the writes */
+ in_be32(&dst->lawar);
+ src++;
+ dst++;
+ }
+}
+
+static void fsl_dp_set_resume_pointer(void *ccsr_base)
+{
+ u32 resume_addr;
+
+ /* the bootloader will finally jump to this address to return kernel */
+#ifdef CONFIG_PPC32
+ resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
+#else
+ resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
+ & 0xffffffff);
+#endif
+
+ /* use the register SPARECR2 to save the resume address */
+ out_be32(ccsr_base + CCSR_SCFG_SPARECR2, resume_addr);
+
+}
+
+int fsl_enter_epu_deepsleep(void)
+{
+ fsl_dp_ddr_save(ccsr_base);
+
+ fsl_dp_set_resume_pointer(ccsr_base);
+
+ fsl_dp_mp_save(ccsr_base);
+ fsl_dp_law_save(ccsr_base);
+ /* enable Warm Device Reset request. */
+ setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+ /* set GPIO1_29 as an output pin (not open-drain), and output 0 */
+ clrbits32(ccsr_base + CCSR_GPIO1_GPDAT, CCSR_GPIO1_GPDIR_29);
+ clrbits32(ccsr_base + CCSR_GPIO1_GPODR, CCSR_GPIO1_GPDIR_29);
+ setbits32(ccsr_base + CCSR_GPIO1_GPDIR, CCSR_GPIO1_GPDIR_29);
+
+ /*
+ * Disable CPC speculation to avoid deep sleep hang, especially
+ * in secure boot mode. This bit will be cleared automatically
+ * when resuming from deep sleep.
+ */
+ setbits32(ccsr_base + CPC_CPCHDBCR0, CPC_CPCHDBCR0_SPEC_DIS);
+
+ fsl_epu_setup_default(dcsr_base + EPU_BLOCK_OFFSET);
+ fsl_npc_setup_default(dcsr_base + NPC_BLOCK_OFFSET);
+ out_be32(dcsr_base + RCPM_BLOCK_OFFSET + CSTTACR0, 0x00001001);
+ out_be32(dcsr_base + RCPM_BLOCK_OFFSET + CG1CR0, 0x00000001);
+
+ fsl_dp_enter_low(ccsr_base, dcsr_base, pld_base, pld_flag);
+
+ fsl_dp_law_restore(ccsr_base);
+ fsl_dp_mp_restore(ccsr_base);
+
+ /* disable Warm Device Reset request */
+ clrbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+ fsl_epu_clean_default(dcsr_base + EPU_BLOCK_OFFSET);
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
new file mode 100644
index 0000000..0705f05
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -0,0 +1,223 @@
+/*
+ * Support Power Management feature
+ *
+ * Copyright 2018 NXP
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+#include <linux/usb.h>
+
+#include <asm/fsl_pm.h>
+
+#define FSL_SLEEP 0x1
+#define FSL_DEEP_SLEEP 0x2
+
+int (*fsl_enter_deepsleep)(void);
+
+/* specify the sleep state of the present platform */
+unsigned int sleep_pm_state;
+/* supported sleep modes by the present platform */
+static unsigned int sleep_modes;
+
+/**
+ * fsl_set_power_except - set which IP block is not powerdown when sleep,
+ * such as MAC, USB, etc.
+ *
+ * @dev: a pointer to the struct device
+ * @on: if 1, do not power down; if 0, power down.
+ */
+void fsl_set_power_except(struct device *dev, int on)
+ {
+ u32 value[2];
+ u32 pw_mask;
+ const phandle *phandle_prop;
+ struct device_node *mac_node;
+ int ret;
+
+ if (dev && !strncmp(dev->bus->name, "usb", 3)) {
+ struct usb_device *udev = container_of(dev,
+ struct usb_device, dev);
+ struct device *controller = udev->bus->controller;
+
+ ret = of_property_read_u32_array(controller->parent->of_node,
+ "sleep", value, 2);
+ } else
+ ret = of_property_read_u32_array(dev->of_node, "sleep",
+ value, 2);
+
+ if (ret) {
+ /* search fman mac node */
+ phandle_prop = of_get_property(dev->of_node, "fsl,fman-mac",
+ NULL);
+ if (phandle_prop == NULL)
+ goto err;
+
+ mac_node = of_find_node_by_phandle(*phandle_prop);
+ ret = of_property_read_u32_array(mac_node, "sleep", value, 2);
+ of_node_put(mac_node);
+ if (ret)
+ goto err;
+ }
+ /* get the second value, it is a mask */
+ pw_mask = value[1];
+ qoriq_pm_ops->set_ip_power(on, pw_mask);
+ return;
+
+err:
+ dev_err(dev, "Can not set wakeup sources\n");
+ return;
+}
+EXPORT_SYMBOL_GPL(fsl_set_power_except);
+
+void qoriq_set_wakeup_source(struct device *dev, void *enable)
+{
+ if (!device_may_wakeup(dev))
+ return;
+
+ fsl_set_power_except(dev, *((int *)enable));
+}
+
+static int qoriq_suspend_enter(suspend_state_t state)
+{
+ int ret = 0;
+ int cpu;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+
+ if (cur_cpu_spec->cpu_flush_caches)
+ cur_cpu_spec->cpu_flush_caches();
+
+ ret = qoriq_pm_ops->plat_enter_sleep();
+
+ break;
+
+ case PM_SUSPEND_MEM:
+
+ cpu = smp_processor_id();
+ qoriq_pm_ops->irq_mask(cpu);
+
+ ret = fsl_enter_deepsleep();
+
+ qoriq_pm_ops->irq_unmask(cpu);
+
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
+
+ return ret;
+}
+
+static int qoriq_suspend_valid(suspend_state_t state)
+{
+ set_pm_suspend_state(state);
+
+ if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
+ return 1;
+
+ if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
+ return 1;
+
+ set_pm_suspend_state(PM_SUSPEND_ON);
+ return 0;
+}
+
+static int qoriq_suspend_begin(suspend_state_t state)
+{
+ const int enable = 1;
+
+ dpm_for_each_dev((void *)&enable, qoriq_set_wakeup_source);
+
+ if (state == PM_SUSPEND_MEM)
+ return fsl_dp_iomap();
+
+ return 0;
+}
+
+static void qoriq_suspend_end(void)
+{
+ const int enable = 0;
+
+ dpm_for_each_dev((void *)&enable, qoriq_set_wakeup_source);
+
+ set_pm_suspend_state(PM_SUSPEND_ON);
+ fsl_dp_iounmap();
+}
+
+static const struct platform_suspend_ops qoriq_suspend_ops = {
+ .valid = qoriq_suspend_valid,
+ .enter = qoriq_suspend_enter,
+ .begin = qoriq_suspend_begin,
+ .end = qoriq_suspend_end,
+};
+
+static const struct of_device_id deepsleep_matches[] = {
+ {
+ .compatible = "fsl,t1040-rcpm",
+ },
+ {
+ .compatible = "fsl,t1024-rcpm",
+ },
+ {
+ .compatible = "fsl,t1023-rcpm",
+ },
+ {},
+};
+
+static int __init qoriq_suspend_init(void)
+{
+ struct device_node *np;
+
+ sleep_modes = FSL_SLEEP;
+ sleep_pm_state = PLAT_PM_SLEEP;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
+ if (np)
+ sleep_pm_state = PLAT_PM_LPM20;
+
+ np = of_find_matching_node_and_match(NULL, deepsleep_matches, NULL);
+ if (np) {
+ fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
+ sleep_modes |= FSL_DEEP_SLEEP;
+ }
+
+ suspend_set_ops(&qoriq_suspend_ops);
+ set_pm_suspend_state(PM_SUSPEND_ON);
+
+ return 0;
+}
+arch_initcall(qoriq_suspend_init);
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..b7942ed
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,1192 @@
+/*
+ * Enter and leave deep sleep/sleep state
+ *
+ * Copyright 2018 NXP
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <asm/fsl_pm.h>
+#include <asm/mmu.h>
+
+/*
+ * the number of bytes occupied by one register
+ * the value of 8 is compatible with both 32-bit and 64-bit registers
+ */
+#define STRIDE_SIZE 8
+
+/* GPR0 - GPR31 */
+#define BOOKE_GPR0_OFF 0x0000
+#define BOOKE_GPR_COUNT 32
+/* IVOR0 - IVOR42 */
+#define BOOKE_IVOR0_OFF (BOOKE_GPR0_OFF + BOOKE_GPR_COUNT * STRIDE_SIZE)
+#define BOOKE_IVOR_COUNT 43
+/* SPRG0 - SPRG9 */
+#define BOOKE_SPRG0_OFF (BOOKE_IVOR0_OFF + BOOKE_IVOR_COUNT * STRIDE_SIZE)
+#define BOOKE_SPRG_COUNT 10
+/* IVPR */
+#define BOOKE_IVPR_OFF (BOOKE_SPRG0_OFF + BOOKE_SPRG_COUNT * STRIDE_SIZE)
+
+#define BOOKE_LR_OFF (BOOKE_IVPR_OFF + STRIDE_SIZE)
+#define BOOKE_MSR_OFF (BOOKE_LR_OFF + STRIDE_SIZE)
+#define BOOKE_TBU_OFF (BOOKE_MSR_OFF + STRIDE_SIZE)
+#define BOOKE_TBL_OFF (BOOKE_TBU_OFF + STRIDE_SIZE)
+#define BOOKE_EPCR_OFF (BOOKE_TBL_OFF + STRIDE_SIZE)
+#define BOOKE_HID0_OFF (BOOKE_EPCR_OFF + STRIDE_SIZE)
+#define BOOKE_PIR_OFF (BOOKE_HID0_OFF + STRIDE_SIZE)
+#define BOOKE_PID0_OFF (BOOKE_PIR_OFF + STRIDE_SIZE)
+#define BOOKE_BUCSR_OFF (BOOKE_PID0_OFF + STRIDE_SIZE)
+
+#define BUFFER_SIZE (BOOKE_BUCSR_OFF + STRIDE_SIZE)
+
+#undef SAVE_GPR
+#define SAVE_GPR(gpr, offset) \
+ PPC_STL gpr, offset(r10)
+
+#define RESTORE_GPR(gpr, offset) \
+ PPC_LL gpr, offset(r10)
+
+#define SAVE_SPR(spr, offset) \
+ mfspr r0, spr ;\
+ PPC_STL r0, offset(r10)
+
+#define RESTORE_SPR(spr, offset) \
+ PPC_LL r0, offset(r10) ;\
+ mtspr spr, r0
+
+#define SAVE_ALL_GPR \
+ SAVE_GPR(r1, BOOKE_GPR0_OFF + STRIDE_SIZE * 1) ;\
+ SAVE_GPR(r2, BOOKE_GPR0_OFF + STRIDE_SIZE * 2) ;\
+ SAVE_GPR(r13, BOOKE_GPR0_OFF + STRIDE_SIZE * 13) ;\
+ SAVE_GPR(r14, BOOKE_GPR0_OFF + STRIDE_SIZE * 14) ;\
+ SAVE_GPR(r15, BOOKE_GPR0_OFF + STRIDE_SIZE * 15) ;\
+ SAVE_GPR(r16, BOOKE_GPR0_OFF + STRIDE_SIZE * 16) ;\
+ SAVE_GPR(r17, BOOKE_GPR0_OFF + STRIDE_SIZE * 17) ;\
+ SAVE_GPR(r18, BOOKE_GPR0_OFF + STRIDE_SIZE * 18) ;\
+ SAVE_GPR(r19, BOOKE_GPR0_OFF + STRIDE_SIZE * 19) ;\
+ SAVE_GPR(r20, BOOKE_GPR0_OFF + STRIDE_SIZE * 20) ;\
+ SAVE_GPR(r21, BOOKE_GPR0_OFF + STRIDE_SIZE * 21) ;\
+ SAVE_GPR(r22, BOOKE_GPR0_OFF + STRIDE_SIZE * 22) ;\
+ SAVE_GPR(r23, BOOKE_GPR0_OFF + STRIDE_SIZE * 23) ;\
+ SAVE_GPR(r24, BOOKE_GPR0_OFF + STRIDE_SIZE * 24) ;\
+ SAVE_GPR(r25, BOOKE_GPR0_OFF + STRIDE_SIZE * 25) ;\
+ SAVE_GPR(r26, BOOKE_GPR0_OFF + STRIDE_SIZE * 26) ;\
+ SAVE_GPR(r27, BOOKE_GPR0_OFF + STRIDE_SIZE * 27) ;\
+ SAVE_GPR(r28, BOOKE_GPR0_OFF + STRIDE_SIZE * 28) ;\
+ SAVE_GPR(r29, BOOKE_GPR0_OFF + STRIDE_SIZE * 29) ;\
+ SAVE_GPR(r30, BOOKE_GPR0_OFF + STRIDE_SIZE * 30) ;\
+ SAVE_GPR(r31, BOOKE_GPR0_OFF + STRIDE_SIZE * 31)
+
+#define RESTORE_ALL_GPR \
+ RESTORE_GPR(r1, BOOKE_GPR0_OFF + STRIDE_SIZE * 1) ;\
+ RESTORE_GPR(r2, BOOKE_GPR0_OFF + STRIDE_SIZE * 2) ;\
+ RESTORE_GPR(r13, BOOKE_GPR0_OFF + STRIDE_SIZE * 13) ;\
+ RESTORE_GPR(r14, BOOKE_GPR0_OFF + STRIDE_SIZE * 14) ;\
+ RESTORE_GPR(r15, BOOKE_GPR0_OFF + STRIDE_SIZE * 15) ;\
+ RESTORE_GPR(r16, BOOKE_GPR0_OFF + STRIDE_SIZE * 16) ;\
+ RESTORE_GPR(r17, BOOKE_GPR0_OFF + STRIDE_SIZE * 17) ;\
+ RESTORE_GPR(r18, BOOKE_GPR0_OFF + STRIDE_SIZE * 18) ;\
+ RESTORE_GPR(r19, BOOKE_GPR0_OFF + STRIDE_SIZE * 19) ;\
+ RESTORE_GPR(r20, BOOKE_GPR0_OFF + STRIDE_SIZE * 20) ;\
+ RESTORE_GPR(r21, BOOKE_GPR0_OFF + STRIDE_SIZE * 21) ;\
+ RESTORE_GPR(r22, BOOKE_GPR0_OFF + STRIDE_SIZE * 22) ;\
+ RESTORE_GPR(r23, BOOKE_GPR0_OFF + STRIDE_SIZE * 23) ;\
+ RESTORE_GPR(r24, BOOKE_GPR0_OFF + STRIDE_SIZE * 24) ;\
+ RESTORE_GPR(r25, BOOKE_GPR0_OFF + STRIDE_SIZE * 25) ;\
+ RESTORE_GPR(r26, BOOKE_GPR0_OFF + STRIDE_SIZE * 26) ;\
+ RESTORE_GPR(r27, BOOKE_GPR0_OFF + STRIDE_SIZE * 27) ;\
+ RESTORE_GPR(r28, BOOKE_GPR0_OFF + STRIDE_SIZE * 28) ;\
+ RESTORE_GPR(r29, BOOKE_GPR0_OFF + STRIDE_SIZE * 29) ;\
+ RESTORE_GPR(r30, BOOKE_GPR0_OFF + STRIDE_SIZE * 30) ;\
+ RESTORE_GPR(r31, BOOKE_GPR0_OFF + STRIDE_SIZE * 31)
+
+#define SAVE_ALL_SPRG \
+ SAVE_SPR(SPRN_SPRG0, BOOKE_SPRG0_OFF + STRIDE_SIZE * 0) ;\
+ SAVE_SPR(SPRN_SPRG1, BOOKE_SPRG0_OFF + STRIDE_SIZE * 1) ;\
+ SAVE_SPR(SPRN_SPRG2, BOOKE_SPRG0_OFF + STRIDE_SIZE * 2) ;\
+ SAVE_SPR(SPRN_SPRG3, BOOKE_SPRG0_OFF + STRIDE_SIZE * 3) ;\
+ SAVE_SPR(SPRN_SPRG4, BOOKE_SPRG0_OFF + STRIDE_SIZE * 4) ;\
+ SAVE_SPR(SPRN_SPRG5, BOOKE_SPRG0_OFF + STRIDE_SIZE * 5) ;\
+ SAVE_SPR(SPRN_SPRG6, BOOKE_SPRG0_OFF + STRIDE_SIZE * 6) ;\
+ SAVE_SPR(SPRN_SPRG7, BOOKE_SPRG0_OFF + STRIDE_SIZE * 7) ;\
+ SAVE_SPR(SPRN_SPRG8, BOOKE_SPRG0_OFF + STRIDE_SIZE * 8) ;\
+ SAVE_SPR(SPRN_SPRG9, BOOKE_SPRG0_OFF + STRIDE_SIZE * 9)
+
+#define RESTORE_ALL_SPRG \
+ RESTORE_SPR(SPRN_SPRG0, BOOKE_SPRG0_OFF + STRIDE_SIZE * 0) ;\
+ RESTORE_SPR(SPRN_SPRG1, BOOKE_SPRG0_OFF + STRIDE_SIZE * 1) ;\
+ RESTORE_SPR(SPRN_SPRG2, BOOKE_SPRG0_OFF + STRIDE_SIZE * 2) ;\
+ RESTORE_SPR(SPRN_SPRG3, BOOKE_SPRG0_OFF + STRIDE_SIZE * 3) ;\
+ RESTORE_SPR(SPRN_SPRG4, BOOKE_SPRG0_OFF + STRIDE_SIZE * 4) ;\
+ RESTORE_SPR(SPRN_SPRG5, BOOKE_SPRG0_OFF + STRIDE_SIZE * 5) ;\
+ RESTORE_SPR(SPRN_SPRG6, BOOKE_SPRG0_OFF + STRIDE_SIZE * 6) ;\
+ RESTORE_SPR(SPRN_SPRG7, BOOKE_SPRG0_OFF + STRIDE_SIZE * 7) ;\
+ RESTORE_SPR(SPRN_SPRG8, BOOKE_SPRG0_OFF + STRIDE_SIZE * 8) ;\
+ RESTORE_SPR(SPRN_SPRG9, BOOKE_SPRG0_OFF + STRIDE_SIZE * 9)
+
+#define SAVE_ALL_IVOR \
+ SAVE_SPR(SPRN_IVOR0, BOOKE_IVOR0_OFF + STRIDE_SIZE * 0) ;\
+ SAVE_SPR(SPRN_IVOR1, BOOKE_IVOR0_OFF + STRIDE_SIZE * 1) ;\
+ SAVE_SPR(SPRN_IVOR2, BOOKE_IVOR0_OFF + STRIDE_SIZE * 2) ;\
+ SAVE_SPR(SPRN_IVOR3, BOOKE_IVOR0_OFF + STRIDE_SIZE * 3) ;\
+ SAVE_SPR(SPRN_IVOR4, BOOKE_IVOR0_OFF + STRIDE_SIZE * 4) ;\
+ SAVE_SPR(SPRN_IVOR5, BOOKE_IVOR0_OFF + STRIDE_SIZE * 5) ;\
+ SAVE_SPR(SPRN_IVOR6, BOOKE_IVOR0_OFF + STRIDE_SIZE * 6) ;\
+ SAVE_SPR(SPRN_IVOR7, BOOKE_IVOR0_OFF + STRIDE_SIZE * 7) ;\
+ SAVE_SPR(SPRN_IVOR8, BOOKE_IVOR0_OFF + STRIDE_SIZE * 8) ;\
+ SAVE_SPR(SPRN_IVOR9, BOOKE_IVOR0_OFF + STRIDE_SIZE * 9) ;\
+ SAVE_SPR(SPRN_IVOR10, BOOKE_IVOR0_OFF + STRIDE_SIZE * 10) ;\
+ SAVE_SPR(SPRN_IVOR11, BOOKE_IVOR0_OFF + STRIDE_SIZE * 11) ;\
+ SAVE_SPR(SPRN_IVOR12, BOOKE_IVOR0_OFF + STRIDE_SIZE * 12) ;\
+ SAVE_SPR(SPRN_IVOR13, BOOKE_IVOR0_OFF + STRIDE_SIZE * 13) ;\
+ SAVE_SPR(SPRN_IVOR14, BOOKE_IVOR0_OFF + STRIDE_SIZE * 14) ;\
+ SAVE_SPR(SPRN_IVOR15, BOOKE_IVOR0_OFF + STRIDE_SIZE * 15) ;\
+ SAVE_SPR(SPRN_IVOR35, BOOKE_IVOR0_OFF + STRIDE_SIZE * 35) ;\
+ SAVE_SPR(SPRN_IVOR36, BOOKE_IVOR0_OFF + STRIDE_SIZE * 36) ;\
+ SAVE_SPR(SPRN_IVOR37, BOOKE_IVOR0_OFF + STRIDE_SIZE * 37) ;\
+ SAVE_SPR(SPRN_IVOR38, BOOKE_IVOR0_OFF + STRIDE_SIZE * 38) ;\
+ SAVE_SPR(SPRN_IVOR39, BOOKE_IVOR0_OFF + STRIDE_SIZE * 39) ;\
+ SAVE_SPR(SPRN_IVOR40, BOOKE_IVOR0_OFF + STRIDE_SIZE * 40) ;\
+ SAVE_SPR(SPRN_IVOR41, BOOKE_IVOR0_OFF + STRIDE_SIZE * 41)
+
+#define RESTORE_ALL_IVOR \
+ RESTORE_SPR(SPRN_IVOR0, BOOKE_IVOR0_OFF + STRIDE_SIZE * 0) ;\
+ RESTORE_SPR(SPRN_IVOR1, BOOKE_IVOR0_OFF + STRIDE_SIZE * 1) ;\
+ RESTORE_SPR(SPRN_IVOR2, BOOKE_IVOR0_OFF + STRIDE_SIZE * 2) ;\
+ RESTORE_SPR(SPRN_IVOR3, BOOKE_IVOR0_OFF + STRIDE_SIZE * 3) ;\
+ RESTORE_SPR(SPRN_IVOR4, BOOKE_IVOR0_OFF + STRIDE_SIZE * 4) ;\
+ RESTORE_SPR(SPRN_IVOR5, BOOKE_IVOR0_OFF + STRIDE_SIZE * 5) ;\
+ RESTORE_SPR(SPRN_IVOR6, BOOKE_IVOR0_OFF + STRIDE_SIZE * 6) ;\
+ RESTORE_SPR(SPRN_IVOR7, BOOKE_IVOR0_OFF + STRIDE_SIZE * 7) ;\
+ RESTORE_SPR(SPRN_IVOR8, BOOKE_IVOR0_OFF + STRIDE_SIZE * 8) ;\
+ RESTORE_SPR(SPRN_IVOR9, BOOKE_IVOR0_OFF + STRIDE_SIZE * 9) ;\
+ RESTORE_SPR(SPRN_IVOR10, BOOKE_IVOR0_OFF + STRIDE_SIZE * 10) ;\
+ RESTORE_SPR(SPRN_IVOR11, BOOKE_IVOR0_OFF + STRIDE_SIZE * 11) ;\
+ RESTORE_SPR(SPRN_IVOR12, BOOKE_IVOR0_OFF + STRIDE_SIZE * 12) ;\
+ RESTORE_SPR(SPRN_IVOR13, BOOKE_IVOR0_OFF + STRIDE_SIZE * 13) ;\
+ RESTORE_SPR(SPRN_IVOR14, BOOKE_IVOR0_OFF + STRIDE_SIZE * 14) ;\
+ RESTORE_SPR(SPRN_IVOR15, BOOKE_IVOR0_OFF + STRIDE_SIZE * 15) ;\
+ RESTORE_SPR(SPRN_IVOR35, BOOKE_IVOR0_OFF + STRIDE_SIZE * 35) ;\
+ RESTORE_SPR(SPRN_IVOR36, BOOKE_IVOR0_OFF + STRIDE_SIZE * 36) ;\
+ RESTORE_SPR(SPRN_IVOR37, BOOKE_IVOR0_OFF + STRIDE_SIZE * 37) ;\
+ RESTORE_SPR(SPRN_IVOR38, BOOKE_IVOR0_OFF + STRIDE_SIZE * 38) ;\
+ RESTORE_SPR(SPRN_IVOR39, BOOKE_IVOR0_OFF + STRIDE_SIZE * 39) ;\
+ RESTORE_SPR(SPRN_IVOR40, BOOKE_IVOR0_OFF + STRIDE_SIZE * 40) ;\
+ RESTORE_SPR(SPRN_IVOR41, BOOKE_IVOR0_OFF + STRIDE_SIZE * 41)
+
+/* reset time base to prevent from overflow */
+#define DELAY(count) \
+ li r3, count; \
+ li r4, 0; \
+ mtspr SPRN_TBWL, r4; \
+101: mfspr r4, SPRN_TBRL; \
+ cmpw r4, r3; \
+ blt 101b
+
+#define FSL_DIS_ALL_IRQ \
+ mfmsr r8; \
+ rlwinm r8, r8, 0, ~MSR_CE; \
+ rlwinm r8, r8, 0, ~MSR_ME; \
+ rlwinm r8, r8, 0, ~MSR_EE; \
+ rlwinm r8, r8, 0, ~MSR_DE; \
+ mtmsr r8; \
+ isync
+
+#ifndef CONFIG_PPC_E500MC
+#define SS_TB 0x00
+#define SS_HID 0x08 /* 2 HIDs */
+#define SS_IAC 0x10 /* 2 IACs */
+#define SS_DAC 0x18 /* 2 DACs */
+#define SS_DBCR 0x20 /* 3 DBCRs */
+#define SS_PID 0x2c /* 3 PIDs */
+#define SS_SPRG 0x38 /* 8 SPRGs */
+#define SS_IVOR 0x58 /* 20 interrupt vectors */
+#define SS_TCR 0xa8
+#define SS_BUCSR 0xac
+#define SS_L1CSR 0xb0 /* 2 L1CSRs */
+#define SS_MSR 0xb8
+#define SS_USPRG 0xbc
+#define SS_GPREG 0xc0 /* r12-r31 */
+#define SS_LR 0x110
+#define SS_CR 0x114
+#define SS_SP 0x118
+#define SS_CURRENT 0x11c
+#define SS_IVPR 0x120
+#define SS_BPTR 0x124
+
+
+#define STATE_SAVE_SIZE 0x128
+
+ .section .data
+ .align 5
+mpc85xx_sleep_save_area:
+ .space STATE_SAVE_SIZE
+ccsrbase_low:
+ .long 0
+ccsrbase_high:
+ .long 0
+powmgtreq:
+ .long 0
+
+ .section .text
+ .align 12
+
+ /*
+ * r3 = high word of physical address of CCSR
+ * r4 = low word of physical address of CCSR
+ * r5 = JOG or deep sleep request
+ * JOG-0x00200000, deep sleep-0x00100000
+ */
+_GLOBAL(mpc85xx_enter_deep_sleep)
+ lis r6, ccsrbase_low@ha
+ stw r4, ccsrbase_low@l(r6)
+ lis r6, ccsrbase_high@ha
+ stw r3, ccsrbase_high@l(r6)
+
+ lis r6, powmgtreq@ha
+ stw r5, powmgtreq@l(r6)
+
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ mfspr r5, SPRN_HID0
+ mfspr r6, SPRN_HID1
+
+ stw r5, SS_HID+0(r10)
+ stw r6, SS_HID+4(r10)
+
+ mfspr r4, SPRN_IAC1
+ mfspr r5, SPRN_IAC2
+ mfspr r6, SPRN_DAC1
+ mfspr r7, SPRN_DAC2
+
+ stw r4, SS_IAC+0(r10)
+ stw r5, SS_IAC+4(r10)
+ stw r6, SS_DAC+0(r10)
+ stw r7, SS_DAC+4(r10)
+
+ mfspr r4, SPRN_DBCR0
+ mfspr r5, SPRN_DBCR1
+ mfspr r6, SPRN_DBCR2
+
+ stw r4, SS_DBCR+0(r10)
+ stw r5, SS_DBCR+4(r10)
+ stw r6, SS_DBCR+8(r10)
+
+ mfspr r4, SPRN_PID0
+ mfspr r5, SPRN_PID1
+ mfspr r6, SPRN_PID2
+
+ stw r4, SS_PID+0(r10)
+ stw r5, SS_PID+4(r10)
+ stw r6, SS_PID+8(r10)
+
+ mfspr r4, SPRN_SPRG0
+ mfspr r5, SPRN_SPRG1
+ mfspr r6, SPRN_SPRG2
+ mfspr r7, SPRN_SPRG3
+
+ stw r4, SS_SPRG+0x00(r10)
+ stw r5, SS_SPRG+0x04(r10)
+ stw r6, SS_SPRG+0x08(r10)
+ stw r7, SS_SPRG+0x0c(r10)
+
+ mfspr r4, SPRN_SPRG4
+ mfspr r5, SPRN_SPRG5
+ mfspr r6, SPRN_SPRG6
+ mfspr r7, SPRN_SPRG7
+
+ stw r4, SS_SPRG+0x10(r10)
+ stw r5, SS_SPRG+0x14(r10)
+ stw r6, SS_SPRG+0x18(r10)
+ stw r7, SS_SPRG+0x1c(r10)
+
+ mfspr r4, SPRN_IVPR
+ stw r4, SS_IVPR(r10)
+
+ mfspr r4, SPRN_IVOR0
+ mfspr r5, SPRN_IVOR1
+ mfspr r6, SPRN_IVOR2
+ mfspr r7, SPRN_IVOR3
+
+ stw r4, SS_IVOR+0x00(r10)
+ stw r5, SS_IVOR+0x04(r10)
+ stw r6, SS_IVOR+0x08(r10)
+ stw r7, SS_IVOR+0x0c(r10)
+
+ mfspr r4, SPRN_IVOR4
+ mfspr r5, SPRN_IVOR5
+ mfspr r6, SPRN_IVOR6
+ mfspr r7, SPRN_IVOR7
+
+ stw r4, SS_IVOR+0x10(r10)
+ stw r5, SS_IVOR+0x14(r10)
+ stw r6, SS_IVOR+0x18(r10)
+ stw r7, SS_IVOR+0x1c(r10)
+
+ mfspr r4, SPRN_IVOR8
+ mfspr r5, SPRN_IVOR9
+ mfspr r6, SPRN_IVOR10
+ mfspr r7, SPRN_IVOR11
+
+ stw r4, SS_IVOR+0x20(r10)
+ stw r5, SS_IVOR+0x24(r10)
+ stw r6, SS_IVOR+0x28(r10)
+ stw r7, SS_IVOR+0x2c(r10)
+
+ mfspr r4, SPRN_IVOR12
+ mfspr r5, SPRN_IVOR13
+ mfspr r6, SPRN_IVOR14
+ mfspr r7, SPRN_IVOR15
+
+ stw r4, SS_IVOR+0x30(r10)
+ stw r5, SS_IVOR+0x34(r10)
+ stw r6, SS_IVOR+0x38(r10)
+ stw r7, SS_IVOR+0x3c(r10)
+
+ mfspr r4, SPRN_IVOR32
+ mfspr r5, SPRN_IVOR33
+ mfspr r6, SPRN_IVOR34
+ mfspr r7, SPRN_IVOR35
+
+ stw r4, SS_IVOR+0x40(r10)
+ stw r5, SS_IVOR+0x44(r10)
+ stw r6, SS_IVOR+0x48(r10)
+ stw r7, SS_IVOR+0x4c(r10)
+
+ mfspr r4, SPRN_TCR
+ mfspr r5, SPRN_BUCSR
+ mfspr r6, SPRN_L1CSR0
+ mfspr r7, SPRN_L1CSR1
+ mfspr r8, SPRN_USPRG0
+
+ stw r4, SS_TCR(r10)
+ stw r5, SS_BUCSR(r10)
+ stw r6, SS_L1CSR+0(r10)
+ stw r7, SS_L1CSR+4(r10)
+ stw r8, SS_USPRG+0(r10)
+
+ stmw r12, SS_GPREG(r10)
+
+ mfmsr r4
+ mflr r5
+ mfcr r6
+
+ stw r4, SS_MSR(r10)
+ stw r5, SS_LR(r10)
+ stw r6, SS_CR(r10)
+ stw r1, SS_SP(r10)
+ stw r2, SS_CURRENT(r10)
+
+1: mftbu r4
+ mftb r5
+ mftbu r6
+ cmpw r4, r6
+ bne 1b
+
+ stw r4, SS_TB+0(r10)
+ stw r5, SS_TB+4(r10)
+
+ lis r5, ccsrbase_low@ha
+ lwz r4, ccsrbase_low@l(r5)
+ lis r5, ccsrbase_high@ha
+ lwz r3, ccsrbase_high@l(r5)
+
+ /* Disable machine checks and critical exceptions */
+ mfmsr r5
+ rlwinm r5, r5, 0, ~MSR_CE
+ rlwinm r5, r5, 0, ~MSR_ME
+ mtmsr r5
+ isync
+
+ /* Use TLB1[15] to map the CCSR at 0xf0000000 */
+ lis r5, 0x100f
+ mtspr SPRN_MAS0, r5
+ lis r5, 0xc000
+ ori r5, r5, 0x0500
+ mtspr SPRN_MAS1, r5
+ lis r5, 0xf000
+ ori r5, r5, 0x000a
+ mtspr SPRN_MAS2, r5
+ rlwinm r5, r4, 0, 0xfffff000
+ ori r5, r5, 0x0005
+ mtspr SPRN_MAS3, r5
+ mtspr SPRN_MAS7, r3
+ isync
+ tlbwe
+ isync
+
+ lis r3, 0xf000
+ lwz r4, 0x20(r3)
+ stw r4, SS_BPTR(r10)
+
+ lis r3, 0xf002 /* L2 cache controller at CCSR+0x20000 */
+ bl flush_disable_L2
+ bl __flush_disable_L1
+
+ /* Enable I-cache, so as not to upset the bus
+ * with our loop.
+ */
+
+ mfspr r4, SPRN_L1CSR1
+ ori r4, r4, 1
+ mtspr SPRN_L1CSR1, r4
+ isync
+
+ /* Set boot page translation */
+ lis r3, 0xf000
+ lis r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
+ ori r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
+ rlwinm r4, r4, 20, 0x000fffff
+ oris r4, r4, 0x8000
+ stw r4, 0x20(r3)
+ lwz r4, 0x20(r3) /* read-back to flush write */
+ twi 0, r4, 0
+ isync
+
+ /* Disable the decrementer */
+ mfspr r4, SPRN_TCR
+ rlwinm r4, r4, 0, ~TCR_DIE
+ mtspr SPRN_TCR, r4
+
+ mfspr r4, SPRN_TSR
+ oris r4, r4, TSR_DIS@h
+ mtspr SPRN_TSR, r4
+
+ /* set PMRCCR[VRCNT] to wait power stable for 40ms */
+ lis r3, 0xf00e
+ lwz r4, 0x84(r3)
+ clrlwi r4, r4, 16
+ oris r4, r4, 0x12a3
+ stw r4, 0x84(r3)
+ lwz r4, 0x84(r3)
+
+ /* set deep sleep bit in POWMGTSCR */
+ lis r3, powmgtreq@ha
+ lwz r8, powmgtreq@l(r3)
+
+ lis r3, 0xf00e
+ lwz r4, 0x80(r3)
+ or r4, r4, r8
+ stw r4, 0x80(r3)
+ lwz r4, 0x80(r3) /* read-back to flush write */
+ twi 0, r4, 0
+ isync
+
+ mftb r5
+1: /* spin until either we enter deep sleep, or the sleep process is
+ * aborted due to a pending wakeup event. Wait some time between
+ * accesses, so we don't flood the bus and prevent the pmc from
+ * detecting an idle system.
+ */
+
+ mftb r4
+ subf r7, r5, r4
+ cmpwi r7, 1000
+ blt 1b
+ mr r5, r4
+
+ lwz r6, 0x80(r3)
+ andis. r6, r6, 0x0010
+ bne 1b
+ b 2f
+
+2: mfspr r4, SPRN_PIR
+ andi. r4, r4, 1
+99: bne 99b
+
+ /* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
+ lis r4, 0x1001
+ mtspr SPRN_MAS0, r4
+ lis r4, 0xc000
+ ori r4, r4, 0x0800
+ mtspr SPRN_MAS1, r4
+ li r4, 0
+ mtspr SPRN_MAS2, r4
+ li r4, 0x0015
+ mtspr SPRN_MAS3, r4
+ li r4, 0
+ mtspr SPRN_MAS7, r4
+ isync
+ tlbwe
+ isync
+
+ lis r3, (3f - PAGE_OFFSET)@h
+ ori r3, r3, (3f - PAGE_OFFSET)@l
+ mtctr r3
+ bctr
+
+ /* Locate the resume vector in the last word of the current page. */
+ . = mpc85xx_enter_deep_sleep + 0xffc
+mpc85xx_deep_resume:
+ b 2b
+
+3:
+ /* Restore the contents of TLB1[0]. It is assumed that it covers
+ * the currently executing code and the sleep save area, and that
+ * it does not alias our temporary mapping (which is at virtual zero).
+ */
+ lis r3, (TLBCAM - PAGE_OFFSET)@h
+ ori r3, r3, (TLBCAM - PAGE_OFFSET)@l
+
+ lwz r4, 0(r3)
+ lwz r5, 4(r3)
+ lwz r6, 8(r3)
+ lwz r7, 12(r3)
+ lwz r8, 16(r3)
+
+ mtspr SPRN_MAS0, r4
+ mtspr SPRN_MAS1, r5
+ mtspr SPRN_MAS2, r6
+ mtspr SPRN_MAS3, r7
+ mtspr SPRN_MAS7, r8
+
+ isync
+ tlbwe
+ isync
+
+ /* Access the ccsrbase address with TLB1[0] */
+ lis r5, ccsrbase_low@ha
+ lwz r4, ccsrbase_low@l(r5)
+ lis r5, ccsrbase_high@ha
+ lwz r3, ccsrbase_high@l(r5)
+
+ /* Use TLB1[15] to map the CCSR at 0xf0000000 */
+ lis r5, 0x100f
+ mtspr SPRN_MAS0, r5
+ lis r5, 0xc000
+ ori r5, r5, 0x0500
+ mtspr SPRN_MAS1, r5
+ lis r5, 0xf000
+ ori r5, r5, 0x000a
+ mtspr SPRN_MAS2, r5
+ rlwinm r5, r4, 0, 0xfffff000
+ ori r5, r5, 0x0005
+ mtspr SPRN_MAS3, r5
+ mtspr SPRN_MAS7, r3
+ isync
+ tlbwe
+ isync
+
+ lis r3, 0xf002 /* L2 cache controller at CCSR+0x20000 */
+ bl invalidate_enable_L2
+
+ /* Access the MEM(r10) with TLB1[0] */
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ lis r3, 0xf000
+ lwz r4, SS_BPTR(r10)
+ stw r4, 0x20(r3) /* restore BPTR */
+
+ /* Program shift running space to PAGE_OFFSET */
+ mfmsr r3
+ lis r4, 1f@h
+ ori r4, r4, 1f@l
+
+ mtsrr1 r3
+ mtsrr0 r4
+ rfi
+
+1: /* Restore the rest of TLB1, in ascending order so that
+ * the TLB1[1] gets invalidated first.
+ *
+ * XXX: It's better to invalidate the temporary mapping
+ * TLB1[15] for CCSR before restore any TLB1 entry include 0.
+ */
+ lis r4, 0x100f
+ mtspr SPRN_MAS0, r4
+ lis r4, 0
+ mtspr SPRN_MAS1, r4
+ isync
+ tlbwe
+ isync
+
+ lis r3, (TLBCAM + 5*4 - 4)@h
+ ori r3, r3, (TLBCAM + 5*4 - 4)@l
+ li r4, 15
+ mtctr r4
+
+2:
+ lwz r5, 4(r3)
+ lwz r6, 8(r3)
+ lwz r7, 12(r3)
+ lwz r8, 16(r3)
+ lwzu r9, 20(r3)
+
+ mtspr SPRN_MAS0, r5
+ mtspr SPRN_MAS1, r6
+ mtspr SPRN_MAS2, r7
+ mtspr SPRN_MAS3, r8
+ mtspr SPRN_MAS7, r9
+
+ isync
+ tlbwe
+ isync
+ bdnz 2b
+
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ lwz r5, SS_HID+0(r10)
+ lwz r6, SS_HID+4(r10)
+
+ isync
+ mtspr SPRN_HID0, r5
+ isync
+
+ msync
+ mtspr SPRN_HID1, r6
+ isync
+
+ lwz r4, SS_IAC+0(r10)
+ lwz r5, SS_IAC+4(r10)
+ lwz r6, SS_DAC+0(r10)
+ lwz r7, SS_DAC+4(r10)
+
+ mtspr SPRN_IAC1, r4
+ mtspr SPRN_IAC2, r5
+ mtspr SPRN_DAC1, r6
+ mtspr SPRN_DAC2, r7
+
+ lwz r4, SS_DBCR+0(r10)
+ lwz r5, SS_DBCR+4(r10)
+ lwz r6, SS_DBCR+8(r10)
+
+ mtspr SPRN_DBCR0, r4
+ mtspr SPRN_DBCR1, r5
+ mtspr SPRN_DBCR2, r6
+
+ lwz r4, SS_PID+0(r10)
+ lwz r5, SS_PID+4(r10)
+ lwz r6, SS_PID+8(r10)
+
+ mtspr SPRN_PID0, r4
+ mtspr SPRN_PID1, r5
+ mtspr SPRN_PID2, r6
+
+ lwz r4, SS_SPRG+0x00(r10)
+ lwz r5, SS_SPRG+0x04(r10)
+ lwz r6, SS_SPRG+0x08(r10)
+ lwz r7, SS_SPRG+0x0c(r10)
+
+ mtspr SPRN_SPRG0, r4
+ mtspr SPRN_SPRG1, r5
+ mtspr SPRN_SPRG2, r6
+ mtspr SPRN_SPRG3, r7
+
+ lwz r4, SS_SPRG+0x10(r10)
+ lwz r5, SS_SPRG+0x14(r10)
+ lwz r6, SS_SPRG+0x18(r10)
+ lwz r7, SS_SPRG+0x1c(r10)
+
+ mtspr SPRN_SPRG4, r4
+ mtspr SPRN_SPRG5, r5
+ mtspr SPRN_SPRG6, r6
+ mtspr SPRN_SPRG7, r7
+
+ lwz r4, SS_IVPR(r10)
+ mtspr SPRN_IVPR, r4
+
+ lwz r4, SS_IVOR+0x00(r10)
+ lwz r5, SS_IVOR+0x04(r10)
+ lwz r6, SS_IVOR+0x08(r10)
+ lwz r7, SS_IVOR+0x0c(r10)
+
+ mtspr SPRN_IVOR0, r4
+ mtspr SPRN_IVOR1, r5
+ mtspr SPRN_IVOR2, r6
+ mtspr SPRN_IVOR3, r7
+
+ lwz r4, SS_IVOR+0x10(r10)
+ lwz r5, SS_IVOR+0x14(r10)
+ lwz r6, SS_IVOR+0x18(r10)
+ lwz r7, SS_IVOR+0x1c(r10)
+
+ mtspr SPRN_IVOR4, r4
+ mtspr SPRN_IVOR5, r5
+ mtspr SPRN_IVOR6, r6
+ mtspr SPRN_IVOR7, r7
+
+ lwz r4, SS_IVOR+0x20(r10)
+ lwz r5, SS_IVOR+0x24(r10)
+ lwz r6, SS_IVOR+0x28(r10)
+ lwz r7, SS_IVOR+0x2c(r10)
+
+ mtspr SPRN_IVOR8, r4
+ mtspr SPRN_IVOR9, r5
+ mtspr SPRN_IVOR10, r6
+ mtspr SPRN_IVOR11, r7
+
+ lwz r4, SS_IVOR+0x30(r10)
+ lwz r5, SS_IVOR+0x34(r10)
+ lwz r6, SS_IVOR+0x38(r10)
+ lwz r7, SS_IVOR+0x3c(r10)
+
+ mtspr SPRN_IVOR12, r4
+ mtspr SPRN_IVOR13, r5
+ mtspr SPRN_IVOR14, r6
+ mtspr SPRN_IVOR15, r7
+
+ lwz r4, SS_IVOR+0x40(r10)
+ lwz r5, SS_IVOR+0x44(r10)
+ lwz r6, SS_IVOR+0x48(r10)
+ lwz r7, SS_IVOR+0x4c(r10)
+
+ mtspr SPRN_IVOR32, r4
+ mtspr SPRN_IVOR33, r5
+ mtspr SPRN_IVOR34, r6
+ mtspr SPRN_IVOR35, r7
+
+ lwz r4, SS_TCR(r10)
+ lwz r5, SS_BUCSR(r10)
+ lwz r6, SS_L1CSR+0(r10)
+ lwz r7, SS_L1CSR+4(r10)
+ lwz r8, SS_USPRG+0(r10)
+
+ mtspr SPRN_TCR, r4
+ mtspr SPRN_BUCSR, r5
+
+ msync
+ isync
+ mtspr SPRN_L1CSR0, r6
+ isync
+
+ mtspr SPRN_L1CSR1, r7
+ isync
+
+ mtspr SPRN_USPRG0, r8
+
+ lmw r12, SS_GPREG(r10)
+
+ lwz r1, SS_SP(r10)
+ lwz r2, SS_CURRENT(r10)
+ lwz r4, SS_MSR(r10)
+ lwz r5, SS_LR(r10)
+ lwz r6, SS_CR(r10)
+
+ msync
+ mtmsr r4
+ isync
+
+ mtlr r5
+ mtcr r6
+
+ li r4, 0
+ mtspr SPRN_TBWL, r4
+
+ lwz r4, SS_TB+0(r10)
+ lwz r5, SS_TB+4(r10)
+
+ mtspr SPRN_TBWU, r4
+ mtspr SPRN_TBWL, r5
+
+ lis r3, 1
+ mtdec r3
+
+ blr
+
+#else /* CONFIG_PPC_E500MC */
+
+ .section .data
+ .align 6
+regs_buffer:
+ .space BUFFER_SIZE
+
+ .section .text
+/*
+ * Save CPU registers
+ * r3 : the base address of the buffer which stores the values of registers
+ */
+e5500_cpu_state_save:
+ /* store the base address to r10 */
+ mr r10, r3
+
+ SAVE_ALL_GPR
+ SAVE_ALL_SPRG
+ SAVE_ALL_IVOR
+
+ SAVE_SPR(SPRN_IVPR, BOOKE_IVPR_OFF)
+ SAVE_SPR(SPRN_PID0, BOOKE_PID0_OFF)
+ SAVE_SPR(SPRN_EPCR, BOOKE_EPCR_OFF)
+ SAVE_SPR(SPRN_HID0, BOOKE_HID0_OFF)
+ SAVE_SPR(SPRN_PIR, BOOKE_PIR_OFF)
+ SAVE_SPR(SPRN_BUCSR, BOOKE_BUCSR_OFF)
+1:
+ mfspr r5, SPRN_TBRU
+ mfspr r4, SPRN_TBRL
+ SAVE_GPR(r5, BOOKE_TBU_OFF)
+ SAVE_GPR(r4, BOOKE_TBL_OFF)
+ mfspr r3, SPRN_TBRU
+ cmpw r3, r5
+ bne 1b
+
+ blr
+
+/*
+ * Restore CPU registers
+ * r3 : the base address of the buffer which stores the values of registers
+ */
+e5500_cpu_state_restore:
+ /* store the base address to r10 */
+ mr r10, r3
+
+ RESTORE_ALL_GPR
+ RESTORE_ALL_SPRG
+ RESTORE_ALL_IVOR
+
+ RESTORE_SPR(SPRN_IVPR, BOOKE_IVPR_OFF)
+ RESTORE_SPR(SPRN_PID0, BOOKE_PID0_OFF)
+ RESTORE_SPR(SPRN_EPCR, BOOKE_EPCR_OFF)
+ RESTORE_SPR(SPRN_HID0, BOOKE_HID0_OFF)
+ RESTORE_SPR(SPRN_PIR, BOOKE_PIR_OFF)
+ RESTORE_SPR(SPRN_BUCSR, BOOKE_BUCSR_OFF)
+
+ li r0, 0
+ mtspr SPRN_TBWL, r0
+ RESTORE_SPR(SPRN_TBWU, BOOKE_TBU_OFF)
+ RESTORE_SPR(SPRN_TBWL, BOOKE_TBL_OFF)
+
+ blr
+
+#define CPC_CPCCSR0 0x0
+#define CPC_CPCCSR0_CPCFL 0x800
+
+/*
+ * Flush the CPC cache.
+ * r3 : the base address of CPC
+ */
+flush_cpc_cache:
+ lwz r6, CPC_CPCCSR0(r3)
+ ori r6, r6, CPC_CPCCSR0_CPCFL
+ stw r6, CPC_CPCCSR0(r3)
+ sync
+
+ /* Wait until completing the flush */
+1: lwz r6, CPC_CPCCSR0(r3)
+ andi. r6, r6, CPC_CPCCSR0_CPCFL
+ bne 1b
+
+ blr
+
+/*
+ * the last stage to enter deep sleep
+ *
+ */
+ .align 6
+_GLOBAL(fsl_dp_enter_low)
+deepsleep_start:
+ LOAD_REG_ADDR(r9, buf_tmp)
+ /* save the return address and MSR */
+ mflr r8
+ PPC_STL r8, 0(r9)
+ mfmsr r8
+ PPC_STL r8, 8(r9)
+ mfspr r8, SPRN_TCR
+ PPC_STL r8, 16(r9)
+ mfcr r8
+ PPC_STL r8, 24(r9)
+ li r8, 0
+ mtspr SPRN_TCR, r8
+
+ /* save the parameters */
+ PPC_STL r3, 32(r9)
+ PPC_STL r4, 40(r9)
+ PPC_STL r5, 48(r9)
+ PPC_STL r6, 56(r9)
+
+ LOAD_REG_ADDR(r3, regs_buffer)
+ bl e5500_cpu_state_save
+
+ /* restore the parameters */
+ LOAD_REG_ADDR(r9, buf_tmp)
+ PPC_LL r31, 32(r9)
+ PPC_LL r30, 40(r9)
+ PPC_LL r29, 48(r9)
+ PPC_LL r28, 56(r9)
+
+ /* flush caches inside CPU */
+ LOAD_REG_ADDR(r3, cur_cpu_spec)
+ PPC_LL r3, 0(r3)
+ PPC_LL r3, CPU_FLUSH_CACHES(r3)
+ PPC_LCMPI 0, r3, 0
+ beq 6f
+#ifdef CONFIG_PPC64
+ PPC_LL r3, 0(r3)
+#endif
+ mtctr r3
+ bctrl
+6:
+ /* Flush the CPC cache */
+#define CPC_OFFSET 0x10000
+ mr r3, r31
+ addis r3, r3, CPC_OFFSET@h
+ bl flush_cpc_cache
+
+ /* prefecth TLB */
+#define CCSR_GPIO1_GPDAT 0x130008
+#define CCSR_GPIO1_GPDAT_29 0x4
+ LOAD_REG_IMMEDIATE(r11, CCSR_GPIO1_GPDAT)
+ add r11, r31, r11
+ lwz r10, 0(r11)
+
+#define CCSR_RCPM_PCPH15SETR 0xe20b4
+#define CCSR_RCPM_PCPH15SETR_CORE0 0x1
+ LOAD_REG_IMMEDIATE(r12, CCSR_RCPM_PCPH15SETR)
+ add r12, r31, r12
+ lwz r10, 0(r12)
+
+#define CCSR_DDR_SDRAM_CFG_2 0x8114
+#define CCSR_DDR_SDRAM_CFG_2_FRC_SR 0x80000000
+ LOAD_REG_IMMEDIATE(r13, CCSR_DDR_SDRAM_CFG_2)
+ add r13, r31, r13
+ lwz r10, 0(r13)
+
+#define DCSR_EPU_EPGCR 0x000
+#define DCSR_EPU_EPGCR_GCE 0x80000000
+ li r14, DCSR_EPU_EPGCR
+ add r14, r30, r14
+ lwz r10, 0(r14)
+
+#define DCSR_EPU_EPECR15 0x33C
+#define DCSR_EPU_EPECR15_IC0 0x80000000
+ li r15, DCSR_EPU_EPECR15
+ add r15, r30, r15
+ lwz r10, 0(r15)
+
+#define CCSR_SCFG_QMIFRSTCR 0xfc40c
+#define CCSR_SCFG_QMIFRSTCR_QMIFRST 0x80000000
+ LOAD_REG_IMMEDIATE(r16, CCSR_SCFG_QMIFRSTCR)
+ add r16, r31, r16
+ lwz r10, 0(r16)
+
+/*
+ * There are two kind of register maps, one for T1040QDS and
+ * the other for T104xRDB.
+ */
+#define T104XRDB_CPLD_MISCCSR 0x17
+#define T104XRDB_CPLD_MISCCSR_SLEEPEN 0x40
+#define T1040QDS_QIXIS_PWR_CTL2 0x21
+#define T1040QDS_QIXIS_PWR_CTL2_PCTL 0x2
+ li r3, T1040QDS_QIXIS_PWR_CTL2
+ PPC_LCMPI 0, r28, T1040QDS_TETRA_FLAG
+ beq 20f
+ li r3, T104XRDB_CPLD_MISCCSR
+20: add r29, r29, r3
+ lbz r10, 0(r29)
+ sync
+
+ LOAD_REG_ADDR(r8, deepsleep_start)
+ LOAD_REG_ADDR(r9, deepsleep_end)
+
+ /* prefecth code to cache so that executing code after disable DDR */
+1: icbtls 2, 0, r8
+ addi r8, r8, 64
+ cmpw r8, r9
+ blt 1b
+ sync
+
+ FSL_DIS_ALL_IRQ
+
+ /*
+ * Place DDR controller in self refresh mode.
+ * From here on, can't access DDR any more.
+ */
+ lwz r10, 0(r13)
+ oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
+ stw r10, 0(r13)
+ lwz r10, 0(r13)
+ sync
+
+ DELAY(500)
+
+ /*
+ * Enable deep sleep signals by write external CPLD/FPGA register.
+ * The bootloader will disable them when wakeup from deep sleep.
+ */
+ lbz r10, 0(r29)
+ li r3, T1040QDS_QIXIS_PWR_CTL2_PCTL
+ PPC_LCMPI 0, r28, T1040QDS_TETRA_FLAG
+ beq 22f
+ li r3, T104XRDB_CPLD_MISCCSR_SLEEPEN
+22: or r10, r10, r3
+ stb r10, 0(r29)
+ lbz r10, 0(r29)
+ sync
+
+ /*
+ * Set GPIO1_29 to lock the signal MCKE down during deep sleep.
+ * The bootloader will clear it when wakeup.
+ */
+ lwz r10, 0(r11)
+ ori r10, r10, CCSR_GPIO1_GPDAT_29
+ stw r10, 0(r11)
+ lwz r10, 0(r11)
+
+ DELAY(100)
+
+ /* Reset QMan system bus interface */
+ lwz r10, 0(r16)
+ oris r10, r10, CCSR_SCFG_QMIFRSTCR_QMIFRST@h
+ stw r10, 0(r16)
+ lwz r10, 0(r16)
+
+ /* Enable all EPU Counters */
+ li r10, 0
+ oris r10, r10, DCSR_EPU_EPGCR_GCE@h
+ stw r10, 0(r14)
+ lwz r10, 0(r14)
+
+ /* Enable SCU15 to trigger on RCPM Concentrator 0 */
+ lwz r10, 0(r15)
+ oris r10, r10, DCSR_EPU_EPECR15_IC0@h
+ stw r10, 0(r15)
+ lwz r10, 0(r15)
+
+ /* put Core0 in PH15 mode, trigger EPU FSM */
+ lwz r10, 0(r12)
+ ori r10, r10, CCSR_RCPM_PCPH15SETR_CORE0
+ stw r10, 0(r12)
+2:
+ b 2b
+
+ /*
+ * Leave some space to prevent prefeching instruction
+ * beyond deepsleep_end. The space also can be used as heap.
+ */
+buf_tmp:
+ .space 128
+ .align 6
+deepsleep_end:
+
+ .align 12
+#ifdef CONFIG_PPC32
+_GLOBAL(fsl_booke_deep_sleep_resume)
+ /* disable interrupts */
+ FSL_DIS_ALL_IRQ
+
+#define ENTRY_DEEPSLEEP_SETUP
+#define ENTRY_MAPPING_BOOT_SETUP
+#include <../../kernel/fsl_booke_entry_mapping.S>
+#undef ENTRY_DEEPSLEEP_SETUP
+#undef ENTRY_MAPPING_BOOT_SETUP
+
+ li r3, 0
+ mfspr r4, SPRN_PIR
+ bl call_setup_cpu
+
+ /* Load each CAM entry */
+ LOAD_REG_ADDR(r3, tlbcam_index)
+ lwz r3, 0(r3)
+ mtctr r3
+ li r9, 0
+3: mr r3, r9
+ bl loadcam_entry
+ addi r9, r9, 1
+ bdnz 3b
+
+ /* restore cpu registers */
+ LOAD_REG_ADDR(r3, regs_buffer)
+ bl e5500_cpu_state_restore
+
+ /* restore return address */
+ LOAD_REG_ADDR(r3, buf_tmp)
+ lwz r4, 16(r3)
+ mtspr SPRN_TCR, r4
+ lwz r4, 0(r3)
+ mtlr r4
+ lwz r4, 8(r3)
+ mtmsr r4
+ lwz r4, 24(r3)
+ mtcr r4
+
+ blr
+
+#else /* CONFIG_PPC32 */
+
+_GLOBAL(fsl_booke_deep_sleep_resume)
+ /* disable interrupts */
+ FSL_DIS_ALL_IRQ
+
+ /* switch to 64-bit mode */
+ bl .enable_64b_mode
+
+ /* set TOC pointer */
+ bl .relative_toc
+
+ /* setup initial TLBs, switch to kernel space ... */
+ bl .start_initialization_book3e
+
+ /* address space changed, set TOC pointer again */
+ bl .relative_toc
+
+ /* call a cpu state restore handler */
+ LOAD_REG_ADDR(r23, cur_cpu_spec)
+ ld r23,0(r23)
+ ld r23,CPU_SPEC_RESTORE(r23)
+ cmpdi 0,r23,0
+ beq 1f
+ ld r23,0(r23)
+ mtctr r23
+ bctrl
+1:
+ LOAD_REG_ADDR(r3, regs_buffer)
+ bl e5500_cpu_state_restore
+
+ /* Load each CAM entry */
+ LOAD_REG_ADDR(r3, tlbcam_index)
+ lwz r3, 0(r3)
+ mtctr r3
+ li r0, 0
+3: mr r3, r0
+ bl loadcam_entry
+ addi r0, r0, 1
+ bdnz 3b
+
+ /* restore return address */
+ LOAD_REG_ADDR(r3, buf_tmp)
+ ld r4, 16(r3)
+ mtspr SPRN_TCR, r4
+ ld r4, 0(r3)
+ mtlr r4
+ ld r4, 8(r3)
+ mtmsr r4
+ ld r4, 24(r3)
+ mtcr r4
+
+ blr
+
+#endif /* CONFIG_PPC32 */
+
+#endif
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index bcd179d..0ce5370 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -5,6 +5,7 @@ menuconfig PPC_86xx
depends on 6xx
select FSL_SOC
select ALTIVEC
+ select FSL_PMC if SUSPEND
help
The Freescale E600 SoCs have 74xx cores.
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 232225e..4549462 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -20,54 +20,192 @@
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <asm/cacheflush.h>
+
+#include <sysdev/fsl_soc.h>
+#include <asm/switch_to.h>
+#include <asm/fsl_pm.h>
struct pmc_regs {
__be32 devdisr;
__be32 devdisr2;
- __be32 :32;
- __be32 :32;
- __be32 pmcsr;
-#define PMCSR_SLP (1 << 17)
+ __be32 res1;
+ __be32 res2;
+ __be32 powmgtcsr;
+#define POWMGTCSR_SLP 0x00020000
+#define POWMGTCSR_DPSLP 0x00100000
+#define POWMGTCSR_LOSSLESS 0x00400000
+ __be32 res3[2];
+ __be32 pmcdr;
};
-static struct device *pmc_dev;
static struct pmc_regs __iomem *pmc_regs;
+static unsigned int pmc_flag;
+
+#define PMC_SLEEP 0x1
+#define PMC_DEEP_SLEEP 0x2
+#define PMC_LOSSLESS 0x4
+
+/**
+ * mpc85xx_pmc_set_wake - enable devices as wakeup event source
+ * @dev: a device affected
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ *
+ * RETURN VALUE:
+ * 0 is returned on success.
+ * -EINVAL is returned if device is not supposed to wake up the system.
+ * -ENODEV is returned if PMC is unavailable.
+ * Error code depending on the platform is returned if both the platform and
+ * the native mechanism fail to enable the generation of wake-up events
+ */
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+ int ret = 0;
+ struct device_node *clk_np;
+ const u32 *prop;
+ u32 pmcdr_mask;
+
+ if (!pmc_regs) {
+ dev_err(dev, "%s: PMC is unavailable\n", __func__);
+ return -ENODEV;
+ }
+
+ if (enable && !device_may_wakeup(dev))
+ return -EINVAL;
+
+ clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
+ if (!clk_np)
+ return -EINVAL;
+
+ prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
+ if (!prop) {
+ ret = -EINVAL;
+ goto out;
+ }
+ pmcdr_mask = be32_to_cpup(prop);
+
+ if (enable)
+ /* clear to enable clock in low power mode */
+ clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
+ else
+ setbits32(&pmc_regs->pmcdr, pmcdr_mask);
+
+out:
+ of_node_put(clk_np);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
+
+/**
+ * mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
+ * in (deep) sleep mode
+ * @enable: True to enable event generation; false to disable
+ */
+void mpc85xx_pmc_set_lossless_ethernet(int enable)
+{
+ if (pmc_flag & PMC_LOSSLESS) {
+ if (enable)
+ setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+ else
+ clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+ }
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);
static int pmc_suspend_enter(suspend_state_t state)
{
- int ret;
+ int ret = 0;
+ int result;
+
+ switch (state) {
+#ifdef CONFIG_PPC_85xx
+ case PM_SUSPEND_MEM:
+#ifdef CONFIG_SPE
+ enable_kernel_spe();
+#endif
+#ifdef CONFIG_PPC_FPU
+ enable_kernel_fp();
+#endif
+
+ pr_debug("%s: Entering deep sleep\n", __func__);
+
+ local_irq_disable();
+ mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
+
+ pr_debug("%s: Resumed from deep sleep\n", __func__);
+ break;
+#endif
- setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
- /* At this point, the CPU is asleep. */
+ case PM_SUSPEND_STANDBY:
+ local_irq_disable();
+ flush_dcache_L1();
- /* Upon resume, wait for SLP bit to be clear. */
- ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
- 10000, 10) ? 0 : -ETIMEDOUT;
- if (ret)
- dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
+ setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
+ /* At this point, the CPU is asleep. */
+
+ /* Upon resume, wait for SLP bit to be clear. */
+ result = spin_event_timeout(
+ (in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
+ 10000, 10);
+ if (!result) {
+ pr_err("%s: timeout waiting for SLP bit "
+ "to be cleared\n", __func__);
+ ret = -ETIMEDOUT;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
return ret;
}
static int pmc_suspend_valid(suspend_state_t state)
{
- if (state != PM_SUSPEND_STANDBY)
- return 0;
- return 1;
+ set_pm_suspend_state(state);
+
+ if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
+ ((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
+ return 1;
+
+ set_pm_suspend_state(PM_SUSPEND_ON);
+ return 0;
+}
+
+static void pmc_suspend_end(void)
+{
+ set_pm_suspend_state(PM_SUSPEND_ON);
}
static const struct platform_suspend_ops pmc_suspend_ops = {
.valid = pmc_suspend_valid,
.enter = pmc_suspend_enter,
+ .end = pmc_suspend_end,
};
-static int pmc_probe(struct platform_device *ofdev)
+static int pmc_probe(struct platform_device *pdev)
{
- pmc_regs = of_iomap(ofdev->dev.of_node, 0);
+ struct device_node *np = pdev->dev.of_node;
+
+ pmc_regs = of_iomap(np, 0);
if (!pmc_regs)
return -ENOMEM;
- pmc_dev = &ofdev->dev;
+ pmc_flag = PMC_SLEEP;
+ if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
+ pmc_flag |= PMC_DEEP_SLEEP;
+
+ if (of_device_is_compatible(np, "fsl,p1022-pmc"))
+ pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;
+
suspend_set_ops(&pmc_suspend_ops);
+ set_pm_suspend_state(PM_SUSPEND_ON);
+
+ pr_info("Freescale PMC driver\n");
return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 1f614fb..b082584 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -46,6 +46,37 @@
extern void init_fec_ioports(struct fs_platform_info*);
extern void init_smc_ioports(struct fs_uart_platform_info*);
static phys_addr_t immrbase = -1;
+static phys_addr_t dcsrbase = -1;
+
+phys_addr_t get_dcsrbase(void)
+{
+ struct device_node *np;
+ const __be32 *prop;
+ int size;
+ u32 naddr;
+
+ if (dcsrbase != -1)
+ return dcsrbase;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
+ if (!np)
+ return -1;
+
+ prop = of_get_property(np, "#address-cells", &size);
+ if (prop && size == 4)
+ naddr = be32_to_cpup(prop);
+ else
+ naddr = 2;
+
+ prop = of_get_property(np, "ranges", NULL);
+ if (prop)
+ dcsrbase = of_translate_address(np, prop + naddr);
+
+ of_node_put(np);
+
+ return dcsrbase;
+}
+EXPORT_SYMBOL(get_dcsrbase);
phys_addr_t get_immrbase(void)
{
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index db11b06..674ed67 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -7,6 +7,7 @@
struct spi_device;
+extern phys_addr_t get_dcsrbase(void);
extern phys_addr_t get_immrbase(void);
#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE)
extern u32 get_brgfreq(void);
@@ -44,5 +45,22 @@ struct platform_diu_data_ops {
void __noreturn fsl_hv_restart(char *cmd);
void __noreturn fsl_hv_halt(void);
+/*
+ * Cast the ccsrbar to 64-bit parameter so that the assembly
+ * code can be compatible with both 32-bit & 36-bit.
+ */
+extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
+
+#ifdef CONFIG_FSL_PMC
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
+void mpc85xx_pmc_set_lossless_ethernet(int enable);
+#else
+static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+ return -ENODEV;
+}
+#define mpc85xx_pmc_set_lossless_ethernet(enable) do { } while (0)
+#endif
+
#endif
#endif
--
1.7.1
^ permalink raw reply related
* [PATCH 5/5] powerpc:dts:pm: add power management node
From: Ran Wang @ 2018-03-29 1:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Rob Herring, Mark Rutland, Scott Wood, Kumar Gala, Li Yang
Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, devicetree,
linux-arm-kernel, Ran Wang
In-Reply-To: <20180329013143.22527-1-ran.wang_1@nxp.com>
Enable Power Management feature on device tree, including MPC8536,
MPC8544, MPC8548, MPC8572, P1010, P1020, P1021, P1022, P2020, P2041,
P3041, T104X, T1024.
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi | 14 ++++++-
arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/p1010si-post.dtsi | 8 ++++
arch/powerpc/boot/dts/fsl/p1020si-post.dtsi | 5 +++
arch/powerpc/boot/dts/fsl/p1021si-post.dtsi | 5 +++
arch/powerpc/boot/dts/fsl/p1022si-post.dtsi | 9 +++--
arch/powerpc/boot/dts/fsl/p2020si-post.dtsi | 14 +++++++
arch/powerpc/boot/dts/fsl/pq3-power.dtsi | 48 +++++++++++++++++++++++++
arch/powerpc/boot/dts/fsl/t1024rdb.dts | 2 +-
arch/powerpc/boot/dts/fsl/t1040rdb.dts | 2 +-
arch/powerpc/boot/dts/fsl/t1042rdb.dts | 2 +-
arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts | 2 +-
14 files changed, 108 insertions(+), 9 deletions(-)
create mode 100644 arch/powerpc/boot/dts/fsl/pq3-power.dtsi
diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
index 4193570..fba40a1 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
@@ -199,6 +199,10 @@
/include/ "pq3-dma-0.dtsi"
/include/ "pq3-etsec1-0.dtsi"
+ enet0: ethernet@24000 {
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec1_clk>;
+ };
/include/ "pq3-etsec1-timer-0.dtsi"
usb@22000 {
@@ -222,9 +226,10 @@
};
/include/ "pq3-etsec1-2.dtsi"
-
- ethernet@26000 {
+ enet2: ethernet@26000 {
cell-index = <1>;
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec3_clk>;
};
usb@2b000 {
@@ -249,4 +254,9 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
+ power@e0070 {
+ compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
index b68eb11..ea7416a 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
@@ -188,4 +188,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
index 579d76c..dddb737 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
@@ -156,4 +156,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
index 49294cf..40a6cff 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
@@ -193,4 +193,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
index 1b4aafc..47b62a8 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -173,6 +173,8 @@
/include/ "pq3-etsec2-0.dtsi"
enet0: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
+
queue-group@b0000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -181,6 +183,8 @@
/include/ "pq3-etsec2-1.dtsi"
enet1: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
+
queue-group@b1000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -189,6 +193,8 @@
/include/ "pq3-etsec2-2.dtsi"
enet2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
+
queue-group@b2000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -201,4 +207,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
index 642dc3a..cc4c746 100644
--- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
@@ -163,14 +163,17 @@
/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
};
/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
};
/include/ "pq3-etsec2-2.dtsi"
enet2: enet2_grp2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
};
global-utilities@e0000 {
@@ -178,6 +181,8 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
/include/ "pq3-etsec2-grp2-0.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
index 407cb5f..378195d 100644
--- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
@@ -159,14 +159,17 @@
/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
};
/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
};
/include/ "pq3-etsec2-2.dtsi"
enet2: enet2_grp2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
};
global-utilities@e0000 {
@@ -174,6 +177,8 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
&qe {
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
index 5f51b7b..6ac21e8 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -225,11 +225,13 @@
/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec1_clk>;
};
/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec2_clk>;
};
global-utilities@e0000 {
@@ -238,9 +240,10 @@
fsl,has-rstcr;
};
- power@e0070{
- compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
- reg = <0xe0070 0x20>;
+/include/ "pq3-power.dtsi"
+ power@e0070 {
+ compatible = "fsl,p1022-pmc", "fsl,mpc8536-pmc",
+ "fsl,mpc8548-pmc";
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
index 884e01b..2c4787c 100644
--- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
@@ -175,6 +175,10 @@
compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
};
/include/ "pq3-etsec1-0.dtsi"
+ enet0: ethernet@24000 {
+ fsl,pmc-handle = <&etsec1_clk>;
+
+ };
/include/ "pq3-etsec1-timer-0.dtsi"
ptp_clock@24e00 {
@@ -183,7 +187,15 @@
/include/ "pq3-etsec1-1.dtsi"
+ enet1: ethernet@25000 {
+ fsl,pmc-handle = <&etsec2_clk>;
+ };
+
/include/ "pq3-etsec1-2.dtsi"
+ enet2: ethernet@26000 {
+ fsl,pmc-handle = <&etsec3_clk>;
+ };
+
/include/ "pq3-esdhc-0.dtsi"
sdhc@2e000 {
compatible = "fsl,p2020-esdhc", "fsl,esdhc";
@@ -198,4 +210,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-power.dtsi b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
new file mode 100644
index 0000000..5a760b3
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
@@ -0,0 +1,48 @@
+/*
+ * PQ3 Power Management device tree stub
+ *
+ * Copyright 2012-2013 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+power@e0070 {
+ compatible = "fsl,mpc8548-pmc";
+ reg = <0xe0070 0x20>;
+
+ etsec1_clk: soc-clk@24 {
+ fsl,pmcdr-mask = <0x00000080>;
+ };
+ etsec2_clk: soc-clk@25 {
+ fsl,pmcdr-mask = <0x00000040>;
+ };
+ etsec3_clk: soc-clk@26 {
+ fsl,pmcdr-mask = <0x00000020>;
+ };
+};
diff --git a/arch/powerpc/boot/dts/fsl/t1024rdb.dts b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
index 73a6453..95fc694 100644
--- a/arch/powerpc/boot/dts/fsl/t1024rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
@@ -91,7 +91,7 @@
board-control@2,0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "fsl,t1024-cpld";
+ compatible = "fsl,t1024-cpld", "fsl,deepsleep-cpld";
reg = <3 0 0x300>;
ranges = <0 3 0 0x300>;
bank-width = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
index 65ff34c..825665c 100644
--- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
@@ -70,7 +70,7 @@
ifc: localbus@ffe124000 {
cpld@3,0 {
- compatible = "fsl,t1040rdb-cpld";
+ compatible = "fsl,t104xrdb-cpld", "fsl,deepsleep-cpld";
};
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1042rdb.dts b/arch/powerpc/boot/dts/fsl/t1042rdb.dts
index 3ebb712..0997643 100644
--- a/arch/powerpc/boot/dts/fsl/t1042rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042rdb.dts
@@ -68,7 +68,7 @@
ifc: localbus@ffe124000 {
cpld@3,0 {
- compatible = "fsl,t1042rdb-cpld";
+ compatible = "fsl,t104xrdb-cpld", "fsl,deepsleep-cpld";
};
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts b/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
index 8ec3ff4..b10cab1 100644
--- a/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
@@ -41,7 +41,7 @@
ifc: localbus@ffe124000 {
cpld@3,0 {
- compatible = "fsl,t1042rdb_pi-cpld";
+ compatible = "fsl,t104xrdb-cpld", "fsl,deepsleep-cpld";
};
};
--
1.7.1
^ permalink raw reply related
* [PATCH 3/5] powerpc/cache: add cache flush operation for various e500
From: Ran Wang @ 2018-03-29 1:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Rob Herring, Mark Rutland, Scott Wood, Kumar Gala, Li Yang
Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, devicetree,
linux-arm-kernel, Ran Wang
In-Reply-To: <20180329013143.22527-1-ran.wang_1@nxp.com>
Various e500 core have different cache architecture, so they
need different cache flush operations. Therefore, add a callback
function cpu_flush_caches to the struct cpu_spec. The cache flush
operation for the specific kind of e500 is selected at init time.
The callback function will flush all caches in the current cpu.
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
Reviewed-by: Yang Li <LeoLi@freescale.com>
Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
arch/powerpc/include/asm/cputable.h | 12 ++++
arch/powerpc/kernel/asm-offsets.c | 3 +
arch/powerpc/kernel/cpu_setup_fsl_booke.S | 81 +++++++++++++++++++++++++++++
arch/powerpc/kernel/cputable.c | 4 ++
4 files changed, 100 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index a2c5c95..364e6cf 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -44,6 +44,14 @@ enum powerpc_pmc_type {
extern int machine_check_e500(struct pt_regs *regs);
extern int machine_check_e200(struct pt_regs *regs);
extern int machine_check_47x(struct pt_regs *regs);
+
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+extern void __flush_caches_e500v2(void);
+extern void __flush_caches_e500mc(void);
+extern void __flush_caches_e5500(void);
+extern void __flush_caches_e6500(void);
+#endif
+
int machine_check_8xx(struct pt_regs *regs);
extern void cpu_down_flush_e500v2(void);
@@ -70,6 +78,10 @@ struct cpu_spec {
/* flush caches inside the current cpu */
void (*cpu_down_flush)(void);
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+ /* flush caches of the cpu which is running the function */
+ void (*cpu_flush_caches)(void);
+#endif
/* number of performance monitor counters */
unsigned int num_pmcs;
enum powerpc_pmc_type pmc_type;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index ea5eb91..cb4b869 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -351,6 +351,9 @@ int main(void)
OFFSET(CPU_SPEC_FEATURES, cpu_spec, cpu_features);
OFFSET(CPU_SPEC_SETUP, cpu_spec, cpu_setup);
OFFSET(CPU_SPEC_RESTORE, cpu_spec, cpu_restore);
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+ OFFSET(CPU_FLUSH_CACHES, cpu_spec, cpu_flush_caches);
+#endif
OFFSET(pbe_address, pbe, address);
OFFSET(pbe_orig_address, pbe, orig_address);
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 462aed9..e94eb41 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -345,3 +345,84 @@ _GLOBAL(cpu_down_flush_e5500)
/* L1 Data Cache of e6500 contains no modified data, no flush is required */
_GLOBAL(cpu_down_flush_e6500)
blr
+
+_GLOBAL(__flush_caches_e500v2)
+ mflr r0
+ bl flush_dcache_L1
+ mtlr r0
+ blr
+
+_GLOBAL(__flush_caches_e500mc)
+_GLOBAL(__flush_caches_e5500)
+ mflr r0
+ bl flush_dcache_L1
+ bl flush_backside_L2_cache
+ mtlr r0
+ blr
+
+/* L1 Data Cache of e6500 contains no modified data, no flush is required */
+_GLOBAL(__flush_caches_e6500)
+ blr
+
+ /* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(flush_disable_L2)
+ /* It's a write-through cache, so only invalidation is needed. */
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 1
+ rlwimi r4, r5, 30, 0xc0000000
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, 0x4000
+ bne 1b
+ mbar
+
+ blr
+
+ /* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(invalidate_enable_L2)
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 3
+ rlwimi r4, r5, 30, 0xc0000000
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, 0x4000
+ bne 1b
+ mbar
+
+ blr
+
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+ mflr r10
+ bl flush_dcache_L1 /* Flush L1 d-cache */
+ mtlr r10
+
+ mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ msync
+ isync
+ mtspr SPRN_L1CSR0, r4
+ isync
+
+1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
+ andi. r4, r4, 2
+ bne 1b
+
+ mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ mtspr SPRN_L1CSR1, r4
+ isync
+
+ blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index c40a9fc..eec3ca7 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2100,6 +2100,7 @@
.machine_check = machine_check_e500,
.platform = "ppc8548",
.cpu_down_flush = cpu_down_flush_e500v2,
+ .cpu_flush_caches = __flush_caches_e500v2,
},
#else
{ /* e500mc */
@@ -2120,6 +2121,7 @@
.machine_check = machine_check_e500mc,
.platform = "ppce500mc",
.cpu_down_flush = cpu_down_flush_e500mc,
+ .cpu_flush_caches = __flush_caches_e500mc,
},
#endif /* CONFIG_PPC_E500MC */
#endif /* CONFIG_PPC32 */
@@ -2145,6 +2147,7 @@
.machine_check = machine_check_e500mc,
.platform = "ppce5500",
.cpu_down_flush = cpu_down_flush_e5500,
+ .cpu_flush_caches = __flush_caches_e5500,
},
{ /* e6500 */
.pvr_mask = 0xffff0000,
@@ -2168,6 +2171,7 @@
.machine_check = machine_check_e500mc,
.platform = "ppce6500",
.cpu_down_flush = cpu_down_flush_e6500,
+ .cpu_flush_caches = __flush_caches_e6500,
},
#endif /* CONFIG_PPC_E500MC */
#ifdef CONFIG_PPC32
--
1.7.1
^ permalink raw reply related
* [PATCH 1/5] powerpc/pm: Fix suspend=n in menuconfig for e500mc platforms.
From: Ran Wang @ 2018-03-29 1:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Rob Herring, Mark Rutland, Scott Wood, Kumar Gala, Li Yang
Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, devicetree,
linux-arm-kernel, Ran Wang
Also, unselect FSL_PMC which is for older platfroms instead.
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
arch/powerpc/Kconfig | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 73ce5dd..ed60c83 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -316,7 +316,7 @@ config ARCH_HIBERNATION_POSSIBLE
config ARCH_SUSPEND_POSSIBLE
def_bool y
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
- (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+ FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \
|| 44x || 40x
config PPC_DCR_NATIVE
@@ -940,8 +940,6 @@ config FSL_PCI
config FSL_PMC
bool
- default y
- depends on SUSPEND && (PPC_85xx || PPC_86xx)
help
Freescale MPC85xx/MPC86xx power management controller support
(suspend/resume). For MPC83xx see platforms/83xx/suspend.c
--
1.7.1
^ permalink raw reply related
* [PATCH 2/5] drivers/soc/fsl: add EPU FSM configuration for deep sleep
From: Ran Wang @ 2018-03-29 1:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Rob Herring, Mark Rutland, Scott Wood, Kumar Gala, Li Yang
Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, devicetree,
linux-arm-kernel, Ran Wang
In-Reply-To: <20180329013143.22527-1-ran.wang_1@nxp.com>
In the last stage of deep sleep, software will trigger a Finite
State Machine (FSM) to control the hardware procedure, such a
board isolation, killing PLLs, removing power, and so on.
When the system is waked up by an interrupt, the FSM controls
the hardware to complete the early resume procedure.
This patch configure the EPU FSM preparing for deep sleep.
Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
drivers/soc/fsl/Kconfig | 7 +
drivers/soc/fsl/Makefile | 1 +
drivers/soc/fsl/sleep_fsm.c | 279 +++++++++++++++++++++++++++++++++++++++++++
drivers/soc/fsl/sleep_fsm.h | 130 ++++++++++++++++++++
4 files changed, 417 insertions(+), 0 deletions(-)
create mode 100644 drivers/soc/fsl/sleep_fsm.c
create mode 100644 drivers/soc/fsl/sleep_fsm.h
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
index 7a9fb9b..4222bd5 100644
--- a/drivers/soc/fsl/Kconfig
+++ b/drivers/soc/fsl/Kconfig
@@ -16,3 +16,10 @@ config FSL_GUTS
Initially only reading SVR and registering soc device are supported.
Other guts accesses, such as reading RCW, should eventually be moved
into this driver as well.
+
+config FSL_SLEEP_FSM
+ bool
+ help
+ This driver configures a hardware FSM (Finite State Machine) for deep sleep.
+ The FSM is used to finish clean-ups at the last stage of system entering deep
+ sleep, and also wakes up system when a wake up event happens.
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
index 44b3beb..28c38c3 100644
--- a/drivers/soc/fsl/Makefile
+++ b/drivers/soc/fsl/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_FSL_DPAA) += qbman/
obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
obj-$(CONFIG_FSL_GUTS) += guts.o
+obj-$(CONFIG_FSL_SLEEP_FSM) += sleep_fsm.o
diff --git a/drivers/soc/fsl/sleep_fsm.c b/drivers/soc/fsl/sleep_fsm.c
new file mode 100644
index 0000000..378857f
--- /dev/null
+++ b/drivers/soc/fsl/sleep_fsm.c
@@ -0,0 +1,279 @@
+/*
+ * deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2018 NXP
+ *
+ * Author: Hongbo Zhang <hongbo.zhang@freescale.com>
+ * Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "sleep_fsm.h"
+/*
+ * These values are from chip's reference manual. For example,
+ * the values for T1040 can be found in "8.4.3.8 Programming
+ * supporting deep sleep mode" of Chapter 8 "Run Control and
+ * Power Management (RCPM)".
+ * The default value can be applied to T104x, LS1021.
+ */
+struct fsm_reg_vals epu_default_val[] = {
+ /* EPGCR (Event Processor Global Control Register) */
+ {EPGCR, 0},
+ /* EPECR (Event Processor Event Control Registers) */
+ {EPECR0 + EPECR_STRIDE * 0, 0},
+ {EPECR0 + EPECR_STRIDE * 1, 0},
+ {EPECR0 + EPECR_STRIDE * 2, 0xF0004004},
+ {EPECR0 + EPECR_STRIDE * 3, 0x80000084},
+ {EPECR0 + EPECR_STRIDE * 4, 0x20000084},
+ {EPECR0 + EPECR_STRIDE * 5, 0x08000004},
+ {EPECR0 + EPECR_STRIDE * 6, 0x80000084},
+ {EPECR0 + EPECR_STRIDE * 7, 0x80000084},
+ {EPECR0 + EPECR_STRIDE * 8, 0x60000084},
+ {EPECR0 + EPECR_STRIDE * 9, 0x08000084},
+ {EPECR0 + EPECR_STRIDE * 10, 0x42000084},
+ {EPECR0 + EPECR_STRIDE * 11, 0x90000084},
+ {EPECR0 + EPECR_STRIDE * 12, 0x80000084},
+ {EPECR0 + EPECR_STRIDE * 13, 0x08000084},
+ {EPECR0 + EPECR_STRIDE * 14, 0x02000084},
+ {EPECR0 + EPECR_STRIDE * 15, 0x00000004},
+ /*
+ * EPEVTCR (Event Processor EVT Pin Control Registers)
+ * SCU8 triger EVT2, and SCU11 triger EVT9
+ */
+ {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x80000001},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0},
+ {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB0000001},
+ /* EPCMPR (Event Processor Counter Compare Registers) */
+ {EPCMPR0 + EPCMPR_STRIDE * 0, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 1, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 2, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 3, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 4, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 5, 0x00000020},
+ {EPCMPR0 + EPCMPR_STRIDE * 6, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 7, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 8, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 9, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 10, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 11, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 12, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 13, 0},
+ {EPCMPR0 + EPCMPR_STRIDE * 14, 0x000000FF},
+ {EPCMPR0 + EPCMPR_STRIDE * 15, 0x000000FF},
+ /* EPCCR (Event Processor Counter Control Registers) */
+ {EPCCR0 + EPCCR_STRIDE * 0, 0},
+ {EPCCR0 + EPCCR_STRIDE * 1, 0},
+ {EPCCR0 + EPCCR_STRIDE * 2, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 3, 0},
+ {EPCCR0 + EPCCR_STRIDE * 4, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 5, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 6, 0},
+ {EPCCR0 + EPCCR_STRIDE * 7, 0},
+ {EPCCR0 + EPCCR_STRIDE * 8, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 9, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 10, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 11, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 12, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 13, 0},
+ {EPCCR0 + EPCCR_STRIDE * 14, 0x92840000},
+ {EPCCR0 + EPCCR_STRIDE * 15, 0x92840000},
+ /* EPSMCR (Event Processor SCU Mux Control Registers) */
+ {EPSMCR0 + EPSMCR_STRIDE * 0, 0},
+ {EPSMCR0 + EPSMCR_STRIDE * 1, 0},
+ {EPSMCR0 + EPSMCR_STRIDE * 2, 0x6C700000},
+ {EPSMCR0 + EPSMCR_STRIDE * 3, 0x2F000000},
+ {EPSMCR0 + EPSMCR_STRIDE * 4, 0x002F0000},
+ {EPSMCR0 + EPSMCR_STRIDE * 5, 0x00002E00},
+ {EPSMCR0 + EPSMCR_STRIDE * 6, 0x7C000000},
+ {EPSMCR0 + EPSMCR_STRIDE * 7, 0x30000000},
+ {EPSMCR0 + EPSMCR_STRIDE * 8, 0x64300000},
+ {EPSMCR0 + EPSMCR_STRIDE * 9, 0x00003000},
+ {EPSMCR0 + EPSMCR_STRIDE * 10, 0x65000030},
+ {EPSMCR0 + EPSMCR_STRIDE * 11, 0x31740000},
+ {EPSMCR0 + EPSMCR_STRIDE * 12, 0x7F000000},
+ {EPSMCR0 + EPSMCR_STRIDE * 13, 0x00003100},
+ {EPSMCR0 + EPSMCR_STRIDE * 14, 0x00000031},
+ {EPSMCR0 + EPSMCR_STRIDE * 15, 0x76000000},
+ /* EPACR (Event Processor Action Control Registers) */
+ {EPACR0 + EPACR_STRIDE * 0, 0},
+ {EPACR0 + EPACR_STRIDE * 1, 0},
+ {EPACR0 + EPACR_STRIDE * 2, 0},
+ {EPACR0 + EPACR_STRIDE * 3, 0x00000080},
+ {EPACR0 + EPACR_STRIDE * 4, 0},
+ {EPACR0 + EPACR_STRIDE * 5, 0x00000040},
+ {EPACR0 + EPACR_STRIDE * 6, 0},
+ {EPACR0 + EPACR_STRIDE * 7, 0},
+ {EPACR0 + EPACR_STRIDE * 8, 0},
+ {EPACR0 + EPACR_STRIDE * 9, 0x0000001C},
+ {EPACR0 + EPACR_STRIDE * 10, 0x00000020},
+ {EPACR0 + EPACR_STRIDE * 11, 0},
+ {EPACR0 + EPACR_STRIDE * 12, 0x00000003},
+ {EPACR0 + EPACR_STRIDE * 13, 0x06000000},
+ {EPACR0 + EPACR_STRIDE * 14, 0x04000000},
+ {EPACR0 + EPACR_STRIDE * 15, 0x02000000},
+ /* EPIMCR (Event Processor Input Mux Control Registers) */
+ {EPIMCR0 + EPIMCR_STRIDE * 0, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 1, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 2, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 3, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 4, 0x44000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 5, 0x40000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 6, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 7, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 8, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 9, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 10, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 11, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 12, 0x44000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 13, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 14, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 15, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 16, 0x6A000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 17, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 18, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 19, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 20, 0x48000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 21, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 22, 0x6C000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 23, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 24, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 25, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 26, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 27, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 28, 0x76000000},
+ {EPIMCR0 + EPIMCR_STRIDE * 29, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 30, 0},
+ {EPIMCR0 + EPIMCR_STRIDE * 31, 0x76000000},
+ /* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
+ {EPXTRIGCR, 0x0000FFDF},
+ /* end */
+ {FSM_END_FLAG, 0},
+};
+
+struct fsm_reg_vals npc_default_val[] = {
+ /* NPC triggered Memory-Mapped Access Registers */
+ {NCR, 0x80000000},
+ {MCCR1, 0},
+ {MCSR1, 0},
+ {MMAR1LO, 0},
+ {MMAR1HI, 0},
+ {MMDR1, 0},
+ {MCSR2, 0},
+ {MMAR2LO, 0},
+ {MMAR2HI, 0},
+ {MMDR2, 0},
+ {MCSR3, 0x80000000},
+ {MMAR3LO, 0x000E2130},
+ {MMAR3HI, 0x00030000},
+ {MMDR3, 0x00020000},
+ /* end */
+ {FSM_END_FLAG, 0},
+};
+
+/**
+ * fsl_fsm_setup - Configure EPU's FSM registers
+ * @base: the base address of registers
+ * @val: Pointer to address-value pairs for FSM registers
+ */
+void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val)
+{
+ struct fsm_reg_vals *data = val;
+
+ BUG_ON(!base || !data);
+ while (data->offset != FSM_END_FLAG) {
+ iowrite32be(data->value, base + data->offset);
+ data++;
+ }
+}
+
+void fsl_epu_setup_default(void __iomem *epu_base)
+{
+ fsl_fsm_setup(epu_base, epu_default_val);
+}
+
+void fsl_npc_setup_default(void __iomem *npc_base)
+{
+ fsl_fsm_setup(npc_base, npc_default_val);
+}
+
+void fsl_epu_clean_default(void __iomem *epu_base)
+{
+ u32 offset;
+
+ /* follow the exact sequence to clear the registers */
+ /* Clear EPACRn */
+ for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPEVTCRn */
+ for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPGCR */
+ iowrite32be(0, epu_base + EPGCR);
+
+ /* Clear EPSMCRn */
+ for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPCCRn */
+ for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPCMPRn */
+ for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPCTRn */
+ for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPIMCRn */
+ for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+
+ /* Clear EPXTRIGCRn */
+ iowrite32be(0, epu_base + EPXTRIGCR);
+
+ /* Clear EPECRn */
+ for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE)
+ iowrite32be(0, epu_base + offset);
+}
diff --git a/drivers/soc/fsl/sleep_fsm.h b/drivers/soc/fsl/sleep_fsm.h
new file mode 100644
index 0000000..e0013c0
--- /dev/null
+++ b/drivers/soc/fsl/sleep_fsm.h
@@ -0,0 +1,130 @@
+/*
+ * deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2018 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSL_SLEEP_FSM_H
+#define _FSL_SLEEP_FSM_H
+
+#define FSL_STRIDE_4B 4
+#define FSL_STRIDE_8B 8
+
+/* End flag */
+#define FSM_END_FLAG 0xFFFFFFFFUL
+
+/* Block offsets */
+#define RCPM_BLOCK_OFFSET 0x00022000
+#define EPU_BLOCK_OFFSET 0x00000000
+#define NPC_BLOCK_OFFSET 0x00001000
+
+/* EPGCR (Event Processor Global Control Register) */
+#define EPGCR 0x000
+
+/* EPEVTCR0-9 (Event Processor EVT Pin Control Registers) */
+#define EPEVTCR0 0x050
+#define EPEVTCR9 0x074
+#define EPEVTCR_STRIDE FSL_STRIDE_4B
+
+/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
+#define EPXTRIGCR 0x090
+
+/* EPIMCR0-31 (Event Processor Input Mux Control Registers) */
+#define EPIMCR0 0x100
+#define EPIMCR31 0x17C
+#define EPIMCR_STRIDE FSL_STRIDE_4B
+
+/* EPSMCR0-15 (Event Processor SCU Mux Control Registers) */
+#define EPSMCR0 0x200
+#define EPSMCR15 0x278
+#define EPSMCR_STRIDE FSL_STRIDE_8B
+
+/* EPECR0-15 (Event Processor Event Control Registers) */
+#define EPECR0 0x300
+#define EPECR15 0x33C
+#define EPECR_STRIDE FSL_STRIDE_4B
+
+/* EPACR0-15 (Event Processor Action Control Registers) */
+#define EPACR0 0x400
+#define EPACR15 0x43C
+#define EPACR_STRIDE FSL_STRIDE_4B
+
+/* EPCCRi0-15 (Event Processor Counter Control Registers) */
+#define EPCCR0 0x800
+#define EPCCR15 0x83C
+#define EPCCR31 0x87C
+#define EPCCR_STRIDE FSL_STRIDE_4B
+
+/* EPCMPR0-15 (Event Processor Counter Compare Registers) */
+#define EPCMPR0 0x900
+#define EPCMPR15 0x93C
+#define EPCMPR31 0x97C
+#define EPCMPR_STRIDE FSL_STRIDE_4B
+
+/* EPCTR0-31 (Event Processor Counter Register) */
+#define EPCTR0 0xA00
+#define EPCTR31 0xA7C
+#define EPCTR_STRIDE FSL_STRIDE_4B
+
+/* NPC triggered Memory-Mapped Access Registers */
+#define NCR 0x000
+#define MCCR1 0x0CC
+#define MCSR1 0x0D0
+#define MMAR1LO 0x0D4
+#define MMAR1HI 0x0D8
+#define MMDR1 0x0DC
+#define MCSR2 0x0E0
+#define MMAR2LO 0x0E4
+#define MMAR2HI 0x0E8
+#define MMDR2 0x0EC
+#define MCSR3 0x0F0
+#define MMAR3LO 0x0F4
+#define MMAR3HI 0x0F8
+#define MMDR3 0x0FC
+
+/* RCPM Core State Action Control Register 0 */
+#define CSTTACR0 0xB00
+
+/* RCPM Core Group 1 Configuration Register 0 */
+#define CG1CR0 0x31C
+
+struct fsm_reg_vals {
+ u32 offset;
+ u32 value;
+};
+
+void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val);
+void fsl_epu_setup_default(void __iomem *epu_base);
+void fsl_npc_setup_default(void __iomem *npc_base);
+void fsl_epu_clean_default(void __iomem *epu_base);
+
+#endif /* _FSL_SLEEP_FSM_H */
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 12/14] powerpc: pass node id into create_section_mapping
From: Michael Ellerman @ 2018-03-29 5:51 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180213150824.27689-13-npiggin@gmail.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
> index 328ff9abc333..435b19e74508 100644
> --- a/arch/powerpc/mm/pgtable-radix.c
> +++ b/arch/powerpc/mm/pgtable-radix.c
> @@ -862,9 +862,9 @@ static void remove_pagetable(unsigned long start, unsigned long end)
> radix__flush_tlb_kernel_range(start, end);
> }
>
> -int __ref radix__create_section_mapping(unsigned long start, unsigned long end)
> +int __ref radix__create_section_mapping(unsigned long start, unsigned long end, int nid)
> {
> - return create_physical_mapping(start, end);
> + return create_physical_mapping(start, end, nid);
> }
This got a little muddled. We add the nid argument here, but
create_physical_mapping() doesn't take it until patch 14.
I managed to fix it by rearranging the last three patches and fiddling
things a bit. If you can check the result once I push that would be good.
cheers
^ permalink raw reply
* Re: [PATCH 09/14] powerpc/64: defer paca allocation until memory topology is discovered
From: Michael Ellerman @ 2018-03-29 5:51 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180213150824.27689-10-npiggin@gmail.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> ---
> arch/powerpc/include/asm/paca.h | 3 +-
> arch/powerpc/kernel/paca.c | 90 ++++++++++++--------------------------
> arch/powerpc/kernel/prom.c | 5 ++-
> arch/powerpc/kernel/setup-common.c | 24 +++++++---
> 4 files changed, 51 insertions(+), 71 deletions(-)
Added SOB.
cheers
^ permalink raw reply
* Re: [PATCH 08/14] powerpc/setup: cpu_to_phys_id array
From: Michael Ellerman @ 2018-03-29 5:51 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180213150824.27689-9-npiggin@gmail.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> Build an array that finds hardware CPU number from logical CPU
> number in firmware CPU discovery. Use that rather than setting
> paca of other CPUs directly, to begin with. Subsequent patch will
> not have pacas allocated at this point.
> ---
> arch/powerpc/include/asm/smp.h | 1 +
> arch/powerpc/kernel/prom.c | 7 +++++++
> arch/powerpc/kernel/setup-common.c | 15 ++++++++++++++-
> 3 files changed, 22 insertions(+), 1 deletion(-)
Added SOB.
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index 4dffef947b8a..5979e34ba90e 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -874,5 +874,12 @@ EXPORT_SYMBOL(cpu_to_chip_id);
>
> bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
> {
> + /*
> + * Early firmware scanning must use this rather than
> + * get_hard_smp_processor_id because we don't have pacas allocated
> + * until memory topology is discovered.
> + */
> + if (cpu_to_phys_id != NULL)
> + return (int)phys_id == cpu_to_phys_id[cpu];
This needed an #ifdef CONFIG_SMP.
cheers
^ permalink raw reply
* Re: [PATCH 10/14] powerpc/64: allocate pacas per node
From: Michael Ellerman @ 2018-03-29 5:50 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180213150824.27689-11-npiggin@gmail.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> Per-node allocations are possible on 64s with radix that does
> not have the bolted SLB limitation.
>
> Hash would be able to do the same if all CPUs had the bottom of
> their node-local memory bolted as well. This is left as an
> exercise for the reader.
> ---
> arch/powerpc/kernel/paca.c | 41 +++++++++++++++++++++++++++++++++++------
> arch/powerpc/kernel/setup_64.c | 4 ++++
> 2 files changed, 39 insertions(+), 6 deletions(-)
Added SOB.
cheers
^ permalink raw reply
* [PATCH] powerpc/fscr: Enable interrupts earlier before calling get_user()
From: Anshuman Khandual @ 2018-03-29 4:33 UTC (permalink / raw)
To: linuxppc-dev
The function get_user() can sleep while trying to fetch instruction
from user address space and causes the following warning from the
scheduler.
BUG: sleeping function called from invalid context
Though interrupts get enabled back but it happens bit later after
get_user() is called. This change moves enabling these interrupts
earlier covering the function get_user(). While at this, lets check
for kernel mode and crash as this interrupt should not have been
triggered from the kernel context.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/kernel/traps.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1e48d15..4d5a55e 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1611,6 +1611,13 @@ void facility_unavailable_exception(struct pt_regs *regs)
else
value = mfspr(SPRN_FSCR);
+ /* We should not have taken this interrupt in kernel */
+ BUG_ON(!user_mode(regs));
+
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
status = value >> 56;
if (status == FSCR_DSCR_LG) {
/*
@@ -1683,10 +1690,6 @@ void facility_unavailable_exception(struct pt_regs *regs)
facility_strings[status])
facility = facility_strings[status];
- /* We restore the interrupt state now */
- if (!arch_irq_disabled_regs(regs))
- local_irq_enable();
-
pr_err_ratelimited("%sFacility '%s' unavailable (%d), exception at 0x%lx, MSR=%lx\n",
hv ? "Hypervisor " : "", facility, status, regs->nip, regs->msr);
--
2.9.3
^ permalink raw reply related
* Re: [PATCH] powerpc/powernv/nvram: opal_nvram_write handle unknown OPAL errors
From: Stewart Smith @ 2018-03-29 4:27 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180326150233.23089-1-npiggin@gmail.com>
Nicholas Piggin <npiggin@gmail.com> writes:
> opal_nvram_write currently just assumes success if it encounters an
> error other than OPAL_BUSY or OPAL_BUSY_EVENT. Have it return -EIO
> on other errors instead.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> arch/powerpc/platforms/powernv/opal-nvram.c | 2 ++
> 1 file changed, 2 insertions(+)
Acked-by: Stewart Smith <stewart@linux.ibm.com>
--
Stewart Smith
OPAL Architect, IBM.
^ 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