LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] [RFC] Emulate "lwsync" to run standard user land on e500 cores
From: Kumar Gala @ 2013-10-24  9:55 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Scott Wood, linuxppc-dev, Wolfgang Denk
In-Reply-To: <1382607919.9395.56.camel@pasglop>


On Oct 24, 2013, at 4:45 AM, Benjamin Herrenschmidt wrote:

> On Wed, 2013-10-23 at 23:06 -0500, Kumar Gala wrote:
>> On Oct 23, 2013, at 5:15 AM, Scott Wood wrote:
>>=20
>>> On Wed, 2013-10-23 at 00:07 -0500, Kumar Gala wrote:
>>>> On Oct 18, 2013, at 2:38 AM, Wolfgang Denk wrote:
>>>>> diff --git a/arch/powerpc/kernel/traps.c =
b/arch/powerpc/kernel/traps.c
>>>>> index f783c93..f330374 100644
>>>>> --- a/arch/powerpc/kernel/traps.c
>>>>> +++ b/arch/powerpc/kernel/traps.c
>>>>> @@ -986,6 +986,13 @@ static int emulate_instruction(struct pt_regs =
*regs)
>>>>> 		return 0;
>>>>> 	}
>>>>>=20
>>>>> +	/* Emulating the lwsync insn as a sync insn */
>>>>> +	if (instword =3D=3D PPC_INST_LWSYNC) {
>>>>> +		PPC_WARN_EMULATED(lwsync, regs);
>>>>> +		asm volatile("sync" : : : "memory");
>>>>=20
>>>> Do we really need the inline asm?  Doesn't the fact of just taking =
an exception and returning from it equate to a sync.
>>>=20
>>> No, it doesn't equate to a sync.  See the discussion here:
>>> http://patchwork.ozlabs.org/patch/256747/
>>>=20
>>=20
>> Thanks.=20
>>=20
>> I'm not sure I'm a fan of doing this as it silently hides a =
significant performance impact.
>>=20
>> Could we possible re-write the userspace instruction to be a 'sync' =
when we hit this?
>=20
> Rewriting user space is a can of worms I wouldn't get into ... is any
> other arch doing it ?

Fair enough
>=20
> I'm not too worried as long as we warn and account them.

Than, I'd ask this be under a Kconfig option that is disabled by =
default.  Users should have to explicitly enable this so they know what =
they are doing.

- k

^ permalink raw reply

* Re: [PATCH] [RFC] Emulate "lwsync" to run standard user land on e500 cores
From: Benjamin Herrenschmidt @ 2013-10-24  9:45 UTC (permalink / raw)
  To: Kumar Gala; +Cc: Scott Wood, linuxppc-dev, Wolfgang Denk
In-Reply-To: <BE5B0245-4ED1-4E3F-ADB1-F6A70C8FE3E1@kernel.crashing.org>

On Wed, 2013-10-23 at 23:06 -0500, Kumar Gala wrote:
> On Oct 23, 2013, at 5:15 AM, Scott Wood wrote:
> 
> > On Wed, 2013-10-23 at 00:07 -0500, Kumar Gala wrote:
> >> On Oct 18, 2013, at 2:38 AM, Wolfgang Denk wrote:
> >>> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> >>> index f783c93..f330374 100644
> >>> --- a/arch/powerpc/kernel/traps.c
> >>> +++ b/arch/powerpc/kernel/traps.c
> >>> @@ -986,6 +986,13 @@ static int emulate_instruction(struct pt_regs *regs)
> >>> 		return 0;
> >>> 	}
> >>> 
> >>> +	/* Emulating the lwsync insn as a sync insn */
> >>> +	if (instword == PPC_INST_LWSYNC) {
> >>> +		PPC_WARN_EMULATED(lwsync, regs);
> >>> +		asm volatile("sync" : : : "memory");
> >> 
> >> Do we really need the inline asm?  Doesn't the fact of just taking an exception and returning from it equate to a sync.
> > 
> > No, it doesn't equate to a sync.  See the discussion here:
> > http://patchwork.ozlabs.org/patch/256747/
> > 
> 
> Thanks. 
> 
> I'm not sure I'm a fan of doing this as it silently hides a significant performance impact.
> 
> Could we possible re-write the userspace instruction to be a 'sync' when we hit this?

Rewriting user space is a can of worms I wouldn't get into ... is any
other arch doing it ?

I'm not too worried as long as we warn and account them.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 1/3] sched: Fix nohz_kick_needed to consider the nr_busy of the parent domain's group
From: Preeti U Murthy @ 2013-10-24  8:07 UTC (permalink / raw)
  To: Vincent Guittot, Peter Zijlstra, Ingo Molnar
  Cc: Michael Neuling, Mike Galbraith, linuxppc-dev, linux-kernel,
	Anton Blanchard, Paul Turner
In-Reply-To: <CAKfTPtAUFdmc7PasebNksYztMwRrWsGWPgN6JJJurddu+UP-hQ@mail.gmail.com>

Hi Vincent,

I have addressed your comments and below is the fresh patch. This patch
applies on PATCH 2/3 posted in this thread.

Regards
Preeti U Murthy


sched:Remove un-necessary iterations over sched domains to update/query nr_busy_cpus

From: Preeti U Murthy <preeti@linux.vnet.ibm.com>

nr_busy_cpus parameter is used by nohz_kick_needed() to find out the number
of busy cpus in a sched domain which has SD_SHARE_PKG_RESOURCES flag set.
Therefore instead of updating nr_busy_cpus at every level of sched domain,
since it is irrelevant, we can update this parameter only at the parent
domain of the sd which has this flag set. Introduce a per-cpu parameter
sd_busy which represents this parent domain.

In nohz_kick_needed() we directly query the nr_busy_cpus parameter
associated with the groups of sd_busy.

By associating sd_busy with the highest domain which has
SD_SHARE_PKG_RESOURCES flag set, we cover all lower level domains which could
have this flag set and trigger nohz_idle_balancing if any of the levels have
more than one busy cpu.

sd_busy is irrelevant for asymmetric load balancing.

While we are at it, we might as well change the nohz_idle parameter to be
updated at the sd_busy domain level alone and not the base domain level of a CPU.
This will unify the concept of busy cpus at just one level of sched domain
where it is currently used.

Signed-off-by: Preeti U Murthy<preeti@linux.vnet.ibm.com>
---
 kernel/sched/core.c  |    5 +++++
 kernel/sched/fair.c  |   38 ++++++++++++++++++++------------------
 kernel/sched/sched.h |    1 +
 3 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index c06b8d3..c540392 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5271,6 +5271,7 @@ DEFINE_PER_CPU(struct sched_domain *, sd_llc);
 DEFINE_PER_CPU(int, sd_llc_size);
 DEFINE_PER_CPU(int, sd_llc_id);
 DEFINE_PER_CPU(struct sched_domain *, sd_numa);
+DEFINE_PER_CPU(struct sched_domain *, sd_busy);
 
 static void update_top_cache_domain(int cpu)
 {
@@ -5290,6 +5291,10 @@ static void update_top_cache_domain(int cpu)
 
 	sd = lowest_flag_domain(cpu, SD_NUMA);
 	rcu_assign_pointer(per_cpu(sd_numa, cpu), sd);
+
+	sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES);
+	if (sd)
+		rcu_assign_pointer(per_cpu(sd_busy, cpu), sd->parent);
 }
 
 /*
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e9c9549..f66cfd9 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6515,16 +6515,16 @@ static inline void nohz_balance_exit_idle(int cpu)
 static inline void set_cpu_sd_state_busy(void)
 {
 	struct sched_domain *sd;
+	int cpu = smp_processor_id();
 
 	rcu_read_lock();
-	sd = rcu_dereference_check_sched_domain(this_rq()->sd);
+	sd = rcu_dereference(per_cpu(sd_busy, cpu));
 
 	if (!sd || !sd->nohz_idle)
 		goto unlock;
 	sd->nohz_idle = 0;
 
-	for (; sd; sd = sd->parent)
-		atomic_inc(&sd->groups->sgp->nr_busy_cpus);
+	atomic_inc(&sd->groups->sgp->nr_busy_cpus);
 unlock:
 	rcu_read_unlock();
 }
@@ -6532,16 +6532,16 @@ unlock:
 void set_cpu_sd_state_idle(void)
 {
 	struct sched_domain *sd;
+	int cpu = smp_processor_id();
 
 	rcu_read_lock();
-	sd = rcu_dereference_check_sched_domain(this_rq()->sd);
+	sd = rcu_dereference(per_cpu(sd_busy, cpu));
 
 	if (!sd || sd->nohz_idle)
 		goto unlock;
 	sd->nohz_idle = 1;
 
-	for (; sd; sd = sd->parent)
-		atomic_dec(&sd->groups->sgp->nr_busy_cpus);
+	atomic_dec(&sd->groups->sgp->nr_busy_cpus);
 unlock:
 	rcu_read_unlock();
 }
@@ -6748,6 +6748,8 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
 {
 	unsigned long now = jiffies;
 	struct sched_domain *sd;
+	struct sched_group_power *sgp;
+	int nr_busy;
 
 	if (unlikely(idle_cpu(cpu)))
 		return 0;
@@ -6773,22 +6775,22 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
 		goto need_kick;
 
 	rcu_read_lock();
-	for_each_domain(cpu, sd) {
-		struct sched_group *sg = sd->groups;
-		struct sched_group_power *sgp = sg->sgp;
-		int nr_busy = atomic_read(&sgp->nr_busy_cpus);
+	sd = rcu_dereference(per_cpu(sd_busy, cpu));
 
-		if (sd->flags & SD_SHARE_PKG_RESOURCES && nr_busy > 1)
-			goto need_kick_unlock;
+	if (sd) {
+		sgp = sd->groups->sgp;
+		nr_busy = atomic_read(&sgp->nr_busy_cpus);
 
-		if (sd->flags & SD_ASYM_PACKING
-		    && (cpumask_first_and(nohz.idle_cpus_mask,
-					  sched_domain_span(sd)) < cpu))
+		if (nr_busy > 1)
 			goto need_kick_unlock;
-
-		if (!(sd->flags & (SD_SHARE_PKG_RESOURCES | SD_ASYM_PACKING)))
-			break;
 	}
+
+	sd = highest_flag_domain(cpu, SD_ASYM_PACKING);
+
+	if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
+				  sched_domain_span(sd)) < cpu))
+		goto need_kick_unlock;
+
 	rcu_read_unlock();
 	return 0;
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index ffc7087..0f1253f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -623,6 +623,7 @@ DECLARE_PER_CPU(struct sched_domain *, sd_llc);
 DECLARE_PER_CPU(int, sd_llc_size);
 DECLARE_PER_CPU(int, sd_llc_id);
 DECLARE_PER_CPU(struct sched_domain *, sd_numa);
+DECLARE_PER_CPU(struct sched_domain *, sd_busy);
 
 struct sched_group_power {
 	atomic_t ref;

^ permalink raw reply related

* RE: [PATCH 02/12][v3] pci: fsl: add structure fsl_pci
From: Zang Roy-R61911 @ 2013-10-24  4:15 UTC (permalink / raw)
  To: Kumar Gala, Lian Minghuan-B31939
  Cc: Wood Scott-B07421, Arnd Bergmann, linux-pci@vger.kernel.org,
	Bjorn Helgaas, linuxppc-dev@lists.ozlabs.org list,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <2B28E421-9B64-4CEC-9E00-8893502CE12F@kernel.crashing.org>



> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Wednesday, October 23, 2013 11:11 PM
> To: Lian Minghuan-B31939
> Cc: linuxppc-dev@lists.ozlabs.org list; Arnd Bergmann; Zang Roy-R61911;
> Wood Scott-B07421; Bjorn Helgaas; linux-pci@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH 02/12][v3] pci: fsl: add structure fsl_pci
>=20
>=20
> On Oct 23, 2013, at 5:41 AM, Minghuan Lian wrote:
>=20
> > PowerPC uses structure pci_controller to describe PCI controller, but
> > ARM uses structure pci_sys_data. In order to support PowerPC and ARM
> > simultaneously, the patch adds a structure fsl_pci that contains most
> > of the members of the pci_controller and pci_sys_data.
> > Meanwhile, it defines a interface fsl_arch_sys_to_pci() which should
> > be implemented in architecture-specific PCI controller driver to
> > convert pci_controller or pci_sys_data to fsl_pci.
> >
> > Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
> > ---
> > change log:
> > v1-v3:
> > Derived from http://patchwork.ozlabs.org/patch/278965/
> >
> > Based on upstream master.
> > Based on the discussion of RFC version here
> > http://patchwork.ozlabs.org/patch/274487/
> >
> > include/linux/fsl/pci-common.h | 41
> > +++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 41 insertions(+)
>=20
> NAK.
>=20
> We discussed this some at the ARM Summit this week and the feeling is we
> need to move to a common interface between the various ARCHs.

Can you share more about the *common interface*?
Any plan to implement the  * common interface*?
Thanks.
Roy

^ permalink raw reply

* Re: [PATCH 02/12][v3] pci: fsl: add structure fsl_pci
From: Kumar Gala @ 2013-10-24  4:11 UTC (permalink / raw)
  To: Minghuan Lian
  Cc: Arnd Bergmann, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood, linuxppc-dev@lists.ozlabs.org list, linux-arm-kernel
In-Reply-To: <1382524894-15164-2-git-send-email-Minghuan.Lian@freescale.com>


On Oct 23, 2013, at 5:41 AM, Minghuan Lian wrote:

> PowerPC uses structure pci_controller to describe PCI controller,
> but ARM uses structure pci_sys_data. In order to support PowerPC
> and ARM simultaneously, the patch adds a structure fsl_pci that
> contains most of the members of the pci_controller and pci_sys_data.
> Meanwhile, it defines a interface fsl_arch_sys_to_pci() which should
> be implemented in architecture-specific PCI controller driver to
> convert pci_controller or pci_sys_data to fsl_pci.
>=20
> Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
> ---
> change log:
> v1-v3:
> Derived from http://patchwork.ozlabs.org/patch/278965/
>=20
> Based on upstream master.
> Based on the discussion of RFC version here
> http://patchwork.ozlabs.org/patch/274487/
>=20
> include/linux/fsl/pci-common.h | 41 =
+++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 41 insertions(+)

NAK.

We discussed this some at the ARM Summit this week and the feeling is we =
need to move to a common interface between the various ARCHs.

- k

>=20
> diff --git a/include/linux/fsl/pci-common.h =
b/include/linux/fsl/pci-common.h
> index 5e4f683..e56a040 100644
> --- a/include/linux/fsl/pci-common.h
> +++ b/include/linux/fsl/pci-common.h
> @@ -102,5 +102,46 @@ struct ccsr_pci {
>=20
> };
>=20
> +/*
> + * Structure of a PCI controller (host bridge)
> + */
> +struct fsl_pci {
> +	struct list_head node;
> +	bool is_pcie;
> +	struct device_node *dn;
> +	struct device *dev;
> +
> +	int first_busno;
> +	int last_busno;
> +	int self_busno;
> +	struct resource busn;
> +
> +	struct pci_ops *ops;
> +	struct ccsr_pci __iomem *regs;
> +
> +	u32 indirect_type;
> +
> +	struct resource io_resource;
> +	resource_size_t io_base_phys;
> +	resource_size_t pci_io_size;
> +
> +	struct resource mem_resources[3];
> +	resource_size_t mem_offset[3];
> +
> +	int global_number;	/* PCI domain number */
> +
> +	resource_size_t dma_window_base_cur;
> +	resource_size_t dma_window_size;
> +
> +	void *sys;
> +};
> +
> +/*
> + * Convert architecture specific pci controller structure to fsl_pci
> + * PowerPC uses structure pci_controller and ARM uses structure =
pci_sys_data
> + * to describe pci controller.
> + */
> +extern struct fsl_pci *fsl_arch_sys_to_pci(void *sys);
> +
> #endif /* __PCI_COMMON_H */
> #endif /* __KERNEL__ */
> --=20
> 1.8.1.2
>=20

^ permalink raw reply

* Re: [PATCH 3/3] sched: Aggressive balance in domains whose groups share package resources
From: Preeti U Murthy @ 2013-10-24  4:04 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Michael Neuling, Mike Galbraith, linuxppc-dev, linux-kernel,
	Anton Blanchard, Paul Turner, Ingo Molnar
In-Reply-To: <20131022222326.GL2490@laptop.programming.kicks-ass.net>

Hi Peter,

On 10/23/2013 03:53 AM, Peter Zijlstra wrote:
> On Mon, Oct 21, 2013 at 05:15:02PM +0530, Vaidyanathan Srinivasan wrote:
>>  kernel/sched/fair.c |   18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>>
>> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
>> index 828ed97..bbcd96b 100644
>> --- a/kernel/sched/fair.c
>> +++ b/kernel/sched/fair.c
>> @@ -5165,6 +5165,8 @@ static int load_balance(int this_cpu, struct rq *this_rq,
>>  {
>>  	int ld_moved, cur_ld_moved, active_balance = 0;
>>  	struct sched_group *group;
>> +	struct sched_domain *child;
>> +	int share_pkg_res = 0;
>>  	struct rq *busiest;
>>  	unsigned long flags;
>>  	struct cpumask *cpus = __get_cpu_var(load_balance_mask);
>> @@ -5190,6 +5192,10 @@ static int load_balance(int this_cpu, struct rq *this_rq,
>>  
>>  	schedstat_inc(sd, lb_count[idle]);
>>  
>> +	child = sd->child;
>> +	if (child && child->flags & SD_SHARE_PKG_RESOURCES)
>> +		share_pkg_res = 1;
>> +
>>  redo:
>>  	if (!should_we_balance(&env)) {
>>  		*continue_balancing = 0;
>> @@ -5202,6 +5208,7 @@ redo:
>>  		goto out_balanced;
>>  	}
>>  
>> +redo_grp:
>>  	busiest = find_busiest_queue(&env, group);
>>  	if (!busiest) {
>>  		schedstat_inc(sd, lb_nobusyq[idle]);
>> @@ -5292,6 +5299,11 @@ more_balance:
>>  			if (!cpumask_empty(cpus)) {
>>  				env.loop = 0;
>>  				env.loop_break = sched_nr_migrate_break;
>> +				if (share_pkg_res &&
>> +					cpumask_intersects(cpus,
>> +						to_cpumask(group->cpumask)))
> 
> sched_group_cpus()
> 
>> +					goto redo_grp;
>> +
>>  				goto redo;
>>  			}
>>  			goto out_balanced;
>> @@ -5318,9 +5330,15 @@ more_balance:
>>  			 */
>>  			if (!cpumask_test_cpu(this_cpu,
>>  					tsk_cpus_allowed(busiest->curr))) {
>> +				cpumask_clear_cpu(cpu_of(busiest), cpus);
>>  				raw_spin_unlock_irqrestore(&busiest->lock,
>>  							    flags);
>>  				env.flags |= LBF_ALL_PINNED;
>> +				if (share_pkg_res &&
>> +					cpumask_intersects(cpus,
>> +						to_cpumask(group->cpumask)))
>> +					goto redo_grp;
>> +
>>  				goto out_one_pinned;
>>  			}
> 
> Man this retry logic is getting annoying.. isn't there anything saner we
> can do?

Let me give this a thought and get back.

Regards
Preeti U Murthy
> 

^ permalink raw reply

* Re: [PATCH] [RFC] Emulate "lwsync" to run standard user land on e500 cores
From: Kumar Gala @ 2013-10-24  4:06 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Wolfgang Denk
In-Reply-To: <1382523314.3926.21.camel@aoeu.buserror.net>


On Oct 23, 2013, at 5:15 AM, Scott Wood wrote:

> On Wed, 2013-10-23 at 00:07 -0500, Kumar Gala wrote:
>> On Oct 18, 2013, at 2:38 AM, Wolfgang Denk wrote:
>>> diff --git a/arch/powerpc/kernel/traps.c =
b/arch/powerpc/kernel/traps.c
>>> index f783c93..f330374 100644
>>> --- a/arch/powerpc/kernel/traps.c
>>> +++ b/arch/powerpc/kernel/traps.c
>>> @@ -986,6 +986,13 @@ static int emulate_instruction(struct pt_regs =
*regs)
>>> 		return 0;
>>> 	}
>>>=20
>>> +	/* Emulating the lwsync insn as a sync insn */
>>> +	if (instword =3D=3D PPC_INST_LWSYNC) {
>>> +		PPC_WARN_EMULATED(lwsync, regs);
>>> +		asm volatile("sync" : : : "memory");
>>=20
>> Do we really need the inline asm?  Doesn't the fact of just taking an =
exception and returning from it equate to a sync.
>=20
> No, it doesn't equate to a sync.  See the discussion here:
> http://patchwork.ozlabs.org/patch/256747/
>=20

Thanks.=20

I'm not sure I'm a fan of doing this as it silently hides a significant =
performance impact.

Could we possible re-write the userspace instruction to be a 'sync' when =
we hit this?

- k

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH 2/8] cell: Remove OOM message after input_allocate_device
From: Geoff Levand @ 2013-10-23 20:49 UTC (permalink / raw)
  To: Joe Perches, Arnd Bergmann
  Cc: cbe-oss-dev, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <d4dc0be1a19693fca1d8d6bbd3a7ee75163cc269.1382555436.git.joe@perches.com>

Hi Joe,

On Wed, 2013-10-23 at 12:14 -0700, Joe Perches wrote:
> Emitting an OOM message isn't necessary after input_allocate_device
> as there's a generic OOM and a dump_stack already done.
> 
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
>  arch/powerpc/platforms/cell/cbe_powerbutton.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/arch/powerpc/platforms/cell/cbe_powerbutton.c b/arch/powerpc/platforms/cell/cbe_powerbutton.c
> index 2bb8031..8804dbd 100644
> --- a/arch/powerpc/platforms/cell/cbe_powerbutton.c
> +++ b/arch/powerpc/platforms/cell/cbe_powerbutton.c
> @@ -58,7 +58,6 @@ static int __init cbe_powerbutton_init(void)
>  	dev = input_allocate_device();
>  	if (!dev) {
>  		ret = -ENOMEM;
> -		printk(KERN_ERR "%s: Not enough memory.\n", __func__);
>  		goto out;
>  	}

Arnd is out on leave, so I'll say that this looks OK.

Acked-by: Geoff Levand <geoff@infradead.org>

^ permalink raw reply

* [PATCH 2/8] cell: Remove OOM message after input_allocate_device
From: Joe Perches @ 2013-10-23 19:14 UTC (permalink / raw)
  To: linux-kernel; +Cc: cbe-oss-dev, Paul Mackerras, linuxppc-dev, Arnd Bergmann
In-Reply-To: <cover.1382555436.git.joe@perches.com>

Emitting an OOM message isn't necessary after input_allocate_device
as there's a generic OOM and a dump_stack already done.

Signed-off-by: Joe Perches <joe@perches.com>
---
 arch/powerpc/platforms/cell/cbe_powerbutton.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/powerpc/platforms/cell/cbe_powerbutton.c b/arch/powerpc/platforms/cell/cbe_powerbutton.c
index 2bb8031..8804dbd 100644
--- a/arch/powerpc/platforms/cell/cbe_powerbutton.c
+++ b/arch/powerpc/platforms/cell/cbe_powerbutton.c
@@ -58,7 +58,6 @@ static int __init cbe_powerbutton_init(void)
 	dev = input_allocate_device();
 	if (!dev) {
 		ret = -ENOMEM;
-		printk(KERN_ERR "%s: Not enough memory.\n", __func__);
 		goto out;
 	}
 
-- 
1.8.1.2.459.gbcd45b4.dirty

^ permalink raw reply related

* [PATCH 0/8] treewide: Remove OOM message after input_alloc_device
From: Joe Perches @ 2013-10-23 19:14 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbe-oss-dev, devel, alsa-devel, linux-samsung-soc, linux-doc,
	linux-iio, acpi4asus-user, platform-driver-x86, ibm-acpi-devel,
	linux-input, linuxppc-dev, linux-arm-kernel, linux-media

Joe Perches (8):
  Documentation: Remove OOM message after input_allocate_device
  cell: Remove OOM message after input_allocate_device
  hid: Remove OOM message after input_allocate_device
  input: Remove OOM message after input_allocate_device
  media: Remove OOM message after input_allocate_device
  platform:x86: Remove OOM message after input_allocate_device
  staging: Remove OOM message after input_allocate_device
  sound: Remove OOM message after input_allocate_device

 Documentation/input/input-programming.txt     | 1 -
 arch/powerpc/platforms/cell/cbe_powerbutton.c | 1 -
 drivers/hid/hid-input.c                       | 1 -
 drivers/hid/hid-picolcd_core.c                | 5 ++---
 drivers/input/joystick/as5011.c               | 2 --
 drivers/input/joystick/db9.c                  | 1 -
 drivers/input/joystick/gamecon.c              | 4 +---
 drivers/input/joystick/turbografx.c           | 1 -
 drivers/input/joystick/walkera0701.c          | 1 -
 drivers/input/keyboard/amikbd.c               | 4 +---
 drivers/input/keyboard/davinci_keyscan.c      | 1 -
 drivers/input/keyboard/gpio_keys.c            | 1 -
 drivers/input/keyboard/lpc32xx-keys.c         | 1 -
 drivers/input/keyboard/max7359_keypad.c       | 1 -
 drivers/input/keyboard/mcs_touchkey.c         | 1 -
 drivers/input/keyboard/mpr121_touchkey.c      | 1 -
 drivers/input/keyboard/nomadik-ske-keypad.c   | 1 -
 drivers/input/keyboard/opencores-kbd.c        | 1 -
 drivers/input/keyboard/pmic8xxx-keypad.c      | 1 -
 drivers/input/keyboard/pxa27x_keypad.c        | 1 -
 drivers/input/keyboard/pxa930_rotary.c        | 1 -
 drivers/input/keyboard/qt1070.c               | 1 -
 drivers/input/keyboard/qt2160.c               | 1 -
 drivers/input/keyboard/sh_keysc.c             | 1 -
 drivers/input/keyboard/tc3589x-keypad.c       | 1 -
 drivers/input/keyboard/tnetv107x-keypad.c     | 1 -
 drivers/input/keyboard/w90p910_keypad.c       | 1 -
 drivers/input/misc/88pm80x_onkey.c            | 1 -
 drivers/input/misc/88pm860x_onkey.c           | 1 -
 drivers/input/misc/arizona-haptics.c          | 4 +---
 drivers/input/misc/atlas_btns.c               | 4 +---
 drivers/input/misc/da9052_onkey.c             | 1 -
 drivers/input/misc/da9055_onkey.c             | 4 +---
 drivers/input/misc/ideapad_slidebar.c         | 1 -
 drivers/input/misc/ims-pcu.c                  | 7 +------
 drivers/input/misc/kxtj9.c                    | 4 +---
 drivers/input/misc/max8997_haptic.c           | 1 -
 drivers/input/misc/mc13783-pwrbutton.c        | 4 +---
 drivers/input/misc/mpu3050.c                  | 1 -
 drivers/input/misc/pcf8574_keypad.c           | 1 -
 drivers/input/misc/pm8xxx-vibrator.c          | 1 -
 drivers/input/misc/pmic8xxx-pwrkey.c          | 1 -
 drivers/input/misc/pwm-beeper.c               | 1 -
 drivers/input/misc/twl4030-pwrbutton.c        | 4 +---
 drivers/input/misc/twl6040-vibra.c            | 1 -
 drivers/input/mouse/appletouch.c              | 4 +---
 drivers/input/mouse/bcm5974.c                 | 4 +---
 drivers/input/mouse/cyapa.c                   | 4 +---
 drivers/input/mouse/inport.c                  | 1 -
 drivers/input/mouse/logibm.c                  | 1 -
 drivers/input/mouse/pc110pad.c                | 1 -
 drivers/input/mouse/pxa930_trkball.c          | 1 -
 drivers/input/tablet/aiptek.c                 | 5 +----
 drivers/input/tablet/gtco.c                   | 1 -
 drivers/input/touchscreen/88pm860x-ts.c       | 1 -
 drivers/input/touchscreen/atmel_mxt_ts.c      | 1 -
 drivers/input/touchscreen/atmel_tsadcc.c      | 1 -
 drivers/input/touchscreen/bu21013_ts.c        | 1 -
 drivers/input/touchscreen/cyttsp4_core.c      | 2 --
 drivers/input/touchscreen/da9034-ts.c         | 1 -
 drivers/input/touchscreen/edt-ft5x06.c        | 1 -
 drivers/input/touchscreen/eeti_ts.c           | 5 +----
 drivers/input/touchscreen/htcpen.c            | 1 -
 drivers/input/touchscreen/intel-mid-touch.c   | 1 -
 drivers/input/touchscreen/lpc32xx_ts.c        | 1 -
 drivers/input/touchscreen/mcs5000_ts.c        | 1 -
 drivers/input/touchscreen/migor_ts.c          | 1 -
 drivers/input/touchscreen/mk712.c             | 1 -
 drivers/input/touchscreen/pixcir_i2c_ts.c     | 1 -
 drivers/input/touchscreen/s3c2410_ts.c        | 1 -
 drivers/input/touchscreen/ti_am335x_tsc.c     | 1 -
 drivers/input/touchscreen/tnetv107x-ts.c      | 1 -
 drivers/media/rc/imon.c                       | 8 ++------
 drivers/media/usb/em28xx/em28xx-input.c       | 4 +---
 drivers/media/usb/pwc/pwc-if.c                | 1 -
 drivers/platform/x86/asus-laptop.c            | 5 ++---
 drivers/platform/x86/eeepc-laptop.c           | 4 +---
 drivers/platform/x86/ideapad-laptop.c         | 4 +---
 drivers/platform/x86/intel_mid_powerbtn.c     | 4 +---
 drivers/platform/x86/panasonic-laptop.c       | 5 +----
 drivers/platform/x86/thinkpad_acpi.c          | 1 -
 drivers/platform/x86/topstar-laptop.c         | 4 +---
 drivers/platform/x86/toshiba_acpi.c           | 4 +---
 drivers/staging/cptm1217/clearpad_tm1217.c    | 2 --
 drivers/staging/iio/adc/mxs-lradc.c           | 4 +---
 drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c | 2 --
 sound/pci/hda/hda_beep.c                      | 4 +---
 87 files changed, 29 insertions(+), 152 deletions(-)

-- 
1.8.1.2.459.gbcd45b4.dirty

^ permalink raw reply

* Re: [PATCH 1/3] sched: Fix nohz_kick_needed to consider the nr_busy of the parent domain's group
From: Vincent Guittot @ 2013-10-23 15:28 UTC (permalink / raw)
  To: Preeti U Murthy
  Cc: Michael Neuling, Peter Zijlstra, linuxppc-dev, linux-kernel,
	Mike Galbraith, Anton Blanchard, Paul Turner, Ingo Molnar
In-Reply-To: <52679BD6.6090507@linux.vnet.ibm.com>

Hi Preeti

On 23 October 2013 11:50, Preeti U Murthy <preeti@linux.vnet.ibm.com> wrote:
> Hi Peter
>
> On 10/23/2013 03:41 AM, Peter Zijlstra wrote:
>> This nohz stuff really needs to be re-thought and made more scalable --
>> its a royal pain :/
>
> Why  not do something like the below instead? It does the following.
>
> This patch introduces sd_busy just like your suggested patch, except that
> it points to the parent of the highest level sched domain which has the
> SD_SHARE_PKG_RESOURCES set and initializes it in update_top_cache_domain().
> This is the sched domain that is relevant in nohz_kick_needed().
>
> sd_set_sd_state_busy(), sd_set_sd_state_idle() and nohz_kick_needed() query
> and update *only* this sched domain(sd_busy) for nr_busy_cpus. They are the
> only users of this parameter. While we are at it, we might as well change
> the nohz_idle parameter to be updated at the sd_busy domain level alone and
> not the base domain level of a CPU. This will unify the concept of busy cpus
> at just one level of sched domain.
>
> There is no need to iterate through all levels of sched domains of a cpu to
> update nr_busy_cpus since it is irrelevant at all other sched domains except
> at sd_busy level.
>
> De-couple asymmetric load balancing from the nr_busy parameter which the
> PATCH 2/3 anyway does. sd_busy therefore is irrelevant for asymmetric load
> balancing.
>
> Regards
> Preeti U Murthy
> --------------------START_PATCH-------------------------------
>
> sched: Fix nohz_kick_needed()
>
> ---
>  kernel/sched/core.c  |    4 ++++
>  kernel/sched/fair.c  |   40 ++++++++++++++++++++++------------------
>  kernel/sched/sched.h |    1 +
>  3 files changed, 27 insertions(+), 18 deletions(-)
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index c06b8d3..c1dd11c 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -5271,6 +5271,7 @@ DEFINE_PER_CPU(struct sched_domain *, sd_llc);
>  DEFINE_PER_CPU(int, sd_llc_size);
>  DEFINE_PER_CPU(int, sd_llc_id);
>  DEFINE_PER_CPU(struct sched_domain *, sd_numa);
> +DEFINE_PER_CPU(struct sched_domain *, sd_busy);
>
>  static void update_top_cache_domain(int cpu)
>  {
> @@ -5290,6 +5291,9 @@ static void update_top_cache_domain(int cpu)
>
>         sd = lowest_flag_domain(cpu, SD_NUMA);
>         rcu_assign_pointer(per_cpu(sd_numa, cpu), sd);
> +
> +       sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES)->parent;

highest_flag_domain can return null pointer

> +       rcu_assign_pointer(per_cpu(sd_busy, cpu), sd);
>  }
>
>  /*
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 813dd61..71e6f14 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -6515,16 +6515,16 @@ static inline void nohz_balance_exit_idle(int cpu)
>  static inline void set_cpu_sd_state_busy(void)
>  {
>         struct sched_domain *sd;
> +       int cpu = smp_processor_id();
>
>         rcu_read_lock();
> -       sd = rcu_dereference_check_sched_domain(this_rq()->sd);
> +       sd = per_cpu(sd_busy, cpu);

Don't you need to use rcu_dereference when using sd_busy ?

>
>         if (!sd || !sd->nohz_idle)
>                 goto unlock;
>         sd->nohz_idle = 0;
>
> -       for (; sd; sd = sd->parent)
> -               atomic_inc(&sd->groups->sgp->nr_busy_cpus);
> +       atomic_inc(&sd->groups->sgp->nr_busy_cpus);
>  unlock:
>         rcu_read_unlock();
>  }
> @@ -6532,16 +6532,16 @@ unlock:
>  void set_cpu_sd_state_idle(void)
>  {
>         struct sched_domain *sd;
> +       int cpu = smp_processor_id();
>
>         rcu_read_lock();
> -       sd = rcu_dereference_check_sched_domain(this_rq()->sd);
> +       sd = per_cpu(sd_busy, cpu);
>
>         if (!sd || sd->nohz_idle)
>                 goto unlock;
>         sd->nohz_idle = 1;
>
> -       for (; sd; sd = sd->parent)
> -               atomic_dec(&sd->groups->sgp->nr_busy_cpus);
> +       atomic_dec(&sd->groups->sgp->nr_busy_cpus);
>  unlock:
>         rcu_read_unlock();
>  }
> @@ -6748,6 +6748,9 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
>  {
>         unsigned long now = jiffies;
>         struct sched_domain *sd;
> +       struct sched_group *sg;
> +       struct sched_group_power *sgp;
> +       int nr_busy;
>
>         if (unlikely(idle_cpu(cpu)))
>                 return 0;
> @@ -6773,22 +6776,23 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
>                 goto need_kick;
>
>         rcu_read_lock();
> -       for_each_domain(cpu, sd) {
> -               struct sched_group *sg = sd->groups;
> -               struct sched_group_power *sgp = sg->sgp;
> -               int nr_busy = atomic_read(&sgp->nr_busy_cpus);
> +       sd = per_cpu(sd_busy, cpu);
>
> -               if (sd->flags & SD_SHARE_PKG_RESOURCES && nr_busy > 1)
> -                       goto need_kick_unlock;
> +       if (sd) {
> +               sg = sd->groups;

sg is not needed anymore

> +               sgp = sg->sgp;
> +               nr_busy = atomic_read(&sgp->nr_busy_cpus);
>
> -               if (sd->flags & SD_ASYM_PACKING && nr_busy != sg->group_weight
> -                   && (cpumask_first_and(nohz.idle_cpus_mask,
> -                                         sched_domain_span(sd)) < cpu))
> +               if (nr_busy > 1)
>                         goto need_kick_unlock;
> -
> -               if (!(sd->flags & (SD_SHARE_PKG_RESOURCES | SD_ASYM_PACKING)))
> -                       break;
>         }
> +
> +       sd = highest_flag_domain(cpu, SD_ASYM_PACKING);
> +
> +       if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
> +                                 sched_domain_span(sd)) < cpu))
> +               goto need_kick_unlock;
> +
>         rcu_read_unlock();
>         return 0;
>
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index ffc7087..0f1253f 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -623,6 +623,7 @@ DECLARE_PER_CPU(struct sched_domain *, sd_llc);
>  DECLARE_PER_CPU(int, sd_llc_size);
>  DECLARE_PER_CPU(int, sd_llc_id);
>  DECLARE_PER_CPU(struct sched_domain *, sd_numa);
> +DECLARE_PER_CPU(struct sched_domain *, sd_busy);
>
>  struct sched_group_power {
>         atomic_t ref;
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: powerpc: Don't corrupt user registers on 32-bit
From: Alexander Graf @ 2013-10-23 15:07 UTC (permalink / raw)
  To: Scott Wood; +Cc: Paul Mackerras, <linuxppc-dev@ozlabs.org>
In-Reply-To: <20131023102045.GA23685@SnaresPenguin>



Am 23.10.2013 um 11:20 schrieb Scott Wood <scottwood@freescale.com>:

> On Wed, Oct 23, 2013 at 09:40:02AM +0100, Paul Mackerras wrote:
>> Commit de79f7b9f6 ("powerpc: Put FP/VSX and VR state into structures")
>> modified load_up_fpu() and load_up_altivec() in such a way that they
>> now use r7 and r8.  Unfortunately, the callers of these functions on
>> 32-bit machines then return to userspace via fast_exception_return,
>> which doesn't restore all of the volatile GPRs, but only r1, r3 -- r6
>> and r9 -- r12.  This was causing userspace segfaults and other
>> userspace misbehaviour on 32-bit machines.
>> 
>> This fixes the problem by changing the register usage of load_up_fpu()
>> and load_up_altivec() to avoid using r7 and r8 and instead use r6 and
>> r10.  This also adds comments to those functions saying which registers
>> may be used.
>> 
>> Signed-off-by: Paul Mackerras <paulus@samba.org>
>> 
>> ---
>> arch/powerpc/kernel/fpu.S    | 14 ++++++++------
>> arch/powerpc/kernel/vector.S | 15 +++++++++------
>> 2 files changed, 17 insertions(+), 12 deletions(-)
> 
> Tested-by: Scott Wood <scottwood@freescale.com> (on e500mc, so no altivec)

Tested-by: Alexander Graf <agraf@suse.de> (on a G4 iBook and 970)

> 
> -Scott
> 

^ permalink raw reply

* Re: perf events ring buffer memory barrier on powerpc
From: Frederic Weisbecker @ 2013-10-23 14:25 UTC (permalink / raw)
  To: Michael Neuling, Peter Zijlstra
  Cc: Mathieu Desnoyers, LKML, Linux PPC dev, Anton Blanchard,
	Victor Kaplansky
In-Reply-To: <20131023141948.GB3566@localhost.localdomain>

2013/10/23 Frederic Weisbecker <fweisbec@gmail.com>:
> On Wed, Oct 23, 2013 at 10:54:54AM +1100, Michael Neuling wrote:
>> Frederic,
>>
>> In the perf ring buffer code we have this in perf_output_get_handle():
>>
>>       if (!local_dec_and_test(&rb->nest))
>>               goto out;
>>
>>       /*
>>        * Publish the known good head. Rely on the full barrier implied
>>        * by atomic_dec_and_test() order the rb->head read and this
>>        * write.
>>        */
>>       rb->user_page->data_head = head;
>>
>> The comment says atomic_dec_and_test() but the code is
>> local_dec_and_test().
>>
>> On powerpc, local_dec_and_test() doesn't have a memory barrier but
>> atomic_dec_and_test() does.  Is the comment wrong, or is
>> local_dec_and_test() suppose to imply a memory barrier too and we have
>> it wrongly implemented in powerpc?
>>
>> My guess is that local_dec_and_test() is correct but we to add an
>> explicit memory barrier like below:
>>
>> (Kudos to Victor Kaplansky for finding this)
>>
>> Mikey
>>
>> diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
>> index cd55144..95768c6 100644
>> --- a/kernel/events/ring_buffer.c
>> +++ b/kernel/events/ring_buffer.c
>> @@ -87,10 +87,10 @@ again:
>>               goto out;
>>
>>       /*
>> -      * Publish the known good head. Rely on the full barrier implied
>> -      * by atomic_dec_and_test() order the rb->head read and this
>> -      * write.
>> +      * Publish the known good head. We need a memory barrier to order the
>> +      * order the rb->head read and this write.
>>        */
>> +     smp_mb ();
>>       rb->user_page->data_head = head;
>>
>>       /*
>
>
> I'm adding Peter in Cc since he wrote that code.
> I agree that local_dec_and_test() doesn't need to imply an smp barrier.
> All it has to provide as a guarantee is the atomicity against local concurrent
> operations (interrupts, preemption, ...).
>
> Now I'm a bit confused about this barrier.
>
> I think we want this ordering:
>
>     Kernel                             User
>
>    READ rb->user_page->data_tail       READ rb->user_page->data_head
>    smp_mb()                            smp_mb()
>    WRITE rb data                       READ rb  data
>    smp_mb()                            smp_mb()
>    rb->user_page->data_head            WRITE rb->user_page->data_tail
      ^^ I meant a write above for data_head.

^ permalink raw reply

* Re: perf events ring buffer memory barrier on powerpc
From: Frederic Weisbecker @ 2013-10-23 14:19 UTC (permalink / raw)
  To: Michael Neuling, Peter Zijlstra
  Cc: Mathieu Desnoyers, linux-kernel, Linux PPC dev, anton,
	Victor Kaplansky
In-Reply-To: <12083.1382486094@ale.ozlabs.ibm.com>

On Wed, Oct 23, 2013 at 10:54:54AM +1100, Michael Neuling wrote:
> Frederic,
> 
> In the perf ring buffer code we have this in perf_output_get_handle():
> 
> 	if (!local_dec_and_test(&rb->nest))
> 		goto out;
> 
> 	/*
> 	 * Publish the known good head. Rely on the full barrier implied
> 	 * by atomic_dec_and_test() order the rb->head read and this
> 	 * write.
> 	 */
> 	rb->user_page->data_head = head;
> 
> The comment says atomic_dec_and_test() but the code is
> local_dec_and_test().
> 
> On powerpc, local_dec_and_test() doesn't have a memory barrier but
> atomic_dec_and_test() does.  Is the comment wrong, or is
> local_dec_and_test() suppose to imply a memory barrier too and we have
> it wrongly implemented in powerpc?
> 
> My guess is that local_dec_and_test() is correct but we to add an
> explicit memory barrier like below:
> 
> (Kudos to Victor Kaplansky for finding this)
> 
> Mikey
> 
> diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
> index cd55144..95768c6 100644
> --- a/kernel/events/ring_buffer.c
> +++ b/kernel/events/ring_buffer.c
> @@ -87,10 +87,10 @@ again:
>  		goto out;
>  
>  	/*
> -	 * Publish the known good head. Rely on the full barrier implied
> -	 * by atomic_dec_and_test() order the rb->head read and this
> -	 * write.
> +	 * Publish the known good head. We need a memory barrier to order the
> +	 * order the rb->head read and this write.
>  	 */
> +	smp_mb ();
>  	rb->user_page->data_head = head;
>  
>  	/*


I'm adding Peter in Cc since he wrote that code.
I agree that local_dec_and_test() doesn't need to imply an smp barrier.
All it has to provide as a guarantee is the atomicity against local concurrent
operations (interrupts, preemption, ...).

Now I'm a bit confused about this barrier.

I think we want this ordering:

    Kernel                             User

   READ rb->user_page->data_tail       READ rb->user_page->data_head
   smp_mb()                            smp_mb()
   WRITE rb data                       READ rb  data
   smp_mb()                            smp_mb()
   rb->user_page->data_head            WRITE rb->user_page->data_tail

So yeah we want a berrier between the data published and the user data_head.
But this ordering concerns wider layout than just rb->head and rb->user_page->data_head

And BTW I can see an smp_rmb() after we read rb->user_page->data_tail. This is probably the
first kernel barrier in my above example. (not sure if rmb() alone is enough though).

^ permalink raw reply

* Re: Missing _restvr_20 and _savevr_20 subroutines for lib/raid6/altivec8.o
From: Ben Hutchings @ 2013-10-23 10:54 UTC (permalink / raw)
  To: Kumar Gala
  Cc: debian-powerpc, linuxppc-dev@lists.ozlabs.org list,
	Anton Blanchard, Debian kernel maintainers
In-Reply-To: <9A520C29-492E-4FFF-9A0C-190182428FBE@kernel.crashing.org>

[-- Attachment #1: Type: text/plain, Size: 1468 bytes --]

On Wed, 2013-10-23 at 00:28 -0500, Kumar Gala wrote:
> On Oct 19, 2013, at 5:24 PM, Ben Hutchings wrote:
> 
> > When building lib/raid6/altivec8.o with gcc 4.8 on Debian, the compiler
> > is generating references to two new runtime subroutines which are
> > apparently not included in the kernel:
> > 
> > ERROR: "_restvr_20" [lib/raid6/raid6_pq.ko] undefined!
> > ERROR: "_savevr_20" [lib/raid6/raid6_pq.ko] undefined!
> > 
> > The save/restore subroutines are specified in
> > http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.7.1.html#SAVE-RESTORE
> > and we do have the _restgpr_* and _savegpr_* subroutines in
> > arch/powerpc/boot/crtsavres.S.  I'm not sure whether these subroutines
> > should be added or whether this indicates the compiler is doing
> > something wrong.
> > 
> > A configuration that triggers this is included below.
> > 
> > Ben.
> 
> Try with CONFIG_CC_OPTIMIZE_FOR_SIZE=n.  A feature was added to gcc
> for -Os to "outline" the save/restore routines.  I'm surprised this
> hasn't shown up sooner.

That does avoid the problem, thanks.

Ben.

> Well need to add _restvr_* / _savevr_* to the version in lib/crtsaveres.S.
> 
> http://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libgcc/config/rs6000/crtrestvr.S;hb=HEAD
> http://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libgcc/config/rs6000/crtsavevr.S;hb=HEAD
> 
> - k

-- 
Ben Hutchings
friends: People who know you well, but like you anyway.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* [PATCH 12/12][v3] pci: fsl: fix function check_pci_ctl_endpt_part
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

The new FSL PCI driver does not use cfg_addr of pci_controller,
we may directly access PCI CCSR using fsl_pci->regs.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
The new patch to fix function check_pci_ctl_endpt_part

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 arch/powerpc/sysdev/fsl_pci.h   | 5 -----
 drivers/iommu/fsl_pamu_domain.c | 6 ++++--
 include/linux/fsl/pci-common.h  | 1 +
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index ae4dbe2..3176eb2 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -16,11 +16,6 @@
 
 struct platform_device;
 
-
-/* FSL PCI controller BRR1 register */
-#define PCI_FSL_BRR1      0xbf8
-#define PCI_FSL_BRR1_VER 0xffff
-
 extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
 extern int mpc83xx_add_bridge(struct device_node *dev);
 u64 fsl_pci_immrbar_base(struct pci_controller *hose);
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c857c30..dd7bc25 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -36,6 +36,7 @@
 
 #include <asm/pci-bridge.h>
 #include <sysdev/fsl_pci.h>
+#include <linux/fsl/pci-common.h>
 
 #include "fsl_pamu_domain.h"
 #include "pci.h"
@@ -908,10 +909,11 @@ static struct iommu_group *get_device_iommu_group(struct device *dev)
 static  bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
 {
 	u32 version;
+	struct fsl_pci *pci = fsl_arch_sys_to_pci(pci_ctl);
 
 	/* Check the PCI controller version number by readding BRR1 register */
-	version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
-	version &= PCI_FSL_BRR1_VER;
+	version = in_be32(&pci->regs->block_rev1);
+	version &= PCIE_IP_REV_MASK;
 	/* If PCI controller version is >= 0x204 we can partition endpoints*/
 	if (version >= 0x204)
 		return 1;
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index 84b0801..6112adf 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -18,6 +18,7 @@
 #define PCIE_LTSSM_L0	0x16		/* L0 state */
 #define PCIE_IP_REV_2_2		0x02080202 /* PCIE IP block version Rev2.2 */
 #define PCIE_IP_REV_3_0		0x02080300 /* PCIE IP block version Rev3.0 */
+#define PCIE_IP_REV_MASK	0xffff
 #define PIWAR_EN		0x80000000	/* Enable */
 #define PIWAR_PF		0x20000000	/* prefetch */
 #define PIWAR_TGI_LOCAL		0x00f00000	/* target - local memory */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 11/12][v3] pci: fsl: update PCI EDAC driver
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

1. The pci-fsl-common driver has set fsl_pci to device as drvdata,
so EDAC driver can not call dev_set_drvdata() again. fsl_pci
contains regs field to point PCI CCSR, so EDAC may directly use
the pointer and not need to call devm_ioremap().
2. Add mpc85xx_pci_err_remove() to disable PCI error interrupt
and delete PCI EDAC from EDAC subsystem.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/
Added mpc85xx_pci_err_remove()

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 arch/powerpc/sysdev/fsl_pci.c |  1 +
 arch/powerpc/sysdev/fsl_pci.h |  6 ++++++
 drivers/edac/mpc85xx_edac.c   | 46 +++++++++++++++----------------------------
 drivers/edac/mpc85xx_edac.h   |  1 +
 4 files changed, 24 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 40d2e1d..4a03e1a 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -236,6 +236,7 @@ void fsl_arch_pci_sys_remove(struct fsl_pci *pci)
 	if (!hose)
 		return;
 
+	mpc85xx_pci_err_remove(to_platform_device(pci->dev));
 	pcibios_free_controller(hose);
 }
 
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index ce77aad..ae4dbe2 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -35,11 +35,17 @@ static inline void fsl_pci_assign_primary(void) {}
 
 #ifdef CONFIG_EDAC_MPC85XX
 int mpc85xx_pci_err_probe(struct platform_device *op);
+int mpc85xx_pci_err_remove(struct platform_device *op);
 #else
 static inline int mpc85xx_pci_err_probe(struct platform_device *op)
 {
 	return -ENOTSUPP;
 }
+static inline int mpc85xx_pci_err_remove(struct platform_device *op)
+{
+	return -ENOTSUPP;
+}
+
 #endif
 
 #ifdef CONFIG_FSL_PCI
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 3eb32f6..14a4116 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -21,6 +21,7 @@
 
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/fsl/pci-common.h>
 #include "edac_module.h"
 #include "edac_core.h"
 #include "mpc85xx_edac.h"
@@ -214,11 +215,13 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
 
 int mpc85xx_pci_err_probe(struct platform_device *op)
 {
+	struct fsl_pci *fslpci;
 	struct edac_pci_ctl_info *pci;
 	struct mpc85xx_pci_pdata *pdata;
-	struct resource r;
 	int res = 0;
 
+	fslpci = platform_get_drvdata(op);
+
 	if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
 		return -ENOMEM;
 
@@ -239,7 +242,6 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
 	pdata = pci->pvt_info;
 	pdata->name = "mpc85xx_pci_err";
 	pdata->irq = NO_IRQ;
-	dev_set_drvdata(&op->dev, pci);
 	pci->dev = &op->dev;
 	pci->mod_name = EDAC_MOD_STR;
 	pci->ctl_name = pdata->name;
@@ -250,30 +252,8 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
 
 	pdata->edac_idx = edac_pci_idx++;
 
-	res = of_address_to_resource(op->dev.of_node, 0, &r);
-	if (res) {
-		printk(KERN_ERR "%s: Unable to get resource for "
-		       "PCI err regs\n", __func__);
-		goto err;
-	}
-
 	/* we only need the error registers */
-	r.start += 0xe00;
-
-	if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
-					pdata->name)) {
-		printk(KERN_ERR "%s: Error while requesting mem region\n",
-		       __func__);
-		res = -EBUSY;
-		goto err;
-	}
-
-	pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
-	if (!pdata->pci_vbase) {
-		printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
-		res = -ENOMEM;
-		goto err;
-	}
+	pdata->pci_vbase = (void *)fslpci->regs + MPC85XX_PCI_ERR_OFFSET;
 
 	orig_pci_err_cap_dr =
 	    in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
@@ -327,20 +307,25 @@ err:
 }
 EXPORT_SYMBOL(mpc85xx_pci_err_probe);
 
-static int mpc85xx_pci_err_remove(struct platform_device *op)
+int mpc85xx_pci_err_remove(struct platform_device *op)
 {
-	struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
-	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
+	struct edac_pci_ctl_info *pci;
+	struct mpc85xx_pci_pdata *pdata;
 
 	edac_dbg(0, "\n");
 
+	pci = edac_pci_del_device(&op->dev);
+
+	if (!pci)
+		return -EINVAL;
+
+	pdata = pci->pvt_info;
+
 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
 		 orig_pci_err_cap_dr);
 
 	out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);
 
-	edac_pci_del_device(pci->dev);
-
 	if (edac_op_state == EDAC_OPSTATE_INT)
 		irq_dispose_mapping(pdata->irq);
 
@@ -348,6 +333,7 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
 
 	return 0;
 }
+EXPORT_SYMBOL(mpc85xx_pci_err_remove);
 
 #endif				/* CONFIG_PCI */
 
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 932016f..3ba235a 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -131,6 +131,7 @@
 #define PCI_EDE_PERR_MASK	(PCI_EDE_TGT_PERR | PCI_EDE_MST_PERR | \
 				PCI_EDE_ADDR_PERR)
 
+#define MPC85XX_PCI_ERR_OFFSET		0x0e00
 #define MPC85XX_PCI_ERR_DR		0x0000
 #define MPC85XX_PCI_ERR_CAP_DR		0x0004
 #define MPC85XX_PCI_ERR_EN		0x0008
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 06/12][v3] pci: fsl: port PCI controller setup code
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

PCI controller setup code will initialize structure fsl_pci
according to PCI dts node and initialize PCI command register
and ATMU. The patch uses general API of_pci_parse_bus_range
to parse PCI bus range, uses general of_address's API to parse
PCI IO/MEM ranges.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 drivers/pci/host/pci-fsl-common.c | 179 +++++++++++++++++++++-----------------
 1 file changed, 97 insertions(+), 82 deletions(-)

diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index f15b605..e09a0ec 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -24,6 +24,8 @@
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
 
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -505,131 +507,144 @@ static void setup_pci_atmu(struct fsl_pci *pci)
 	}
 }
 
-static void __init setup_pci_cmd(struct pci_controller *hose)
+static void __init setup_pci_cmd(struct fsl_pci *pci)
 {
 	u16 cmd;
 	int cap_x;
 
-	early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
+	early_fsl_read_config_word(pci, 0, 0, PCI_COMMAND, &cmd);
 	cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
 		| PCI_COMMAND_IO;
-	early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
+	early_fsl_write_config_word(pci, 0, 0, PCI_COMMAND, cmd);
 
-	cap_x = early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX);
+	cap_x = early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_PCIX);
 	if (cap_x) {
 		int pci_x_cmd = cap_x + PCI_X_CMD;
 		cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
 			| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
-		early_write_config_word(hose, 0, 0, pci_x_cmd, cmd);
-	} else {
-		early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
-	}
+		early_fsl_write_config_word(pci, 0, 0, pci_x_cmd, cmd);
+	} else
+		early_fsl_write_config_byte(pci, 0, 0, PCI_LATENCY_TIMER,
+					    0x80);
 }
 
-int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
+static int __init
+fsl_pci_setup(struct platform_device *pdev, struct fsl_pci *pci)
 {
-	int len;
-	struct pci_controller *hose;
-	struct resource rsrc;
-	const int *bus_range;
+	struct resource *rsrc;
 	u8 hdr_type, progif;
-	struct device_node *dev;
-	struct ccsr_pci __iomem *pci;
-
-	dev = pdev->dev.of_node;
+	struct device_node *dn;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	int mem = 0;
 
-	if (!of_device_is_available(dev)) {
-		pr_warning("%s: disabled\n", dev->full_name);
-		return -ENODEV;
-	}
+	dn = pdev->dev.of_node;
+	pci->dn = dn;
+	pci->dev = &pdev->dev;
 
-	pr_debug("Adding PCI host bridge %s\n", dev->full_name);
+	dev_info(&pdev->dev, "Find controller %s\n", dn->full_name);
 
 	/* Fetch host bridge registers address */
-	if (of_address_to_resource(dev, 0, &rsrc)) {
-		printk(KERN_WARNING "Can't get pci register base!");
-		return -ENOMEM;
+	rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!rsrc) {
+		dev_err(&pdev->dev, "Can't get pci register base!");
+		return -EINVAL;
 	}
+	dev_info(&pdev->dev, "REG 0x%016llx..0x%016llx\n",
+		 (u64)rsrc->start, (u64)rsrc->end);
 
-	/* Get bus range if any */
-	bus_range = of_get_property(dev, "bus-range", &len);
-	if (bus_range == NULL || len < 2 * sizeof(int))
-		printk(KERN_WARNING "Can't get bus-range for %s, assume"
-			" bus 0\n", dev->full_name);
-
-	pci_add_flags(PCI_REASSIGN_ALL_BUS);
-	hose = pcibios_alloc_controller(dev);
-	if (!hose)
-		return -ENOMEM;
+	/* Parse pci range resources from device tree */
+	if (of_pci_range_parser_init(&parser, dn)) {
+		dev_err(&pdev->dev, "missing ranges property\n");
+		return -EINVAL;
+	}
 
-	/* set platform device as the parent */
-	hose->parent = &pdev->dev;
-	hose->first_busno = bus_range ? bus_range[0] : 0x0;
-	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+	/* Get the I/O and memory ranges from device tree */
+	for_each_of_pci_range(&parser, &range) {
+		unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
+		if (restype == IORESOURCE_IO) {
+			of_pci_range_to_resource(&range, dn,
+						 &pci->io_resource);
+			pci->io_resource.name = "I/O";
+			pci->io_resource.start = range.pci_addr;
+			pci->io_resource.end = range.pci_addr + range.size - 1;
+			pci->pci_io_size = range.size;
+			pci->io_base_phys = range.cpu_addr - range.pci_addr;
+			dev_info(&pdev->dev,
+				 " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+				 range.cpu_addr,
+				 range.cpu_addr + range.size - 1,
+				 range.pci_addr);
+		}
+		if (restype == IORESOURCE_MEM) {
+			if (mem >= 3)
+				continue;
+			of_pci_range_to_resource(&range, dn,
+						 &pci->mem_resources[mem]);
+			pci->mem_resources[mem].name = "MEM";
+			pci->mem_offset[mem] = range.cpu_addr - range.pci_addr;
+			dev_info(&pdev->dev,
+				 "MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
+				 (u64)pci->mem_resources[mem].start,
+				 (u64)pci->mem_resources[mem].end,
+				 range.pci_addr);
+		}
+	}
 
-	pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
-		 (u64)rsrc.start, (u64)resource_size(&rsrc));
+	/* Get bus range */
+	if (of_pci_parse_bus_range(dn, &pci->busn)) {
+		dev_err(&pdev->dev, "failed to parse bus-range property\n");
+		pci->first_busno = 0x0;
+		pci->last_busno = 0xff;
+	} else {
+		pci->first_busno = pci->busn.start;
+		pci->last_busno = pci->busn.end;
+	}
+	dev_info(&pdev->dev, "Firmware bus number %d->%d\n",
+		 pci->first_busno, pci->last_busno);
 
-	pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc));
-	if (!hose->private_data)
-		goto no_bridge;
+	pci->regs = devm_ioremap_resource(&pdev->dev, rsrc);
+	if (IS_ERR(pci->regs))
+		return PTR_ERR(pci->regs);
 
-	setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4,
-			   PPC_INDIRECT_TYPE_BIG_ENDIAN);
+	pci->ops = &fsl_indirect_pci_ops;
+	pci->indirect_type = INDIRECT_TYPE_BIG_ENDIAN;
 
-	if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0)
-		hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
+	if (in_be32(&pci->regs->block_rev1) < PCIE_IP_REV_3_0)
+		pci->indirect_type |= INDIRECT_TYPE_FSL_CFG_REG_LINK;
 
-	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
-		/* use fsl_indirect_read_config for PCIe */
-		hose->ops = &fsl_indirect_pcie_ops;
-		/* For PCIE read HEADER_TYPE to identify controler mode */
-		early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
-		if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+	pci->is_pcie = !!early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_EXP);
+	if (pci->is_pcie) {
+		/* For PCIE read HEADER_TYPE to identify controller mode */
+		early_fsl_read_config_byte(pci, 0, 0, PCI_HEADER_TYPE,
+					   &hdr_type);
+		if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL)
 			goto no_bridge;
-
 	} else {
 		/* For PCI read PROG to identify controller mode */
-		early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
+		early_fsl_read_config_byte(pci, 0, 0, PCI_CLASS_PROG, &progif);
 		if ((progif & 1) == 1)
 			goto no_bridge;
 	}
 
-	setup_pci_cmd(hose);
+	setup_pci_cmd(pci);
 
 	/* check PCI express link status */
-	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
-		hose->indirect_type |= PPC_INDIRECT_TYPE_EXT_REG |
-			PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
-		if (fsl_pcie_check_link(hose))
-			hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+	if (pci->is_pcie) {
+		pci->indirect_type |= INDIRECT_TYPE_EXT_REG |
+				       INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
+		if (!fsl_pci_check_link(pci))
+			pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
 	}
 
-	printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
-		"Firmware bus number: %d->%d\n",
-		(unsigned long long)rsrc.start, hose->first_busno,
-		hose->last_busno);
-
-	pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
-		hose, hose->cfg_addr, hose->cfg_data);
-
-	/* Interpret the "ranges" property */
-	/* This also maps the I/O region and sets isa_io/mem_base */
-	pci_process_bridge_OF_ranges(hose, dev, is_primary);
-
 	/* Setup PEX window registers */
-	setup_pci_atmu(hose);
+	setup_pci_atmu(pci);
+
+	platform_set_drvdata(pdev, pci);
 
 	return 0;
 
 no_bridge:
-	iounmap(hose->private_data);
-	/* unmap cfg_data & cfg_addr separately if not on same page */
-	if (((unsigned long)hose->cfg_data & PAGE_MASK) !=
-	    ((unsigned long)hose->cfg_addr & PAGE_MASK))
-		iounmap(hose->cfg_data);
-	iounmap(hose->cfg_addr);
-	pcibios_free_controller(hose);
 	return -ENODEV;
 }
 
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 10/12][v3] pci: fsl: support function fsl_pci_assign_primary
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

Change pci_ids to fsl_pci_ids Freescale-specific name and change
static to extern modifier for using in fsl_pci_assign_primary().

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 arch/powerpc/sysdev/fsl_pci.c     | 5 +++--
 drivers/pci/host/pci-fsl-common.c | 4 ++--
 include/linux/fsl/pci-common.h    | 2 ++
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 0a0c240..40d2e1d 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -735,7 +735,8 @@ void fsl_pci_assign_primary(void)
 		of_node_put(np);
 		np = fsl_pci_primary;
 
-		if (of_match_node(pci_ids, np) && of_device_is_available(np))
+		if (of_match_node(fsl_pci_ids, np) &&
+		    of_device_is_available(np))
 			return;
 	}
 
@@ -744,7 +745,7 @@ void fsl_pci_assign_primary(void)
 	 * designate one as primary.  This can go away once
 	 * various bugs with primary-less systems are fixed.
 	 */
-	for_each_matching_node(np, pci_ids) {
+	for_each_matching_node(np, fsl_pci_ids) {
 		if (of_device_is_available(np)) {
 			fsl_pci_primary = np;
 			of_node_put(np);
diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index 729a5f4..8b4f793 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -634,7 +634,7 @@ no_bridge:
 	return -ENODEV;
 }
 
-static const struct of_device_id pci_ids[] = {
+const struct of_device_id fsl_pci_ids[] = {
 	{ .compatible = "fsl,mpc8540-pci", },
 	{ .compatible = "fsl,mpc8548-pcie", },
 	{ .compatible = "fsl,mpc8610-pci", },
@@ -725,7 +725,7 @@ static struct platform_driver fsl_pci_driver = {
 	.driver = {
 		.name = "fsl-pci",
 		.pm = PCI_PM_OPS,
-		.of_match_table = pci_ids,
+		.of_match_table = fsl_pci_ids,
 	},
 	.probe = fsl_pci_probe,
 	.remove = fsl_pci_remove,
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index bfb1f03..84b0801 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -136,6 +136,8 @@ struct fsl_pci {
 	void *sys;
 };
 
+extern const struct of_device_id fsl_pci_ids[];
+
 /*
  * Convert architecture specific pci controller structure to fsl_pci
  * PowerPC uses structure pci_controller and ARM uses structure pci_sys_data
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 08/12][v3] pci: fsl: add PowerPC PCI driver
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

1. Implement fsl_arch_pci64_dma_offset() to return PowerPC PCI64
DMA offset
2. Implement fsl_arch_sys_to_pci() to convert pci_controller
to fsl_pci
3. Implement fsl_arch_fake_pci_bus() to fake pci_controller
and PCI bus.
4. Implement fsl_arch_pci_exclude_device() to call
ppc_md.pci_exclude_device()
5. Implement fsl_arch_pci_sys_register() to initialize pci_controller
according to fsl_pci, add register PCI controller to PowerPC PCI
subsystem.
6. Implement fsl_arch_pci_sys_remove() to remove PCI controller from
PowerPC PCI subsystem.
7. Add mpc83xx_pcie_check_link() because pci-fsl-common dose not
support mpc83xx.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 arch/powerpc/sysdev/fsl_pci.c | 142 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 135 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 26039e3..0a0c240 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -62,7 +62,11 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev)
 #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
 
 #define MAX_PHYS_ADDR_BITS	40
-static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
+
+u64 fsl_arch_pci64_dma_offset(void)
+{
+	return 1ull << MAX_PHYS_ADDR_BITS;
+}
 
 static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
 {
@@ -77,17 +81,44 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
 	if ((dev->bus == &pci_bus_type) &&
 	    dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
 		set_dma_ops(dev, &dma_direct_ops);
-		set_dma_offset(dev, pci64_dma_offset);
+		set_dma_offset(dev, fsl_arch_pci64_dma_offset());
 	}
 
 	*dev->dma_mask = dma_mask;
 	return 0;
 }
 
+struct fsl_pci *fsl_arch_sys_to_pci(void *sys)
+{
+	struct pci_controller *hose = sys;
+	struct fsl_pci *pci = hose->private_data;
+
+	/* Update the first bus number */
+	if (pci->first_busno != hose->first_busno)
+		pci->first_busno = hose->first_busno;
+
+	return pci;
+}
+
+struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr)
+{
+	static struct pci_bus bus;
+	static struct pci_controller hose;
+
+	bus.number = busnr;
+	bus.sysdata = &hose;
+	hose.private_data = pci;
+	bus.ops = pci->ops;
+
+	return &bus;
+}
+
 void fsl_pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_controller *hose = pci_bus_to_host(bus);
-	int i, is_pcie = 0, no_link;
+	bool is_pcie, no_link;
+	int i;
+	struct fsl_pci *pci = fsl_arch_sys_to_pci(hose);
 
 	/* The root complex bridge comes up with bogus resources,
 	 * we copy the PHB ones in.
@@ -97,9 +128,8 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
 	 * tricky.
 	 */
 
-	if (fsl_pcie_bus_fixup)
-		is_pcie = early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
-	no_link = !!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK);
+	is_pcie = pci->is_pcie;
+	no_link = !fsl_pci_check_link(pci);
 
 	if (bus->parent == hose->bus && (is_pcie || no_link)) {
 		for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; ++i) {
@@ -121,6 +151,94 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
 	}
 }
 
+int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
+{
+	struct pci_controller *hose = pci->sys;
+
+	if (!hose)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(hose, bus, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int fsl_arch_pci_sys_register(struct fsl_pci *pci)
+{
+	struct pci_controller *hose;
+
+	pci_add_flags(PCI_REASSIGN_ALL_BUS);
+	hose = pcibios_alloc_controller(pci->dn);
+	if (!hose)
+		return -ENOMEM;
+
+	/* set platform device as the parent */
+	hose->private_data = pci;
+	hose->parent = pci->dev;
+	hose->first_busno = pci->first_busno;
+	hose->last_busno = pci->last_busno;
+	hose->ops = pci->ops;
+
+#ifdef CONFIG_PPC32
+	/* On 32 bits, limit I/O space to 16MB */
+	if (pci->pci_io_size > 0x01000000)
+		pci->pci_io_size = 0x01000000;
+
+	/* 32 bits needs to map IOs here */
+	hose->io_base_virt = ioremap(pci->io_base_phys + pci->io_resource.start,
+				     pci->pci_io_size);
+
+	/* Expect trouble if pci_addr is not 0 */
+	if (fsl_pci_primary == pci->dn)
+		isa_io_base = (unsigned long)hose->io_base_virt;
+#endif /* CONFIG_PPC32 */
+
+	hose->pci_io_size = pci->io_resource.start + pci->pci_io_size;
+	hose->io_base_phys = pci->io_base_phys;
+	hose->io_resource = pci->io_resource;
+
+	memcpy(hose->mem_offset, pci->mem_offset, sizeof(hose->mem_offset));
+	memcpy(hose->mem_resources, pci->mem_resources,
+		sizeof(hose->mem_resources));
+	hose->dma_window_base_cur = pci->dma_window_base_cur;
+	hose->dma_window_size = pci->dma_window_size;
+
+	pci->sys = hose;
+
+	/*
+	 * Install our own dma_set_mask handler to fixup dma_ops
+	 * and dma_offset when memory is more than dma window size
+	 */
+	if (pci->is_pcie && memblock_end_of_DRAM() > hose->dma_window_size)
+		ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
+
+#ifdef CONFIG_SWIOTLB
+	/*
+	 * if we couldn't map all of DRAM via the dma windows
+	 * we need SWIOTLB to handle buffers located outside of
+	 * dma capable memory region
+	 */
+	if (memblock_end_of_DRAM() - 1 > hose->dma_window_base_cur +
+			hose->dma_window_size)
+		ppc_swiotlb_enable = 1;
+#endif
+
+	mpc85xx_pci_err_probe(to_platform_device(pci->dev));
+	return 0;
+}
+
+void fsl_arch_pci_sys_remove(struct fsl_pci *pci)
+{
+	struct pci_controller *hose = pci->sys;
+
+	if (!hose)
+		return;
+
+	pcibios_free_controller(hose);
+}
+
 #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header);
@@ -260,6 +378,16 @@ static struct pci_ops mpc83xx_pcie_ops = {
 	.write = mpc83xx_pcie_write_config,
 };
 
+static int mpc83xx_pcie_check_link(struct pci_controller *hose)
+{
+	u32 val = 0;
+
+	early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
+	if (val < PCIE_LTSSM_L0)
+		return 1;
+	return 0;
+}
+
 static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
 				     struct resource *reg)
 {
@@ -294,7 +422,7 @@ static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
 	out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
 	out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
 
-	if (fsl_pcie_check_link(hose))
+	if (mpc83xx_pcie_check_link(hose))
 		hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
 
 	return 0;
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 09/12][v3] pci: fsl: update PCI PM driver
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

The patch updates PCI PM driver, uses fsl_pci instead of
pci_controller.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 drivers/pci/host/pci-fsl-common.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index c7bc472..729a5f4 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -699,19 +699,12 @@ static int fsl_pci_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int fsl_pci_resume(struct device *dev)
 {
-	struct pci_controller *hose;
-	struct resource pci_rsrc;
+	struct fsl_pci *pci = dev_get_drvdata(dev);
 
-	hose = pci_find_hose_for_OF_device(dev->of_node);
-	if (!hose)
+	if (!pci)
 		return -ENODEV;
 
-	if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
-		dev_err(dev, "Get pci register base failed.");
-		return -ENODEV;
-	}
-
-	setup_pci_atmu(hose);
+	setup_pci_atmu(pci);
 
 	return 0;
 }
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 07/12][v3] pci: fsl: port PCI platform driver
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

1. The patch ports FSL PCI platform driver. probe function
initialize fsl_pci and register it to architecture PCI system,
remove function removes fsl_pci from architecture PCI system.
fsl_arch_pci_sys_register() and fsl_arch_pci_sys_remove() should
be implemented in architecture-specific driver to provide
register/remove functionality.
2. Remove architecture-specific header and unnecessary header.
3. Change Kconfig and Makefile to support FSL PCI common driver

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 arch/powerpc/Kconfig              |  1 +
 drivers/pci/host/Kconfig          | 10 ++++++++
 drivers/pci/host/Makefile         |  1 +
 drivers/pci/host/pci-fsl-common.c | 53 +++++++++++++++++++++++++--------------
 include/linux/fsl/pci-common.h    |  6 +++++
 5 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 38f3b7e..7447d97d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -690,6 +690,7 @@ config FSL_SOC
 
 config FSL_PCI
  	bool
+	select PCI_FSL_COMMON if FSL_SOC_BOOKE || PPC_86xx
 	select PPC_INDIRECT_PCI
 	select PCI_QUIRKS
 
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 3d95048..48242b33 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -19,4 +19,14 @@ config PCI_TEGRA
 	bool "NVIDIA Tegra PCIe controller"
 	depends on ARCH_TEGRA
 
+config PCI_FSL_COMMON
+	bool "Common driver for Freescale PCI/PCIe controller"
+	depends on FSL_SOC_BOOKE || PPC_86xx
+	help
+	  This driver provides common support for PCI/PCIE controller
+	  on Freescale embedded processors 85xx/86xx/QorIQ/Layerscape.
+	  Additional drivers must be enabled in order to provide some
+	  architecture-dependent functions and register the controller
+	  to PCI subsystem.
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index c9a997b..7c338a7 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
+obj-$(CONFIG_PCI_FSL_COMMON) += pci-fsl-common.o
diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index e09a0ec..c7bc472 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -16,26 +16,12 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/log2.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc-pci.h>
-#include <asm/machdep.h>
-#include <asm/disassemble.h>
-#include <asm/ppc-opcode.h>
-#include <sysdev/fsl_soc.h>
-#include <sysdev/fsl_pci.h>
+#include <linux/fsl/pci-common.h>
 
 /* Indirect type */
 #define INDIRECT_TYPE_EXT_REG			0x00000002
@@ -672,12 +658,40 @@ static const struct of_device_id pci_ids[] = {
 static int fsl_pci_probe(struct platform_device *pdev)
 {
 	int ret;
-	struct device_node *node;
+	struct fsl_pci *pci;
+
+	if (!of_device_is_available(pdev->dev.of_node)) {
+		dev_dbg(&pdev->dev, "disabled\n");
+		return -ENODEV;
+	}
+
+	pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
+	if (!pci) {
+		dev_err(&pdev->dev, "no memory for fsl_pci\n");
+		return -ENOMEM;
+	}
+
+	ret = fsl_pci_setup(pdev, pci);
+	if (ret)
+		return ret;
+
+	ret = fsl_arch_pci_sys_register(pci);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register pcie to Arch\n");
+		return ret;
+	}
+
+	return 0;
+}
 
-	node = pdev->dev.of_node;
-	ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+static int fsl_pci_remove(struct platform_device *pdev)
+{
+	struct fsl_pci *pci = platform_get_drvdata(pdev);
+
+	if (!pci)
+		return -ENODEV;
 
-	mpc85xx_pci_err_probe(pdev);
+	fsl_arch_pci_sys_remove(pci);
 
 	return 0;
 }
@@ -721,6 +735,7 @@ static struct platform_driver fsl_pci_driver = {
 		.of_match_table = pci_ids,
 	},
 	.probe = fsl_pci_probe,
+	.remove = fsl_pci_remove,
 };
 
 static int __init fsl_pci_init(void)
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index 490ee53..bfb1f03 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -159,5 +159,11 @@ extern struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr);
 /* Return PCI64 DMA offset */
 u64 fsl_arch_pci64_dma_offset(void);
 
+/* Register PCI/PCIe controller to architecture system */
+extern int fsl_arch_pci_sys_register(struct fsl_pci *pci);
+
+/* Remove PCI/PCIe controller from architecture system */
+extern void fsl_arch_pci_sys_remove(struct fsl_pci *pci);
+
 #endif /* __PCI_COMMON_H */
 #endif /* __KERNEL__ */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 05/12][v3] pci: fsl: port PCI ATMU related code
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

The patch ports PCI ATMU related code, just uses general IO API
iowrite32be/ioread32be instead of out_be32/in_be32, uses structure
fsl_pci instead of PowerPC's pci_controller and uses dev_*()
instead of pr_*() to output the information.
The patch also provides the weak function
fsl_arch_pci64_dma_offset(), the architecture-specific driver may
return different offset.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 drivers/pci/host/pci-fsl-common.c | 191 ++++++++++++++++++++------------------
 include/linux/fsl/pci-common.h    |   3 +
 2 files changed, 104 insertions(+), 90 deletions(-)

diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index 505a6a1..f15b605 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -42,6 +42,11 @@
 #define INDIRECT_TYPE_BIG_ENDIAN		0x00000010
 #define INDIRECT_TYPE_FSL_CFG_REG_LINK		0x00000040
 
+u64 __weak fsl_arch_pci64_dma_offset(void)
+{
+	return 0;
+}
+
 int __weak fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
 {
 	return PCIBIOS_SUCCESSFUL;
@@ -231,8 +236,8 @@ static int early_fsl_find_capability(struct fsl_pci *pci,
 }
 
 static int setup_one_atmu(struct ccsr_pci __iomem *pci,
-	unsigned int index, const struct resource *res,
-	resource_size_t offset)
+			  unsigned int index, const struct resource *res,
+			  resource_size_t offset)
 {
 	resource_size_t pci_addr = res->start - offset;
 	resource_size_t phys_addr = res->start;
@@ -253,10 +258,10 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
 		if (index + i >= 5)
 			return -1;
 
-		out_be32(&pci->pow[index + i].potar, pci_addr >> 12);
-		out_be32(&pci->pow[index + i].potear, (u64)pci_addr >> 44);
-		out_be32(&pci->pow[index + i].powbar, phys_addr >> 12);
-		out_be32(&pci->pow[index + i].powar, flags | (bits - 1));
+		iowrite32be(pci_addr >> 12, &pci->pow[index + i].potar);
+		iowrite32be((u64)pci_addr >> 44, &pci->pow[index + i].potear);
+		iowrite32be(phys_addr >> 12, &pci->pow[index + i].powbar);
+		iowrite32be(flags | (bits - 1), &pci->pow[index + i].powar);
 
 		pci_addr += (resource_size_t)1U << bits;
 		phys_addr += (resource_size_t)1U << bits;
@@ -267,21 +272,19 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
 }
 
 /* atmu setup for fsl pci/pcie controller */
-static void setup_pci_atmu(struct pci_controller *hose)
+static void setup_pci_atmu(struct fsl_pci *pci)
 {
-	struct ccsr_pci __iomem *pci = hose->private_data;
 	int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
 	u64 mem, sz, paddr_hi = 0;
 	u64 offset = 0, paddr_lo = ULLONG_MAX;
 	u32 pcicsrbar = 0, pcicsrbar_sz;
 	u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
 			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
-	const char *name = hose->dn->full_name;
 	const u64 *reg;
 	int len;
 
-	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
-		if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
+	if (pci->is_pcie) {
+		if (in_be32(&pci->regs->block_rev1) >= PCIE_IP_REV_2_2) {
 			win_idx = 2;
 			start_idx = 0;
 			end_idx = 3;
@@ -289,47 +292,54 @@ static void setup_pci_atmu(struct pci_controller *hose)
 	}
 
 	/* Disable all windows (except powar0 since it's ignored) */
-	for(i = 1; i < 5; i++)
-		out_be32(&pci->pow[i].powar, 0);
+	for (i = 1; i < 5; i++)
+		iowrite32be(0, &pci->regs->pow[i].powar);
 	for (i = start_idx; i < end_idx; i++)
-		out_be32(&pci->piw[i].piwar, 0);
+		iowrite32be(0, &pci->regs->piw[i].piwar);
 
 	/* Setup outbound MEM window */
-	for(i = 0, j = 1; i < 3; i++) {
-		if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
+	for (i = 0, j = 1; i < 3; i++) {
+		if (!(pci->mem_resources[i].flags & IORESOURCE_MEM))
 			continue;
 
-		paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
-		paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
+		paddr_lo = min_t(u64, paddr_lo, pci->mem_resources[i].start);
+		paddr_hi = max_t(u64, paddr_hi, pci->mem_resources[i].end);
 
 		/* We assume all memory resources have the same offset */
-		offset = hose->mem_offset[i];
-		n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
+		offset = pci->mem_offset[i];
+		n = setup_one_atmu(pci->regs, j, &pci->mem_resources[i],
+				   offset);
 
 		if (n < 0 || j >= 5) {
-			pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
-			hose->mem_resources[i].flags |= IORESOURCE_DISABLED;
+			dev_err(pci->dev,
+				"Ran out of outbound PCI ATMUs for resource %d!\n",
+				i);
+			pci->mem_resources[i].flags |= IORESOURCE_DISABLED;
 		} else
 			j += n;
 	}
 
 	/* Setup outbound IO window */
-	if (hose->io_resource.flags & IORESOURCE_IO) {
-		if (j >= 5) {
-			pr_err("Ran out of outbound PCI ATMUs for IO resource\n");
-		} else {
-			pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
-				 "phy base 0x%016llx.\n",
-				 (u64)hose->io_resource.start,
-				 (u64)resource_size(&hose->io_resource),
-				 (u64)hose->io_base_phys);
-			out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12));
-			out_be32(&pci->pow[j].potear, 0);
-			out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12));
+	if (pci->io_resource.flags & IORESOURCE_IO) {
+		if (j >= 5)
+			dev_err(pci->dev,
+				"Ran out of outbound PCI ATMUs for IO resource\n");
+		else {
+			dev_dbg(pci->dev,
+				 "PCI IO resource start 0x%016llx,"
+				 "size 0x%016llx, phy base 0x%016llx.\n",
+				 (u64)pci->io_resource.start,
+				 (u64)resource_size(&pci->io_resource),
+				 (u64)pci->io_base_phys);
+			iowrite32be(pci->io_resource.start >> 12,
+				    &pci->regs->pow[j].potar);
+			iowrite32be(0, &pci->regs->pow[j].potear);
+			iowrite32be(pci->io_base_phys >> 12,
+				    &pci->regs->pow[j].powbar);
 			/* Enable, IO R/W */
-			out_be32(&pci->pow[j].powar, 0x80088000
-				| (ilog2(hose->io_resource.end
-				- hose->io_resource.start + 1) - 1));
+			iowrite32be(0x80088000 |
+				  (ilog2(resource_size(&pci->io_resource)) - 1),
+				  &pci->regs->pow[j].powar);
 		}
 	}
 
@@ -338,18 +348,20 @@ static void setup_pci_atmu(struct pci_controller *hose)
 	paddr_lo -= offset;
 
 	if (paddr_hi == paddr_lo) {
-		pr_err("%s: No outbound window space\n", name);
+		dev_err(pci->dev, "No outbound window space\n");
 		return;
 	}
 
 	if (paddr_lo == 0) {
-		pr_err("%s: No space for inbound window\n", name);
+		dev_err(pci->dev, "No space for inbound window\n");
 		return;
 	}
 
 	/* setup PCSRBAR/PEXCSRBAR */
-	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
-	early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+	early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+				     0xffffffff);
+	early_fsl_read_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+				    &pcicsrbar_sz);
 	pcicsrbar_sz = ~pcicsrbar_sz + 1;
 
 	if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
@@ -357,11 +369,12 @@ static void setup_pci_atmu(struct pci_controller *hose)
 		pcicsrbar = 0x100000000ull - pcicsrbar_sz;
 	else
 		pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
-	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
+	early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
+				     pcicsrbar);
 
-	paddr_lo = min(paddr_lo, (u64)pcicsrbar);
+	paddr_lo = min_t(u64, paddr_lo, pcicsrbar);
 
-	pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
+	dev_info(pci->dev, "PCICSRBAR @ 0x%x\n", pcicsrbar);
 
 	/* Setup inbound mem window */
 	mem = memblock_end_of_DRAM();
@@ -378,17 +391,19 @@ static void setup_pci_atmu(struct pci_controller *hose)
 	 * can avoid allocating a new ATMU by extending the DDR ATMU by one
 	 * page.
 	 */
-	reg = of_get_property(hose->dn, "msi-address-64", &len);
+	reg = of_get_property(pci->dn, "msi-address-64", &len);
 	if (reg && (len == sizeof(u64))) {
 		u64 address = be64_to_cpup(reg);
 
 		if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
-			pr_info("%s: extending DDR ATMU to cover MSIIR", name);
+			dev_info(pci->dev,
+				 "extending DDR ATMU to cover MSIIR\n");
 			mem += PAGE_SIZE;
 		} else {
 			/* TODO: Create a new ATMU for MSIIR */
-			pr_warn("%s: msi-address-64 address of %llx is "
-				"unsupported\n", name, address);
+			dev_warn(pci->dev,
+				 "msi-address-64 address of %llx is "
+				 "unsupported\n", address);
 		}
 	}
 
@@ -396,25 +411,26 @@ static void setup_pci_atmu(struct pci_controller *hose)
 	mem_log = ilog2(sz);
 
 	/* PCIe can overmap inbound & outbound since RX & TX are separated */
-	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
+	if (pci->is_pcie) {
 		/* Size window to exact size if power-of-two or one size up */
 		if ((1ull << mem_log) != mem) {
 			mem_log++;
 			if ((1ull << mem_log) > mem)
-				pr_info("%s: Setting PCI inbound window "
-					"greater than memory size\n", name);
+				dev_info(pci->dev,
+					 "Setting PCI inbound window "
+					 "greater than memory size\n");
 		}
 
 		piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
 
 		/* Setup inbound memory window */
-		out_be32(&pci->piw[win_idx].pitar,  0x00000000);
-		out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
-		out_be32(&pci->piw[win_idx].piwar,  piwar);
+		iowrite32be(0, &pci->regs->piw[win_idx].pitar);
+		iowrite32be(0, &pci->regs->piw[win_idx].piwbar);
+		iowrite32be(piwar, &pci->regs->piw[win_idx].piwar);
 		win_idx--;
 
-		hose->dma_window_base_cur = 0x00000000;
-		hose->dma_window_size = (resource_size_t)sz;
+		pci->dma_window_base_cur = 0x00000000;
+		pci->dma_window_size = (resource_size_t)sz;
 
 		/*
 		 * if we have >4G of memory setup second PCI inbound window to
@@ -431,28 +447,22 @@ static void setup_pci_atmu(struct pci_controller *hose)
 			piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
 
 			/* Setup inbound memory window */
-			out_be32(&pci->piw[win_idx].pitar,  0x00000000);
-			out_be32(&pci->piw[win_idx].piwbear,
-					pci64_dma_offset >> 44);
-			out_be32(&pci->piw[win_idx].piwbar,
-					pci64_dma_offset >> 12);
-			out_be32(&pci->piw[win_idx].piwar,  piwar);
-
-			/*
-			 * install our own dma_set_mask handler to fixup dma_ops
-			 * and dma_offset
-			 */
-			ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
-
-			pr_info("%s: Setup 64-bit PCI DMA window\n", name);
+			iowrite32be(0, &pci->regs->piw[win_idx].pitar);
+			iowrite32be(fsl_arch_pci64_dma_offset() >> 44,
+				    &pci->regs->piw[win_idx].piwbear);
+			iowrite32be(fsl_arch_pci64_dma_offset() >> 12,
+				    &pci->regs->piw[win_idx].piwbar);
+			iowrite32be(piwar,
+				    &pci->regs->piw[win_idx].piwar);
 		}
 	} else {
 		u64 paddr = 0;
 
 		/* Setup inbound memory window */
-		out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
-		out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
-		out_be32(&pci->piw[win_idx].piwar,  (piwar | (mem_log - 1)));
+		iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].pitar);
+		iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].piwbar);
+		iowrite32be((piwar | (mem_log - 1)),
+			    &pci->regs->piw[win_idx].piwar);
 		win_idx--;
 
 		paddr += 1ull << mem_log;
@@ -462,35 +472,36 @@ static void setup_pci_atmu(struct pci_controller *hose)
 			mem_log = ilog2(sz);
 			piwar |= (mem_log - 1);
 
-			out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
-			out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
-			out_be32(&pci->piw[win_idx].piwar,  piwar);
+			iowrite32be(paddr >> 12,
+				    &pci->regs->piw[win_idx].pitar);
+			iowrite32be(paddr >> 12,
+				    &pci->regs->piw[win_idx].piwbar);
+			iowrite32be(piwar,
+				    &pci->regs->piw[win_idx].piwar);
 			win_idx--;
 
 			paddr += 1ull << mem_log;
 		}
 
-		hose->dma_window_base_cur = 0x00000000;
-		hose->dma_window_size = (resource_size_t)paddr;
+		pci->dma_window_base_cur = 0x00000000;
+		pci->dma_window_size = (resource_size_t)paddr;
 	}
 
-	if (hose->dma_window_size < mem) {
-#ifdef CONFIG_SWIOTLB
-		ppc_swiotlb_enable = 1;
-#else
-		pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to "
-			"map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
-			 name);
+	if (pci->dma_window_size < mem) {
+#ifndef CONFIG_SWIOTLB
+		dev_err(pci->dev,
+			"Memory size exceeds PCI ATMU ability to "
+			"map - enable CONFIG_SWIOTLB to avoid dma errors.\n");
 #endif
 		/* adjusting outbound windows could reclaim space in mem map */
 		if (paddr_hi < 0xffffffffull)
-			pr_warning("%s: WARNING: Outbound window cfg leaves "
+			dev_warn(pci->dev,
+				 "Outbound window cfg leaves "
 				"gaps in memory map. Adjusting the memory map "
-				"could reduce unnecessary bounce buffering.\n",
-				name);
+				"could reduce unnecessary bounce buffering.\n");
 
-		pr_info("%s: DMA window size is 0x%llx\n", name,
-			(u64)hose->dma_window_size);
+		dev_info(pci->dev, "DMA window size is 0x%llx\n",
+			 (u64)pci->dma_window_size);
 	}
 }
 
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index a3aca29..490ee53 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -156,5 +156,8 @@ int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
  */
 extern struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr);
 
+/* Return PCI64 DMA offset */
+u64 fsl_arch_pci64_dma_offset(void);
+
 #endif /* __PCI_COMMON_H */
 #endif /* __KERNEL__ */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 03/12][v3] pci: fsl: add PCI indirect access support
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

The patch adds PCI indirect read/write functions. The main code
is ported from arch/powerpc/sysdev/indirect_pci.c. We use general
IO API iowrite32be/ioread32be instead of out_be32/in_be32, and
use structure fsl_Pci instead of PowerPC's pci_controller.
The patch also provides fsl_pcie_check_link() to check PCI link.
The weak function fsl_arch_pci_exclude_device() is provided to
call ppc_md.pci_exclude_device() for PowerPC architecture.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 drivers/pci/host/pci-fsl-common.c | 169 ++++++++++++++++++++++++++++++++------
 include/linux/fsl/pci-common.h    |   6 ++
 2 files changed, 151 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index 69d338b..8bc9a64 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -35,52 +35,173 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
-static int fsl_pcie_check_link(struct pci_controller *hose)
+/* Indirect type */
+#define INDIRECT_TYPE_EXT_REG			0x00000002
+#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS	0x00000004
+#define INDIRECT_TYPE_NO_PCIE_LINK		0x00000008
+#define INDIRECT_TYPE_BIG_ENDIAN		0x00000010
+#define INDIRECT_TYPE_FSL_CFG_REG_LINK		0x00000040
+
+int __weak fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
+{
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int fsl_pci_read_config(struct fsl_pci *pci, int bus, int devfn,
+				int offset, int len, u32 *val)
+{
+	u32 bus_no, reg, data;
+
+	if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+		if (bus != pci->first_busno)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		if (devfn != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	if (fsl_arch_pci_exclude_device(pci, bus, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	bus_no = (bus == pci->first_busno) ? pci->self_busno : bus;
+
+	if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
+		reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+	else
+		reg = offset & 0xfc;
+
+	if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+		iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+			    &pci->regs->config_addr);
+	else
+		iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+			  &pci->regs->config_addr);
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	data = ioread32(&pci->regs->config_data);
+	switch (len) {
+	case 1:
+		*val = (data >> (8 * (offset & 3))) & 0xff;
+		break;
+	case 2:
+		*val = (data >> (8 * (offset & 3))) & 0xffff;
+		break;
+	default:
+		*val = data;
+		break;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int fsl_pci_write_config(struct fsl_pci *pci, int bus, int devfn,
+				 int offset, int len, u32 val)
+{
+	void __iomem *cfg_data;
+	u32 bus_no, reg;
+
+	if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+		if (bus != pci->first_busno)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		if (devfn != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	if (fsl_arch_pci_exclude_device(pci, bus, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	bus_no = (bus == pci->first_busno) ?
+			pci->self_busno : bus;
+
+	if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
+		reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+	else
+		reg = offset & 0xfc;
+
+	if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+		iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+			    &pci->regs->config_addr);
+	else
+		iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
+			  &pci->regs->config_addr);
+
+	/* suppress setting of PCI_PRIMARY_BUS */
+	if (pci->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+		if ((offset == PCI_PRIMARY_BUS) &&
+		    (bus == pci->first_busno))
+			val &= 0xffffff00;
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = ((void *) &(pci->regs->config_data)) + (offset & 3);
+	switch (len) {
+	case 1:
+		iowrite8(val, cfg_data);
+		break;
+	case 2:
+		iowrite16(val, cfg_data);
+		break;
+	default:
+		iowrite32(val, cfg_data);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+bool fsl_pci_check_link(struct fsl_pci *pci)
 {
 	u32 val = 0;
 
-	if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) {
-		if (hose->ops->read == fsl_indirect_read_config) {
-			struct pci_bus bus;
-			bus.number = hose->first_busno;
-			bus.sysdata = hose;
-			bus.ops = hose->ops;
-			indirect_read_config(&bus, 0, PCIE_LTSSM, 4, &val);
-		} else
-			early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
+	if (pci->indirect_type & INDIRECT_TYPE_FSL_CFG_REG_LINK) {
+		fsl_pci_read_config(pci, 0, 0, PCIE_LTSSM, 4, &val);
 		if (val < PCIE_LTSSM_L0)
-			return 1;
+			return false;
 	} else {
-		struct ccsr_pci __iomem *pci = hose->private_data;
 		/* for PCIe IP rev 3.0 or greater use CSR0 for link state */
-		val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK)
+		val = (ioread32be(&pci->regs->pex_csr0) & PEX_CSR0_LTSSM_MASK)
 				>> PEX_CSR0_LTSSM_SHIFT;
 		if (val != PEX_CSR0_LTSSM_L0)
-			return 1;
+			return false;
 	}
 
-	return 0;
+	return true;
 }
 
 static int fsl_indirect_read_config(struct pci_bus *bus, unsigned int devfn,
 				    int offset, int len, u32 *val)
 {
-	struct pci_controller *hose = pci_bus_to_host(bus);
+	struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
+
+	if (!pci)
+		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	if (fsl_pcie_check_link(hose))
-		hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+	if (fsl_pci_check_link(pci))
+		pci->indirect_type &= ~INDIRECT_TYPE_NO_PCIE_LINK;
 	else
-		hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+		pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
 
-	return indirect_read_config(bus, devfn, offset, len, val);
+	return fsl_pci_read_config(pci, bus->number, devfn, offset, len, val);
 }
 
-#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-
-static struct pci_ops fsl_indirect_pcie_ops =
+static int fsl_indirect_write_config(struct pci_bus *bus, unsigned int devfn,
+				     int offset, int len, u32 val)
 {
+	struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
+
+	if (!pci)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return fsl_pci_write_config(pci, bus->number, devfn,
+				     offset, len, val);
+}
+
+static struct pci_ops fsl_indirect_pci_ops = {
 	.read = fsl_indirect_read_config,
-	.write = indirect_write_config,
+	.write = fsl_indirect_write_config,
 };
 
 static int setup_one_atmu(struct ccsr_pci __iomem *pci,
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index e56a040..7df4355 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -143,5 +143,11 @@ struct fsl_pci {
  */
 extern struct fsl_pci *fsl_arch_sys_to_pci(void *sys);
 
+/* Return link status true -> link, false -> no link */
+bool fsl_pci_check_link(struct fsl_pci *pci);
+
+/* To avoid touching specified devices */
+int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
+
 #endif /* __PCI_COMMON_H */
 #endif /* __KERNEL__ */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 04/12][v3] pci: fsl: add early PCI indirect access support
From: Minghuan Lian @ 2013-10-23 10:41 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Minghuan Lian, linux-pci, Zang Roy-R61911, Bjorn Helgaas,
	Scott Wood
In-Reply-To: <1382524894-15164-1-git-send-email-Minghuan.Lian@freescale.com>

The driver needs to read/write PCI configuration very early, at
that time architecture-specific PCI controller structure and
PCI bus have not been created. The patch provides an interface
fsl_arch_fake_pci_bus which should be implemented in
architecture-specific PCI driver to fake a PCI controller structure
and PCI bus. Using the fake PCI controller and PCI bus, the patch
provides the early indirect read/write functions.

Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
---
change log:
v1-v3:
Derived from http://patchwork.ozlabs.org/patch/278965/

Based on upstream master.
Based on the discussion of RFC version here
http://patchwork.ozlabs.org/patch/274487/

 drivers/pci/host/pci-fsl-common.c | 26 ++++++++++++++++++++++++++
 include/linux/fsl/pci-common.h    |  7 +++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/pci/host/pci-fsl-common.c b/drivers/pci/host/pci-fsl-common.c
index 8bc9a64..505a6a1 100644
--- a/drivers/pci/host/pci-fsl-common.c
+++ b/drivers/pci/host/pci-fsl-common.c
@@ -204,6 +204,32 @@ static struct pci_ops fsl_indirect_pci_ops = {
 	.write = fsl_indirect_write_config,
 };
 
+#define EARLY_FSL_PCI_OP(rw, size, type)				\
+int early_fsl_##rw##_config_##size(struct fsl_pci *pci, int bus,	\
+				   int devfn, int offset, type value)	\
+{									\
+	return pci_bus_##rw##_config_##size(fsl_arch_fake_pci_bus(pci, bus),\
+					    devfn, offset, value);	\
+}
+
+EARLY_FSL_PCI_OP(read, byte, u8 *)
+EARLY_FSL_PCI_OP(read, word, u16 *)
+EARLY_FSL_PCI_OP(read, dword, u32 *)
+EARLY_FSL_PCI_OP(write, byte, u8)
+EARLY_FSL_PCI_OP(write, word, u16)
+EARLY_FSL_PCI_OP(write, dword, u32)
+
+static int early_fsl_find_capability(struct fsl_pci *pci,
+				     int busnr, int devfn, int cap)
+{
+	struct pci_bus *bus = fsl_arch_fake_pci_bus(pci, busnr);
+
+	if (!bus)
+		return 0;
+
+	return pci_bus_find_capability(bus, devfn, cap);
+}
+
 static int setup_one_atmu(struct ccsr_pci __iomem *pci,
 	unsigned int index, const struct resource *res,
 	resource_size_t offset)
diff --git a/include/linux/fsl/pci-common.h b/include/linux/fsl/pci-common.h
index 7df4355..a3aca29 100644
--- a/include/linux/fsl/pci-common.h
+++ b/include/linux/fsl/pci-common.h
@@ -149,5 +149,12 @@ bool fsl_pci_check_link(struct fsl_pci *pci);
 /* To avoid touching specified devices */
 int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
 
+/*
+ * To fake a PCI bus
+ * it is called by early_fsl_*(), at that time the architecture-dependent
+ * pci controller and pci bus have not been created.
+ */
+extern struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr);
+
 #endif /* __PCI_COMMON_H */
 #endif /* __KERNEL__ */
-- 
1.8.1.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox