* Re: [PATCH] powerpc64/ftrace: Include ftrace.h needed for enable/disable calls
From: Luke Dashjr @ 2018-08-17 15:16 UTC (permalink / raw)
To: Naveen N. Rao
Cc: Ingo Molnar, Paul Mackerras, Steven Rostedt, kvm-ppc,
linuxppc-dev, Michael Ellerman
In-Reply-To: <1534501411.hvsbp9w9ur.naveen@linux.ibm.com>
On Friday 17 August 2018 10:25:40 Naveen N. Rao wrote:
> Luke Dashjr wrote:
> > this_cpu_disable_ftrace and this_cpu_enable_ftrace are inlines in
> > ftrace.h Without it included, the build fails.
>
> I'm unable to reproduce this. Can you share your .config and the build
> environment?
https://luke.dashjr.org/tmp/code/4.18-config.xz
Gentoo GNU/Linux (mostly stable keywords) on a Raptor Talos II POWER9 system.
> > Fixes: a4bc64d305af ("powerpc64/ftrace: Disable ftrace during kvm
> > entry/exit") Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>
> > Cc: stable@vger.kernel.org
> > ---
> > arch/powerpc/kvm/book3s_hv.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> > index ee4a8854985e..15c2c64291f4 100644
> > --- a/arch/powerpc/kvm/book3s_hv.c
> > +++ b/arch/powerpc/kvm/book3s_hv.c
> > @@ -46,6 +46,7 @@
> > #include <linux/compiler.h>
> > #include <linux/of.h>
> >
> > +#include <asm/ftrace.h>
> > #include <asm/reg.h>
> > #include <asm/ppc-opcode.h>
> > #include <asm/asm-prototypes.h>
>
> In any case, this change itself looks alright to me. So:
> Acked-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
>
>
> Thanks,
> Naveen
^ permalink raw reply
* Re: [PATCH 3/3] powerpc/mm/ Add proper pte access check helper
From: Christophe LEROY @ 2018-08-17 15:12 UTC (permalink / raw)
To: Aneesh Kumar K.V, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <20171204021912.25974-3-aneesh.kumar@linux.vnet.ibm.com>
Le 04/12/2017 à 03:19, Aneesh Kumar K.V a écrit :
> pte_access_premitted get called in get_user_pages_fast path. If we have marked
> the pte PROT_NONE, we should not allow a read access on the address. With
> the current implementation we are not checking the READ and only check for
> WRITE. This is needed on archs like ppc64 that implement PROT_NONE using
> _PAGE_USER access instead of _PAGE_PRESENT. Also add pte_user check just to make sure
> we are not accessing kernel mapping.
>
> Even though there is code duplication, keeping the low level pte accessors
> different for different platforms helps in code readability.
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/book3s/32/pgtable.h | 23 +++++++++++++++++++++++
> arch/powerpc/include/asm/nohash/pgtable.h | 23 +++++++++++++++++++++++
> 2 files changed, 46 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
> index 016579ef16d3..30a155c0a6b0 100644
> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
> @@ -311,6 +311,29 @@ static inline int pte_present(pte_t pte)
> return pte_val(pte) & _PAGE_PRESENT;
> }
>
> +/*
> + * We only find page table entry in the last level
> + * Hence no need for other accessors
> + */
> +#define pte_access_permitted pte_access_permitted
> +static inline bool pte_access_permitted(pte_t pte, bool write)
> +{
> + unsigned long pteval = pte_val(pte);
> + /*
> + * A read-only access is controlled by _PAGE_USER bit.
> + * We have _PAGE_READ set for WRITE and EXECUTE
> + */
> + unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;
> +
> + if (write)
> + need_pte_bits |= _PAGE_WRITE;
> +
> + if ((pteval & need_pte_bits) != need_pte_bits)
> + return false;
> +
> + return true;
> +}
> +
> /* Conversion functions: convert a page and protection to a page entry,
> * and a page entry and page directory to the page they refer to.
> *
> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
> index 5c68f4a59f75..fc4376c8d444 100644
> --- a/arch/powerpc/include/asm/nohash/pgtable.h
> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
> @@ -45,6 +45,29 @@ static inline int pte_present(pte_t pte)
> return pte_val(pte) & _PAGE_PRESENT;
> }
>
> +/*
> + * We only find page table entry in the last level
> + * Hence no need for other accessors
> + */
> +#define pte_access_permitted pte_access_permitted
> +static inline bool pte_access_permitted(pte_t pte, bool write)
> +{
> + unsigned long pteval = pte_val(pte);
> + /*
> + * A read-only access is controlled by _PAGE_USER bit.
> + * We have _PAGE_READ set for WRITE and EXECUTE
> + */
Not fully right. asm/pte-common.h defines:
#define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_NA)
#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \
_PAGE_EXEC)
#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
_PAGE_EXEC)
#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
_PAGE_EXEC)
On the 8xx, _PAGE_USER = 0
> + unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;
> +
> + if (write)
> + need_pte_bits |= _PAGE_WRITE;
> +
> + if ((pteval & need_pte_bits) != need_pte_bits)
> + return false;
This test is not fully correct:
- To check access(read) permission, you also have to check that _PAGE_NA
is not set.
- To check write permission, you also have to check that neither
_PAGE_NA nor _PAGE_RO are set.
On the 8xx, you have:
_PAGE_RW = _PAGE_WRITE = 0
_PAGE_NA = 0x0200
_PAGE_RO = 0x0600
Christophe
> +
> + return true;
> +}
> +
> /* Conversion functions: convert a page and protection to a page entry,
> * and a page entry and page directory to the page they refer to.
> *
>
^ permalink raw reply
* [PATCH v5] powerpc/topology: Get topology for shared processors at boot
From: Srikar Dronamraju @ 2018-08-17 14:54 UTC (permalink / raw)
To: linuxppc-dev, Michael Ellerman
Cc: Michael Bringmann, Manjunatha H R, Srikar Dronamraju,
Michal Suchanek
On a shared lpar, Phyp will not update the cpu associativity at boot
time. Just after the boot system does recognize itself as a shared lpar and
trigger a request for correct cpu associativity. But by then the scheduler
would have already created/destroyed its sched domains.
This causes
- Broken load balance across Nodes causing islands of cores.
- Performance degradation esp if the system is lightly loaded
- dmesg to wrongly report all cpus to be in Node 0.
- Messages in dmesg saying borken topology.
- With commit 051f3ca02e46 ("sched/topology: Introduce NUMA identity
node sched domain"), can cause rcu stalls at boot up.
>From a scheduler maintainer's perspective, moving cpus from one node to
another or creating more numa levels after boot is not appropriate
without some notification to the user space.
https://lore.kernel.org/lkml/20150406214558.GA38501@linux.vnet.ibm.com/T/#u
The sched_domains_numa_masks table which is used to generate cpumasks is
only created at boot time just before creating sched domains and never
updated. Hence, its better to get the topology correct before the sched
domains are created.
For example on 64 core Power 8 shared lpar, dmesg reports
[ 2.088360] Brought up 512 CPUs
[ 2.088368] Node 0 CPUs: 0-511
[ 2.088371] Node 1 CPUs:
[ 2.088373] Node 2 CPUs:
[ 2.088375] Node 3 CPUs:
[ 2.088376] Node 4 CPUs:
[ 2.088378] Node 5 CPUs:
[ 2.088380] Node 6 CPUs:
[ 2.088382] Node 7 CPUs:
[ 2.088386] Node 8 CPUs:
[ 2.088388] Node 9 CPUs:
[ 2.088390] Node 10 CPUs:
[ 2.088392] Node 11 CPUs:
...
[ 3.916091] BUG: arch topology borken
[ 3.916103] the DIE domain not a subset of the NUMA domain
[ 3.916105] BUG: arch topology borken
[ 3.916106] the DIE domain not a subset of the NUMA domain
...
numactl/lscpu output will still be correct with cores spreading across
all nodes.
Socket(s): 64
NUMA node(s): 12
Model: 2.0 (pvr 004d 0200)
Model name: POWER8 (architected), altivec supported
Hypervisor vendor: pHyp
Virtualization type: para
L1d cache: 64K
L1i cache: 32K
NUMA node0 CPU(s): 0-7,32-39,64-71,96-103,176-183,272-279,368-375,464-471
NUMA node1 CPU(s): 8-15,40-47,72-79,104-111,184-191,280-287,376-383,472-479
NUMA node2 CPU(s): 16-23,48-55,80-87,112-119,192-199,288-295,384-391,480-487
NUMA node3 CPU(s): 24-31,56-63,88-95,120-127,200-207,296-303,392-399,488-495
NUMA node4 CPU(s): 208-215,304-311,400-407,496-503
NUMA node5 CPU(s): 168-175,264-271,360-367,456-463
NUMA node6 CPU(s): 128-135,224-231,320-327,416-423
NUMA node7 CPU(s): 136-143,232-239,328-335,424-431
NUMA node8 CPU(s): 216-223,312-319,408-415,504-511
NUMA node9 CPU(s): 144-151,240-247,336-343,432-439
NUMA node10 CPU(s): 152-159,248-255,344-351,440-447
NUMA node11 CPU(s): 160-167,256-263,352-359,448-455
Currently on this lpar, the scheduler detects 2 levels of Numa and
created numa sched domains for all cpus, but it finds a single DIE
domain consisting of all cpus. Hence it deletes all numa sched domains.
To address this, detect the shared processor and update topology soon after
cpus are setup so that correct topology is updated just before scheduler
creates sched domain.
With the fix, dmesg reports
[ 0.491336] numa: Node 0 CPUs: 0-7 32-39 64-71 96-103 176-183 272-279 368-375 464-471
[ 0.491351] numa: Node 1 CPUs: 8-15 40-47 72-79 104-111 184-191 280-287 376-383 472-479
[ 0.491359] numa: Node 2 CPUs: 16-23 48-55 80-87 112-119 192-199 288-295 384-391 480-487
[ 0.491366] numa: Node 3 CPUs: 24-31 56-63 88-95 120-127 200-207 296-303 392-399 488-495
[ 0.491374] numa: Node 4 CPUs: 208-215 304-311 400-407 496-503
[ 0.491379] numa: Node 5 CPUs: 168-175 264-271 360-367 456-463
[ 0.491384] numa: Node 6 CPUs: 128-135 224-231 320-327 416-423
[ 0.491389] numa: Node 7 CPUs: 136-143 232-239 328-335 424-431
[ 0.491394] numa: Node 8 CPUs: 216-223 312-319 408-415 504-511
[ 0.491399] numa: Node 9 CPUs: 144-151 240-247 336-343 432-439
[ 0.491404] numa: Node 10 CPUs: 152-159 248-255 344-351 440-447
[ 0.491409] numa: Node 11 CPUs: 160-167 256-263 352-359 448-455
and lscpu would also report
Socket(s): 64
NUMA node(s): 12
Model: 2.0 (pvr 004d 0200)
Model name: POWER8 (architected), altivec supported
Hypervisor vendor: pHyp
Virtualization type: para
L1d cache: 64K
L1i cache: 32K
NUMA node0 CPU(s): 0-7,32-39,64-71,96-103,176-183,272-279,368-375,464-471
NUMA node1 CPU(s): 8-15,40-47,72-79,104-111,184-191,280-287,376-383,472-479
NUMA node2 CPU(s): 16-23,48-55,80-87,112-119,192-199,288-295,384-391,480-487
NUMA node3 CPU(s): 24-31,56-63,88-95,120-127,200-207,296-303,392-399,488-495
NUMA node4 CPU(s): 208-215,304-311,400-407,496-503
NUMA node5 CPU(s): 168-175,264-271,360-367,456-463
NUMA node6 CPU(s): 128-135,224-231,320-327,416-423
NUMA node7 CPU(s): 136-143,232-239,328-335,424-431
NUMA node8 CPU(s): 216-223,312-319,408-415,504-511
NUMA node9 CPU(s): 144-151,240-247,336-343,432-439
NUMA node10 CPU(s): 152-159,248-255,344-351,440-447
NUMA node11 CPU(s): 160-167,256-263,352-359,448-455
Previous attempt to solve this problem
https://patchwork.ozlabs.org/patch/530090/
Reported-by: Manjunatha H R <manjuhr1@in.ibm.com>
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
---
Changelog v1->v2
Fix compile warnings and checkpatch issues.
Changelog v2->v3
Fix compile warnings on !CONFIG_SMP
Changelog v3->v4
Now do early topology init on shared processor. Earlier we used to do only
for vphn enabled. However we want this update to happen even when
topology_updates=off. Changed patch title accordingly
arch/powerpc/include/asm/topology.h | 5 +++++
arch/powerpc/kernel/smp.c | 6 ++++++
arch/powerpc/mm/numa.c | 22 ++++++++++++++--------
3 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 16b077801a5f..a4a718dbfec6 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -92,6 +92,7 @@ extern int stop_topology_update(void);
extern int prrn_is_enabled(void);
extern int find_and_online_cpu_nid(int cpu);
extern int timed_topology_update(int nsecs);
+extern void __init shared_proc_topology_init(void);
#else
static inline int start_topology_update(void)
{
@@ -113,6 +114,10 @@ static inline int timed_topology_update(int nsecs)
{
return 0;
}
+
+#ifdef CONFIG_SMP
+static inline void shared_proc_topology_init(void) {}
+#endif
#endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */
#include <asm-generic/topology.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 4794d6b4f4d2..b3142c7b9c31 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -1156,6 +1156,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
if (smp_ops && smp_ops->bringup_done)
smp_ops->bringup_done();
+ /*
+ * On a shared LPAR, associativity needs to be requested.
+ * Hence, get numa topology before dumping cpu topology
+ */
+ shared_proc_topology_init();
dump_numa_cpu_topology();
/*
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 0c7e05d89244..35ac5422903a 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1078,7 +1078,6 @@ static int prrn_enabled;
static void reset_topology_timer(void);
static int topology_timer_secs = 1;
static int topology_inited;
-static int topology_update_needed;
/*
* Change polling interval for associativity changes.
@@ -1306,11 +1305,8 @@ int numa_update_cpu_topology(bool cpus_locked)
struct device *dev;
int weight, new_nid, i = 0;
- if (!prrn_enabled && !vphn_enabled) {
- if (!topology_inited)
- topology_update_needed = 1;
+ if (!prrn_enabled && !vphn_enabled && topology_inited)
return 0;
- }
weight = cpumask_weight(&cpu_associativity_changes_mask);
if (!weight)
@@ -1423,7 +1419,6 @@ int numa_update_cpu_topology(bool cpus_locked)
out:
kfree(updates);
- topology_update_needed = 0;
return changed;
}
@@ -1551,6 +1546,15 @@ int prrn_is_enabled(void)
return prrn_enabled;
}
+void __init shared_proc_topology_init(void)
+{
+ if (lppaca_shared_proc(get_lppaca())) {
+ bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
+ nr_cpumask_bits);
+ numa_update_cpu_topology(false);
+ }
+}
+
static int topology_read(struct seq_file *file, void *v)
{
if (vphn_enabled || prrn_enabled)
@@ -1608,10 +1612,6 @@ static int topology_update_init(void)
return -ENOMEM;
topology_inited = 1;
- if (topology_update_needed)
- bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
- nr_cpumask_bits);
-
return 0;
}
device_initcall(topology_update_init);
--
2.17.1
^ permalink raw reply related
* [PATCH v5] powerpc/topology: Get topology for shared processors at boot
From: Srikar Dronamraju @ 2018-08-17 14:48 UTC (permalink / raw)
To: linuxppc-dev, Michael Ellerman
Cc: Michael Bringmann, Manjunatha H R, Srikar Dronamraju,
Michal Suchanek
On a shared lpar, Phyp will not update the cpu associativity at boot
time. Just after the boot system does recognize itself as a shared lpar and
trigger a request for correct cpu associativity. But by then the scheduler
would have already created/destroyed its sched domains.
This causes
- Broken load balance across Nodes causing islands of cores.
- Performance degradation esp if the system is lightly loaded
- dmesg to wrongly report all cpus to be in Node 0.
- Messages in dmesg saying borken topology.
- With commit 051f3ca02e46 ("sched/topology: Introduce NUMA identity
node sched domain"), can cause rcu stalls at boot up.
>From a scheduler maintainer's perspective, moving cpus from one node to
another or creating more numa levels after boot is not appropriate
without some notification to the user space.
https://lore.kernel.org/lkml/20150406214558.GA38501@linux.vnet.ibm.com/T/#u
The sched_domains_numa_masks table which is used to generate cpumasks is
only created at boot time just before creating sched domains and never
updated. Hence, its better to get the topology correct before the sched
domains are created.
For example on 64 core Power 8 shared lpar, dmesg reports
[ 2.088360] Brought up 512 CPUs
[ 2.088368] Node 0 CPUs: 0-511
[ 2.088371] Node 1 CPUs:
[ 2.088373] Node 2 CPUs:
[ 2.088375] Node 3 CPUs:
[ 2.088376] Node 4 CPUs:
[ 2.088378] Node 5 CPUs:
[ 2.088380] Node 6 CPUs:
[ 2.088382] Node 7 CPUs:
[ 2.088386] Node 8 CPUs:
[ 2.088388] Node 9 CPUs:
[ 2.088390] Node 10 CPUs:
[ 2.088392] Node 11 CPUs:
...
[ 3.916091] BUG: arch topology borken
[ 3.916103] the DIE domain not a subset of the NUMA domain
[ 3.916105] BUG: arch topology borken
[ 3.916106] the DIE domain not a subset of the NUMA domain
...
numactl/lscpu output will still be correct with cores spreading across
all nodes.
Socket(s): 64
NUMA node(s): 12
Model: 2.0 (pvr 004d 0200)
Model name: POWER8 (architected), altivec supported
Hypervisor vendor: pHyp
Virtualization type: para
L1d cache: 64K
L1i cache: 32K
NUMA node0 CPU(s): 0-7,32-39,64-71,96-103,176-183,272-279,368-375,464-471
NUMA node1 CPU(s): 8-15,40-47,72-79,104-111,184-191,280-287,376-383,472-479
NUMA node2 CPU(s): 16-23,48-55,80-87,112-119,192-199,288-295,384-391,480-487
NUMA node3 CPU(s): 24-31,56-63,88-95,120-127,200-207,296-303,392-399,488-495
NUMA node4 CPU(s): 208-215,304-311,400-407,496-503
NUMA node5 CPU(s): 168-175,264-271,360-367,456-463
NUMA node6 CPU(s): 128-135,224-231,320-327,416-423
NUMA node7 CPU(s): 136-143,232-239,328-335,424-431
NUMA node8 CPU(s): 216-223,312-319,408-415,504-511
NUMA node9 CPU(s): 144-151,240-247,336-343,432-439
NUMA node10 CPU(s): 152-159,248-255,344-351,440-447
NUMA node11 CPU(s): 160-167,256-263,352-359,448-455
Currently on this lpar, the scheduler detects 2 levels of Numa and
created numa sched domains for all cpus, but it finds a single DIE
domain consisting of all cpus. Hence it deletes all numa sched domains.
To address this, detect the shared processor and update topology soon after
cpus are setup so that correct topology is updated just before scheduler
creates sched domain.
With the fix, dmesg reports
[ 0.491336] numa: Node 0 CPUs: 0-7 32-39 64-71 96-103 176-183 272-279 368-375 464-471
[ 0.491351] numa: Node 1 CPUs: 8-15 40-47 72-79 104-111 184-191 280-287 376-383 472-479
[ 0.491359] numa: Node 2 CPUs: 16-23 48-55 80-87 112-119 192-199 288-295 384-391 480-487
[ 0.491366] numa: Node 3 CPUs: 24-31 56-63 88-95 120-127 200-207 296-303 392-399 488-495
[ 0.491374] numa: Node 4 CPUs: 208-215 304-311 400-407 496-503
[ 0.491379] numa: Node 5 CPUs: 168-175 264-271 360-367 456-463
[ 0.491384] numa: Node 6 CPUs: 128-135 224-231 320-327 416-423
[ 0.491389] numa: Node 7 CPUs: 136-143 232-239 328-335 424-431
[ 0.491394] numa: Node 8 CPUs: 216-223 312-319 408-415 504-511
[ 0.491399] numa: Node 9 CPUs: 144-151 240-247 336-343 432-439
[ 0.491404] numa: Node 10 CPUs: 152-159 248-255 344-351 440-447
[ 0.491409] numa: Node 11 CPUs: 160-167 256-263 352-359 448-455
and lscpu would also report
Socket(s): 64
NUMA node(s): 12
Model: 2.0 (pvr 004d 0200)
Model name: POWER8 (architected), altivec supported
Hypervisor vendor: pHyp
Virtualization type: para
L1d cache: 64K
L1i cache: 32K
NUMA node0 CPU(s): 0-7,32-39,64-71,96-103,176-183,272-279,368-375,464-471
NUMA node1 CPU(s): 8-15,40-47,72-79,104-111,184-191,280-287,376-383,472-479
NUMA node2 CPU(s): 16-23,48-55,80-87,112-119,192-199,288-295,384-391,480-487
NUMA node3 CPU(s): 24-31,56-63,88-95,120-127,200-207,296-303,392-399,488-495
NUMA node4 CPU(s): 208-215,304-311,400-407,496-503
NUMA node5 CPU(s): 168-175,264-271,360-367,456-463
NUMA node6 CPU(s): 128-135,224-231,320-327,416-423
NUMA node7 CPU(s): 136-143,232-239,328-335,424-431
NUMA node8 CPU(s): 216-223,312-319,408-415,504-511
NUMA node9 CPU(s): 144-151,240-247,336-343,432-439
NUMA node10 CPU(s): 152-159,248-255,344-351,440-447
NUMA node11 CPU(s): 160-167,256-263,352-359,448-455
Previous attempt to solve this problem
https://patchwork.ozlabs.org/patch/530090/
Reported-by: Manjunatha H R <manjuhr1@in.ibm.com>
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
---
Changelog v1->v2
Fix compile warnings and checkpatch issues.
Changelog v2->v3
Fix compile warnings on !CONFIG_SMP
Changelog v3->v4
Now do early topology init on shared processor. Earlier we used to do only
for vphn enabled. However we want this update to happen even when
topology_updates=off. Changed patch title accordingly
Changelog v4->v5:
Handled comments from Michael Ellerman where numa_update_cpu_topology
was simply returning without updating the topology.
arch/powerpc/include/asm/topology.h | 5 +++++
arch/powerpc/kernel/smp.c | 6 ++++++
arch/powerpc/mm/numa.c | 22 ++++++++++++++--------
3 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 16b077801a5f..a4a718dbfec6 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -92,6 +92,7 @@ extern int stop_topology_update(void);
extern int prrn_is_enabled(void);
extern int find_and_online_cpu_nid(int cpu);
extern int timed_topology_update(int nsecs);
+extern void __init shared_proc_topology_init(void);
#else
static inline int start_topology_update(void)
{
@@ -113,6 +114,10 @@ static inline int timed_topology_update(int nsecs)
{
return 0;
}
+
+#ifdef CONFIG_SMP
+static inline void shared_proc_topology_init(void) {}
+#endif
#endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */
#include <asm-generic/topology.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 4794d6b4f4d2..b3142c7b9c31 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -1156,6 +1156,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
if (smp_ops && smp_ops->bringup_done)
smp_ops->bringup_done();
+ /*
+ * On a shared LPAR, associativity needs to be requested.
+ * Hence, get numa topology before dumping cpu topology
+ */
+ shared_proc_topology_init();
dump_numa_cpu_topology();
/*
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 0c7e05d89244..35ac5422903a 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1078,7 +1078,6 @@ static int prrn_enabled;
static void reset_topology_timer(void);
static int topology_timer_secs = 1;
static int topology_inited;
-static int topology_update_needed;
/*
* Change polling interval for associativity changes.
@@ -1306,11 +1305,8 @@ int numa_update_cpu_topology(bool cpus_locked)
struct device *dev;
int weight, new_nid, i = 0;
- if (!prrn_enabled && !vphn_enabled) {
- if (!topology_inited)
- topology_update_needed = 1;
+ if (!prrn_enabled && !vphn_enabled && topology_inited)
return 0;
- }
weight = cpumask_weight(&cpu_associativity_changes_mask);
if (!weight)
@@ -1423,7 +1419,6 @@ int numa_update_cpu_topology(bool cpus_locked)
out:
kfree(updates);
- topology_update_needed = 0;
return changed;
}
@@ -1551,6 +1546,15 @@ int prrn_is_enabled(void)
return prrn_enabled;
}
+void __init shared_proc_topology_init(void)
+{
+ if (lppaca_shared_proc(get_lppaca())) {
+ bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
+ nr_cpumask_bits);
+ numa_update_cpu_topology(false);
+ }
+}
+
static int topology_read(struct seq_file *file, void *v)
{
if (vphn_enabled || prrn_enabled)
@@ -1608,10 +1612,6 @@ static int topology_update_init(void)
return -ENOMEM;
topology_inited = 1;
- if (topology_update_needed)
- bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
- nr_cpumask_bits);
-
--
2.17.1
^ permalink raw reply related
* [PATCH 1/3] dmaengine: fsldma: move spin_lock_bh to spin_lock in tasklet
From: Barry Song @ 2018-08-17 13:00 UTC (permalink / raw)
To: leoyang.li, zw, dan.j.williams, vkoul, linuxppc-dev, dmaengine,
linux-kernel
Cc: Barry Song
as you are already in a tasklet, it is unnecessary to call spin_lock_bh.
Signed-off-by: Barry Song <21cnbao@gmail.com>
---
drivers/dma/fsldma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 1117b51..9d360a3 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -987,7 +987,7 @@ static void dma_do_tasklet(unsigned long data)
chan_dbg(chan, "tasklet entry\n");
- spin_lock_bh(&chan->desc_lock);
+ spin_lock(&chan->desc_lock);
/* the hardware is now idle and ready for more */
chan->idle = true;
@@ -995,7 +995,7 @@ static void dma_do_tasklet(unsigned long data)
/* Run all cleanup for descriptors which have been completed */
fsldma_cleanup_descriptors(chan);
- spin_unlock_bh(&chan->desc_lock);
+ spin_unlock(&chan->desc_lock);
chan_dbg(chan, "tasklet exit\n");
}
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] powerpc/traps: Avoid rate limit messages from show unhandled signals
From: Murilo Opsfelder Araujo @ 2018-08-17 12:45 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
In-Reply-To: <20180817065500.16899-1-mpe@ellerman.id.au>
Hi, Michael.
On Fri, Aug 17, 2018 at 04:55:00PM +1000, Michael Ellerman wrote:
> In the recent commit to add an explicit ratelimit state when showing
> unhandled signals, commit 35a52a10c3ac ("powerpc/traps: Use an
> explicit ratelimit state for show_signal_msg()"), I put the check of
> show_unhandled_signals and the ratelimit state before the call to
> unhandled_signal() so as to avoid unnecessarily calling the latter
> when show_unhandled_signals is false.
>
> However that causes us to check the ratelimit state on every call, so
> if we take a lot of *handled* signals that has the effect of making
> the ratelimit code print warnings that callbacks have been suppressed
> when they haven't.
>
> So rearrange the code so that we check show_unhandled_signals first,
> then call unhandled_signal() and finally check the ratelimit state.
>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Nice catch. Thanks for patching it.
Reviewed-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>
> ---
> arch/powerpc/kernel/traps.c | 13 ++++++-------
> 1 file changed, 6 insertions(+), 7 deletions(-)
>
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index 070e96f1773a..c85adb858271 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -315,22 +315,21 @@ void user_single_step_siginfo(struct task_struct *tsk,
> info->si_addr = (void __user *)regs->nip;
> }
>
> -static bool show_unhandled_signals_ratelimited(void)
> +static void show_signal_msg(int signr, struct pt_regs *regs, int code,
> + unsigned long addr)
> {
> static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
> DEFAULT_RATELIMIT_BURST);
> - return show_unhandled_signals && __ratelimit(&rs);
> -}
>
> -static void show_signal_msg(int signr, struct pt_regs *regs, int code,
> - unsigned long addr)
> -{
> - if (!show_unhandled_signals_ratelimited())
> + if (!show_unhandled_signals)
> return;
>
> if (!unhandled_signal(current, signr))
> return;
>
> + if (!__ratelimit(&rs))
> + return;
> +
> pr_info("%s[%d]: %s (%d) at %lx nip %lx lr %lx code %x",
> current->comm, current->pid, signame(signr), signr,
> addr, regs->nip, regs->link, code);
> --
> 2.17.1
>
--
Murilo
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/process: Constify the number of insns printed by show instructions functions.
From: Murilo Opsfelder Araujo @ 2018-08-17 12:39 UTC (permalink / raw)
To: Christophe Leroy
Cc: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
linux-kernel, linuxppc-dev
In-Reply-To: <ae227d64c78e893b63ed71d911e016cb88212459.1534192631.git.christophe.leroy@c-s.fr>
Hi, Christophe.
On Tue, Aug 14, 2018 at 08:59:20AM +0000, Christophe Leroy wrote:
> instructions_to_print var is assigned value 16 and there is no
> way to change it.
>
> This patch replaces it by a constant.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>
> ---
> arch/powerpc/kernel/process.c | 11 +++++------
> 1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index c722ce4ca1c0..6317f2ed04ab 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -1259,17 +1259,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
> return last;
> }
>
> -static int instructions_to_print = 16;
> +#define NR_INSN_TO_PRINT 16
>
> static void show_instructions(struct pt_regs *regs)
> {
> int i;
> - unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 *
> - sizeof(int));
> + unsigned long pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
>
> printk("Instruction dump:");
>
> - for (i = 0; i < instructions_to_print; i++) {
> + for (i = 0; i < NR_INSN_TO_PRINT; i++) {
> int instr;
>
> if (!(i % 8))
> @@ -1306,9 +1305,9 @@ void show_user_instructions(struct pt_regs *regs)
> char buf[96]; /* enough for 8 times 9 + 2 chars */
> int l = 0;
>
> - pc = regs->nip - (instructions_to_print * 3 / 4 * sizeof(int));
> + pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
>
> - for (i = 0; i < instructions_to_print; i++) {
> + for (i = 0; i < NR_INSN_TO_PRINT; i++) {
> int instr;
>
> if (!(i % 8) && (i > 0)) {
> --
> 2.13.3
>
--
Murilo
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/process: fix nested output in show_user_instructions()
From: Murilo Opsfelder Araujo @ 2018-08-17 12:34 UTC (permalink / raw)
To: Christophe Leroy
Cc: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
linux-kernel, linuxppc-dev
In-Reply-To: <718cc9c9bd1d4bb2b4c2596f1a7ee00334e77055.1534192631.git.christophe.leroy@c-s.fr>
Hi, Christophe.
On Tue, Aug 14, 2018 at 08:59:18AM +0000, Christophe Leroy wrote:
> When two processes crash at the same time, we sometimes encounter
> nesting in the middle of a line:
>
> [ 4.365317] init[1]: segfault (11) at 0 nip 0 lr 0 code 1
> [ 4.370452] init[1]: code: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
> [ 4.372042] init[74]: segfault (11) at 10a74 nip 1000c198 lr 100078c8 code 1 in sh[10000000+14000]
> [ 4.386829] XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
> [ 4.391542] init[1]: code: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
> [ 4.400863] init[74]: code: 90010024 bf61000c 91490a7c 3fa01002 3be00000 7d3e4b78 3bbd0c20 3b600000
> [ 4.409867] init[74]: code: 3b9d0040 7c7fe02e 2f830000 419e0028 <89230000> 2f890000 41be001c 4b7f6e79
My smoke test passed with the two patches.
Perhaps adding an output sample of how messages would look like after your patch
could be an enhancement to the commit message.
Otherwise:
Reviewed-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>
> This patch fixes it by preparing complete lines in a buffer and
> printing it at once.
>
> Fixes: 88b0fe1757359 ("powerpc: Add show_user_instructions()")
> Cc: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
> ---
> arch/powerpc/kernel/process.c | 17 +++++++++--------
> 1 file changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index 913c5725cdb2..c722ce4ca1c0 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -1303,32 +1303,33 @@ void show_user_instructions(struct pt_regs *regs)
> {
> unsigned long pc;
> int i;
> + char buf[96]; /* enough for 8 times 9 + 2 chars */
> + int l = 0;
>
> pc = regs->nip - (instructions_to_print * 3 / 4 * sizeof(int));
>
> - pr_info("%s[%d]: code: ", current->comm, current->pid);
> -
> for (i = 0; i < instructions_to_print; i++) {
> int instr;
>
> if (!(i % 8) && (i > 0)) {
> - pr_cont("\n");
> - pr_info("%s[%d]: code: ", current->comm, current->pid);
> + pr_info("%s[%d]: code: %s\n", current->comm, current->pid, buf);
> + l = 0;
> }
>
> if (probe_kernel_address((unsigned int __user *)pc, instr)) {
> - pr_cont("XXXXXXXX ");
> + l += sprintf(buf + l, "XXXXXXXX ");
> } else {
> if (regs->nip == pc)
> - pr_cont("<%08x> ", instr);
> + l += sprintf(buf + l, "<%08x> ", instr);
> else
> - pr_cont("%08x ", instr);
> + l += sprintf(buf + l, "%08x ", instr);
> }
>
> pc += sizeof(int);
> }
>
> - pr_cont("\n");
> + if (l)
> + pr_info("%s[%d]: code: %s\n", current->comm, current->pid, buf);
> }
>
> struct regbit {
> --
> 2.13.3
>
--
Murilo
^ permalink raw reply
* Re: [PATCH v2 1/4] powerpc/tm: Remove msr_tm_active()
From: Breno Leitao @ 2018-08-17 12:26 UTC (permalink / raw)
To: Michael Ellerman, linuxppc-dev; +Cc: Michael Neuling
In-Reply-To: <87tvntakb6.fsf@concordia.ellerman.id.au>
Hi Michael,
On 08/16/2018 09:49 PM, Michael Ellerman wrote:
> Michael Neuling <mikey@neuling.org> writes:
>
>> On Mon, 2018-06-18 at 19:59 -0300, Breno Leitao wrote:
>>> Currently msr_tm_active() is a wrapper around MSR_TM_ACTIVE() if
>>> CONFIG_PPC_TRANSACTIONAL_MEM is set, or it is just a function that
>>> returns false if CONFIG_PPC_TRANSACTIONAL_MEM is not set.
>>>
>>> This function is not necessary, since MSR_TM_ACTIVE() just do the same,
>>> checking for the TS bits and does not require any TM facility.
>>>
>>> This patchset remove every instance of msr_tm_active() and replaced it
>>> by MSR_TM_ACTIVE().
>>>
>>> Signed-off-by: Breno Leitao <leitao@debian.org>
>>>
>>
>> Patch looks good... one minor nit below...
>>
>>>
>>> - if (!msr_tm_active(regs->msr) &&
>>> - !current->thread.load_fp && !loadvec(current->thread))
>>> + if (!current->thread.load_fp && !loadvec(current->thread)) {
>>> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>> + if (!MSR_TM_ACTIVE(regs->msr))
>>> + return;
>>
>> Can you make a MSR_TM_ACTIVE() that returns false when
>> !CONFIG_PPC_TRANSACTIONAL_MEM. Then you don't need this inline #ifdef.
>
> Is that safe?
>
> I see ~50 callers of MSR_TM_ACTIVE(), are they all inside #ifdef TM ?
I checked all of them, and the only two that are not called inside a #ifdef
are at kvm/book3s_hv_tm.c. They are:
kvm/book3s_hv_tm.c: if (!MSR_TM_ACTIVE(msr)) {
kvm/book3s_hv_tm.c: if (MSR_TM_ACTIVE(msr) || !(vcpu->arch.texasr & TEXASR_FS)) {
All the others are being called inside the #ifdef
Other than that, I do not see why it would be a problem in the way I
implemented it, since it will return false for the two cases above, which
seems correct. Take a look on how the definition became:
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
#else
#define MSR_TM_ACTIVE(x) 0
#endif
I also tested it with different config files, and I didn't see any complain.
These are the platforms I built for.
* powernv_defconfig
* pseries_le_defconfig
* pseries_defconfig
* ppc64_defconfig
* ppc64e_defconfig
* pmac32_defconfig
* ppc44x_defconfig
* mpc85xx_smp_defconfig
* mpc85xx_defconfig
* ps3_defconfig
Anyway, if you have any other suggestion I can follow in order to guarantee
that I am not causing any regression, I would be happy. Touching these core
kernel macros is scary!
Thanks!
^ permalink raw reply
* Re: [PATCH RFC 1/2] drivers/base: export lock_device_hotplug/unlock_device_hotplug
From: David Hildenbrand @ 2018-08-17 11:56 UTC (permalink / raw)
To: Heiko Carstens
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Michal Hocko,
Benjamin Herrenschmidt, Linux Memory Management List,
Paul Mackerras, linux-s390, sthemmin, Pavel Tatashin,
ACPI Devel Maling List, David Rientjes, xen-devel, Len Brown,
haiyangz, Dan Williams, Andrew Morton, Vlastimil Babka, osalvador,
Rafael J. Wysocki, Linux Kernel Mailing List, Martin Schwidefsky,
devel, Vitaly Kuznetsov, linuxppc-dev
In-Reply-To: <20180817112850.GB3565@osiris>
On 17.08.2018 13:28, Heiko Carstens wrote:
> On Fri, Aug 17, 2018 at 01:04:58PM +0200, David Hildenbrand wrote:
>>>> If there are no objections, I'll go into that direction. But I'll wait
>>>> for more comments regarding the general concept first.
>>>
>>> It is the middle of the merge window, and maintainers are really busy
>>> right now. I doubt you will get many review comments just yet...
>>>
>>
>> This has been broken since 2015, so I guess it can wait a bit :)
>
> I hope you figured out what needs to be locked why. Your patch description
> seems to be "only" about locking order ;)
Well I hope so, too ... but there is a reason for the RFC mark ;) There
is definitely a lot of magic in the current code. And that's why it is
also not that obvious that locking is wrong.
To avoid/fix the locking order problem was the motivation for the
original patch that dropped mem_hotplug_lock on one path. So I focused
on that in my description.
>
> I tried to figure out and document that partially with 55adc1d05dca ("mm:
> add private lock to serialize memory hotplug operations"), and that wasn't
> easy to figure out. I was especially concerned about sprinkling
Haven't seen that so far as that was reworked by 3f906ba23689
("mm/memory-hotplug: switch locking to a percpu rwsem"). Thanks for the
pointer. There is a long history to all this.
> lock/unlock_device_hotplug() calls, which has the potential to make it the
> next BKL thing.
Well, the thing with memory hotplug and device_hotplug_lock is that
a) ACPI already holds it while adding/removing memory via add_memory()
b) we hold it during online/offline of memory (via sysfs calls to
device_online()/device_offline())
So it is already pretty much involved in all memory hotplug/unplug
activities on x86 (except paravirt). And as far as I understand, there
are good reasons to hold the lock in core.c and ACPI. (as mentioned by
Rafael)
The exceptions are add_memory() called on s390x, hyper-v, xen and ppc
(including manual probing). And device_online()/device_offline() called
from the kernel.
Holding device_hotplug_lock when adding/removing memory from the system
doesn't sound too wrong (especially as devices are created/removed). At
least that way (documenting and following the rules in the patch
description) we might at least get locking right.
I am very open to other suggestions (but as noted by Greg, many
maintainers might be busy by know).
E.g. When adding the memory block devices, we know that there won't be a
driver to attach to (as there are no drivers for the "memory" subsystem)
- the bus_probe_device() function that takes the device_lock() could
pretty much be avoided for that case. But burying such special cases
down in core driver code definitely won't make locking related to memory
hotplug easier.
Thanks for having a look!
--
Thanks,
David / dhildenb
^ permalink raw reply
* Re: [PATCH RFC 1/2] drivers/base: export lock_device_hotplug/unlock_device_hotplug
From: Heiko Carstens @ 2018-08-17 11:28 UTC (permalink / raw)
To: David Hildenbrand
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Michal Hocko,
Benjamin Herrenschmidt, Linux Memory Management List,
Paul Mackerras, linux-s390, sthemmin, Pavel Tatashin,
ACPI Devel Maling List, David Rientjes, xen-devel, Len Brown,
haiyangz, Dan Williams, Andrew Morton, Vlastimil Babka, osalvador,
Rafael J. Wysocki, Linux Kernel Mailing List, Martin Schwidefsky,
devel, Vitaly Kuznetsov, linuxppc-dev
In-Reply-To: <4ac624be-d2d6-5975-821f-b20a475781dc@redhat.com>
On Fri, Aug 17, 2018 at 01:04:58PM +0200, David Hildenbrand wrote:
> >> If there are no objections, I'll go into that direction. But I'll wait
> >> for more comments regarding the general concept first.
> >
> > It is the middle of the merge window, and maintainers are really busy
> > right now. I doubt you will get many review comments just yet...
> >
>
> This has been broken since 2015, so I guess it can wait a bit :)
I hope you figured out what needs to be locked why. Your patch description
seems to be "only" about locking order ;)
I tried to figure out and document that partially with 55adc1d05dca ("mm:
add private lock to serialize memory hotplug operations"), and that wasn't
easy to figure out. I was especially concerned about sprinkling
lock/unlock_device_hotplug() calls, which has the potential to make it the
next BKL thing.
^ permalink raw reply
* Re: [PATCH v7 4/9] powerpc/pseries: Define MCE error event section.
From: Mahesh Jagannath Salgaonkar @ 2018-08-17 11:22 UTC (permalink / raw)
To: Michael Ellerman, Mahesh Jagannath Salgaonkar, linuxppc-dev
Cc: Aneesh Kumar K.V, Michal Suchanek, Ananth Narayan,
Nicholas Piggin, Laurent Dufour
In-Reply-To: <87lg97aqxc.fsf@concordia.ellerman.id.au>
On 08/16/2018 09:44 AM, Michael Ellerman wrote:
> Mahesh Jagannath Salgaonkar <mahesh@linux.vnet.ibm.com> writes:
>> On 08/08/2018 08:12 PM, Michael Ellerman wrote:
> ...
>>>
>>>> + union {
>>>> + struct {
>>>> + uint8_t ue_err_type;
>>>> + /* XXXXXXXX
>>>> + * X 1: Permanent or Transient UE.
>>>> + * X 1: Effective address provided.
>>>> + * X 1: Logical address provided.
>>>> + * XX 2: Reserved.
>>>> + * XXX 3: Type of UE error.
>>>> + */
>>>
>>> But which bit is bit 0? And is that the LSB or MSB?
>>
>> RTAS errorlog data in BE format, the leftmost bit is MSB 0 (1: Permanent
>> or Transient UE.). I Will update the comment above that properly points
>> out which one is MSB 0.
>>
>>>
>>>
>>>> + uint8_t reserved_1[6];
>>>> + __be64 effective_address;
>>>> + __be64 logical_address;
>>>> + } ue_error;
>>>> + struct {
>>>> + uint8_t soft_err_type;
>>>> + /* XXXXXXXX
>>>> + * X 1: Effective address provided.
>>>> + * XXXXX 5: Reserved.
>>>> + * XX 2: Type of SLB/ERAT/TLB error.
>>>> + */
>>>> + uint8_t reserved_1[6];
>>>> + __be64 effective_address;
>>>> + uint8_t reserved_2[8];
>>>> + } soft_error;
>>>> + } u;
>>>> +};
>>>> +#pragma pack(pop)
>>>
>>> Why not __packed ?
>>
>> Because when used __packed it added 1 byte extra padding between
>> reserved_1[6] and effective_address. That caused wrong effective address
>> to be printed on the console. Hence I switched to #pragma pack to force
>> 1 byte alignment for this structure alone.
>
> OK, that's weird.
>
> Do we really need to bother with all the union stuff? The only
> difference is the field names, and whether logical address has a value
Also the bit fields for UE and other sub errors differ. Yeah but we can
do away with union stuff.
> or not. What about:
>
> struct pseries_mc_errorlog {
> __be32 fru_id;
> __be32 proc_id;
> u8 error_type;
> u8 sub_error_type;
> u8 reserved_1[6];
> __be64 effective_address;
> __be64 logical_address;
> } __packed;
Sure will do.
Thanks
-Mahesh.
>
> cheers
>
^ permalink raw reply
* Re: [PATCH RFC 1/2] drivers/base: export lock_device_hotplug/unlock_device_hotplug
From: David Hildenbrand @ 2018-08-17 11:04 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Rafael J. Wysocki, Michal Hocko, Benjamin Herrenschmidt,
Heiko Carstens, Linux Memory Management List, Paul Mackerras,
linux-s390, sthemmin, Pavel Tatashin, ACPI Devel Maling List,
David Rientjes, xen-devel, Len Brown, haiyangz, Dan Williams,
Andrew Morton, Vlastimil Babka, osalvador, Rafael J. Wysocki,
Linux Kernel Mailing List, Martin Schwidefsky, devel,
Vitaly Kuznetsov, linuxppc-dev
In-Reply-To: <20180817100604.GA18164@kroah.com>
On 17.08.2018 12:06, Greg Kroah-Hartman wrote:
> On Fri, Aug 17, 2018 at 11:41:24AM +0200, David Hildenbrand wrote:
>> On 17.08.2018 11:03, Rafael J. Wysocki wrote:
>>> On Fri, Aug 17, 2018 at 10:56 AM David Hildenbrand <david@redhat.com> wrote:
>>>>
>>>> On 17.08.2018 10:41, Greg Kroah-Hartman wrote:
>>>>> On Fri, Aug 17, 2018 at 09:59:00AM +0200, David Hildenbrand wrote:
>>>>>> From: Vitaly Kuznetsov <vkuznets@redhat.com>
>>>>>>
>>>>>> Well require to call add_memory()/add_memory_resource() with
>>>>>> device_hotplug_lock held, to avoid a lock inversion. Allow external modules
>>>>>> (e.g. hv_balloon) that make use of add_memory()/add_memory_resource() to
>>>>>> lock device hotplug.
>>>>>>
>>>>>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>>>>>> [modify patch description]
>>>>>> Signed-off-by: David Hildenbrand <david@redhat.com>
>>>>>> ---
>>>>>> drivers/base/core.c | 2 ++
>>>>>> 1 file changed, 2 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/base/core.c b/drivers/base/core.c
>>>>>> index 04bbcd779e11..9010b9e942b5 100644
>>>>>> --- a/drivers/base/core.c
>>>>>> +++ b/drivers/base/core.c
>>>>>> @@ -700,11 +700,13 @@ void lock_device_hotplug(void)
>>>>>> {
>>>>>> mutex_lock(&device_hotplug_lock);
>>>>>> }
>>>>>> +EXPORT_SYMBOL_GPL(lock_device_hotplug);
>>>>>>
>>>>>> void unlock_device_hotplug(void)
>>>>>> {
>>>>>> mutex_unlock(&device_hotplug_lock);
>>>>>> }
>>>>>> +EXPORT_SYMBOL_GPL(unlock_device_hotplug);
>>>>>
>>>>> If these are going to be "global" symbols, let's properly name them.
>>>>> device_hotplug_lock/unlock would be better. But I am _really_ nervous
>>>>> about letting stuff outside of the driver core mess with this, as people
>>>>> better know what they are doing.
>>>>
>>>> The only "problem" is that we have kernel modules (for paravirtualized
>>>> devices) that call add_memory(). This is Hyper-V right now, but we might
>>>> have other ones in the future. Without them we would not have to export
>>>> it. We might also get kernel modules that want to call remove_memory() -
>>>> which will require the device_hotplug_lock as of now.
>>>>
>>>> What we could do is
>>>>
>>>> a) add_memory() -> _add_memory() and don't export it
>>>> b) add_memory() takes the device_hotplug_lock and calls _add_memory() .
>>>> We export that one.
>>>> c) Use add_memory() in external modules only
>>>>
>>>> Similar wrapper would be needed e.g. for remove_memory() later on.
>>>
>>> That would be safer IMO, as it would prevent developers from using
>>> add_memory() without the lock, say.
>>>
>>> If the lock is always going to be required for add_memory(), make it
>>> hard (or event impossible) to use the latter without it.
>>>
>>
>> If there are no objections, I'll go into that direction. But I'll wait
>> for more comments regarding the general concept first.
>
> It is the middle of the merge window, and maintainers are really busy
> right now. I doubt you will get many review comments just yet...
>
This has been broken since 2015, so I guess it can wait a bit :)
--
Thanks,
David / dhildenb
^ permalink raw reply
* Re: [PATCH v2 3/4] powerpc/mm: fix a warning when a cache is common to PGD and hugepages
From: Christophe LEROY @ 2018-08-17 10:44 UTC (permalink / raw)
To: Aneesh Kumar K.V, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, aneesh.kumar
Cc: linux-kernel, linuxppc-dev
In-Reply-To: <6dea8d0c-c4ab-49aa-da26-a729c18fa818@linux.ibm.com>
Le 17/08/2018 à 05:32, Aneesh Kumar K.V a écrit :
> On 08/14/2018 08:24 PM, Christophe Leroy wrote:
>> While implementing TLB miss HW assistance on the 8xx, the following
>> warning was encountered:
>>
>> [ 423.732965] WARNING: CPU: 0 PID: 345 at mm/slub.c:2412
>> ___slab_alloc.constprop.30+0x26c/0x46c
>> [ 423.733033] CPU: 0 PID: 345 Comm: mmap Not tainted
>> 4.18.0-rc8-00664-g2dfff9121c55 #671
>> [ 423.733075] NIP: c0108f90 LR: c0109ad0 CTR: 00000004
>> [ 423.733121] REGS: c455bba0 TRAP: 0700 Not tainted
>> (4.18.0-rc8-00664-g2dfff9121c55)
>> [ 423.733147] MSR: 00021032 <ME,IR,DR,RI> CR: 24224848 XER: 20000000
>> [ 423.733319]
>> [ 423.733319] GPR00: c0109ad0 c455bc50 c4521910 c60053c0 007080c0
>> c0011b34 c7fa41e0 c455be30
>> [ 423.733319] GPR08: 00000001 c00103a0 c7fa41e0 c49afcc4 24282842
>> 10018840 c079b37c 00000040
>> [ 423.733319] GPR16: 73f00000 00210d00 00000000 00000001 c455a000
>> 00000100 00000200 c455a000
>> [ 423.733319] GPR24: c60053c0 c0011b34 007080c0 c455a000 c455a000
>> c7fa41e0 00000000 00009032
>> [ 423.734190] NIP [c0108f90] ___slab_alloc.constprop.30+0x26c/0x46c
>> [ 423.734257] LR [c0109ad0] kmem_cache_alloc+0x210/0x23c
>> [ 423.734283] Call Trace:
>> [ 423.734326] [c455bc50] [00000100] 0x100 (unreliable)
>> [ 423.734430] [c455bcc0] [c0109ad0] kmem_cache_alloc+0x210/0x23c
>> [ 423.734543] [c455bcf0] [c0011b34] huge_pte_alloc+0xc0/0x1dc
>> [ 423.734633] [c455bd20] [c01044dc] hugetlb_fault+0x408/0x48c
>> [ 423.734720] [c455bdb0] [c0104b20] follow_hugetlb_page+0x14c/0x44c
>> [ 423.734826] [c455be10] [c00e8e54] __get_user_pages+0x1c4/0x3dc
>> [ 423.734919] [c455be80] [c00e9924] __mm_populate+0xac/0x140
>> [ 423.735020] [c455bec0] [c00db14c] vm_mmap_pgoff+0xb4/0xb8
>> [ 423.735127] [c455bf00] [c00f27c0] ksys_mmap_pgoff+0xcc/0x1fc
>> [ 423.735222] [c455bf40] [c000e0f8] ret_from_syscall+0x0/0x38
>> [ 423.735271] Instruction dump:
>> [ 423.735321] 7cbf482e 38fd0008 7fa6eb78 7fc4f378 4bfff5dd 7fe3fb78
>> 4bfffe24 81370010
>> [ 423.735536] 71280004 41a2ff88 4840c571 4bffff80 <0fe00000> 4bfffeb8
>> 81340010 712a0004
>> [ 423.735757] ---[ end trace e9b222919a470790 ]---
>>
>> This warning occurs when calling kmem_cache_zalloc() on a
>> cache having a constructor.
>>
>> In this case it happens because PGD cache and 512k hugepte cache are
>> the same size (4k). While a cache with constructor is created for
>> the PGD, hugepages create cache without constructor and uses
>> kmem_cache_zalloc(). As both expect a cache with the same size,
>> the hugepages reuse the cache created for PGD, hence the conflict.
>>
>> In order to avoid this conflict, this patch:
>> - modifies pgtable_cache_add() so that a zeroising constructor is
>> added for any cache size.
>> - replaces calls to kmem_cache_zalloc() by kmem_cache_alloc()
>>
>
> Can't we just do kmem_cache_alloc with gfp flags __GFP_ZERO? and remove
> the constructor completely?
I don't understand what you mean. That's exactly what I did in v1 (by
using kmem_cache_zalloc()), and you commented that doing this we would
zeroise at allocation whereas the constructors are called when adding
memory to the slab and when freeing the allocated block. Or did I
misunderstood your comment ?
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
return kmem_cache_alloc(k, flags | __GFP_ZERO);
}
Christophe
>
>
> -aneesh
^ permalink raw reply
* [RFC 13/15] PCI: turn pcibios_alloc_irq into a callback
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
Weak functions are a bit confusing, and we can better deal with
this using a callback function. pcibios_free_irq() is actually
completely unused, but it seems better to treat it the same way
as the allocation, unless we want to remove it completely.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/pci.c | 16 +++-------------
drivers/pci/pci-driver.c | 13 +++++++++++--
include/linux/pci.h | 2 ++
3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 0e2ea1c78542..3d196c68e362 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -22,19 +22,6 @@
#include <linux/pci-ecam.h>
#include <linux/slab.h>
-#ifdef CONFIG_ACPI
-/*
- * Try to assign the IRQ number when probing a new device
- */
-int pcibios_alloc_irq(struct pci_dev *dev)
-{
- if (!acpi_disabled)
- acpi_pci_irq_enable(dev);
-
- return 0;
-}
-#endif
-
/*
* raw_pci_read/write - Platform-specific PCI config space access.
*/
@@ -93,6 +80,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
ACPI_COMPANION_SET(&bridge->dev, adev);
set_dev_node(bus_dev, acpi_get_node(acpi_device_handle(adev)));
+
+ /* Try to assign the IRQ number when probing a new device */
+ bridge->alloc_irq = acpi_pci_irq_enable;
}
return 0;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index bef17c3fca67..c96bc7bd56da 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -387,13 +387,22 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
return error;
}
-int __weak pcibios_alloc_irq(struct pci_dev *dev)
+int pcibios_alloc_irq(struct pci_dev *dev)
{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
+
+ if (bridge->alloc_irq)
+ return bridge->alloc_irq(dev);
+
return 0;
}
-void __weak pcibios_free_irq(struct pci_dev *dev)
+void pcibios_free_irq(struct pci_dev *dev)
{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
+
+ if (bridge->free_irq)
+ bridge->free_irq(dev);
}
#ifdef CONFIG_PCI_IOV
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d1072690cb4f..1296d9fcc5da 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -476,6 +476,8 @@ struct pci_host_bridge {
int (*map_irq)(const struct pci_dev *, u8, u8);
void (*release_fn)(struct pci_host_bridge *);
void (*bus_add_device)(struct pci_dev *pdev);
+ int (*alloc_irq)(struct pci_dev *);
+ int (*free_irq)(struct pci_dev *);
void *release_data;
struct msi_controller *msi;
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
--
2.18.0
^ permalink raw reply related
* [RFC 06/15] powerpc/pci: fold pci_create_root_bus into pcibios_scan_phb
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
This slightly simplifies the pcibios_scan_phb() implementation, and
gives us an easier point to add further fields in the pci_host_bridge
structure.
I tried removing fields that are duplicated between pci_host_bridge
and pci_controller (which really serve the same purpose), but
ran into the problem that we can't call pci_alloc_host_bridge()
as early as pcibios_alloc_controller(). Some more refactoring
is needed for that, but it could noticably clean the powerpc code
up more.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/include/asm/pci-bridge.h | 3 ++
arch/powerpc/kernel/pci-common.c | 72 ++++++++++-----------------
2 files changed, 30 insertions(+), 45 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 94d449031b18..42ae567084d9 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -51,8 +51,11 @@ struct pci_controller_ops {
/*
* Structure of a PCI controller (host bridge)
+ * Some members here are duplicated in struct pci_host_bridge
+ * and should be moved there.
*/
struct pci_controller {
+ struct pci_host_bridge *bridge;
struct pci_bus *bus;
char is_dynamic;
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 57ca621a32f4..096011ec8670 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1587,81 +1587,63 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
return of_node_get(hose->dn);
}
-static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
-{
- int error;
- struct pci_host_bridge *bridge;
-
- bridge = pci_alloc_host_bridge(0);
- if (!bridge)
- return NULL;
-
- bridge->dev.parent = parent;
-
- list_splice_init(resources, &bridge->windows);
- bridge->sysdata = sysdata;
- bridge->busnr = bus;
- bridge->ops = ops;
-
- error = pci_register_host_bridge(bridge);
- if (error < 0)
- goto err_out;
-
- return bridge->bus;
-
-err_out:
- kfree(bridge);
- return NULL;
-}
-
/**
* pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
* @hose: Pointer to the PCI host controller instance structure
*/
void pcibios_scan_phb(struct pci_controller *hose)
{
- LIST_HEAD(resources);
- struct pci_bus *bus;
struct device_node *node = hose->dn;
int mode;
+ struct pci_host_bridge *bridge;
+ int error;
pr_debug("PCI: Scanning PHB %pOF\n", node);
+ /* The allocation should ideally be done in pcibios_alloc_controller(),
+ * but pci_alloc_host_bridge() requires slab to work first */
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return;
+
/* Get some IO space for the new PHB */
pcibios_setup_phb_io_space(hose);
/* Wire up PHB bus resources */
- pcibios_setup_phb_resources(hose, &resources);
+ pcibios_setup_phb_resources(hose, &bridge->windows);
hose->busn.start = hose->first_busno;
hose->busn.end = hose->last_busno;
hose->busn.flags = IORESOURCE_BUS;
- pci_add_resource(&resources, &hose->busn);
+ pci_add_resource(&bridge->windows, &hose->busn);
+
+ bridge->dev.parent = hose->parent;
+ bridge->sysdata = hose;
+ bridge->busnr = hose->first_busno;
+ bridge->ops = hose->ops;
- /* Create an empty bus for the toplevel */
- bus = pci_create_root_bus(hose->parent, hose->first_busno,
- hose->ops, hose, &resources);
- if (bus == NULL) {
+ error = pci_register_host_bridge(bridge);
+ if (error < 0) {
pr_err("Failed to create bus for PCI domain %04x\n",
hose->global_number);
- pci_free_resource_list(&resources);
+ pci_free_host_bridge(bridge);
return;
}
- hose->bus = bus;
+ hose->bridge = bridge;
+ hose->bus = bridge->bus;
/* Get probe mode and perform scan */
mode = PCI_PROBE_NORMAL;
if (node && hose->controller_ops.probe_mode)
- mode = hose->controller_ops.probe_mode(bus);
+ mode = hose->controller_ops.probe_mode(bridge->bus);
pr_debug(" probe mode: %d\n", mode);
if (mode == PCI_PROBE_DEVTREE)
- of_scan_bus(node, bus);
+ of_scan_bus(node, bridge->bus);
if (mode == PCI_PROBE_NORMAL) {
- pci_bus_update_busn_res_end(bus, 255);
- hose->last_busno = pci_scan_child_bus(bus);
- pci_bus_update_busn_res_end(bus, hose->last_busno);
+ pci_bus_update_busn_res_end(bridge->bus, 255);
+ hose->last_busno = pci_scan_child_bus(bridge->bus);
+ pci_bus_update_busn_res_end(bridge->bus, hose->last_busno);
}
/* Platform gets a chance to do some global fixups before
@@ -1671,9 +1653,9 @@ void pcibios_scan_phb(struct pci_controller *hose)
ppc_md.pcibios_fixup_phb(hose);
/* Configure PCI Express settings */
- if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
+ if (bridge->bus && !pci_has_flag(PCI_PROBE_ONLY)) {
struct pci_bus *child;
- list_for_each_entry(child, &bus->children, node)
+ list_for_each_entry(child, &bridge->bus->children, node)
pcie_bus_configure_settings(child);
}
}
--
2.18.0
^ permalink raw reply related
* [RFC 12/15] PCI: make pcibios_bus_add_device() a callback function
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
Weak functions are confusion, and we can now add callback pointers
to pci host bridges for any controller, so let's make this one
a callback rather than a __weak global function.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/kernel/pci-common.c | 7 +------
arch/sh/drivers/pci/pci.c | 1 +
arch/sh/drivers/pci/pcie-sh7786.c | 3 ++-
arch/sh/include/asm/pci.h | 2 ++
drivers/pci/bus.c | 8 +++++++-
include/linux/pci.h | 2 +-
6 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 096011ec8670..afc9598e4349 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -270,12 +270,6 @@ int pcibios_sriov_disable(struct pci_dev *pdev)
#endif /* CONFIG_PCI_IOV */
-void pcibios_bus_add_device(struct pci_dev *pdev)
-{
- if (ppc_md.pcibios_bus_add_device)
- ppc_md.pcibios_bus_add_device(pdev);
-}
-
static resource_size_t pcibios_io_size(const struct pci_controller *hose)
{
#ifdef CONFIG_PPC64
@@ -1617,6 +1611,7 @@ void pcibios_scan_phb(struct pci_controller *hose)
hose->busn.flags = IORESOURCE_BUS;
pci_add_resource(&bridge->windows, &hose->busn);
+ bridge->bus_add_device = ppc_md->pcibios_bus_add_device;
bridge->dev.parent = hose->parent;
bridge->sysdata = hose;
bridge->busnr = hose->first_busno;
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 8256626bc53c..d5c01a86cde1 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -65,6 +65,7 @@ static void pcibios_scanbus(struct pci_channel *hose)
bridge->ops = hose->pci_ops;
bridge->swizzle_irq = pci_common_swizzle;
bridge->map_irq = pcibios_map_platform_irq;
+ bridge->bus_add_device = hose->bus_add_device;
ret = pci_scan_root_bus_bridge(bridge);
if (ret) {
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 3d81a8b80942..ab78356681a0 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -122,6 +122,7 @@ extern struct pci_ops sh7786_pci_ops;
.reg_base = start, \
.mem_offset = 0, \
.io_offset = 0, \
+ .bus_add_device = sh7786_pci_bus_add_device, \
}
static struct pci_channel sh7786_pci_channels[] = {
@@ -488,7 +489,7 @@ int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
return evt2irq(0xae0);
}
-void pcibios_bus_add_device(struct pci_dev *pdev)
+static void sh7786_pci_bus_add_device(struct pci_dev *pdev)
{
pdev->dev.dma_pfn_offset = dma_pfn_offset;
}
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 10a36b1cf2ea..e605141cbcbe 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -35,6 +35,8 @@ struct pci_channel {
/* Optional error handling */
struct timer_list err_timer, serr_timer;
unsigned int err_irq, serr_irq;
+
+ void (*bus_add_device)(struct pci_dev *pdev);
};
/* arch/sh/drivers/pci/pci.c */
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 5cb40b2518f9..45873ac1a49c 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -299,7 +299,13 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
-void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
+static void pcibios_bus_add_device(struct pci_dev *pdev)
+{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
+
+ if (bridge->bus_add_device)
+ bridge->bus_add_device(pdev);
+}
/**
* pci_bus_add_device - start driver for a single device
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1dd8a3ecf753..d1072690cb4f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -475,6 +475,7 @@ struct pci_host_bridge {
u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */
int (*map_irq)(const struct pci_dev *, u8, u8);
void (*release_fn)(struct pci_host_bridge *);
+ void (*bus_add_device)(struct pci_dev *pdev);
void *release_data;
struct msi_controller *msi;
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
@@ -880,7 +881,6 @@ extern struct list_head pci_root_buses; /* List of all known PCI buses */
int no_pci_devices(void);
void pcibios_resource_survey_bus(struct pci_bus *bus);
-void pcibios_bus_add_device(struct pci_dev *pdev);
void pcibios_add_bus(struct pci_bus *bus);
void pcibios_remove_bus(struct pci_bus *bus);
void pcibios_fixup_bus(struct pci_bus *);
--
2.18.0
^ permalink raw reply related
* [RFC 15/15] PCI: make pcibios_add_bus/remove_bus callbacks
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
These are mostly not architecture specific but are meant for particular
PCI host bridge implementations, in particular for the ACPI version.
Turn them both into callback functions that are implemented by the
APCI PCI implementation as well as the one architecture that overrides
pcibios_remove_bus.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/pci.c | 10 ----------
arch/ia64/pci/pci.c | 10 ----------
arch/s390/pci/pci.c | 3 ++-
arch/x86/pci/common.c | 10 ----------
drivers/acpi/pci_root.c | 2 ++
drivers/pci/probe.c | 12 ++++++++++--
include/linux/pci.h | 2 ++
7 files changed, 16 insertions(+), 33 deletions(-)
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 8958a7c32a9f..99fac25efe88 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -191,14 +191,4 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
return bus;
}
-void pcibios_add_bus(struct pci_bus *bus)
-{
- acpi_pci_add_bus(bus);
-}
-
-void pcibios_remove_bus(struct pci_bus *bus)
-{
- acpi_pci_remove_bus(bus);
-}
-
#endif
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 511b8a058d80..f47e0920d308 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -367,16 +367,6 @@ void pcibios_fixup_bus(struct pci_bus *b)
platform_pci_fixup_bus(b);
}
-void pcibios_add_bus(struct pci_bus *bus)
-{
- acpi_pci_add_bus(bus);
-}
-
-void pcibios_remove_bus(struct pci_bus *bus)
-{
- acpi_pci_remove_bus(bus);
-}
-
void pcibios_set_master (struct pci_dev *dev)
{
/* No special bus mastering setup handling */
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index b21205f131ce..120beb83b6a5 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -769,7 +769,7 @@ static void zpci_free_domain(struct zpci_dev *zdev)
spin_unlock(&zpci_domain_lock);
}
-void pcibios_remove_bus(struct pci_bus *bus)
+static void zpci_remove_bus(struct pci_bus *bus)
{
struct zpci_dev *zdev = get_zdev_by_bus(bus);
@@ -801,6 +801,7 @@ static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
bridge->sysdata = sysdata;
bridge->busnr = bus;
bridge->ops = ops;
+ bridge->remove_bus = zpci_remove_bus;
error = pci_scan_root_bus_bridge(bridge);
if (error < 0)
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 920d0885434c..987e6fefd5d3 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -168,16 +168,6 @@ void pcibios_fixup_bus(struct pci_bus *b)
pcibios_fixup_device_resources(dev);
}
-void pcibios_add_bus(struct pci_bus *bus)
-{
- acpi_pci_add_bus(bus);
-}
-
-void pcibios_remove_bus(struct pci_bus *bus)
-{
- acpi_pci_remove_bus(bus);
-}
-
/*
* Only use DMI information to set this if nothing was passed
* on the kernel command line (which was parsed earlier).
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 5da0f70c4e65..cf7a9a7bf1e7 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -911,6 +911,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
bridge->busnr = busnum;
bridge->ops = ops->pci_ops;
bridge->prepare = acpi_pci_root_bridge_prepare;
+ bridge->add_bus = acpi_pci_add_bus;
+ bridge->remove_bus = acpi_pci_remove_bus;
pci_set_host_bridge_release(bridge, acpi_pci_root_release_info,
info);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f493d7e299e6..86a678fa8c13 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2905,12 +2905,20 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
-void __weak pcibios_add_bus(struct pci_bus *bus)
+void pcibios_add_bus(struct pci_bus *bus)
{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+
+ if (bridge->add_bus)
+ bridge->add_bus(bus);
}
-void __weak pcibios_remove_bus(struct pci_bus *bus)
+void pcibios_remove_bus(struct pci_bus *bus)
{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+
+ if (bridge->remove_bus)
+ bridge->remove_bus(bus);
}
int pci_host_probe(struct pci_host_bridge *bridge)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 24216daef6f8..bc9635313747 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -479,6 +479,8 @@ struct pci_host_bridge {
void (*bus_add_device)(struct pci_dev *pdev);
int (*alloc_irq)(struct pci_dev *);
int (*free_irq)(struct pci_dev *);
+ void (*add_bus)(struct pci_bus *);
+ void (*remove_bus)(struct pci_bus *);
void *release_data;
struct msi_controller *msi;
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
--
2.18.0
^ permalink raw reply related
* [RFC 09/15] PCI: xenfront: clean up pcifront_scan_root()
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
Merging pci_scan_root_bus() into pcifront_scan_root() simplifies
the implementation and makes it more readable. We can allocate
the pcifront_sd structure along with the bridge structure, which
helps manage its lifetime rules so we don't free it before the
device has been released.
There are two small issues that I noticed that could be improved:
- It seems we unregister the 'bus' device that is a child of the
'pci_host_bridge' device after we unregister its parent in
pcifront_free_roots(), which seems odd.
- We probably don't need an extra pci_bus_entry list at all,
but could instead walk the children of the pcifront_device,
which are all pci_host_bridge devices.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/xen-pcifront.c | 67 ++++++++++++--------------------------
1 file changed, 21 insertions(+), 46 deletions(-)
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 24070e1c5f22..a5eb6cb02bec 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -443,40 +443,12 @@ static int pcifront_scan_bus(struct pcifront_device *pdev,
return 0;
}
-static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
-{
- struct pci_host_bridge *bridge;
- int error;
-
- bridge = pci_alloc_host_bridge(0);
- if (!bridge)
- return NULL;
-
- list_splice_init(resources, &bridge->windows);
- bridge->dev.parent = parent;
- bridge->sysdata = sysdata;
- bridge->busnr = bus;
- bridge->ops = ops;
-
- error = pci_scan_root_bus_bridge(bridge);
- if (error < 0)
- goto err_out;
-
- return bridge->bus;
-
-err_out:
- kfree(bridge);
- return NULL;
-}
-
static int pcifront_scan_root(struct pcifront_device *pdev,
unsigned int domain, unsigned int bus)
{
- struct pci_bus *b;
- LIST_HEAD(resources);
struct pcifront_sd *sd = NULL;
struct pci_bus_entry *bus_entry = NULL;
+ struct pci_host_bridge *bridge;
int err = 0;
static struct resource busn_res = {
.start = 0,
@@ -498,50 +470,55 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
domain, bus);
+ bridge = pci_alloc_host_bridge(sizeof(*sd));
+ if (!bridge)
+ return -ENOMEM;
+
bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL);
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!bus_entry || !sd) {
+ sd = pci_host_bridge_priv(bridge);
+ if (!bus_entry) {
err = -ENOMEM;
goto err_out;
}
- pci_add_resource(&resources, &ioport_resource);
- pci_add_resource(&resources, &iomem_resource);
- pci_add_resource(&resources, &busn_res);
+ pci_add_resource(&bridge->windows, &ioport_resource);
+ pci_add_resource(&bridge->windows, &iomem_resource);
+ pci_add_resource(&bridge->windows, &busn_res);
pcifront_init_sd(sd, domain, bus, pdev);
+ bridge->dev.parent = &pdev->xdev->dev;
+ bridge->sysdata = sd;
+ bridge->busnr = bus;
+ bridge->ops = &pcifront_bus_ops;
pci_lock_rescan_remove();
- b = pci_scan_root_bus(&pdev->xdev->dev, bus,
- &pcifront_bus_ops, sd, &resources);
- if (!b) {
+ err = pci_scan_root_bus_bridge(bridge);
+ if (err < 0) {
dev_err(&pdev->xdev->dev,
"Error creating PCI Frontend Bus!\n");
- err = -ENOMEM;
pci_unlock_rescan_remove();
- pci_free_resource_list(&resources);
goto err_out;
}
- bus_entry->bus = b;
+ bus_entry->bus = bridge->bus;
list_add(&bus_entry->list, &pdev->root_buses);
/* pci_scan_root_bus skips devices which do not have a
* devfn==0. The pcifront_scan_bus enumerates all devfn. */
- err = pcifront_scan_bus(pdev, domain, bus, b);
+ err = pcifront_scan_bus(pdev, domain, bus, bridge->bus);
/* Claim resources before going "live" with our devices */
- pci_walk_bus(b, pcifront_claim_resource, pdev);
+ pci_walk_bus(bridge->bus, pcifront_claim_resource, pdev);
/* Create SysFS and notify udev of the devices. Aka: "going live" */
- pci_bus_add_devices(b);
+ pci_bus_add_devices(bridge->bus);
pci_unlock_rescan_remove();
return err;
err_out:
+ pci_free_host_bridge(bridge);
kfree(bus_entry);
- kfree(sd);
return err;
}
@@ -605,8 +582,6 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
free_root_bus_devs(bus_entry->bus);
- kfree(bus_entry->bus->sysdata);
-
device_unregister(bus_entry->bus->bridge);
pci_remove_bus(bus_entry->bus);
--
2.18.0
^ permalink raw reply related
* [RFC 05/15] PCI: move pci_create_root_bus into callers
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
There are only seven remaining callers of the old pci_scan_root_bus()
interface. Since we want to expose the pci_host_bridge structure
everywhere and discourage users from calling the old interfaces, let's
move the implementation into the respective callsites.
While this duplicates the source code, it makes the object code smaller
for almost all users by avoiding the global implementation, and it allows
further cleanup of the callers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/kernel/pci-common.c | 28 +++++++++++++++++++++++++++
arch/sparc/kernel/pci.c | 28 +++++++++++++++++++++++++++
drivers/acpi/pci_root.c | 30 ++++++++++++++++++++++++++++-
drivers/parisc/dino.c | 28 +++++++++++++++++++++++++++
drivers/parisc/lba_pci.c | 28 +++++++++++++++++++++++++++
drivers/pci/controller/pci-hyperv.c | 28 +++++++++++++++++++++++++++
drivers/pci/controller/vmd.c | 30 ++++++++++++++++++++++++++++-
drivers/pci/probe.c | 29 ----------------------------
include/linux/pci.h | 3 ---
9 files changed, 198 insertions(+), 34 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 88e4f69a09e5..57ca621a32f4 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1587,6 +1587,34 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
return of_node_get(hose->dn);
}
+static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
/**
* pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
* @hose: Pointer to the PCI host controller instance structure
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 17ea16a1337c..afbce59d9231 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -691,6 +691,34 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
pci_claim_bus_resources(child_bus);
}
+static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
struct device *parent)
{
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7433035ded95..85dbcf47015b 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -873,6 +873,34 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
__acpi_pci_root_release_info(bridge->release_data);
}
+static struct pci_bus *acpi_pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
struct acpi_pci_root_ops *ops,
struct acpi_pci_root_info *info,
@@ -902,7 +930,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
pci_acpi_root_add_resources(info);
pci_add_resource(&info->resources, &root->secondary);
- bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+ bus = acpi_pci_create_root_bus(NULL, busnum, ops->pci_ops,
sysdata, &info->resources);
if (!bus)
goto out_release_info;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 7390fb8ca9d1..91c837de7616 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -882,6 +882,34 @@ static const char *cujo_vers[] = {
void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);
+static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
/*
** Determine if dino should claim this chip (return 0) or not (return 1).
** If so, initialize the chip appropriately (card-mode vs bridge mode).
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 69bd98421eb1..901b7f07fe91 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1464,6 +1464,34 @@ lba_hw_init(struct lba_device *d)
*/
static unsigned int lba_next_bus = 0;
+static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
/*
* Determine if lba should claim this chip (return 0) or not (return 1).
* If so, initialize the chip and tell other partners in crime they
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index c00f82cc54aa..df7cddea8e30 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1457,6 +1457,34 @@ static void prepopulate_bars(struct hv_pcibus_device *hbus)
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
}
+static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
/**
* create_root_hv_pci_bus() - Expose a new root PCI bus
* @hbus: Root PCI bus, as understood by this driver
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index fd2dbd7eed7b..311c9f6761ae 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -579,6 +579,34 @@ static int vmd_find_free_domain(void)
return domain + 1;
}
+static struct pci_bus *vmd_create_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ int error;
+ struct pci_host_bridge *bridge;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ bridge->dev.parent = parent;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_register_host_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
{
struct pci_sysdata *sd = &vmd->sysdata;
@@ -705,7 +733,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]);
pci_add_resource_offset(&resources, &vmd->resources[2], offset[1]);
- vmd->bus = pci_create_root_bus(&vmd->dev->dev, busn_start, &vmd_ops,
+ vmd->bus = vmd_create_root_bus(&vmd->dev->dev, busn_start, &vmd_ops,
sd, &resources);
if (!vmd->bus) {
pci_free_resource_list(&resources);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5ca7d5941ad0..eaedb4fe143a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2909,35 +2909,6 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
{
}
-struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
-{
- int error;
- struct pci_host_bridge *bridge;
-
- bridge = pci_alloc_host_bridge(0);
- if (!bridge)
- return NULL;
-
- bridge->dev.parent = parent;
-
- list_splice_init(resources, &bridge->windows);
- bridge->sysdata = sysdata;
- bridge->busnr = bus;
- bridge->ops = ops;
-
- error = pci_register_host_bridge(bridge);
- if (error < 0)
- goto err_out;
-
- return bridge->bus;
-
-err_out:
- kfree(bridge);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(pci_create_root_bus);
-
int pci_host_probe(struct pci_host_bridge *bridge)
{
struct pci_bus *bus, *child;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index e1337148cf9f..1dd8a3ecf753 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -905,9 +905,6 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
void pcibios_scan_specific_bus(int busn);
struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
-struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata,
- struct list_head *resources);
int pci_host_probe(struct pci_host_bridge *bridge);
int pci_register_host_bridge(struct pci_host_bridge *);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
--
2.18.0
^ permalink raw reply related
* [RFC 01/15] PCI: clean up legacy host bridge scan functions
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
Aside from the modern pci_host_bridge based interfaces, we have a couple
of interfaces from old times that are still used in a couple of platforms:
pci_create_root_bus(), pci_scan_bus() and pci_scan_root_bus().
As a first step towards getting everybody to use the new interfaces,
this simplifies the latter two to call the pci_alloc_host_bridge() and
pci_register_host_bridge()/pci_scan_root_bus_bridge() interfaces directly.
The behavior should be entirely unchanged here, but we can then push
down the functions into the individual host implementations.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/probe.c | 86 ++++++++++++++++++++++++---------------------
1 file changed, 45 insertions(+), 41 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ec784009a36b..b0f666271245 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -23,13 +23,6 @@
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
-static struct resource busn_resource = {
- .name = "PCI busn",
- .start = 0,
- .end = 255,
- .flags = IORESOURCE_BUS,
-};
-
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
@@ -3060,53 +3053,64 @@ EXPORT_SYMBOL(pci_scan_root_bus_bridge);
struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
- struct resource_entry *window;
- bool found = false;
- struct pci_bus *b;
- int max;
-
- resource_list_for_each_entry(window, resources)
- if (window->res->flags & IORESOURCE_BUS) {
- found = true;
- break;
- }
+ struct pci_host_bridge *bridge;
+ int error;
- b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
- if (!b)
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
return NULL;
- if (!found) {
- dev_info(&b->dev,
- "No busn resource found for root bus, will use [bus %02x-ff]\n",
- bus);
- pci_bus_insert_busn_res(b, bus, 255);
- }
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
- max = pci_scan_child_bus(b);
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
- if (!found)
- pci_bus_update_busn_res_end(b, max);
+ return bridge->bus;
- return b;
+err_out:
+ kfree(bridge);
+ return NULL;
}
EXPORT_SYMBOL(pci_scan_root_bus);
+static struct resource busn_resource = {
+ .name = "PCI busn",
+ .start = 0,
+ .end = 255,
+ .flags = IORESOURCE_BUS,
+};
+
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
void *sysdata)
{
- LIST_HEAD(resources);
- struct pci_bus *b;
+ struct pci_host_bridge *bridge;
+ int error;
- pci_add_resource(&resources, &ioport_resource);
- pci_add_resource(&resources, &iomem_resource);
- pci_add_resource(&resources, &busn_resource);
- b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
- if (b) {
- pci_scan_child_bus(b);
- } else {
- pci_free_resource_list(&resources);
- }
- return b;
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ goto err;
+
+ pci_add_resource(&bridge->windows, &ioport_resource);
+ pci_add_resource(&bridge->windows, &iomem_resource);
+ pci_add_resource(&bridge->windows, &busn_resource);
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err;
+
+ return bridge->bus;
+
+err:
+ pci_free_host_bridge(bridge);
+ return NULL;
}
EXPORT_SYMBOL(pci_scan_bus);
--
2.18.0
^ permalink raw reply related
* [RFC 04/15] PCI: export pci_register_host_bridge
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
There are a couple of users of the old pci_create_root_bus() interface,
which calls pci_register_host_bridge() without actually scanning the bus.
In order to get those callers a little closer to the current method
of separating the allocation and probing of the host bridge, this
exports the internal interface to modules. If all the callers can
get moved over to pci_host_probe() or pci_scan_root_bus_bridge()
later, the export can be removed again.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/probe.c | 25 ++++++++++++++++++++++++-
include/linux/pci.h | 1 +
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cf169742c03e..5ca7d5941ad0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -762,7 +762,29 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus)
dev_set_msi_domain(&bus->dev, d);
}
-static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+/*
+ * pci_register_host_bridge() - Register a host bridge without scanning
+ *
+ * @bridge: a newly allocated host bridge structure
+ *
+ * This is the core part of bringing up a new PCI host bridge,
+ * before we scan for attached devices and register them as
+ * pci_dev.
+ *
+ * For the most part, this is an implementation detail of the
+ * pci_host_probe() interface, which brings up the entire bus,
+ * bus some older platforms still call it directly and manually
+ * scan for devices.
+ *
+ * If your driver uses this, try to convert it to using
+ * pci_host_probe() instead.
+ *
+ * Return: zero on suggess, or a negative error code.
+ * Note: after pci_register_host_bridge() successfully returns,
+ * the pci_host_bridge device is alive in driver core, and must
+ * not be freed directly.
+ */
+int pci_register_host_bridge(struct pci_host_bridge *bridge)
{
struct device *parent = bridge->dev.parent;
struct resource_entry *window, *n;
@@ -877,6 +899,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
kfree(bus);
return err;
}
+EXPORT_SYMBOL_GPL(pci_register_host_bridge);
static bool pci_bridge_child_ext_cfg_accessible(struct pci_dev *bridge)
{
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d226e06fb5e5..e1337148cf9f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -909,6 +909,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
int pci_host_probe(struct pci_host_bridge *bridge);
+int pci_register_host_bridge(struct pci_host_bridge *);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);
--
2.18.0
^ permalink raw reply related
* [RFC 00/15] PCI: turn some __weak functions into callbacks
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
This is made possible through work from Lorenzo and others to
convert many of the existing drivers, as well as the removal
of some of the older architectures that nobody used.
I'm adding a bit of duplication into the less maintained code
here, but it makes everything more consistent, and gives an
easy place to hook up callback functions etc.
The three parts of this series are:
a) push up the registration into the callers (this is where
code gets added)
b) clean up some of the more common host bridge
implementations again to integrate that code better.
This could be done for the rest as well, or we could just
leave them alone.
c) start moving the __weak functions into callbacks in
pci_host_bridge. This is intentionally incomplete, since
it is a lot of work to do it for all those functions,
and I want to get consensus on the approach first, as well
as maybe get other developers to help out with the rest.
Please have a look.
Arnd
[1] https://lore.kernel.org/lkml/4288331.jNpl6KXlNO@wuerfel/
[2] https://patchwork.kernel.org/patch/10555657/
Arnd Bergmann (15):
PCI: clean up legacy host bridge scan functions
PCI: move pci_scan_bus into callers
PCI: move pci_scan_root_bus into callers
PCI: export pci_register_host_bridge
PCI: move pci_create_root_bus into callers
powerpc/pci: fold pci_create_root_bus into pcibios_scan_phb
PCI/ACPI: clean up acpi_pci_root_create()
x86: PCI: clean up pcibios_scan_root()
PCI: xenfront: clean up pcifront_scan_root()
sparc/PCI: simplify pci_scan_one_pbm
PCI: hyperv: convert to pci_scan_root_bus_bridge
PCI: make pcibios_bus_add_device() a callback function
PCI: turn pcibios_alloc_irq into a callback
PCI: make pcibios_root_bridge_prepare a callback
PCI: make pcibios_add_bus/remove_bus callbacks
arch/arm64/kernel/pci.c | 40 ++-----
arch/ia64/pci/pci.c | 25 +----
arch/ia64/sn/kernel/io_init.c | 27 +++++
arch/microblaze/pci/pci-common.c | 27 +++++
arch/powerpc/include/asm/pci-bridge.h | 3 +
arch/powerpc/kernel/pci-common.c | 60 +++++------
arch/s390/pci/pci.c | 30 +++++-
arch/sh/drivers/pci/pci.c | 1 +
arch/sh/drivers/pci/pcie-sh7786.c | 3 +-
arch/sh/include/asm/pci.h | 2 +
arch/sparc/kernel/pci.c | 40 ++++---
arch/sparc/kernel/pcic.c | 35 ++++++
arch/x86/pci/acpi.c | 15 +--
arch/x86/pci/common.c | 42 ++++----
arch/xtensa/kernel/pci.c | 27 +++++
drivers/acpi/pci_root.c | 43 +++++---
drivers/parisc/dino.c | 28 +++++
drivers/parisc/lba_pci.c | 28 +++++
drivers/pci/bus.c | 8 +-
drivers/pci/controller/pci-hyperv.c | 47 ++++----
drivers/pci/controller/vmd.c | 30 +++++-
drivers/pci/hotplug/ibmphp_core.c | 35 ++++++
drivers/pci/pci-driver.c | 13 ++-
drivers/pci/probe.c | 150 +++++++++-----------------
drivers/pci/xen-pcifront.c | 40 +++----
include/linux/acpi.h | 2 +
include/linux/pci.h | 17 ++-
27 files changed, 514 insertions(+), 304 deletions(-)
--
2.18.0
^ permalink raw reply
* [RFC 10/15] sparc/PCI: simplify pci_scan_one_pbm
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
We no longer need a separate pci_create_root_bus() function, and
merging it into pci_scan_one_pbm() makes the implementation easier
to understand.
A possible future cleanup would move the allocation of the
pci_host_bridge structure into the callers of pci_scan_one_pbm,
and avoid duplication between pci_host_bridge and pci_pbm_info
fields.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/sparc/kernel/pci.c | 62 ++++++++++++++---------------------------
1 file changed, 21 insertions(+), 41 deletions(-)
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index afbce59d9231..0d34fb2ac55b 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -691,70 +691,50 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
pci_claim_bus_resources(child_bus);
}
-static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
+struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent)
{
- int error;
+ struct device_node *node = pbm->op->dev.of_node;
struct pci_host_bridge *bridge;
+ int ret;
bridge = pci_alloc_host_bridge(0);
if (!bridge)
return NULL;
bridge->dev.parent = parent;
+ bridge->sysdata = pbm;
+ bridge->busnr = pbm->pci_first_busno;
+ bridge->ops = pbm->pci_ops;
- list_splice_init(resources, &bridge->windows);
- bridge->sysdata = sysdata;
- bridge->busnr = bus;
- bridge->ops = ops;
-
- error = pci_register_host_bridge(bridge);
- if (error < 0)
- goto err_out;
-
- return bridge->bus;
-
-err_out:
- kfree(bridge);
- return NULL;
-}
-
-struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
- struct device *parent)
-{
- LIST_HEAD(resources);
- struct device_node *node = pbm->op->dev.of_node;
- struct pci_bus *bus;
-
- printk("PCI: Scanning PBM %s\n", node->full_name);
-
- pci_add_resource_offset(&resources, &pbm->io_space,
+ pci_add_resource_offset(&bridge->windows, &pbm->io_space,
pbm->io_offset);
- pci_add_resource_offset(&resources, &pbm->mem_space,
+ pci_add_resource_offset(&bridge->windows, &pbm->mem_space,
pbm->mem_offset);
if (pbm->mem64_space.flags)
- pci_add_resource_offset(&resources, &pbm->mem64_space,
+ pci_add_resource_offset(&bridge->windows, &pbm->mem64_space,
pbm->mem64_offset);
pbm->busn.start = pbm->pci_first_busno;
pbm->busn.end = pbm->pci_last_busno;
pbm->busn.flags = IORESOURCE_BUS;
- pci_add_resource(&resources, &pbm->busn);
- bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
- pbm, &resources);
- if (!bus) {
+ pci_add_resource(&bridge->windows, &pbm->busn);
+
+ printk("PCI: Scanning PBM %s\n", node->full_name);
+ ret = pci_register_host_bridge(bridge);
+ if (!ret) {
printk(KERN_ERR "Failed to create bus for %s\n",
node->full_name);
- pci_free_resource_list(&resources);
+ pci_free_host_bridge(bridge);
return NULL;
}
- pci_of_scan_bus(pbm, node, bus);
- pci_bus_register_of_sysfs(bus);
+ pci_of_scan_bus(pbm, node, bridge->bus);
+ pci_bus_register_of_sysfs(bridge->bus);
- pci_claim_bus_resources(bus);
+ pci_claim_bus_resources(bridge->bus);
- pci_bus_add_devices(bus);
- return bus;
+ pci_bus_add_devices(bridge->bus);
+ return bridge->bus;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
--
2.18.0
^ permalink raw reply related
* [RFC 03/15] PCI: move pci_scan_root_bus into callers
From: Arnd Bergmann @ 2018-08-17 10:26 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas
Cc: linux-kernel, Christoph Hellwig, Lorenzo Pieralisi,
Benjamin Herrenschmidt, linuxppc-dev, linux-acpi, Arnd Bergmann
In-Reply-To: <20180817102645.3839621-1-arnd@arndb.de>
There are only six remaining callers of the old pci_scan_root_bus()
interface. Since we want to expose the pci_host_bridge structure
everywhere and discourage users from calling the old interfaces, let's
move the implementation into the respective callsites.
While this duplicates the source code, it makes the object code smaller
for almost all users by avoiding the global implementation, and it allows
further cleanup of the callers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/ia64/sn/kernel/io_init.c | 27 +++++++++++++++++++++++++++
arch/microblaze/pci/pci-common.c | 27 +++++++++++++++++++++++++++
arch/s390/pci/pci.c | 27 +++++++++++++++++++++++++++
arch/x86/pci/common.c | 27 +++++++++++++++++++++++++++
arch/xtensa/kernel/pci.c | 27 +++++++++++++++++++++++++++
drivers/pci/probe.c | 28 ----------------------------
drivers/pci/xen-pcifront.c | 27 +++++++++++++++++++++++++++
include/linux/pci.h | 3 ---
8 files changed, 162 insertions(+), 31 deletions(-)
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index d63809a6adfa..e768702a7b45 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -213,6 +213,33 @@ sn_io_slot_fixup(struct pci_dev *dev)
}
EXPORT_SYMBOL(sn_io_slot_fixup);
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
/*
* sn_pci_controller_fixup() - This routine sets up a bus's resources
* consistent with the Linux PCI abstraction layer.
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index f34346d56095..302071385e1b 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -977,6 +977,33 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose,
(unsigned long)hose->io_base_virt - _IO_BASE);
}
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
static void pcibios_scan_phb(struct pci_controller *hose)
{
LIST_HEAD(resources);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 9f6f392a4461..b21205f131ce 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -786,6 +786,33 @@ void pcibios_remove_bus(struct pci_bus *bus)
kfree(zdev);
}
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
static int zpci_scan_bus(struct zpci_dev *zdev)
{
LIST_HEAD(resources);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index d4ec117c1142..e740d9aa4024 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -453,6 +453,33 @@ void __init dmi_check_pciprobe(void)
dmi_check_system(pciprobe_dmi_table);
}
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
void pcibios_scan_root(int busnum)
{
struct pci_bus *bus;
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 21f13e9aabe1..5a8fd67e6c5e 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -116,6 +116,33 @@ static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
}
}
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
static int __init pcibios_init(void)
{
struct pci_controller *pci_ctrl;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 12c3aa63c34d..cf169742c03e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -3050,34 +3050,6 @@ int pci_scan_root_bus_bridge(struct pci_host_bridge *bridge)
}
EXPORT_SYMBOL(pci_scan_root_bus_bridge);
-struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata, struct list_head *resources)
-{
- struct pci_host_bridge *bridge;
- int error;
-
- bridge = pci_alloc_host_bridge(0);
- if (!bridge)
- return NULL;
-
- list_splice_init(resources, &bridge->windows);
- bridge->dev.parent = parent;
- bridge->sysdata = sysdata;
- bridge->busnr = bus;
- bridge->ops = ops;
-
- error = pci_scan_root_bus_bridge(bridge);
- if (error < 0)
- goto err_out;
-
- return bridge->bus;
-
-err_out:
- kfree(bridge);
- return NULL;
-}
-EXPORT_SYMBOL(pci_scan_root_bus);
-
/**
* pci_rescan_bus_bridge_resize - Scan a PCI bus for devices
* @bridge: PCI bridge for the bus to scan
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index eba6e33147a2..24070e1c5f22 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -443,6 +443,33 @@ static int pcifront_scan_bus(struct pcifront_device *pdev,
return 0;
}
+static struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+ struct pci_host_bridge *bridge;
+ int error;
+
+ bridge = pci_alloc_host_bridge(0);
+ if (!bridge)
+ return NULL;
+
+ list_splice_init(resources, &bridge->windows);
+ bridge->dev.parent = parent;
+ bridge->sysdata = sysdata;
+ bridge->busnr = bus;
+ bridge->ops = ops;
+
+ error = pci_scan_root_bus_bridge(bridge);
+ if (error < 0)
+ goto err_out;
+
+ return bridge->bus;
+
+err_out:
+ kfree(bridge);
+ return NULL;
+}
+
static int pcifront_scan_root(struct pcifront_device *pdev,
unsigned int domain, unsigned int bus)
{
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d77ce35a2b33..d226e06fb5e5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -912,9 +912,6 @@ int pci_host_probe(struct pci_host_bridge *bridge);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);
-struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata,
- struct list_head *resources);
int pci_scan_root_bus_bridge(struct pci_host_bridge *bridge);
struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
int busnr);
--
2.18.0
^ permalink raw reply related
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